Merge tag 'devprop-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Nov 2017 04:36:37 +0000 (20:36 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Nov 2017 04:36:37 +0000 (20:36 -0800)
Pull device properties framework updates from Rafael Wysocki:
 "These make the fwnode_handle_get() function return a pointer to the
  target fwnode object, which reflects the of_node_get() behavior, and
  add a macro for iterating over graph endpoints (Sakari Ailus)"

* tag 'devprop-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  device property: Add a macro for interating over graph endpoints
  device property: Make fwnode_handle_get() return the fwnode

1714 files changed:
.mailmap
CREDITS
Documentation/ABI/stable/sysfs-devices
Documentation/ABI/testing/evm
Documentation/ABI/testing/sysfs-bus-mmc [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-power
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-power
Documentation/Makefile
Documentation/RCU/Design/Expedited-Grace-Periods/Expedited-Grace-Periods.html
Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Diagram.html [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.html [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-callback-invocation.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-callback-registry.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-dyntick.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-cleanup.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-fqs.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-1.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-2.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-3.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-hotplug.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/TreeRCU-qs.svg [new file with mode: 0644]
Documentation/RCU/Design/Memory-Ordering/rcu_node-lock.svg [new file with mode: 0644]
Documentation/RCU/stallwarn.txt
Documentation/acpi/lpit.txt [new file with mode: 0644]
Documentation/admin-guide/README.rst
Documentation/admin-guide/bug-hunting.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/reporting-bugs.rst
Documentation/arm64/silicon-errata.txt
Documentation/cdrom/ide-cd
Documentation/core-api/kernel-api.rst
Documentation/cpu-freq/cpufreq-stats.txt
Documentation/dev-tools/coccinelle.rst
Documentation/dev-tools/kselftest.rst
Documentation/devicetree/bindings/hwmon/gpio-fan.txt [moved from Documentation/devicetree/bindings/gpio/gpio-fan.txt with 100% similarity]
Documentation/devicetree/bindings/hwmon/max1619.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/max31785.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt
Documentation/devicetree/bindings/interrupt-controller/openrisc,ompic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt
Documentation/devicetree/bindings/interrupt-controller/socionext,synquacer-exiu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/mtk-sd.txt
Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt
Documentation/devicetree/bindings/mmc/sdhci-msm.txt
Documentation/devicetree/bindings/mmc/sdhci-omap.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/tmio_mmc.txt
Documentation/devicetree/bindings/openrisc/opencores/or1ksim.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/da9211.txt
Documentation/devicetree/bindings/regulator/pfuze100.txt
Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
Documentation/devicetree/bindings/spi/sh-msiof.txt
Documentation/devicetree/bindings/spi/spi-davinci.txt
Documentation/devicetree/bindings/spi/spi-rspi.txt
Documentation/devicetree/bindings/spi/spi-sprd-adi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/timer/renesas,cmt.txt
Documentation/devicetree/bindings/trivial-devices.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/dmaengine/00-INDEX [deleted file]
Documentation/dmaengine/client.txt [deleted file]
Documentation/dmaengine/provider.txt [deleted file]
Documentation/dmaengine/pxa_dma.txt [deleted file]
Documentation/doc-guide/kernel-doc.rst
Documentation/driver-api/dmaengine/client.rst [new file with mode: 0644]
Documentation/driver-api/dmaengine/dmatest.rst [moved from Documentation/dmaengine/dmatest.txt with 50% similarity]
Documentation/driver-api/dmaengine/index.rst [new file with mode: 0644]
Documentation/driver-api/dmaengine/provider.rst [new file with mode: 0644]
Documentation/driver-api/dmaengine/pxa_dma.rst [new file with mode: 0644]
Documentation/driver-api/index.rst
Documentation/driver-api/pm/devices.rst
Documentation/driver-api/usb/usb.rst
Documentation/fault-injection/notifier-error-inject.txt
Documentation/fb/fbcon.txt
Documentation/features/debug/KASAN/arch-support.txt
Documentation/filesystems/dnotify.txt
Documentation/filesystems/ext4.txt
Documentation/filesystems/path-lookup.md
Documentation/hid/hiddev.txt
Documentation/hwmon/max31785 [new file with mode: 0644]
Documentation/hwmon/sht15
Documentation/input/devices/xpad.rst
Documentation/kprobes.txt
Documentation/laptops/laptop-mode.txt
Documentation/locking/rt-mutex-design.txt
Documentation/media/dvb-drivers/bt8xx.rst
Documentation/media/uapi/v4l/dev-sliced-vbi.rst
Documentation/media/uapi/v4l/extended-controls.rst
Documentation/media/uapi/v4l/pixfmt-reserved.rst
Documentation/media/v4l-drivers/bttv.rst
Documentation/media/v4l-drivers/max2175.rst
Documentation/memory-barriers.txt
Documentation/networking/cdc_mbim.txt
Documentation/networking/checksum-offloads.txt
Documentation/networking/packet_mmap.txt
Documentation/openrisc/README [moved from arch/openrisc/README.openrisc with 56% similarity]
Documentation/openrisc/TODO [moved from arch/openrisc/TODO.openrisc with 100% similarity]
Documentation/pi-futex.txt
Documentation/power/interface.txt
Documentation/power/pci.txt
Documentation/power/pm_qos_interface.txt
Documentation/power/runtime_pm.txt
Documentation/power/suspend-and-cpuhotplug.txt
Documentation/process/3.Early-stage.rst
Documentation/process/4.Coding.rst
Documentation/process/index.rst
Documentation/process/kernel-driver-statement.rst [new file with mode: 0644]
Documentation/process/submitting-drivers.rst
Documentation/process/submitting-patches.rst
Documentation/security/LSM.rst
Documentation/security/credentials.rst
Documentation/security/keys/request-key.rst
Documentation/sound/cards/joystick.rst
Documentation/sound/hd-audio/notes.rst
Documentation/sound/kernel-api/writing-an-alsa-driver.rst
Documentation/sysctl/README
Documentation/sysctl/fs.txt
Documentation/timers/highres.txt
Documentation/trace/ftrace-uses.rst [new file with mode: 0644]
Documentation/trace/intel_th.txt
Documentation/translations/ko_KR/memory-barriers.txt
Documentation/usb/gadget-testing.txt
Documentation/watchdog/hpwdt.txt
Documentation/watchdog/pcwd-watchdog.txt
Documentation/x86/amd-memory-encryption.txt
Documentation/x86/intel_rdt_ui.txt
Documentation/x86/orc-unwinder.txt
Documentation/x86/x86_64/mm.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/atomic.h
arch/alpha/include/asm/rwsem.h
arch/alpha/include/asm/spinlock.h
arch/arc/include/asm/spinlock.h
arch/arc/kernel/smp.c
arch/arm/common/locomo.c
arch/arm/include/asm/arch_gicv3.h
arch/arm/include/asm/hardware/locomo.h
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/spinlock.h
arch/arm/include/asm/topology.h
arch/arm/kernel/traps.c
arch/arm/mach-footbridge/dc21285.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-ixp4xx/dsmg600-setup.c
arch/arm/mach-ixp4xx/nas100d-setup.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/sharpsl_pm.c
arch/arm/mach-pxa/stargate2.c
arch/arm/mach-shmobile/pm-rmobile.c
arch/arm/mach-tegra/cpuidle-tegra20.c
arch/arm/probes/kprobes/test-core.c
arch/arm/vdso/vgettimeofday.c
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/boot/dts/mediatek/mt8173.dtsi
arch/arm64/include/asm/Kbuild
arch/arm64/include/asm/acpi.h
arch/arm64/include/asm/arch_gicv3.h
arch/arm64/include/asm/fixmap.h
arch/arm64/include/asm/spinlock.h
arch/arm64/include/asm/spinlock_types.h
arch/arm64/include/asm/topology.h
arch/arm64/mm/mmu.c
arch/blackfin/include/asm/spinlock.h
arch/hexagon/include/asm/spinlock.h
arch/ia64/Kconfig
arch/ia64/include/asm/rwsem.h
arch/ia64/include/asm/sn/bte.h
arch/ia64/include/asm/spinlock.h
arch/ia64/kernel/asm-offsets.c
arch/ia64/kernel/fsys.S
arch/ia64/kernel/fsyscall_gtod_data.h
arch/ia64/kernel/mca.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/time.c
arch/ia64/sn/kernel/bte.c
arch/ia64/sn/kernel/bte_error.c
arch/ia64/sn/kernel/huberror.c
arch/ia64/sn/kernel/mca.c
arch/m32r/include/asm/spinlock.h
arch/m68k/Kconfig.cpu
arch/m68k/Kconfig.machine
arch/m68k/amiga/amisound.c
arch/m68k/coldfire/Makefile
arch/m68k/coldfire/m5441x.c
arch/m68k/coldfire/m54xx.c
arch/m68k/coldfire/stmark2.c [new file with mode: 0644]
arch/m68k/configs/amiga_defconfig
arch/m68k/configs/apollo_defconfig
arch/m68k/configs/atari_defconfig
arch/m68k/configs/bvme6000_defconfig
arch/m68k/configs/hp300_defconfig
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/configs/mvme147_defconfig
arch/m68k/configs/mvme16x_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/configs/stmark2_defconfig [new file with mode: 0644]
arch/m68k/configs/sun3_defconfig
arch/m68k/configs/sun3x_defconfig
arch/m68k/include/asm/m5441xsim.h
arch/m68k/include/asm/mac_iop.h
arch/m68k/include/asm/mcfmmu.h
arch/m68k/include/asm/mmu_context.h
arch/m68k/kernel/setup.c
arch/m68k/kernel/setup_mm.c
arch/m68k/mac/baboon.c
arch/m68k/mac/config.c
arch/m68k/mac/iop.c
arch/m68k/mac/macboing.c
arch/m68k/mac/oss.c
arch/m68k/mac/psc.c
arch/m68k/mac/via.c
arch/m68k/mm/mcfmmu.c
arch/metag/include/asm/spinlock.h
arch/metag/include/asm/spinlock_lnkget.h
arch/metag/include/asm/spinlock_lock1.h
arch/mips/ar7/platform.c
arch/mips/ar7/prom.c
arch/mips/include/asm/spinlock.h
arch/mips/include/asm/vdso.h
arch/mips/kernel/pm-cps.c
arch/mips/kernel/smp-bmips.c
arch/mips/mti-malta/malta-display.c
arch/mips/sgi-ip22/ip22-reset.c
arch/mips/sgi-ip32/ip32-reset.c
arch/mn10300/include/asm/spinlock.h
arch/mn10300/kernel/mn10300-serial.c
arch/openrisc/Kconfig
arch/openrisc/Makefile
arch/openrisc/boot/dts/or1ksim.dts
arch/openrisc/boot/dts/simple_smp.dts [new file with mode: 0644]
arch/openrisc/configs/simple_smp_defconfig [new file with mode: 0644]
arch/openrisc/include/asm/Kbuild
arch/openrisc/include/asm/cacheflush.h [new file with mode: 0644]
arch/openrisc/include/asm/cmpxchg.h
arch/openrisc/include/asm/cpuinfo.h
arch/openrisc/include/asm/mmu_context.h
arch/openrisc/include/asm/pgtable.h
arch/openrisc/include/asm/serial.h
arch/openrisc/include/asm/smp.h [new file with mode: 0644]
arch/openrisc/include/asm/spinlock.h
arch/openrisc/include/asm/spinlock_types.h [new file with mode: 0644]
arch/openrisc/include/asm/spr_defs.h
arch/openrisc/include/asm/thread_info.h
arch/openrisc/include/asm/time.h [new file with mode: 0644]
arch/openrisc/include/asm/tlbflush.h
arch/openrisc/include/asm/unwinder.h [new file with mode: 0644]
arch/openrisc/kernel/Makefile
arch/openrisc/kernel/dma.c
arch/openrisc/kernel/entry.S
arch/openrisc/kernel/head.S
arch/openrisc/kernel/setup.c
arch/openrisc/kernel/smp.c [new file with mode: 0644]
arch/openrisc/kernel/stacktrace.c [new file with mode: 0644]
arch/openrisc/kernel/sync-timer.c [new file with mode: 0644]
arch/openrisc/kernel/time.c
arch/openrisc/kernel/traps.c
arch/openrisc/kernel/unwinder.c [new file with mode: 0644]
arch/openrisc/lib/delay.c
arch/openrisc/mm/Makefile
arch/openrisc/mm/cache.c [new file with mode: 0644]
arch/openrisc/mm/fault.c
arch/openrisc/mm/init.c
arch/openrisc/mm/tlb.c
arch/parisc/include/asm/atomic.h
arch/parisc/include/asm/spinlock.h
arch/parisc/kernel/pdc_cons.c
arch/powerpc/include/asm/spinlock.h
arch/powerpc/kernel/machine_kexec_file_64.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/watchdog.c
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/powernv/opal-msglog.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/boot/compressed/Makefile
arch/s390/boot/compressed/misc.c
arch/s390/configs/default_defconfig
arch/s390/configs/gcov_defconfig
arch/s390/configs/performance_defconfig
arch/s390/crypto/aes_s390.c
arch/s390/defconfig
arch/s390/include/asm/Kbuild
arch/s390/include/asm/alternative.h [new file with mode: 0644]
arch/s390/include/asm/archrandom.h
arch/s390/include/asm/atomic_ops.h
arch/s390/include/asm/ccwgroup.h
arch/s390/include/asm/cpacf.h
arch/s390/include/asm/ctl_reg.h
arch/s390/include/asm/debug.h
arch/s390/include/asm/dis.h
arch/s390/include/asm/ipl.h
arch/s390/include/asm/kprobes.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/nmi.h
arch/s390/include/asm/pci_debug.h
arch/s390/include/asm/pci_insn.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/runtime_instr.h
arch/s390/include/asm/rwsem.h [deleted file]
arch/s390/include/asm/sections.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/smp.h
arch/s390/include/asm/spinlock.h
arch/s390/include/asm/spinlock_types.h
arch/s390/include/asm/string.h
arch/s390/include/asm/switch_to.h
arch/s390/include/asm/sysinfo.h
arch/s390/include/asm/topology.h
arch/s390/include/asm/vdso.h
arch/s390/include/uapi/asm/kvm_virtio.h [deleted file]
arch/s390/include/uapi/asm/sthyi.h [new file with mode: 0644]
arch/s390/include/uapi/asm/unistd.h
arch/s390/kernel/Makefile
arch/s390/kernel/alternative.c [new file with mode: 0644]
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/compat_wrapper.c
arch/s390/kernel/debug.c
arch/s390/kernel/dis.c
arch/s390/kernel/early.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/guarded_storage.c
arch/s390/kernel/ipl.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/lgr.c
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/module.c
arch/s390/kernel/nmi.c
arch/s390/kernel/perf_cpum_cf_events.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/process.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/relocate_kernel.S
arch/s390/kernel/runtime_instr.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/sthyi.c [moved from arch/s390/kvm/sthyi.c with 77% similarity]
arch/s390/kernel/suspend.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/topology.c
arch/s390/kernel/vdso.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/kvm/Makefile
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/lib/mem.S
arch/s390/lib/spinlock.c
arch/s390/lib/string.c
arch/s390/mm/cmm.c
arch/s390/mm/init.c
arch/s390/mm/pgalloc.c
arch/s390/mm/vmem.c
arch/s390/net/bpf_jit.h
arch/s390/net/bpf_jit_comp.c
arch/s390/pci/pci.c
arch/s390/pci/pci_insn.c
arch/s390/tools/Makefile
arch/s390/tools/gen_opcode_table.c [new file with mode: 0644]
arch/s390/tools/opcodes.txt [new file with mode: 0644]
arch/sh/include/asm/spinlock-cas.h
arch/sh/include/asm/spinlock-llsc.h
arch/sparc/include/asm/atomic_32.h
arch/sparc/include/asm/ptrace.h
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/kernel/led.c
arch/tile/gxio/dma_queue.c
arch/tile/include/asm/spinlock_32.h
arch/tile/include/asm/spinlock_64.h
arch/tile/include/gxio/dma_queue.h
arch/tile/kernel/ptrace.c
arch/um/include/shared/init.h
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/boot/.gitignore
arch/x86/boot/Makefile
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/mem_encrypt.S [new file with mode: 0644]
arch/x86/boot/compressed/misc.h
arch/x86/boot/compressed/pagetable.c
arch/x86/boot/genimage.sh [new file with mode: 0644]
arch/x86/boot/header.S
arch/x86/boot/video-vga.c
arch/x86/configs/tiny.config
arch/x86/configs/x86_64_defconfig
arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S
arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S
arch/x86/entry/calling.h
arch/x86/entry/common.c
arch/x86/entry/entry_64.S
arch/x86/entry/entry_64_compat.S
arch/x86/entry/syscalls/Makefile
arch/x86/entry/vdso/vclock_gettime.c
arch/x86/entry/vdso/vdso2c.c
arch/x86/entry/vdso/vma.c
arch/x86/events/amd/iommu.c
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/perf_event.h
arch/x86/hyperv/hv_init.c
arch/x86/include/asm/apic.h
arch/x86/include/asm/archrandom.h
arch/x86/include/asm/barrier.h
arch/x86/include/asm/bitops.h
arch/x86/include/asm/compat.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/disabled-features.h
arch/x86/include/asm/elf.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/hypervisor.h
arch/x86/include/asm/inat.h
arch/x86/include/asm/insn-eval.h [new file with mode: 0644]
arch/x86/include/asm/io.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/irq.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/irqdomain.h
arch/x86/include/asm/kprobes.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/kvm_para.h
arch/x86/include/asm/mem_encrypt.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/module.h
arch/x86/include/asm/mpspec_def.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/qspinlock.h
arch/x86/include/asm/refcount.h
arch/x86/include/asm/rmwcc.h
arch/x86/include/asm/rwsem.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/switch_to.h
arch/x86/include/asm/syscalls.h
arch/x86/include/asm/timer.h
arch/x86/include/asm/trace/fpu.h
arch/x86/include/asm/trace/irq_vectors.h
arch/x86/include/asm/traps.h
arch/x86/include/asm/tsc.h
arch/x86/include/asm/umip.h [new file with mode: 0644]
arch/x86/include/asm/unwind.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/vgtod.h
arch/x86/include/asm/x2apic.h [deleted file]
arch/x86/include/asm/x86_init.h
arch/x86/include/uapi/asm/kvm_para.h
arch/x86/include/uapi/asm/processor-flags.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/apei.c
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/alternative.c
arch/x86/kernel/apic/Makefile
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_common.c [new file with mode: 0644]
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/apic_noop.c
arch/x86/kernel/apic/apic_numachip.c
arch/x86/kernel/apic/bigsmp_32.c
arch/x86/kernel/apic/htirq.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/apic/x2apic.h [new file with mode: 0644]
arch/x86/kernel/apic/x2apic_cluster.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpuid-deps.c [new file with mode: 0644]
arch/x86/kernel/cpu/hypervisor.c
arch/x86/kernel/cpu/intel_rdt.c
arch/x86/kernel/cpu/intel_rdt.h
arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
arch/x86/kernel/cpu/intel_rdt_monitor.c
arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
arch/x86/kernel/cpu/mcheck/mce-severity.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/proc.c
arch/x86/kernel/cpu/vmware.c
arch/x86/kernel/crash.c
arch/x86/kernel/espfix_64.c
arch/x86/kernel/fpu/init.c
arch/x86/kernel/fpu/xstate.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/i8259.c
arch/x86/kernel/idt.c
arch/x86/kernel/irq.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/kprobes/common.h
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/kprobes/ftrace.c
arch/x86/kernel/kprobes/opt.c
arch/x86/kernel/kvm.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/ldt.c
arch/x86/kernel/nmi.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pmem.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/time.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/tsc_sync.c
arch/x86/kernel/umip.c [new file with mode: 0644]
arch/x86/kernel/unwind_orc.c
arch/x86/kernel/uprobes.c
arch/x86/kernel/verify_cpu.S
arch/x86/kernel/vm86_32.c
arch/x86/kernel/vsmp_64.c
arch/x86/kernel/x86_init.c
arch/x86/kvm/mmu.c
arch/x86/kvm/page_track.c
arch/x86/lib/Makefile
arch/x86/lib/insn-eval.c [new file with mode: 0644]
arch/x86/lib/rwsem.S
arch/x86/mm/extable.c
arch/x86/mm/fault.c
arch/x86/mm/init.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/kasan_init_64.c
arch/x86/mm/mem_encrypt.c
arch/x86/mm/mpx.c
arch/x86/mm/pageattr.c
arch/x86/oprofile/op_model_ppro.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.c
arch/x86/platform/uv/uv_irq.c
arch/x86/realmode/init.c
arch/x86/um/ldt.c
arch/x86/xen/apic.c
arch/x86/xen/enlighten_hvm.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/enlighten_pvh.c
arch/x86/xen/mmu_pv.c
arch/x86/xen/p2m.c
arch/x86/xen/smp_pv.c
arch/x86/xen/spinlock.c
arch/x86/xen/xen-asm_64.S
arch/x86/xen/xen-head.S
arch/xtensa/include/asm/spinlock.h
arch/xtensa/platforms/iss/console.c
arch/xtensa/platforms/iss/network.c
arch/xtensa/platforms/xtfpga/lcd.c
block/bio.c
block/blk-wbt.c
block/genhd.c
crypto/ccm.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/ac.c
drivers/acpi/acpi_lpit.c [new file with mode: 0644]
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_processor.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acinterp.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/dbconvert.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/exconcat.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/exmisc.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/hwtimer.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/nsconvert.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/utstrsuppt.c [new file with mode: 0644]
drivers/acpi/acpica/utstrtoul64.c
drivers/acpi/apei/erst.c
drivers/acpi/apei/ghes.c
drivers/acpi/button.c
drivers/acpi/cppc_acpi.c
drivers/acpi/device_pm.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/pmic/tps68470_pmic.c [new file with mode: 0644]
drivers/acpi/resource.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/sysfs.c
drivers/acpi/x86/utils.c
drivers/ata/ahci.h
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata.h
drivers/atm/idt77105.c
drivers/atm/iphase.c
drivers/auxdisplay/img-ascii-lcd.c
drivers/auxdisplay/panel.c
drivers/base/arch_topology.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/dd.c
drivers/base/power/Makefile
drivers/base/power/domain.c
drivers/base/power/domain_governor.c
drivers/base/power/generic_ops.c
drivers/base/power/main.c
drivers/base/power/qos.c
drivers/base/power/runtime.c
drivers/base/power/sysfs.c
drivers/base/power/wakeup.c
drivers/base/regmap/Kconfig
drivers/base/regmap/internal.h
drivers/base/regmap/regmap-spi.c
drivers/base/regmap/regmap-spmi.c
drivers/base/regmap/regmap.c
drivers/block/amiflop.c
drivers/block/aoe/aoemain.c
drivers/block/ataflop.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_req.h
drivers/block/drbd/drbd_worker.c
drivers/block/rbd.c
drivers/char/dtlk.c
drivers/char/hangcheck-timer.c
drivers/char/hw_random/xgene-rng.c
drivers/char/nwbutton.c
drivers/char/random.c
drivers/char/rtc.c
drivers/char/tlclk.c
drivers/char/tpm/tpm-dev-common.c
drivers/char/tpm/tpm-sysfs.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm2-cmd.c
drivers/char/tpm/tpm2-space.c
drivers/char/tpm/tpm_crb.c
drivers/char/tpm/tpm_tis.c
drivers/char/tpm/tpm_tis_core.c
drivers/char/tpm/tpm_tis_core.h
drivers/char/tpm/tpm_tis_spi.c
drivers/clocksource/Kconfig
drivers/clocksource/arm_arch_timer.c
drivers/clocksource/bcm2835_timer.c
drivers/clocksource/mips-gic-timer.c
drivers/clocksource/owl-timer.c
drivers/clocksource/rockchip_timer.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/timer-fttmr010.c
drivers/clocksource/timer-of.c
drivers/clocksource/timer-of.h
drivers/cpufreq/arm_big_little.c
drivers/cpufreq/arm_big_little.h
drivers/cpufreq/arm_big_little_dt.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/powernow-k8.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpufreq/pxa2xx-cpufreq.c
drivers/cpufreq/scpi-cpufreq.c
drivers/cpufreq/spear-cpufreq.c
drivers/cpufreq/speedstep-lib.c
drivers/cpufreq/ti-cpufreq.c
drivers/cpufreq/vexpress-spc-cpufreq.c
drivers/cpuidle/cpuidle-arm.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/governors/ladder.c
drivers/cpuidle/governors/menu.c
drivers/crypto/axis/artpec6_crypto.c
drivers/crypto/caam/jr.c
drivers/crypto/mv_cesa.c
drivers/crypto/nx/nx-842-powernv.c
drivers/crypto/picoxcell_crypto.c
drivers/devfreq/devfreq.c
drivers/devfreq/exynos-bus.c
drivers/devfreq/governor_passive.c
drivers/devfreq/governor_performance.c
drivers/devfreq/governor_powersave.c
drivers/devfreq/governor_simpleondemand.c
drivers/devfreq/governor_userspace.c
drivers/devfreq/rk3399_dmc.c
drivers/edac/altera_edac.c
drivers/edac/amd64_edac.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc.h
drivers/edac/ghes_edac.c
drivers/edac/i7core_edac.c
drivers/edac/pnd2_edac.c
drivers/edac/sb_edac.c
drivers/edac/skx_edac.c
drivers/edac/thunderx_edac.c
drivers/firewire/core-transaction.c
drivers/firewire/ohci.c
drivers/firmware/tegra/ivc.c
drivers/gpio/gpio-xgene-sb.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
drivers/gpu/drm/etnaviv/etnaviv_gpu.c
drivers/gpu/drm/gma500/psb_lid.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
drivers/hsi/clients/ssi_protocol.c
drivers/hv/vmbus_drv.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/asc7621.c
drivers/hwmon/aspeed-pwm-tacho.c
drivers/hwmon/gpio-fan.c
drivers/hwmon/k10temp.c
drivers/hwmon/max1619.c
drivers/hwmon/max6621.c [new file with mode: 0644]
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/max31785.c [new file with mode: 0644]
drivers/hwmon/pmbus/pmbus.h
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/sht15.c
drivers/hwmon/stts751.c
drivers/hwmon/w83793.c
drivers/hwmon/xgene-hwmon.c
drivers/ide/ide-cd.c
drivers/ide/ide-io.c
drivers/ide/ide-probe.c
drivers/idle/intel_idle.c
drivers/infiniband/hw/hfi1/file_ops.c
drivers/infiniband/hw/hfi1/pio.c
drivers/infiniband/hw/hfi1/ruc.c
drivers/infiniband/hw/hfi1/sdma.c
drivers/infiniband/hw/hfi1/sdma.h
drivers/infiniband/hw/hfi1/uc.c
drivers/infiniband/hw/hfi1/ud.c
drivers/infiniband/hw/hfi1/user_sdma.c
drivers/infiniband/hw/qib/qib_ruc.c
drivers/infiniband/hw/qib/qib_uc.c
drivers/infiniband/hw/qib/qib_ud.c
drivers/infiniband/sw/rdmavt/qp.c
drivers/input/misc/regulator-haptic.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/vmmouse.c
drivers/input/rmi4/rmi_smbus.c
drivers/input/touchscreen/s3c2410_ts.c
drivers/input/touchscreen/tsc200x-core.c
drivers/iommu/amd_iommu.c
drivers/iommu/intel_irq_remapping.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-aspeed-i2c-ic.c
drivers/irqchip/irq-brcmstb-l2.c
drivers/irqchip/irq-gic-common.c
drivers/irqchip/irq-gic-common.h
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-meson-gpio.c [new file with mode: 0644]
drivers/irqchip/irq-mips-gic.c
drivers/irqchip/irq-omap-intc.c
drivers/irqchip/irq-ompic.c [new file with mode: 0644]
drivers/irqchip/irq-renesas-intc-irqpin.c
drivers/irqchip/irq-sni-exiu.c [new file with mode: 0644]
drivers/irqchip/irq-stm32-exti.c
drivers/macintosh/adb-iop.c
drivers/macintosh/smu.c
drivers/mailbox/mailbox-altera.c
drivers/mailbox/pcc.c
drivers/md/dm-bufio.c
drivers/md/dm-integrity.c
drivers/md/dm-kcopyd.c
drivers/md/dm-mpath.c
drivers/md/dm-stats.c
drivers/md/dm-switch.c
drivers/md/dm-thin.c
drivers/md/dm-verity-target.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid5.c
drivers/media/dvb-core/dvb_ringbuffer.c
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
drivers/memstick/host/jmb38x_ms.c
drivers/memstick/host/r592.c
drivers/memstick/host/tifm_ms.c
drivers/misc/lkdtm_core.c
drivers/misc/mei/pci-me.c
drivers/misc/mei/pci-txe.c
drivers/misc/mic/scif/scif_rb.c
drivers/misc/mic/scif/scif_rma_list.c
drivers/misc/sgi-xp/xpc_main.c
drivers/misc/sgi-xp/xpc_sn2.c
drivers/misc/vmw_balloon.c
drivers/mmc/core/block.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/host.c
drivers/mmc/core/host.h
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/queue.c
drivers/mmc/core/queue.h
drivers/mmc/core/sd.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/cavium.c
drivers/mmc/host/dw_mmc-k3.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/meson-gx-mmc.c
drivers/mmc/host/meson-mx-sdio.c [new file with mode: 0644]
drivers/mmc/host/mmci.c
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/renesas_sdhi_internal_dmac.c
drivers/mmc/host/renesas_sdhi_sys_dmac.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-cadence.c
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-at91.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-omap.c [new file with mode: 0644]
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-pci-o2micro.c
drivers/mmc/host/sdhci-pci-o2micro.h [deleted file]
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci_f_sdh30.c
drivers/mmc/host/sunxi-mmc.c
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/tmio_mmc_core.c
drivers/mmc/host/usdhi6rol0.c
drivers/mmc/host/via-sdmmc.c
drivers/mmc/host/vub300.c
drivers/mmc/host/wbsd.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/can/c_can/c_can_pci.c
drivers/net/can/c_can/c_can_platform.c
drivers/net/can/ifi_canfd/ifi_canfd.c
drivers/net/can/peak_canfd/peak_pciefd_main.c
drivers/net/can/sun4i_can.c
drivers/net/cris/eth_v10.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/hisilicon/hip04_eth.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_ptp.c
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/intel/ixgbevf/vf.h
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/dev.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/neterion/vxge/vxge-main.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/falcon/efx.c
drivers/net/ethernet/sfc/falcon/falcon.c
drivers/net/ethernet/sfc/falcon/farch.c
drivers/net/ethernet/sfc/falcon/nic.h
drivers/net/ethernet/sfc/falcon/tx.c
drivers/net/ethernet/sfc/farch.c
drivers/net/ethernet/sfc/nic.h
drivers/net/ethernet/sfc/ptp.c
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/tile/tilegx.c
drivers/net/ethernet/tile/tilepro.c
drivers/net/hamradio/yam.c
drivers/net/tap.c
drivers/net/tun.c
drivers/net/usb/asix_devices.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/qmi_wwan.c
drivers/net/vxlan.c
drivers/net/wan/hdlc_cisco.c
drivers/net/wan/hdlc_fr.c
drivers/net/wireless/ath/ath5k/desc.c
drivers/net/wireless/ath/ath6kl/recovery.c
drivers/net/wireless/atmel/at76c50x-usb.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/mac80211_hwsim.c
drivers/nubus/nubus.c
drivers/opp/Kconfig [new file with mode: 0644]
drivers/opp/Makefile [moved from drivers/base/power/opp/Makefile with 100% similarity]
drivers/opp/core.c [moved from drivers/base/power/opp/core.c with 92% similarity]
drivers/opp/cpu.c [moved from drivers/base/power/opp/cpu.c with 100% similarity]
drivers/opp/debugfs.c [moved from drivers/base/power/opp/debugfs.c with 97% similarity]
drivers/opp/of.c [moved from drivers/base/power/opp/of.c with 99% similarity]
drivers/opp/opp.h [moved from drivers/base/power/opp/opp.h with 95% similarity]
drivers/parport/ieee1284.c
drivers/pci/msi.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pcmcia/bcm63xx_pcmcia.c
drivers/pcmcia/bfin_cf_pcmcia.c
drivers/pcmcia/i82365.c
drivers/pcmcia/omap_cf.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/soc_common.c
drivers/pcmcia/tcic.c
drivers/pcmcia/yenta_socket.c
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/power/avs/smartreflex.c
drivers/ras/cec.c
drivers/regulator/Kconfig
drivers/regulator/axp20x-regulator.c
drivers/regulator/da9211-regulator.c
drivers/regulator/da9211-regulator.h
drivers/regulator/pbias-regulator.c
drivers/regulator/qcom_spmi-regulator.c
drivers/regulator/tps65218-regulator.c
drivers/rtc/class.c
drivers/rtc/systohc.c
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_int.h
drivers/s390/block/scm_blk.h
drivers/s390/char/sclp_con.c
drivers/s390/char/sclp_tty.c
drivers/s390/char/tape.h
drivers/s390/char/tape_class.c
drivers/s390/char/tape_std.c
drivers/s390/char/vmlogrdr.c
drivers/s390/char/vmur.c
drivers/s390/char/vmur.h
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/cio_debug.h
drivers/s390/cio/cmf.c
drivers/s390/cio/eadm_sch.c
drivers/s390/cio/qdio_debug.h
drivers/s390/cio/qdio_thinint.c
drivers/s390/cio/vfio_ccw_cp.c
drivers/s390/crypto/ap_asm.h
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_card.c
drivers/s390/crypto/ap_queue.c
drivers/s390/crypto/pkey_api.c
drivers/s390/crypto/zcrypt_api.h
drivers/s390/crypto/zcrypt_cex4.c
drivers/s390/crypto/zcrypt_msgtype50.c
drivers/s390/crypto/zcrypt_msgtype6.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/lcs.c
drivers/s390/net/lcs.h
drivers/s390/net/qeth_core_main.c
drivers/s390/virtio/Makefile
drivers/s390/virtio/kvm_virtio.c [deleted file]
drivers/scsi/aic7xxx/aic79xx.h
drivers/scsi/aic7xxx/aic79xx_core.c
drivers/scsi/aic7xxx/aic79xx_osm.h
drivers/scsi/aic94xx/aic94xx_hwi.c
drivers/scsi/aic94xx/aic94xx_hwi.h
drivers/scsi/aic94xx/aic94xx_scb.c
drivers/scsi/aic94xx/aic94xx_tmf.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2i/bnx2i.h
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/csiostor/csio_hw.c
drivers/scsi/csiostor/csio_mb.c
drivers/scsi/csiostor/csio_mb.h
drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/dc395x.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe_transport.c
drivers/scsi/gdth.c
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ipr.c
drivers/scsi/isci/host.c
drivers/scsi/isci/isci.h
drivers/scsi/isci/phy.c
drivers/scsi/isci/port.c
drivers/scsi/isci/port_config.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libiscsi.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_init.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/megaraid/megaraid_ioctl.h
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_mm.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pmcraid.c
drivers/scsi/qla1280.c
drivers/scsi/qla1280.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_srp.c
drivers/scsi/smartpqi/smartpqi_init.c
drivers/soc/mediatek/mtk-scpsys.c
drivers/soc/rockchip/pm_domains.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-armada-3700.c
drivers/spi/spi-axi-spi-engine.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-imx.c
drivers/spi/spi-mxs.c
drivers/spi/spi-orion.c
drivers/spi/spi-rspi.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sprd-adi.c [new file with mode: 0644]
drivers/spi/spi-tegra114.c
drivers/spi/spi.c
drivers/staging/speakup/main.c
drivers/staging/speakup/synth.c
drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/iscsi/iscsi_target_erl0.h
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_erl1.h
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_login.h
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
drivers/target/target_core_user.c
drivers/tty/cyclades.c
drivers/tty/isicom.c
drivers/tty/moxa.c
drivers/tty/rocket.c
drivers/tty/vt/keyboard.c
drivers/tty/vt/vt.c
drivers/usb/class/cdc-wdm.c
drivers/usb/core/devio.c
drivers/usb/core/sysfs.c
drivers/usb/gadget/udc/gr_udc.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/misc/usbtest.c
drivers/vfio/vfio.c
drivers/vhost/scsi.c
drivers/watchdog/alim7101_wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/lpc18xx_wdt.c
drivers/watchdog/machzwd.c
drivers/watchdog/mixcomwd.c
drivers/watchdog/sbc60xxwdt.c
drivers/watchdog/sc520_wdt.c
drivers/watchdog/via_wdt.c
drivers/watchdog/w83877f_wdt.c
drivers/xen/grant-table.c
fs/aio.c
fs/buffer.c
fs/crypto/keyinfo.c
fs/dcache.c
fs/direct-io.c
fs/exec.c
fs/fcntl.c
fs/file_table.c
fs/fs_pin.c
fs/fuse/dev.c
fs/inode.c
fs/namei.c
fs/namespace.c
fs/ncpfs/dir.c
fs/ncpfs/inode.c
fs/ncpfs/ncp_fs_sb.h
fs/ncpfs/sock.c
fs/nfs/dir.c
fs/overlayfs/ovl_entry.h
fs/overlayfs/readdir.c
fs/proc/array.c
fs/proc_namespace.c
fs/pstore/platform.c
fs/readdir.c
fs/splice.c
fs/userfaultfd.c
fs/xfs/xfs_log_priv.h
include/acpi/acexcep.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/actbl1.h
include/acpi/apei.h
include/acpi/pcc.h
include/asm-generic/atomic-long.h
include/asm-generic/div64.h
include/asm-generic/qrwlock.h
include/asm-generic/qrwlock_types.h
include/asm-generic/qspinlock.h
include/asm-generic/rwsem.h
include/asm-generic/vmlinux.lds.h
include/linux/acpi.h
include/linux/arch_topology.h
include/linux/atomic.h
include/linux/average.h
include/linux/bitmap.h
include/linux/bitops.h
include/linux/compiler-clang.h
include/linux/compiler-gcc.h
include/linux/compiler-intel.h
include/linux/compiler.h
include/linux/compiler_types.h [new file with mode: 0644]
include/linux/completion.h
include/linux/cpu.h
include/linux/cpufreq.h
include/linux/cpuhotplug.h
include/linux/cpumask.h
include/linux/dcache.h
include/linux/devfreq.h
include/linux/device.h
include/linux/dynamic_queue_limits.h
include/linux/freezer.h
include/linux/fs.h
include/linux/genetlink.h
include/linux/genhd.h
include/linux/gpio-fan.h [deleted file]
include/linux/huge_mm.h
include/linux/hypervisor.h
include/linux/ide.h
include/linux/if_team.h
include/linux/ioport.h
include/linux/ioprio.h
include/linux/irq.h
include/linux/irq_work.h
include/linux/irqchip/arm-gic-v3.h
include/linux/irqchip/arm-gic-v4.h
include/linux/irqchip/irq-omap-intc.h
include/linux/irqdesc.h
include/linux/irqdomain.h
include/linux/jump_label.h
include/linux/jump_label_ratelimit.h
include/linux/kallsyms.h
include/linux/kexec.h
include/linux/kprobes.h
include/linux/kthread.h
include/linux/ktime.h
include/linux/linkage.h
include/linux/llist.h
include/linux/lockdep.h
include/linux/log2.h
include/linux/math64.h
include/linux/mem_encrypt.h
include/linux/mfd/axp20x.h
include/linux/mfd/rtsx_pci.h
include/linux/mfd/tps65218.h
include/linux/mm.h
include/linux/mmc/host.h
include/linux/mmc/sdhci-pci-data.h
include/linux/mmzone.h
include/linux/module.h
include/linux/msi.h
include/linux/netfilter/nfnetlink.h
include/linux/parport.h
include/linux/pci.h
include/linux/percpu-defs.h
include/linux/perf_event.h
include/linux/platform_data/sht15.h [deleted file]
include/linux/pm.h
include/linux/pm_domain.h
include/linux/pm_opp.h
include/linux/pm_qos.h
include/linux/pm_runtime.h
include/linux/printk.h
include/linux/rculist.h
include/linux/rcupdate.h
include/linux/regmap.h
include/linux/regulator/da9211.h
include/linux/rtc.h
include/linux/rtnetlink.h
include/linux/rwlock.h
include/linux/rwlock_api_smp.h
include/linux/rwsem.h
include/linux/sched.h
include/linux/sched/isolation.h [new file with mode: 0644]
include/linux/sched/rt.h
include/linux/sched/sysctl.h
include/linux/skbuff.h
include/linux/spi/spi-fsl-dspi.h [new file with mode: 0644]
include/linux/spinlock.h
include/linux/spinlock_up.h
include/linux/sysctl.h
include/linux/tick.h
include/linux/time.h
include/linux/time32.h [new file with mode: 0644]
include/linux/time64.h
include/linux/timekeeper_internal.h
include/linux/timekeeping.h
include/linux/timekeeping32.h [new file with mode: 0644]
include/linux/timer.h
include/linux/workqueue.h
include/net/act_api.h
include/net/ip_vs.h
include/net/netfilter/nf_tables.h
include/net/pkt_cls.h
include/scsi/libfcoe.h
include/scsi/libsas.h
include/sound/seq_kernel.h
include/sound/timer.h
include/trace/events/irq_matrix.h [new file with mode: 0644]
include/trace/events/sched.h
include/uapi/drm/i915_drm.h
include/uapi/linux/elf.h
include/uapi/linux/stddef.h
include/uapi/linux/xattr.h
init/Kconfig
init/main.c
kernel/acct.c
kernel/bpf/arraymap.c
kernel/cgroup/cpuset.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/exit.c
kernel/extable.c
kernel/irq/Kconfig
kernel/irq/Makefile
kernel/irq/autoprobe.c
kernel/irq/chip.c
kernel/irq/debugfs.c
kernel/irq/internals.h
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/matrix.c [new file with mode: 0644]
kernel/irq/msi.c
kernel/irq/proc.c
kernel/irq/spurious.c
kernel/irq/timings.c
kernel/irq_work.c
kernel/jump_label.c
kernel/kallsyms.c
kernel/kexec_file.c
kernel/kprobes.c
kernel/kthread.c
kernel/locking/lockdep.c
kernel/locking/qrwlock.c
kernel/locking/qspinlock_paravirt.h
kernel/locking/rwsem.c
kernel/locking/spinlock.c
kernel/module.c
kernel/power/Kconfig
kernel/power/qos.c
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/power/swap.c
kernel/rcu/rcu.h
kernel/rcu/rcu_segcblist.c
kernel/rcu/rcutorture.c
kernel/rcu/tree.c
kernel/rcu/tree.h
kernel/rcu/tree_plugin.h
kernel/rcu/update.c
kernel/resource.c
kernel/sched/Makefile
kernel/sched/clock.c
kernel/sched/core.c
kernel/sched/cpufreq_schedutil.c
kernel/sched/cputime.c
kernel/sched/deadline.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/idle.c
kernel/sched/isolation.c [new file with mode: 0644]
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/topology.c
kernel/seccomp.c
kernel/smp.c
kernel/softirq.c
kernel/task_work.c
kernel/test_kprobes.c
kernel/time/Kconfig
kernel/time/clockevents.c
kernel/time/hrtimer.c
kernel/time/ntp.c
kernel/time/ntp_internal.h
kernel/time/posix-cpu-timers.c
kernel/time/posix-stubs.c
kernel/time/tick-oneshot.c
kernel/time/tick-sched.c
kernel/time/time.c
kernel/time/timekeeping.c
kernel/time/timekeeping.h
kernel/time/timer.c
kernel/trace/bpf_trace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.h
kernel/trace/trace_output.c
kernel/trace/trace_sched_wakeup.c
kernel/trace/trace_stack.c
kernel/user_namespace.c
kernel/watchdog.c
kernel/workqueue.c
kernel/workqueue_internal.h
lib/Kconfig.debug
lib/asn1_decoder.c
lib/assoc_array.c
lib/bitmap.c
lib/crc32.c
lib/crc4.c
lib/crc8.c
lib/div64.c
lib/dynamic_queue_limits.c
lib/gcd.c
lib/llist.c
lib/random32.c
lib/swiotlb.c
lib/vsprintf.c
mm/gup.c
mm/huge_memory.c
mm/memory.c
mm/slab.h
mm/sparse.c
net/8021q/vlan.c
net/atm/mpc.c
net/core/dev.c
net/core/netpoll.c
net/core/pktgen.c
net/core/skbuff.c
net/decnet/dn_route.c
net/dsa/switch.c
net/ipv4/inet_fragment.c
net/ipv4/route.c
net/ipv4/tcp_input.c
net/ipv4/tcp_offload.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_tunnel.c
net/ipv6/udp.c
net/l2tp/l2tp_ip.c
net/l2tp/l2tp_ip6.c
net/llc/llc_input.c
net/mac80211/sta_info.c
net/netfilter/ipvs/ip_vs_conn.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_est.c
net/netfilter/ipvs/ip_vs_lblc.c
net/netfilter/ipvs/ip_vs_lblcr.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nfnetlink_queue.c
net/netlabel/netlabel_calipso.c
net/netrom/nr_loopback.c
net/qrtr/qrtr.c
net/rds/ib_recv.c
net/sched/act_api.c
net/sched/act_bpf.c
net/sched/act_connmark.c
net/sched/act_csum.c
net/sched/act_gact.c
net/sched/act_ife.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_sample.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/act_skbmod.c
net/sched/act_tunnel_key.c
net/sched/act_vlan.c
net/sched/cls_api.c
net/sched/cls_basic.c
net/sched/cls_bpf.c
net/sched/cls_cgroup.c
net/sched/cls_flow.c
net/sched/cls_flower.c
net/sched/cls_fw.c
net/sched/cls_matchall.c
net/sched/cls_route.c
net/sched/cls_rsvp.h
net/sched/cls_tcindex.c
net/sched/cls_u32.c
net/wireless/nl80211.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_policy.c
samples/connector/cn_test.c
samples/kprobes/Makefile
samples/kprobes/jprobe_example.c [deleted file]
samples/kprobes/kprobe_example.c
samples/mic/mpssd/mpssd.c
scripts/Makefile.build
scripts/documentation-file-ref-check [new file with mode: 0755]
scripts/find-unused-docs.sh [new file with mode: 0755]
scripts/headers_install.sh
scripts/kernel-doc
scripts/leaking_addresses.pl [new file with mode: 0755]
scripts/mod/modpost.c
security/apparmor/include/lib.h
security/apparmor/ipc.c
security/apparmor/label.c
security/commoncap.c
security/integrity/digsig.c
security/integrity/evm/evm.h
security/integrity/evm/evm_crypto.c
security/integrity/evm/evm_main.c
security/integrity/evm/evm_secfs.c
security/integrity/iint.c
security/integrity/ima/ima_api.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/integrity.h
security/keys/gc.c
security/smack/smack_lsm.c
security/tomoyo/audit.c
security/tomoyo/common.c
security/tomoyo/common.h
security/tomoyo/util.c
sound/core/hrtimer.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/oss/seq_oss_readq.c
sound/core/seq/oss/seq_oss_readq.h
sound/core/timer.c
sound/firewire/amdtp-am824.c
sound/firewire/amdtp-stream.c
sound/firewire/amdtp-stream.h
sound/firewire/digi00x/amdtp-dot.c
sound/firewire/fireface/amdtp-ff.c
sound/firewire/fireface/ff-midi.c
sound/firewire/fireface/ff-transaction.c
sound/firewire/isight.c
sound/firewire/motu/amdtp-motu.c
sound/firewire/oxfw/oxfw-scs1x.c
sound/firewire/tascam/amdtp-tascam.c
sound/firewire/tascam/tascam-transaction.c
sound/oss/midibuf.c
sound/oss/soundcard.c
sound/oss/sys_timer.c
sound/oss/uart6850.c
sound/pci/hda/patch_realtek.c
sound/soc/xtensa/xtfpga-i2s.c
sound/usb/bcd2000/bcd2000.c
sound/usb/quirks.c
tools/arch/x86/include/asm/atomic.h
tools/include/asm-generic/atomic-gcc.h
tools/include/linux/poison.h
tools/include/uapi/drm/i915_drm.h
tools/include/uapi/linux/kcmp.h [new file with mode: 0644]
tools/include/uapi/linux/prctl.h [new file with mode: 0644]
tools/objtool/check.c
tools/objtool/objtool.c
tools/perf/Documentation/perf-list.txt
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-sched.txt
tools/perf/Documentation/perf-script.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Makefile.perf
tools/perf/arch/arm/annotate/instructions.c
tools/perf/arch/arm64/annotate/instructions.c
tools/perf/arch/powerpc/annotate/instructions.c
tools/perf/arch/s390/annotate/instructions.c
tools/perf/arch/x86/annotate/instructions.c
tools/perf/arch/x86/include/arch-tests.h
tools/perf/arch/x86/tests/Build
tools/perf/arch/x86/tests/arch-tests.c
tools/perf/builtin-annotate.c
tools/perf/builtin-buildid-cache.c
tools/perf/builtin-buildid-list.c
tools/perf/builtin-c2c.c
tools/perf/builtin-config.c
tools/perf/builtin-diff.c
tools/perf/builtin-evlist.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-list.c
tools/perf/builtin-lock.c
tools/perf/builtin-mem.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/check-headers.sh
tools/perf/perf.h
tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/goldmontplus/cache.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/goldmontplus/frontend.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/goldmontplus/memory.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/goldmontplus/other.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/goldmontplus/pipeline.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/goldmontplus/virtual-memory.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/mapfile.csv
tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json [new file with mode: 0644]
tools/perf/pmu-events/jevents.c
tools/perf/pmu-events/jevents.h
tools/perf/pmu-events/pmu-events.h
tools/perf/tests/attr.c
tools/perf/tests/attr.py
tools/perf/tests/attr/base-record
tools/perf/tests/attr/test-record-group
tools/perf/tests/attr/test-record-group-sampling
tools/perf/tests/attr/test-record-group1
tools/perf/tests/attr/test-stat-C0
tools/perf/tests/attr/test-stat-basic
tools/perf/tests/attr/test-stat-default
tools/perf/tests/attr/test-stat-detailed-1
tools/perf/tests/attr/test-stat-detailed-2
tools/perf/tests/attr/test-stat-detailed-3
tools/perf/tests/attr/test-stat-group
tools/perf/tests/attr/test-stat-group1
tools/perf/tests/attr/test-stat-no-inherit
tools/perf/tests/builtin-test.c
tools/perf/tests/mmap-thread-lookup.c
tools/perf/tests/topology.c
tools/perf/trace/beauty/Build
tools/perf/trace/beauty/beauty.h
tools/perf/trace/beauty/kcmp.c [new file with mode: 0644]
tools/perf/trace/beauty/kcmp_type.sh [new file with mode: 0755]
tools/perf/trace/beauty/madvise_behavior.sh [new file with mode: 0755]
tools/perf/trace/beauty/mmap.c
tools/perf/trace/beauty/prctl.c [new file with mode: 0644]
tools/perf/trace/beauty/prctl_option.sh [new file with mode: 0755]
tools/perf/ui/browsers/hists.c
tools/perf/ui/progress.c
tools/perf/ui/progress.h
tools/perf/ui/stdio/hist.c
tools/perf/ui/tui/progress.c
tools/perf/util/Build
tools/perf/util/annotate.c
tools/perf/util/auxtrace.c
tools/perf/util/auxtrace.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/comm.c
tools/perf/util/config.c
tools/perf/util/data-convert-bt.c
tools/perf/util/data.c
tools/perf/util/data.h
tools/perf/util/debug.c
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/evsel_fprintf.c
tools/perf/util/header.c
tools/perf/util/hist.c
tools/perf/util/intel-bts.c
tools/perf/util/intel-pt.c
tools/perf/util/jit.h
tools/perf/util/jitdump.c
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/metricgroup.c [new file with mode: 0644]
tools/perf/util/metricgroup.h [new file with mode: 0644]
tools/perf/util/mmap.c [new file with mode: 0644]
tools/perf/util/mmap.h [new file with mode: 0644]
tools/perf/util/namespaces.c
tools/perf/util/namespaces.h
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.l
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/print_binary.c
tools/perf/util/print_binary.h
tools/perf/util/probe-file.c
tools/perf/util/python-ext-sources
tools/perf/util/rb_resort.h
tools/perf/util/rwsem.c [new file with mode: 0644]
tools/perf/util/rwsem.h [new file with mode: 0644]
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/srcline.c
tools/perf/util/srcline.h
tools/perf/util/stat-shadow.c
tools/perf/util/stat.c
tools/perf/util/stat.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/top.h
tools/perf/util/trace-event-info.c
tools/perf/util/trace-event-read.c
tools/perf/util/util.c
tools/perf/util/util.h
tools/perf/util/vdso.c
tools/perf/util/zlib.c
tools/power/acpi/tools/acpidump/Makefile
tools/power/acpi/tools/acpidump/apdump.c
tools/power/acpi/tools/acpidump/apmain.c
tools/power/cpupower/.gitignore
tools/power/cpupower/Makefile
tools/power/cpupower/utils/cpufreq-info.c
tools/testing/selftests/powerpc/dscr/dscr.h
tools/testing/selftests/powerpc/dscr/dscr_default_test.c
tools/testing/selftests/rcutorture/bin/config_override.sh
tools/testing/selftests/rcutorture/bin/configcheck.sh
tools/testing/selftests/rcutorture/bin/configinit.sh
tools/testing/selftests/rcutorture/bin/kvm-build.sh
tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
tools/testing/selftests/rcutorture/bin/kvm.sh
tools/testing/selftests/rcutorture/bin/parse-build.sh
tools/testing/selftests/rcutorture/bin/parse-torture.sh
tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/barriers.h
tools/testing/selftests/x86/entry_from_vm86.c
tools/testing/selftests/x86/ldt_gdt.c
tools/testing/selftests/x86/protection_keys.c
tools/virtio/ringtest/main.h
virt/kvm/kvm_main.c

index 4757d361fd333ee109a5c09bf825bb3a89ebf01a..c021f29779a7a1cce57d5c6aa36ee271a745e47a 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -102,6 +102,7 @@ Leonid I Ananiev <leonid.i.ananiev@intel.com>
 Linas Vepstas <linas@austin.ibm.com>
 Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@web.de>
 Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
+Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com>
 Marcin Nowakowski <marcin.nowakowski@mips.com> <marcin.nowakowski@imgtec.com>
 Mark Brown <broonie@sirena.org.uk>
 Martin Kepplinger <martink@posteo.de> <martin.kepplinger@theobroma-systems.com>
diff --git a/CREDITS b/CREDITS
index 9fbd2c77b5462d71dd9d24b5966c03d528094ce6..a3ec0c744172439331561531dad8eb71ad92f0f2 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2113,6 +2113,10 @@ S: J. Obrechtstr 23
 S: NL-5216 GP 's-Hertogenbosch
 S: The Netherlands
 
+N: Ashley Lai
+E: ashleydlai@gmail.com
+D: IBM VTPM driver
+
 N: Savio Lam
 E: lam836@cs.cuhk.hk
 D: Author of the dialog utility, foundation
@@ -3333,6 +3337,10 @@ S: Braunschweiger Strasse 79
 S: 31134 Hildesheim
 S: Germany
 
+N: Marcel Selhorst
+E: tpmdd@selhorst.net
+D: TPM driver
+
 N: Darren Senn
 E: sinster@darkwater.com
 D: Whatever I notice needs doing (so far: itimers, /proc)
@@ -4128,7 +4136,6 @@ D: MD driver
 D: EISA/sysfs subsystem
 S: France
 
-
 # Don't add your name here, unless you really _are_ after Marc
 # alphabetically. Leonard used to be very proud of being the 
 # last entry, and he'll get positively pissed if he can't even
index 35c457f8ce736403a8af48fb1952f9aa7706e1da..4404bd9b96c1972336b02707346f951fc3642a6b 100644 (file)
@@ -1,5 +1,5 @@
 # Note: This documents additional properties of any device beyond what
-# is documented in Documentation/sysfs-rules.txt
+# is documented in Documentation/admin-guide/sysfs-rules.rst
 
 What:          /sys/devices/*/of_node
 Date:          February 2015
index 8374d4557e5dc0c3293775abaf369e92b91893a4..9578247e17929bf4fcd6bd50b185f955031dc96d 100644 (file)
@@ -7,17 +7,37 @@ Description:
                HMAC-sha1 value across the extended attributes, storing the
                value as the extended attribute 'security.evm'.
 
-               EVM depends on the Kernel Key Retention System to provide it
-               with a trusted/encrypted key for the HMAC-sha1 operation.
-               The key is loaded onto the root's keyring using keyctl.  Until
-               EVM receives notification that the key has been successfully
-               loaded onto the keyring (echo 1 > <securityfs>/evm), EVM
-               can not create or validate the 'security.evm' xattr, but
-               returns INTEGRITY_UNKNOWN.  Loading the key and signaling EVM
-               should be done as early as possible.  Normally this is done
-               in the initramfs, which has already been measured as part
-               of the trusted boot.  For more information on creating and
-               loading existing trusted/encrypted keys, refer to:
-               Documentation/keys-trusted-encrypted.txt.  (A sample dracut
-               patch, which loads the trusted/encrypted key and enables
-               EVM, is available from http://linux-ima.sourceforge.net/#EVM.)
+               EVM supports two classes of security.evm. The first is
+               an HMAC-sha1 generated locally with a
+               trusted/encrypted key stored in the Kernel Key
+               Retention System. The second is a digital signature
+               generated either locally or remotely using an
+               asymmetric key. These keys are loaded onto root's
+               keyring using keyctl, and EVM is then enabled by
+               echoing a value to <securityfs>/evm:
+
+               1: enable HMAC validation and creation
+               2: enable digital signature validation
+               3: enable HMAC and digital signature validation and HMAC
+                  creation
+
+               Further writes will be blocked if HMAC support is enabled or
+               if bit 32 is set:
+
+               echo 0x80000002 ><securityfs>/evm
+
+               will enable digital signature validation and block
+               further writes to <securityfs>/evm.
+
+               Until this is done, EVM can not create or validate the
+               'security.evm' xattr, but returns INTEGRITY_UNKNOWN.
+               Loading keys and signaling EVM should be done as early
+               as possible.  Normally this is done in the initramfs,
+               which has already been measured as part of the trusted
+               boot.  For more information on creating and loading
+               existing trusted/encrypted keys, refer to:
+
+               Documentation/security/keys/trusted-encrypted.rst. Both dracut
+               (via 97masterkey and 98integrity) and systemd (via
+               core/ima-setup) have support for loading keys at boot
+               time.
diff --git a/Documentation/ABI/testing/sysfs-bus-mmc b/Documentation/ABI/testing/sysfs-bus-mmc
new file mode 100644 (file)
index 0000000..519f028
--- /dev/null
@@ -0,0 +1,4 @@
+What:          /sys/bus/mmc/devices/.../rev
+Date:          October 2017
+Contact:       Jin Qian <jinqian@android.com>
+Description:   Extended CSD revision number
index 676fdf5f2a99af0ee623eeef4b2938c1c1c8924f..80a00f7b666709d7edf3c0296753959dd802bcf9 100644 (file)
@@ -211,7 +211,9 @@ Description:
                device, after it has been suspended at run time, from a resume
                request to the moment the device will be ready to process I/O,
                in microseconds.  If it is equal to 0, however, this means that
-               the PM QoS resume latency may be arbitrary.
+               the PM QoS resume latency may be arbitrary and the special value
+               "n/a" means that user space cannot accept any resume latency at
+               all for the given device.
 
                Not all drivers support this attribute.  If it isn't supported,
                it is not present.
@@ -258,19 +260,3 @@ Description:
 
                This attribute has no effect on system-wide suspend/resume and
                hibernation.
-
-What:          /sys/devices/.../power/pm_qos_remote_wakeup
-Date:          September 2012
-Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
-Description:
-               The /sys/devices/.../power/pm_qos_remote_wakeup attribute
-               is used for manipulating the PM QoS "remote wakeup required"
-               flag.  If set, this flag indicates to the kernel that the
-               device is a source of user events that have to be signaled from
-               its low-power states.
-
-               Not all drivers support this attribute.  If it isn't supported,
-               it is not present.
-
-               This attribute has no effect on system-wide suspend/resume and
-               hibernation.
index f3d5817c4ef0fae54150bc3e772e7cc535bde805..d6d862db3b5d65fe09c26783298bba21ceec5558 100644 (file)
@@ -187,7 +187,8 @@ Description:        Processor frequency boosting control
                This switch controls the boost setting for the whole system.
                Boosting allows the CPU and the firmware to run at a frequency
                beyound it's nominal limit.
-               More details can be found in Documentation/cpu-freq/boost.txt
+               More details can be found in
+               Documentation/admin-guide/pm/cpufreq.rst
 
 
 What:          /sys/devices/system/cpu/cpu#/crash_notes
@@ -223,7 +224,8 @@ Description:        Parameters for the Intel P-state driver
                no_turbo: limits the driver to selecting P states below the turbo
                frequency range.
 
-               More details can be found in Documentation/cpu-freq/intel-pstate.txt
+               More details can be found in
+               Documentation/admin-guide/pm/intel_pstate.rst
 
 What:          /sys/devices/system/cpu/cpu*/cache/index*/<set_of_attributes_mentioned_below>
 Date:          July 2014(documented, existed before August 2008)
index a1d1612f36519f832c2d307293527083cf025271..1e0d1dac706bb6cb45d079d13019be06a4ed4788 100644 (file)
@@ -18,7 +18,8 @@ Description:
                Writing one of the above strings to this file causes the system
                to transition into the corresponding state, if available.
 
-               See Documentation/power/states.txt for more information.
+               See Documentation/admin-guide/pm/sleep-states.rst for more
+               information.
 
 What:          /sys/power/mem_sleep
 Date:          November 2016
@@ -35,7 +36,8 @@ Description:
                represented by it to be used on subsequent attempts to suspend
                the system.
 
-               See Documentation/power/states.txt for more information.
+               See Documentation/admin-guide/pm/sleep-states.rst for more
+               information.
 
 What:          /sys/power/disk
 Date:          September 2006
index 85f7856f009203d9e7d15487e452a8b9771c3784..2ca77ad0f2388c24f5954bc328437c431476c202 100644 (file)
@@ -97,6 +97,9 @@ endif # HAVE_SPHINX
 # The following targets are independent of HAVE_SPHINX, and the rules should
 # work or silently pass without Sphinx.
 
+refcheckdocs:
+       $(Q)cd $(srctree);scripts/documentation-file-ref-check
+
 cleandocs:
        $(Q)rm -rf $(BUILDDIR)
        $(Q)$(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/media clean
@@ -109,6 +112,7 @@ dochelp:
        @echo  '  epubdocs        - EPUB'
        @echo  '  xmldocs         - XML'
        @echo  '  linkcheckdocs   - check for broken external links (will connect to external hosts)'
+       @echo  '  refcheckdocs    - check for references to non-existing files under Documentation'
        @echo  '  cleandocs       - clean all generated files'
        @echo
        @echo  '  make SPHINXDIRS="s1 s2" [target] Generate only docs of folder s1, s2'
@@ -116,3 +120,5 @@ dochelp:
        @echo
        @echo  '  make SPHINX_CONF={conf-file} [target] use *additional* sphinx-build'
        @echo  '  configuration. This is e.g. useful to build with nit-picking config.'
+       @echo
+       @echo  '  Default location for the generated documents is Documentation/output'
index e5d0bbd0230b4954a8d6aae50f77ce9446640255..7394f034be65dec6e3e12f52ffb1371121155d1e 100644 (file)
@@ -527,7 +527,7 @@ grace period also drove it to completion.
 This straightforward approach had the disadvantage of needing to
 account for POSIX signals sent to user tasks,
 so more recent implemementations use the Linux kernel's
-<a href="https://www.kernel.org/doc/Documentation/workqueue.txt">workqueues</a>.
+<a href="https://www.kernel.org/doc/Documentation/core-api/workqueue.rst">workqueues</a>.
 
 <p>
 The requesting task still does counter snapshotting and funnel-lock
diff --git a/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Diagram.html b/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Diagram.html
new file mode 100644 (file)
index 0000000..e5b42a7
--- /dev/null
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+        <html>
+        <head><title>A Diagram of TREE_RCU's Grace-Period Memory Ordering</title>
+        <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+
+<p><img src="TreeRCU-gp.svg" alt="TreeRCU-gp.svg">
+
+</body></html>
diff --git a/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.html b/Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.html
new file mode 100644 (file)
index 0000000..8651b0b
--- /dev/null
@@ -0,0 +1,707 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+        <html>
+        <head><title>A Tour Through TREE_RCU's Grace-Period Memory Ordering</title>
+        <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+
+           <p>August 8, 2017</p>
+           <p>This article was contributed by Paul E.&nbsp;McKenney</p>
+
+<h3>Introduction</h3>
+
+<p>This document gives a rough visual overview of how Tree RCU's
+grace-period memory ordering guarantee is provided.
+
+<ol>
+<li>   <a href="#What Is Tree RCU's Grace Period Memory Ordering Guarantee?">
+       What Is Tree RCU's Grace Period Memory Ordering Guarantee?</a>
+<li>   <a href="#Tree RCU Grace Period Memory Ordering Building Blocks">
+       Tree RCU Grace Period Memory Ordering Building Blocks</a>
+<li>   <a href="#Tree RCU Grace Period Memory Ordering Components">
+       Tree RCU Grace Period Memory Ordering Components</a>
+<li>   <a href="#Putting It All Together">Putting It All Together</a>
+</ol>
+
+<h3><a name="What Is Tree RCU's Grace Period Memory Ordering Guarantee?">
+What Is Tree RCU's Grace Period Memory Ordering Guarantee?</a></h3>
+
+<p>RCU grace periods provide extremely strong memory-ordering guarantees
+for non-idle non-offline code.
+Any code that happens after the end of a given RCU grace period is guaranteed
+to see the effects of all accesses prior to the beginning of that grace
+period that are within RCU read-side critical sections.
+Similarly, any code that happens before the beginning of a given RCU grace
+period is guaranteed to see the effects of all accesses following the end
+of that grace period that are within RCU read-side critical sections.
+
+<p>This guarantee is particularly pervasive for <tt>synchronize_sched()</tt>,
+for which RCU-sched read-side critical sections include any region
+of code for which preemption is disabled.
+Given that each individual machine instruction can be thought of as
+an extremely small region of preemption-disabled code, one can think of
+<tt>synchronize_sched()</tt> as <tt>smp_mb()</tt> on steroids.
+
+<p>RCU updaters use this guarantee by splitting their updates into
+two phases, one of which is executed before the grace period and
+the other of which is executed after the grace period.
+In the most common use case, phase one removes an element from
+a linked RCU-protected data structure, and phase two frees that element.
+For this to work, any readers that have witnessed state prior to the
+phase-one update (in the common case, removal) must not witness state
+following the phase-two update (in the common case, freeing).
+
+<p>The RCU implementation provides this guarantee using a network
+of lock-based critical sections, memory barriers, and per-CPU
+processing, as is described in the following sections.
+
+<h3><a name="Tree RCU Grace Period Memory Ordering Building Blocks">
+Tree RCU Grace Period Memory Ordering Building Blocks</a></h3>
+
+<p>The workhorse for RCU's grace-period memory ordering is the
+critical section for the <tt>rcu_node</tt> structure's
+<tt>-&gt;lock</tt>.
+These critical sections use helper functions for lock acquisition, including
+<tt>raw_spin_lock_rcu_node()</tt>,
+<tt>raw_spin_lock_irq_rcu_node()</tt>, and
+<tt>raw_spin_lock_irqsave_rcu_node()</tt>.
+Their lock-release counterparts are
+<tt>raw_spin_unlock_rcu_node()</tt>,
+<tt>raw_spin_unlock_irq_rcu_node()</tt>, and
+<tt>raw_spin_unlock_irqrestore_rcu_node()</tt>,
+respectively.
+For completeness, a
+<tt>raw_spin_trylock_rcu_node()</tt>
+is also provided.
+The key point is that the lock-acquisition functions, including
+<tt>raw_spin_trylock_rcu_node()</tt>, all invoke
+<tt>smp_mb__after_unlock_lock()</tt> immediately after successful
+acquisition of the lock.
+
+<p>Therefore, for any given <tt>rcu_node</tt> struction, any access
+happening before one of the above lock-release functions will be seen
+by all CPUs as happening before any access happening after a later
+one of the above lock-acquisition functions.
+Furthermore, any access happening before one of the
+above lock-release function on any given CPU will be seen by all
+CPUs as happening before any access happening after a later one
+of the above lock-acquisition functions executing on that same CPU,
+even if the lock-release and lock-acquisition functions are operating
+on different <tt>rcu_node</tt> structures.
+Tree RCU uses these two ordering guarantees to form an ordering
+network among all CPUs that were in any way involved in the grace
+period, including any CPUs that came online or went offline during
+the grace period in question.
+
+<p>The following litmus test exhibits the ordering effects of these
+lock-acquisition and lock-release functions:
+
+<pre>
+ 1 int x, y, z;
+ 2
+ 3 void task0(void)
+ 4 {
+ 5   raw_spin_lock_rcu_node(rnp);
+ 6   WRITE_ONCE(x, 1);
+ 7   r1 = READ_ONCE(y);
+ 8   raw_spin_unlock_rcu_node(rnp);
+ 9 }
+10
+11 void task1(void)
+12 {
+13   raw_spin_lock_rcu_node(rnp);
+14   WRITE_ONCE(y, 1);
+15   r2 = READ_ONCE(z);
+16   raw_spin_unlock_rcu_node(rnp);
+17 }
+18
+19 void task2(void)
+20 {
+21   WRITE_ONCE(z, 1);
+22   smp_mb();
+23   r3 = READ_ONCE(x);
+24 }
+25
+26 WARN_ON(r1 == 0 &amp;&amp; r2 == 0 &amp;&amp; r3 == 0);
+</pre>
+
+<p>The <tt>WARN_ON()</tt> is evaluated at &ldquo;the end of time&rdquo;,
+after all changes have propagated throughout the system.
+Without the <tt>smp_mb__after_unlock_lock()</tt> provided by the
+acquisition functions, this <tt>WARN_ON()</tt> could trigger, for example
+on PowerPC.
+The <tt>smp_mb__after_unlock_lock()</tt> invocations prevent this
+<tt>WARN_ON()</tt> from triggering.
+
+<p>This approach must be extended to include idle CPUs, which need
+RCU's grace-period memory ordering guarantee to extend to any
+RCU read-side critical sections preceding and following the current
+idle sojourn.
+This case is handled by calls to the strongly ordered
+<tt>atomic_add_return()</tt> read-modify-write atomic operation that
+is invoked within <tt>rcu_dynticks_eqs_enter()</tt> at idle-entry
+time and within <tt>rcu_dynticks_eqs_exit()</tt> at idle-exit time.
+The grace-period kthread invokes <tt>rcu_dynticks_snap()</tt> and
+<tt>rcu_dynticks_in_eqs_since()</tt> (both of which invoke
+an <tt>atomic_add_return()</tt> of zero) to detect idle CPUs.
+
+<table>
+<tr><th>&nbsp;</th></tr>
+<tr><th align="left">Quick Quiz:</th></tr>
+<tr><td>
+       But what about CPUs that remain offline for the entire
+       grace period?
+</td></tr>
+<tr><th align="left">Answer:</th></tr>
+<tr><td bgcolor="#ffffff"><font color="ffffff">
+       Such CPUs will be offline at the beginning of the grace period,
+       so the grace period won't expect quiescent states from them.
+       Races between grace-period start and CPU-hotplug operations
+       are mediated by the CPU's leaf <tt>rcu_node</tt> structure's
+       <tt>-&gt;lock</tt> as described above.
+</font></td></tr>
+<tr><td>&nbsp;</td></tr>
+</table>
+
+<p>The approach must be extended to handle one final case, that
+of waking a task blocked in <tt>synchronize_rcu()</tt>.
+This task might be affinitied to a CPU that is not yet aware that
+the grace period has ended, and thus might not yet be subject to
+the grace period's memory ordering.
+Therefore, there is an <tt>smp_mb()</tt> after the return from
+<tt>wait_for_completion()</tt> in the <tt>synchronize_rcu()</tt>
+code path.
+
+<table>
+<tr><th>&nbsp;</th></tr>
+<tr><th align="left">Quick Quiz:</th></tr>
+<tr><td>
+       What?  Where???
+       I don't see any <tt>smp_mb()</tt> after the return from
+       <tt>wait_for_completion()</tt>!!!
+</td></tr>
+<tr><th align="left">Answer:</th></tr>
+<tr><td bgcolor="#ffffff"><font color="ffffff">
+       That would be because I spotted the need for that
+       <tt>smp_mb()</tt> during the creation of this documentation,
+       and it is therefore unlikely to hit mainline before v4.14.
+       Kudos to Lance Roy, Will Deacon, Peter Zijlstra, and
+       Jonathan Cameron for asking questions that sensitized me
+       to the rather elaborate sequence of events that demonstrate
+       the need for this memory barrier.
+</font></td></tr>
+<tr><td>&nbsp;</td></tr>
+</table>
+
+<p>Tree RCU's grace--period memory-ordering guarantees rely most
+heavily on the <tt>rcu_node</tt> structure's <tt>-&gt;lock</tt>
+field, so much so that it is necessary to abbreviate this pattern
+in the diagrams in the next section.
+For example, consider the <tt>rcu_prepare_for_idle()</tt> function
+shown below, which is one of several functions that enforce ordering
+of newly arrived RCU callbacks against future grace periods:
+
+<pre>
+ 1 static void rcu_prepare_for_idle(void)
+ 2 {
+ 3   bool needwake;
+ 4   struct rcu_data *rdp;
+ 5   struct rcu_dynticks *rdtp = this_cpu_ptr(&amp;rcu_dynticks);
+ 6   struct rcu_node *rnp;
+ 7   struct rcu_state *rsp;
+ 8   int tne;
+ 9
+10   if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_ALL) ||
+11       rcu_is_nocb_cpu(smp_processor_id()))
+12     return;
+13   tne = READ_ONCE(tick_nohz_active);
+14   if (tne != rdtp-&gt;tick_nohz_enabled_snap) {
+15     if (rcu_cpu_has_callbacks(NULL))
+16       invoke_rcu_core();
+17     rdtp-&gt;tick_nohz_enabled_snap = tne;
+18     return;
+19   }
+20   if (!tne)
+21     return;
+22   if (rdtp-&gt;all_lazy &amp;&amp;
+23       rdtp-&gt;nonlazy_posted != rdtp-&gt;nonlazy_posted_snap) {
+24     rdtp-&gt;all_lazy = false;
+25     rdtp-&gt;nonlazy_posted_snap = rdtp-&gt;nonlazy_posted;
+26     invoke_rcu_core();
+27     return;
+28   }
+29   if (rdtp-&gt;last_accelerate == jiffies)
+30     return;
+31   rdtp-&gt;last_accelerate = jiffies;
+32   for_each_rcu_flavor(rsp) {
+33     rdp = this_cpu_ptr(rsp-&gt;rda);
+34     if (rcu_segcblist_pend_cbs(&amp;rdp-&gt;cblist))
+35       continue;
+36     rnp = rdp-&gt;mynode;
+37     raw_spin_lock_rcu_node(rnp);
+38     needwake = rcu_accelerate_cbs(rsp, rnp, rdp);
+39     raw_spin_unlock_rcu_node(rnp);
+40     if (needwake)
+41       rcu_gp_kthread_wake(rsp);
+42   }
+43 }
+</pre>
+
+<p>But the only part of <tt>rcu_prepare_for_idle()</tt> that really
+matters for this discussion are lines&nbsp;37&ndash;39.
+We will therefore abbreviate this function as follows:
+
+</p><p><img src="rcu_node-lock.svg" alt="rcu_node-lock.svg">
+
+<p>The box represents the <tt>rcu_node</tt> structure's <tt>-&gt;lock</tt>
+critical section, with the double line on top representing the additional
+<tt>smp_mb__after_unlock_lock()</tt>.
+
+<h3><a name="Tree RCU Grace Period Memory Ordering Components">
+Tree RCU Grace Period Memory Ordering Components</a></h3>
+
+<p>Tree RCU's grace-period memory-ordering guarantee is provided by
+a number of RCU components:
+
+<ol>
+<li>   <a href="#Callback Registry">Callback Registry</a>
+<li>   <a href="#Grace-Period Initialization">Grace-Period Initialization</a>
+<li>   <a href="#Self-Reported Quiescent States">
+       Self-Reported Quiescent States</a>
+<li>   <a href="#Dynamic Tick Interface">Dynamic Tick Interface</a>
+<li>   <a href="#CPU-Hotplug Interface">CPU-Hotplug Interface</a>
+<li>   <a href="Forcing Quiescent States">Forcing Quiescent States</a>
+<li>   <a href="Grace-Period Cleanup">Grace-Period Cleanup</a>
+<li>   <a href="Callback Invocation">Callback Invocation</a>
+</ol>
+
+<p>Each of the following section looks at the corresponding component
+in detail.
+
+<h4><a name="Callback Registry">Callback Registry</a></h4>
+
+<p>If RCU's grace-period guarantee is to mean anything at all, any
+access that happens before a given invocation of <tt>call_rcu()</tt>
+must also happen before the corresponding grace period.
+The implementation of this portion of RCU's grace period guarantee
+is shown in the following figure:
+
+</p><p><img src="TreeRCU-callback-registry.svg" alt="TreeRCU-callback-registry.svg">
+
+<p>Because <tt>call_rcu()</tt> normally acts only on CPU-local state,
+it provides no ordering guarantees, either for itself or for
+phase one of the update (which again will usually be removal of
+an element from an RCU-protected data structure).
+It simply enqueues the <tt>rcu_head</tt> structure on a per-CPU list,
+which cannot become associated with a grace period until a later
+call to <tt>rcu_accelerate_cbs()</tt>, as shown in the diagram above.
+
+<p>One set of code paths shown on the left invokes
+<tt>rcu_accelerate_cbs()</tt> via
+<tt>note_gp_changes()</tt>, either directly from <tt>call_rcu()</tt> (if
+the current CPU is inundated with queued <tt>rcu_head</tt> structures)
+or more likely from an <tt>RCU_SOFTIRQ</tt> handler.
+Another code path in the middle is taken only in kernels built with
+<tt>CONFIG_RCU_FAST_NO_HZ=y</tt>, which invokes
+<tt>rcu_accelerate_cbs()</tt> via <tt>rcu_prepare_for_idle()</tt>.
+The final code path on the right is taken only in kernels built with
+<tt>CONFIG_HOTPLUG_CPU=y</tt>, which invokes
+<tt>rcu_accelerate_cbs()</tt> via
+<tt>rcu_advance_cbs()</tt>, <tt>rcu_migrate_callbacks</tt>,
+<tt>rcutree_migrate_callbacks()</tt>, and <tt>takedown_cpu()</tt>,
+which in turn is invoked on a surviving CPU after the outgoing
+CPU has been completely offlined.
+
+<p>There are a few other code paths within grace-period processing
+that opportunistically invoke <tt>rcu_accelerate_cbs()</tt>.
+However, either way, all of the CPU's recently queued <tt>rcu_head</tt>
+structures are associated with a future grace-period number under
+the protection of the CPU's lead <tt>rcu_node</tt> structure's
+<tt>-&gt;lock</tt>.
+In all cases, there is full ordering against any prior critical section
+for that same <tt>rcu_node</tt> structure's <tt>-&gt;lock</tt>, and
+also full ordering against any of the current task's or CPU's prior critical
+sections for any <tt>rcu_node</tt> structure's <tt>-&gt;lock</tt>.
+
+<p>The next section will show how this ordering ensures that any
+accesses prior to the <tt>call_rcu()</tt> (particularly including phase
+one of the update)
+happen before the start of the corresponding grace period.
+
+<table>
+<tr><th>&nbsp;</th></tr>
+<tr><th align="left">Quick Quiz:</th></tr>
+<tr><td>
+       But what about <tt>synchronize_rcu()</tt>?
+</td></tr>
+<tr><th align="left">Answer:</th></tr>
+<tr><td bgcolor="#ffffff"><font color="ffffff">
+       The <tt>synchronize_rcu()</tt> passes <tt>call_rcu()</tt>
+       to <tt>wait_rcu_gp()</tt>, which invokes it.
+       So either way, it eventually comes down to <tt>call_rcu()</tt>.
+</font></td></tr>
+<tr><td>&nbsp;</td></tr>
+</table>
+
+<h4><a name="Grace-Period Initialization">Grace-Period Initialization</a></h4>
+
+<p>Grace-period initialization is carried out by
+the grace-period kernel thread, which makes several passes over the
+<tt>rcu_node</tt> tree within the <tt>rcu_gp_init()</tt> function.
+This means that showing the full flow of ordering through the
+grace-period computation will require duplicating this tree.
+If you find this confusing, please note that the state of the
+<tt>rcu_node</tt> changes over time, just like Heraclitus's river.
+However, to keep the <tt>rcu_node</tt> river tractable, the
+grace-period kernel thread's traversals are presented in multiple
+parts, starting in this section with the various phases of
+grace-period initialization.
+
+<p>The first ordering-related grace-period initialization action is to
+increment the <tt>rcu_state</tt> structure's <tt>-&gt;gpnum</tt>
+grace-period-number counter, as shown below:
+
+</p><p><img src="TreeRCU-gp-init-1.svg" alt="TreeRCU-gp-init-1.svg" width="75%">
+
+<p>The actual increment is carried out using <tt>smp_store_release()</tt>,
+which helps reject false-positive RCU CPU stall detection.
+Note that only the root <tt>rcu_node</tt> structure is touched.
+
+<p>The first pass through the <tt>rcu_node</tt> tree updates bitmasks
+based on CPUs having come online or gone offline since the start of
+the previous grace period.
+In the common case where the number of online CPUs for this <tt>rcu_node</tt>
+structure has not transitioned to or from zero,
+this pass will scan only the leaf <tt>rcu_node</tt> structures.
+However, if the number of online CPUs for a given leaf <tt>rcu_node</tt>
+structure has transitioned from zero,
+<tt>rcu_init_new_rnp()</tt> will be invoked for the first incoming CPU.
+Similarly, if the number of online CPUs for a given leaf <tt>rcu_node</tt>
+structure has transitioned to zero,
+<tt>rcu_cleanup_dead_rnp()</tt> will be invoked for the last outgoing CPU.
+The diagram below shows the path of ordering if the leftmost
+<tt>rcu_node</tt> structure onlines its first CPU and if the next
+<tt>rcu_node</tt> structure has no online CPUs
+(or, alternatively if the leftmost <tt>rcu_node</tt> structure offlines
+its last CPU and if the next <tt>rcu_node</tt> structure has no online CPUs).
+
+</p><p><img src="TreeRCU-gp-init-2.svg" alt="TreeRCU-gp-init-1.svg" width="75%">
+
+<p>The final <tt>rcu_gp_init()</tt> pass through the <tt>rcu_node</tt>
+tree traverses breadth-first, setting each <tt>rcu_node</tt> structure's
+<tt>-&gt;gpnum</tt> field to the newly incremented value from the
+<tt>rcu_state</tt> structure, as shown in the following diagram.
+
+</p><p><img src="TreeRCU-gp-init-3.svg" alt="TreeRCU-gp-init-1.svg" width="75%">
+
+<p>This change will also cause each CPU's next call to
+<tt>__note_gp_changes()</tt>
+to notice that a new grace period has started, as described in the next
+section.
+But because the grace-period kthread started the grace period at the
+root (with the increment of the <tt>rcu_state</tt> structure's
+<tt>-&gt;gpnum</tt> field) before setting each leaf <tt>rcu_node</tt>
+structure's <tt>-&gt;gpnum</tt> field, each CPU's observation of
+the start of the grace period will happen after the actual start
+of the grace period.
+
+<table>
+<tr><th>&nbsp;</th></tr>
+<tr><th align="left">Quick Quiz:</th></tr>
+<tr><td>
+       But what about the CPU that started the grace period?
+       Why wouldn't it see the start of the grace period right when
+       it started that grace period?
+</td></tr>
+<tr><th align="left">Answer:</th></tr>
+<tr><td bgcolor="#ffffff"><font color="ffffff">
+       In some deep philosophical and overly anthromorphized
+       sense, yes, the CPU starting the grace period is immediately
+       aware of having done so.
+       However, if we instead assume that RCU is not self-aware,
+       then even the CPU starting the grace period does not really
+       become aware of the start of this grace period until its
+       first call to <tt>__note_gp_changes()</tt>.
+       On the other hand, this CPU potentially gets early notification
+       because it invokes <tt>__note_gp_changes()</tt> during its
+       last <tt>rcu_gp_init()</tt> pass through its leaf
+       <tt>rcu_node</tt> structure.
+</font></td></tr>
+<tr><td>&nbsp;</td></tr>
+</table>
+
+<h4><a name="Self-Reported Quiescent States">
+Self-Reported Quiescent States</a></h4>
+
+<p>When all entities that might block the grace period have reported
+quiescent states (or as described in a later section, had quiescent
+states reported on their behalf), the grace period can end.
+Online non-idle CPUs report their own quiescent states, as shown
+in the following diagram:
+
+</p><p><img src="TreeRCU-qs.svg" alt="TreeRCU-qs.svg" width="75%">
+
+<p>This is for the last CPU to report a quiescent state, which signals
+the end of the grace period.
+Earlier quiescent states would push up the <tt>rcu_node</tt> tree
+only until they encountered an <tt>rcu_node</tt> structure that
+is waiting for additional quiescent states.
+However, ordering is nevertheless preserved because some later quiescent
+state will acquire that <tt>rcu_node</tt> structure's <tt>-&gt;lock</tt>.
+
+<p>Any number of events can lead up to a CPU invoking
+<tt>note_gp_changes</tt> (or alternatively, directly invoking
+<tt>__note_gp_changes()</tt>), at which point that CPU will notice
+the start of a new grace period while holding its leaf
+<tt>rcu_node</tt> lock.
+Therefore, all execution shown in this diagram happens after the
+start of the grace period.
+In addition, this CPU will consider any RCU read-side critical
+section that started before the invocation of <tt>__note_gp_changes()</tt>
+to have started before the grace period, and thus a critical
+section that the grace period must wait on.
+
+<table>
+<tr><th>&nbsp;</th></tr>
+<tr><th align="left">Quick Quiz:</th></tr>
+<tr><td>
+       But a RCU read-side critical section might have started
+       after the beginning of the grace period
+       (the <tt>-&gt;gpnum++</tt> from earlier), so why should
+       the grace period wait on such a critical section?
+</td></tr>
+<tr><th align="left">Answer:</th></tr>
+<tr><td bgcolor="#ffffff"><font color="ffffff">
+       It is indeed not necessary for the grace period to wait on such
+       a critical section.
+       However, it is permissible to wait on it.
+       And it is furthermore important to wait on it, as this
+       lazy approach is far more scalable than a &ldquo;big bang&rdquo;
+       all-at-once grace-period start could possibly be.
+</font></td></tr>
+<tr><td>&nbsp;</td></tr>
+</table>
+
+<p>If the CPU does a context switch, a quiescent state will be
+noted by <tt>rcu_node_context_switch()</tt> on the left.
+On the other hand, if the CPU takes a scheduler-clock interrupt
+while executing in usermode, a quiescent state will be noted by
+<tt>rcu_check_callbacks()</tt> on the right.
+Either way, the passage through a quiescent state will be noted
+in a per-CPU variable.
+
+<p>The next time an <tt>RCU_SOFTIRQ</tt> handler executes on
+this CPU (for example, after the next scheduler-clock
+interrupt), <tt>__rcu_process_callbacks()</tt> will invoke
+<tt>rcu_check_quiescent_state()</tt>, which will notice the
+recorded quiescent state, and invoke
+<tt>rcu_report_qs_rdp()</tt>.
+If <tt>rcu_report_qs_rdp()</tt> verifies that the quiescent state
+really does apply to the current grace period, it invokes
+<tt>rcu_report_rnp()</tt> which traverses up the <tt>rcu_node</tt>
+tree as shown at the bottom of the diagram, clearing bits from
+each <tt>rcu_node</tt> structure's <tt>-&gt;qsmask</tt> field,
+and propagating up the tree when the result is zero.
+
+<p>Note that traversal passes upwards out of a given <tt>rcu_node</tt>
+structure only if the current CPU is reporting the last quiescent
+state for the subtree headed by that <tt>rcu_node</tt> structure.
+A key point is that if a CPU's traversal stops at a given <tt>rcu_node</tt>
+structure, then there will be a later traversal by another CPU
+(or perhaps the same one) that proceeds upwards
+from that point, and the <tt>rcu_node</tt> <tt>-&gt;lock</tt>
+guarantees that the first CPU's quiescent state happens before the
+remainder of the second CPU's traversal.
+Applying this line of thought repeatedly shows that all CPUs'
+quiescent states happen before the last CPU traverses through
+the root <tt>rcu_node</tt> structure, the &ldquo;last CPU&rdquo;
+being the one that clears the last bit in the root <tt>rcu_node</tt>
+structure's <tt>-&gt;qsmask</tt> field.
+
+<h4><a name="Dynamic Tick Interface">Dynamic Tick Interface</a></h4>
+
+<p>Due to energy-efficiency considerations, RCU is forbidden from
+disturbing idle CPUs.
+CPUs are therefore required to notify RCU when entering or leaving idle
+state, which they do via fully ordered value-returning atomic operations
+on a per-CPU variable.
+The ordering effects are as shown below:
+
+</p><p><img src="TreeRCU-dyntick.svg" alt="TreeRCU-dyntick.svg" width="50%">
+
+<p>The RCU grace-period kernel thread samples the per-CPU idleness
+variable while holding the corresponding CPU's leaf <tt>rcu_node</tt>
+structure's <tt>-&gt;lock</tt>.
+This means that any RCU read-side critical sections that precede the
+idle period (the oval near the top of the diagram above) will happen
+before the end of the current grace period.
+Similarly, the beginning of the current grace period will happen before
+any RCU read-side critical sections that follow the
+idle period (the oval near the bottom of the diagram above).
+
+<p>Plumbing this into the full grace-period execution is described
+<a href="#Forcing Quiescent States">below</a>.
+
+<h4><a name="CPU-Hotplug Interface">CPU-Hotplug Interface</a></h4>
+
+<p>RCU is also forbidden from disturbing offline CPUs, which might well
+be powered off and removed from the system completely.
+CPUs are therefore required to notify RCU of their comings and goings
+as part of the corresponding CPU hotplug operations.
+The ordering effects are shown below:
+
+</p><p><img src="TreeRCU-hotplug.svg" alt="TreeRCU-hotplug.svg" width="50%">
+
+<p>Because CPU hotplug operations are much less frequent than idle transitions,
+they are heavier weight, and thus acquire the CPU's leaf <tt>rcu_node</tt>
+structure's <tt>-&gt;lock</tt> and update this structure's
+<tt>-&gt;qsmaskinitnext</tt>.
+The RCU grace-period kernel thread samples this mask to detect CPUs
+having gone offline since the beginning of this grace period.
+
+<p>Plumbing this into the full grace-period execution is described
+<a href="#Forcing Quiescent States">below</a>.
+
+<h4><a name="Forcing Quiescent States">Forcing Quiescent States</a></h4>
+
+<p>As noted above, idle and offline CPUs cannot report their own
+quiescent states, and therefore the grace-period kernel thread
+must do the reporting on their behalf.
+This process is called &ldquo;forcing quiescent states&rdquo;, it is
+repeated every few jiffies, and its ordering effects are shown below:
+
+</p><p><img src="TreeRCU-gp-fqs.svg" alt="TreeRCU-gp-fqs.svg" width="100%">
+
+<p>Each pass of quiescent state forcing is guaranteed to traverse the
+leaf <tt>rcu_node</tt> structures, and if there are no new quiescent
+states due to recently idled and/or offlined CPUs, then only the
+leaves are traversed.
+However, if there is a newly offlined CPU as illustrated on the left
+or a newly idled CPU as illustrated on the right, the corresponding
+quiescent state will be driven up towards the root.
+As with self-reported quiescent states, the upwards driving stops
+once it reaches an <tt>rcu_node</tt> structure that has quiescent
+states outstanding from other CPUs.
+
+<table>
+<tr><th>&nbsp;</th></tr>
+<tr><th align="left">Quick Quiz:</th></tr>
+<tr><td>
+       The leftmost drive to root stopped before it reached
+       the root <tt>rcu_node</tt> structure, which means that
+       there are still CPUs subordinate to that structure on
+       which the current grace period is waiting.
+       Given that, how is it possible that the rightmost drive
+       to root ended the grace period?
+</td></tr>
+<tr><th align="left">Answer:</th></tr>
+<tr><td bgcolor="#ffffff"><font color="ffffff">
+       Good analysis!
+       It is in fact impossible in the absence of bugs in RCU.
+       But this diagram is complex enough as it is, so simplicity
+       overrode accuracy.
+       You can think of it as poetic license, or you can think of
+       it as misdirection that is resolved in the
+       <a href="#Putting It All Together">stitched-together diagram</a>.
+</font></td></tr>
+<tr><td>&nbsp;</td></tr>
+</table>
+
+<h4><a name="Grace-Period Cleanup">Grace-Period Cleanup</a></h4>
+
+<p>Grace-period cleanup first scans the <tt>rcu_node</tt> tree
+breadth-first setting all the <tt>-&gt;completed</tt> fields equal
+to the number of the newly completed grace period, then it sets
+the <tt>rcu_state</tt> structure's <tt>-&gt;completed</tt> field,
+again to the number of the newly completed grace period.
+The ordering effects are shown below:
+
+</p><p><img src="TreeRCU-gp-cleanup.svg" alt="TreeRCU-gp-cleanup.svg" width="75%">
+
+<p>As indicated by the oval at the bottom of the diagram, once
+grace-period cleanup is complete, the next grace period can begin.
+
+<table>
+<tr><th>&nbsp;</th></tr>
+<tr><th align="left">Quick Quiz:</th></tr>
+<tr><td>
+       But when precisely does the grace period end?
+</td></tr>
+<tr><th align="left">Answer:</th></tr>
+<tr><td bgcolor="#ffffff"><font color="ffffff">
+       There is no useful single point at which the grace period
+       can be said to end.
+       The earliest reasonable candidate is as soon as the last
+       CPU has reported its quiescent state, but it may be some
+       milliseconds before RCU becomes aware of this.
+       The latest reasonable candidate is once the <tt>rcu_state</tt>
+       structure's <tt>-&gt;completed</tt> field has been updated,
+       but it is quite possible that some CPUs have already completed
+       phase two of their updates by that time.
+       In short, if you are going to work with RCU, you need to
+       learn to embrace uncertainty.
+</font></td></tr>
+<tr><td>&nbsp;</td></tr>
+</table>
+
+
+<h4><a name="Callback Invocation">Callback Invocation</a></h4>
+
+<p>Once a given CPU's leaf <tt>rcu_node</tt> structure's
+<tt>-&gt;completed</tt> field has been updated, that CPU can begin
+invoking its RCU callbacks that were waiting for this grace period
+to end.
+These callbacks are identified by <tt>rcu_advance_cbs()</tt>,
+which is usually invoked by <tt>__note_gp_changes()</tt>.
+As shown in the diagram below, this invocation can be triggered by
+the scheduling-clock interrupt (<tt>rcu_check_callbacks()</tt> on
+the left) or by idle entry (<tt>rcu_cleanup_after_idle()</tt> on
+the right, but only for kernels build with
+<tt>CONFIG_RCU_FAST_NO_HZ=y</tt>).
+Either way, <tt>RCU_SOFTIRQ</tt> is raised, which results in
+<tt>rcu_do_batch()</tt> invoking the callbacks, which in turn
+allows those callbacks to carry out (either directly or indirectly
+via wakeup) the needed phase-two processing for each update.
+
+</p><p><img src="TreeRCU-callback-invocation.svg" alt="TreeRCU-callback-invocation.svg" width="60%">
+
+<p>Please note that callback invocation can also be prompted by any
+number of corner-case code paths, for example, when a CPU notes that
+it has excessive numbers of callbacks queued.
+In all cases, the CPU acquires its leaf <tt>rcu_node</tt> structure's
+<tt>-&gt;lock</tt> before invoking callbacks, which preserves the
+required ordering against the newly completed grace period.
+
+<p>However, if the callback function communicates to other CPUs,
+for example, doing a wakeup, then it is that function's responsibility
+to maintain ordering.
+For example, if the callback function wakes up a task that runs on
+some other CPU, proper ordering must in place in both the callback
+function and the task being awakened.
+To see why this is important, consider the top half of the
+<a href="#Grace-Period Cleanup">grace-period cleanup</a> diagram.
+The callback might be running on a CPU corresponding to the leftmost
+leaf <tt>rcu_node</tt> structure, and awaken a task that is to run on
+a CPU corresponding to the rightmost leaf <tt>rcu_node</tt> structure,
+and the grace-period kernel thread might not yet have reached the
+rightmost leaf.
+In this case, the grace period's memory ordering might not yet have
+reached that CPU, so again the callback function and the awakened
+task must supply proper ordering.
+
+<h3><a name="Putting It All Together">Putting It All Together</a></h3>
+
+<p>A stitched-together diagram is
+<a href="Tree-RCU-Diagram.html">here</a>.
+
+<h3><a name="Legal Statement">
+Legal Statement</a></h3>
+
+<p>This work represents the view of the author and does not necessarily
+represent the view of IBM.
+
+</p><p>Linux is a registered trademark of Linus Torvalds.
+
+</p><p>Other company, product, and service names may be trademarks or
+service marks of others.
+
+</body></html>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-callback-invocation.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-callback-invocation.svg
new file mode 100644 (file)
index 0000000..8324083
--- /dev/null
@@ -0,0 +1,486 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="592.12805"
+   height="469.83038"
+   viewBox="-44 -44 7874.1949 6244.9802"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-callback-invocation.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="1.2009216"
+     inkscape:cx="289.88715"
+     inkscape:cy="219.06265"
+     inkscape:window-x="713"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="g3058"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3079"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       originx="-116.00011px"
+       originy="-87.2081px" />
+  </sodipodi:namedview>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     id="g4"
+     transform="translate(-2296.0293,-2364.1166)">
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,2411.7612 0,4920.3076"
+       id="path3134-9-0-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,4672.443 -2393.6631,0.5116 0,1196.8316 2393.6631,-0.5116"
+       id="path3134-9-0"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,4672.443 2393.6631,0.5116 0,1196.8316 -2393.6631,-0.5116"
+       id="path3134-9-0-7"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 8100 - 5710 5790-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 9300 - 4512 7140-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1040 9300 - 1502 7140-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2240 8100 - 2702 5940-->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1350 3450 - 2444 2510-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4950 3450 - 3854 2510-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 6600 - 4050 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1050 6600 - 1050 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2250 5400 - 2250 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2250 8100 - 2250 6240-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1050 9300 - 1050 7440-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 9300 - 4050 7440-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 8100 - 5250 6240-->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9300 3150 - 10860 3150-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 11400 3600 - 11400 4410-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 11400 5100 - 11400 5910-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9900 4650 - 10860 4650-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9600 6150 - 10860 6150-->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 5400 - 5250 4290-->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <rect
+       x="2333.5203"
+       y="5109.5566"
+       width="2844.0974"
+       height="360.77411"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.0005789, 60.00115781;stroke-dashoffset:0"
+       id="rect118-3"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="2562.135"
+       y="5357.9937"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_check_callbacks()</text>
+    <rect
+       x="7069.6187"
+       y="5087.4678"
+       width="2975.115"
+       height="382.86298"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057902, 60.00115804;stroke-dashoffset:0"
+       id="rect118-36"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="7165.2524"
+       y="5333.4927"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_cleanup_after_idle()</text>
+    <g
+       id="g3058"
+       transform="translate(-53.192514,-2819.2063)">
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier"
+         id="text202"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="6532.0293"
+         x="5073.3374"
+         xml:space="preserve">rcu_advance_cbs()</text>
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="5650.2598"
+         x="4800.2563" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="5726.2852"
+         x="4800.2563" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-3-7"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="6961.395"
+         x="7220.106"
+         xml:space="preserve"><tspan
+           id="tspan3104-6-5"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Leaf</tspan></text>
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-3"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="6321.9248"
+         x="5073.3374"
+         xml:space="preserve">__note_gp_changes()</text>
+    </g>
+    <g
+       id="g3049"
+       transform="translate(26.596257,6090.5512)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,1872.6808,-2726.4833)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-3"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-6"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="1785.2073"
+         x="5717.4517"
+         xml:space="preserve"><tspan
+           id="tspan3104-7"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Phase Two</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-5"
+         y="2005.6624"
+         x="6119.668"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="2005.6624"
+           x="6119.668"
+           id="tspan3112-3"
+           sodipodi:role="line">of Update</tspan></text>
+    </g>
+    <rect
+       x="5097.8271"
+       y="6268.2183"
+       width="1994.7195"
+       height="664.90662"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057858, 60.00115716;stroke-dashoffset:0"
+       id="rect118-36-3"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="5363.7886"
+       y="6534.1812"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">RCU_SOFTIRQ</text>
+    <text
+       xml:space="preserve"
+       x="5363.7886"
+       y="6800.1436"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6-6-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_do_batch()</text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-callback-registry.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-callback-registry.svg
new file mode 100644 (file)
index 0000000..7ac6f92
--- /dev/null
@@ -0,0 +1,655 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="816.04761"
+   height="636.55627"
+   viewBox="-44 -44 10851.906 8461.0989"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-callback-registry.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="1.2009216"
+     inkscape:cx="408.02381"
+     inkscape:cy="254.38856"
+     inkscape:window-x="713"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="g4"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3079"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       originx="5.2596966e-08px"
+       originy="-4.5963961e-06px" />
+  </sodipodi:namedview>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     id="g4"
+     transform="translate(-753.44492,-1306.6788)">
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,2411.7612 0,6117.1391"
+       id="path3134-9-0-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,3342.6302 -3856.4573,0 10.6979,5757.1962 2918.1436,-2e-4"
+       id="path3134-9-0"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,3342.6302 3856.4574,0 -12.188,5757.1963 -2918.1436,-3e-4"
+       id="path3134-9-0-7"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 8100 - 5710 5790-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 9300 - 4512 7140-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1040 9300 - 1502 7140-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2240 8100 - 2702 5940-->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1350 3450 - 2444 2510-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4950 3450 - 3854 2510-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 6600 - 4050 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1050 6600 - 1050 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2250 5400 - 2250 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2250 8100 - 2250 6240-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1050 9300 - 1050 7440-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 9300 - 4050 7440-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 8100 - 5250 6240-->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9300 3150 - 10860 3150-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 11400 3600 - 11400 4410-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 11400 5100 - 11400 5910-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9900 4650 - 10860 4650-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9600 6150 - 10860 6150-->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 5400 - 5250 4290-->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <rect
+       x="4544.7305"
+       y="4603.417"
+       width="3240.0088"
+       height="2650.6289"
+       rx="0"
+       style="stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+       id="rect118"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="5073.3374"
+       y="6372.4521"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">rcu_accelerate_cbs()</text>
+    <g
+       id="g3107"
+       transform="translate(2715.7065,4700.8888)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="4773.3452"
+       y="4825.2578"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_prepare_for_idle()</text>
+    <rect
+       x="790.93585"
+       y="4630.8252"
+       width="3240.0088"
+       height="2650.6289"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.0005789, 60.00115781;stroke-dashoffset:0"
+       id="rect118-3"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="1319.5447"
+       y="6639.2261"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_accelerate_cbs()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-7"
+       transform="translate(-1038.0776,4728.2971)">
+      <rect
+         id="rect112-5"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="1019.5512"
+       y="4852.666"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">note_gp_changes()</text>
+    <text
+       xml:space="preserve"
+       x="1319.5447"
+       y="6376.6328"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_advance_cbs()</text>
+    <text
+       xml:space="preserve"
+       x="1340.6649"
+       y="6111.4473"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6-6-2"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">__note_gp_changes()</text>
+    <rect
+       x="5422.6279"
+       y="3041.8311"
+       width="1480.4871"
+       height="379.24637"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.0005789, 60.00115794;stroke-dashoffset:0"
+       id="rect118-3-9"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="5607.2734"
+       y="3283.3892"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">call_rcu()</text>
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       id="path3084"
+       sodipodi:cx="319.379"
+       sodipodi:cy="345.54001"
+       sodipodi:rx="65.917107"
+       sodipodi:ry="39.550262"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       transform="matrix(13.298129,0,0,13.298129,1915.7286,4523.6528)" />
+    <text
+       xml:space="preserve"
+       x="5853.9238"
+       y="8902.3623"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104">Wake up</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6165.7158"
+       y="9122.8174"
+       id="text3110"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3112"
+         x="6165.7158"
+         y="9122.8174">grace-period</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6162.8716"
+       y="9364.3564"
+       id="text3114"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3116"
+         x="6162.8716"
+         y="9364.3564">kernel thread</tspan></text>
+    <rect
+       x="8239.8516"
+       y="4608.7363"
+       width="3240.0088"
+       height="2650.6289"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057902, 60.00115804;stroke-dashoffset:0"
+       id="rect118-36"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="8768.4678"
+       y="6484.1562"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-75"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_accelerate_cbs()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-3"
+       transform="translate(6410.833,4706.2127)">
+      <rect
+         id="rect112-56"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="8329.5352"
+       y="4830.5771"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">takedown_cpu()</text>
+    <text
+       xml:space="preserve"
+       x="8335.4873"
+       y="5094.127"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcutree_migrate_callbacks()</text>
+    <text
+       xml:space="preserve"
+       x="8335.4873"
+       y="5357.1006"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6-0"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_migrate_callbacks()</text>
+    <text
+       xml:space="preserve"
+       x="8768.4678"
+       y="6224.9038"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6-6-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_advance_cbs()</text>
+    <text
+       xml:space="preserve"
+       x="3467.9963"
+       y="6987.9912"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7220.106"
+       y="6961.395"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="10905.331"
+       y="6961.395"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-3"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-5">Leaf</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       id="path3084-3"
+       sodipodi:cx="319.379"
+       sodipodi:cy="345.54001"
+       sodipodi:rx="65.917107"
+       sodipodi:ry="39.550262"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       transform="matrix(13.298129,0,0,13.298129,1872.6808,-2726.4833)" />
+    <text
+       xml:space="preserve"
+       x="5717.4517"
+       y="1785.2073"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-7">Phase One</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6119.668"
+       y="2005.6624"
+       id="text3110-5"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3112-3"
+         x="6119.668"
+         y="2005.6624">of Update</tspan></text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-dyntick.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-dyntick.svg
new file mode 100644 (file)
index 0000000..423df00
--- /dev/null
@@ -0,0 +1,700 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="670.61804"
+   height="557.16394"
+   viewBox="-44 -44 8917.9652 7405.8166"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-dyntick.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3946-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4880"
+       style="overflow:visible">
+      <path
+         id="path4882"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-6"
+       style="overflow:visible">
+      <path
+         id="path3946-10"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36"
+       style="overflow:visible">
+      <path
+         id="path3940-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-6"
+       style="overflow:visible">
+      <path
+         id="path3940-26"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-8"
+       style="overflow:visible">
+      <path
+         id="path3940-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-367"
+       style="overflow:visible">
+      <path
+         id="path3940-5"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-56"
+       style="overflow:visible">
+      <path
+         id="path3946-2"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3081"
+       style="overflow:visible">
+      <path
+         id="path3083"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3085"
+       style="overflow:visible">
+      <path
+         id="path3087"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3089"
+       style="overflow:visible">
+      <path
+         id="path3091"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3093"
+       style="overflow:visible">
+      <path
+         id="path3095"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3097"
+       style="overflow:visible">
+      <path
+         id="path3099"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-9"
+       style="overflow:visible">
+      <path
+         id="path3940-1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3675"
+       style="overflow:visible">
+      <path
+         id="path3940-3"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1148"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="1.4142136"
+     inkscape:cx="381.32663"
+     inkscape:cy="239.67141"
+     inkscape:window-x="833"
+     inkscape:window-y="24"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5"
+     inkscape:snap-global="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3154"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       originx="-235.14935px"
+       originy="-709.25071px" />
+  </sodipodi:namedview>
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1-3-5"
+     d="m 3754.1051,47.378296 -2.828,7173.860804"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <path
+     sodipodi:nodetypes="ccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1-3"
+     d="m 6681.1176,1435.1734 -2.828,1578.9586 -2861.3912,7.7159"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <path
+     sodipodi:nodetypes="ccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1"
+     d="m 3748.8929,3772.1176 2904.1747,-0.8434 26.8008,1842.1825"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <g
+     id="g3115"
+     transform="translate(-2341.8794,10827.399)">
+    <rect
+       ry="0"
+       id="rect118-3"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057923, 60.00115859;stroke-dashoffset:0"
+       rx="0"
+       height="2349.7295"
+       width="5308.7119"
+       y="-8909.5498"
+       x="2379.3704" />
+    <g
+       transform="translate(2576.8841,-9085.2783)"
+       id="g3107-7"
+       style="fill:none;stroke-width:0.025in">
+      <rect
+         x="2084.55"
+         y="949.37109"
+         width="2809.1992"
+         height="1370.8721"
+         rx="0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         id="rect112-5" />
+      <rect
+         x="2084.55"
+         y="1025.3964"
+         width="2809.1992"
+         height="1294.8468"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         id="rect112-3-3" />
+    </g>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-6-6-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-7356.375"
+       x="4769.4536"
+       xml:space="preserve">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-3"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-6825.5815"
+       x="7082.9585"
+       xml:space="preserve"><tspan
+         id="tspan3104-6"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Leaf</tspan></text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-7-7"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-8652.5312"
+       x="2466.7822"
+       xml:space="preserve">dyntick_save_progress_counter()</text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-7-2-0"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-8368.1475"
+       x="2463.3262"
+       xml:space="preserve">rcu_implicit_dynticks_qs()</text>
+  </g>
+  <g
+     id="g4504"
+     transform="translate(2063.5184,-16111.739)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4409.043"
+       xml:space="preserve"><tspan
+         id="tspan3104"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110"
+       y="17055.541"
+       x="4579.373"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4579.373"
+         id="tspan3112"
+         sodipodi:role="line">read-side</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114"
+       y="17297.08"
+       x="4584.8276"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4584.8276"
+         id="tspan3116"
+         sodipodi:role="line">critical section</tspan></text>
+  </g>
+  <g
+     id="g3148-9-9"
+     transform="translate(2035.3087,6370.5796)">
+    <rect
+       x="3592.3828"
+       y="-4715.7246"
+       width="3164.783"
+       height="769.99048"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+       id="rect118-3-5-1-3"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4418.6582"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_dynticks_eqs_enter()</text>
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4165.7954"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-0-0"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">atomic_add_return()</text>
+  </g>
+  <g
+     id="g3148-9-9-2"
+     transform="translate(2035.3089,9031.6839)">
+    <rect
+       x="3592.3828"
+       y="-4715.7246"
+       width="3164.783"
+       height="769.99048"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+       id="rect118-3-5-1-3-6"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4418.6582"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-6-1"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_dynticks_eqs_exit()</text>
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4165.7954"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-0-0-8"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">atomic_add_return()</text>
+  </g>
+  <g
+     id="g4504-7"
+     transform="translate(2082.3248,-10883.562)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084-9"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4409.043"
+       xml:space="preserve"><tspan
+         id="tspan3104-0"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110-2"
+       y="17055.541"
+       x="4579.373"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4579.373"
+         id="tspan3112-3"
+         sodipodi:role="line">read-side</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114-7"
+       y="17297.08"
+       x="4584.8276"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4584.8276"
+         id="tspan3116-5"
+         sodipodi:role="line">critical section</tspan></text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-cleanup.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-cleanup.svg
new file mode 100644 (file)
index 0000000..754f426
--- /dev/null
@@ -0,0 +1,1126 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1026.1281"
+   height="1246.2428"
+   viewBox="-44 -44 13645.583 16565.045"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-gp-cleanup.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3946-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4880"
+       style="overflow:visible">
+      <path
+         id="path4882"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-6"
+       style="overflow:visible">
+      <path
+         id="path3946-10"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-1"
+       style="overflow:visible">
+      <path
+         id="path3946-2"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3130"
+       style="overflow:visible">
+      <path
+         id="path3132"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3134"
+       style="overflow:visible">
+      <path
+         id="path3136"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3138"
+       style="overflow:visible">
+      <path
+         id="path3140"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3142"
+       style="overflow:visible">
+      <path
+         id="path3144"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3146"
+       style="overflow:visible">
+      <path
+         id="path3148"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-7"
+       style="overflow:visible">
+      <path
+         id="path3940-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36"
+       style="overflow:visible">
+      <path
+         id="path3940-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36-7"
+       style="overflow:visible">
+      <path
+         id="path3940-7-4"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="0.70710678"
+     inkscape:cx="617.89017"
+     inkscape:cy="542.52419"
+     inkscape:window-x="86"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="g3188-3"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3391"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       originx="-1.7575793e-05px"
+       originy="70.717956px" />
+  </sodipodi:namedview>
+  <path
+     sodipodi:nodetypes="cccccccccccccccccccccccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3"
+     d="m 6899.303,45.238347 -2.8276,2480.757053 -2316.0141,-1.687 -2.8276,2179.855 2321.1758,-0.844 -2.7042,-1843.237 2404.5142,-0.211 16.1022,1993.267 -7783.8345,-4.728 -16.7936,2120.3945 2033.1033,-23.5344 2.0128,-1866.5611 2051.9097,14.079 2.0128,1838.2983 1280.8475,-4.728 14.608,-1830.1043 1312.2492,12.923 14.608,1818.337 2000.0061,20.4217 -12.279,-1841.4117 1304.168,1.616 -12.279,2032.7057 -4638.6513,1.6154 19.5828,569.0378"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2450.4073,-11647.612)"
+     id="g3188">
+    <text
+       xml:space="preserve"
+       x="3199.1516"
+       y="13255.592"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+    <g
+       id="g3107"
+       transform="translate(947.90548,11584.029)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5452.3052"
+       y="13844.535"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5">Root</tspan></text>
+  </g>
+  <rect
+     ry="0"
+     id="rect118"
+     style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+     rx="0"
+     height="14649.609"
+     width="13482.601"
+     y="403.13776"
+     x="37.490932" />
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="662.59283"
+     x="153.2673"
+     xml:space="preserve">rcu_gp_cleanup()</text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2329.9437,-11611.245)"
+     id="g3147">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5324.5371"
+       y="15414.598"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-753"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+  </g>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(3181.0244,-11647.612)"
+     id="g3153">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7479.5796"
+       y="17699.943"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-9"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-9"
+       d="m 3710.957,19425.516 -20.9546,8604.655"
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(-737.93887,7732.6672)"
+       id="g3188-3">
+      <text
+         xml:space="preserve"
+         x="3225.7478"
+         y="13175.802"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-60"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">rsp-&gt;completed =</text>
+      <g
+         id="g3107-62"
+         transform="translate(947.90548,11584.029)">
+        <rect
+           id="rect112-6"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-1"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5452.3052"
+         y="13844.535"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-8"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-7">Root</tspan></text>
+      <text
+         xml:space="preserve"
+         x="3225.7478"
+         y="13390.038"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-60-3"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">       rnp-&gt;completed</text>
+      <flowRoot
+         xml:space="preserve"
+         id="flowRoot3356"
+         style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         transform="matrix(13.298129,0,0,13.298129,-2487.0857,3868.8376)"><flowRegion
+           id="flowRegion3358"><rect
+             id="rect3360"
+             width="373.35239"
+             height="63.63961"
+             x="332.34018"
+             y="681.87292" /></flowRegion><flowPara
+           id="flowPara3362" /></flowRoot>    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(-858.40227,7769.0342)"
+       id="g3147-9">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-2"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-02"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-3"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-5"
+       transform="translate(5205.6909,23741.476)">
+      <rect
+         id="rect112-7-1-9"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9710.0928"
+       y="26001.982"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-2"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-8">Leaf</tspan></text>
+    <g
+       transform="translate(-4830.8839,7769.0342)"
+       id="g3147-3-7"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-6-3"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-0-6"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-6-1"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+    </g>
+    <g
+       transform="translate(-3340.0639,7732.6672)"
+       id="g3153-2-9"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-6-3"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-1-1"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-8-9"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-7-4"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-9-7">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-6672.8049,7732.6672)"
+       id="g3153-20-8"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-2-4"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-3-5"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-7-0"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-5-3"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-92-6">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-10005.546,7732.6672)"
+       id="g3153-28-0"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-9-6"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-7-3"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-3-2"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-6-0"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-1-6">Leaf</tspan></text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812908px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2285.411,21615.005 -582.9982,865.094"
+       id="path3414-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 5094.193,21615.267 582.998,865.094"
+       id="path3414-9-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 334.77783,23828.182 -582.9982,865.094"
+       id="path3414-8-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 7079.8249,23828.444 582.9999,865.094"
+       id="path3414-9-4-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 1751.2742,23828.182 0,846.288"
+       id="path3414-8-3-65"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 5628.2495,23854.778 0,846.288"
+       id="path3414-8-3-6-6"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+  </g>
+  <g
+     transform="translate(-1642.5377,-11611.245)"
+     id="g3147-3"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7-0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-6"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5327.3057"
+       y="15428.84"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-36"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+  </g>
+  <g
+     transform="translate(-151.71746,-11647.612)"
+     id="g3153-2"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-6"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-8"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-9">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-3484.4587,-11647.612)"
+     id="g3153-20"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-2"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-3"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-7"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-92">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7486.4907"
+       y="17670.119"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+  </g>
+  <g
+     transform="translate(-6817.1997,-11647.612)"
+     id="g3153-28"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-1">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7474.1382"
+       y="17688.926"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+  </g>
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812908px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 5473.757,2234.7264 -582.9982,865.094"
+     id="path3414"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8282.5389,2234.9884 582.9982,865.094"
+     id="path3414-9"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 3523.1239,4447.9034 -582.9982,865.094"
+     id="path3414-8"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 10268.171,4448.1654 583,865.094"
+     id="path3414-9-4"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 4939.6203,4447.9034 0,846.288"
+     id="path3414-8-3"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8816.5956,4474.4994 0,846.288"
+     id="path3414-8-3-6"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <text
+     xml:space="preserve"
+     x="7318.9653"
+     y="6031.6353"
+     font-style="normal"
+     font-weight="bold"
+     font-size="192"
+     id="text202-2"
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     id="g4504-3-9"
+     transform="translate(4866.6205,-1197.2204)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084-6-1"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-7-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16888.277"
+       x="4344.877"
+       xml:space="preserve"><tspan
+         id="tspan3104-5-7"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Start of</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110-3-0"
+       y="17119.1"
+       x="4578.7886"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17119.1"
+         x="4578.7886"
+         id="tspan3112-5-9"
+         sodipodi:role="line">Next Grace</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114-6-3"
+       y="17350.271"
+       x="4581.7886"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17350.271"
+         x="4581.7886"
+         id="tspan3116-2-6"
+         sodipodi:role="line">Period</tspan></text>
+  </g>
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-5"
+     d="m 6875.6003,15833.906 1595.7755,0"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send-36)" />
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-fqs.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-fqs.svg
new file mode 100644 (file)
index 0000000..7ddc094
--- /dev/null
@@ -0,0 +1,1309 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1626.5847"
+   height="843.1416"
+   viewBox="-44 -44 21630.534 11207.028"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-gp-fqs.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3946-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4880"
+       style="overflow:visible">
+      <path
+         id="path4882"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-6"
+       style="overflow:visible">
+      <path
+         id="path3946-10"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36"
+       style="overflow:visible">
+      <path
+         id="path3940-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-6"
+       style="overflow:visible">
+      <path
+         id="path3940-26"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-8"
+       style="overflow:visible">
+      <path
+         id="path3940-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-367"
+       style="overflow:visible">
+      <path
+         id="path3940-5"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-56"
+       style="overflow:visible">
+      <path
+         id="path3946-2"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3081"
+       style="overflow:visible">
+      <path
+         id="path3083"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3085"
+       style="overflow:visible">
+      <path
+         id="path3087"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3089"
+       style="overflow:visible">
+      <path
+         id="path3091"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3093"
+       style="overflow:visible">
+      <path
+         id="path3095"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3097"
+       style="overflow:visible">
+      <path
+         id="path3099"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-9"
+       style="overflow:visible">
+      <path
+         id="path3940-1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-91"
+       style="overflow:visible">
+      <path
+         id="path3940-27"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3082"
+       style="overflow:visible">
+      <path
+         id="path3084"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-09"
+       style="overflow:visible">
+      <path
+         id="path3940-3"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3093-6"
+       style="overflow:visible">
+      <path
+         id="path3095-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3675"
+       style="overflow:visible">
+      <path
+         id="path3940-35"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="0.5"
+     inkscape:cx="843.3925"
+     inkscape:cy="528.22238"
+     inkscape:window-x="860"
+     inkscape:window-y="65"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5"
+     inkscape:snap-global="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3154"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       originx="306.04964px"
+       originy="286.40704px" />
+  </sodipodi:namedview>
+  <path
+     sodipodi:nodetypes="ccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1"
+     d="m 16000.705,7361.3625 3383.738,-0.8434 7.995,1860.9894"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <path
+     sodipodi:nodetypes="ccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1-3"
+     d="m 19393.687,5043.2247 -2.828,1541.346 -3303.342,-1.6876"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <path
+     sodipodi:nodetypes="ccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1-6"
+     d="m 5568.2242,7353.9621 -3929.1209,17.9634 20.2153,2632.0515"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <path
+     sodipodi:nodetypes="ccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1-3-2"
+     d="m 1629.8598,3926.2473 12.2312,2669.7292 3867.5308,7.7168"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <path
+     sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3"
+     d="m 10932.061,46.910528 -2.827,638.638602 -5325.0378,35.9259 -21.6339,7219.96837 2057.8863,-38.4562 -21.5106,-2087.7208 -491.6705,-0.211 -2.7042,-1993.689 1393.686,-4.728 39.6256,4057.454 2379.6691,32.779 14.608,-1848.911 1312.249,12.923 14.608,1818.337 2000.007,20.422 -12.28,-1841.412 1191.331,1.616 15.929,1289.8537 520.344,0.202 m 0,0 -15.641,-1570.1327 -2629.727,-18.604 3.166,-2124.92 -2385.245,19.007 21.973,-2444.6293 5551.053,37.8148 1.584,7165.3369 m 0,0 -5602.722,0.1016 19.583,813.521"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <rect
+     ry="0"
+     id="rect118"
+     style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057925, 60.0011585;stroke-dashoffset:0"
+     rx="0"
+     height="8254.9336"
+     width="14128.912"
+     y="443.33136"
+     x="4032.6365" />
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="720.02423"
+     x="4178.2354"
+     xml:space="preserve">rcu_gp_fqs()</text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(6381.5083,-10649.537)"
+     id="g3147">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5250.5327"
+       y="15512.733"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-35"
+       style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+  </g>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(7232.589,-10685.904)"
+     id="g3153">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(2409.0267,-10649.537)"
+     id="g3147-3"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7-0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-6"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5284.6885"
+       y="15500.379"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6"
+       style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+  </g>
+  <g
+     transform="translate(3899.8472,-10685.904)"
+     id="g3153-2"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-6"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-8"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-9">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(567.10542,-10685.904)"
+     id="g3153-20"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-2"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-3"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-7"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-92">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-2765.6353,-10685.904)"
+     id="g3153-28"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-1">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7428.2939"
+       y="17707.271"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-75"
+       style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+  </g>
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812908px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 9525.3217,3196.4324 -582.9982,865.094"
+     id="path3414"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 12334.103,3196.6944 582.999,865.094"
+     id="path3414-9"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 7574.6885,5409.6094 -582.9983,865.094"
+     id="path3414-8"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 14319.735,5409.8714 583.001,865.094"
+     id="path3414-9-4"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8991.1849,5409.6094 0,846.288"
+     id="path3414-8-3"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 12868.16,5436.2054 0,846.288"
+     id="path3414-8-3-6"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <rect
+     ry="0"
+     id="rect118-1"
+     style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057965, 60.00115916;stroke-dashoffset:0"
+     rx="0"
+     height="7164.1621"
+     width="13301.43"
+     y="984.91095"
+     x="4277.6021" />
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7-2"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="1236.326"
+     x="4409.96"
+     xml:space="preserve"
+     sodipodi:linespacing="125%">force_qs_rnp()<tspan
+   style="font-size:192px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+   id="tspan3307" /></text>
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7-2-7"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="1547.8876"
+     x="4417.6396"
+     xml:space="preserve">dyntick_save_progress_counter()</text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(6501.9719,-10685.904)"
+     id="g3188">
+    <g
+       id="g3107"
+       transform="translate(947.90548,11584.029)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5452.3052"
+       y="13844.535"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5">Root</tspan></text>
+    <text
+       xml:space="preserve"
+       x="3158.8521"
+       y="13313.027"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+  </g>
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7-2-7-2"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="1858.8729"
+     x="4414.1836"
+     xml:space="preserve">rcu_implicit_dynticks_qs()</text>
+  <text
+     xml:space="preserve"
+     x="14659.87"
+     y="7002.561"
+     font-style="normal"
+     font-weight="bold"
+     font-size="192"
+     id="text202-62"
+     style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+  <g
+     id="g4504"
+     transform="translate(14776.087,-12503.687)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3089"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4409.043"
+       xml:space="preserve"><tspan
+         id="tspan3104"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110"
+       y="17055.541"
+       x="4579.373"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4579.373"
+         id="tspan3112"
+         sodipodi:role="line">read-side</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114"
+       y="17297.08"
+       x="4584.8276"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4584.8276"
+         id="tspan3116"
+         sodipodi:role="line">critical section</tspan></text>
+  </g>
+  <g
+     id="g3148-9-9"
+     transform="translate(14747.877,9978.6315)">
+    <rect
+       x="3592.3828"
+       y="-4715.7246"
+       width="3164.783"
+       height="769.99048"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+       id="rect118-3-5-1-3"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4418.6582"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_dynticks_eqs_enter()</text>
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4165.7954"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-0-0"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">atomic_add_return()</text>
+  </g>
+  <g
+     id="g3148-9-9-2"
+     transform="translate(14747.877,12639.736)">
+    <rect
+       x="3592.3828"
+       y="-4715.7246"
+       width="3164.783"
+       height="769.99048"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+       id="rect118-3-5-1-3-6"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4418.6582"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-6-1"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_dynticks_eqs_exit()</text>
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4165.7954"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-0-0-8"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">atomic_add_return()</text>
+  </g>
+  <g
+     id="g4504-7"
+     transform="translate(14794.893,-7275.5109)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084-9"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4409.043"
+       xml:space="preserve"><tspan
+         id="tspan3104-0"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110-2"
+       y="17055.541"
+       x="4579.373"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4579.373"
+         id="tspan3112-3"
+         sodipodi:role="line">read-side</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114-7"
+       y="17297.08"
+       x="4584.8276"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4584.8276"
+         id="tspan3116-5"
+         sodipodi:role="line">critical section</tspan></text>
+  </g>
+  <g
+     id="g4504-6"
+     transform="translate(-2953.0872,-13662.506)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084-1"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-8"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4409.043"
+       xml:space="preserve"><tspan
+         id="tspan3104-7"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110-9"
+       y="17055.541"
+       x="4579.373"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4579.373"
+         id="tspan3112-2"
+         sodipodi:role="line">read-side</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114-0"
+       y="17297.08"
+       x="4584.8276"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4584.8276"
+         id="tspan3116-2"
+         sodipodi:role="line">critical section</tspan></text>
+  </g>
+  <g
+     id="g3148-9-9-3"
+     transform="translate(-3554.8919,9313.0075)">
+    <rect
+       x="3592.3828"
+       y="-4981.6865"
+       width="3728.9751"
+       height="2265.0989"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+       id="rect118-3-5-1-3-7"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4684.6201"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-6-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_report_dead()</text>
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4431.7573"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-0-0-9"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_cleanup_dying_idle_cpu()</text>
+    <g
+       transform="translate(1783.3183,-5255.3491)"
+       id="g3107-7-5"
+       style="fill:none;stroke-width:0.025in">
+      <rect
+         x="2084.55"
+         y="949.37109"
+         width="2809.1992"
+         height="1370.8721"
+         rx="0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         id="rect112-5-3" />
+      <rect
+         x="2084.55"
+         y="1025.3964"
+         width="2809.1992"
+         height="1294.8468"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         id="rect112-3-3-5" />
+    </g>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-6-6-2-6"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-3526.4448"
+       x="4241.8574"
+       xml:space="preserve">-&gt;qsmaskinitnext</text>
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-3-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-2987.4167"
+       x="6305.1484"
+       xml:space="preserve"><tspan
+         id="tspan3104-6-9"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Leaf</tspan></text>
+  </g>
+  <g
+     id="g4504-7-2"
+     transform="translate(-2934.2807,-6492.8204)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084-9-2"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-2-8"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4409.043"
+       xml:space="preserve"><tspan
+         id="tspan3104-0-9"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110-2-7"
+       y="17055.541"
+       x="4579.373"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4579.373"
+         id="tspan3112-3-3"
+         sodipodi:role="line">read-side</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114-7-6"
+       y="17297.08"
+       x="4584.8276"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4584.8276"
+         id="tspan3116-5-1"
+         sodipodi:role="line">critical section</tspan></text>
+  </g>
+  <g
+     id="g3206"
+     transform="translate(3999.5374,3999.1768)">
+    <rect
+       ry="0"
+       id="rect118-3-5-1-3-1"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00058007, 60.00116001;stroke-dashoffset:0"
+       rx="0"
+       height="2265.0989"
+       width="3728.9751"
+       y="3382.2036"
+       x="-3958.3845" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-3-27-6-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="3679.27"
+       x="-3804.9949"
+       xml:space="preserve">rcu_cpu_starting()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-7-5-0"
+       transform="translate(-5767.4491,3108.5424)">
+      <rect
+         id="rect112-5-3-9"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-3-5-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="-3308.9099"
+       y="4837.4453"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6-6-2-6-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinitnext</text>
+    <text
+       xml:space="preserve"
+       x="-1245.6189"
+       y="5376.4731"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-2-0"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-9-6">Leaf</tspan></text>
+  </g>
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1-3-6"
+     d="m 15475.193,7360.7089 467.332,8.6247"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-1.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-1.svg
new file mode 100644 (file)
index 0000000..0161262
--- /dev/null
@@ -0,0 +1,656 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1039.3743"
+   height="677.72852"
+   viewBox="-44 -44 13821.733 9008.3597"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-gp-init-1.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3946-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4880"
+       style="overflow:visible">
+      <path
+         id="path4882"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-6"
+       style="overflow:visible">
+      <path
+         id="path3946-10"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36"
+       style="overflow:visible">
+      <path
+         id="path3940-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="0.70710678"
+     inkscape:cx="617.89019"
+     inkscape:cy="636.57143"
+     inkscape:window-x="697"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3059"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       originx="1.6062488e-07px"
+       originy="10.7285px" />
+  </sodipodi:namedview>
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3"
+     d="m 6871.027,46.883461 0,8777.144039"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2450.4075,-10679.115)"
+     id="g3188">
+    <text
+       xml:space="preserve"
+       x="3305.5364"
+       y="13255.592"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">rsp-&gt;gpnum++</text>
+    <g
+       id="g3107"
+       transform="translate(947.90548,11584.029)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5452.3052"
+       y="13844.535"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5">Root</tspan></text>
+  </g>
+  <rect
+     ry="0"
+     id="rect118"
+     style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+     rx="0"
+     height="6844.4546"
+     width="13658.751"
+     y="1371.6335"
+     x="37.490932" />
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="1631.0878"
+     x="153.26733"
+     xml:space="preserve">rcu_gp_init()</text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2329.9439,-10642.748)"
+     id="g3147">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+  </g>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(3181.0246,-10679.115)"
+     id="g3153">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-1642.5375,-10642.748)"
+     id="g3147-3"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7-0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-6"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+  </g>
+  <g
+     transform="translate(-151.71726,-10679.115)"
+     id="g3153-2"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-6"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-8"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-9">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-3484.4587,-10679.115)"
+     id="g3153-20"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-2"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-3"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-7"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-92">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-6817.1998,-10679.115)"
+     id="g3153-28"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-1">Leaf</tspan></text>
+  </g>
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812908px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 5473.7572,3203.2219 -582.9982,865.094"
+     id="path3414"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8282.5391,3203.4839 582.9982,865.094"
+     id="path3414-9"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 3523.1241,5416.3989 -582.9982,865.094"
+     id="path3414-8"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 10268.171,5416.6609 583,865.094"
+     id="path3414-9-4"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 4939.6205,5416.3989 0,846.288"
+     id="path3414-8-3"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8816.5958,5442.9949 0,846.288"
+     id="path3414-8-3-6"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <g
+     id="g4504-3-9"
+     transform="translate(4866.0367,-16425.339)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084-6-1"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-7-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16888.277"
+       x="4344.877"
+       xml:space="preserve"><tspan
+         id="tspan3104-5-7"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">End of</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110-3-0"
+       y="17119.1"
+       x="4578.7886"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17119.1"
+         x="4578.7886"
+         id="tspan3112-5-9"
+         sodipodi:role="line">Last Grace</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114-6-3"
+       y="17350.271"
+       x="4581.7886"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17350.271"
+         x="4581.7886"
+         id="tspan3116-2-6"
+         sodipodi:role="line">Period</tspan></text>
+  </g>
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-5"
+     d="m 8546.5914,605.78414 -1595.7755,0"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send-36)" />
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-2.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-2.svg
new file mode 100644 (file)
index 0000000..4d956a7
--- /dev/null
@@ -0,0 +1,656 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1037.9602"
+   height="666.38184"
+   viewBox="-44 -44 13802.928 8857.5401"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-gp-init-2.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3946-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4880"
+       style="overflow:visible">
+      <path
+         id="path4882"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-6"
+       style="overflow:visible">
+      <path
+         id="path3946-10"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="false"
+     inkscape:zoom="0.79710462"
+     inkscape:cx="564.27119"
+     inkscape:cy="397.32188"
+     inkscape:window-x="833"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5" />
+  <path
+     sodipodi:nodetypes="cccccccccccccccccccccccccccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3"
+     d="m 6861.6904,46.438525 -2.8276,1315.668775 -5343.8436,17.1194 -2.8276,6561.7446 2039.0799,17.963 -2.7042,-2144.1399 -491.6705,-0.2109 -2.7042,-1993.6887 1487.7179,-4.7279 -17.8,1812.453 2017.2374,-7.6434 4.9532,-2151.5723 -1405.5264,11.163 -10.919,-1891.1468 1739.2164,-2.7175 -13.2006,4234.2295 -1701.3595,1.3953 -8.7841,2107.7116 1702.6392,-4.8334 33.4144,-1867.7167 1312.2492,12.9229 14.608,1818.3367 2000.0063,20.4217 -12.279,-1841.4113 1304.168,1.6154 -12.279,2032.7059 -4638.6515,1.6154 19.5828,569.0378"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <rect
+     ry="0"
+     id="rect118"
+     style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+     rx="0"
+     height="7653.1299"
+     width="13639.945"
+     y="555.69745"
+     x="37.490929" />
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="799.34259"
+     x="134.46091"
+     xml:space="preserve">rcu_gp_init()</text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2311.1375,-10650.009)"
+     id="g3147">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+  </g>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(3162.2182,-10686.376)"
+     id="g3153">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-1661.3439,-10650.009)"
+     id="g3147-3"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7-0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-6"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5398.415"
+       y="15310.093"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-8"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinit</text>
+    <text
+       xml:space="preserve"
+       x="5398.415"
+       y="15545.01"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-5-8"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinitnext</text>
+  </g>
+  <g
+     transform="translate(-170.52359,-10686.376)"
+     id="g3153-2"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-6"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-8"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-9">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-3503.2651,-10686.376)"
+     id="g3153-20"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-2"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-3"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-7"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-92">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-6836.0062,-10686.376)"
+     id="g3153-28"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-1">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7699.7246"
+       y="17734.791"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-4"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinit</text>
+  </g>
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812908px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 5454.9508,3195.9607 -582.9982,865.094"
+     id="path3414"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8263.7327,3196.2227 582.9982,865.094"
+     id="path3414-9"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 3504.3177,5409.1377 -582.9982,865.094"
+     id="path3414-8"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 10249.365,5409.3997 583,865.094"
+     id="path3414-9-4"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 4920.8141,5409.1377 0,846.288"
+     id="path3414-8-3"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8797.7894,5435.7337 0,846.288"
+     id="path3414-8-3-6"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <rect
+     ry="0"
+     id="rect118-1"
+     style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057923, 60.00115846;stroke-dashoffset:0"
+     rx="0"
+     height="4418.4302"
+     width="4932.5845"
+     y="1492.2119"
+     x="2087.8708" />
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7-2"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="1690.4336"
+     x="2223.3145"
+     xml:space="preserve"
+     sodipodi:linespacing="125%">rcu_init_new_rnp()<tspan
+   style="font-size:192px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+   id="tspan3307"> or</tspan></text>
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7-2-7"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="1958.5066"
+     x="2223.3145"
+     xml:space="preserve">rcu_cleanup_dead_rnp()</text>
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7-2-7-6"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="2227.4531"
+     x="2226.1592"
+     xml:space="preserve"
+     sodipodi:linespacing="125%"><tspan
+       style="font-size:192px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+       id="tspan3327">(optional)</tspan></text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2431.6011,-10686.376)"
+     id="g3188">
+    <text
+       xml:space="preserve"
+       x="3305.5364"
+       y="13255.592"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">-&gt;qsmaskinit</text>
+    <g
+       id="g3107"
+       transform="translate(947.90548,11584.029)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5452.3052"
+       y="13844.535"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5">Root</tspan></text>
+    <text
+       xml:space="preserve"
+       x="3305.5364"
+       y="13490.509"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinitnext</text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-3.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp-init-3.svg
new file mode 100644 (file)
index 0000000..de6ecc5
--- /dev/null
@@ -0,0 +1,632 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1039.3743"
+   height="594.19171"
+   viewBox="-44 -44 13821.733 7897.9895"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-gp-init-2.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3946-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4880"
+       style="overflow:visible">
+      <path
+         id="path4882"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-6"
+       style="overflow:visible">
+      <path
+         id="path3946-10"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="false"
+     inkscape:zoom="0.70710678"
+     inkscape:cx="617.89019"
+     inkscape:cy="625.84293"
+     inkscape:window-x="697"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5" />
+  <path
+     sodipodi:nodetypes="cccccccccccccccccccccccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3"
+     d="m 6899.3032,45.520244 -2.8276,2480.757056 -2316.0141,-1.687 -2.8276,2179.8547 2321.1758,-0.8434 -2.7042,-1843.2376 2404.5142,-0.2109 16.1022,1993.2669 -7783.8345,-4.7279 -16.7936,2120.3946 2033.1033,-23.5344 2.0128,-1866.561 2051.9097,14.0785 2.0128,1838.2987 1280.8475,-4.728 14.608,-1830.1039 1312.2492,12.9229 14.608,1818.3367 2000.0059,20.4217 -12.279,-1841.4113 1304.168,1.6154 -12.279,2032.7059 -4638.6511,1.6154 19.5828,569.0378"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2450.4075,-11647.329)"
+     id="g3188">
+    <text
+       xml:space="preserve"
+       x="3305.5364"
+       y="13255.592"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+    <g
+       id="g3107"
+       transform="translate(947.90548,11584.029)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5452.3052"
+       y="13844.535"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5">Root</tspan></text>
+  </g>
+  <rect
+     ry="0"
+     id="rect118"
+     style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+     rx="0"
+     height="6844.4546"
+     width="13658.751"
+     y="403.41983"
+     x="37.490932" />
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="662.8739"
+     x="153.26733"
+     xml:space="preserve">rcu_gp_init()</text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2329.9439,-11610.962)"
+     id="g3147">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5392.3345"
+       y="15407.104"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+  </g>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(3181.0246,-11647.329)"
+     id="g3153">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7536.4883"
+       y="17640.934"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-9"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+  </g>
+  <g
+     transform="translate(-1642.5375,-11610.962)"
+     id="g3147-3"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7-0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-6"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5378.4146"
+       y="15436.927"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-3"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+  </g>
+  <g
+     transform="translate(-151.71726,-11647.329)"
+     id="g3153-2"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-6"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-8"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-9">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-3484.4587,-11647.329)"
+     id="g3153-20"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-2"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-3"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-7"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-92">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7520.1294"
+       y="17673.639"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-35"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+  </g>
+  <g
+     transform="translate(-6817.1998,-11647.329)"
+     id="g3153-28"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-1">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7521.4663"
+       y="17666.062"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-75"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+  </g>
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812908px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 5473.7572,2235.0081 -582.9982,865.094"
+     id="path3414"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8282.5391,2235.2701 582.9982,865.094"
+     id="path3414-9"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 3523.1241,4448.1851 -582.9982,865.094"
+     id="path3414-8"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 10268.171,4448.4471 583,865.094"
+     id="path3414-9-4"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 4939.6205,4448.1851 0,846.288"
+     id="path3414-8-3"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8816.5958,4474.7811 0,846.288"
+     id="path3414-8-3-6"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <text
+     xml:space="preserve"
+     x="7370.856"
+     y="5997.5972"
+     font-style="normal"
+     font-weight="bold"
+     font-size="192"
+     id="text202-62"
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-gp.svg
new file mode 100644 (file)
index 0000000..b13b7b0
--- /dev/null
@@ -0,0 +1,5135 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1626.5841"
+   height="6394.5298"
+   viewBox="-44 -44 21630.525 84996.019"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-gp.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36"
+       style="overflow:visible">
+      <path
+         id="path3940-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-6"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3085"
+       style="overflow:visible">
+      <path
+         id="path3087"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3089"
+       style="overflow:visible">
+      <path
+         id="path3091"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3093"
+       style="overflow:visible">
+      <path
+         id="path3095"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3097"
+       style="overflow:visible">
+      <path
+         id="path3099"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3101"
+       style="overflow:visible">
+      <path
+         id="path3103"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-7"
+       style="overflow:visible">
+      <path
+         id="path3940-5"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-79"
+       style="overflow:visible">
+      <path
+         id="path3940-20"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-37"
+       style="overflow:visible">
+      <path
+         id="path3946-5"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3081"
+       style="overflow:visible">
+      <path
+         id="path3083"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3085-9"
+       style="overflow:visible">
+      <path
+         id="path3087-2"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3089-2"
+       style="overflow:visible">
+      <path
+         id="path3091-8"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3093-9"
+       style="overflow:visible">
+      <path
+         id="path3095-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3097-3"
+       style="overflow:visible">
+      <path
+         id="path3099-6"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-12"
+       style="overflow:visible">
+      <path
+         id="path3940-93"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2"
+       style="overflow:visible">
+      <path
+         id="path3946-66"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3077"
+       style="overflow:visible">
+      <path
+         id="path3079"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3081-4"
+       style="overflow:visible">
+      <path
+         id="path3083-9"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3085-5"
+       style="overflow:visible">
+      <path
+         id="path3087-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3089-4"
+       style="overflow:visible">
+      <path
+         id="path3091-87"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3093-1"
+       style="overflow:visible">
+      <path
+         id="path3095-72"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-72"
+       style="overflow:visible">
+      <path
+         id="path3940-26"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-6"
+       style="overflow:visible">
+      <path
+         id="path3940-25"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-8"
+       style="overflow:visible">
+      <path
+         id="path3946-62"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3179"
+       style="overflow:visible">
+      <path
+         id="path3181"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3183"
+       style="overflow:visible">
+      <path
+         id="path3185"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3187"
+       style="overflow:visible">
+      <path
+         id="path3189"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3191"
+       style="overflow:visible">
+      <path
+         id="path3193"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3195"
+       style="overflow:visible">
+      <path
+         id="path3197"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3199"
+       style="overflow:visible">
+      <path
+         id="path3201"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3203"
+       style="overflow:visible">
+      <path
+         id="path3205"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3207"
+       style="overflow:visible">
+      <path
+         id="path3209"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3211"
+       style="overflow:visible">
+      <path
+         id="path3213"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3215"
+       style="overflow:visible">
+      <path
+         id="path3217"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-5"
+       style="overflow:visible">
+      <path
+         id="path3940-52"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3150"
+       style="overflow:visible">
+      <path
+         id="path3152"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-9"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3156"
+       style="overflow:visible">
+      <path
+         id="path3158"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3160"
+       style="overflow:visible">
+      <path
+         id="path3162"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3164"
+       style="overflow:visible">
+      <path
+         id="path3166"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3168"
+       style="overflow:visible">
+      <path
+         id="path3170"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3172"
+       style="overflow:visible">
+      <path
+         id="path3174"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-8"
+       style="overflow:visible">
+      <path
+         id="path3940-7-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-17"
+       style="overflow:visible">
+      <path
+         id="path3940-8"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36-4"
+       style="overflow:visible">
+      <path
+         id="path3940-7-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-94"
+       style="overflow:visible">
+      <path
+         id="path3946-59"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3157"
+       style="overflow:visible">
+      <path
+         id="path3159"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3161"
+       style="overflow:visible">
+      <path
+         id="path3163"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3165"
+       style="overflow:visible">
+      <path
+         id="path3167"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3169"
+       style="overflow:visible">
+      <path
+         id="path3171"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3173"
+       style="overflow:visible">
+      <path
+         id="path3175"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3177"
+       style="overflow:visible">
+      <path
+         id="path3179"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3181"
+       style="overflow:visible">
+      <path
+         id="path3183"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3185"
+       style="overflow:visible">
+      <path
+         id="path3187"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3189"
+       style="overflow:visible">
+      <path
+         id="path3191"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3193"
+       style="overflow:visible">
+      <path
+         id="path3195"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3197"
+       style="overflow:visible">
+      <path
+         id="path3199"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-35"
+       style="overflow:visible">
+      <path
+         id="path3940-70"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3203-8"
+       style="overflow:visible">
+      <path
+         id="path3205-1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-83"
+       style="overflow:visible">
+      <path
+         id="path3940-79"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3038"
+       style="overflow:visible">
+      <path
+         id="path3040"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3042"
+       style="overflow:visible">
+      <path
+         id="path3044"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="0.6004608"
+     inkscape:cx="826.65969"
+     inkscape:cy="483.3047"
+     inkscape:window-x="66"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3079"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       originx="413.99932px"
+       originy="5758.0031px" />
+  </sodipodi:namedview>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     id="g4"
+     transform="translate(4751.9713,-1307.071)">
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,2411.7612 0,6117.1391"
+       id="path3134-9-0-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,3342.6302 -3856.4573,0 10.6979,5757.1962 2918.1436,-2e-4"
+       id="path3134-9-0"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 6161.6776,3342.6302 3856.4574,0 -12.188,5757.1963 -2918.1436,-3e-4"
+       id="path3134-9-0-7"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 8100 - 5710 5790-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 9300 - 4512 7140-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1040 9300 - 1502 7140-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2240 8100 - 2702 5940-->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1350 3450 - 2444 2510-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4950 3450 - 3854 2510-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 6600 - 4050 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1050 6600 - 1050 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2250 5400 - 2250 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2250 8100 - 2250 6240-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1050 9300 - 1050 7440-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 9300 - 4050 7440-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 8100 - 5250 6240-->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9300 3150 - 10860 3150-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 11400 3600 - 11400 4410-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 11400 5100 - 11400 5910-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9900 4650 - 10860 4650-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9600 6150 - 10860 6150-->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 5400 - 5250 4290-->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <rect
+       x="4544.7305"
+       y="4603.417"
+       width="3240.0088"
+       height="2650.6289"
+       rx="0"
+       style="stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+       id="rect118"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="5073.3374"
+       y="6372.4521"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">rcu_accelerate_cbs()</text>
+    <g
+       id="g3107"
+       transform="translate(2715.7065,4700.8888)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="4773.3452"
+       y="4825.2578"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_prepare_for_idle()</text>
+    <rect
+       x="790.93585"
+       y="4630.8252"
+       width="3240.0088"
+       height="2650.6289"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.0005789, 60.00115781;stroke-dashoffset:0"
+       id="rect118-3"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="1319.5447"
+       y="6639.2261"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_accelerate_cbs()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-7"
+       transform="translate(-1038.0776,4728.2971)">
+      <rect
+         id="rect112-5"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="1019.5512"
+       y="4852.666"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">note_gp_changes()</text>
+    <text
+       xml:space="preserve"
+       x="1319.5447"
+       y="6376.6328"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_advance_cbs()</text>
+    <text
+       xml:space="preserve"
+       x="1340.6649"
+       y="6111.4473"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6-6-2"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">__note_gp_changes()</text>
+    <rect
+       x="5422.6279"
+       y="3041.8311"
+       width="1480.4871"
+       height="379.24637"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.0005789, 60.00115794;stroke-dashoffset:0"
+       id="rect118-3-9"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="5607.2734"
+       y="3283.3892"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">call_rcu()</text>
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       id="path3084"
+       sodipodi:cx="319.379"
+       sodipodi:cy="345.54001"
+       sodipodi:rx="65.917107"
+       sodipodi:ry="39.550262"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       transform="matrix(13.298129,0,0,13.298129,1915.7286,4523.6528)" />
+    <text
+       xml:space="preserve"
+       x="5853.9238"
+       y="8902.3623"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104">Wake up</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6165.7158"
+       y="9122.8174"
+       id="text3110"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3112"
+         x="6165.7158"
+         y="9122.8174">grace-period</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6162.8716"
+       y="9364.3564"
+       id="text3114"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3116"
+         x="6162.8716"
+         y="9364.3564">kernel thread</tspan></text>
+    <rect
+       x="8239.8516"
+       y="4608.7363"
+       width="3240.0088"
+       height="2650.6289"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057902, 60.00115804;stroke-dashoffset:0"
+       id="rect118-36"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="8768.4678"
+       y="6484.1562"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-75"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_accelerate_cbs()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-3"
+       transform="translate(6410.833,4706.2127)">
+      <rect
+         id="rect112-56"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="8329.5352"
+       y="4830.5771"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">takedown_cpu()</text>
+    <text
+       xml:space="preserve"
+       x="8335.4873"
+       y="5094.127"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcutree_migrate_callbacks()</text>
+    <text
+       xml:space="preserve"
+       x="8335.4873"
+       y="5357.1006"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6-0"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_migrate_callbacks()</text>
+    <text
+       xml:space="preserve"
+       x="8768.4678"
+       y="6224.9038"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6-6-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_advance_cbs()</text>
+    <text
+       xml:space="preserve"
+       x="3467.9963"
+       y="6987.9912"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7220.106"
+       y="6961.395"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="10905.331"
+       y="6961.395"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-3"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-5">Leaf</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       id="path3084-3"
+       sodipodi:cx="319.379"
+       sodipodi:cy="345.54001"
+       sodipodi:rx="65.917107"
+       sodipodi:ry="39.550262"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       transform="matrix(13.298129,0,0,13.298129,1872.6808,-2726.4833)" />
+    <text
+       xml:space="preserve"
+       x="5717.4517"
+       y="1785.2073"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-7">Phase One</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6119.668"
+       y="2005.6624"
+       id="text3110-5"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3112-3"
+         x="6119.668"
+         y="2005.6624">of Update</tspan></text>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-3"
+       d="m 6169.6477,11384.719 0,8777.145"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1749.0282,658.72243)"
+       id="g3188">
+      <text
+         xml:space="preserve"
+         x="3305.5364"
+         y="13255.592"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-5"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">rsp-&gt;gpnum++</text>
+      <g
+         id="g3107-62"
+         transform="translate(947.90548,11584.029)">
+        <rect
+           id="rect112-9"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-1"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5452.3052"
+         y="13844.535"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-2"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-7">Root</tspan></text>
+    </g>
+    <rect
+       ry="0"
+       id="rect118-0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057845, 60.00115689;stroke-dashoffset:0"
+       rx="0"
+       height="23612.516"
+       width="13607.611"
+       y="12709.474"
+       x="-663.88806" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-93"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="12968.928"
+       x="-548.11169"
+       xml:space="preserve">rcu_gp_init()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1628.5648,695.08943)"
+       id="g3147">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(2479.6454,658.72243)"
+       id="g3153">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-2343.9166,695.08943)"
+       id="g3147-3"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-6"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-0"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-6"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+    </g>
+    <g
+       transform="translate(-853.09625,658.72243)"
+       id="g3153-2"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-6"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-1"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-8"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-7"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-9">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-4185.8377,658.72243)"
+       id="g3153-20"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-2"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-3"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-7"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-5"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-92">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-7518.5789,658.72243)"
+       id="g3153-28"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-9"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-7"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-3"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-6"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-1">Leaf</tspan></text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4772.378,14541.058 -582.9982,865.094"
+       id="path3414"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 7581.1599,14541.32 582.9982,865.094"
+       id="path3414-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2821.7449,16754.235 -582.9982,865.094"
+       id="path3414-8"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 9566.7916,16754.497 583.0014,865.094"
+       id="path3414-9-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4238.2414,16754.235 0,846.288"
+       id="path3414-8-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 8115.2166,16780.831 0,846.288"
+       id="path3414-8-3-6"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <g
+       id="g4504-3-9"
+       transform="translate(4164.6575,-5087.5013)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-1"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7-2"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16888.277"
+         x="4344.877"
+         xml:space="preserve"><tspan
+           id="tspan3104-5-7"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">End of</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3-0"
+         y="17119.1"
+         x="4578.7886"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17119.1"
+           x="4578.7886"
+           id="tspan3112-5-9"
+           sodipodi:role="line">Last Grace</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6-3"
+         y="17350.271"
+         x="4581.7886"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17350.271"
+           x="4581.7886"
+           id="tspan3116-2-6"
+           sodipodi:role="line">Period</tspan></text>
+    </g>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-5"
+       d="m 7845.2122,11943.62 -1595.7756,0"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send-36)" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       id="path3084-6"
+       sodipodi:cx="319.379"
+       sodipodi:cy="345.54001"
+       sodipodi:rx="65.917107"
+       sodipodi:ry="39.550262"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       transform="matrix(13.298129,0,0,13.298129,1915.7264,6279.0065)" />
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6165.6357"
+       y="10691.992"
+       id="text3110-0"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3112-6"
+         x="6165.6357"
+         y="10691.992">Grace-period</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6162.8696"
+       y="10947.994"
+       id="text3114-2"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3116-6"
+         x="6162.8696"
+         y="10947.994">kernel thread</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6165.3237"
+       y="11188.528"
+       id="text3114-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3116-8"
+         x="6165.3237"
+         y="11188.528">awakened</tspan></text>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-3-2"
+       d="m 6161.6774,9725.7319 0,531.9251"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <path
+       sodipodi:nodetypes="cccccccccccccccccccccccccccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-1"
+       d="m 6169.1878,20208.525 -2.8277,1315.668 -5343.84363,17.12 -2.8276,6561.744 2039.08003,17.963 -2.7042,-2144.14 -491.6705,-0.211 -2.7042,-1993.689 1487.7179,-4.728 -17.7999,1812.453 2017.2372,-7.643 4.9533,-2151.572 -1405.5264,11.163 -10.9189,-1891.147 1739.2163,-2.718 -13.2006,4234.23 -1701.3596,1.395 -8.784,2107.712 1702.6392,-4.834 33.4144,-1867.716 1312.2491,12.923 14.608,1818.336 2000.0062,20.422 -12.279,-1841.411 1304.1668,1.615 -12.279,2032.706 -4638.6501,1.615 19.5828,569.038"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1618.635,9512.0768)"
+       id="g3147-7">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-8"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-4"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-5"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(2469.7158,9475.7098)"
+       id="g3153-0">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-3"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-6"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-1"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-0"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-6">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-2353.8464,9512.0768)"
+       id="g3147-3-3"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-6-2"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-0-0"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-6-6"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5398.415"
+         y="15310.093"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-8"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinit</text>
+      <text
+         xml:space="preserve"
+         x="5398.415"
+         y="15545.01"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-5-8"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinitnext</text>
+    </g>
+    <g
+       transform="translate(-863.02623,9475.7098)"
+       id="g3153-2-1"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-6-5"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-1-5"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-8-4"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-7-7"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-9-6">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-4195.7676,9475.7098)"
+       id="g3153-20-5"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-2-6"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-3-9"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-7-3"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-5-7"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-92-4">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-7528.5086,9475.7098)"
+       id="g3153-28-5"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-9-2"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-7-5"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-3-4"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-6-7"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-1-4">Leaf</tspan></text>
+      <text
+         xml:space="preserve"
+         x="7699.7246"
+         y="17734.791"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-4"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinit</text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="M 4762.4482,23358.047 4179.45,24223.141"
+       id="path3414-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 7571.23,23358.309 582.9982,865.094"
+       id="path3414-9-3"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2811.8152,25571.224 -582.9982,865.094"
+       id="path3414-8-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 9556.8622,25571.486 582.9988,865.094"
+       id="path3414-9-4-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4228.3115,25571.224 0,846.288"
+       id="path3414-8-3-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 8105.2867,25597.82 0,846.288"
+       id="path3414-8-3-6-6"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <rect
+       ry="0"
+       id="rect118-1"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115756;stroke-dashoffset:0"
+       rx="0"
+       height="4418.4302"
+       width="4932.5845"
+       y="21654.297"
+       x="1395.3682" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="21852.52"
+       x="1530.812"
+       xml:space="preserve"
+       sodipodi:linespacing="125%">rcu_init_new_rnp()<tspan
+   style="font-size:192px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+   id="tspan3307"> or</tspan></text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-7"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="22120.592"
+       x="1530.812"
+       xml:space="preserve">rcu_cleanup_dead_rnp()</text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-7-6"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="22389.539"
+       x="1533.6567"
+       xml:space="preserve"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:192px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3327">(optional)</tspan></text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1739.0986,9475.7098)"
+       id="g3188-8">
+      <text
+         xml:space="preserve"
+         x="3305.5364"
+         y="13255.592"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-84"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">-&gt;qsmaskinit</text>
+      <g
+         id="g3107-31"
+         transform="translate(947.90548,11584.029)">
+        <rect
+           id="rect112-4"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-9"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5452.3052"
+         y="13844.535"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-20"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6">Root</tspan></text>
+      <text
+         xml:space="preserve"
+         x="3305.5364"
+         y="13490.509"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-5-89"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinitnext</text>
+    </g>
+    <path
+       sodipodi:nodetypes="cccccccccccccccccccccccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-10"
+       d="m 6187.9943,28881.474 -2.8275,2480.757 -2316.0141,-1.687 -2.8276,2179.854 2321.1757,-0.843 -2.7041,-1843.237 2404.5141,-0.212 16.1022,1993.267 -7783.83443,-4.728 -16.7937,2120.395 2033.10343,-23.534 2.0128,-1866.562 2051.9098,14.079 2.0128,1838.299 1280.8474,-4.728 14.608,-1830.104 1312.2492,12.923 14.608,1818.336 2000.0057,20.422 -12.279,-1841.411 1304.167,1.615 -12.279,2032.706 -4638.6499,1.615 19.5828,569.038"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1739.0986,17188.625)"
+       id="g3188-6">
+      <text
+         xml:space="preserve"
+         x="3305.5364"
+         y="13255.592"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-1"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+      <g
+         id="g3107-5"
+         transform="translate(947.90548,11584.029)">
+        <rect
+           id="rect112-94"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-90"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5452.3052"
+         y="13844.535"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-9"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-1">Root</tspan></text>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1618.6352,17224.992)"
+       id="g3147-1">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-1"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-5"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-9"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5392.3345"
+         y="15407.104"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-6-7"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(2469.7158,17188.625)"
+       id="g3153-7">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-67"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-36"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-5"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-63"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-94">Leaf</tspan></text>
+      <text
+         xml:space="preserve"
+         x="7536.4883"
+         y="17640.934"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-9"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+    </g>
+    <g
+       transform="translate(-2353.8462,17224.992)"
+       id="g3147-3-8"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-6-1"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-0-2"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-6-9"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5378.4146"
+         y="15436.927"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-3"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+    </g>
+    <g
+       transform="translate(-863.02613,17188.625)"
+       id="g3153-2-3"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-6-9"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-1-0"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-8-8"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-7-8"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-9-5">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-4195.7673,17188.625)"
+       id="g3153-20-0"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-2-9"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-3-6"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-7-38"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-5-5"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-92-6">Leaf</tspan></text>
+      <text
+         xml:space="preserve"
+         x="7520.1294"
+         y="17673.639"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-35"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+    </g>
+    <g
+       transform="translate(-7528.5085,17188.625)"
+       id="g3153-28-1"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-9-1"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-7-59"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-3-8"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-6-4"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-1-8">Leaf</tspan></text>
+      <text
+         xml:space="preserve"
+         x="7521.4663"
+         y="17666.062"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-75-1"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4762.4484,31070.961 -582.9982,865.095"
+       id="path3414-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 7571.2303,31071.223 582.9982,865.095"
+       id="path3414-9-30"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2811.8153,33284.138 -582.9982,865.094"
+       id="path3414-8-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 9556.862,33284.401 582.999,865.093"
+       id="path3414-9-4-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4228.3118,33284.138 0,846.288"
+       id="path3414-8-3-4"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 8105.287,33310.734 0,846.288"
+       id="path3414-8-3-6-4"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       x="6659.5469"
+       y="34833.551"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-62"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;gpnum = rsp-&gt;gpnum</text>
+    <path
+       sodipodi:nodetypes="ccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-1-8"
+       d="m 11248.729,43927.515 3383.749,-0.843 7.995,1860.989"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <path
+       sodipodi:nodetypes="ccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-1-3"
+       d="m 14641.723,41609.377 -2.828,1541.346 -3303.353,-1.688"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <path
+       sodipodi:nodetypes="ccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-1-6"
+       d="m 816.24399,43920.114 -3929.12029,17.964 20.2152,2632.051"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <path
+       sodipodi:nodetypes="ccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-1-3-2"
+       d="m -3122.1199,40492.4 12.2312,2669.729 3867.53038,7.717"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <path
+       sodipodi:nodetypes="cccccccccccccccccccccccccccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-4"
+       d="m 6180.0812,36613.063 -2.827,638.638 -5325.0381,35.926 -9.78989,7279.202 2659.62569,0 0,-2260.682 -1196.8316,0 0,-1861.738 1462.7942,0 0,2127.7 3723.476,0 0,1861.738 2035.5457,-11.246 -12.28,-1788.219 1191.3338,1.616 15.928,1289.854 520.347,0.202 m 0,0 -15.641,-1570.133 -2629.7318,-18.604 3.165,-2124.92 -2305.4983,-7.354 0,-2287.279 5319.2511,0 0,7180.99 m 0,0 0,19229.094 -4441.5746,0"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <rect
+       ry="0"
+       id="rect118-7"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+       rx="0"
+       height="8254.9336"
+       width="14128.912"
+       y="37009.492"
+       x="-719.34235" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-24"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="37286.184"
+       x="-573.74298"
+       xml:space="preserve">rcu_gp_fqs()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1629.528,25916.616)"
+       id="g3147-0">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-62"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-9"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-90"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5250.5327"
+         y="15512.733"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-35-8"
+         style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(2480.6088,25880.249)"
+       id="g3153-1">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-31"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-10"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-34"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-03"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-91">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-2342.9531,25916.616)"
+       id="g3147-3-9"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-6-6"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-0-9"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-6-3"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5284.6885"
+         y="15500.379"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-6-3"
+         style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    </g>
+    <g
+       transform="translate(-852.13285,25880.249)"
+       id="g3153-2-8"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-6-0"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-1-56"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-8-6"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-7-4"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-9-0">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-4184.8743,25880.249)"
+       id="g3153-20-04"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-2-62"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-3-67"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-7-5"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-5-6"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-92-9">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-7517.6112,25880.249)"
+       id="g3153-28-8"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-9-7"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-7-2"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-3-82"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-6-9"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-1-9">Leaf</tspan></text>
+      <text
+         xml:space="preserve"
+         x="7428.2939"
+         y="17707.271"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-75-6"
+         style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4773.3421,39762.585 -582.9986,865.094"
+       id="path3414-02"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 7582.1232,39762.847 582.999,865.094"
+       id="path3414-9-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2822.7083,41975.762 -582.9982,865.094"
+       id="path3414-8-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 9567.7542,41976.024 583.0018,865.094"
+       id="path3414-9-4-1"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4239.2048,41975.762 0,846.288"
+       id="path3414-8-3-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 8116.1802,42002.358 0,846.288"
+       id="path3414-8-3-6-2"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <rect
+       ry="0"
+       id="rect118-1-1"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057924, 60.00115835;stroke-dashoffset:0"
+       rx="0"
+       height="7164.1621"
+       width="13301.43"
+       y="37551.07"
+       x="-474.37598" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-5"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="37802.488"
+       x="-342.01831"
+       xml:space="preserve"
+       sodipodi:linespacing="125%">force_qs_rnp()<tspan
+   style="font-size:192px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+   id="tspan3307-9" /></text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-7-9"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="38114.047"
+       x="-334.33856"
+       xml:space="preserve">dyntick_save_progress_counter()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1749.9916,25880.249)"
+       id="g3188-1">
+      <g
+         id="g3107-4"
+         transform="translate(947.90548,11584.029)">
+        <rect
+           id="rect112-91"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-0"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5452.3052"
+         y="13844.535"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-7"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-58">Root</tspan></text>
+      <text
+         xml:space="preserve"
+         x="3158.8521"
+         y="13313.027"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-70"
+         style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    </g>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-7-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="38425.035"
+       x="-337.79462"
+       xml:space="preserve">rcu_implicit_dynticks_qs()</text>
+    <text
+       xml:space="preserve"
+       x="9907.8887"
+       y="43568.723"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-62-4"
+       style="font-size:192.00001526px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    <g
+       id="g4504"
+       transform="translate(10024.106,24062.466)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3089"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-80"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-4"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-29"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-61"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-04"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-22"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g3148-9-9"
+       transform="translate(9995.8972,46544.783)">
+      <rect
+         x="3592.3828"
+         y="-4715.7246"
+         width="3164.783"
+         height="769.99048"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         id="rect118-3-5-1-3"
+         ry="0" />
+      <text
+         xml:space="preserve"
+         x="3745.7725"
+         y="-4418.6582"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-3-27-6"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_dynticks_eqs_enter()</text>
+      <text
+         xml:space="preserve"
+         x="3745.7725"
+         y="-4165.7954"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-3-27-0-0"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">atomic_add_return()</text>
+    </g>
+    <g
+       id="g3148-9-9-2"
+       transform="translate(9995.8972,49205.888)">
+      <rect
+         x="3592.3828"
+         y="-4715.7246"
+         width="3164.783"
+         height="769.99048"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         id="rect118-3-5-1-3-6"
+         ry="0" />
+      <text
+         xml:space="preserve"
+         x="3745.7725"
+         y="-4418.6582"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-3-27-6-1"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_dynticks_eqs_exit()</text>
+      <text
+         xml:space="preserve"
+         x="3745.7725"
+         y="-4165.7954"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-3-27-0-0-8"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">atomic_add_return()</text>
+    </g>
+    <g
+       id="g4504-7"
+       transform="translate(10042.913,29290.642)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-9"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-2"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-0"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-2"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-3-2"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-7"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-5"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g4504-6"
+       transform="translate(-7705.0623,22903.647)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-1"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-8"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-7-0"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-9"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-2"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-0"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g3148-9-9-3"
+       transform="translate(-8306.8632,45879.159)">
+      <rect
+         x="3592.3828"
+         y="-4981.6865"
+         width="3728.9751"
+         height="2265.0989"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         id="rect118-3-5-1-3-7"
+         ry="0" />
+      <text
+         xml:space="preserve"
+         x="3745.7725"
+         y="-4684.6201"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-3-27-6-5"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_report_dead()</text>
+      <text
+         xml:space="preserve"
+         x="3745.7725"
+         y="-4431.7573"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-3-27-0-0-9"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_cleanup_dying_idle_cpu()</text>
+      <g
+         transform="translate(1783.3183,-5255.3491)"
+         id="g3107-7-5"
+         style="fill:none;stroke-width:0.025in">
+        <rect
+           x="2084.55"
+           y="949.37109"
+           width="2809.1992"
+           height="1370.8721"
+           rx="0"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           id="rect112-5-3" />
+        <rect
+           x="2084.55"
+           y="1025.3964"
+           width="2809.1992"
+           height="1294.8468"
+           rx="0"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           id="rect112-3-3-5" />
+      </g>
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-6-6-2-6"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-3526.4448"
+         x="4241.8574"
+         xml:space="preserve">-&gt;qsmaskinitnext</text>
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-3-2"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-2987.4167"
+         x="6305.1484"
+         xml:space="preserve"><tspan
+           id="tspan3104-6-9"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Leaf</tspan></text>
+    </g>
+    <g
+       id="g4504-7-2"
+       transform="translate(-7686.2563,30073.332)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-9-2"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-2-8"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-0-9"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-2-7"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-3-3"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-7-6"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-5-1"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g3206"
+       transform="translate(-752.44253,40565.329)">
+      <rect
+         ry="0"
+         id="rect118-3-5-1-3-1"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00058007, 60.00116001;stroke-dashoffset:0"
+         rx="0"
+         height="2265.0989"
+         width="3728.9751"
+         y="3382.2036"
+         x="-3958.3845" />
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-27-6-2"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="3679.27"
+         x="-3804.9949"
+         xml:space="preserve">rcu_cpu_starting()</text>
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-7-5-0"
+         transform="translate(-5767.4491,3108.5424)">
+        <rect
+           id="rect112-5-3-9"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-3-5-3"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="-3308.9099"
+         y="4837.4453"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-6-6-2-6-6"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinitnext</text>
+      <text
+         xml:space="preserve"
+         x="-1245.6189"
+         y="5376.4731"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-2-0"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-9-6">Leaf</tspan></text>
+    </g>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-1-3-6"
+       d="m 10723.215,43926.861 467.335,8.625"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send-8)"
+       d="m 4431.0572,60276.11 16.472,2346.582"
+       id="path3134-9-0-3-1-9-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(-59.697399,41012.242)"
+       id="g3188-83">
+      <text
+         xml:space="preserve"
+         x="3172.5554"
+         y="13255.592"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-80"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+      <g
+         id="g3107-40"
+         transform="translate(947.90548,11584.029)">
+        <rect
+           id="rect112-919"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-6"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5452.3052"
+         y="13844.535"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-25"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-4">Root</tspan></text>
+    </g>
+    <rect
+       ry="0"
+       id="rect118-4"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057845, 60.00115689;stroke-dashoffset:0"
+       rx="0"
+       height="7164.1641"
+       width="13639.945"
+       y="52743.297"
+       x="-2453.8081" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-99"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="52950.113"
+       x="-2356.8381"
+       xml:space="preserve">rcu_report_rnp()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(-180.16099,41048.609)"
+       id="g3147-36">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-0"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-50"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-29"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(670.91971,41012.242)"
+       id="g3153-4">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-35"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-17"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-4"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-3"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-14">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-4152.6419,41048.609)"
+       id="g3147-3-6"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-6-9"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-0-4"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-6-2"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5284.9155"
+         y="15386.685"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-3-2"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    </g>
+    <g
+       transform="translate(-2661.8217,41012.242)"
+       id="g3153-2-6"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-6-4"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-1-1"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-8-2"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-7-88"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-9-9">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-5994.5632,41012.242)"
+       id="g3153-20-2"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-2-8"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-3-8"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-7-8"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-5-68"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-92-3">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-9327.3041,41012.242)"
+       id="g3153-28-83"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-9-3"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-7-3"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-3-80"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-6-47"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-1-6">Leaf</tspan></text>
+      <text
+         xml:space="preserve"
+         x="7422.3945"
+         y="17661.012"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-67"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2963.6526,54894.579 -582.9982,865.092"
+       id="path3414-89"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 5772.4344,54894.841 582.9982,865.092"
+       id="path3414-9-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 1013.0193,57107.754 -582.99819,865.094"
+       id="path3414-8-68"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 7758.0666,57108.016 583,865.094"
+       id="path3414-9-4-79"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2429.5159,57107.754 0,846.288"
+       id="path3414-8-3-0"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 6306.4911,57134.35 0,846.288"
+       id="path3414-8-3-6-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cccccccccccccccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-33"
+       d="m 4421.0737,51833.378 -2.8276,1315.669 -5343.84362,17.119 -2.8276,6561.745 2039.08002,17.963 -2.7043,-2144.141 -491.67069,-0.211 -2.7042,-1993.689 1487.71819,-4.728 -17.8001,1812.453 2017.2374,-7.643 4.9532,-2151.571 -1405.5263,11.162 -10.9191,-1891.146 1739.2165,-2.718 0.1197,7086.03"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 4432.9209,44194.481 8.8008,4666.688 -2616.9163,17.119 15.9788,1446.406 2603.2718,-0.843 -29.6181,2086.665"
+       id="path3134-9-0-3-1-7"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccccc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+       d="m 4423.9777,48861.171 2616.9159,17.119 -15.979,1465.213 -2584.4649,-19.65"
+       id="path3134-9-0-3-1-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <g
+       transform="translate(-1706.1312,54634.242)"
+       id="g3115">
+      <rect
+         x="4485.6865"
+         y="-8571.0352"
+         width="3296.428"
+         height="2199.2754"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057923, 60.00115859;stroke-dashoffset:0"
+         id="rect118-3-3"
+         ry="0" />
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-7-2"
+         transform="translate(2656.673,-8952.2968)">
+        <rect
+           id="rect112-5-6"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-3-52"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="4714.3018"
+         y="-8349.1943"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-6"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">note_gp_changes()</text>
+      <text
+         xml:space="preserve"
+         x="5014.2954"
+         y="-7170.978"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-6-6-5"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rdp-&gt;gpnum</text>
+      <text
+         xml:space="preserve"
+         x="5035.4155"
+         y="-7436.1636"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-6-6-2-8"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">__note_gp_changes()</text>
+      <text
+         xml:space="preserve"
+         x="7162.7471"
+         y="-6692.6006"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-79"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-6">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-3299.9731,54048.57)"
+       id="g3148">
+      <rect
+         ry="0"
+         id="rect118-3-5"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         rx="0"
+         height="412.66794"
+         width="3240.0085"
+         y="-4640.499"
+         x="3517.1572" />
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4418.6582"
+         x="3745.7725"
+         xml:space="preserve">rcu_node_context_switch()</text>
+    </g>
+    <g
+       transform="translate(1881.1886,54048.57)"
+       id="g3148-5">
+      <rect
+         ry="0"
+         id="rect118-3-5-6"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         rx="0"
+         height="412.66794"
+         width="3240.0085"
+         y="-4640.499"
+         x="3517.1572" />
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-2"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4418.6582"
+         x="3745.7725"
+         xml:space="preserve">rcu_check_callbacks()</text>
+    </g>
+    <g
+       transform="translate(-850.30204,55463.106)"
+       id="g3148-9">
+      <rect
+         ry="0"
+         id="rect118-3-5-1"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         rx="0"
+         height="864.02148"
+         width="3540.9114"
+         y="-4640.499"
+         x="3517.1572" />
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-27"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4418.6582"
+         x="3745.7725"
+         xml:space="preserve">rcu_process_callbacks()</text>
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-27-0"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4165.7954"
+         x="3745.7725"
+         xml:space="preserve">rcu_check_quiescent_state())</text>
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-27-0-9"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-3914.085"
+         x="3745.7725"
+         xml:space="preserve">rcu__report_qs_rdp())</text>
+    </g>
+    <g
+       id="g4504-3"
+       transform="translate(3886.2577,30763.697)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-0"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-5"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-5"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2-4"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g4504-3-9-1"
+       transform="translate(3886.2577,34216.283)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-1-0"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7-2-4"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-5-7-8"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3-0-7"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-5-9-0"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6-3-8"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2-6-6"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g4504-3-0"
+       transform="translate(-4075.0211,30763.697)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,228.84485,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-6"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7-26"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-5-1"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3-8"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-5-7"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6-9"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2-2"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g4504-3-9-0"
+       transform="translate(-4181.4064,34216.283)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-1-2"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7-2-3"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-5-7-7"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3-0-5"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-5-9-9"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6-3-2"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2-6-2"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+       d="m 8448.9566,48370.097 0,2393.663"
+       id="path3134-9-0-3-1-9-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+       d="m 390.28991,48370.097 0,2393.663"
+       id="path3134-9-0-3-1-9-8-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <g
+       id="g4504-2"
+       transform="translate(-143.72569,46137.076)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-4"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-79"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4273.4326"
+         xml:space="preserve"><tspan
+           id="tspan3104-3"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Wake up</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-92"
+         y="17055.541"
+         x="4585.2246"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4585.2246"
+           id="tspan3112-8"
+           sodipodi:role="line">grace-period</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-3"
+         y="17297.08"
+         x="4582.3804"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4582.3804"
+           id="tspan3116-0"
+           sodipodi:role="line">kernel thread</tspan></text>
+    </g>
+    <g
+       transform="translate(-707.64089,66256.889)"
+       id="g3148-2">
+      <rect
+         ry="0"
+         id="rect118-3-5-2"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         rx="0"
+         height="412.66794"
+         width="3240.0085"
+         y="-4640.499"
+         x="3517.1572" />
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-8"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4418.6582"
+         x="4064.9268"
+         xml:space="preserve">rcu_report_qs_rsp()</text>
+    </g>
+    <path
+       sodipodi:type="arc"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       id="path3084-6-9"
+       sodipodi:cx="319.379"
+       sodipodi:cy="345.54001"
+       sodipodi:rx="65.917107"
+       sodipodi:ry="39.550262"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       transform="matrix(13.298129,0,0,13.298129,2044.7501,59781.881)" />
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6294.6587"
+       y="64194.863"
+       id="text3110-0-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3112-6-5"
+         x="6294.6587"
+         y="64194.863">Grace-period</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6291.8931"
+       y="64450.863"
+       id="text3114-2-4"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3116-6-9"
+         x="6291.8931"
+         y="64450.863">kernel thread</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="6294.3472"
+       y="64691.398"
+       id="text3114-1-2"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3116-8-5"
+         x="6294.3472"
+         y="64691.398">awakened</tspan></text>
+    <path
+       sodipodi:nodetypes="ccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-3-2-7"
+       d="m 5310.5974,63210.805 984.0615,0 -3.9578,549.726"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <path
+       sodipodi:nodetypes="cccccccccccccccccccccccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-99"
+       d="m 6322.9337,64896.388 -2.8276,2480.757 -2316.0141,-1.687 -2.8276,2179.855 2321.1758,-0.844 -2.7042,-1843.237 2404.5142,-0.212 16.1023,1993.267 -7783.83452,-4.728 -16.79346,2120.395 2033.10318,-23.535 2.0128,-1866.561 2051.9096,14.08 2.0128,1838.298 1280.8474,-4.728 14.6081,-1830.105 1312.2491,12.923 14.608,1818.337 2000.0093,20.422 -12.279,-1841.412 1304.1722,1.616 -12.279,2032.706 -4638.6586,1.616 19.5827,569.037"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1874.038,53203.538)"
+       id="g3188-7">
+      <text
+         xml:space="preserve"
+         x="3199.1516"
+         y="13255.592"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-82"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+      <g
+         id="g3107-53"
+         transform="translate(947.90548,11584.029)">
+        <rect
+           id="rect112-49"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-02"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5452.3052"
+         y="13844.535"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-0"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-19">Root</tspan></text>
+    </g>
+    <rect
+       ry="0"
+       id="rect118-6"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057845, 60.00115689;stroke-dashoffset:0"
+       rx="0"
+       height="14649.609"
+       width="13482.601"
+       y="65254.539"
+       x="-538.87689" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-21"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="65513.996"
+       x="-423.10056"
+       xml:space="preserve">rcu_gp_cleanup()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1753.5744,53239.905)"
+       id="g3147-2">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-07"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-3"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-1"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5324.5371"
+         y="15414.598"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-753"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-1"
+       transform="translate(7817.6676,69212.346)">
+      <rect
+         id="rect112-7-1-90"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-56"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="12322.059"
+       y="71472.641"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-77"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-4">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="10084.225"
+       y="70903.312"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-9-0"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+    <path
+       sodipodi:nodetypes="ccc"
+       inkscape:connector-curvature="0"
+       id="path3134-9-0-3-9"
+       d="m 6315.6122,72629.054 -20.9533,8108.684 1648.968,0"
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+    <text
+       xml:space="preserve"
+       x="5092.4683"
+       y="74111.672"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-60"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rsp-&gt;completed =</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-62-6"
+       transform="translate(2814.6217,72520.234)">
+      <rect
+         id="rect112-6"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-1-4"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="7319.022"
+       y="74780.406"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-8"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-7-7">Root</tspan></text>
+    <text
+       xml:space="preserve"
+       x="5092.4683"
+       y="74325.906"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-60-3"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">       rnp-&gt;completed</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       transform="translate(1746.2528,60972.572)"
+       id="g3147-9">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-2"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-02"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-3"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+    </g>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-5"
+       transform="translate(7810.3459,76945.013)">
+      <rect
+         id="rect112-7-1-9"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="12314.736"
+       y="79205.188"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-2"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-8">Leaf</tspan></text>
+    <g
+       transform="translate(-2226.2288,60972.572)"
+       id="g3147-3-7"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-6-3"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-0-6"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-6-1"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+    </g>
+    <g
+       transform="translate(-735.4075,60936.205)"
+       id="g3153-2-9"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-6-3"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-1-1-4"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-8-9"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-7-4-8"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-9-7">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-4068.1496,60936.205)"
+       id="g3153-20-8"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-2-4"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-3-5"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-7-0"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-5-3"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-92-6-5">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-7400.8907,60936.205)"
+       id="g3153-28-0"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-9-6"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-7-3-8"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-3-2"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-6-0"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-1-6-2">Leaf</tspan></text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4890.0661,74818.542 -582.9982,865.094"
+       id="path3414-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 7698.8481,74818.804 582.998,865.094"
+       id="path3414-9-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2939.433,77031.719 -582.9982,865.094"
+       id="path3414-8-4-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 9684.4834,77031.981 583.0036,865.094"
+       id="path3414-9-4-7-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4355.9293,77031.719 0,846.288"
+       id="path3414-8-3-65"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 8232.9046,77058.315 0,846.288"
+       id="path3414-8-3-6-6-6"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <g
+       transform="translate(-2218.9069,53239.905)"
+       id="g3147-3-64"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-6-62"
+         transform="translate(3054.6101,13760.052)">
+        <rect
+           id="rect112-7-0-8"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-6-96"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="5327.3057"
+         y="15428.84"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-36"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+    </g>
+    <g
+       transform="translate(-728.08545,53203.538)"
+       id="g3153-2-0"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-6-7"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-1-01"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-8-0"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-7-1"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-9-3">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-4060.8278,53203.538)"
+       id="g3153-20-7"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-2-7"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-3-2"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-7-6"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-5-4"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-92-5">Leaf</tspan></text>
+      <text
+         xml:space="preserve"
+         x="7486.4907"
+         y="17670.119"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-6-2"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+    </g>
+    <g
+       transform="translate(-7393.5687,53203.538)"
+       id="g3153-28-02"
+       style="fill:none;stroke-width:0.025in">
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-6-9-9-9"
+         transform="translate(5213.0126,16008.808)">
+        <rect
+           id="rect112-7-1-7-0"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-5-2-3-9"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="9717.4141"
+         y="18269.314"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3-7-35-7-6-94"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6-5-6-0-1-5">Leaf</tspan></text>
+      <text
+         xml:space="preserve"
+         x="7474.1382"
+         y="17688.926"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-5-1"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4897.3878,67085.876 -582.9982,865.094"
+       id="path3414-03"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 7706.1695,67086.138 582.9982,865.094"
+       id="path3414-9-78"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 2946.7546,69299.053 -582.9981,865.094"
+       id="path3414-8-8"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 9691.8054,69299.315 583.0036,865.094"
+       id="path3414-9-4-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 4363.251,69299.053 0,846.288"
+       id="path3414-8-3-04"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 8240.2262,69325.649 0,846.288"
+       id="path3414-8-3-6-67"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       x="6742.6001"
+       y="70882.617"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-2"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;completed = -&gt;gpnum</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g4504-3-9-6"
+       transform="translate(4290.2512,63653.93)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-1-09"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7-2-7"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16888.277"
+         x="4344.877"
+         xml:space="preserve"><tspan
+           id="tspan3104-5-7-5"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Start of</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3-0-9"
+         y="17119.1"
+         x="4578.7886"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17119.1"
+           x="4578.7886"
+           id="tspan3112-5-9-7"
+           sodipodi:role="line">Next Grace</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6-3-85"
+         y="17350.271"
+         x="4581.7886"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17350.271"
+           x="4581.7886"
+           id="tspan3116-2-6-3"
+           sodipodi:role="line">Period</tspan></text>
+    </g>
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 4406.3256,79248.348 -0.01,5813.579"
+       id="path3134-9-0-3-37"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 4406.3181,82402.301 -2393.663,0.512 0,1196.832 2393.663,-0.512"
+       id="path3134-9-0-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251251;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 4406.3181,82402.301 2393.6631,0.512 0,1196.832 -2393.6631,-0.512"
+       id="path3134-9-0-7-7"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <rect
+       x="578.16779"
+       y="82839.773"
+       width="2844.0972"
+       height="360.77411"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057845, 60.00115702;stroke-dashoffset:0"
+       id="rect118-3-4"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="806.7832"
+       y="83088.211"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-19"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_check_callbacks()</text>
+    <rect
+       x="5314.2671"
+       y="82817.688"
+       width="2975.115"
+       height="382.86298"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057858, 60.00115716;stroke-dashoffset:0"
+       id="rect118-36-0"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="5409.8989"
+       y="83063.711"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6-9"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_cleanup_after_idle()</text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-88"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="81443.047"
+       x="3264.7983"
+       xml:space="preserve">rcu_advance_cbs()</text>
+    <rect
+       id="rect112-58"
+       style="fill:none;stroke:#000000;stroke-width:29.99999809;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="1370.8721"
+       width="2809.1992"
+       y="80561.273"
+       x="2991.7173" />
+    <rect
+       id="rect112-3-4"
+       style="fill:none;stroke:#000000;stroke-width:29.99999809;stroke-linecap:butt;stroke-linejoin:miter"
+       rx="0"
+       height="1294.8468"
+       width="2809.1992"
+       y="80637.297"
+       x="2991.7173" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-3-7-37"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="81872.406"
+       x="5411.5601"
+       xml:space="preserve"><tspan
+         id="tspan3104-6-5-13"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Leaf</tspan></text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-3-8"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="81232.938"
+       x="3264.7983"
+       xml:space="preserve">__note_gp_changes()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3049"
+       transform="translate(-1728.7601,83820.41)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,1872.6808,-2726.4833)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-3-0"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-6-9"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="1785.2073"
+         x="5717.4517"
+         xml:space="preserve"><tspan
+           id="tspan3104-7-7"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Phase Two</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-5-9"
+         y="2005.6624"
+         x="6119.668"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="2005.6624"
+           x="6119.668"
+           id="tspan3112-3-9"
+           sodipodi:role="line">of Update</tspan></text>
+    </g>
+    <rect
+       x="3342.4805"
+       y="83998.438"
+       width="1994.7195"
+       height="664.90662"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057818, 60.00115636;stroke-dashoffset:0"
+       id="rect118-36-3"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="3608.4419"
+       y="84264.398"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">RCU_SOFTIRQ</text>
+    <text
+       xml:space="preserve"
+       x="3608.4419"
+       y="84530.367"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-9-6-6-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_do_batch()</text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-hotplug.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-hotplug.svg
new file mode 100644 (file)
index 0000000..2c9310b
--- /dev/null
@@ -0,0 +1,775 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="613.22784"
+   height="707.07056"
+   viewBox="-44 -44 8154.7829 9398.3736"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-hotplug.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3946-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4880"
+       style="overflow:visible">
+      <path
+         id="path4882"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-6"
+       style="overflow:visible">
+      <path
+         id="path3946-10"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36"
+       style="overflow:visible">
+      <path
+         id="path3940-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-6"
+       style="overflow:visible">
+      <path
+         id="path3940-26"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-8"
+       style="overflow:visible">
+      <path
+         id="path3940-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-367"
+       style="overflow:visible">
+      <path
+         id="path3940-5"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-56"
+       style="overflow:visible">
+      <path
+         id="path3946-2"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3081"
+       style="overflow:visible">
+      <path
+         id="path3083"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3085"
+       style="overflow:visible">
+      <path
+         id="path3087"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3089"
+       style="overflow:visible">
+      <path
+         id="path3091"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3093"
+       style="overflow:visible">
+      <path
+         id="path3095"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker3097"
+       style="overflow:visible">
+      <path
+         id="path3099"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-9"
+       style="overflow:visible">
+      <path
+         id="path3940-1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3675"
+       style="overflow:visible">
+      <path
+         id="path3940-3"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1148"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="1.4142136"
+     inkscape:cx="325.41695"
+     inkscape:cy="364.94502"
+     inkscape:window-x="833"
+     inkscape:window-y="24"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5"
+     inkscape:snap-global="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3154"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       originx="65.610033px"
+       originy="-659.12429px" />
+  </sodipodi:namedview>
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1-3-5"
+     d="m 5749.1555,47.151064 2.828,9167.338436"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <path
+     sodipodi:nodetypes="ccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1"
+     d="m 5746.8844,5080.2018 -4107.7813,-0.8434 20.2152,2632.0511"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <path
+     sodipodi:nodetypes="ccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3-1-3"
+     d="m 1629.8595,1633.6804 12.2312,2669.7294 4055.5945,7.7159"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <g
+     id="g3115"
+     transform="translate(1657.6576,12154.29)">
+    <rect
+       ry="0"
+       id="rect118-3"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057923, 60.00115859;stroke-dashoffset:0"
+       rx="0"
+       height="2349.7295"
+       width="3992.2642"
+       y="-8909.5498"
+       x="2379.3704" />
+    <g
+       transform="translate(582.16224,-9085.2783)"
+       id="g3107-7"
+       style="fill:none;stroke-width:0.025in">
+      <rect
+         x="2084.55"
+         y="949.37109"
+         width="2809.1992"
+         height="1370.8721"
+         rx="0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         id="rect112-5" />
+      <rect
+         x="2084.55"
+         y="1025.3964"
+         width="2809.1992"
+         height="1294.8468"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         id="rect112-3-3" />
+    </g>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-6-6-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-7356.375"
+       x="2774.7393"
+       xml:space="preserve">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-7-7"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-8652.5312"
+       x="2466.7822"
+       xml:space="preserve">dyntick_save_progress_counter()</text>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-2-7-2-0"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-8368.1475"
+       x="2463.3262"
+       xml:space="preserve">rcu_implicit_dynticks_qs()</text>
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-3"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-6817.3472"
+       x="5103.9922"
+       xml:space="preserve"><tspan
+         id="tspan3104-6"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Leaf</tspan></text>
+  </g>
+  <g
+     id="g4504"
+     transform="translate(-2953.0872,-15955.072)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4409.043"
+       xml:space="preserve"><tspan
+         id="tspan3104"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110"
+       y="17055.541"
+       x="4579.373"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4579.373"
+         id="tspan3112"
+         sodipodi:role="line">read-side</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114"
+       y="17297.08"
+       x="4584.8276"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4584.8276"
+         id="tspan3116"
+         sodipodi:role="line">critical section</tspan></text>
+  </g>
+  <g
+     id="g3148-9-9"
+     transform="translate(-3554.8919,7020.44)">
+    <rect
+       x="3592.3828"
+       y="-4981.6865"
+       width="3728.9751"
+       height="2265.0989"
+       rx="0"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+       id="rect118-3-5-1-3"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4684.6201"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_report_dead()</text>
+    <text
+       xml:space="preserve"
+       x="3745.7725"
+       y="-4431.7573"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-3-27-0-0"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_cleanup_dying_idle_cpu()</text>
+    <g
+       transform="translate(1783.3183,-5255.3491)"
+       id="g3107-7-5"
+       style="fill:none;stroke-width:0.025in">
+      <rect
+         x="2084.55"
+         y="949.37109"
+         width="2809.1992"
+         height="1370.8721"
+         rx="0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         id="rect112-5-3" />
+      <rect
+         x="2084.55"
+         y="1025.3964"
+         width="2809.1992"
+         height="1294.8468"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         id="rect112-3-3-5" />
+    </g>
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-6-6-2-6"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-3526.4448"
+       x="4241.8574"
+       xml:space="preserve">-&gt;qsmaskinitnext</text>
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-3-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-2987.4167"
+       x="6305.1484"
+       xml:space="preserve"><tspan
+         id="tspan3104-6-9"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Leaf</tspan></text>
+  </g>
+  <g
+     id="g4504-7"
+     transform="translate(-2934.2808,-8785.3871)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084-9"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4409.043"
+       xml:space="preserve"><tspan
+         id="tspan3104-0"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110-2"
+       y="17055.541"
+       x="4579.373"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4579.373"
+         id="tspan3112-3"
+         sodipodi:role="line">read-side</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114-7"
+       y="17297.08"
+       x="4584.8276"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4584.8276"
+         id="tspan3116-5"
+         sodipodi:role="line">critical section</tspan></text>
+  </g>
+  <g
+     id="g3206"
+     transform="translate(3999.537,1706.6099)">
+    <rect
+       ry="0"
+       id="rect118-3-5-1-3-1"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00058007, 60.00116001;stroke-dashoffset:0"
+       rx="0"
+       height="2265.0989"
+       width="3728.9751"
+       y="3382.2036"
+       x="-3958.3845" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-3-27-6-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="3679.27"
+       x="-3804.9949"
+       xml:space="preserve">rcu_cpu_starting()</text>
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-7-5-0"
+       transform="translate(-5767.4491,3108.5424)">
+      <rect
+         id="rect112-5-3-9"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-3-5-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="-3308.9099"
+       y="4837.4453"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-6-6-2-6-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmaskinitnext</text>
+    <text
+       xml:space="preserve"
+       x="-1245.6189"
+       y="5376.4731"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-2-0"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-9-6">Leaf</tspan></text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/TreeRCU-qs.svg b/Documentation/RCU/Design/Memory-Ordering/TreeRCU-qs.svg
new file mode 100644 (file)
index 0000000..de3992f
--- /dev/null
@@ -0,0 +1,1095 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1037.9601"
+   height="1373.2583"
+   viewBox="-44 -44 13802.927 18253.333"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="TreeRCU-qs.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3940"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4073"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.2,0.2)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4070"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="scale(0.4,0.4)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3952"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3946"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-7"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3952-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-3"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-2"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3940-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-3"
+       style="overflow:visible">
+      <path
+         id="path3946-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible">
+      <path
+         id="path3946-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4880"
+       style="overflow:visible">
+      <path
+         id="path4882"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible">
+      <path
+         id="path3946-0"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-6"
+       style="overflow:visible">
+      <path
+         id="path3946-10"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-36"
+       style="overflow:visible">
+      <path
+         id="path3940-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-6"
+       style="overflow:visible">
+      <path
+         id="path3940-26"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-8"
+       style="overflow:visible">
+      <path
+         id="path3940-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="true"
+     inkscape:zoom="0.70710678"
+     inkscape:cx="616.47598"
+     inkscape:cy="595.41964"
+     inkscape:window-x="813"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="g4405"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3381" />
+  </sodipodi:namedview>
+  <path
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send-8)"
+     d="m 6922.3555,14693.733 16.472,2346.582"
+     id="path3134-9-0-3-1-9-9"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2431.6011,-4570.136)"
+     id="g3188">
+    <text
+       xml:space="preserve"
+       x="3172.5554"
+       y="13255.592"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+    <g
+       id="g3107"
+       transform="translate(947.90548,11584.029)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5452.3052"
+       y="13844.535"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5">Root</tspan></text>
+  </g>
+  <rect
+     ry="0"
+     id="rect118"
+     style="fill:none;stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+     rx="0"
+     height="7164.1636"
+     width="13639.945"
+     y="7160.9038"
+     x="37.490932" />
+  <text
+     style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+     id="text202-7"
+     font-size="192"
+     font-weight="bold"
+     font-style="normal"
+     y="7367.7192"
+     x="134.46094"
+     xml:space="preserve">rcu_report_rnp()</text>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(2311.1375,-4533.769)"
+     id="g3147">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+  </g>
+  <g
+     style="fill:none;stroke-width:0.025in"
+     transform="translate(3162.2182,-4570.136)"
+     id="g3153">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-1661.3439,-4533.769)"
+     id="g3147-3"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-6"
+       transform="translate(3054.6101,13760.052)">
+      <rect
+         id="rect112-7-0"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-6"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="5284.9155"
+       y="15386.685"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-3"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+  </g>
+  <g
+     transform="translate(-170.52365,-4570.136)"
+     id="g3153-2"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-6"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-1"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-8"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-9">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-3503.2651,-4570.136)"
+     id="g3153-20"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-2"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-3"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-7"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-5"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-92">Leaf</tspan></text>
+  </g>
+  <g
+     transform="translate(-6836.0062,-4570.136)"
+     id="g3153-28"
+     style="fill:none;stroke-width:0.025in">
+    <g
+       style="fill:none;stroke-width:0.025in"
+       id="g3107-6-9-9"
+       transform="translate(5213.0126,16008.808)">
+      <rect
+         id="rect112-7-1-7"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3-5-2-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="9717.4141"
+       y="18269.314"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7-5-1-2-3-7-35-7-6"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       sodipodi:linespacing="125%"><tspan
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+         id="tspan3104-6-5-6-0-1">Leaf</tspan></text>
+    <text
+       xml:space="preserve"
+       x="7422.3945"
+       y="17661.012"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-67"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">-&gt;qsmask &amp;= ~-&gt;grpmask</text>
+  </g>
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812908px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 5454.9508,9312.2011 -582.9982,865.0929"
+     id="path3414"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8263.7327,9312.4631 582.9982,865.0929"
+     id="path3414-9"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812813px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 3504.3177,11525.377 -582.9982,865.094"
+     id="path3414-8"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 10249.365,11525.639 583,865.094"
+     id="path3414-9-4"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 4920.8141,11525.377 0,846.288"
+     id="path3414-8-3"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:13.29812717px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+     d="m 8797.7894,11551.973 0,846.288"
+     id="path3414-8-3-6"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     sodipodi:nodetypes="cccccccccccccccc"
+     inkscape:connector-curvature="0"
+     id="path3134-9-0-3"
+     d="m 6912.3719,6251.0009 -2.8276,1315.669 -5343.8436,17.119 -2.8276,6561.7441 2039.08,17.963 -2.7042,-2144.14 -491.6706,-0.211 -2.7042,-1993.689 1487.718,-4.728 -17.8001,1812.453 2017.2374,-7.643 4.9532,-2151.5715 -1405.5263,11.1629 -10.9191,-1891.1465 1739.2165,-2.718 0.1141,7086.0301"
+     style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)" />
+  <g
+     id="g4405"
+     transform="translate(1241.222,9051.8644)">
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+       d="m 5694.6259,-9006.994 -2.828,3233.9212 -2616.9163,17.1191 15.9788,1446.406 2603.2719,-0.8434 -29.6182,2086.6656"
+       id="path3134-9-0-3-1"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccccc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+       d="m 5674.0539,-5773.0705 2616.9163,17.1191 -15.9788,1465.2124 -2584.4655,-19.6498"
+       id="path3134-9-0-3-1-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <g
+       transform="translate(-456.05505,0)"
+       id="g3115">
+      <rect
+         x="4485.6865"
+         y="-8571.0352"
+         width="3296.428"
+         height="2199.2754"
+         rx="0"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057923, 60.00115859;stroke-dashoffset:0"
+         id="rect118-3"
+         ry="0" />
+      <g
+         style="fill:none;stroke-width:0.025in"
+         id="g3107-7"
+         transform="translate(2656.673,-8952.2968)">
+        <rect
+           id="rect112-5"
+           style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1370.8721"
+           width="2809.1992"
+           y="949.37109"
+           x="2084.55" />
+        <rect
+           id="rect112-3-3"
+           style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+           rx="0"
+           height="1294.8468"
+           width="2809.1992"
+           y="1025.3964"
+           x="2084.55" />
+      </g>
+      <text
+         xml:space="preserve"
+         x="4714.3018"
+         y="-8349.1943"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">note_gp_changes()</text>
+      <text
+         xml:space="preserve"
+         x="5014.2954"
+         y="-7170.978"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-6-6"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rdp-&gt;gpnum</text>
+      <text
+         xml:space="preserve"
+         x="5035.4155"
+         y="-7436.1636"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-6-6-2"
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">__note_gp_changes()</text>
+      <text
+         xml:space="preserve"
+         x="7162.7471"
+         y="-6692.6006"
+         font-style="normal"
+         font-weight="bold"
+         font-size="192"
+         id="text202-7-5-1-2-3"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         sodipodi:linespacing="125%"><tspan
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+           id="tspan3104-6">Leaf</tspan></text>
+    </g>
+    <g
+       transform="translate(-2049.897,-585.6713)"
+       id="g3148">
+      <rect
+         ry="0"
+         id="rect118-3-5"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         rx="0"
+         height="412.66794"
+         width="3240.0085"
+         y="-4640.499"
+         x="3517.1572" />
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4418.6582"
+         x="3745.7725"
+         xml:space="preserve">rcu_node_context_switch()</text>
+    </g>
+    <g
+       transform="translate(3131.2648,-585.6713)"
+       id="g3148-5">
+      <rect
+         ry="0"
+         id="rect118-3-5-6"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         rx="0"
+         height="412.66794"
+         width="3240.0085"
+         y="-4640.499"
+         x="3517.1572" />
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-2"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4418.6582"
+         x="3745.7725"
+         xml:space="preserve">rcu_check_callbacks()</text>
+    </g>
+    <g
+       transform="translate(399.7744,828.86448)"
+       id="g3148-9">
+      <rect
+         ry="0"
+         id="rect118-3-5-1"
+         style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+         rx="0"
+         height="864.02148"
+         width="3540.9114"
+         y="-4640.499"
+         x="3517.1572" />
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-27"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4418.6582"
+         x="3745.7725"
+         xml:space="preserve">rcu_process_callbacks()</text>
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-27-0"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-4165.7954"
+         x="3745.7725"
+         xml:space="preserve">rcu_check_quiescent_state())</text>
+      <text
+         style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-3-27-0-9"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="-3914.085"
+         x="3745.7725"
+         xml:space="preserve">rcu__report_qs_rdp())</text>
+    </g>
+    <g
+       id="g4504-3"
+       transform="translate(5136.3339,-23870.546)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-5"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-5"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g4504-3-9"
+       transform="translate(5136.3339,-20417.959)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-1"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7-2"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-5-7"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3-0"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-5-9"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6-3"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2-6"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g4504-3-0"
+       transform="translate(-2824.9451,-23870.546)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,228.84485,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-6"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7-26"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-5-1"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3-8"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-5-7"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6-9"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2-2"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <g
+       id="g4504-3-9-0"
+       transform="translate(-2931.3303,-20417.959)">
+      <path
+         transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+         d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+         sodipodi:ry="39.550262"
+         sodipodi:rx="65.917107"
+         sodipodi:cy="345.54001"
+         sodipodi:cx="319.379"
+         id="path3084-6-1-2"
+         style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+         sodipodi:type="arc" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+         id="text202-7-5-1-2-7-2-3"
+         font-size="192"
+         font-weight="bold"
+         font-style="normal"
+         y="16835.086"
+         x="4409.043"
+         xml:space="preserve"><tspan
+           id="tspan3104-5-7-7"
+           style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">RCU</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3110-3-0-5"
+         y="17055.541"
+         x="4579.373"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17055.541"
+           x="4579.373"
+           id="tspan3112-5-9-9"
+           sodipodi:role="line">read-side</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3114-6-3-2"
+         y="17297.08"
+         x="4584.8276"
+         style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+         xml:space="preserve"><tspan
+           y="17297.08"
+           x="4584.8276"
+           id="tspan3116-2-6-2"
+           sodipodi:role="line">critical section</tspan></text>
+    </g>
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+       d="m 9699.0326,-6264.1445 0,2393.6632"
+       id="path3134-9-0-3-1-9-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#969696;stroke-width:53.19251633;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+       d="m 1640.3664,-6264.1445 0,2393.6632"
+       id="path3134-9-0-3-1-9-8-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+  </g>
+  <g
+     id="g4504"
+     transform="translate(2347.5727,554.69889)">
+    <path
+       transform="matrix(13.298129,0,0,13.298129,335.22989,12456.379)"
+       d="m 385.2961,345.54001 c 0,21.84301 -29.51209,39.55026 -65.9171,39.55026 -36.40501,0 -65.91711,-17.70725 -65.91711,-39.55026 0,-21.84301 29.5121,-39.55026 65.91711,-39.55026 36.40501,0 65.9171,17.70725 65.9171,39.55026 z"
+       sodipodi:ry="39.550262"
+       sodipodi:rx="65.917107"
+       sodipodi:cy="345.54001"
+       sodipodi:cx="319.379"
+       id="path3084"
+       style="fill:#ffffa1;fill-opacity:0;stroke:#000000;stroke-width:2.25600004;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2.256, 4.512;stroke-dashoffset:0"
+       sodipodi:type="arc" />
+    <text
+       sodipodi:linespacing="125%"
+       style="font-size:192px;font-style:normal;font-weight:bold;line-height:125%;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-1-2"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="16835.086"
+       x="4273.4326"
+       xml:space="preserve"><tspan
+         id="tspan3104"
+         style="font-size:159.57754517px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">Wake up</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3110"
+       y="17055.541"
+       x="4585.2246"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17055.541"
+         x="4585.2246"
+         id="tspan3112"
+         sodipodi:role="line">grace-period</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text3114"
+       y="17297.08"
+       x="4582.3804"
+       style="font-size:159.57754517px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       xml:space="preserve"><tspan
+         y="17297.08"
+         x="4582.3804"
+         id="tspan3116"
+         sodipodi:role="line">kernel thread</tspan></text>
+  </g>
+  <g
+     transform="translate(1783.6576,20674.512)"
+     id="g3148-2">
+    <rect
+       ry="0"
+       id="rect118-3-5-2"
+       style="fill:none;stroke:#000000;stroke-width:30.00057983;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057963, 60.00115926;stroke-dashoffset:0"
+       rx="0"
+       height="412.66794"
+       width="3240.0085"
+       y="-4640.499"
+       x="3517.1572" />
+    <text
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier"
+       id="text202-7-5-3-8"
+       font-size="192"
+       font-weight="bold"
+       font-style="normal"
+       y="-4418.6582"
+       x="4064.9268"
+       xml:space="preserve">rcu_report_qs_rsp()</text>
+  </g>
+</svg>
diff --git a/Documentation/RCU/Design/Memory-Ordering/rcu_node-lock.svg b/Documentation/RCU/Design/Memory-Ordering/rcu_node-lock.svg
new file mode 100644 (file)
index 0000000..94c96c5
--- /dev/null
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5e -->
+
+<!-- CreationDate: Wed Dec  9 17:35:03 2015 -->
+
+<!-- Magnification: 2.000 -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="303.54147"
+   height="211.57945"
+   viewBox="-44 -44 4036.5336 2812.3117"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="rcu_node-lock.svg">
+  <metadata
+     id="metadata212">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs210">
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path3970"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1087"
+     inkscape:window-height="1144"
+     id="namedview208"
+     showgrid="false"
+     inkscape:zoom="1.0495049"
+     inkscape:cx="311.2033"
+     inkscape:cy="168.10913"
+     inkscape:window-x="833"
+     inkscape:window-y="28"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="g4"
+     fit-margin-top="5"
+     fit-margin-right="5"
+     fit-margin-left="5"
+     fit-margin-bottom="5" />
+  <g
+     style="fill:none;stroke-width:0.025in"
+     id="g4"
+     transform="translate(-1905.5784,-4568.3024)">
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 8100 - 5710 5790-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 9300 - 4512 7140-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1040 9300 - 1502 7140-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2240 8100 - 2702 5940-->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1350 3450 - 2444 2510-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4950 3450 - 3854 2510-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 6600 - 4050 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1050 6600 - 1050 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2250 5400 - 2250 4290-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 2250 8100 - 2250 6240-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 1050 9300 - 1050 7440-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 4050 9300 - 4050 7440-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 8100 - 5250 6240-->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Circle -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9300 3150 - 10860 3150-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 11400 3600 - 11400 4410-->
+    <!-- Line: box -->
+    <rect
+       x="1943.0693"
+       y="4603.417"
+       width="3873.5518"
+       height="2650.6289"
+       rx="0"
+       style="stroke:#000000;stroke-width:30.00057793;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:30.00057884, 60.00115769;stroke-dashoffset:0"
+       id="rect118"
+       ry="0" />
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 11400 5100 - 11400 5910-->
+    <!-- Line: box -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9900 4650 - 10860 4650-->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 9600 6150 - 10860 6150-->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Line -->
+    <!-- Arrowhead on XXXpoint 5250 5400 - 5250 4290-->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Line: box -->
+    <!-- Text -->
+    <!-- Text -->
+    <!-- Text -->
+    <text
+       xml:space="preserve"
+       x="3105.219"
+       y="6425.6445"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;font-family:Courier">rcu_accelerate_cbs()</text>
+    <!-- Text -->
+    <!-- Text -->
+    <g
+       id="g3107"
+       transform="translate(747.5807,4700.8888)">
+      <rect
+         id="rect112"
+         style="stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1370.8721"
+         width="2809.1992"
+         y="949.37109"
+         x="2084.55" />
+      <rect
+         id="rect112-3"
+         style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:butt;stroke-linejoin:miter"
+         rx="0"
+         height="1294.8468"
+         width="2809.1992"
+         y="1025.3964"
+         x="2084.55" />
+    </g>
+    <text
+       xml:space="preserve"
+       x="2025.5763"
+       y="4825.2578"
+       font-style="normal"
+       font-weight="bold"
+       font-size="192"
+       id="text202-7"
+       style="font-size:192px;font-style:normal;font-weight:bold;text-anchor:start;fill:#000000;stroke-width:0.025in;font-family:Courier">rcu_prepare_for_idle()</text>
+  </g>
+</svg>
index 96a3d81837e1b120098eccfd1b95b0bfc4947be9..a08f928c8557507212d81ee7fbc2cd2c78f5a53e 100644 (file)
@@ -40,7 +40,9 @@ o     Booting Linux using a console connection that is too slow to
 o      Anything that prevents RCU's grace-period kthreads from running.
        This can result in the "All QSes seen" console-log message.
        This message will include information on when the kthread last
-       ran and how often it should be expected to run.
+       ran and how often it should be expected to run.  It can also
+       result in the "rcu_.*kthread starved for" console-log message,
+       which will include additional debugging information.
 
 o      A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might
        happen to preempt a low-priority task in the middle of an RCU
@@ -60,6 +62,20 @@ o    A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that
        CONFIG_PREEMPT_RCU case, you might see stall-warning
        messages.
 
+o      A periodic interrupt whose handler takes longer than the time
+       interval between successive pairs of interrupts.  This can
+       prevent RCU's kthreads and softirq handlers from running.
+       Note that certain high-overhead debugging options, for example
+       the function_graph tracer, can result in interrupt handler taking
+       considerably longer than normal, which can in turn result in
+       RCU CPU stall warnings.
+
+o      Testing a workload on a fast system, tuning the stall-warning
+       timeout down to just barely avoid RCU CPU stall warnings, and then
+       running the same workload with the same stall-warning timeout on a
+       slow system.  Note that thermal throttling and on-demand governors
+       can cause a single system to be sometimes fast and sometimes slow!
+
 o      A hardware or software issue shuts off the scheduler-clock
        interrupt on a CPU that is not in dyntick-idle mode.  This
        problem really has happened, and seems to be most likely to
@@ -155,67 +171,32 @@ Interpreting RCU's CPU Stall-Detector "Splats"
 For non-RCU-tasks flavors of RCU, when a CPU detects that it is stalling,
 it will print a message similar to the following:
 
-INFO: rcu_sched_state detected stall on CPU 5 (t=2500 jiffies)
-
-This message indicates that CPU 5 detected that it was causing a stall,
-and that the stall was affecting RCU-sched.  This message will normally be
-followed by a stack dump of the offending CPU.  On TREE_RCU kernel builds,
-RCU and RCU-sched are implemented by the same underlying mechanism,
-while on PREEMPT_RCU kernel builds, RCU is instead implemented
-by rcu_preempt_state.
-
-On the other hand, if the offending CPU fails to print out a stall-warning
-message quickly enough, some other CPU will print a message similar to
-the following:
-
-INFO: rcu_bh_state detected stalls on CPUs/tasks: { 3 5 } (detected by 2, 2502 jiffies)
+       INFO: rcu_sched detected stalls on CPUs/tasks:
+       2-...: (3 GPs behind) idle=06c/0/0 softirq=1453/1455 fqs=0
+       16-...: (0 ticks this GP) idle=81c/0/0 softirq=764/764 fqs=0
+       (detected by 32, t=2603 jiffies, g=7073, c=7072, q=625)
 
-This message indicates that CPU 2 detected that CPUs 3 and 5 were both
-causing stalls, and that the stall was affecting RCU-bh.  This message
+This message indicates that CPU 32 detected that CPUs 2 and 16 were both
+causing stalls, and that the stall was affecting RCU-sched.  This message
 will normally be followed by stack dumps for each CPU.  Please note that
-PREEMPT_RCU builds can be stalled by tasks as well as by CPUs,
-and that the tasks will be indicated by PID, for example, "P3421".
-It is even possible for a rcu_preempt_state stall to be caused by both
-CPUs -and- tasks, in which case the offending CPUs and tasks will all
-be called out in the list.
-
-Finally, if the grace period ends just as the stall warning starts
-printing, there will be a spurious stall-warning message:
-
-INFO: rcu_bh_state detected stalls on CPUs/tasks: { } (detected by 4, 2502 jiffies)
-
-This is rare, but does happen from time to time in real life.  It is also
-possible for a zero-jiffy stall to be flagged in this case, depending
-on how the stall warning and the grace-period initialization happen to
-interact.  Please note that it is not possible to entirely eliminate this
-sort of false positive without resorting to things like stop_machine(),
-which is overkill for this sort of problem.
-
-Recent kernels will print a long form of the stall-warning message:
-
-       INFO: rcu_preempt detected stall on CPU
-       0: (63959 ticks this GP) idle=241/3fffffffffffffff/0 softirq=82/543
-          (t=65000 jiffies)
-
-In kernels with CONFIG_RCU_FAST_NO_HZ, more information is printed:
-
-       INFO: rcu_preempt detected stall on CPU
-       0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 softirq=82/543 last_accelerate: a345/d342 nonlazy_posted: 25 .D
-          (t=65000 jiffies)
+PREEMPT_RCU builds can be stalled by tasks as well as by CPUs, and that
+the tasks will be indicated by PID, for example, "P3421".  It is even
+possible for a rcu_preempt_state stall to be caused by both CPUs -and-
+tasks, in which case the offending CPUs and tasks will all be called
+out in the list.
 
-The "(64628 ticks this GP)" indicates that this CPU has taken more
-than 64,000 scheduling-clock interrupts during the current stalled
-grace period.  If the CPU was not yet aware of the current grace
-period (for example, if it was offline), then this part of the message
-indicates how many grace periods behind the CPU is.
+CPU 2's "(3 GPs behind)" indicates that this CPU has not interacted with
+the RCU core for the past three grace periods.  In contrast, CPU 16's "(0
+ticks this GP)" indicates that this CPU has not taken any scheduling-clock
+interrupts during the current stalled grace period.
 
 The "idle=" portion of the message prints the dyntick-idle state.
 The hex number before the first "/" is the low-order 12 bits of the
-dynticks counter, which will have an even-numbered value if the CPU is
-in dyntick-idle mode and an odd-numbered value otherwise.  The hex
-number between the two "/"s is the value of the nesting, which will
-be a small positive number if in the idle loop and a very large positive
-number (as shown above) otherwise.
+dynticks counter, which will have an even-numbered value if the CPU
+is in dyntick-idle mode and an odd-numbered value otherwise.  The hex
+number between the two "/"s is the value of the nesting, which will be
+a small non-negative number if in the idle loop (as shown above) and a
+very large positive number otherwise.
 
 The "softirq=" portion of the message tracks the number of RCU softirq
 handlers that the stalled CPU has executed.  The number before the "/"
@@ -230,24 +211,72 @@ handlers are no longer able to execute on this CPU.  This can happen if
 the stalled CPU is spinning with interrupts are disabled, or, in -rt
 kernels, if a high-priority process is starving RCU's softirq handler.
 
-For CONFIG_RCU_FAST_NO_HZ kernels, the "last_accelerate:" prints the
-low-order 16 bits (in hex) of the jiffies counter when this CPU last
-invoked rcu_try_advance_all_cbs() from rcu_needs_cpu() or last invoked
-rcu_accelerate_cbs() from rcu_prepare_for_idle().  The "nonlazy_posted:"
-prints the number of non-lazy callbacks posted since the last call to
-rcu_needs_cpu().  Finally, an "L" indicates that there are currently
-no non-lazy callbacks ("." is printed otherwise, as shown above) and
-"D" indicates that dyntick-idle processing is enabled ("." is printed
-otherwise, for example, if disabled via the "nohz=" kernel boot parameter).
+The "fps=" shows the number of force-quiescent-state idle/offline
+detection passes that the grace-period kthread has made across this
+CPU since the last time that this CPU noted the beginning of a grace
+period.
+
+The "detected by" line indicates which CPU detected the stall (in this
+case, CPU 32), how many jiffies have elapsed since the start of the
+grace period (in this case 2603), the number of the last grace period
+to start and to complete (7073 and 7072, respectively), and an estimate
+of the total number of RCU callbacks queued across all CPUs (625 in
+this case).
+
+In kernels with CONFIG_RCU_FAST_NO_HZ, more information is printed
+for each CPU:
+
+       0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 softirq=82/543 last_accelerate: a345/d342 nonlazy_posted: 25 .D
+
+The "last_accelerate:" prints the low-order 16 bits (in hex) of the
+jiffies counter when this CPU last invoked rcu_try_advance_all_cbs()
+from rcu_needs_cpu() or last invoked rcu_accelerate_cbs() from
+rcu_prepare_for_idle().  The "nonlazy_posted:" prints the number
+of non-lazy callbacks posted since the last call to rcu_needs_cpu().
+Finally, an "L" indicates that there are currently no non-lazy callbacks
+("." is printed otherwise, as shown above) and "D" indicates that
+dyntick-idle processing is enabled ("." is printed otherwise, for example,
+if disabled via the "nohz=" kernel boot parameter).
+
+If the grace period ends just as the stall warning starts printing,
+there will be a spurious stall-warning message, which will include
+the following:
+
+       INFO: Stall ended before state dump start
+
+This is rare, but does happen from time to time in real life.  It is also
+possible for a zero-jiffy stall to be flagged in this case, depending
+on how the stall warning and the grace-period initialization happen to
+interact.  Please note that it is not possible to entirely eliminate this
+sort of false positive without resorting to things like stop_machine(),
+which is overkill for this sort of problem.
+
+If all CPUs and tasks have passed through quiescent states, but the
+grace period has nevertheless failed to end, the stall-warning splat
+will include something like the following:
+
+       All QSes seen, last rcu_preempt kthread activity 23807 (4297905177-4297881370), jiffies_till_next_fqs=3, root ->qsmask 0x0
+
+The "23807" indicates that it has been more than 23 thousand jiffies
+since the grace-period kthread ran.  The "jiffies_till_next_fqs"
+indicates how frequently that kthread should run, giving the number
+of jiffies between force-quiescent-state scans, in this case three,
+which is way less than 23807.  Finally, the root rcu_node structure's
+->qsmask field is printed, which will normally be zero.
 
 If the relevant grace-period kthread has been unable to run prior to
-the stall warning, the following additional line is printed:
+the stall warning, as was the case in the "All QSes seen" line above,
+the following additional line is printed:
 
-       rcu_preempt kthread starved for 2023 jiffies!
+       kthread starved for 23807 jiffies! g7073 c7072 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1
 
-Starving the grace-period kthreads of CPU time can of course result in
-RCU CPU stall warnings even when all CPUs and tasks have passed through
-the required quiescent states.
+Starving the grace-period kthreads of CPU time can of course result
+in RCU CPU stall warnings even when all CPUs and tasks have passed
+through the required quiescent states.  The "g" and "c" numbers flag the
+number of the last grace period started and completed, respectively,
+the "f" precedes the ->gp_flags command to the grace-period kthread,
+the "RCU_GP_WAIT_FQS" indicates that the kthread is waiting for a short
+timeout, and the "state" precedes value of the task_struct ->state field.
 
 
 Multiple Warnings From One Stall
@@ -264,13 +293,28 @@ Stall Warnings for Expedited Grace Periods
 If an expedited grace period detects a stall, it will place a message
 like the following in dmesg:
 
-       INFO: rcu_sched detected expedited stalls on CPUs: { 1 2 6 } 26009 jiffies s: 1043
-
-This indicates that CPUs 1, 2, and 6 have failed to respond to a
-reschedule IPI, that the expedited grace period has been going on for
-26,009 jiffies, and that the expedited grace-period sequence counter is
-1043.  The fact that this last value is odd indicates that an expedited
-grace period is in flight.
+       INFO: rcu_sched detected expedited stalls on CPUs/tasks: { 7-... } 21119 jiffies s: 73 root: 0x2/.
+
+This indicates that CPU 7 has failed to respond to a reschedule IPI.
+The three periods (".") following the CPU number indicate that the CPU
+is online (otherwise the first period would instead have been "O"),
+that the CPU was online at the beginning of the expedited grace period
+(otherwise the second period would have instead been "o"), and that
+the CPU has been online at least once since boot (otherwise, the third
+period would instead have been "N").  The number before the "jiffies"
+indicates that the expedited grace period has been going on for 21,119
+jiffies.  The number following the "s:" indicates that the expedited
+grace-period sequence counter is 73.  The fact that this last value is
+odd indicates that an expedited grace period is in flight.  The number
+following "root:" is a bitmask that indicates which children of the root
+rcu_node structure correspond to CPUs and/or tasks that are blocking the
+current expedited grace period.  If the tree had more than one level,
+additional hex numbers would be printed for the states of the other
+rcu_node structures in the tree.
+
+As with normal grace periods, PREEMPT_RCU builds can be stalled by
+tasks as well as by CPUs, and that the tasks will be indicated by PID,
+for example, "P3421".
 
 It is entirely possible to see stall warnings from normal and from
-expedited grace periods at about the same time from the same run.
+expedited grace periods at about the same time during the same run.
diff --git a/Documentation/acpi/lpit.txt b/Documentation/acpi/lpit.txt
new file mode 100644 (file)
index 0000000..b426398
--- /dev/null
@@ -0,0 +1,25 @@
+To enumerate platform Low Power Idle states, Intel platforms are using
+“Low Power Idle Table” (LPIT). More details about this table can be
+downloaded from:
+http://www.uefi.org/sites/default/files/resources/Intel_ACPI_Low_Power_S0_Idle.pdf
+
+Residencies for each low power state can be read via FFH
+(Function fixed hardware) or a memory mapped interface.
+
+On platforms supporting S0ix sleep states, there can be two types of
+residencies:
+- CPU PKG C10 (Read via FFH interface)
+- Platform Controller Hub (PCH) SLP_S0 (Read via memory mapped interface)
+
+The following attributes are added dynamically to the cpuidle
+sysfs attribute group:
+       /sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us
+       /sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us
+
+The "low_power_idle_cpu_residency_us" attribute shows time spent
+by the CPU package in PKG C10
+
+The "low_power_idle_system_residency_us" attribute shows SLP_S0
+residency, or system time spent with the SLP_S0# signal asserted.
+This is the lowest possible system power state, achieved only when CPU is in
+PKG C10 and all functional blocks in PCH are in a low power state.
index b5343c5aa224ce0ffbbddadc8d2a73e3c427f3b1..63066db39910b29dfe4371d780730757199eced7 100644 (file)
@@ -350,7 +350,7 @@ If something goes wrong
    help debugging the problem.  The text above the dump is also
    important: it tells something about why the kernel dumped code (in
    the above example, it's due to a bad kernel pointer). More information
-   on making sense of the dump is in Documentation/admin-guide/oops-tracing.rst
+   on making sense of the dump is in Documentation/admin-guide/bug-hunting.rst
 
  - If you compiled the kernel with CONFIG_KALLSYMS you can send the dump
    as is, otherwise you will have to use the ``ksymoops`` program to make
index 08c4b13081898fc458f9b51593e884b5bbdc0a6c..f278b289e260d4ebb2ad8e0cde7b2c9b367930dc 100644 (file)
@@ -240,7 +240,7 @@ In order to report it upstream, you should identify the mailing list
 used for the development of the affected code. This can be done by using
 the ``get_maintainer.pl`` script.
 
-For example, if you find a bug at the gspca's conex.c file, you can get
+For example, if you find a bug at the gspca's sonixj.c file, you can get
 their maintainers with::
 
        $ ./scripts/get_maintainer.pl -f drivers/media/usb/gspca/sonixj.c
@@ -257,7 +257,7 @@ Please notice that it will point to:
   Tejun and Bhaktipriya (in this specific case, none really envolved on the
   development of this file);
 - The driver maintainer (Hans Verkuil);
-- The subsystem maintainer (Mauro Carvalho Chehab)
+- The subsystem maintainer (Mauro Carvalho Chehab);
 - The driver and/or subsystem mailing list (linux-media@vger.kernel.org);
 - the Linux Kernel mailing list (linux-kernel@vger.kernel.org).
 
@@ -274,14 +274,14 @@ Fixing the bug
 --------------
 
 If you know programming, you could help us by not only reporting the bug,
-but also providing us with a solution. After all open source is about
+but also providing us with a solution. After all, open source is about
 sharing what you do and don't you want to be recognised for your genius?
 
 If you decide to take this way, once you have worked out a fix please submit
 it upstream.
 
 Please do read
-ref:`Documentation/process/submitting-patches.rst <submittingpatches>` though
+:ref:`Documentation/process/submitting-patches.rst <submittingpatches>` though
 to help your code get accepted.
 
 
index 05496622b4effb8212eb2175bea67f9a7bebe0d0..b74e13312fdc291d55ac29b137cc8df4ee608b5e 100644 (file)
        amijoy.map=     [HW,JOY] Amiga joystick support
                        Map of devices attached to JOY0DAT and JOY1DAT
                        Format: <a>,<b>
-                       See also Documentation/input/joystick.txt
+                       See also Documentation/input/joydev/joystick.rst
 
        analog.map=     [HW,JOY] Analog joystick and gamepad support
                        Specifies type or capabilities of an analog joystick
        bttv.card=      [HW,V4L] bttv (bt848 + bt878 based grabber cards)
        bttv.radio=     Most important insmod options are available as
                        kernel args too.
-       bttv.pll=       See Documentation/video4linux/bttv/Insmod-options
+       bttv.pll=       See Documentation/media/v4l-drivers/bttv.rst
        bttv.tuner=
 
        bulk_remove=off [PPC]  This parameter disables the use of the pSeries
                For now, only VisioBraille is supported.
 
        consoleblank=   [KNL] The console blank (screen saver) timeout in
-                       seconds. Defaults to 10*60 = 10mins. A value of 0
-                       disables the blank timer.
+                       seconds. A value of 0 disables the blank timer.
+                       Defaults to 0.
 
        coredump_filter=
                        [KNL] Change the default value for
                        It will be ignored when crashkernel=X,high is not used
                        or memory reserved is below 4G.
 
+       crossrelease_fullstack
+                       [KNL] Allow to record full stack trace in cross-release
+
        cryptomgr.notests
                         [KNL] Disable crypto self-tests
 
        db9.dev[2|3]=   [HW,JOY] Multisystem joystick support via parallel port
                        (one device per port)
                        Format: <port#>,<type>
-                       See also Documentation/input/joystick-parport.txt
+                       See also Documentation/input/devices/joystick-parport.rst
 
        ddebug_query=   [KNL,DYNAMIC_DEBUG] Enable debug messages at early boot
                        time. See
                        [HW,JOY] Multisystem joystick and NES/SNES/PSX pad
                        support via parallel port (up to 5 devices per port)
                        Format: <port#>,<pad1>,<pad2>,<pad3>,<pad4>,<pad5>
-                       See also Documentation/input/joystick-parport.txt
+                       See also Documentation/input/devices/joystick-parport.rst
 
        gamma=          [HW,DRM]
 
        irqaffinity=    [SMP] Set the default irq affinity mask
                        The argument is a cpu list, as described above.
 
+       irqchip.gicv2_force_probe=
+                       [ARM, ARM64]
+                       Format: <bool>
+                       Force the kernel to look for the second 4kB page
+                       of a GICv2 controller even if the memory range
+                       exposed by the device tree is too small.
+
        irqfixup        [HW]
                        When an interrupt is not handled search all handlers
                        for it. Intended to get systems with badly broken
        isapnp=         [ISAPNP]
                        Format: <RDP>,<reset>,<pci_scan>,<verbosity>
 
-       isolcpus=       [KNL,SMP] Isolate CPUs from the general scheduler.
-                       The argument is a cpu list, as described above.
+       isolcpus=       [KNL,SMP] Isolate a given set of CPUs from disturbance.
+                       [Deprecated - use cpusets instead]
+                       Format: [flag-list,]<cpu-list>
+
+                       Specify one or more CPUs to isolate from disturbances
+                       specified in the flag list (default: domain):
+
+                       nohz
+                         Disable the tick when a single task runs.
+                       domain
+                         Isolate from the general SMP balancing and scheduling
+                         algorithms. Note that performing domain isolation this way
+                         is irreversible: it's not possible to bring back a CPU to
+                         the domains once isolated through isolcpus. It's strongly
+                         advised to use cpusets instead to disable scheduler load
+                         balancing through the "cpuset.sched_load_balance" file.
+                         It offers a much more flexible interface where CPUs can
+                         move in and out of an isolated set anytime.
+
+                         You can move a process onto or off an "isolated" CPU via
+                         the CPU affinity syscalls or cpuset.
+                         <cpu number> begins at 0 and the maximum value is
+                         "number of CPUs in system - 1".
+
+                       The format of <cpu-list> is described above.
 
-                       This option can be used to specify one or more CPUs
-                       to isolate from the general SMP balancing and scheduling
-                       algorithms. You can move a process onto or off an
-                       "isolated" CPU via the CPU affinity syscalls or cpuset.
-                       <cpu number> begins at 0 and the maximum value is
-                       "number of CPUs in system - 1".
 
-                       This option is the preferred way to isolate CPUs. The
-                       alternative -- manually setting the CPU mask of all
-                       tasks in the system -- can cause problems and
-                       suboptimal load balancer performance.
 
        iucv=           [HW,NET]
 
                                ivrs_acpihid[00:14.5]=AMD0020:0
 
        js=             [HW,JOY] Analog joystick
-                       See Documentation/input/joystick.txt.
+                       See Documentation/input/joydev/joystick.rst.
 
        nokaslr         [KNL]
                        When CONFIG_RANDOMIZE_BASE is set, this disables
                        s2idle  - Suspend-To-Idle
                        shallow - Power-On Suspend or equivalent (if supported)
                        deep    - Suspend-To-RAM or equivalent (if supported)
-                       See Documentation/power/states.txt.
+                       See Documentation/admin-guide/pm/sleep-states.rst.
 
        meye.*=         [HW] Set MotionEye Camera parameters
-                       See Documentation/video4linux/meye.txt.
+                       See Documentation/media/v4l-drivers/meye.rst.
 
        mfgpt_irq=      [IA-32] Specify the IRQ to use for the
                        Multi-Function General Purpose Timers on AMD Geode
 
        noalign         [KNL,ARM]
 
+       noaltinstr      [S390] Disables alternative instructions patching
+                       (CPU alternatives feature).
+
        noapic          [SMP,APIC] Tells the kernel to not make use of any
                        IOAPICs that may be present in the system.
 
 
        plip=           [PPT,NET] Parallel port network link
                        Format: { parport<nr> | timid | 0 }
-                       See also Documentation/parport.txt.
+                       See also Documentation/admin-guide/parport.rst.
 
        pmtmr=          [X86] Manual setup of pmtmr I/O Port.
                        Override pmtimer IOPort with a hex value.
        rcutorture.stall_cpu_holdoff= [KNL]
                        Time to wait (s) after boot before inducing stall.
 
+       rcutorture.stall_cpu_irqsoff= [KNL]
+                       Disable interrupts while stalling if set.
+
        rcutorture.stat_interval= [KNL]
                        Time (s) between statistics printk()s.
 
                        [KNL] Should the soft-lockup detector generate panics.
                        Format: <integer>
 
+                       A nonzero value instructs the soft-lockup detector
+                       to panic the machine when a soft-lockup occurs. This
+                       is also controlled by CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC
+                       which is the respective build-time switch to that
+                       functionality.
+
        softlockup_all_cpu_backtrace=
                        [KNL] Should the soft-lockup detector generate
                        backtraces on all cpus.
                        Used to run time disable IRQ_TIME_ACCOUNTING on any
                        platforms where RDTSC is slow and this accounting
                        can add overhead.
+                       [x86] unstable: mark the TSC clocksource as unstable, this
+                       marks the TSC unconditionally unstable at bootup and
+                       avoids any further wobbles once the TSC watchdog notices.
 
        turbografx.map[2|3]=    [HW,JOY]
                        TurboGraFX parallel port interface
                        Format:
                        <port#>,<js1>,<js2>,<js3>,<js4>,<js5>,<js6>,<js7>
-                       See also Documentation/input/joystick-parport.txt
+                       See also Documentation/input/devices/joystick-parport.rst
 
        udbg-immortal   [PPC] When debugging early kernel crashes that
                        happen after console_init() and before a proper
index 26b60b41965277df1753a8704d972b6adeacddb0..4650edb8840a96b7a6bda742b466e039b9a0dd41 100644 (file)
@@ -94,7 +94,7 @@ step-by-step instructions for how a user can trigger the bug.
 
 If the failure includes an "OOPS:", take a picture of the screen, capture
 a netconsole trace, or type the message from your screen into the bug
-report.  Please read "Documentation/admin-guide/oops-tracing.rst" before posting your
+report.  Please read "Documentation/admin-guide/bug-hunting.rst" before posting your
 bug report. This explains what you should do with the "Oops" information
 to make it useful to the recipient.
 
@@ -120,7 +120,7 @@ summary from [1.]>" for easy identification by the developers::
   [4.2.] Kernel .config file:
   [5.] Most recent kernel version which did not have the bug:
   [6.] Output of Oops.. message (if applicable) with symbolic information
-       resolved (see Documentation/admin-guide/oops-tracing.rst)
+       resolved (see Documentation/admin-guide/bug-hunting.rst)
   [7.] A small shell script or example program which triggers the
        problem (if possible)
   [8.] Environment
index 66e8ce14d23d03ab654c0c14699bd7845ad91aa9..304bf22bb83cc0ec8dfbbcf2a48b206ecb781afb 100644 (file)
@@ -70,6 +70,7 @@ stable kernels.
 |                |                 |                 |                             |
 | Hisilicon      | Hip0{5,6,7}     | #161010101      | HISILICON_ERRATUM_161010101 |
 | Hisilicon      | Hip0{6,7}       | #161010701      | N/A                         |
+| Hisilicon      | Hip07           | #161600802      | HISILICON_ERRATUM_161600802 |
 |                |                 |                 |                             |
 | Qualcomm Tech. | Falkor v1       | E1003           | QCOM_FALKOR_ERRATUM_1003    |
 | Qualcomm Tech. | Falkor v1       | E1009           | QCOM_FALKOR_ERRATUM_1009    |
index f4dc9de2694e90019ea8377537dfe40aeef1df8e..a5f2a7f1ff4601dcb774489ae85545e7ec797c89 100644 (file)
@@ -55,13 +55,9 @@ This driver provides the following features:
    (to compile support as a module which can be loaded and unloaded)
    to the options: 
 
-      Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
+      ATA/ATAPI/MFM/RLL support
       Include IDE/ATAPI CDROM support
 
-   and `no' to
-
-      Use old disk-only driver on primary interface
-
    Depending on what type of IDE interface you have, you may need to
    specify additional configuration options.  See
    Documentation/ide/ide.txt.
index 5da10184d9084a77c15e42b56f76a4571193344a..2d9da6c40a4d36e6d75ecf5d37e11cbd0ca18d14 100644 (file)
@@ -2,11 +2,9 @@
 The Linux Kernel API
 ====================
 
-Data Types
-==========
 
-Doubly Linked Lists
--------------------
+List Management Functions
+=========================
 
 .. kernel-doc:: include/linux/list.h
    :internal:
@@ -55,12 +53,27 @@ The Linux kernel provides more basic utility functions.
 Bitmap Operations
 -----------------
 
+.. kernel-doc:: lib/bitmap.c
+   :doc: bitmap introduction
+
+.. kernel-doc:: include/linux/bitmap.h
+   :doc: declare bitmap
+
+.. kernel-doc:: include/linux/bitmap.h
+   :doc: bitmap overview
+
+.. kernel-doc:: include/linux/bitmap.h
+   :doc: bitmap bitops
+
 .. kernel-doc:: lib/bitmap.c
    :export:
 
 .. kernel-doc:: lib/bitmap.c
    :internal:
 
+.. kernel-doc:: include/linux/bitmap.h
+   :internal:
+
 Command-line Parsing
 --------------------
 
@@ -70,13 +83,16 @@ Command-line Parsing
 CRC Functions
 -------------
 
+.. kernel-doc:: lib/crc4.c
+   :export:
+
 .. kernel-doc:: lib/crc7.c
    :export:
 
-.. kernel-doc:: lib/crc16.c
+.. kernel-doc:: lib/crc8.c
    :export:
 
-.. kernel-doc:: lib/crc-itu-t.c
+.. kernel-doc:: lib/crc16.c
    :export:
 
 .. kernel-doc:: lib/crc32.c
@@ -84,6 +100,9 @@ CRC Functions
 .. kernel-doc:: lib/crc-ccitt.c
    :export:
 
+.. kernel-doc:: lib/crc-itu-t.c
+   :export:
+
 idr/ida Functions
 -----------------
 
@@ -96,6 +115,30 @@ idr/ida Functions
 .. kernel-doc:: lib/idr.c
    :export:
 
+Math Functions in Linux
+=======================
+
+Base 2 log and power Functions
+------------------------------
+
+.. kernel-doc:: include/linux/log2.h
+   :internal:
+
+Division Functions
+------------------
+
+.. kernel-doc:: include/asm-generic/div64.h
+   :functions: do_div
+
+.. kernel-doc:: include/linux/math64.h
+   :internal:
+
+.. kernel-doc:: lib/div64.c
+   :functions: div_s64_rem div64_u64_rem div64_u64 div64_s64
+
+.. kernel-doc:: lib/gcd.c
+   :export:
+
 Memory Management in Linux
 ==========================
 
index 2bbe207354ed7c7e73ceb7f51ddb105c49827a1d..a873855c811d63f3a47cd2ec830404abb89d48c8 100644 (file)
@@ -90,6 +90,9 @@ Freq_i to Freq_j. Freq_i is in descending order with increasing rows and
 Freq_j is in descending order with increasing columns. The output here also 
 contains the actual freq values for each row and column for better readability.
 
+If the transition table is bigger than PAGE_SIZE, reading this will
+return an -EFBIG error.
+
 --------------------------------------------------------------------------------
 <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
    From  :    To
index 4a64b4c69d3f9590733b8b5e23899449748fcabf..37e474ff69115da89dd780475a35d119d5ee4383 100644 (file)
@@ -209,7 +209,7 @@ err.log will now have the profiling information, while stdout will
 provide some progress information as Coccinelle moves forward with
 work.
 
-DEBUG_FILE support is only supported when using coccinelle >= 1.2.
+DEBUG_FILE support is only supported when using coccinelle >= 1.0.2.
 
 .cocciconfig support
 --------------------
index ebd03d11d2c226906bfc10149e5a5724ec498c3d..e80850eefe138156cc94db035384391207bb23ec 100644 (file)
@@ -31,6 +31,17 @@ To build and run the tests with a single command, use::
 
 Note that some tests will require root privileges.
 
+Build and run from user specific object directory (make O=dir)::
+
+  $ make O=/tmp/kselftest kselftest
+
+Build and run KBUILD_OUTPUT directory (make KBUILD_OUTPUT=)::
+
+  $ make KBUILD_OUTPUT=/tmp/kselftest kselftest
+
+The above commands run the tests and print pass/fail summary to make it
+easier to understand the test results. Please find the detailed individual
+test results for each test in /tmp/testname file(s).
 
 Running a subset of selftests
 =============================
@@ -46,10 +57,21 @@ You can specify multiple tests to build and run::
 
   $  make TARGETS="size timers" kselftest
 
+Build and run from user specific object directory (make O=dir)::
+
+  $ make O=/tmp/kselftest TARGETS="size timers" kselftest
+
+Build and run KBUILD_OUTPUT directory (make KBUILD_OUTPUT=)::
+
+  $ make KBUILD_OUTPUT=/tmp/kselftest TARGETS="size timers" kselftest
+
+The above commands run the tests and print pass/fail summary to make it
+easier to understand the test results. Please find the detailed individual
+test results for each test in /tmp/testname file(s).
+
 See the top-level tools/testing/selftests/Makefile for the list of all
 possible targets.
 
-
 Running the full range hotplug selftests
 ========================================
 
@@ -113,9 +135,17 @@ Contributing new tests (details)
  * Use TEST_GEN_XXX if such binaries or files are generated during
    compiling.
 
-   TEST_PROGS, TEST_GEN_PROGS mean it is the excutable tested by
+   TEST_PROGS, TEST_GEN_PROGS mean it is the executable tested by
    default.
 
+   TEST_CUSTOM_PROGS should be used by tests that require custom build
+   rule and prevent common build rule use.
+
+   TEST_PROGS are for test shell scripts. Please ensure shell script has
+   its exec bit set. Otherwise, lib.mk run_tests will generate a warning.
+
+   TEST_CUSTOM_PROGS and TEST_PROGS will be run by common run_tests.
+
    TEST_PROGS_EXTENDED, TEST_GEN_PROGS_EXTENDED mean it is the
    executable which is not tested by default.
    TEST_FILES, TEST_GEN_FILES mean it is the file which is used by
diff --git a/Documentation/devicetree/bindings/hwmon/max1619.txt b/Documentation/devicetree/bindings/hwmon/max1619.txt
new file mode 100644 (file)
index 0000000..c70dbbe
--- /dev/null
@@ -0,0 +1,12 @@
+Bindings for MAX1619 Temperature Sensor
+
+Required properties:
+- compatible : "maxim,max1619"
+- reg        : I2C address, one of 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, or
+               0x4d, 0x4e
+
+Example:
+       temp@4c {
+               compatible = "maxim,max1619";
+               reg = <0x4c>;
+       };
diff --git a/Documentation/devicetree/bindings/hwmon/max31785.txt b/Documentation/devicetree/bindings/hwmon/max31785.txt
new file mode 100644 (file)
index 0000000..106e08c
--- /dev/null
@@ -0,0 +1,22 @@
+Bindings for the Maxim MAX31785 Intelligent Fan Controller
+==========================================================
+
+Reference:
+
+https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
+
+The Maxim MAX31785 is a PMBus device providing closed-loop, multi-channel fan
+management with temperature and remote voltage sensing. Various fan control
+features are provided, including PWM frequency control, temperature hysteresis,
+dual tachometer measurements, and fan health monitoring.
+
+Required properties:
+- compatible     : One of "maxim,max31785" or "maxim,max31785a"
+- reg            : I2C address, one of 0x52, 0x53, 0x54, 0x55.
+
+Example:
+
+        fans@52 {
+                compatible = "maxim,max31785";
+                reg = <0x52>;
+        };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
new file mode 100644 (file)
index 0000000..a83f9a5
--- /dev/null
@@ -0,0 +1,36 @@
+Amlogic meson GPIO interrupt controller
+
+Meson SoCs contains an interrupt controller which is able to watch the SoC
+pads and generate an interrupt on edge or level. The controller is essentially
+a 256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge
+or level and polarity. It does not expose all 256 mux inputs because the
+documentation shows that the upper part is not mapped to any pad. The actual
+number of interrupt exposed depends on the SoC.
+
+Required properties:
+
+- compatible : must have "amlogic,meson8-gpio-intc” and either
+   “amlogic,meson8-gpio-intc” for meson8 SoCs (S802) or
+   “amlogic,meson8b-gpio-intc” for meson8b SoCs (S805) or
+   “amlogic,meson-gxbb-gpio-intc” for GXBB SoCs (S905) or
+   “amlogic,meson-gxl-gpio-intc” for GXL SoCs (S905X, S912)
+- interrupt-parent : a phandle to the GIC the interrupts are routed to.
+   Usually this is provided at the root level of the device tree as it is
+   common to most of the SoC.
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+   interrupt source. The value must be 2.
+- meson,channel-interrupts: Array with the 8 upstream hwirq numbers. These
+   are the hwirqs used on the parent interrupt controller.
+
+Example:
+
+gpio_interrupt: interrupt-controller@9880 {
+       compatible = "amlogic,meson-gxbb-gpio-intc",
+                    "amlogic,meson-gpio-intc";
+       reg = <0x0 0x9880 0x0 0x10>;
+       interrupt-controller;
+       #interrupt-cells = <2>;
+       meson,channel-interrupts = <64 65 66 67 68 69 70 71>;
+};
index 5eb108e180fa282711a4d448c8353196ae6cadf1..0a57f2f4167de1994bf5254ad99503fe22e3e224 100644 (file)
@@ -75,6 +75,10 @@ These nodes must have the following properties:
 - reg: Specifies the base physical address and size of the ITS
   registers.
 
+Optional:
+- socionext,synquacer-pre-its: (u32, u32) tuple describing the untranslated
+  address and size of the pre-ITS window.
+
 The main GIC node must contain the appropriate #address-cells,
 #size-cells and ranges properties for the reg property of all ITS
 nodes.
index 448273a30a111b14120525ece19385d42138c21c..36df06c5c567df9cea4ff0e3ab26c92c4ea16f57 100644 (file)
@@ -2,7 +2,8 @@ Broadcom Generic Level 2 Interrupt Controller
 
 Required properties:
 
-- compatible: should be "brcm,l2-intc"
+- compatible: should be "brcm,l2-intc" for latched interrupt controllers
+              should be "brcm,bcm7271-l2-intc" for level interrupt controllers
 - reg: specifies the base physical address and size of the registers
 - interrupt-controller: identifies the node as an interrupt controller
 - #interrupt-cells: specifies the number of cells needed to encode an
diff --git a/Documentation/devicetree/bindings/interrupt-controller/openrisc,ompic.txt b/Documentation/devicetree/bindings/interrupt-controller/openrisc,ompic.txt
new file mode 100644 (file)
index 0000000..caec07c
--- /dev/null
@@ -0,0 +1,22 @@
+Open Multi-Processor Interrupt Controller
+
+Required properties:
+
+- compatible : This should be "openrisc,ompic"
+- reg : Specifies base physical address and size of the register space. The
+  size is based on the number of cores the controller has been configured
+  to handle, this should be set to 8 bytes per cpu core.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : This should be set to 0 as this will not be an irq
+  parent.
+- interrupts : Specifies the interrupt line to which the ompic is wired.
+
+Example:
+
+ompic: interrupt-controller@98000000 {
+       compatible = "openrisc,ompic";
+       reg = <0x98000000 16>;
+       interrupt-controller;
+       #interrupt-cells = <0>;
+       interrupts = <1>;
+};
index e3f052d8c11a24c34409b174b5117779b2ecdc5d..33c9a10fdc91a1dca6f7e09308ab81862f2e5874 100644 (file)
@@ -13,6 +13,9 @@ Required properties:
     - "renesas,irqc-r8a7793" (R-Car M2-N)
     - "renesas,irqc-r8a7794" (R-Car E2)
     - "renesas,intc-ex-r8a7795" (R-Car H3)
+    - "renesas,intc-ex-r8a7796" (R-Car M3-W)
+    - "renesas,intc-ex-r8a77970" (R-Car V3M)
+    - "renesas,intc-ex-r8a77995" (R-Car D3)
 - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
   interrupts.txt in this directory
 - clocks: Must contain a reference to the functional clock.
diff --git a/Documentation/devicetree/bindings/interrupt-controller/socionext,synquacer-exiu.txt b/Documentation/devicetree/bindings/interrupt-controller/socionext,synquacer-exiu.txt
new file mode 100644 (file)
index 0000000..8b2faef
--- /dev/null
@@ -0,0 +1,32 @@
+Socionext SynQuacer External Interrupt Unit (EXIU)
+
+The Socionext Synquacer SoC has an external interrupt unit (EXIU)
+that forwards a block of 32 configurable input lines to 32 adjacent
+level-high type GICv3 SPIs.
+
+Required properties:
+
+- compatible           : Should be "socionext,synquacer-exiu".
+- reg                  : Specifies base physical address and size of the
+                         control registers.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells     : Specifies the number of cells needed to encode an
+                         interrupt source. The value must be 3.
+- interrupt-parent     : phandle of the GIC these interrupts are routed to.
+- socionext,spi-base   : The SPI number of the first SPI of the 32 adjacent
+                         ones the EXIU forwards its interrups to.
+
+Notes:
+
+- Only SPIs can use the EXIU as an interrupt parent.
+
+Example:
+
+       exiu: interrupt-controller@510c0000 {
+               compatible = "socionext,synquacer-exiu";
+               reg = <0x0 0x510c0000 0x0 0x20>;
+               interrupt-controller;
+               interrupt-parent = <&gic>;
+               #interrupt-cells = <3>;
+               socionext,spi-base = <112>;
+       };
index 6e7703d4ff5b67ced053e79ee511f4e284fb822a..edf03f09244b352565b6a15d0d8cde162cf2599f 100644 (file)
@@ -2,7 +2,9 @@ STM32 External Interrupt Controller
 
 Required properties:
 
-- compatible: Should be "st,stm32-exti"
+- compatible: Should be:
+    "st,stm32-exti"
+    "st,stm32h7-exti"
 - reg: Specifies base physical address and size of the registers
 - interrupt-controller: Indentifies the node as an interrupt controller
 - #interrupt-cells: Specifies the number of cells to encode an interrupt
diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
new file mode 100644 (file)
index 0000000..8765c60
--- /dev/null
@@ -0,0 +1,54 @@
+* Amlogic Meson6, Meson8 and Meson8b SDIO/MMC controller
+
+The highspeed MMC host controller on Amlogic SoCs provides an interface
+for MMC, SD, SDIO and SDHC types of memory cards.
+
+Supported maximum speeds are the ones of the eMMC standard 4.41 as well
+as the speed of SD standard 2.0.
+
+The hardware provides an internal "mux" which allows up to three slots
+to be controlled. Only one slot can be accessed at a time.
+
+Required properties:
+ - compatible : must be one of
+       - "amlogic,meson8-sdio"
+       - "amlogic,meson8b-sdio"
+       along with the generic "amlogic,meson-mx-sdio"
+ - reg : mmc controller base registers
+ - interrupts : mmc controller interrupt
+ - #address-cells : must be 1
+ - size-cells : must be 0
+ - clocks : phandle to clock providers
+ - clock-names : must contain "core" and "clkin"
+
+Required child nodes:
+A node for each slot provided by the MMC controller is required.
+NOTE: due to a driver limitation currently only one slot (= child node)
+      is supported!
+
+Required properties on each child node (= slot):
+ - compatible : must be "mmc-slot" (see mmc.txt within this directory)
+ - reg : the slot (or "port") ID
+
+Optional properties on each child node (= slot):
+ - bus-width : must be 1 or 4 (8-bit bus is not supported)
+ - for cd and all other additional generic mmc parameters
+   please refer to mmc.txt within this directory
+
+Examples:
+       mmc@c1108c20 {
+               compatible = "amlogic,meson8-sdio", "amlogic,meson-mx-sdio";
+               reg = <0xc1108c20 0x20>;
+               interrupts = <0 28 1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&clkc CLKID_SDIO>, <&clkc CLKID_CLK81>;
+               clock-names = "core", "clkin";
+
+               slot@1 {
+                       compatible = "mmc-slot";
+                       reg = <1>;
+
+                       bus-width = <4>;
+               };
+       };
index b32ade645ad97cbc655dbd0b53b7a998905d6f7f..94a90b49a6925dfff4b0b18a5a60f65c4852583c 100644 (file)
@@ -53,6 +53,9 @@ Optional properties:
 - no-sdio: controller is limited to send sdio cmd during initialization
 - no-sd: controller is limited to send sd cmd during initialization
 - no-mmc: controller is limited to send mmc cmd during initialization
+- fixed-emmc-driver-type: for non-removable eMMC, enforce this driver type.
+  The value <n> is the driver type as specified in the eMMC specification
+  (table 206 in spec version 5.1).
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
index 4182ea36ca5b1ca2e1282f93a2d398cacb1fc357..72d2a734ab851cb3312f327c28de942c2531a765 100644 (file)
@@ -7,10 +7,18 @@ This file documents differences between the core properties in mmc.txt
 and the properties used by the msdc driver.
 
 Required properties:
-- compatible: Should be "mediatek,mt8173-mmc","mediatek,mt8135-mmc"
+- compatible: value should be either of the following.
+       "mediatek,mt8135-mmc": for mmc host ip compatible with mt8135
+       "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
+       "mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
+       "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
+- reg: physical base address of the controller and length
 - interrupts: Should contain MSDC interrupt number
-- clocks: MSDC source clock, HCLK
-- clock-names: "source", "hclk"
+- clocks: Should contain phandle for the clock feeding the MMC controller
+- clock-names: Should contain the following:
+       "source" - source clock (required)
+       "hclk" - HCLK which used for host (required)
+       "source_cg" - independent source clock gate (required for MT2712)
 - pinctrl-names: should be "default", "state_uhs"
 - pinctrl-0: should contain default/high speed pin ctrl
 - pinctrl-1: should contain uhs mode pin ctrl
@@ -30,6 +38,10 @@ Optional properties:
 - mediatek,hs400-cmd-resp-sel-rising:  HS400 command response sample selection
                                       If present,HS400 command responses are sampled on rising edges.
                                       If not present,HS400 command responses are sampled on falling edges.
+- mediatek,latch-ck: Some SoCs do not support enhance_rx, need set correct latch-ck to avoid data crc
+                    error caused by stop clock(fifo full)
+                    Valid range = [0:0x7]. if not present, default value is 0.
+                    applied to compatible "mediatek,mt2701-mmc".
 
 Examples:
 mmc0: mmc@11230000 {
index de2c53cff4f133c0ac7a853910a2651b9db4c473..3ee9263adf7354cfc7d62e0839f2fb91ef8bda5a 100644 (file)
@@ -15,6 +15,8 @@ Required properties:
 Optional properties:
 - vqmmc-supply: phandle to the regulator device tree node, mentioned
   as the VCCQ/VDD_IO supply in the eMMC/SD specs.
+- fujitsu,cmd-dat-delay-select: boolean property indicating that this host
+  requires the CMD_DAT_DELAY control to be enabled.
 
 Example:
 
index 0576264eab5e9b4cb29e003ff9014ad45bedf014..bfdcdc4ccdffdd12733f318b4c969600bb72c388 100644 (file)
@@ -18,6 +18,8 @@ Required properties:
        "core"  - SDC MMC clock (MCLK) (required)
        "bus"   - SDCC bus voter clock (optional)
        "xo"    - TCXO clock (optional)
+       "cal"   - reference clock for RCLK delay calibration (optional)
+       "sleep" - sleep clock for RCLK delay calibration (optional)
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-omap.txt b/Documentation/devicetree/bindings/mmc/sdhci-omap.txt
new file mode 100644 (file)
index 0000000..51775a3
--- /dev/null
@@ -0,0 +1,16 @@
+* TI OMAP SDHCI Controller
+
+Refer to mmc.txt for standard MMC bindings.
+
+Required properties:
+- compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
+- ti,hwmods: Must be "mmc<n>", <n> is controller instance starting 1
+
+Example:
+       mmc1: mmc@4809c000 {
+               compatible = "ti,dra7-sdhci";
+               reg = <0x4809c000 0x400>;
+               ti,hwmods = "mmc1";
+               bus-width = <4>;
+               vmmc-supply = <&vmmc>; /* phandle to regulator node */
+       };
index 54ef642f23a05291258b283431b21b191f0ad39a..3c6762430fd915dab218fcb91260172eb958df0f 100644 (file)
@@ -10,7 +10,7 @@ described in mmc.txt, can be used. Additionally the following tmio_mmc-specific
 optional bindings can be used.
 
 Required properties:
-- compatible:  "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit
+- compatible: should contain one or more of the following:
                "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
                "renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
                "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
@@ -26,6 +26,16 @@ Required properties:
                "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
                "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
                "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
+               "renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
+               "renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
+               "renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 or RZ/G1
+                                          SDHI controller
+               "renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 SDHI controller
+
+
+               When compatible with the generic version, nodes must list
+               the SoC-specific version corresponding to the platform
+               first followed by the generic version.
 
 - clocks: Most controllers only have 1 clock source per channel. However, on
          some variations of this controller, the internal card detection
@@ -43,3 +53,61 @@ Optional properties:
 - pinctrl-names: should be "default", "state_uhs"
 - pinctrl-0: should contain default/high speed pin ctrl
 - pinctrl-1: should contain uhs mode pin ctrl
+
+Example: R8A7790 (R-Car H2) SDHI controller nodes
+
+       sdhi0: sd@ee100000 {
+               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
+               reg = <0 0xee100000 0 0x328>;
+               interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 314>;
+               dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+                      <&dmac1 0xcd>, <&dmac1 0xce>;
+               dma-names = "tx", "rx", "tx", "rx";
+               max-frequency = <195000000>;
+               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+               resets = <&cpg 314>;
+               status = "disabled";
+       };
+
+       sdhi1: sd@ee120000 {
+               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
+               reg = <0 0xee120000 0 0x328>;
+               interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 313>;
+               dmas = <&dmac0 0xc9>, <&dmac0 0xca>,
+                      <&dmac1 0xc9>, <&dmac1 0xca>;
+               dma-names = "tx", "rx", "tx", "rx";
+               max-frequency = <195000000>;
+               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+               resets = <&cpg 313>;
+               status = "disabled";
+       };
+
+       sdhi2: sd@ee140000 {
+               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
+               reg = <0 0xee140000 0 0x100>;
+               interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 312>;
+               dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
+                      <&dmac1 0xc1>, <&dmac1 0xc2>;
+               dma-names = "tx", "rx", "tx", "rx";
+               max-frequency = <97500000>;
+               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+               resets = <&cpg 312>;
+               status = "disabled";
+       };
+
+       sdhi3: sd@ee160000 {
+               compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
+               reg = <0 0xee160000 0 0x100>;
+               interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 311>;
+               dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+                      <&dmac1 0xd3>, <&dmac1 0xd4>;
+               dma-names = "tx", "rx", "tx", "rx";
+               max-frequency = <97500000>;
+               power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+               resets = <&cpg 311>;
+               status = "disabled";
+       };
diff --git a/Documentation/devicetree/bindings/openrisc/opencores/or1ksim.txt b/Documentation/devicetree/bindings/openrisc/opencores/or1ksim.txt
new file mode 100644 (file)
index 0000000..4950c79
--- /dev/null
@@ -0,0 +1,39 @@
+OpenRISC Generic SoC
+====================
+
+Boards and FPGA SoC's which support the OpenRISC standard platform.  The
+platform essentially follows the conventions of the OpenRISC architecture
+specification, however some aspects, such as the boot protocol have been defined
+by the Linux port.
+
+Required properties
+-------------------
+ - compatible: Must include "opencores,or1ksim"
+
+CPU nodes:
+----------
+A "cpus" node is required.  Required properties:
+ - #address-cells: Must be 1.
+ - #size-cells: Must be 0.
+A CPU sub-node is also required for at least CPU 0.  Since the topology may
+be probed via CPS, it is not necessary to specify secondary CPUs.  Required
+properties:
+ - compatible: Must be "opencores,or1200-rtlsvn481".
+ - reg: CPU number.
+ - clock-frequency: The CPU clock frequency in Hz.
+Example:
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cpu@0 {
+                       compatible = "opencores,or1200-rtlsvn481";
+                       reg = <0>;
+                       clock-frequency = <20000000>;
+               };
+       };
+
+
+Boot protocol
+-------------
+The bootloader may pass the following arguments to the kernel:
+ - r3:  address of a flattened device-tree blob or 0x0.
index 0f2a6f8fcafdb988dfc93042e7b5d700ee5ac206..27717e816e7134460a6aca8b691d51235d9bb09a 100644 (file)
@@ -1,8 +1,9 @@
-* Dialog Semiconductor DA9211/DA9212/DA9213/DA9214/DA9215 Voltage Regulator
+* Dialog Semiconductor DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/DA9215/DA9225
+ Voltage Regulator
 
 Required properties:
-- compatible: "dlg,da9211" or "dlg,da9212" or "dlg,da9213"
-  or "dlg,da9214" or "dlg,da9215"
+- compatible: "dlg,da9211" or "dlg,da9212" or "dlg,da9213" or "dlg,da9223"
+  or "dlg,da9214" or "dlg,da9224" or "dlg,da9215" or "dlg,da9225"
 - reg: I2C slave address, usually 0x68.
 - interrupts: the interrupt outputs of the controller
 - regulators: A node that houses a sub-node for each regulator within the
@@ -16,7 +17,6 @@ Optional properties:
 - Any optional property defined in regulator.txt
 
 Example 1) DA9211
-
        pmic: da9211@68 {
                compatible = "dlg,da9211";
                reg = <0x68>;
@@ -35,7 +35,6 @@ Example 1) DA9211
        };
 
 Example 2) DA9212
-
        pmic: da9212@68 {
                compatible = "dlg,da9212";
                reg = <0x68>;
@@ -79,7 +78,25 @@ Example 3) DA9213
                };
        };
 
-Example 4) DA9214
+Example 4) DA9223
+       pmic: da9223@68 {
+               compatible = "dlg,da9223";
+               reg = <0x68>;
+               interrupts = <3 27>;
+
+               regulators {
+                       BUCKA {
+                               regulator-name = "VBUCKA";
+                               regulator-min-microvolt = < 300000>;
+                               regulator-max-microvolt = <1570000>;
+                               regulator-min-microamp  = <3000000>;
+                               regulator-max-microamp  = <6000000>;
+                               enable-gpios = <&gpio 27 0>;
+                       };
+               };
+       };
+
+Example 5) DA9214
        pmic: da9214@68 {
                compatible = "dlg,da9214";
                reg = <0x68>;
@@ -105,7 +122,33 @@ Example 4) DA9214
                };
        };
 
-Example 5) DA9215
+Example 6) DA9224
+       pmic: da9224@68 {
+               compatible = "dlg,da9224";
+               reg = <0x68>;
+               interrupts = <3 27>;
+
+               regulators {
+                       BUCKA {
+                               regulator-name = "VBUCKA";
+                               regulator-min-microvolt = < 300000>;
+                               regulator-max-microvolt = <1570000>;
+                               regulator-min-microamp  = <3000000>;
+                               regulator-max-microamp  = <6000000>;
+                               enable-gpios = <&gpio 27 0>;
+                       };
+                       BUCKB {
+                               regulator-name = "VBUCKB";
+                               regulator-min-microvolt = < 300000>;
+                               regulator-max-microvolt = <1570000>;
+                               regulator-min-microamp  = <3000000>;
+                               regulator-max-microamp  = <6000000>;
+                               enable-gpios = <&gpio 17 0>;
+                       };
+               };
+       };
+
+Example 7) DA9215
        pmic: da9215@68 {
                compatible = "dlg,da9215";
                reg = <0x68>;
@@ -131,3 +174,28 @@ Example 5) DA9215
                };
        };
 
+Example 8) DA9225
+       pmic: da9225@68 {
+               compatible = "dlg,da9225";
+               reg = <0x68>;
+               interrupts = <3 27>;
+
+               regulators {
+                       BUCKA {
+                               regulator-name = "VBUCKA";
+                               regulator-min-microvolt = < 300000>;
+                               regulator-max-microvolt = <1570000>;
+                               regulator-min-microamp  = <4000000>;
+                               regulator-max-microamp  = <7000000>;
+                               enable-gpios = <&gpio 27 0>;
+                       };
+                       BUCKB {
+                               regulator-name = "VBUCKB";
+                               regulator-min-microvolt = < 300000>;
+                               regulator-max-microvolt = <1570000>;
+                               regulator-min-microamp  = <4000000>;
+                               regulator-max-microamp  = <7000000>;
+                               enable-gpios = <&gpio 17 0>;
+                       };
+               };
+       };
index 444c47831a408c6b24d908f707117d7d3788cfde..c6dd3f5e485b75cf0cab3543b43dfbada9c2b175 100644 (file)
@@ -21,7 +21,7 @@ Each regulator is defined using the standard binding for regulators.
 
 Example 1: PFUZE100
 
-       pmic: pfuze100@08 {
+       pmic: pfuze100@8 {
                compatible = "fsl,pfuze100";
                reg = <0x08>;
 
@@ -122,7 +122,7 @@ Example 1: PFUZE100
 
 Example 2: PFUZE200
 
-       pmic: pfuze200@08 {
+       pmic: pfuze200@8 {
                compatible = "fsl,pfuze200";
                reg = <0x08>;
 
@@ -216,7 +216,7 @@ Example 2: PFUZE200
 
 Example 3: PFUZE3000
 
-       pmic: pfuze3000@08 {
+       pmic: pfuze3000@8 {
                compatible = "fsl,pfuze3000";
                reg = <0x08>;
 
index 0fa3b0fac129838e44fb02ffd5074c0b523c3a35..57d2c65899df2cfdce7aafdc9ba3667094b1f784 100644 (file)
@@ -8,6 +8,7 @@ Qualcomm SPMI Regulators
                        "qcom,pm8916-regulators"
                        "qcom,pm8941-regulators"
                        "qcom,pm8994-regulators"
+                       "qcom,pmi8994-regulators"
 
 - interrupts:
        Usage: optional
@@ -100,6 +101,15 @@ Qualcomm SPMI Regulators
        Definition: Reference to regulator supplying the input pin, as
                    described in the data sheet.
 
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_l1-supply:
+       Usage: optional (pmi8994 only)
+       Value type: <phandle>
+       Definition: Reference to regulator supplying the input pin, as
+                   described in the data sheet.
+
 
 The regulator node houses sub-nodes for each regulator within the device. Each
 sub-node is identified using the node's name, with valid values listed for each
@@ -122,6 +132,9 @@ pm8994:
        l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
        l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, lvs1, lvs2
 
+pmi8994:
+       s1, s2, s3, l1
+
 The content of each sub-node is defined by the standard binding for regulators -
 see regulator.txt - with additional custom properties described below:
 
index e865855726a2b973a201ab1c3babc4df70451007..bdd83959019c7883859cc3a1e6bec751a35dd09d 100644 (file)
@@ -1,7 +1,9 @@
 Renesas MSIOF spi controller
 
 Required properties:
-- compatible           : "renesas,msiof-r8a7790" (R-Car H2)
+- compatible           : "renesas,msiof-r8a7743" (RZ/G1M)
+                        "renesas,msiof-r8a7745" (RZ/G1E)
+                        "renesas,msiof-r8a7790" (R-Car H2)
                         "renesas,msiof-r8a7791" (R-Car M2-W)
                         "renesas,msiof-r8a7792" (R-Car V2H)
                         "renesas,msiof-r8a7793" (R-Car M2-N)
@@ -10,7 +12,7 @@ Required properties:
                         "renesas,msiof-r8a7796" (R-Car M3-W)
                         "renesas,msiof-sh73a0" (SH-Mobile AG5)
                         "renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device)
-                        "renesas,rcar-gen2-msiof" (generic R-Car Gen2 compatible device)
+                        "renesas,rcar-gen2-msiof" (generic R-Car Gen2 and RZ/G1 compatible device)
                         "renesas,rcar-gen3-msiof" (generic R-Car Gen3 compatible device)
                         "renesas,sh-msiof"      (deprecated)
 
index f5916c92fe9149140ae7183168cecc1a0eccf918..1925277bfc1ec9da99df94bec2c9ef93d74ed2a3 100644 (file)
@@ -24,6 +24,16 @@ Required properties:
        based on a specific SoC configuration.
 - interrupts: interrupt number mapped to CPU.
 - clocks: spi clk phandle
+          For 66AK2G this property should be set per binding,
+          Documentation/devicetree/bindings/clock/ti,sci-clk.txt
+
+SoC-specific Required Properties:
+
+The following are mandatory properties for Keystone 2 66AK2G SoCs only:
+
+- power-domains:       Should contain a phandle to a PM domain provider node
+                       and an args specifier containing the SPI device id
+                       value. This property is as per the binding,
 
 Optional:
 - cs-gpios: gpio chip selects
index 8f4169f6393648c7741911620f12327985c0d750..3b02b3a7cfb28858dc4eaf7ad9fa8f9404832779 100644 (file)
@@ -5,11 +5,14 @@ Required properties:
                     "renesas,rspi-<soctype>", "renesas,rspi" as fallback.
                     For Renesas Serial Peripheral Interface on RZ/A1H:
                     "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
-                    For Quad Serial Peripheral Interface on R-Car Gen2:
+                    For Quad Serial Peripheral Interface on R-Car Gen2 and
+                    RZ/G1 devices:
                     "renesas,qspi-<soctype>", "renesas,qspi" as fallback.
                     Examples with soctypes are:
                        - "renesas,rspi-sh7757" (SH)
                        - "renesas,rspi-r7s72100" (RZ/A1H)
+                       - "renesas,qspi-r8a7743" (RZ/G1M)
+                       - "renesas,qspi-r8a7745" (RZ/G1E)
                        - "renesas,qspi-r8a7790" (R-Car H2)
                        - "renesas,qspi-r8a7791" (R-Car M2-W)
                        - "renesas,qspi-r8a7792" (R-Car V2H)
diff --git a/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt b/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt
new file mode 100644 (file)
index 0000000..8de589b
--- /dev/null
@@ -0,0 +1,58 @@
+Spreadtrum ADI controller
+
+ADI is the abbreviation of Anolog-Digital interface, which is used to access
+analog chip (such as PMIC) from digital chip. ADI controller follows the SPI
+framework for its hardware implementation is alike to SPI bus and its timing
+is compatile to SPI timing.
+
+ADI controller has 50 channels including 2 software read/write channels and
+48 hardware channels to access analog chip. For 2 software read/write channels,
+users should set ADI registers to access analog chip. For hardware channels,
+we can configure them to allow other hardware components to use it independently,
+which means we can just link one analog chip address to one hardware channel,
+then users can access the mapped analog chip address by this hardware channel
+triggered by hardware components instead of ADI software channels.
+
+Thus we introduce one property named "sprd,hw-channels" to configure hardware
+channels, the first value specifies the hardware channel id which is used to
+transfer data triggered by hardware automatically, and the second value specifies
+the analog chip address where user want to access by hardware components.
+
+Since we have multi-subsystems will use unique ADI to access analog chip, when
+one system is reading/writing data by ADI software channels, that should be under
+one hardware spinlock protection to prevent other systems from reading/writing
+data by ADI software channels at the same time, or two parallel routine of setting
+ADI registers will make ADI controller registers chaos to lead incorrect results.
+Then we need one hardware spinlock to synchronize between the multiple subsystems.
+
+Required properties:
+- compatible: Should be "sprd,sc9860-adi".
+- reg: Offset and length of ADI-SPI controller register space.
+- hwlocks: Reference to a phandle of a hwlock provider node.
+- hwlock-names: Reference to hwlock name strings defined in the same order
+       as the hwlocks, should be "adi".
+- #address-cells: Number of cells required to define a chip select address
+       on the ADI-SPI bus. Should be set to 1.
+- #size-cells: Size of cells required to define a chip select address size
+       on the ADI-SPI bus. Should be set to 0.
+
+Optional properties:
+- sprd,hw-channels: This is an array of channel values up to 49 channels.
+       The first value specifies the hardware channel id which is used to
+       transfer data triggered by hardware automatically, and the second
+       value specifies the analog chip address where user want to access
+       by hardware components.
+
+SPI slave nodes must be children of the SPI controller node and can contain
+properties described in Documentation/devicetree/bindings/spi/spi-bus.txt.
+
+Example:
+       adi_bus: spi@40030000 {
+               compatible = "sprd,sc9860-adi";
+               reg = <0 0x40030000 0 0x10000>;
+               hwlocks = <&hwlock1 0>;
+               hwlock-names = "adi";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               sprd,hw-channels = <30 0x8c20>;
+       };
index 6ca6b9e582a0e803ee85ef15972448a5be2cfda5..d740989eb56981cbce66e2cd6930481d452f1f97 100644 (file)
@@ -20,16 +20,16 @@ Required Properties:
                (CMT1 on sh73a0 and r8a7740)
                This is a fallback for the above renesas,cmt-48-* entries.
 
-    - "renesas,cmt0-r8a73a4" for the 32-bit CMT0 device included in r8a73a4.
-    - "renesas,cmt1-r8a73a4" for the 48-bit CMT1 device included in r8a73a4.
-    - "renesas,cmt0-r8a7790" for the 32-bit CMT0 device included in r8a7790.
-    - "renesas,cmt1-r8a7790" for the 48-bit CMT1 device included in r8a7790.
-    - "renesas,cmt0-r8a7791" for the 32-bit CMT0 device included in r8a7791.
-    - "renesas,cmt1-r8a7791" for the 48-bit CMT1 device included in r8a7791.
-    - "renesas,cmt0-r8a7793" for the 32-bit CMT0 device included in r8a7793.
-    - "renesas,cmt1-r8a7793" for the 48-bit CMT1 device included in r8a7793.
-    - "renesas,cmt0-r8a7794" for the 32-bit CMT0 device included in r8a7794.
-    - "renesas,cmt1-r8a7794" for the 48-bit CMT1 device included in r8a7794.
+    - "renesas,r8a73a4-cmt0" for the 32-bit CMT0 device included in r8a73a4.
+    - "renesas,r8a73a4-cmt1" for the 48-bit CMT1 device included in r8a73a4.
+    - "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790.
+    - "renesas,r8a7790-cmt1" for the 48-bit CMT1 device included in r8a7790.
+    - "renesas,r8a7791-cmt0" for the 32-bit CMT0 device included in r8a7791.
+    - "renesas,r8a7791-cmt1" for the 48-bit CMT1 device included in r8a7791.
+    - "renesas,r8a7793-cmt0" for the 32-bit CMT0 device included in r8a7793.
+    - "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,rcar-gen2-cmt0" for 32-bit CMT0 devices included in R-Car Gen2.
     - "renesas,rcar-gen2-cmt1" for 48-bit CMT1 devices included in R-Car Gen2.
@@ -46,7 +46,7 @@ Required Properties:
 Example: R8A7790 (R-Car H2) CMT0 and CMT1 nodes
 
        cmt0: timer@ffca0000 {
-               compatible = "renesas,cmt0-r8a7790", "renesas,rcar-gen2-cmt0";
+               compatible = "renesas,r8a7790-cmt0", "renesas,rcar-gen2-cmt0";
                reg = <0 0xffca0000 0 0x1004>;
                interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>,
                             <0 142 IRQ_TYPE_LEVEL_HIGH>;
@@ -55,7 +55,7 @@ Example: R8A7790 (R-Car H2) CMT0 and CMT1 nodes
        };
 
        cmt1: timer@e6130000 {
-               compatible = "renesas,cmt1-r8a7790", "renesas,rcar-gen2-cmt1";
+               compatible = "renesas,r8a7790-cmt1", "renesas,rcar-gen2-cmt1";
                reg = <0 0xe6130000 0 0x1004>;
                interrupts = <0 120 IRQ_TYPE_LEVEL_HIGH>,
                             <0 121 IRQ_TYPE_LEVEL_HIGH>,
index af284fbd4d238e4ce5b77e5d55c989c99366c8b0..8bcac6ee73daa54254aa32d96d9aeacdc93a966d 100644 (file)
@@ -71,6 +71,7 @@ isil,isl29028         Intersil ISL29028 Ambient Light and Proximity Sensor
 isil,isl29030          Intersil ISL29030 Ambient Light and Proximity Sensor
 maxim,ds1050           5 Bit Programmable, Pulse-Width Modulator
 maxim,max1237          Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
+maxim,max6621          PECI-to-I2C translator for PECI-to-SMBus/I2C protocol conversion
 maxim,max6625          9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
 mc,rv3029c2            Real Time Clock Module with I2C-Bus
 mcube,mc3230           mCube 3-axis 8-bit digital accelerometer
index 1afd298eddd73147ebf6a1dcbc56bf404559cff1..b1eeca851d6f55adde03c945561b56085289ee37 100644 (file)
@@ -246,6 +246,7 @@ onion       Onion Corporation
 onnn   ON Semiconductor Corp.
 ontat  On Tat Industrial Company
 opencores      OpenCores.org
+openrisc       OpenRISC.io
 option Option NV
 ORCL   Oracle Corporation
 ortustech      Ortus Technology Co., Ltd.
diff --git a/Documentation/dmaengine/00-INDEX b/Documentation/dmaengine/00-INDEX
deleted file mode 100644 (file)
index 07de657..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-00-INDEX
-       - this file.
-client.txt
-       -the DMA Engine API Guide.
-dmatest.txt
-       - how to compile, configure and use the dmatest system.
-provider.txt
-       - the DMA controller API.
\ No newline at end of file
diff --git a/Documentation/dmaengine/client.txt b/Documentation/dmaengine/client.txt
deleted file mode 100644 (file)
index c72b456..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-                       DMA Engine API Guide
-                       ====================
-
-                Vinod Koul <vinod dot koul at intel.com>
-
-NOTE: For DMA Engine usage in async_tx please see:
-       Documentation/crypto/async-tx-api.txt
-
-
-Below is a guide to device driver writers on how to use the Slave-DMA API of the
-DMA Engine. This is applicable only for slave DMA usage only.
-
-The slave DMA usage consists of following steps:
-1. Allocate a DMA slave channel
-2. Set slave and controller specific parameters
-3. Get a descriptor for transaction
-4. Submit the transaction
-5. Issue pending requests and wait for callback notification
-
-1. Allocate a DMA slave channel
-
-   Channel allocation is slightly different in the slave DMA context,
-   client drivers typically need a channel from a particular DMA
-   controller only and even in some cases a specific channel is desired.
-   To request a channel dma_request_chan() API is used.
-
-   Interface:
-       struct dma_chan *dma_request_chan(struct device *dev, const char *name);
-
-   Which will find and return the 'name' DMA channel associated with the 'dev'
-   device. The association is done via DT, ACPI or board file based
-   dma_slave_map matching table.
-
-   A channel allocated via this interface is exclusive to the caller,
-   until dma_release_channel() is called.
-
-2. Set slave and controller specific parameters
-
-   Next step is always to pass some specific information to the DMA
-   driver. Most of the generic information which a slave DMA can use
-   is in struct dma_slave_config. This allows the clients to specify
-   DMA direction, DMA addresses, bus widths, DMA burst lengths etc
-   for the peripheral.
-
-   If some DMA controllers have more parameters to be sent then they
-   should try to embed struct dma_slave_config in their controller
-   specific structure. That gives flexibility to client to pass more
-   parameters, if required.
-
-   Interface:
-       int dmaengine_slave_config(struct dma_chan *chan,
-                                 struct dma_slave_config *config)
-
-   Please see the dma_slave_config structure definition in dmaengine.h
-   for a detailed explanation of the struct members. Please note
-   that the 'direction' member will be going away as it duplicates the
-   direction given in the prepare call.
-
-3. Get a descriptor for transaction
-
-   For slave usage the various modes of slave transfers supported by the
-   DMA-engine are:
-
-   slave_sg    - DMA a list of scatter gather buffers from/to a peripheral
-   dma_cyclic  - Perform a cyclic DMA operation from/to a peripheral till the
-                 operation is explicitly stopped.
-   interleaved_dma - This is common to Slave as well as M2M clients. For slave
-                address of devices' fifo could be already known to the driver.
-                Various types of operations could be expressed by setting
-                appropriate values to the 'dma_interleaved_template' members.
-
-   A non-NULL return of this transfer API represents a "descriptor" for
-   the given transaction.
-
-   Interface:
-       struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
-               struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
-               unsigned long flags);
-
-       struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
-               struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
-               size_t period_len, enum dma_data_direction direction);
-
-       struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma(
-               struct dma_chan *chan, struct dma_interleaved_template *xt,
-               unsigned long flags);
-
-   The peripheral driver is expected to have mapped the scatterlist for
-   the DMA operation prior to calling dmaengine_prep_slave_sg(), and must
-   keep the scatterlist mapped until the DMA operation has completed.
-   The scatterlist must be mapped using the DMA struct device.
-   If a mapping needs to be synchronized later, dma_sync_*_for_*() must be
-   called using the DMA struct device, too.
-   So, normal setup should look like this:
-
-       nr_sg = dma_map_sg(chan->device->dev, sgl, sg_len);
-       if (nr_sg == 0)
-               /* error */
-
-       desc = dmaengine_prep_slave_sg(chan, sgl, nr_sg, direction, flags);
-
-   Once a descriptor has been obtained, the callback information can be
-   added and the descriptor must then be submitted. Some DMA engine
-   drivers may hold a spinlock between a successful preparation and
-   submission so it is important that these two operations are closely
-   paired.
-
-   Note:
-       Although the async_tx API specifies that completion callback
-       routines cannot submit any new operations, this is not the
-       case for slave/cyclic DMA.
-
-       For slave DMA, the subsequent transaction may not be available
-       for submission prior to callback function being invoked, so
-       slave DMA callbacks are permitted to prepare and submit a new
-       transaction.
-
-       For cyclic DMA, a callback function may wish to terminate the
-       DMA via dmaengine_terminate_async().
-
-       Therefore, it is important that DMA engine drivers drop any
-       locks before calling the callback function which may cause a
-       deadlock.
-
-       Note that callbacks will always be invoked from the DMA
-       engines tasklet, never from interrupt context.
-
-4. Submit the transaction
-
-   Once the descriptor has been prepared and the callback information
-   added, it must be placed on the DMA engine drivers pending queue.
-
-   Interface:
-       dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
-
-   This returns a cookie can be used to check the progress of DMA engine
-   activity via other DMA engine calls not covered in this document.
-
-   dmaengine_submit() will not start the DMA operation, it merely adds
-   it to the pending queue. For this, see step 5, dma_async_issue_pending.
-
-5. Issue pending DMA requests and wait for callback notification
-
-   The transactions in the pending queue can be activated by calling the
-   issue_pending API. If channel is idle then the first transaction in
-   queue is started and subsequent ones queued up.
-
-   On completion of each DMA operation, the next in queue is started and
-   a tasklet triggered. The tasklet will then call the client driver
-   completion callback routine for notification, if set.
-
-   Interface:
-       void dma_async_issue_pending(struct dma_chan *chan);
-
-Further APIs:
-
-1. int dmaengine_terminate_sync(struct dma_chan *chan)
-   int dmaengine_terminate_async(struct dma_chan *chan)
-   int dmaengine_terminate_all(struct dma_chan *chan) /* DEPRECATED */
-
-   This causes all activity for the DMA channel to be stopped, and may
-   discard data in the DMA FIFO which hasn't been fully transferred.
-   No callback functions will be called for any incomplete transfers.
-
-   Two variants of this function are available.
-
-   dmaengine_terminate_async() might not wait until the DMA has been fully
-   stopped or until any running complete callbacks have finished. But it is
-   possible to call dmaengine_terminate_async() from atomic context or from
-   within a complete callback. dmaengine_synchronize() must be called before it
-   is safe to free the memory accessed by the DMA transfer or free resources
-   accessed from within the complete callback.
-
-   dmaengine_terminate_sync() will wait for the transfer and any running
-   complete callbacks to finish before it returns. But the function must not be
-   called from atomic context or from within a complete callback.
-
-   dmaengine_terminate_all() is deprecated and should not be used in new code.
-
-2. int dmaengine_pause(struct dma_chan *chan)
-
-   This pauses activity on the DMA channel without data loss.
-
-3. int dmaengine_resume(struct dma_chan *chan)
-
-   Resume a previously paused DMA channel. It is invalid to resume a
-   channel which is not currently paused.
-
-4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
-        dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
-
-   This can be used to check the status of the channel. Please see
-   the documentation in include/linux/dmaengine.h for a more complete
-   description of this API.
-
-   This can be used in conjunction with dma_async_is_complete() and
-   the cookie returned from dmaengine_submit() to check for
-   completion of a specific DMA transaction.
-
-   Note:
-       Not all DMA engine drivers can return reliable information for
-       a running DMA channel. It is recommended that DMA engine users
-       pause or stop (via dmaengine_terminate_all()) the channel before
-       using this API.
-
-5. void dmaengine_synchronize(struct dma_chan *chan)
-
-  Synchronize the termination of the DMA channel to the current context.
-
-  This function should be used after dmaengine_terminate_async() to synchronize
-  the termination of the DMA channel to the current context. The function will
-  wait for the transfer and any running complete callbacks to finish before it
-  returns.
-
-  If dmaengine_terminate_async() is used to stop the DMA channel this function
-  must be called before it is safe to free memory accessed by previously
-  submitted descriptors or to free any resources accessed within the complete
-  callback of previously submitted descriptors.
-
-  The behavior of this function is undefined if dma_async_issue_pending() has
-  been called between dmaengine_terminate_async() and this function.
diff --git a/Documentation/dmaengine/provider.txt b/Documentation/dmaengine/provider.txt
deleted file mode 100644 (file)
index 5dbe054..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-DMAengine controller documentation
-==================================
-
-Hardware Introduction
-+++++++++++++++++++++
-
-Most of the Slave DMA controllers have the same general principles of
-operations.
-
-They have a given number of channels to use for the DMA transfers, and
-a given number of requests lines.
-
-Requests and channels are pretty much orthogonal. Channels can be used
-to serve several to any requests. To simplify, channels are the
-entities that will be doing the copy, and requests what endpoints are
-involved.
-
-The request lines actually correspond to physical lines going from the
-DMA-eligible devices to the controller itself. Whenever the device
-will want to start a transfer, it will assert a DMA request (DRQ) by
-asserting that request line.
-
-A very simple DMA controller would only take into account a single
-parameter: the transfer size. At each clock cycle, it would transfer a
-byte of data from one buffer to another, until the transfer size has
-been reached.
-
-That wouldn't work well in the real world, since slave devices might
-require a specific number of bits to be transferred in a single
-cycle. For example, we may want to transfer as much data as the
-physical bus allows to maximize performances when doing a simple
-memory copy operation, but our audio device could have a narrower FIFO
-that requires data to be written exactly 16 or 24 bits at a time. This
-is why most if not all of the DMA controllers can adjust this, using a
-parameter called the transfer width.
-
-Moreover, some DMA controllers, whenever the RAM is used as a source
-or destination, can group the reads or writes in memory into a buffer,
-so instead of having a lot of small memory accesses, which is not
-really efficient, you'll get several bigger transfers. This is done
-using a parameter called the burst size, that defines how many single
-reads/writes it's allowed to do without the controller splitting the
-transfer into smaller sub-transfers.
-
-Our theoretical DMA controller would then only be able to do transfers
-that involve a single contiguous block of data. However, some of the
-transfers we usually have are not, and want to copy data from
-non-contiguous buffers to a contiguous buffer, which is called
-scatter-gather.
-
-DMAEngine, at least for mem2dev transfers, require support for
-scatter-gather. So we're left with two cases here: either we have a
-quite simple DMA controller that doesn't support it, and we'll have to
-implement it in software, or we have a more advanced DMA controller,
-that implements in hardware scatter-gather.
-
-The latter are usually programmed using a collection of chunks to
-transfer, and whenever the transfer is started, the controller will go
-over that collection, doing whatever we programmed there.
-
-This collection is usually either a table or a linked list. You will
-then push either the address of the table and its number of elements,
-or the first item of the list to one channel of the DMA controller,
-and whenever a DRQ will be asserted, it will go through the collection
-to know where to fetch the data from.
-
-Either way, the format of this collection is completely dependent on
-your hardware. Each DMA controller will require a different structure,
-but all of them will require, for every chunk, at least the source and
-destination addresses, whether it should increment these addresses or
-not and the three parameters we saw earlier: the burst size, the
-transfer width and the transfer size.
-
-The one last thing is that usually, slave devices won't issue DRQ by
-default, and you have to enable this in your slave device driver first
-whenever you're willing to use DMA.
-
-These were just the general memory-to-memory (also called mem2mem) or
-memory-to-device (mem2dev) kind of transfers. Most devices often
-support other kind of transfers or memory operations that dmaengine
-support and will be detailed later in this document.
-
-DMA Support in Linux
-++++++++++++++++++++
-
-Historically, DMA controller drivers have been implemented using the
-async TX API, to offload operations such as memory copy, XOR,
-cryptography, etc., basically any memory to memory operation.
-
-Over time, the need for memory to device transfers arose, and
-dmaengine was extended. Nowadays, the async TX API is written as a
-layer on top of dmaengine, and acts as a client. Still, dmaengine
-accommodates that API in some cases, and made some design choices to
-ensure that it stayed compatible.
-
-For more information on the Async TX API, please look the relevant
-documentation file in Documentation/crypto/async-tx-api.txt.
-
-DMAEngine Registration
-++++++++++++++++++++++
-
-struct dma_device Initialization
---------------------------------
-
-Just like any other kernel framework, the whole DMAEngine registration
-relies on the driver filling a structure and registering against the
-framework. In our case, that structure is dma_device.
-
-The first thing you need to do in your driver is to allocate this
-structure. Any of the usual memory allocators will do, but you'll also
-need to initialize a few fields in there:
-
-  * channels:  should be initialized as a list using the
-               INIT_LIST_HEAD macro for example
-
-  * src_addr_widths:
-    - should contain a bitmask of the supported source transfer width
-
-  * dst_addr_widths:
-    - should contain a bitmask of the supported destination transfer
-      width
-
-  * directions:
-    - should contain a bitmask of the supported slave directions
-      (i.e. excluding mem2mem transfers)
-
-  * residue_granularity:
-    - Granularity of the transfer residue reported to dma_set_residue.
-    - This can be either:
-      + Descriptor
-        -> Your device doesn't support any kind of residue
-           reporting. The framework will only know that a particular
-           transaction descriptor is done.
-      + Segment
-        -> Your device is able to report which chunks have been
-           transferred
-      + Burst
-        -> Your device is able to report which burst have been
-           transferred
-
-  * dev:       should hold the pointer to the struct device associated
-               to your current driver instance.
-
-Supported transaction types
----------------------------
-
-The next thing you need is to set which transaction types your device
-(and driver) supports.
-
-Our dma_device structure has a field called cap_mask that holds the
-various types of transaction supported, and you need to modify this
-mask using the dma_cap_set function, with various flags depending on
-transaction types you support as an argument.
-
-All those capabilities are defined in the dma_transaction_type enum,
-in include/linux/dmaengine.h
-
-Currently, the types available are:
-  * DMA_MEMCPY
-    - The device is able to do memory to memory copies
-
-  * DMA_XOR
-    - The device is able to perform XOR operations on memory areas
-    - Used to accelerate XOR intensive tasks, such as RAID5
-
-  * DMA_XOR_VAL
-    - The device is able to perform parity check using the XOR
-      algorithm against a memory buffer.
-
-  * DMA_PQ
-    - The device is able to perform RAID6 P+Q computations, P being a
-      simple XOR, and Q being a Reed-Solomon algorithm.
-
-  * DMA_PQ_VAL
-    - The device is able to perform parity check using RAID6 P+Q
-      algorithm against a memory buffer.
-
-  * DMA_INTERRUPT
-    - The device is able to trigger a dummy transfer that will
-      generate periodic interrupts
-    - Used by the client drivers to register a callback that will be
-      called on a regular basis through the DMA controller interrupt
-
-  * DMA_PRIVATE
-    - The devices only supports slave transfers, and as such isn't
-      available for async transfers.
-
-  * DMA_ASYNC_TX
-    - Must not be set by the device, and will be set by the framework
-      if needed
-    - /* TODO: What is it about? */
-
-  * DMA_SLAVE
-    - The device can handle device to memory transfers, including
-      scatter-gather transfers.
-    - While in the mem2mem case we were having two distinct types to
-      deal with a single chunk to copy or a collection of them, here,
-      we just have a single transaction type that is supposed to
-      handle both.
-    - If you want to transfer a single contiguous memory buffer,
-      simply build a scatter list with only one item.
-
-  * DMA_CYCLIC
-    - The device can handle cyclic transfers.
-    - A cyclic transfer is a transfer where the chunk collection will
-      loop over itself, with the last item pointing to the first.
-    - It's usually used for audio transfers, where you want to operate
-      on a single ring buffer that you will fill with your audio data.
-
-  * DMA_INTERLEAVE
-    - The device supports interleaved transfer.
-    - These transfers can transfer data from a non-contiguous buffer
-      to a non-contiguous buffer, opposed to DMA_SLAVE that can
-      transfer data from a non-contiguous data set to a continuous
-      destination buffer.
-    - It's usually used for 2d content transfers, in which case you
-      want to transfer a portion of uncompressed data directly to the
-      display to print it
-
-These various types will also affect how the source and destination
-addresses change over time.
-
-Addresses pointing to RAM are typically incremented (or decremented)
-after each transfer. In case of a ring buffer, they may loop
-(DMA_CYCLIC). Addresses pointing to a device's register (e.g. a FIFO)
-are typically fixed.
-
-Device operations
------------------
-
-Our dma_device structure also requires a few function pointers in
-order to implement the actual logic, now that we described what
-operations we were able to perform.
-
-The functions that we have to fill in there, and hence have to
-implement, obviously depend on the transaction types you reported as
-supported.
-
-   * device_alloc_chan_resources
-   * device_free_chan_resources
-     - These functions will be called whenever a driver will call
-       dma_request_channel or dma_release_channel for the first/last
-       time on the channel associated to that driver.
-     - They are in charge of allocating/freeing all the needed
-       resources in order for that channel to be useful for your
-       driver.
-     - These functions can sleep.
-
-   * device_prep_dma_*
-     - These functions are matching the capabilities you registered
-       previously.
-     - These functions all take the buffer or the scatterlist relevant
-       for the transfer being prepared, and should create a hardware
-       descriptor or a list of hardware descriptors from it
-     - These functions can be called from an interrupt context
-     - Any allocation you might do should be using the GFP_NOWAIT
-       flag, in order not to potentially sleep, but without depleting
-       the emergency pool either.
-     - Drivers should try to pre-allocate any memory they might need
-       during the transfer setup at probe time to avoid putting to
-       much pressure on the nowait allocator.
-
-     - It should return a unique instance of the
-       dma_async_tx_descriptor structure, that further represents this
-       particular transfer.
-
-     - This structure can be initialized using the function
-       dma_async_tx_descriptor_init.
-     - You'll also need to set two fields in this structure:
-       + flags:
-               TODO: Can it be modified by the driver itself, or
-               should it be always the flags passed in the arguments
-
-       + tx_submit:    A pointer to a function you have to implement,
-                       that is supposed to push the current
-                       transaction descriptor to a pending queue, waiting
-                       for issue_pending to be called.
-     - In this structure the function pointer callback_result can be
-       initialized in order for the submitter to be notified that a
-       transaction has completed. In the earlier code the function pointer
-       callback has been used. However it does not provide any status to the
-       transaction and will be deprecated. The result structure defined as
-       dmaengine_result that is passed in to callback_result has two fields:
-       + result: This provides the transfer result defined by
-                dmaengine_tx_result. Either success or some error
-                condition.
-       + residue: Provides the residue bytes of the transfer for those that
-                 support residue.
-
-   * device_issue_pending
-     - Takes the first transaction descriptor in the pending queue,
-       and starts the transfer. Whenever that transfer is done, it
-       should move to the next transaction in the list.
-     - This function can be called in an interrupt context
-
-   * device_tx_status
-     - Should report the bytes left to go over on the given channel
-     - Should only care about the transaction descriptor passed as
-       argument, not the currently active one on a given channel
-     - The tx_state argument might be NULL
-     - Should use dma_set_residue to report it
-     - In the case of a cyclic transfer, it should only take into
-       account the current period.
-     - This function can be called in an interrupt context.
-
-   * device_config
-     - Reconfigures the channel with the configuration given as
-       argument
-     - This command should NOT perform synchronously, or on any
-       currently queued transfers, but only on subsequent ones
-     - In this case, the function will receive a dma_slave_config
-       structure pointer as an argument, that will detail which
-       configuration to use.
-     - Even though that structure contains a direction field, this
-       field is deprecated in favor of the direction argument given to
-       the prep_* functions
-     - This call is mandatory for slave operations only. This should NOT be
-       set or expected to be set for memcpy operations.
-       If a driver support both, it should use this call for slave
-       operations only and not for memcpy ones.
-
-   * device_pause
-     - Pauses a transfer on the channel
-     - This command should operate synchronously on the channel,
-       pausing right away the work of the given channel
-
-   * device_resume
-     - Resumes a transfer on the channel
-     - This command should operate synchronously on the channel,
-       resuming right away the work of the given channel
-
-   * device_terminate_all
-     - Aborts all the pending and ongoing transfers on the channel
-     - For aborted transfers the complete callback should not be called
-     - Can be called from atomic context or from within a complete
-       callback of a descriptor. Must not sleep. Drivers must be able
-       to handle this correctly.
-     - Termination may be asynchronous. The driver does not have to
-       wait until the currently active transfer has completely stopped.
-       See device_synchronize.
-
-   * device_synchronize
-     - Must synchronize the termination of a channel to the current
-       context.
-     - Must make sure that memory for previously submitted
-       descriptors is no longer accessed by the DMA controller.
-     - Must make sure that all complete callbacks for previously
-       submitted descriptors have finished running and none are
-       scheduled to run.
-     - May sleep.
-
-
-Misc notes (stuff that should be documented, but don't really know
-where to put them)
-------------------------------------------------------------------
-  * dma_run_dependencies
-    - Should be called at the end of an async TX transfer, and can be
-      ignored in the slave transfers case.
-    - Makes sure that dependent operations are run before marking it
-      as complete.
-
-  * dma_cookie_t
-    - it's a DMA transaction ID that will increment over time.
-    - Not really relevant any more since the introduction of virt-dma
-      that abstracts it away.
-
-  * DMA_CTRL_ACK
-    - If clear, the descriptor cannot be reused by provider until the
-      client acknowledges receipt, i.e. has has a chance to establish any
-      dependency chains
-    - This can be acked by invoking async_tx_ack()
-    - If set, does not mean descriptor can be reused
-
-  * DMA_CTRL_REUSE
-    - If set, the descriptor can be reused after being completed. It should
-      not be freed by provider if this flag is set.
-    - The descriptor should be prepared for reuse by invoking
-      dmaengine_desc_set_reuse() which will set DMA_CTRL_REUSE.
-    - dmaengine_desc_set_reuse() will succeed only when channel support
-      reusable descriptor as exhibited by capabilities
-    - As a consequence, if a device driver wants to skip the dma_map_sg() and
-      dma_unmap_sg() in between 2 transfers, because the DMA'd data wasn't used,
-      it can resubmit the transfer right after its completion.
-    - Descriptor can be freed in few ways
-       - Clearing DMA_CTRL_REUSE by invoking dmaengine_desc_clear_reuse()
-         and submitting for last txn
-       - Explicitly invoking dmaengine_desc_free(), this can succeed only
-         when DMA_CTRL_REUSE is already set
-       - Terminating the channel
-
-  * DMA_PREP_CMD
-    - If set, the client driver tells DMA controller that passed data in DMA
-      API is command data.
-    - Interpretation of command data is DMA controller specific. It can be
-      used for issuing commands to other peripherals/register reads/register
-      writes for which the descriptor should be in different format from
-      normal data descriptors.
-
-General Design Notes
---------------------
-
-Most of the DMAEngine drivers you'll see are based on a similar design
-that handles the end of transfer interrupts in the handler, but defer
-most work to a tasklet, including the start of a new transfer whenever
-the previous transfer ended.
-
-This is a rather inefficient design though, because the inter-transfer
-latency will be not only the interrupt latency, but also the
-scheduling latency of the tasklet, which will leave the channel idle
-in between, which will slow down the global transfer rate.
-
-You should avoid this kind of practice, and instead of electing a new
-transfer in your tasklet, move that part to the interrupt handler in
-order to have a shorter idle window (that we can't really avoid
-anyway).
-
-Glossary
---------
-
-Burst:                 A number of consecutive read or write operations
-               that can be queued to buffers before being flushed to
-               memory.
-Chunk:         A contiguous collection of bursts
-Transfer:      A collection of chunks (be it contiguous or not)
diff --git a/Documentation/dmaengine/pxa_dma.txt b/Documentation/dmaengine/pxa_dma.txt
deleted file mode 100644 (file)
index 0736d44..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-PXA/MMP - DMA Slave controller
-==============================
-
-Constraints
------------
-  a) Transfers hot queuing
-     A driver submitting a transfer and issuing it should be granted the transfer
-     is queued even on a running DMA channel.
-     This implies that the queuing doesn't wait for the previous transfer end,
-     and that the descriptor chaining is not only done in the irq/tasklet code
-     triggered by the end of the transfer.
-     A transfer which is submitted and issued on a phy doesn't wait for a phy to
-     stop and restart, but is submitted on a "running channel". The other
-     drivers, especially mmp_pdma waited for the phy to stop before relaunching
-     a new transfer.
-
-  b) All transfers having asked for confirmation should be signaled
-     Any issued transfer with DMA_PREP_INTERRUPT should trigger a callback call.
-     This implies that even if an irq/tasklet is triggered by end of tx1, but
-     at the time of irq/dma tx2 is already finished, tx1->complete() and
-     tx2->complete() should be called.
-
-  c) Channel running state
-     A driver should be able to query if a channel is running or not. For the
-     multimedia case, such as video capture, if a transfer is submitted and then
-     a check of the DMA channel reports a "stopped channel", the transfer should
-     not be issued until the next "start of frame interrupt", hence the need to
-     know if a channel is in running or stopped state.
-
-  d) Bandwidth guarantee
-     The PXA architecture has 4 levels of DMAs priorities : high, normal, low.
-     The high priorities get twice as much bandwidth as the normal, which get twice
-     as much as the low priorities.
-     A driver should be able to request a priority, especially the real-time
-     ones such as pxa_camera with (big) throughputs.
-
-Design
-------
-  a) Virtual channels
-     Same concept as in sa11x0 driver, ie. a driver was assigned a "virtual
-     channel" linked to the requestor line, and the physical DMA channel is
-     assigned on the fly when the transfer is issued.
-
-  b) Transfer anatomy for a scatter-gather transfer
-     +------------+-----+---------------+----------------+-----------------+
-     | desc-sg[0] | ... | desc-sg[last] | status updater | finisher/linker |
-     +------------+-----+---------------+----------------+-----------------+
-
-     This structure is pointed by dma->sg_cpu.
-     The descriptors are used as follows :
-      - desc-sg[i]: i-th descriptor, transferring the i-th sg
-        element to the video buffer scatter gather
-      - status updater
-        Transfers a single u32 to a well known dma coherent memory to leave
-        a trace that this transfer is done. The "well known" is unique per
-        physical channel, meaning that a read of this value will tell which
-        is the last finished transfer at that point in time.
-      - finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN
-      - linker: has ddadr= desc-sg[0] of next transfer, dcmd=0
-
-  c) Transfers hot-chaining
-     Suppose the running chain is :
-         Buffer 1         Buffer 2
-     +---------+----+---+  +----+----+----+---+
-     | d0 | .. | dN | l |  | d0 | .. | dN | f |
-     +---------+----+-|-+  ^----+----+----+---+
-                      |    |
-                      +----+
-
-     After a call to dmaengine_submit(b3), the chain will look like :
-          Buffer 1              Buffer 2             Buffer 3
-     +---------+----+---+  +----+----+----+---+  +----+----+----+---+
-     | d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
-     +---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
-                      |    |                |    |
-                      +----+                +----+
-                                           new_link
-
-     If while new_link was created the DMA channel stopped, it is _not_
-     restarted. Hot-chaining doesn't break the assumption that
-     dma_async_issue_pending() is to be used to ensure the transfer is actually started.
-
-     One exception to this rule :
-       - if Buffer1 and Buffer2 had all their addresses 8 bytes aligned
-       - and if Buffer3 has at least one address not 4 bytes aligned
-       - then hot-chaining cannot happen, as the channel must be stopped, the
-         "align bit" must be set, and the channel restarted As a consequence,
-         such a transfer tx_submit() will be queued on the submitted queue, and
-         this specific case if the DMA is already running in aligned mode.
-
-  d) Transfers completion updater
-     Each time a transfer is completed on a channel, an interrupt might be
-     generated or not, up to the client's request. But in each case, the last
-     descriptor of a transfer, the "status updater", will write the latest
-     transfer being completed into the physical channel's completion mark.
-
-     This will speed up residue calculation, for large transfers such as video
-     buffers which hold around 6k descriptors or more. This also allows without
-     any lock to find out what is the latest completed transfer in a running
-     DMA chain.
-
-  e) Transfers completion, irq and tasklet
-     When a transfer flagged as "DMA_PREP_INTERRUPT" is finished, the dma irq
-     is raised. Upon this interrupt, a tasklet is scheduled for the physical
-     channel.
-     The tasklet is responsible for :
-      - reading the physical channel last updater mark
-      - calling all the transfer callbacks of finished transfers, based on
-        that mark, and each transfer flags.
-     If a transfer is completed while this handling is done, a dma irq will
-     be raised, and the tasklet will be scheduled once again, having a new
-     updater mark.
-
-  f) Residue
-     Residue granularity will be descriptor based. The issued but not completed
-     transfers will be scanned for all of their descriptors against the
-     currently running descriptor.
-
-  g) Most complicated case of driver's tx queues
-     The most tricky situation is when :
-       - there are not "acked" transfers (tx0)
-       - a driver submitted an aligned tx1, not chained
-       - a driver submitted an aligned tx2 => tx2 is cold chained to tx1
-       - a driver issued tx1+tx2 => channel is running in aligned mode
-       - a driver submitted an aligned tx3 => tx3 is hot-chained
-       - a driver submitted an unaligned tx4 => tx4 is put in submitted queue,
-         not chained
-       - a driver issued tx4 => tx4 is put in issued queue, not chained
-       - a driver submitted an aligned tx5 => tx5 is put in submitted queue, not
-         chained
-       - a driver submitted an aligned tx6 => tx6 is put in submitted queue,
-         cold chained to tx5
-
-     This translates into (after tx4 is issued) :
-       - issued queue
-     +-----+ +-----+ +-----+ +-----+
-     | tx1 | | tx2 | | tx3 | | tx4 |
-     +---|-+ ^---|-+ ^-----+ +-----+
-         |   |   |   |
-         +---+   +---+
-       - submitted queue
-     +-----+ +-----+
-     | tx5 | | tx6 |
-     +---|-+ ^-----+
-         |   |
-         +---+
-       - completed queue : empty
-       - allocated queue : tx0
-
-     It should be noted that after tx3 is completed, the channel is stopped, and
-     restarted in "unaligned mode" to handle tx4.
-
-Author: Robert Jarzmik <robert.jarzmik@free.fr>
index b24854b5d6beb21dcb538240135d1db447555e9c..0268335414ce3bc18cd33ed70628e0c846fd7c84 100644 (file)
@@ -65,7 +65,7 @@ Without options, the kernel-doc directive includes all documentation comments
 from the source file.
 
 The kernel-doc extension is included in the kernel source tree, at
-``Documentation/sphinx/kernel-doc.py``. Internally, it uses the
+``Documentation/sphinx/kerneldoc.py``. Internally, it uses the
 ``scripts/kernel-doc`` script to extract the documentation comments from the
 source.
 
diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst
new file mode 100644 (file)
index 0000000..6245c99
--- /dev/null
@@ -0,0 +1,275 @@
+====================
+DMA Engine API Guide
+====================
+
+Vinod Koul <vinod dot koul at intel.com>
+
+.. note:: For DMA Engine usage in async_tx please see:
+          ``Documentation/crypto/async-tx-api.txt``
+
+
+Below is a guide to device driver writers on how to use the Slave-DMA API of the
+DMA Engine. This is applicable only for slave DMA usage only.
+
+DMA usage
+=========
+
+The slave DMA usage consists of following steps:
+
+- Allocate a DMA slave channel
+
+- Set slave and controller specific parameters
+
+- Get a descriptor for transaction
+
+- Submit the transaction
+
+- Issue pending requests and wait for callback notification
+
+The details of these operations are:
+
+1. Allocate a DMA slave channel
+
+   Channel allocation is slightly different in the slave DMA context,
+   client drivers typically need a channel from a particular DMA
+   controller only and even in some cases a specific channel is desired.
+   To request a channel dma_request_chan() API is used.
+
+   Interface:
+
+   .. code-block:: c
+
+      struct dma_chan *dma_request_chan(struct device *dev, const char *name);
+
+   Which will find and return the ``name`` DMA channel associated with the 'dev'
+   device. The association is done via DT, ACPI or board file based
+   dma_slave_map matching table.
+
+   A channel allocated via this interface is exclusive to the caller,
+   until dma_release_channel() is called.
+
+2. Set slave and controller specific parameters
+
+   Next step is always to pass some specific information to the DMA
+   driver. Most of the generic information which a slave DMA can use
+   is in struct dma_slave_config. This allows the clients to specify
+   DMA direction, DMA addresses, bus widths, DMA burst lengths etc
+   for the peripheral.
+
+   If some DMA controllers have more parameters to be sent then they
+   should try to embed struct dma_slave_config in their controller
+   specific structure. That gives flexibility to client to pass more
+   parameters, if required.
+
+   Interface:
+
+   .. code-block:: c
+
+      int dmaengine_slave_config(struct dma_chan *chan,
+                       struct dma_slave_config *config)
+
+   Please see the dma_slave_config structure definition in dmaengine.h
+   for a detailed explanation of the struct members. Please note
+   that the 'direction' member will be going away as it duplicates the
+   direction given in the prepare call.
+
+3. Get a descriptor for transaction
+
+  For slave usage the various modes of slave transfers supported by the
+  DMA-engine are:
+
+  - slave_sg: DMA a list of scatter gather buffers from/to a peripheral
+
+  - dma_cyclic: Perform a cyclic DMA operation from/to a peripheral till the
+    operation is explicitly stopped.
+
+  - interleaved_dma: This is common to Slave as well as M2M clients. For slave
+    address of devices' fifo could be already known to the driver.
+    Various types of operations could be expressed by setting
+    appropriate values to the 'dma_interleaved_template' members.
+
+  A non-NULL return of this transfer API represents a "descriptor" for
+  the given transaction.
+
+  Interface:
+
+  .. code-block:: c
+
+     struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
+               struct dma_chan *chan, struct scatterlist *sgl,
+               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned long flags);
+
+     struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
+               struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+               size_t period_len, enum dma_data_direction direction);
+
+     struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma(
+               struct dma_chan *chan, struct dma_interleaved_template *xt,
+               unsigned long flags);
+
+  The peripheral driver is expected to have mapped the scatterlist for
+  the DMA operation prior to calling dmaengine_prep_slave_sg(), and must
+  keep the scatterlist mapped until the DMA operation has completed.
+  The scatterlist must be mapped using the DMA struct device.
+  If a mapping needs to be synchronized later, dma_sync_*_for_*() must be
+  called using the DMA struct device, too.
+  So, normal setup should look like this:
+
+  .. code-block:: c
+
+     nr_sg = dma_map_sg(chan->device->dev, sgl, sg_len);
+       if (nr_sg == 0)
+               /* error */
+
+       desc = dmaengine_prep_slave_sg(chan, sgl, nr_sg, direction, flags);
+
+  Once a descriptor has been obtained, the callback information can be
+  added and the descriptor must then be submitted. Some DMA engine
+  drivers may hold a spinlock between a successful preparation and
+  submission so it is important that these two operations are closely
+  paired.
+
+  .. note::
+
+     Although the async_tx API specifies that completion callback
+     routines cannot submit any new operations, this is not the
+     case for slave/cyclic DMA.
+
+     For slave DMA, the subsequent transaction may not be available
+     for submission prior to callback function being invoked, so
+     slave DMA callbacks are permitted to prepare and submit a new
+     transaction.
+
+     For cyclic DMA, a callback function may wish to terminate the
+     DMA via dmaengine_terminate_async().
+
+     Therefore, it is important that DMA engine drivers drop any
+     locks before calling the callback function which may cause a
+     deadlock.
+
+     Note that callbacks will always be invoked from the DMA
+     engines tasklet, never from interrupt context.
+
+4. Submit the transaction
+
+   Once the descriptor has been prepared and the callback information
+   added, it must be placed on the DMA engine drivers pending queue.
+
+   Interface:
+
+   .. code-block:: c
+
+      dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
+
+   This returns a cookie can be used to check the progress of DMA engine
+   activity via other DMA engine calls not covered in this document.
+
+   dmaengine_submit() will not start the DMA operation, it merely adds
+   it to the pending queue. For this, see step 5, dma_async_issue_pending.
+
+5. Issue pending DMA requests and wait for callback notification
+
+   The transactions in the pending queue can be activated by calling the
+   issue_pending API. If channel is idle then the first transaction in
+   queue is started and subsequent ones queued up.
+
+   On completion of each DMA operation, the next in queue is started and
+   a tasklet triggered. The tasklet will then call the client driver
+   completion callback routine for notification, if set.
+
+   Interface:
+
+   .. code-block:: c
+
+      void dma_async_issue_pending(struct dma_chan *chan);
+
+Further APIs:
+------------
+
+1. Terminate APIs
+
+   .. code-block:: c
+
+      int dmaengine_terminate_sync(struct dma_chan *chan)
+      int dmaengine_terminate_async(struct dma_chan *chan)
+      int dmaengine_terminate_all(struct dma_chan *chan) /* DEPRECATED */
+
+   This causes all activity for the DMA channel to be stopped, and may
+   discard data in the DMA FIFO which hasn't been fully transferred.
+   No callback functions will be called for any incomplete transfers.
+
+   Two variants of this function are available.
+
+   dmaengine_terminate_async() might not wait until the DMA has been fully
+   stopped or until any running complete callbacks have finished. But it is
+   possible to call dmaengine_terminate_async() from atomic context or from
+   within a complete callback. dmaengine_synchronize() must be called before it
+   is safe to free the memory accessed by the DMA transfer or free resources
+   accessed from within the complete callback.
+
+   dmaengine_terminate_sync() will wait for the transfer and any running
+   complete callbacks to finish before it returns. But the function must not be
+   called from atomic context or from within a complete callback.
+
+   dmaengine_terminate_all() is deprecated and should not be used in new code.
+
+2. Pause API
+
+   .. code-block:: c
+
+      int dmaengine_pause(struct dma_chan *chan)
+
+   This pauses activity on the DMA channel without data loss.
+
+3. Resume API
+
+   .. code-block:: c
+
+       int dmaengine_resume(struct dma_chan *chan)
+
+   Resume a previously paused DMA channel. It is invalid to resume a
+   channel which is not currently paused.
+
+4. Check Txn complete
+
+   .. code-block:: c
+
+      enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
+               dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
+
+   This can be used to check the status of the channel. Please see
+   the documentation in include/linux/dmaengine.h for a more complete
+   description of this API.
+
+   This can be used in conjunction with dma_async_is_complete() and
+   the cookie returned from dmaengine_submit() to check for
+   completion of a specific DMA transaction.
+
+   .. note::
+
+      Not all DMA engine drivers can return reliable information for
+      a running DMA channel. It is recommended that DMA engine users
+      pause or stop (via dmaengine_terminate_all()) the channel before
+      using this API.
+
+5. Synchronize termination API
+
+   .. code-block:: c
+
+      void dmaengine_synchronize(struct dma_chan *chan)
+
+   Synchronize the termination of the DMA channel to the current context.
+
+   This function should be used after dmaengine_terminate_async() to synchronize
+   the termination of the DMA channel to the current context. The function will
+   wait for the transfer and any running complete callbacks to finish before it
+   returns.
+
+   If dmaengine_terminate_async() is used to stop the DMA channel this function
+   must be called before it is safe to free memory accessed by previously
+   submitted descriptors or to free any resources accessed within the complete
+   callback of previously submitted descriptors.
+
+   The behavior of this function is undefined if dma_async_issue_pending() has
+   been called between dmaengine_terminate_async() and this function.
similarity index 50%
rename from Documentation/dmaengine/dmatest.txt
rename to Documentation/driver-api/dmaengine/dmatest.rst
index fb683c72dea847898521d64aa532eed175697ba0..3922c0a3f0c09c7d4d0e8e775796bf4d05a25dfe 100644 (file)
@@ -1,11 +1,13 @@
-                               DMA Test Guide
-                               ==============
+==============
+DMA Test Guide
+==============
 
-               Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 
 This small document introduces how to test DMA drivers using dmatest module.
 
-       Part 1 - How to build the test module
+Part 1 - How to build the test module
+=====================================
 
 The menuconfig contains an option that could be found by following path:
        Device Drivers -> DMA Engine support -> DMA Test client
@@ -13,25 +15,31 @@ The menuconfig contains an option that could be found by following path:
 In the configuration file the option called CONFIG_DMATEST. The dmatest could
 be built as module or inside kernel. Let's consider those cases.
 
-       Part 2 - When dmatest is built as a module...
+Part 2 - When dmatest is built as a module
+==========================================
 
-Example of usage:
-       % modprobe dmatest channel=dma0chan0 timeout=2000 iterations=1 run=1
+Example of usage: ::
 
-...or:
-       % modprobe dmatest
-       % echo dma0chan0 > /sys/module/dmatest/parameters/channel
-       % echo 2000 > /sys/module/dmatest/parameters/timeout
-       % echo 1 > /sys/module/dmatest/parameters/iterations
-       % echo 1 > /sys/module/dmatest/parameters/run
+    % modprobe dmatest channel=dma0chan0 timeout=2000 iterations=1 run=1
 
-...or on the kernel command line:
+...or: ::
 
-       dmatest.channel=dma0chan0 dmatest.timeout=2000 dmatest.iterations=1 dmatest.run=1
+    % modprobe dmatest
+    % echo dma0chan0 > /sys/module/dmatest/parameters/channel
+    % echo 2000 > /sys/module/dmatest/parameters/timeout
+    % echo 1 > /sys/module/dmatest/parameters/iterations
+    % echo 1 > /sys/module/dmatest/parameters/run
 
-Hint: available channel list could be extracted by running the following
-command:
-       % ls -1 /sys/class/dma/
+...or on the kernel command line: ::
+
+    dmatest.channel=dma0chan0 dmatest.timeout=2000 dmatest.iterations=1 dmatest.run=1
+
+..hint:: available channel list could be extracted by running the following
+         command:
+
+::
+
+    % ls -1 /sys/class/dma/
 
 Once started a message like "dmatest: Started 1 threads using dma0chan0" is
 emitted. After that only test failure messages are reported until the test
@@ -39,8 +47,9 @@ stops.
 
 Note that running a new test will not stop any in progress test.
 
-The following command returns the state of the test.
-       % cat /sys/module/dmatest/parameters/run
+The following command returns the state of the test. ::
+
+    % cat /sys/module/dmatest/parameters/run
 
 To wait for test completion userpace can poll 'run' until it is false, or use
 the wait parameter. Specifying 'wait=1' when loading the module causes module
@@ -50,15 +59,19 @@ before returning. For example, the following scripts wait for 42 tests
 to complete before exiting. Note that if 'iterations' is set to 'infinite' then
 waiting is disabled.
 
-Example:
-       % modprobe dmatest run=1 iterations=42 wait=1
-       % modprobe -r dmatest
-...or:
-       % modprobe dmatest run=1 iterations=42
-       % cat /sys/module/dmatest/parameters/wait
-       % modprobe -r dmatest
+Example: ::
+
+    % modprobe dmatest run=1 iterations=42 wait=1
+    % modprobe -r dmatest
 
-       Part 3 - When built-in in the kernel...
+...or: ::
+
+    % modprobe dmatest run=1 iterations=42
+    % cat /sys/module/dmatest/parameters/wait
+    % modprobe -r dmatest
+
+Part 3 - When built-in in the kernel
+====================================
 
 The module parameters that is supplied to the kernel command line will be used
 for the first performed test. After user gets a control, the test could be
@@ -66,27 +79,32 @@ re-run with the same or different parameters. For the details see the above
 section "Part 2 - When dmatest is built as a module..."
 
 In both cases the module parameters are used as the actual values for the test
-case. You always could check them at run-time by running
-       % grep -H . /sys/module/dmatest/parameters/*
+case. You always could check them at run-time by running ::
+
+    % grep -H . /sys/module/dmatest/parameters/*
 
-       Part 4 - Gathering the test results
+Part 4 - Gathering the test results
+===================================
 
-Test results are printed to the kernel log buffer with the format:
+Test results are printed to the kernel log buffer with the format: ::
 
-"dmatest: result <channel>: <test id>: '<error msg>' with src_off=<val> dst_off=<val> len=<val> (<err code>)"
+    "dmatest: result <channel>: <test id>: '<error msg>' with src_off=<val> dst_off=<val> len=<val> (<err code>)"
 
-Example of output:
-       % dmesg | tail -n 1
-       dmatest: result dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0)
+Example of output: ::
+
+
+    % dmesg | tail -n 1
+    dmatest: result dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0)
 
 The message format is unified across the different types of errors. A number in
 the parens represents additional information, e.g. error code, error counter,
 or status. A test thread also emits a summary line at completion listing the
 number of tests executed, number that failed, and a result code.
 
-Example:
-       % dmesg | tail -n 1
-       dmatest: dma0chan0-copy0: summary 1 test, 0 failures 1000 iops 100000 KB/s (0)
+Example: ::
+
+    % dmesg | tail -n 1
+    dmatest: dma0chan0-copy0: summary 1 test, 0 failures 1000 iops 100000 KB/s (0)
 
 The details of a data miscompare error are also emitted, but do not follow the
 above format.
diff --git a/Documentation/driver-api/dmaengine/index.rst b/Documentation/driver-api/dmaengine/index.rst
new file mode 100644 (file)
index 0000000..3026fa9
--- /dev/null
@@ -0,0 +1,55 @@
+=======================
+DMAEngine documentation
+=======================
+
+DMAEngine documentation provides documents for various aspects of DMAEngine
+framework.
+
+DMAEngine documentation
+-----------------------
+
+This book helps with DMAengine internal APIs and guide for DMAEngine device
+driver writers.
+
+.. toctree::
+   :maxdepth: 1
+
+   provider
+
+DMAEngine client documentation
+------------------------------
+
+This book is a guide to device driver writers on how to use the Slave-DMA
+API of the DMAEngine. This is applicable only for slave DMA usage only.
+
+.. toctree::
+   :maxdepth: 1
+
+   client
+
+DMA Test documentation
+----------------------
+
+This book introduces how to test DMA drivers using dmatest module.
+
+.. toctree::
+   :maxdepth: 1
+
+   dmatest
+
+PXA DMA documentation
+----------------------
+
+This book adds some notes about PXA DMA
+
+.. toctree::
+   :maxdepth: 1
+
+   pxa_dma
+
+.. only::  subproject
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst
new file mode 100644 (file)
index 0000000..814acb4
--- /dev/null
@@ -0,0 +1,508 @@
+==================================
+DMAengine controller documentation
+==================================
+
+Hardware Introduction
+=====================
+
+Most of the Slave DMA controllers have the same general principles of
+operations.
+
+They have a given number of channels to use for the DMA transfers, and
+a given number of requests lines.
+
+Requests and channels are pretty much orthogonal. Channels can be used
+to serve several to any requests. To simplify, channels are the
+entities that will be doing the copy, and requests what endpoints are
+involved.
+
+The request lines actually correspond to physical lines going from the
+DMA-eligible devices to the controller itself. Whenever the device
+will want to start a transfer, it will assert a DMA request (DRQ) by
+asserting that request line.
+
+A very simple DMA controller would only take into account a single
+parameter: the transfer size. At each clock cycle, it would transfer a
+byte of data from one buffer to another, until the transfer size has
+been reached.
+
+That wouldn't work well in the real world, since slave devices might
+require a specific number of bits to be transferred in a single
+cycle. For example, we may want to transfer as much data as the
+physical bus allows to maximize performances when doing a simple
+memory copy operation, but our audio device could have a narrower FIFO
+that requires data to be written exactly 16 or 24 bits at a time. This
+is why most if not all of the DMA controllers can adjust this, using a
+parameter called the transfer width.
+
+Moreover, some DMA controllers, whenever the RAM is used as a source
+or destination, can group the reads or writes in memory into a buffer,
+so instead of having a lot of small memory accesses, which is not
+really efficient, you'll get several bigger transfers. This is done
+using a parameter called the burst size, that defines how many single
+reads/writes it's allowed to do without the controller splitting the
+transfer into smaller sub-transfers.
+
+Our theoretical DMA controller would then only be able to do transfers
+that involve a single contiguous block of data. However, some of the
+transfers we usually have are not, and want to copy data from
+non-contiguous buffers to a contiguous buffer, which is called
+scatter-gather.
+
+DMAEngine, at least for mem2dev transfers, require support for
+scatter-gather. So we're left with two cases here: either we have a
+quite simple DMA controller that doesn't support it, and we'll have to
+implement it in software, or we have a more advanced DMA controller,
+that implements in hardware scatter-gather.
+
+The latter are usually programmed using a collection of chunks to
+transfer, and whenever the transfer is started, the controller will go
+over that collection, doing whatever we programmed there.
+
+This collection is usually either a table or a linked list. You will
+then push either the address of the table and its number of elements,
+or the first item of the list to one channel of the DMA controller,
+and whenever a DRQ will be asserted, it will go through the collection
+to know where to fetch the data from.
+
+Either way, the format of this collection is completely dependent on
+your hardware. Each DMA controller will require a different structure,
+but all of them will require, for every chunk, at least the source and
+destination addresses, whether it should increment these addresses or
+not and the three parameters we saw earlier: the burst size, the
+transfer width and the transfer size.
+
+The one last thing is that usually, slave devices won't issue DRQ by
+default, and you have to enable this in your slave device driver first
+whenever you're willing to use DMA.
+
+These were just the general memory-to-memory (also called mem2mem) or
+memory-to-device (mem2dev) kind of transfers. Most devices often
+support other kind of transfers or memory operations that dmaengine
+support and will be detailed later in this document.
+
+DMA Support in Linux
+====================
+
+Historically, DMA controller drivers have been implemented using the
+async TX API, to offload operations such as memory copy, XOR,
+cryptography, etc., basically any memory to memory operation.
+
+Over time, the need for memory to device transfers arose, and
+dmaengine was extended. Nowadays, the async TX API is written as a
+layer on top of dmaengine, and acts as a client. Still, dmaengine
+accommodates that API in some cases, and made some design choices to
+ensure that it stayed compatible.
+
+For more information on the Async TX API, please look the relevant
+documentation file in Documentation/crypto/async-tx-api.txt.
+
+DMAEngine APIs
+==============
+
+``struct dma_device`` Initialization
+------------------------------------
+
+Just like any other kernel framework, the whole DMAEngine registration
+relies on the driver filling a structure and registering against the
+framework. In our case, that structure is dma_device.
+
+The first thing you need to do in your driver is to allocate this
+structure. Any of the usual memory allocators will do, but you'll also
+need to initialize a few fields in there:
+
+- channels: should be initialized as a list using the
+  INIT_LIST_HEAD macro for example
+
+- src_addr_widths:
+  should contain a bitmask of the supported source transfer width
+
+- dst_addr_widths:
+  should contain a bitmask of the supported destination transfer width
+
+- directions:
+  should contain a bitmask of the supported slave directions
+  (i.e. excluding mem2mem transfers)
+
+- residue_granularity:
+
+  - Granularity of the transfer residue reported to dma_set_residue.
+    This can be either:
+
+  - Descriptor
+
+    - Your device doesn't support any kind of residue
+      reporting. The framework will only know that a particular
+      transaction descriptor is done.
+
+      - Segment
+
+        - Your device is able to report which chunks have been transferred
+
+      - Burst
+
+        - Your device is able to report which burst have been transferred
+
+  - dev: should hold the pointer to the ``struct device`` associated
+    to your current driver instance.
+
+Supported transaction types
+---------------------------
+
+The next thing you need is to set which transaction types your device
+(and driver) supports.
+
+Our ``dma_device structure`` has a field called cap_mask that holds the
+various types of transaction supported, and you need to modify this
+mask using the dma_cap_set function, with various flags depending on
+transaction types you support as an argument.
+
+All those capabilities are defined in the ``dma_transaction_type enum``,
+in ``include/linux/dmaengine.h``
+
+Currently, the types available are:
+
+- DMA_MEMCPY
+
+  - The device is able to do memory to memory copies
+
+- DMA_XOR
+
+  - The device is able to perform XOR operations on memory areas
+
+  - Used to accelerate XOR intensive tasks, such as RAID5
+
+- DMA_XOR_VAL
+
+  - The device is able to perform parity check using the XOR
+    algorithm against a memory buffer.
+
+- DMA_PQ
+
+  - The device is able to perform RAID6 P+Q computations, P being a
+    simple XOR, and Q being a Reed-Solomon algorithm.
+
+- DMA_PQ_VAL
+
+  - The device is able to perform parity check using RAID6 P+Q
+    algorithm against a memory buffer.
+
+- DMA_INTERRUPT
+
+  - The device is able to trigger a dummy transfer that will
+    generate periodic interrupts
+
+  - Used by the client drivers to register a callback that will be
+    called on a regular basis through the DMA controller interrupt
+
+- DMA_PRIVATE
+
+  - The devices only supports slave transfers, and as such isn't
+    available for async transfers.
+
+- DMA_ASYNC_TX
+
+  - Must not be set by the device, and will be set by the framework
+    if needed
+
+  - TODO: What is it about?
+
+- DMA_SLAVE
+
+  - The device can handle device to memory transfers, including
+    scatter-gather transfers.
+
+  - While in the mem2mem case we were having two distinct types to
+    deal with a single chunk to copy or a collection of them, here,
+    we just have a single transaction type that is supposed to
+    handle both.
+
+  - If you want to transfer a single contiguous memory buffer,
+    simply build a scatter list with only one item.
+
+- DMA_CYCLIC
+
+  - The device can handle cyclic transfers.
+
+  - A cyclic transfer is a transfer where the chunk collection will
+    loop over itself, with the last item pointing to the first.
+
+  - It's usually used for audio transfers, where you want to operate
+    on a single ring buffer that you will fill with your audio data.
+
+- DMA_INTERLEAVE
+
+  - The device supports interleaved transfer.
+
+  - These transfers can transfer data from a non-contiguous buffer
+    to a non-contiguous buffer, opposed to DMA_SLAVE that can
+    transfer data from a non-contiguous data set to a continuous
+    destination buffer.
+
+  - It's usually used for 2d content transfers, in which case you
+    want to transfer a portion of uncompressed data directly to the
+    display to print it
+
+These various types will also affect how the source and destination
+addresses change over time.
+
+Addresses pointing to RAM are typically incremented (or decremented)
+after each transfer. In case of a ring buffer, they may loop
+(DMA_CYCLIC). Addresses pointing to a device's register (e.g. a FIFO)
+are typically fixed.
+
+Device operations
+-----------------
+
+Our dma_device structure also requires a few function pointers in
+order to implement the actual logic, now that we described what
+operations we were able to perform.
+
+The functions that we have to fill in there, and hence have to
+implement, obviously depend on the transaction types you reported as
+supported.
+
+- ``device_alloc_chan_resources``
+
+- ``device_free_chan_resources``
+
+  - These functions will be called whenever a driver will call
+    ``dma_request_channel`` or ``dma_release_channel`` for the first/last
+    time on the channel associated to that driver.
+
+  - They are in charge of allocating/freeing all the needed
+    resources in order for that channel to be useful for your driver.
+
+  - These functions can sleep.
+
+- ``device_prep_dma_*``
+
+  - These functions are matching the capabilities you registered
+    previously.
+
+  - These functions all take the buffer or the scatterlist relevant
+    for the transfer being prepared, and should create a hardware
+    descriptor or a list of hardware descriptors from it
+
+  - These functions can be called from an interrupt context
+
+  - Any allocation you might do should be using the GFP_NOWAIT
+    flag, in order not to potentially sleep, but without depleting
+    the emergency pool either.
+
+  - Drivers should try to pre-allocate any memory they might need
+    during the transfer setup at probe time to avoid putting to
+    much pressure on the nowait allocator.
+
+  - It should return a unique instance of the
+    ``dma_async_tx_descriptor structure``, that further represents this
+    particular transfer.
+
+  - This structure can be initialized using the function
+    ``dma_async_tx_descriptor_init``.
+
+  - You'll also need to set two fields in this structure:
+
+    - flags:
+      TODO: Can it be modified by the driver itself, or
+      should it be always the flags passed in the arguments
+
+    - tx_submit: A pointer to a function you have to implement,
+      that is supposed to push the current transaction descriptor to a
+      pending queue, waiting for issue_pending to be called.
+
+  - In this structure the function pointer callback_result can be
+    initialized in order for the submitter to be notified that a
+    transaction has completed. In the earlier code the function pointer
+    callback has been used. However it does not provide any status to the
+    transaction and will be deprecated. The result structure defined as
+    ``dmaengine_result`` that is passed in to callback_result
+    has two fields:
+
+    - result: This provides the transfer result defined by
+      ``dmaengine_tx_result``. Either success or some error condition.
+
+    - residue: Provides the residue bytes of the transfer for those that
+      support residue.
+
+- ``device_issue_pending``
+
+  - Takes the first transaction descriptor in the pending queue,
+    and starts the transfer. Whenever that transfer is done, it
+    should move to the next transaction in the list.
+
+  - This function can be called in an interrupt context
+
+- ``device_tx_status``
+
+  - Should report the bytes left to go over on the given channel
+
+  - Should only care about the transaction descriptor passed as
+    argument, not the currently active one on a given channel
+
+  - The tx_state argument might be NULL
+
+  - Should use dma_set_residue to report it
+
+  - In the case of a cyclic transfer, it should only take into
+    account the current period.
+
+  - This function can be called in an interrupt context.
+
+- device_config
+
+  - Reconfigures the channel with the configuration given as argument
+
+  - This command should NOT perform synchronously, or on any
+    currently queued transfers, but only on subsequent ones
+
+  - In this case, the function will receive a ``dma_slave_config``
+    structure pointer as an argument, that will detail which
+    configuration to use.
+
+  - Even though that structure contains a direction field, this
+    field is deprecated in favor of the direction argument given to
+    the prep_* functions
+
+  - This call is mandatory for slave operations only. This should NOT be
+    set or expected to be set for memcpy operations.
+    If a driver support both, it should use this call for slave
+    operations only and not for memcpy ones.
+
+- device_pause
+
+  - Pauses a transfer on the channel
+
+  - This command should operate synchronously on the channel,
+    pausing right away the work of the given channel
+
+- device_resume
+
+  - Resumes a transfer on the channel
+
+  - This command should operate synchronously on the channel,
+    resuming right away the work of the given channel
+
+- device_terminate_all
+
+  - Aborts all the pending and ongoing transfers on the channel
+
+  - For aborted transfers the complete callback should not be called
+
+  - Can be called from atomic context or from within a complete
+    callback of a descriptor. Must not sleep. Drivers must be able
+    to handle this correctly.
+
+  - Termination may be asynchronous. The driver does not have to
+    wait until the currently active transfer has completely stopped.
+    See device_synchronize.
+
+- device_synchronize
+
+  - Must synchronize the termination of a channel to the current
+    context.
+
+  - Must make sure that memory for previously submitted
+    descriptors is no longer accessed by the DMA controller.
+
+  - Must make sure that all complete callbacks for previously
+    submitted descriptors have finished running and none are
+    scheduled to run.
+
+  - May sleep.
+
+
+Misc notes
+==========
+
+(stuff that should be documented, but don't really know
+where to put them)
+
+``dma_run_dependencies``
+
+- Should be called at the end of an async TX transfer, and can be
+  ignored in the slave transfers case.
+
+- Makes sure that dependent operations are run before marking it
+  as complete.
+
+dma_cookie_t
+
+- it's a DMA transaction ID that will increment over time.
+
+- Not really relevant any more since the introduction of ``virt-dma``
+  that abstracts it away.
+
+DMA_CTRL_ACK
+
+- If clear, the descriptor cannot be reused by provider until the
+  client acknowledges receipt, i.e. has has a chance to establish any
+  dependency chains
+
+- This can be acked by invoking async_tx_ack()
+
+- If set, does not mean descriptor can be reused
+
+DMA_CTRL_REUSE
+
+- If set, the descriptor can be reused after being completed. It should
+  not be freed by provider if this flag is set.
+
+- The descriptor should be prepared for reuse by invoking
+  ``dmaengine_desc_set_reuse()`` which will set DMA_CTRL_REUSE.
+
+- ``dmaengine_desc_set_reuse()`` will succeed only when channel support
+  reusable descriptor as exhibited by capabilities
+
+- As a consequence, if a device driver wants to skip the
+  ``dma_map_sg()`` and ``dma_unmap_sg()`` in between 2 transfers,
+  because the DMA'd data wasn't used, it can resubmit the transfer right after
+  its completion.
+
+- Descriptor can be freed in few ways
+
+  - Clearing DMA_CTRL_REUSE by invoking
+    ``dmaengine_desc_clear_reuse()`` and submitting for last txn
+
+  - Explicitly invoking ``dmaengine_desc_free()``, this can succeed only
+    when DMA_CTRL_REUSE is already set
+
+  - Terminating the channel
+
+- DMA_PREP_CMD
+
+  - If set, the client driver tells DMA controller that passed data in DMA
+    API is command data.
+
+  - Interpretation of command data is DMA controller specific. It can be
+    used for issuing commands to other peripherals/register reads/register
+    writes for which the descriptor should be in different format from
+    normal data descriptors.
+
+General Design Notes
+====================
+
+Most of the DMAEngine drivers you'll see are based on a similar design
+that handles the end of transfer interrupts in the handler, but defer
+most work to a tasklet, including the start of a new transfer whenever
+the previous transfer ended.
+
+This is a rather inefficient design though, because the inter-transfer
+latency will be not only the interrupt latency, but also the
+scheduling latency of the tasklet, which will leave the channel idle
+in between, which will slow down the global transfer rate.
+
+You should avoid this kind of practice, and instead of electing a new
+transfer in your tasklet, move that part to the interrupt handler in
+order to have a shorter idle window (that we can't really avoid
+anyway).
+
+Glossary
+========
+
+- Burst: A number of consecutive read or write operations that
+  can be queued to buffers before being flushed to memory.
+
+- Chunk: A contiguous collection of bursts
+
+- Transfer: A collection of chunks (be it contiguous or not)
diff --git a/Documentation/driver-api/dmaengine/pxa_dma.rst b/Documentation/driver-api/dmaengine/pxa_dma.rst
new file mode 100644 (file)
index 0000000..442ee69
--- /dev/null
@@ -0,0 +1,190 @@
+==============================
+PXA/MMP - DMA Slave controller
+==============================
+
+Constraints
+===========
+
+a) Transfers hot queuing
+A driver submitting a transfer and issuing it should be granted the transfer
+is queued even on a running DMA channel.
+This implies that the queuing doesn't wait for the previous transfer end,
+and that the descriptor chaining is not only done in the irq/tasklet code
+triggered by the end of the transfer.
+A transfer which is submitted and issued on a phy doesn't wait for a phy to
+stop and restart, but is submitted on a "running channel". The other
+drivers, especially mmp_pdma waited for the phy to stop before relaunching
+a new transfer.
+
+b) All transfers having asked for confirmation should be signaled
+Any issued transfer with DMA_PREP_INTERRUPT should trigger a callback call.
+This implies that even if an irq/tasklet is triggered by end of tx1, but
+at the time of irq/dma tx2 is already finished, tx1->complete() and
+tx2->complete() should be called.
+
+c) Channel running state
+A driver should be able to query if a channel is running or not. For the
+multimedia case, such as video capture, if a transfer is submitted and then
+a check of the DMA channel reports a "stopped channel", the transfer should
+not be issued until the next "start of frame interrupt", hence the need to
+know if a channel is in running or stopped state.
+
+d) Bandwidth guarantee
+The PXA architecture has 4 levels of DMAs priorities : high, normal, low.
+The high priorities get twice as much bandwidth as the normal, which get twice
+as much as the low priorities.
+A driver should be able to request a priority, especially the real-time
+ones such as pxa_camera with (big) throughputs.
+
+Design
+======
+a) Virtual channels
+Same concept as in sa11x0 driver, ie. a driver was assigned a "virtual
+channel" linked to the requestor line, and the physical DMA channel is
+assigned on the fly when the transfer is issued.
+
+b) Transfer anatomy for a scatter-gather transfer
+
+::
+
+   +------------+-----+---------------+----------------+-----------------+
+   | desc-sg[0] | ... | desc-sg[last] | status updater | finisher/linker |
+   +------------+-----+---------------+----------------+-----------------+
+
+This structure is pointed by dma->sg_cpu.
+The descriptors are used as follows :
+
+    - desc-sg[i]: i-th descriptor, transferring the i-th sg
+      element to the video buffer scatter gather
+
+    - status updater
+      Transfers a single u32 to a well known dma coherent memory to leave
+      a trace that this transfer is done. The "well known" is unique per
+      physical channel, meaning that a read of this value will tell which
+      is the last finished transfer at that point in time.
+
+    - finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN
+
+    - linker: has ddadr= desc-sg[0] of next transfer, dcmd=0
+
+c) Transfers hot-chaining
+Suppose the running chain is:
+
+::
+
+   Buffer 1              Buffer 2
+   +---------+----+---+  +----+----+----+---+
+   | d0 | .. | dN | l |  | d0 | .. | dN | f |
+   +---------+----+-|-+  ^----+----+----+---+
+                    |    |
+                    +----+
+
+After a call to dmaengine_submit(b3), the chain will look like:
+
+::
+
+   Buffer 1              Buffer 2              Buffer 3
+   +---------+----+---+  +----+----+----+---+  +----+----+----+---+
+   | d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
+   +---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
+                    |    |                |    |
+                    +----+                +----+
+                                         new_link
+
+If while new_link was created the DMA channel stopped, it is _not_
+restarted. Hot-chaining doesn't break the assumption that
+dma_async_issue_pending() is to be used to ensure the transfer is actually started.
+
+One exception to this rule :
+
+- if Buffer1 and Buffer2 had all their addresses 8 bytes aligned
+
+- and if Buffer3 has at least one address not 4 bytes aligned
+
+- then hot-chaining cannot happen, as the channel must be stopped, the
+  "align bit" must be set, and the channel restarted As a consequence,
+  such a transfer tx_submit() will be queued on the submitted queue, and
+  this specific case if the DMA is already running in aligned mode.
+
+d) Transfers completion updater
+Each time a transfer is completed on a channel, an interrupt might be
+generated or not, up to the client's request. But in each case, the last
+descriptor of a transfer, the "status updater", will write the latest
+transfer being completed into the physical channel's completion mark.
+
+This will speed up residue calculation, for large transfers such as video
+buffers which hold around 6k descriptors or more. This also allows without
+any lock to find out what is the latest completed transfer in a running
+DMA chain.
+
+e) Transfers completion, irq and tasklet
+When a transfer flagged as "DMA_PREP_INTERRUPT" is finished, the dma irq
+is raised. Upon this interrupt, a tasklet is scheduled for the physical
+channel.
+
+The tasklet is responsible for :
+
+- reading the physical channel last updater mark
+
+- calling all the transfer callbacks of finished transfers, based on
+  that mark, and each transfer flags.
+
+If a transfer is completed while this handling is done, a dma irq will
+be raised, and the tasklet will be scheduled once again, having a new
+updater mark.
+
+f) Residue
+Residue granularity will be descriptor based. The issued but not completed
+transfers will be scanned for all of their descriptors against the
+currently running descriptor.
+
+g) Most complicated case of driver's tx queues
+The most tricky situation is when :
+
+ - there are not "acked" transfers (tx0)
+
+ - a driver submitted an aligned tx1, not chained
+
+ - a driver submitted an aligned tx2 => tx2 is cold chained to tx1
+
+ - a driver issued tx1+tx2 => channel is running in aligned mode
+
+ - a driver submitted an aligned tx3 => tx3 is hot-chained
+
+ - a driver submitted an unaligned tx4 => tx4 is put in submitted queue,
+   not chained
+
+ - a driver issued tx4 => tx4 is put in issued queue, not chained
+
+ - a driver submitted an aligned tx5 => tx5 is put in submitted queue, not
+   chained
+
+ - a driver submitted an aligned tx6 => tx6 is put in submitted queue,
+   cold chained to tx5
+
+ This translates into (after tx4 is issued) :
+
+ - issued queue
+
+ ::
+
+      +-----+ +-----+ +-----+ +-----+
+      | tx1 | | tx2 | | tx3 | | tx4 |
+      +---|-+ ^---|-+ ^-----+ +-----+
+          |   |   |   |
+          +---+   +---+
+        - submitted queue
+      +-----+ +-----+
+      | tx5 | | tx6 |
+      +---|-+ ^-----+
+          |   |
+          +---+
+
+- completed queue : empty
+
+- allocated queue : tx0
+
+It should be noted that after tx3 is completed, the channel is stopped, and
+restarted in "unaligned mode" to handle tx4.
+
+Author: Robert Jarzmik <robert.jarzmik@free.fr>
index 9c20624842b72fa3cc0248abdc441ef126a98dc8..d17a9876b473a4910e4e01820c21307e57c31578 100644 (file)
@@ -46,6 +46,7 @@ available subsections can be seen below.
    pinctl
    gpio
    misc_devices
+   dmaengine/index
 
 .. only::  subproject and html
 
index a0dc2879a152c89dbb9d5f715ec07fbfe6a4cd8e..53c1b0b06da5faae4670b33dd37e365e145b4210 100644 (file)
@@ -274,7 +274,7 @@ sleep states and the hibernation state ("suspend-to-disk").  Each phase involves
 executing callbacks for every device before the next phase begins.  Not all
 buses or classes support all these callbacks and not all drivers use all the
 callbacks.  The various phases always run after tasks have been frozen and
-before they are unfrozen.  Furthermore, the ``*_noirq phases`` run at a time
+before they are unfrozen.  Furthermore, the ``*_noirq`` phases run at a time
 when IRQ handlers have been disabled (except for those marked with the
 IRQF_NO_SUSPEND flag).
 
@@ -328,7 +328,10 @@ the phases are: ``prepare``, ``suspend``, ``suspend_late``, ``suspend_noirq``.
        After the ``->prepare`` callback method returns, no new children may be
        registered below the device.  The method may also prepare the device or
        driver in some way for the upcoming system power transition, but it
-       should not put the device into a low-power state.
+       should not put the device into a low-power state.  Moreover, if the
+       device supports runtime power management, the ``->prepare`` callback
+       method must not update its state in case it is necessary to resume it
+       from runtime suspend later on.
 
        For devices supporting runtime power management, the return value of the
        prepare callback can be used to indicate to the PM core that it may
@@ -351,11 +354,35 @@ the phases are: ``prepare``, ``suspend``, ``suspend_late``, ``suspend_noirq``.
        is because all such devices are initially set to runtime-suspended with
        runtime PM disabled.
 
+       This feature also can be controlled by device drivers by using the
+       ``DPM_FLAG_NEVER_SKIP`` and ``DPM_FLAG_SMART_PREPARE`` driver power
+       management flags.  [Typically, they are set at the time the driver is
+       probed against the device in question by passing them to the
+       :c:func:`dev_pm_set_driver_flags` helper function.]  If the first of
+       these flags is set, the PM core will not apply the direct-complete
+       procedure described above to the given device and, consequenty, to any
+       of its ancestors.  The second flag, when set, informs the middle layer
+       code (bus types, device types, PM domains, classes) that it should take
+       the return value of the ``->prepare`` callback provided by the driver
+       into account and it may only return a positive value from its own
+       ``->prepare`` callback if the driver's one also has returned a positive
+       value.
+
     2. The ``->suspend`` methods should quiesce the device to stop it from
        performing I/O.  They also may save the device registers and put it into
        the appropriate low-power state, depending on the bus type the device is
        on, and they may enable wakeup events.
 
+       However, for devices supporting runtime power management, the
+       ``->suspend`` methods provided by subsystems (bus types and PM domains
+       in particular) must follow an additional rule regarding what can be done
+       to the devices before their drivers' ``->suspend`` methods are called.
+       Namely, they can only resume the devices from runtime suspend by
+       calling :c:func:`pm_runtime_resume` for them, if that is necessary, and
+       they must not update the state of the devices in any other way at that
+       time (in case the drivers need to resume the devices from runtime
+       suspend in their ``->suspend`` methods).
+
     3. For a number of devices it is convenient to split suspend into the
        "quiesce device" and "save device state" phases, in which cases
        ``suspend_late`` is meant to do the latter.  It is always executed after
@@ -729,6 +756,36 @@ state temporarily, for example so that its system wakeup capability can be
 disabled.  This all depends on the hardware and the design of the subsystem and
 device driver in question.
 
+If it is necessary to resume a device from runtime suspend during a system-wide
+transition into a sleep state, that can be done by calling
+:c:func:`pm_runtime_resume` for it from the ``->suspend`` callback (or its
+couterpart for transitions related to hibernation) of either the device's driver
+or a subsystem responsible for it (for example, a bus type or a PM domain).
+That is guaranteed to work by the requirement that subsystems must not change
+the state of devices (possibly except for resuming them from runtime suspend)
+from their ``->prepare`` and ``->suspend`` callbacks (or equivalent) *before*
+invoking device drivers' ``->suspend`` callbacks (or equivalent).
+
+Some bus types and PM domains have a policy to resume all devices from runtime
+suspend upfront in their ``->suspend`` callbacks, but that may not be really
+necessary if the driver of the device can cope with runtime-suspended devices.
+The driver can indicate that by setting ``DPM_FLAG_SMART_SUSPEND`` in
+:c:member:`power.driver_flags` at the probe time, by passing it to the
+:c:func:`dev_pm_set_driver_flags` helper.  That also may cause middle-layer code
+(bus types, PM domains etc.) to skip the ``->suspend_late`` and
+``->suspend_noirq`` callbacks provided by the driver if the device remains in
+runtime suspend at the beginning of the ``suspend_late`` phase of system-wide
+suspend (or in the ``poweroff_late`` phase of hibernation), when runtime PM
+has been disabled for it, under the assumption that its state should not change
+after that point until the system-wide transition is over.  If that happens, the
+driver's system-wide resume callbacks, if present, may still be invoked during
+the subsequent system-wide resume transition and the device's runtime power
+management status may be set to "active" before enabling runtime PM for it,
+so the driver must be prepared to cope with the invocation of its system-wide
+resume callbacks back-to-back with its ``->runtime_suspend`` one (without the
+intervening ``->runtime_resume`` and so on) and the final state of the device
+must reflect the "active" status for runtime PM in that case.
+
 During system-wide resume from a sleep state it's easiest to put devices into
 the full-power state, as explained in :file:`Documentation/power/runtime_pm.txt`.
 Refer to that document for more information regarding this particular issue as
index dba0f876b36f4dc1f52c412f82896972b36d208a..078e981e2b161f387f7703032f19265e437fea1b 100644 (file)
@@ -690,9 +690,7 @@ The USB devices are now exported via debugfs:
 This file is handy for status viewing tools in user mode, which can scan
 the text format and ignore most of it. More detailed device status
 (including class and vendor status) is available from device-specific
-files. For information about the current format of this file, see the
-``Documentation/usb/proc_usb_info.txt`` file in your Linux kernel
-sources.
+files. For information about the current format of this file, see below.
 
 This file, in combination with the poll() system call, can also be used
 to detect when devices are added or removed::
index 83d3f4e43e91726201ba56392f0723c40927fc67..e861d761de249ffc53c6ec2fcc5d25b6da56487e 100644 (file)
@@ -6,41 +6,11 @@ specified notifier chain callbacks. It is useful to test the error handling of
 notifier call chain failures which is rarely executed.  There are kernel
 modules that can be used to test the following notifiers.
 
- * CPU notifier
  * PM notifier
  * Memory hotplug notifier
  * powerpc pSeries reconfig notifier
  * Netdevice notifier
 
-CPU notifier error injection module
------------------------------------
-This feature can be used to test the error handling of the CPU notifiers by
-injecting artificial errors to CPU notifier chain callbacks.
-
-If the notifier call chain should be failed with some events notified, write
-the error code to debugfs interface
-/sys/kernel/debug/notifier-error-inject/cpu/actions/<notifier event>/error
-
-Possible CPU notifier events to be failed are:
-
- * CPU_UP_PREPARE
- * CPU_UP_PREPARE_FROZEN
- * CPU_DOWN_PREPARE
- * CPU_DOWN_PREPARE_FROZEN
-
-Example1: Inject CPU offline error (-1 == -EPERM)
-
-       # cd /sys/kernel/debug/notifier-error-inject/cpu
-       # echo -1 > actions/CPU_DOWN_PREPARE/error
-       # echo 0 > /sys/devices/system/cpu/cpu1/online
-       bash: echo: write error: Operation not permitted
-
-Example2: inject CPU online error (-2 == -ENOENT)
-
-       # echo -2 > actions/CPU_UP_PREPARE/error
-       # echo 1 > /sys/devices/system/cpu/cpu1/online
-       bash: echo: write error: No such file or directory
-
 PM notifier error injection module
 ----------------------------------
 This feature is controlled through debugfs interface
index a38d3aa4d189960121ed9740fa0827773b574b91..79c22d096bbc0b83ffbbbc162aec23abaa59e08c 100644 (file)
@@ -77,8 +77,8 @@ C. Boot options
 1. fbcon=font:<name>
 
         Select the initial font to use. The value 'name' can be any of the
-        compiled-in fonts: VGA8x16, 7x14, 10x18, VGA8x8, MINI4x6, RomanLarge,
-        SUN8x16, SUN12x22, ProFont6x11, Acorn8x8, PEARL8x8.
+        compiled-in fonts: 10x18, 6x10, 7x14, Acorn8x8, MINI4x6,
+        PEARL8x8, ProFont6x11, SUN12x22, SUN8x16, VGA8x16, VGA8x8.
 
        Note, not all drivers can handle font with widths not divisible by 8,
         such as vga16fb.
index 76bbd7fe27b35bec5839e6bcac0337c550fc76b2..f377290fe48eef50afbc5c9e49f94d7c646d8c6c 100644 (file)
@@ -34,6 +34,6 @@
     |        tile: | TODO |
     |          um: | TODO |
     |   unicore32: | TODO |
-    |         x86: |  ok  |
+    |         x86: |  ok  | 64-bit only
     |      xtensa: | TODO |
     -----------------------
index 6baf88f468590cbd2816ed0198c048c10d754a6b..15156883d321995aa34c12126ff3186c5903b44d 100644 (file)
@@ -62,7 +62,7 @@ disabled, fcntl(fd, F_NOTIFY, ...) will return -EINVAL.
 
 Example
 -------
-See Documentation/filesystems/dnotify_test.c for an example.
+See tools/testing/selftests/filesystems/dnotify_test.c for an example.
 
 NOTE
 ----
index 5a8f7f4d2bca227516b0e21fae0945b4554d4485..75236c0c2ac231151b98e8ee2e1cbfd2b2ae6451 100644 (file)
@@ -94,10 +94,10 @@ Note: More extensive information for getting started with ext4 can be
 * ability to pack bitmaps and inode tables into larger virtual groups via the
   flex_bg feature
 * large file support
-* Inode allocation using large virtual block groups via flex_bg
+* inode allocation using large virtual block groups via flex_bg
 * delayed allocation
 * large block (up to pagesize) support
-* efficient new ordered mode in JBD2 and ext4(avoid using buffer head to force
+* efficient new ordered mode in JBD2 and ext4 (avoid using buffer head to force
   the ordering)
 
 [1] Filesystems with a block size of 1k may see a limit imposed by the
@@ -105,7 +105,7 @@ directory hash tree having a maximum depth of two.
 
 2.2 Candidate features for future inclusion
 
-* Online defrag (patches available but not well tested)
+* online defrag (patches available but not well tested)
 * reduced mke2fs time via lazy itable initialization in conjunction with
   the uninit_bg feature (capability to do this is available in e2fsprogs
   but a kernel thread to do lazy zeroing of unused inode table blocks
@@ -602,7 +602,7 @@ Table of Ext4 specific ioctls
                              bitmaps and inode table, the userspace tool thus
                              just passes the new number of blocks.
 
-EXT4_IOC_SWAP_BOOT           Swap i_blocks and associated attributes
+ EXT4_IOC_SWAP_BOOT          Swap i_blocks and associated attributes
                              (like i_blocks, i_size, i_flags, ...) from
                              the specified inode with inode
                              EXT4_BOOT_LOADER_INO (#5). This is typically
index 1b39e084a2b29d84df85f0134549b7abecc71dbd..1933ef734e63b03802b42ce236b2b664b239dd93 100644 (file)
@@ -826,9 +826,9 @@ If the filesystem may need to revalidate dcache entries, then
 *is* passed the dentry but does not have access to the `inode` or the
 `seq` number from the `nameidata`, so it needs to be extra careful
 when accessing fields in the dentry.  This "extra care" typically
-involves using `ACCESS_ONCE()` or the newer [`READ_ONCE()`] to access
-fields, and verifying the result is not NULL before using it.  This
-pattern can be see in `nfs_lookup_revalidate()`.
+involves using [`READ_ONCE()`] to access fields, and verifying the
+result is not NULL before using it.  This pattern can be seen in
+`nfs_lookup_revalidate()`.
 
 A pair of patterns
 ------------------
index 6e8c9f1d2f223448b4e070ee1801e2c9ede36e79..638448707aa214f655c7b5860d53d9e14088fbb7 100644 (file)
@@ -12,7 +12,7 @@ To support these disparate requirements, the Linux USB system provides
 HID events to two separate interfaces:
 * the input subsystem, which converts HID events into normal input
 device interfaces (such as keyboard, mouse and joystick) and a
-normalised event interface - see Documentation/input/input.txt
+normalised event interface - see Documentation/input/input.rst
 * the hiddev interface, which provides fairly raw HID events
 
 The data flow for a HID event produced by a device is something like
diff --git a/Documentation/hwmon/max31785 b/Documentation/hwmon/max31785
new file mode 100644 (file)
index 0000000..45fb609
--- /dev/null
@@ -0,0 +1,51 @@
+Kernel driver max31785
+======================
+
+Supported chips:
+  * Maxim MAX31785, MAX31785A
+    Prefix: 'max31785' or 'max31785a'
+    Addresses scanned: -
+    Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
+
+Author: Andrew Jeffery <andrew@aj.id.au>
+
+Description
+-----------
+
+The Maxim MAX31785 is a PMBus device providing closed-loop, multi-channel fan
+management with temperature and remote voltage sensing. Various fan control
+features are provided, including PWM frequency control, temperature hysteresis,
+dual tachometer measurements, and fan health monitoring.
+
+For dual rotor fan configuration, the MAX31785 exposes the slowest rotor of the
+two in the fan[1-4]_input attributes.
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have to instantiate
+devices explicitly.
+
+Sysfs attributes
+----------------
+
+fan[1-4]_alarm         Fan alarm.
+fan[1-4]_fault         Fan fault.
+fan[1-4]_input         Fan RPM.
+
+in[1-6]_crit           Critical maximum output voltage
+in[1-6]_crit_alarm     Output voltage critical high alarm
+in[1-6]_input          Measured output voltage
+in[1-6]_label          "vout[18-23]"
+in[1-6]_lcrit          Critical minimum output voltage
+in[1-6]_lcrit_alarm    Output voltage critical low alarm
+in[1-6]_max            Maximum output voltage
+in[1-6]_max_alarm      Output voltage high alarm
+in[1-6]_min            Minimum output voltage
+in[1-6]_min_alarm      Output voltage low alarm
+
+temp[1-11]_crit                Critical high temperature
+temp[1-11]_crit_alarm  Chip temperature critical high alarm
+temp[1-11]_input       Measured temperature
+temp[1-11]_max         Maximum temperature
+temp[1-11]_max_alarm   Chip temperature high alarm
index 778987d1856fd2c117cb779c3ef988cb2127218d..5e3207c3b177d285722e82d86c02304995b9cf4f 100644 (file)
@@ -42,8 +42,7 @@ chip. These coefficients are used to internally calibrate the signals from the
 sensors. Disabling the reload of those coefficients allows saving 10ms for each
 measurement and decrease power consumption, while losing on precision.
 
-Some options may be set directly in the sht15_platform_data structure
-or via sysfs attributes.
+Some options may be set via sysfs attributes.
 
 Notes:
   * The regulator supply name is set to "vcc".
index 5a709ab77c8dbe42f8d7da8669cb6090a3f8323f..b8bd65962dd8a664369ee8769ab7df2b6abf9bbd 100644 (file)
@@ -230,4 +230,5 @@ Historic Edits
 2005-03-19 - Dominic Cerquetti <binary1230@yahoo.com>
  - added stuff for dance pads, new d-pad->axes mappings
 
-Later changes may be viewed with 'git log Documentation/input/xpad.txt'
+Later changes may be viewed with
+'git log --follow Documentation/input/devices/xpad.rst'
index 2335715bf471ac94aebfb47c623cf1a6bfadd3e7..22208bf2386d1dac06b04f4b8c064286885f9d55 100644 (file)
@@ -8,7 +8,7 @@ Kernel Probes (Kprobes)
 
 .. CONTENTS
 
-  1. Concepts: Kprobes, Jprobes, Return Probes
+  1. Concepts: Kprobes, and Return Probes
   2. Architectures Supported
   3. Configuring Kprobes
   4. API Reference
@@ -16,12 +16,12 @@ Kernel Probes (Kprobes)
   6. Probe Overhead
   7. TODO
   8. Kprobes Example
-  9. Jprobes Example
-  10. Kretprobes Example
+  9. Kretprobes Example
+  10. Deprecated Features
   Appendix A: The kprobes debugfs interface
   Appendix B: The kprobes sysctl interface
 
-Concepts: Kprobes, Jprobes, Return Probes
+Concepts: Kprobes and Return Probes
 =========================================
 
 Kprobes enables you to dynamically break into any kernel routine and
@@ -32,12 +32,10 @@ routine to be invoked when the breakpoint is hit.
 .. [1] some parts of the kernel code can not be trapped, see
        :ref:`kprobes_blacklist`)
 
-There are currently three types of probes: kprobes, jprobes, and
-kretprobes (also called return probes).  A kprobe can be inserted
-on virtually any instruction in the kernel.  A jprobe is inserted at
-the entry to a kernel function, and provides convenient access to the
-function's arguments.  A return probe fires when a specified function
-returns.
+There are currently two types of probes: kprobes, and kretprobes
+(also called return probes).  A kprobe can be inserted on virtually
+any instruction in the kernel.  A return probe fires when a specified
+function returns.
 
 In the typical case, Kprobes-based instrumentation is packaged as
 a kernel module.  The module's init function installs ("registers")
@@ -82,45 +80,6 @@ After the instruction is single-stepped, Kprobes executes the
 "post_handler," if any, that is associated with the kprobe.
 Execution then continues with the instruction following the probepoint.
 
-How Does a Jprobe Work?
------------------------
-
-A jprobe is implemented using a kprobe that is placed on a function's
-entry point.  It employs a simple mirroring principle to allow
-seamless access to the probed function's arguments.  The jprobe
-handler routine should have the same signature (arg list and return
-type) as the function being probed, and must always end by calling
-the Kprobes function jprobe_return().
-
-Here's how it works.  When the probe is hit, Kprobes makes a copy of
-the saved registers and a generous portion of the stack (see below).
-Kprobes then points the saved instruction pointer at the jprobe's
-handler routine, and returns from the trap.  As a result, control
-passes to the handler, which is presented with the same register and
-stack contents as the probed function.  When it is done, the handler
-calls jprobe_return(), which traps again to restore the original stack
-contents and processor state and switch to the probed function.
-
-By convention, the callee owns its arguments, so gcc may produce code
-that unexpectedly modifies that portion of the stack.  This is why
-Kprobes saves a copy of the stack and restores it after the jprobe
-handler has run.  Up to MAX_STACK_SIZE bytes are copied -- e.g.,
-64 bytes on i386.
-
-Note that the probed function's args may be passed on the stack
-or in registers.  The jprobe will work in either case, so long as the
-handler's prototype matches that of the probed function.
-
-Note that in some architectures (e.g.: arm64 and sparc64) the stack
-copy is not done, as the actual location of stacked parameters may be
-outside of a reasonable MAX_STACK_SIZE value and because that location
-cannot be determined by the jprobes code. In this case the jprobes
-user must be careful to make certain the calling signature of the
-function does not cause parameters to be passed on the stack (e.g.:
-more than eight function arguments, an argument of more than sixteen
-bytes, or more than 64 bytes of argument data, depending on
-architecture).
-
 Return Probes
 -------------
 
@@ -245,8 +204,7 @@ Pre-optimization
 After preparing the detour buffer, Kprobes verifies that none of the
 following situations exist:
 
-- The probe has either a break_handler (i.e., it's a jprobe) or a
-  post_handler.
+- The probe has a post_handler.
 - Other instructions in the optimized region are probed.
 - The probe is disabled.
 
@@ -331,7 +289,7 @@ rejects registering it, if the given address is in the blacklist.
 Architectures Supported
 =======================
 
-Kprobes, jprobes, and return probes are implemented on the following
+Kprobes and return probes are implemented on the following
 architectures:
 
 - i386 (Supports jump optimization)
@@ -446,27 +404,6 @@ architecture-specific trap number associated with the fault (e.g.,
 on i386, 13 for a general protection fault or 14 for a page fault).
 Returns 1 if it successfully handled the exception.
 
-register_jprobe
----------------
-
-::
-
-       #include <linux/kprobes.h>
-       int register_jprobe(struct jprobe *jp)
-
-Sets a breakpoint at the address jp->kp.addr, which must be the address
-of the first instruction of a function.  When the breakpoint is hit,
-Kprobes runs the handler whose address is jp->entry.
-
-The handler should have the same arg list and return type as the probed
-function; and just before it returns, it must call jprobe_return().
-(The handler never actually returns, since jprobe_return() returns
-control to Kprobes.)  If the probed function is declared asmlinkage
-or anything else that affects how args are passed, the handler's
-declaration must match.
-
-register_jprobe() returns 0 on success, or a negative errno otherwise.
-
 register_kretprobe
 ------------------
 
@@ -513,7 +450,6 @@ unregister_*probe
 
        #include <linux/kprobes.h>
        void unregister_kprobe(struct kprobe *kp);
-       void unregister_jprobe(struct jprobe *jp);
        void unregister_kretprobe(struct kretprobe *rp);
 
 Removes the specified probe.  The unregister function can be called
@@ -532,7 +468,6 @@ register_*probes
        #include <linux/kprobes.h>
        int register_kprobes(struct kprobe **kps, int num);
        int register_kretprobes(struct kretprobe **rps, int num);
-       int register_jprobes(struct jprobe **jps, int num);
 
 Registers each of the num probes in the specified array.  If any
 error occurs during registration, all probes in the array, up to
@@ -555,7 +490,6 @@ unregister_*probes
        #include <linux/kprobes.h>
        void unregister_kprobes(struct kprobe **kps, int num);
        void unregister_kretprobes(struct kretprobe **rps, int num);
-       void unregister_jprobes(struct jprobe **jps, int num);
 
 Removes each of the num probes in the specified array at once.
 
@@ -574,7 +508,6 @@ disable_*probe
        #include <linux/kprobes.h>
        int disable_kprobe(struct kprobe *kp);
        int disable_kretprobe(struct kretprobe *rp);
-       int disable_jprobe(struct jprobe *jp);
 
 Temporarily disables the specified ``*probe``. You can enable it again by using
 enable_*probe(). You must specify the probe which has been registered.
@@ -587,7 +520,6 @@ enable_*probe
        #include <linux/kprobes.h>
        int enable_kprobe(struct kprobe *kp);
        int enable_kretprobe(struct kretprobe *rp);
-       int enable_jprobe(struct jprobe *jp);
 
 Enables ``*probe`` which has been disabled by disable_*probe(). You must specify
 the probe which has been registered.
@@ -595,12 +527,10 @@ the probe which has been registered.
 Kprobes Features and Limitations
 ================================
 
-Kprobes allows multiple probes at the same address.  Currently,
-however, there cannot be multiple jprobes on the same function at
-the same time.  Also, a probepoint for which there is a jprobe or
-a post_handler cannot be optimized.  So if you install a jprobe,
-or a kprobe with a post_handler, at an optimized probepoint, the
-probepoint will be unoptimized automatically.
+Kprobes allows multiple probes at the same address. Also,
+a probepoint for which there is a post_handler cannot be optimized.
+So if you install a kprobe with a post_handler, at an optimized
+probepoint, the probepoint will be unoptimized automatically.
 
 In general, you can install a probe anywhere in the kernel.
 In particular, you can probe interrupt handlers.  Known exceptions
@@ -662,7 +592,7 @@ We're unaware of other specific cases where this could be a problem.
 If, upon entry to or exit from a function, the CPU is running on
 a stack other than that of the current task, registering a return
 probe on that function may produce undesirable results.  For this
-reason, Kprobes doesn't support return probes (or kprobes or jprobes)
+reason, Kprobes doesn't support return probes (or kprobes)
 on the x86_64 version of __switch_to(); the registration functions
 return -EINVAL.
 
@@ -706,24 +636,24 @@ Probe Overhead
 On a typical CPU in use in 2005, a kprobe hit takes 0.5 to 1.0
 microseconds to process.  Specifically, a benchmark that hits the same
 probepoint repeatedly, firing a simple handler each time, reports 1-2
-million hits per second, depending on the architecture.  A jprobe or
-return-probe hit typically takes 50-75% longer than a kprobe hit.
+million hits per second, depending on the architecture.  A return-probe
+hit typically takes 50-75% longer than a kprobe hit.
 When you have a return probe set on a function, adding a kprobe at
 the entry to that function adds essentially no overhead.
 
 Here are sample overhead figures (in usec) for different architectures::
 
-  k = kprobe; j = jprobe; r = return probe; kr = kprobe + return probe
-  on same function; jr = jprobe + return probe on same function::
+  k = kprobe; r = return probe; kr = kprobe + return probe
+  on same function
 
   i386: Intel Pentium M, 1495 MHz, 2957.31 bogomips
-  k = 0.57 usec; j = 1.00; r = 0.92; kr = 0.99; jr = 1.40
+  k = 0.57 usec; r = 0.92; kr = 0.99
 
   x86_64: AMD Opteron 246, 1994 MHz, 3971.48 bogomips
-  k = 0.49 usec; j = 0.76; r = 0.80; kr = 0.82; jr = 1.07
+  k = 0.49 usec; r = 0.80; kr = 0.82
 
   ppc64: POWER5 (gr), 1656 MHz (SMT disabled, 1 virtual CPU per physical CPU)
-  k = 0.77 usec; j = 1.31; r = 1.26; kr = 1.45; jr = 1.99
+  k = 0.77 usec; r = 1.26; kr = 1.45
 
 Optimized Probe Overhead
 ------------------------
@@ -755,11 +685,6 @@ Kprobes Example
 
 See samples/kprobes/kprobe_example.c
 
-Jprobes Example
-===============
-
-See samples/kprobes/jprobe_example.c
-
 Kretprobes Example
 ==================
 
@@ -772,6 +697,37 @@ For additional information on Kprobes, refer to the following URLs:
 - http://www-users.cs.umn.edu/~boutcher/kprobes/
 - http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
 
+Deprecated Features
+===================
+
+Jprobes is now a deprecated feature. People who are depending on it should
+migrate to other tracing features or use older kernels. Please consider to
+migrate your tool to one of the following options:
+
+- Use trace-event to trace target function with arguments.
+
+  trace-event is a low-overhead (and almost no visible overhead if it
+  is off) statically defined event interface. You can define new events
+  and trace it via ftrace or any other tracing tools.
+
+  See the following urls:
+
+    - https://lwn.net/Articles/379903/
+    - https://lwn.net/Articles/381064/
+    - https://lwn.net/Articles/383362/
+
+- Use ftrace dynamic events (kprobe event) with perf-probe.
+
+  If you build your kernel with debug info (CONFIG_DEBUG_INFO=y), you can
+  find which register/stack is assigned to which local variable or arguments
+  by using perf-probe and set up new event to trace it.
+
+  See following documents:
+
+  - Documentation/trace/kprobetrace.txt
+  - Documentation/trace/events.txt
+  - tools/perf/Documentation/perf-probe.txt
+
 
 The kprobes debugfs interface
 =============================
@@ -783,14 +739,13 @@ under the /sys/kernel/debug/kprobes/ directory (assuming debugfs is mounted at /
 /sys/kernel/debug/kprobes/list: Lists all registered probes on the system::
 
        c015d71a  k  vfs_read+0x0
-       c011a316  j  do_fork+0x0
        c03dedc5  r  tcp_v4_rcv+0x0
 
 The first column provides the kernel address where the probe is inserted.
-The second column identifies the type of probe (k - kprobe, r - kretprobe
-and j - jprobe), while the third column specifies the symbol+offset of
-the probe. If the probed function belongs to a module, the module name
-is also specified. Following columns show probe status. If the probe is on
+The second column identifies the type of probe (k - kprobe and r - kretprobe)
+while the third column specifies the symbol+offset of the probe.
+If the probed function belongs to a module, the module name is also
+specified. Following columns show probe status. If the probe is on
 a virtual address that is no longer valid (module init sections, module
 virtual addresses that correspond to modules that've been unloaded),
 such probes are marked with [GONE]. If the probe is temporarily disabled,
index 19276f5d195cb75f5cef6a4a554f17e972c5cd55..1c707fc9b1419548297a0fb867e2fe589e37b594 100644 (file)
@@ -184,7 +184,7 @@ is done when dirty_ratio is reached.
 DO_CPU:
 
 Enable CPU frequency scaling when in laptop mode. (Requires CPUFreq to be setup.
-See Documentation/cpu-freq/user-guide.txt for more info. Disabled by default.)
+See Documentation/admin-guide/pm/cpufreq.rst for more info. Disabled by default.)
 
 CPU_MAXFREQ:
 
@@ -287,7 +287,7 @@ MINIMUM_BATTERY_MINUTES=10
 
 # Should the maximum CPU frequency be adjusted down while on battery?
 # Requires CPUFreq to be setup.
-# See Documentation/cpu-freq/user-guide.txt for more info
+# 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
@@ -378,7 +378,7 @@ BATT_HD=${BATT_HD:-'4'}
 DIRTY_RATIO=${DIRTY_RATIO:-'40'}
 
 # cpu frequency scaling
-# See Documentation/cpu-freq/user-guide.txt for more info
+# See Documentation/admin-guide/pm/cpufreq.rst for more info
 DO_CPU=${CPU_MANAGE:-'0'}
 CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}
 
index 6c6e8c2410de390dafa0319d694a6df42000ed6b..3d7b865539cc51cd81b639cef5dda696a344ed03 100644 (file)
@@ -8,7 +8,7 @@ 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/rt-mutex.txt.  Although this document does explain problems
+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.
 
index b43958b7340c7303f9ad81a27f7cdfc34ce31032..e3e387bdf498d1860e5dfb11f568759327c08f25 100644 (file)
@@ -18,7 +18,7 @@ General information
 
 This class of cards has a bt878a as the PCI interface, and require the bttv driver
 for accessing the i2c bus and the gpio pins of the bt8xx chipset.
-Please see Documentation/dvb/cards.txt => o Cards based on the Conexant Bt8xx PCI bridge:
+Please see Documentation/media/dvb-drivers/cards.rst => o Cards based on the Conexant Bt8xx PCI bridge:
 
 Compiling kernel please enable:
 
@@ -45,7 +45,7 @@ Loading Modules
 Regular case: If the bttv driver detects a bt8xx-based DVB card, all frontend and backend modules will be loaded automatically.
 Exceptions are:
 - Old TwinHan DST cards or clones with or without CA slot and not containing an Eeprom.
-People running udev please see Documentation/dvb/udev.txt.
+People running udev please see Documentation/media/dvb-drivers/udev.rst.
 
 In the following cases overriding the PCI type detection for dvb-bt8xx might be necessary:
 
@@ -72,7 +72,7 @@ Useful parameters for verbosity level and debugging the dst module:
 The autodetected values are determined by the cards' "response string".
 In your logs see f. ex.: dst_get_device_id: Recognize [DSTMCI].
 For bug reports please send in a complete log with verbose=4 activated.
-Please also see Documentation/dvb/ci.txt.
+Please also see Documentation/media/dvb-drivers/ci.rst.
 
 Running multiple cards
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -100,7 +100,7 @@ Examples of card ID's:
 
        $ modprobe bttv card=113 card=135
 
-For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
+For a full list of card ID's please see Documentation/media/v4l-drivers/bttv-cardlist.rst.
 In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org.
 
 Probing the cards with broken PCI subsystem ID
index 9d6c860271cb58c443f3d46b2c48997fa45f8c85..d311a6866b3b0d4092a16a6994aea254add1e8f4 100644 (file)
@@ -431,7 +431,7 @@ MPEG stream.
 *Historical context*: This format specification originates from a
 custom, embedded, sliced VBI data format used by the ``ivtv`` driver.
 This format has already been informally specified in the kernel sources
-in the file ``Documentation/video4linux/cx2341x/README.vbi`` . The
+in the file ``Documentation/media/v4l-drivers/cx2341x.rst`` . The
 maximum size of the payload and other aspects of this format are driven
 by the CX23415 MPEG decoder's capabilities and limitations with respect
 to extracting, decoding, and displaying sliced VBI data embedded within
index a3e81c1d276b2e73150d929b41a37a356e143244..dfe49ae57e7885144ea20b18642305cc622ce6ea 100644 (file)
@@ -284,7 +284,7 @@ enum v4l2_mpeg_stream_vbi_fmt -
     * - ``V4L2_MPEG_STREAM_VBI_FMT_IVTV``
       - VBI in private packets, IVTV format (documented in the kernel
        sources in the file
-       ``Documentation/video4linux/cx2341x/README.vbi``)
+       ``Documentation/media/v4l-drivers/cx2341x.rst``)
 
 
 
index 521adb795535972d87da61bfb4f4385c3b72c303..38af1472a4b452aa4042b8c79709ddaa1e9228db 100644 (file)
@@ -52,7 +52,7 @@ please make a proposal on the linux-media mailing list.
        `http://www.ivtvdriver.org/ <http://www.ivtvdriver.org/>`__
 
        The format is documented in the kernel sources in the file
-       ``Documentation/video4linux/cx2341x/README.hm12``
+       ``Documentation/media/v4l-drivers/cx2341x.rst``
     * .. _V4L2-PIX-FMT-CPIA1:
 
       - ``V4L2_PIX_FMT_CPIA1``
index 195ccaac281615ff850a57bd964b7603ef3bed81..5f35e2fb5afa1cf6abc726cb7997e203e54a837f 100644 (file)
@@ -307,7 +307,7 @@ console and let some terminal application log the messages.  /me uses
 screen.  See Documentation/admin-guide/serial-console.rst for details on setting
 up a serial console.
 
-Read Documentation/admin-guide/oops-tracing.rst to learn how to get any useful
+Read Documentation/admin-guide/bug-hunting.rst to learn how to get any useful
 information out of a register+stack dump printed by the kernel on
 protection faults (so-called "kernel oops").
 
index 04478c25d57ac3d8b8bd78f5bc93d40759ebdf46..b1a4c89fd869eb688418d938c024c2bae88d4063 100644 (file)
@@ -7,7 +7,7 @@ The MAX2175 driver implements the following driver-specific controls:
 -------------------------------
     Enable/Disable I2S output of the tuner. This is a private control
     that can be accessed only using the subdev interface.
-    Refer to Documentation/media/kapi/v4l2-controls for more details.
+    Refer to Documentation/media/kapi/v4l2-controls.rst for more details.
 
 .. flat-table::
     :header-rows:  0
index b759a60624fd3d195981cf4e7d4cd9acc60f3c0d..479ecec8059347ef5637ea0b5414e6c878f336d8 100644 (file)
@@ -53,7 +53,7 @@ CONTENTS
      - SMP barrier pairing.
      - Examples of memory barrier sequences.
      - Read memory barriers vs load speculation.
-     - Transitivity
+     - Multicopy atomicity.
 
  (*) Explicit kernel barriers.
 
@@ -383,8 +383,8 @@ Memory barriers come in four basic varieties:
      to have any effect on loads.
 
      A CPU can be viewed as committing a sequence of store operations to the
-     memory system as time progresses.  All stores before a write barrier will
-     occur in the sequence _before_ all the stores after the write barrier.
+     memory system as time progresses.  All stores _before_ a write barrier
+     will occur _before_ all the stores after the write barrier.
 
      [!] Note that write barriers should normally be paired with read or data
      dependency barriers; see the "SMP barrier pairing" subsection.
@@ -635,6 +635,11 @@ can be used to record rare error conditions and the like, and the CPUs'
 naturally occurring ordering prevents such records from being lost.
 
 
+Note well that the ordering provided by a data dependency is local to
+the CPU containing it.  See the section on "Multicopy atomicity" for
+more information.
+
+
 The data dependency barrier is very important to the RCU system,
 for example.  See rcu_assign_pointer() and rcu_dereference() in
 include/linux/rcupdate.h.  This permits the current target of an RCU'd
@@ -851,38 +856,11 @@ In short, control dependencies apply only to the stores in the then-clause
 and else-clause of the if-statement in question (including functions
 invoked by those two clauses), not to code following that if-statement.
 
-Finally, control dependencies do -not- provide transitivity.  This is
-demonstrated by two related examples, with the initial values of
-'x' and 'y' both being zero:
-
-       CPU 0                     CPU 1
-       =======================   =======================
-       r1 = READ_ONCE(x);        r2 = READ_ONCE(y);
-       if (r1 > 0)               if (r2 > 0)
-         WRITE_ONCE(y, 1);         WRITE_ONCE(x, 1);
-
-       assert(!(r1 == 1 && r2 == 1));
-
-The above two-CPU example will never trigger the assert().  However,
-if control dependencies guaranteed transitivity (which they do not),
-then adding the following CPU would guarantee a related assertion:
 
-       CPU 2
-       =====================
-       WRITE_ONCE(x, 2);
+Note well that the ordering provided by a control dependency is local
+to the CPU containing it.  See the section on "Multicopy atomicity"
+for more information.
 
-       assert(!(r1 == 2 && r2 == 1 && x == 2)); /* FAILS!!! */
-
-But because control dependencies do -not- provide transitivity, the above
-assertion can fail after the combined three-CPU example completes.  If you
-need the three-CPU example to provide ordering, you will need smp_mb()
-between the loads and stores in the CPU 0 and CPU 1 code fragments,
-that is, just before or just after the "if" statements.  Furthermore,
-the original two-CPU example is very fragile and should be avoided.
-
-These two examples are the LB and WWC litmus tests from this paper:
-http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf and this
-site: https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html.
 
 In summary:
 
@@ -922,8 +900,8 @@ In summary:
 
   (*) Control dependencies pair normally with other types of barriers.
 
-  (*) Control dependencies do -not- provide transitivity.  If you
-      need transitivity, use smp_mb().
+  (*) Control dependencies do -not- provide multicopy atomicity.  If you
+      need all the CPUs to see a given store at the same time, use smp_mb().
 
   (*) Compilers do not understand control dependencies.  It is therefore
       your job to ensure that they do not break your code.
@@ -936,13 +914,14 @@ When dealing with CPU-CPU interactions, certain types of memory barrier should
 always be paired.  A lack of appropriate pairing is almost certainly an error.
 
 General barriers pair with each other, though they also pair with most
-other types of barriers, albeit without transitivity.  An acquire barrier
-pairs with a release barrier, but both may also pair with other barriers,
-including of course general barriers.  A write barrier pairs with a data
-dependency barrier, a control dependency, an acquire barrier, a release
-barrier, a read barrier, or a general barrier.  Similarly a read barrier,
-control dependency, or a data dependency barrier pairs with a write
-barrier, an acquire barrier, a release barrier, or a general barrier:
+other types of barriers, albeit without multicopy atomicity.  An acquire
+barrier pairs with a release barrier, but both may also pair with other
+barriers, including of course general barriers.  A write barrier pairs
+with a data dependency barrier, a control dependency, an acquire barrier,
+a release barrier, a read barrier, or a general barrier.  Similarly a
+read barrier, control dependency, or a data dependency barrier pairs
+with a write barrier, an acquire barrier, a release barrier, or a
+general barrier:
 
        CPU 1                 CPU 2
        ===============       ===============
@@ -968,7 +947,7 @@ Or even:
        ===============       ===============================
        r1 = READ_ONCE(y);
        <general barrier>
-       WRITE_ONCE(y, 1);     if (r2 = READ_ONCE(x)) {
+       WRITE_ONCE(x, 1);     if (r2 = READ_ONCE(x)) {
                                 <implicit control dependency>
                                 WRITE_ONCE(y, 1);
                              }
@@ -1359,64 +1338,79 @@ the speculation will be cancelled and the value reloaded:
        retrieved                               :       :       +-------+
 
 
-TRANSITIVITY
-------------
+MULTICOPY ATOMICITY
+--------------------
 
-Transitivity is a deeply intuitive notion about ordering that is not
-always provided by real computer systems.  The following example
-demonstrates transitivity:
+Multicopy atomicity is a deeply intuitive notion about ordering that is
+not always provided by real computer systems, namely that a given store
+becomes visible at the same time to all CPUs, or, alternatively, that all
+CPUs agree on the order in which all stores become visible.  However,
+support of full multicopy atomicity would rule out valuable hardware
+optimizations, so a weaker form called ``other multicopy atomicity''
+instead guarantees only that a given store becomes visible at the same
+time to all -other- CPUs.  The remainder of this document discusses this
+weaker form, but for brevity will call it simply ``multicopy atomicity''.
+
+The following example demonstrates multicopy atomicity:
 
        CPU 1                   CPU 2                   CPU 3
        ======================= ======================= =======================
                { X = 0, Y = 0 }
-       STORE X=1               LOAD X                  STORE Y=1
-                               <general barrier>       <general barrier>
-                               LOAD Y                  LOAD X
-
-Suppose that CPU 2's load from X returns 1 and its load from Y returns 0.
-This indicates that CPU 2's load from X in some sense follows CPU 1's
-store to X and that CPU 2's load from Y in some sense preceded CPU 3's
-store to Y.  The question is then "Can CPU 3's load from X return 0?"
-
-Because CPU 2's load from X in some sense came after CPU 1's store, it
+       STORE X=1               r1=LOAD X (reads 1)     LOAD Y (reads 1)
+                               <general barrier>       <read barrier>
+                               STORE Y=r1              LOAD X
+
+Suppose that CPU 2's load from X returns 1, which it then stores to Y,
+and CPU 3's load from Y returns 1.  This indicates that CPU 1's store
+to X precedes CPU 2's load from X and that CPU 2's store to Y precedes
+CPU 3's load from Y.  In addition, the memory barriers guarantee that
+CPU 2 executes its load before its store, and CPU 3 loads from Y before
+it loads from X.  The question is then "Can CPU 3's load from X return 0?"
+
+Because CPU 3's load from X in some sense comes after CPU 2's load, it
 is natural to expect that CPU 3's load from X must therefore return 1.
-This expectation is an example of transitivity: if a load executing on
-CPU A follows a load from the same variable executing on CPU B, then
-CPU A's load must either return the same value that CPU B's load did,
-or must return some later value.
-
-In the Linux kernel, use of general memory barriers guarantees
-transitivity.  Therefore, in the above example, if CPU 2's load from X
-returns 1 and its load from Y returns 0, then CPU 3's load from X must
-also return 1.
-
-However, transitivity is -not- guaranteed for read or write barriers.
-For example, suppose that CPU 2's general barrier in the above example
-is changed to a read barrier as shown below:
+This expectation follows from multicopy atomicity: if a load executing
+on CPU B follows a load from the same variable executing on CPU A (and
+CPU A did not originally store the value which it read), then on
+multicopy-atomic systems, CPU B's load must return either the same value
+that CPU A's load did or some later value.  However, the Linux kernel
+does not require systems to be multicopy atomic.
+
+The use of a general memory barrier in the example above compensates
+for any lack of multicopy atomicity.  In the example, if CPU 2's load
+from X returns 1 and CPU 3's load from Y returns 1, then CPU 3's load
+from X must indeed also return 1.
+
+However, dependencies, read barriers, and write barriers are not always
+able to compensate for non-multicopy atomicity.  For example, suppose
+that CPU 2's general barrier is removed from the above example, leaving
+only the data dependency shown below:
 
        CPU 1                   CPU 2                   CPU 3
        ======================= ======================= =======================
                { X = 0, Y = 0 }
-       STORE X=1               LOAD X                  STORE Y=1
-                               <read barrier>          <general barrier>
-                               LOAD Y                  LOAD X
-
-This substitution destroys transitivity: in this example, it is perfectly
-legal for CPU 2's load from X to return 1, its load from Y to return 0,
-and CPU 3's load from X to return 0.
-
-The key point is that although CPU 2's read barrier orders its pair
-of loads, it does not guarantee to order CPU 1's store.  Therefore, if
-this example runs on a system where CPUs 1 and 2 share a store buffer
-or a level of cache, CPU 2 might have early access to CPU 1's writes.
-General barriers are therefore required to ensure that all CPUs agree
-on the combined order of CPU 1's and CPU 2's accesses.
-
-General barriers provide "global transitivity", so that all CPUs will
-agree on the order of operations.  In contrast, a chain of release-acquire
-pairs provides only "local transitivity", so that only those CPUs on
-the chain are guaranteed to agree on the combined order of the accesses.
-For example, switching to C code in deference to Herman Hollerith:
+       STORE X=1               r1=LOAD X (reads 1)     LOAD Y (reads 1)
+                               <data dependency>       <read barrier>
+                               STORE Y=r1              LOAD X (reads 0)
+
+This substitution allows non-multicopy atomicity to run rampant: in
+this example, it is perfectly legal for CPU 2's load from X to return 1,
+CPU 3's load from Y to return 1, and its load from X to return 0.
+
+The key point is that although CPU 2's data dependency orders its load
+and store, it does not guarantee to order CPU 1's store.  Thus, if this
+example runs on a non-multicopy-atomic system where CPUs 1 and 2 share a
+store buffer or a level of cache, CPU 2 might have early access to CPU 1's
+writes.  General barriers are therefore required to ensure that all CPUs
+agree on the combined order of multiple accesses.
+
+General barriers can compensate not only for non-multicopy atomicity,
+but can also generate additional ordering that can ensure that -all-
+CPUs will perceive the same order of -all- operations.  In contrast, a
+chain of release-acquire pairs do not provide this additional ordering,
+which means that only those CPUs on the chain are guaranteed to agree
+on the combined order of the accesses.  For example, switching to C code
+in deference to the ghost of Herman Hollerith:
 
        int u, v, x, y, z;
 
@@ -1448,9 +1442,9 @@ For example, switching to C code in deference to Herman Hollerith:
                r3 = READ_ONCE(u);
        }
 
-Because cpu0(), cpu1(), and cpu2() participate in a local transitive
-chain of smp_store_release()/smp_load_acquire() pairs, the following
-outcome is prohibited:
+Because cpu0(), cpu1(), and cpu2() participate in a chain of
+smp_store_release()/smp_load_acquire() pairs, the following outcome
+is prohibited:
 
        r0 == 1 && r1 == 1 && r2 == 1
 
@@ -1460,9 +1454,9 @@ outcome is prohibited:
 
        r1 == 1 && r5 == 0
 
-However, the transitivity of release-acquire is local to the participating
-CPUs and does not apply to cpu3().  Therefore, the following outcome
-is possible:
+However, the ordering provided by a release-acquire chain is local
+to the CPUs participating in that chain and does not apply to cpu3(),
+at least aside from stores.  Therefore, the following outcome is possible:
 
        r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0
 
@@ -1490,8 +1484,8 @@ following outcome is possible:
 Note that this outcome can happen even on a mythical sequentially
 consistent system where nothing is ever reordered.
 
-To reiterate, if your code requires global transitivity, use general
-barriers throughout.
+To reiterate, if your code requires full ordering of all operations,
+use general barriers throughout.
 
 
 ========================
@@ -1886,18 +1880,6 @@ There are some more advanced barrier functions:
      See Documentation/atomic_{t,bitops}.txt for more information.
 
 
- (*) lockless_dereference();
-
-     This can be thought of as a pointer-fetch wrapper around the
-     smp_read_barrier_depends() data-dependency barrier.
-
-     This is also similar to rcu_dereference(), but in cases where
-     object lifetime is handled by some mechanism other than RCU, for
-     example, when the objects removed only when the system goes down.
-     In addition, lockless_dereference() is used in some data structures
-     that can be used both with and without RCU.
-
-
  (*) dma_wmb();
  (*) dma_rmb();
 
@@ -3101,6 +3083,9 @@ AMD64 Architecture Programmer's Manual Volume 2: System Programming
        Chapter 7.1: Memory-Access Ordering
        Chapter 7.4: Buffering and Combining Memory Writes
 
+ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
+       Chapter B2: The AArch64 Application Level Memory Model
+
 IA-32 Intel Architecture Software Developer's Manual, Volume 3:
 System Programming Guide
        Chapter 7.1: Locked Atomic Operations
@@ -3112,6 +3097,8 @@ The SPARC Architecture Manual, Version 9
        Appendix D: Formal Specification of the Memory Models
        Appendix J: Programming with the Memory Models
 
+Storage in the PowerPC (Stone and Fitzgerald)
+
 UltraSPARC Programmer Reference Manual
        Chapter 5: Memory Accesses and Cacheability
        Chapter 15: Sparc-V9 Memory Models
index e4c376abbdad9441f264e4d65bea69168282c861..4e68f0bc5dba13e991be2802764d617be6281c60 100644 (file)
@@ -332,8 +332,8 @@ References
 [5] "MBIM (Mobile Broadband Interface Model) Registry"
        - http://compliance.usb.org/mbim/
 
-[6] "/dev/bus/usb filesystem output"
-       - Documentation/usb/proc_usb_info.txt
+[6] "/sys/kernel/debug/usb/devices output format"
+       - Documentation/driver-api/usb/usb.rst
 
 [7] "/sys/bus/usb/devices/.../descriptors"
        - Documentation/ABI/stable/sysfs-bus-usb
index d52d191bbb0c4c7a4ba5de9a5c6fad6683c6ac12..27bc09cfcf6d8df3fd2eb9dff1de6e471a53c327 100644 (file)
@@ -47,7 +47,7 @@ The requirements for GSO are more complicated, because when segmenting an
  (section 'E') for more details.
 
 A driver declares its offload capabilities in netdev->hw_features; see
- Documentation/networking/netdev-features for more.  Note that a device
+ Documentation/networking/netdev-features.txt for more.  Note that a device
  which only advertises NETIF_F_IP[V6]_CSUM must still obey the csum_start
  and csum_offset given in the SKB; if it tries to deduce these itself in
  hardware (as some NICs do) the driver should check that the values in the
index f3b9e507ab05b26eb6517ac2f43992863a606ba1..bf654845556e19d0d09ad113d997ac48aa67ccaa 100644 (file)
@@ -1055,7 +1055,7 @@ TX_RING part only TP_STATUS_AVAILABLE is set, then the tp_sec and tp_{n,u}sec
 members do not contain a valid value. For TX_RINGs, by default no timestamp
 is generated!
 
-See include/linux/net_tstamp.h and Documentation/networking/timestamping
+See include/linux/net_tstamp.h and Documentation/networking/timestamping.txt
 for more information on hardware timestamps.
 
 -------------------------------------------------------------------------------
similarity index 56%
rename from arch/openrisc/README.openrisc
rename to Documentation/openrisc/README
index 072069ab51003bd8091c16c75fa0dd4755fb4d01..777a893d533d14cb161987085ab471645f2b4c24 100644 (file)
@@ -7,13 +7,7 @@ target architecture, specifically, is the 32-bit OpenRISC 1000 family (or1k).
 For information about OpenRISC processors and ongoing development:
 
        website         http://openrisc.io
-
-For more information about Linux on OpenRISC, please contact South Pole AB.
-
-       email:          info@southpole.se
-
-       website:        http://southpole.se
-                       http://southpoleconsulting.com
+       email           openrisc@lists.librecores.org
 
 ---------------------------------------------------------------------
 
@@ -24,37 +18,54 @@ In order to build and run Linux for OpenRISC, you'll need at least a basic
 toolchain and, perhaps, the architectural simulator.  Steps to get these bits
 in place are outlined here.
 
-1)  The toolchain can be obtained from openrisc.io.  Instructions for building
-a toolchain can be found at:
+1) Toolchain
+
+Toolchain binaries can be obtained from openrisc.io or our github releases page.
+Instructions for building the different toolchains can be found on openrisc.io
+or Stafford's toolchain build and release scripts.
+
+       binaries        https://github.com/openrisc/or1k-gcc/releases
+       toolchains      https://openrisc.io/software
+       building        https://github.com/stffrdhrn/or1k-toolchain-build
 
-https://github.com/openrisc/tutorials
+2) Building
 
-2) or1ksim (optional)
+Build the Linux kernel as usual
 
-or1ksim is the architectural simulator which will allow you to actually run
-your OpenRISC Linux kernel if you don't have an OpenRISC processor at hand.
+       make ARCH=openrisc defconfig
+       make ARCH=openrisc
 
-       git clone https://github.com/openrisc/or1ksim.git
+3) Running on FPGA (optional)
 
-       cd or1ksim
-       ./configure --prefix=$OPENRISC_PREFIX
-       make
-       make install
+The OpenRISC community typically uses FuseSoC to manage building and programming
+an SoC into an FPGA.  The below is an example of programming a De0 Nano
+development board with the OpenRISC SoC.  During the build FPGA RTL is code
+downloaded from the FuseSoC IP cores repository and built using the FPGA vendor
+tools.  Binaries are loaded onto the board with openocd.
 
-3)  Linux kernel
+       git clone https://github.com/olofk/fusesoc
+       cd fusesoc
+       sudo pip install -e .
 
-Build the kernel as usual
+       fusesoc init
+       fusesoc build de0_nano
+       fusesoc pgm de0_nano
 
-       make ARCH=openrisc defconfig
-       make ARCH=openrisc
+       openocd -f interface/altera-usb-blaster.cfg \
+               -f board/or1k_generic.cfg
+
+       telnet localhost 4444
+       > init
+       > halt; load_image vmlinux ; reset
 
-4)  Run in architectural simulator
+4) Running on a Simulator (optional)
 
-Grab the or1ksim platform configuration file (from the or1ksim source) and
-together with your freshly built vmlinux, run your kernel with the following
-incantation:
+QEMU is a processor emulator which we recommend for simulating the OpenRISC
+platform.  Please follow the OpenRISC instructions on the QEMU website to get
+Linux running on QEMU.  You can build QEMU yourself, but your Linux distribution
+likely provides binary packages to support OpenRISC.
 
-       sim -f arch/openrisc/or1ksim.cfg vmlinux
+       qemu openrisc   https://wiki.qemu.org/Documentation/Platforms/OpenRISC
 
 ---------------------------------------------------------------------
 
index aafddbee7377496593e9b4066bc20f5ef845dcbd..b154f6c0c36e44b28c90732eea098abbe04fe841 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/rt-mutex.txt.
+Documentation/locking/rt-mutex.txt.
index 974916ff6608e7b55f390d69e64a8fbe7396a9e9..27df7f98668a32013632feda7f4b377a0941471b 100644 (file)
@@ -24,7 +24,8 @@ platform.
 
 If one of the strings listed in /sys/power/state is written to it, the system
 will attempt to transition into the corresponding sleep state.  Refer to
-Documentation/power/states.txt for a description of each of those states.
+Documentation/admin-guide/pm/sleep-states.rst for a description of each of
+those states.
 
 /sys/power/disk controls the operating mode of hibernation (Suspend-to-Disk).
 Specifically, it tells the kernel what to do after creating a hibernation image.
@@ -42,7 +43,7 @@ The currently selected option is printed in square brackets.
 The 'platform' option is only available if the platform provides a special
 mechanism to put the system to sleep after creating a hibernation image (ACPI
 does that, for example).  The 'suspend' option is available if Suspend-to-RAM
-is supported.  Refer to Documentation/power/basic_pm_debugging.txt for the
+is supported.  Refer to Documentation/power/basic-pm-debugging.txt for the
 description of the 'test_resume' option.
 
 To select an option, write the string representing it to /sys/power/disk.
index a1b7f715893050bc16a94b8ae63b50b9c51d3479..704cd36079b8081a7b06ce1f7ca5761d31e0ef3c 100644 (file)
@@ -8,7 +8,7 @@ management.  Based on previous work by Patrick Mochel <mochel@transmeta.com>
 
 This document only covers the aspects of power management specific to PCI
 devices.  For general description of the kernel's interfaces related to device
-power management refer to Documentation/power/admin-guide/devices.rst and
+power management refer to Documentation/driver-api/pm/devices.rst and
 Documentation/power/runtime_pm.txt.
 
 ---------------------------------------------------------------------------
@@ -417,7 +417,7 @@ pm->runtime_idle() callback.
 2.4. System-Wide Power Transitions
 ----------------------------------
 There are a few different types of system-wide power transitions, described in
-Documentation/power/admin-guide/devices.rst.  Each of them requires devices to be handled
+Documentation/driver-api/pm/devices.rst.  Each of them requires devices to be handled
 in a specific way and the PM core executes subsystem-level power management
 callbacks for this purpose.  They are executed in phases such that each phase
 involves executing the same subsystem-level callback for every device belonging
@@ -623,7 +623,7 @@ System restore requires a hibernation image to be loaded into memory and the
 pre-hibernation memory contents to be restored before the pre-hibernation system
 activity can be resumed.
 
-As described in Documentation/power/admin-guide/devices.rst, the hibernation image is loaded
+As described in Documentation/driver-api/pm/devices.rst, the hibernation image is loaded
 into memory by a fresh instance of the kernel, called the boot kernel, which in
 turn is loaded and run by a boot loader in the usual way.  After the boot kernel
 has loaded the image, it needs to replace its own code and data with the code
@@ -677,7 +677,7 @@ controlling the runtime power management of their devices.
 
 At the time of this writing there are two ways to define power management
 callbacks for a PCI device driver, the recommended one, based on using a
-dev_pm_ops structure described in Documentation/power/admin-guide/devices.rst, and the
+dev_pm_ops structure described in Documentation/driver-api/pm/devices.rst, and the
 "legacy" one, in which the .suspend(), .suspend_late(), .resume_early(), and
 .resume() callbacks from struct pci_driver are used.  The legacy approach,
 however, doesn't allow one to define runtime power management callbacks and is
@@ -961,6 +961,39 @@ dev_pm_ops to indicate that one suspend routine is to be pointed to by the
 .suspend(), .freeze(), and .poweroff() members and one resume routine is to
 be pointed to by the .resume(), .thaw(), and .restore() members.
 
+3.1.19. Driver Flags for Power Management
+
+The PM core allows device drivers to set flags that influence the handling of
+power management for the devices by the core itself and by middle layer code
+including the PCI bus type.  The flags should be set once at the driver probe
+time with the help of the dev_pm_set_driver_flags() function and they should not
+be updated directly afterwards.
+
+The DPM_FLAG_NEVER_SKIP flag prevents the PM core from using the direct-complete
+mechanism allowing device suspend/resume callbacks to be skipped if the device
+is in runtime suspend when the system suspend starts.  That also affects all of
+the ancestors of the device, so this flag should only be used if absolutely
+necessary.
+
+The DPM_FLAG_SMART_PREPARE flag instructs the PCI bus type to only return a
+positive value from pci_pm_prepare() if the ->prepare callback provided by the
+driver of the device returns a positive value.  That allows the driver to opt
+out from using the direct-complete mechanism dynamically.
+
+The DPM_FLAG_SMART_SUSPEND flag tells the PCI bus type that from the driver's
+perspective the device can be safely left in runtime suspend during system
+suspend.  That causes pci_pm_suspend(), pci_pm_freeze() and pci_pm_poweroff()
+to skip resuming the device from runtime suspend unless there are PCI-specific
+reasons for doing that.  Also, it causes pci_pm_suspend_late/noirq(),
+pci_pm_freeze_late/noirq() and pci_pm_poweroff_late/noirq() to return early
+if the device remains in runtime suspend in the beginning of the "late" phase
+of the system-wide transition under way.  Moreover, if the device is in
+runtime suspend in pci_pm_resume_noirq() or pci_pm_restore_noirq(), its runtime
+power management status will be changed to "active" (as it is going to be put
+into D0 going forward), but if it is in runtime suspend in pci_pm_thaw_noirq(),
+the function will set the power.direct_complete flag for it (to make the PM core
+skip the subsequent "thaw" callbacks for it) and return.
+
 3.2. Device Runtime Power Management
 ------------------------------------
 In addition to providing device power management callbacks PCI device drivers
@@ -1046,5 +1079,5 @@ PCI Local Bus Specification, Rev. 3.0
 PCI Bus Power Management Interface Specification, Rev. 1.2
 Advanced Configuration and Power Interface (ACPI) Specification, Rev. 3.0b
 PCI Express Base Specification, Rev. 2.0
-Documentation/power/admin-guide/devices.rst
+Documentation/driver-api/pm/devices.rst
 Documentation/power/runtime_pm.txt
index 21d2d48f87a254a2c4281bae68646f29c393fb14..19c5f7b1a7babed3e55a5918097c36243a707f86 100644 (file)
@@ -98,8 +98,7 @@ Values are updated in response to changes of the request list.
 The target values of resume latency and active state latency tolerance are
 simply the minimum of the request values held in the parameter list elements.
 The PM QoS flags aggregate value is a gather (bitwise OR) of all list elements'
-values.  Two device PM QoS flags are defined currently: PM_QOS_FLAG_NO_POWER_OFF
-and PM_QOS_FLAG_REMOTE_WAKEUP.
+values.  One device PM QoS flag is defined currently: PM_QOS_FLAG_NO_POWER_OFF.
 
 Note: The aggregated target values are implemented in such a way that reading
 the aggregated value does not require any locking mechanism.
@@ -153,14 +152,14 @@ PM QoS list of resume latency constraints and remove sysfs attribute
 pm_qos_resume_latency_us from the device's power directory.
 
 int dev_pm_qos_expose_flags(device, value)
-Add a request to the device's PM QoS list of flags and create sysfs attributes
-pm_qos_no_power_off and pm_qos_remote_wakeup under the device's power directory
-allowing user space to change these flags' value.
+Add a request to the device's PM QoS list of flags and create sysfs attribute
+pm_qos_no_power_off under the device's power directory allowing user space to
+change the value of the PM_QOS_FLAG_NO_POWER_OFF flag.
 
 void dev_pm_qos_hide_flags(device)
 Drop the request added by dev_pm_qos_expose_flags() from the device's PM QoS list
-of flags and remove sysfs attributes pm_qos_no_power_off and pm_qos_remote_wakeup
-under the device's power directory.
+of flags and remove sysfs attribute pm_qos_no_power_off from the device's power
+directory.
 
 Notification mechanisms:
 The per-device PM QoS framework has a per-device notification tree.
index 625549d4c74a09642d72bce75387c15348406223..57af2f7963eea56edef636905f7cc6a007d221f9 100644 (file)
@@ -680,7 +680,7 @@ left in runtime suspend.  If that happens, the PM core will not execute any
 system suspend and resume callbacks for all of those devices, except for the
 complete callback, which is then entirely responsible for handling the device
 as appropriate.  This only applies to system suspend transitions that are not
-related to hibernation (see Documentation/power/admin-guide/devices.rst for more
+related to hibernation (see Documentation/driver-api/pm/devices.rst for more
 information).
 
 The PM core does its best to reduce the probability of race conditions between
index 2fc909502db59d2f795ab5e9db92b98714e32dcf..31abd04b957284f55697be1aa226e906c981196c 100644 (file)
@@ -232,7 +232,7 @@ d. Handling microcode update during suspend/hibernate:
    hibernate/restore cycle.]
 
    In the current design of the kernel however, during a CPU offline operation
-   as part of the suspend/hibernate cycle (the CPU_DEAD_FROZEN notification),
+   as part of the suspend/hibernate cycle (cpuhp_tasks_frozen is set),
    the existing copy of microcode image in the kernel is not freed up.
    And during the CPU online operations (during resume/restore), since the
    kernel finds that it already has copies of the microcode images for all the
@@ -252,10 +252,9 @@ Yes, they are listed below:
    the _cpu_down() and _cpu_up() functions is *always* 0.
    This might not reflect the true current state of the system, since the
    tasks could have been frozen by an out-of-band event such as a suspend
-   operation in progress. Hence, it will lead to wrong notifications being
-   sent during the cpu online/offline events (eg, CPU_ONLINE notification
-   instead of CPU_ONLINE_FROZEN) which in turn will lead to execution of
-   inappropriate code by the callbacks registered for such CPU hotplug events.
+   operation in progress. Hence, the cpuhp_tasks_frozen variable will not
+   reflect the frozen state and the CPU hotplug callbacks which evaluate
+   that variable might execute the wrong code path.
 
 2. If a regular CPU hotplug stress test happens to race with the freezer due
    to a suspend operation in progress at the same time, then we could hit the
index af2c0af931d613b69e7dedcb66de16702036badd..be00716071d4d1c88c637a08b2d52267963b5330 100644 (file)
@@ -178,7 +178,7 @@ matter is (1) kernel developers tend to be busy, (2) there is no shortage
 of people with grand plans and little code (or even prospect of code) to
 back them up, and (3) nobody is obligated to review or comment on ideas
 posted by others.  Beyond that, high-level designs often hide problems
-which are only reviewed when somebody actually tries to implement those
+which are only revealed when somebody actually tries to implement those
 designs; for that reason, kernel developers would rather see the code.
 
 If a request-for-comments posting yields little in the way of comments, do
index 6df19943dd4dc551db0d9a792cabd1e608504ec7..26b106071364c8d6462c2fad0dbddfd3958d96b9 100644 (file)
@@ -307,7 +307,7 @@ variety of potential coding problems; it can also propose fixes for those
 problems.  Quite a few "semantic patches" for the kernel have been packaged
 under the scripts/coccinelle directory; running "make coccicheck" will run
 through those semantic patches and report on any problems found.  See
-Documentation/coccinelle.txt for more information.
+Documentation/dev-tools/coccinelle.rst for more information.
 
 Other kinds of portability errors are best found by compiling your code for
 other architectures.  If you do not happen to have an S/390 system or a
index 61e43cc3ed171e2371b6372609533dc16fc9b057..a430f6eee7569570b8e81c5399c6a14dc3b4480c 100644 (file)
@@ -26,6 +26,7 @@ Below are the essential guides that every developer should read.
    coding-style
    email-clients
    kernel-enforcement-statement
+   kernel-driver-statement
 
 Other guides to the community that are of interest to most developers are: 
 
diff --git a/Documentation/process/kernel-driver-statement.rst b/Documentation/process/kernel-driver-statement.rst
new file mode 100644 (file)
index 0000000..60d9d86
--- /dev/null
@@ -0,0 +1,199 @@
+Kernel Driver Statement
+-----------------------
+
+Position Statement on Linux Kernel Modules
+==========================================
+
+
+We, the undersigned Linux kernel developers, consider any closed-source
+Linux kernel module or driver to be harmful and undesirable. We have
+repeatedly found them to be detrimental to Linux users, businesses, and
+the greater Linux ecosystem. Such modules negate the openness,
+stability, flexibility, and maintainability of the Linux development
+model and shut their users off from the expertise of the Linux
+community. Vendors that provide closed-source kernel modules force their
+customers to give up key Linux advantages or choose new vendors.
+Therefore, in order to take full advantage of the cost savings and
+shared support benefits open source has to offer, we urge vendors to
+adopt a policy of supporting their customers on Linux with open-source
+kernel code.
+
+We speak only for ourselves, and not for any company we might work for
+today, have in the past, or will in the future.
+
+ - Dave Airlie
+ - Nick Andrew
+ - Jens Axboe
+ - Ralf Baechle
+ - Felipe Balbi
+ - Ohad Ben-Cohen
+ - Muli Ben-Yehuda
+ - Jiri Benc
+ - Arnd Bergmann
+ - Thomas Bogendoerfer
+ - Vitaly Bordug
+ - James Bottomley
+ - Josh Boyer
+ - Neil Brown
+ - Mark Brown
+ - David Brownell
+ - Michael Buesch
+ - Franck Bui-Huu
+ - Adrian Bunk
+ - François Cami
+ - Ralph Campbell
+ - Luiz Fernando N. Capitulino
+ - Mauro Carvalho Chehab
+ - Denis Cheng
+ - Jonathan Corbet
+ - Glauber Costa
+ - Alan Cox
+ - Magnus Damm
+ - Ahmed S. Darwish
+ - Robert P. J. Day
+ - Hans de Goede
+ - Arnaldo Carvalho de Melo
+ - Helge Deller
+ - Jean Delvare
+ - Mathieu Desnoyers
+ - Sven-Thorsten Dietrich
+ - Alexey Dobriyan
+ - Daniel Drake
+ - Alex Dubov
+ - Randy Dunlap
+ - Michael Ellerman
+ - Pekka Enberg
+ - Jan Engelhardt
+ - Mark Fasheh
+ - J. Bruce Fields
+ - Larry Finger
+ - Jeremy Fitzhardinge
+ - Mike Frysinger
+ - Kumar Gala
+ - Robin Getz
+ - Liam Girdwood
+ - Jan-Benedict Glaw
+ - Thomas Gleixner
+ - Brice Goglin
+ - Cyrill Gorcunov
+ - Andy Gospodarek
+ - Thomas Graf
+ - Krzysztof Halasa
+ - Harvey Harrison
+ - Stephen Hemminger
+ - Michael Hennerich
+ - Tejun Heo
+ - Benjamin Herrenschmidt
+ - Kristian Høgsberg
+ - Henrique de Moraes Holschuh
+ - Marcel Holtmann
+ - Mike Isely
+ - Takashi Iwai
+ - Olof Johansson
+ - Dave Jones
+ - Jesper Juhl
+ - Matthias Kaehlcke
+ - Kenji Kaneshige
+ - Jan Kara
+ - Jeremy Kerr
+ - Russell King
+ - Olaf Kirch
+ - Roel Kluin
+ - Hans-Jürgen Koch
+ - Auke Kok
+ - Peter Korsgaard
+ - Jiri Kosina
+ - Mariusz Kozlowski
+ - Greg Kroah-Hartman
+ - Michael Krufky
+ - Aneesh Kumar
+ - Clemens Ladisch
+ - Christoph Lameter
+ - Gunnar Larisch
+ - Anders Larsen
+ - Grant Likely
+ - John W. Linville
+ - Yinghai Lu
+ - Tony Luck
+ - Pavel Machek
+ - Matt Mackall
+ - Paul Mackerras
+ - Roland McGrath
+ - Patrick McHardy
+ - Kyle McMartin
+ - Paul Menage
+ - Thierry Merle
+ - Eric Miao
+ - Akinobu Mita
+ - Ingo Molnar
+ - James Morris
+ - Andrew Morton
+ - Paul Mundt
+ - Oleg Nesterov
+ - Luca Olivetti
+ - S.Çağlar Onur
+ - Pierre Ossman
+ - Keith Owens
+ - Venkatesh Pallipadi
+ - Nick Piggin
+ - Nicolas Pitre
+ - Evgeniy Polyakov
+ - Richard Purdie
+ - Mike Rapoport
+ - Sam Ravnborg
+ - Gerrit Renker
+ - Stefan Richter
+ - David Rientjes
+ - Luis R. Rodriguez
+ - Stefan Roese
+ - Francois Romieu
+ - Rami Rosen
+ - Stephen Rothwell
+ - Maciej W. Rozycki
+ - Mark Salyzyn
+ - Yoshinori Sato
+ - Deepak Saxena
+ - Holger Schurig
+ - Amit Shah
+ - Yoshihiro Shimoda
+ - Sergei Shtylyov
+ - Kay Sievers
+ - Sebastian Siewior
+ - Rik Snel
+ - Jes Sorensen
+ - Alexey Starikovskiy
+ - Alan Stern
+ - Timur Tabi
+ - Hirokazu Takata
+ - Eliezer Tamir
+ - Eugene Teo
+ - Doug Thompson
+ - FUJITA Tomonori
+ - Dmitry Torokhov
+ - Marcelo Tosatti
+ - Steven Toth
+ - Theodore Tso
+ - Matthias Urlichs
+ - Geert Uytterhoeven
+ - Arjan van de Ven
+ - Ivo van Doorn
+ - Rik van Riel
+ - Wim Van Sebroeck
+ - Hans Verkuil
+ - Horst H. von Brand
+ - Dmitri Vorobiev
+ - Anton Vorontsov
+ - Daniel Walker
+ - Johannes Weiner
+ - Harald Welte
+ - Matthew Wilcox
+ - Dan J. Williams
+ - Darrick J. Wong
+ - David Woodhouse
+ - Chris Wright
+ - Bryan Wu
+ - Rafael J. Wysocki
+ - Herbert Xu
+ - Vlad Yasevich
+ - Peter Zijlstra
+ - Bartlomiej Zolnierkiewicz
index afb82ee0cbea21816d114876a2e1e84bb5563474..b38bf2054ce38cdf3b8d504a10f62492b1054481 100644 (file)
@@ -117,7 +117,7 @@ PM support:
                anything.  For the driver testing instructions see
                Documentation/power/drivers-testing.txt and for a relatively
                complete overview of the power management issues related to
-               drivers see Documentation/power/admin-guide/devices.rst .
+               drivers see Documentation/driver-api/pm/devices.rst.
 
 Control:
                In general if there is active maintenance of a driver by
index 733478ade91b50efd098bbfd3cd6831cfa99fcc9..1ef19d3a3eee86880777006ac06ea4f19f5e4bec 100644 (file)
@@ -621,14 +621,14 @@ The canonical patch subject line is::
 
 The canonical patch message body contains the following:
 
-  - A ``from`` line specifying the patch author (only needed if the person
-    sending the patch is not the author).
-
-  - An empty line.
+  - A ``from`` line specifying the patch author, followed by an empty
+    line (only needed if the person sending the patch is not the author).
 
   - The body of the explanation, line wrapped at 75 columns, which will
     be copied to the permanent changelog to describe this patch.
 
+  - An empty line.
+
   - The ``Signed-off-by:`` lines, described above, which will
     also go in the changelog.
 
index d75778b0fa1000bf37627c8541e02279c6c4dede..98522e0e1ee23278f8ffbe2aa4b6ad1a46e09f1e 100644 (file)
@@ -5,7 +5,7 @@ Linux Security Module Development
 Based on https://lkml.org/lkml/2007/10/26/215,
 a new LSM is accepted into the kernel when its intent (a description of
 what it tries to protect against and in what cases one would expect to
-use it) has been appropriately documented in ``Documentation/security/LSM``.
+use it) has been appropriately documented in ``Documentation/security/LSM.rst``.
 This allows an LSM's code to be easily compared to its goals, and so
 that end users and distros can make a more informed decision about which
 LSMs suit their requirements.
index 038a7e19eff9ae456fee18b4cdab224675ef0bb7..66a2e24939d808896f11874c358b10c1dd894c7b 100644 (file)
@@ -196,7 +196,7 @@ The Linux kernel supports the following types of credentials:
      When a process accesses a key, if not already present, it will normally be
      cached on one of these keyrings for future accesses to find.
 
-     For more information on using keys, see Documentation/security/keys.txt.
+     For more information on using keys, see ``Documentation/security/keys/*``.
 
  5. LSM
 
index b2d16abaa9e9c2a416658a4cde83fcb2bc73d8b8..21e27238cec6ffac58cd0242fe787d23f044848a 100644 (file)
@@ -3,7 +3,7 @@ Key Request Service
 ===================
 
 The key request service is part of the key retention service (refer to
-Documentation/security/core.rst).  This document explains more fully how
+Documentation/security/keys/core.rst).  This document explains more fully how
 the requesting algorithm works.
 
 The process starts by either the kernel requesting a service by calling
index a6e468c81d02f3da807940b4031b996a6c8e33a6..488946fc10797e202ab191e90fe6e01a747fe329 100644 (file)
@@ -11,7 +11,7 @@ General
 
 First of all, you need to enable GAMEPORT support on Linux kernel for
 using a joystick with the ALSA driver.  For the details of gameport
-support, refer to Documentation/input/joystick.txt.
+support, refer to Documentation/input/joydev/joystick.rst.
 
 The joystick support of ALSA drivers is different between ISA and PCI
 cards.  In the case of ISA (PnP) cards, it's usually handled by the
index f59c3cdbfaf4ccba37f62fca292507ef9b94ea2c..9f7347830ba4234bf618043e41869e7ebe231060 100644 (file)
@@ -192,7 +192,7 @@ preset model instead of PCI (and codec-) SSID look-up.
 What ``model`` option values are available depends on the codec chip.
 Check your codec chip from the codec proc file (see "Codec Proc-File"
 section below).  It will show the vendor/product name of your codec
-chip.  Then, see Documentation/sound/HD-Audio-Models.rst file,
+chip.  Then, see Documentation/sound/hd-audio/models.rst file,
 the section of HD-audio driver.  You can find a list of codecs
 and ``model`` options belonging to each codec.  For example, for Realtek
 ALC262 codec chip, pass ``model=ultra`` for devices that are compatible
index 58ffa3f5bda7873f5835e2f754c4e6f7fb6035be..a0b268466cb1db1653a005de4d46cb8ebe934389 100644 (file)
@@ -2498,7 +2498,7 @@ Mic boost
 Mic-boost switch is set as “Mic Boost” or “Mic Boost (6dB)”.
 
 More precise information can be found in
-``Documentation/sound/alsa/ControlNames.txt``.
+``Documentation/sound/designs/control-names.rst``.
 
 Access Flags
 ------------
index 91f54ffa00774c86f4528ce77e797067de632e6a..d5f24ab0ecc36bc4272d80389802f5f31e692802 100644 (file)
@@ -60,7 +60,7 @@ debug/                <empty>
 dev/           device specific information (eg dev/cdrom/info)
 fs/            specific filesystems
                filehandle, inode, dentry and quota tuning
-               binfmt_misc <Documentation/binfmt_misc.txt>
+               binfmt_misc <Documentation/admin-guide/binfmt-misc.rst>
 kernel/                global kernel info / tuning
                miscellaneous stuff
 net/           networking stuff, for documentation look in:
index 35e17f748ca78a927df127289ccd20689382aa73..6c00c1e2743fa2048882514d8644a908fff3a475 100644 (file)
@@ -277,7 +277,7 @@ in a mount namespace.
 ----------------------------------------------------------
 
 Documentation for the files in /proc/sys/fs/binfmt_misc is
-in Documentation/binfmt_misc.txt.
+in Documentation/admin-guide/binfmt-misc.rst.
 
 
 3. /proc/sys/fs/mqueue - POSIX message queues filesystem
index e8789976e77c30d1d5235d19cb1d613e52d71067..9d88f67781c28b90b5c6846b74446d492695ff55 100644 (file)
@@ -4,10 +4,10 @@ High resolution timers and dynamic ticks design notes
 Further information can be found in the paper of the OLS 2006 talk "hrtimers
 and beyond". The paper is part of the OLS 2006 Proceedings Volume 1, which can
 be found on the OLS website:
-http://www.linuxsymposium.org/2006/linuxsymposium_procv1.pdf
+https://www.kernel.org/doc/ols/2006/ols2006v1-pages-333-346.pdf
 
 The slides to this talk are available from:
-http://tglx.de/projects/hrtimers/ols2006-hrtimers.pdf
+http://www.cs.columbia.edu/~nahum/w6998/papers/ols2006-hrtimers-slides.pdf
 
 The slides contain five figures (pages 2, 15, 18, 20, 22), which illustrate the
 changes in the time(r) related Linux subsystems. Figure #1 (p. 2) shows the
diff --git a/Documentation/trace/ftrace-uses.rst b/Documentation/trace/ftrace-uses.rst
new file mode 100644 (file)
index 0000000..8494a80
--- /dev/null
@@ -0,0 +1,293 @@
+=================================
+Using ftrace to hook to functions
+=================================
+
+.. Copyright 2017 VMware Inc.
+..   Author:   Steven Rostedt <srostedt@goodmis.org>
+..  License:   The GNU Free Documentation License, Version 1.2
+..               (dual licensed under the GPL v2)
+
+Written for: 4.14
+
+Introduction
+============
+
+The ftrace infrastructure was originially created to attach callbacks to the
+beginning of functions in order to record and trace the flow of the kernel.
+But callbacks to the start of a function can have other use cases. Either
+for live kernel patching, or for security monitoring. This document describes
+how to use ftrace to implement your own function callbacks.
+
+
+The ftrace context
+==================
+
+WARNING: The ability to add a callback to almost any function within the
+kernel comes with risks. A callback can be called from any context
+(normal, softirq, irq, and NMI). Callbacks can also be called just before
+going to idle, during CPU bring up and takedown, or going to user space.
+This requires extra care to what can be done inside a callback. A callback
+can be called outside the protective scope of RCU.
+
+The ftrace infrastructure has some protections agains recursions and RCU
+but one must still be very careful how they use the callbacks.
+
+
+The ftrace_ops structure
+========================
+
+To register a function callback, a ftrace_ops is required. This structure
+is used to tell ftrace what function should be called as the callback
+as well as what protections the callback will perform and not require
+ftrace to handle.
+
+There is only one field that is needed to be set when registering
+an ftrace_ops with ftrace::
+
+.. code-block: c
+
+ struct ftrace_ops ops = {
+       .func                   = my_callback_func,
+       .flags                  = MY_FTRACE_FLAGS
+       .private                        = any_private_data_structure,
+ };
+
+Both .flags and .private are optional. Only .func is required.
+
+To enable tracing call::
+
+.. c:function::  register_ftrace_function(&ops);
+
+To disable tracing call::
+
+.. c:function::  unregister_ftrace_function(&ops);
+
+The above is defined by including the header::
+
+.. c:function:: #include <linux/ftrace.h>
+
+The registered callback will start being called some time after the
+register_ftrace_function() is called and before it returns. The exact time
+that callbacks start being called is dependent upon architecture and scheduling
+of services. The callback itself will have to handle any synchronization if it
+must begin at an exact moment.
+
+The unregister_ftrace_function() will guarantee that the callback is
+no longer being called by functions after the unregister_ftrace_function()
+returns. Note that to perform this guarantee, the unregister_ftrace_function()
+may take some time to finish.
+
+
+The callback function
+=====================
+
+The prototype of the callback function is as follows (as of v4.14)::
+
+.. code-block: c
+
+ void callback_func(unsigned long ip, unsigned long parent_ip,
+                   struct ftrace_ops *op, struct pt_regs *regs);
+
+@ip
+        This is the instruction pointer of the function that is being traced.
+        (where the fentry or mcount is within the function)
+
+@parent_ip
+       This is the instruction pointer of the function that called the
+       the function being traced (where the call of the function occurred).
+
+@op
+       This is a pointer to ftrace_ops that was used to register the callback.
+       This can be used to pass data to the callback via the private pointer.
+
+@regs
+       If the FTRACE_OPS_FL_SAVE_REGS or FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED
+       flags are set in the ftrace_ops structure, then this will be pointing
+       to the pt_regs structure like it would be if an breakpoint was placed
+       at the start of the function where ftrace was tracing. Otherwise it
+       either contains garbage, or NULL.
+
+
+The ftrace FLAGS
+================
+
+The ftrace_ops flags are all defined and documented in include/linux/ftrace.h.
+Some of the flags are used for internal infrastructure of ftrace, but the
+ones that users should be aware of are the following:
+
+FTRACE_OPS_FL_SAVE_REGS
+       If the callback requires reading or modifying the pt_regs
+       passed to the callback, then it must set this flag. Registering
+       a ftrace_ops with this flag set on an architecture that does not
+       support passing of pt_regs to the callback will fail.
+
+FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED
+       Similar to SAVE_REGS but the registering of a
+       ftrace_ops on an architecture that does not support passing of regs
+       will not fail with this flag set. But the callback must check if
+       regs is NULL or not to determine if the architecture supports it.
+
+FTRACE_OPS_FL_RECURSION_SAFE
+       By default, a wrapper is added around the callback to
+       make sure that recursion of the function does not occur. That is,
+       if a function that is called as a result of the callback's execution
+       is also traced, ftrace will prevent the callback from being called
+       again. But this wrapper adds some overhead, and if the callback is
+       safe from recursion, it can set this flag to disable the ftrace
+       protection.
+
+       Note, if this flag is set, and recursion does occur, it could cause
+       the system to crash, and possibly reboot via a triple fault.
+
+       It is OK if another callback traces a function that is called by a
+       callback that is marked recursion safe. Recursion safe callbacks
+       must never trace any function that are called by the callback
+       itself or any nested functions that those functions call.
+
+       If this flag is set, it is possible that the callback will also
+       be called with preemption enabled (when CONFIG_PREEMPT is set),
+       but this is not guaranteed.
+
+FTRACE_OPS_FL_IPMODIFY
+       Requires FTRACE_OPS_FL_SAVE_REGS set. If the callback is to "hijack"
+       the traced function (have another function called instead of the
+       traced function), it requires setting this flag. This is what live
+       kernel patches uses. Without this flag the pt_regs->ip can not be
+       modified.
+
+       Note, only one ftrace_ops with FTRACE_OPS_FL_IPMODIFY set may be
+       registered to any given function at a time.
+
+FTRACE_OPS_FL_RCU
+       If this is set, then the callback will only be called by functions
+       where RCU is "watching". This is required if the callback function
+       performs any rcu_read_lock() operation.
+
+       RCU stops watching when the system goes idle, the time when a CPU
+       is taken down and comes back online, and when entering from kernel
+       to user space and back to kernel space. During these transitions,
+       a callback may be executed and RCU synchronization will not protect
+       it.
+
+
+Filtering which functions to trace
+==================================
+
+If a callback is only to be called from specific functions, a filter must be
+set up. The filters are added by name, or ip if it is known.
+
+.. code-block: c
+
+ int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
+                      int len, int reset);
+
+@ops
+       The ops to set the filter with
+
+@buf
+       The string that holds the function filter text.
+@len
+       The length of the string.
+
+@reset
+       Non-zero to reset all filters before applying this filter.
+
+Filters denote which functions should be enabled when tracing is enabled.
+If @buf is NULL and reset is set, all functions will be enabled for tracing.
+
+The @buf can also be a glob expression to enable all functions that
+match a specific pattern.
+
+See Filter Commands in :file:`Documentation/trace/ftrace.txt`.
+
+To just trace the schedule function::
+
+.. code-block: c
+
+ ret = ftrace_set_filter(&ops, "schedule", strlen("schedule"), 0);
+
+To add more functions, call the ftrace_set_filter() more than once with the
+@reset parameter set to zero. To remove the current filter set and replace it
+with new functions defined by @buf, have @reset be non-zero.
+
+To remove all the filtered functions and trace all functions::
+
+.. code-block: c
+
+  ret = ftrace_set_filter(&ops, NULL, 0, 1);
+
+
+Sometimes more than one function has the same name. To trace just a specific
+function in this case, ftrace_set_filter_ip() can be used.
+
+.. code-block: c
+
+ ret = ftrace_set_filter_ip(&ops, ip, 0, 0);
+
+Although the ip must be the address where the call to fentry or mcount is
+located in the function. This function is used by perf and kprobes that
+gets the ip address from the user (usually using debug info from the kernel).
+
+If a glob is used to set the filter, functions can be added to a "notrace"
+list that will prevent those functions from calling the callback.
+The "notrace" list takes precedence over the "filter" list. If the
+two lists are non-empty and contain the same functions, the callback will not
+be called by any function.
+
+An empty "notrace" list means to allow all functions defined by the filter
+to be traced.
+
+.. code-block: c
+
+  int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
+                        int len, int reset);
+
+This takes the same parameters as ftrace_set_filter() but will add the
+functions it finds to not be traced. This is a separate list from the
+filter list, and this function does not modify the filter list.
+
+A non-zero @reset will clear the "notrace" list before adding functions
+that match @buf to it.
+
+Clearing the "notrace" list is the same as clearing the filter list
+
+.. code-block: c
+
+  ret = ftrace_set_notrace(&ops, NULL, 0, 1);
+
+The filter and notrace lists may be changed at any time. If only a set of
+functions should call the callback, it is best to set the filters before
+registering the callback. But the changes may also happen after the callback
+has been registered.
+
+If a filter is in place, and the @reset is non-zero, and @buf contains a
+matching glob to functions, the switch will happen during the time of
+the ftrace_set_filter() call. At no time will all functions call the callback.
+
+.. code-block: c
+
+       ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1);
+
+       register_ftrace_function(&ops);
+
+       msleep(10);
+
+       ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 1);
+
+is not the same as:
+
+.. code-block: c
+
+       ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1);
+
+       register_ftrace_function(&ops);
+
+       msleep(10);
+
+       ftrace_set_filter(&ops, NULL, 0, 1);
+
+       ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 0);
+
+As the latter will have a short time where all functions will call
+the callback, between the time of the reset, and the time of the
+new setting of the filter.
index f92070e7dde09d0e0ad69efdb04e9f5b4716d7d5..7a57165c249285de5402c972e1a3322d5b449a79 100644 (file)
@@ -37,7 +37,7 @@ description is at Documentation/ABI/testing/sysfs-bus-intel_th-devices-gth.
 
 STH registers an stm class device, through which it provides interface
 to userspace and kernelspace software trace sources. See
-Documentation/tracing/stm.txt for more information on that.
+Documentation/trace/stm.txt for more information on that.
 
 MSU can be configured to collect trace data into a system memory
 buffer, which can later on be read from its device nodes via read() or
index a7a813258013e7812ad6197c5da62af6cd03dad7..ec3b46e27b7aa3aeca361d169bfda8ea09bf91fb 100644 (file)
@@ -1858,18 +1858,6 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
      참고하세요.
 
 
- (*) lockless_dereference();
-
-     이 함수는 smp_read_barrier_depends() 데이터 의존성 배리어를 사용하는
-     포인터 읽어오기 래퍼(wrapper) 함수로 생각될 수 있습니다.
-
-     객체의 라이프타임이 RCU 외의 메커니즘으로 관리된다는 점을 제외하면
-     rcu_dereference() 와도 유사한데, 예를 들면 객체가 시스템이 꺼질 때에만
-     제거되는 경우 등입니다.  또한, lockless_dereference() 은 RCU 와 함께
-     사용될수도, RCU 없이 사용될 수도 있는 일부 데이터 구조에 사용되고
-     있습니다.
-
-
  (*) dma_wmb();
  (*) dma_rmb();
 
index fbc397d17e98a71be5826362e430863cce837998..441a4b9b666fbb2b2aace2cbc2f5ab542635d553 100644 (file)
@@ -773,7 +773,7 @@ host:
 # cat /dev/usb/lp0
 
 More advanced testing can be done with the prn_example
-described in Documentation/usb/gadget-printer.txt.
+described in Documentation/usb/gadget_printer.txt.
 
 
 20. UAC1 function (virtual ALSA card, using u_audio API)
index 7a9f635d0258cee99d70fc7b9d49b92093e7e6be..6d866c537127769f14d1c643916275342c3d635d 100644 (file)
@@ -15,7 +15,7 @@ Last reviewed: 05/20/2016
 
  Watchdog functionality is enabled like any other common watchdog driver. That
  is, an application needs to be started that kicks off the watchdog timer. A
- basic application exists in the Documentation/watchdog/src directory called
+ basic application exists in tools/testing/selftests/watchdog/ named
  watchdog-test.c. Simply compile the C file and kick it off. If the system
  gets into a bad state and hangs, the HPE ProLiant iLO timer register will
  not be updated in a timely fashion and a hardware system reset (also known as
index 4f68052395c0323278caa14d003a0924695e0887..b8e60a441a434bad97dec0882c3cb0014489fbda 100644 (file)
@@ -25,7 +25,7 @@ Last reviewed: 10/05/2007
 
  If you want to write a program to be compatible with the PC Watchdog
  driver, simply use of modify the watchdog test program:
Documentation/watchdog/src/watchdog-test.c
tools/testing/selftests/watchdog/watchdog-test.c
 
 
  Other IOCTL functions include:
index f512ab7185411e813a233f0473853b41a94f7d2f..afc41f544dab9c6437f8d7b07bb58fb4eb495bd9 100644 (file)
@@ -1,4 +1,5 @@
-Secure Memory Encryption (SME) is a feature found on AMD processors.
+Secure Memory Encryption (SME) and Secure Encrypted Virtualization (SEV) are
+features found on AMD processors.
 
 SME provides the ability to mark individual pages of memory as encrypted using
 the standard x86 page tables.  A page that is marked encrypted will be
@@ -6,24 +7,38 @@ automatically decrypted when read from DRAM and encrypted when written to
 DRAM.  SME can therefore be used to protect the contents of DRAM from physical
 attacks on the system.
 
+SEV enables running encrypted virtual machines (VMs) in which the code and data
+of the guest VM are secured so that a decrypted version is available only
+within the VM itself. SEV guest VMs have the concept of private and shared
+memory. Private memory is encrypted with the guest-specific key, while shared
+memory may be encrypted with hypervisor key. When SME is enabled, the hypervisor
+key is the same key which is used in SME.
+
 A page is encrypted when a page table entry has the encryption bit set (see
 below on how to determine its position).  The encryption bit can also be
 specified in the cr3 register, allowing the PGD table to be encrypted. Each
 successive level of page tables can also be encrypted by setting the encryption
 bit in the page table entry that points to the next table. This allows the full
 page table hierarchy to be encrypted. Note, this means that just because the
-encryption bit is set in cr3, doesn't imply the full hierarchy is encyrpted.
+encryption bit is set in cr3, doesn't imply the full hierarchy is encrypted.
 Each page table entry in the hierarchy needs to have the encryption bit set to
 achieve that. So, theoretically, you could have the encryption bit set in cr3
 so that the PGD is encrypted, but not set the encryption bit in the PGD entry
 for a PUD which results in the PUD pointed to by that entry to not be
 encrypted.
 
-Support for SME can be determined through the CPUID instruction. The CPUID
-function 0x8000001f reports information related to SME:
+When SEV is enabled, instruction pages and guest page tables are always treated
+as private. All the DMA operations inside the guest must be performed on shared
+memory. Since the memory encryption bit is controlled by the guest OS when it
+is operating in 64-bit or 32-bit PAE mode, in all other modes the SEV hardware
+forces the memory encryption bit to 1.
+
+Support for SME and SEV can be determined through the CPUID instruction. The
+CPUID function 0x8000001f reports information related to SME:
 
        0x8000001f[eax]:
                Bit[0] indicates support for SME
+               Bit[1] indicates support for SEV
        0x8000001f[ebx]:
                Bits[5:0]  pagetable bit number used to activate memory
                           encryption
@@ -39,6 +54,13 @@ determine if SME is enabled and/or to enable memory encryption:
                Bit[23]   0 = memory encryption features are disabled
                          1 = memory encryption features are enabled
 
+If SEV is supported, MSR 0xc0010131 (MSR_AMD64_SEV) can be used to determine if
+SEV is active:
+
+       0xc0010131:
+               Bit[0]    0 = memory encryption is not active
+                         1 = memory encryption is active
+
 Linux relies on BIOS to set this bit if BIOS has determined that the reduction
 in the physical address space as a result of enabling memory encryption (see
 CPUID information above) will not conflict with the address space resource
index 4d8848e4e224a8eb8207c8fb7469be57340f1671..6851854cf69dd8334d61cd55d2b02bd13b32daeb 100644 (file)
@@ -87,6 +87,17 @@ with the following files:
                        bytes) at which a previously used LLC_occupancy
                        counter can be considered for re-use.
 
+Finally, in the top level of the "info" directory there is a file
+named "last_cmd_status". This is reset with every "command" issued
+via the file system (making new directories or writing to any of the
+control files). If the command was successful, it will read as "ok".
+If the command failed, it will provide more information that can be
+conveyed in the error returns from file operations. E.g.
+
+       # echo L3:0=f7 > schemata
+       bash: echo: write error: Invalid argument
+       # cat info/last_cmd_status
+       mask f7 has non-consecutive 1-bits
 
 Resource alloc and monitor groups
 ---------------------------------
index af0c9a4c65a6dab9d5b806dadb011209de718c33..cd4b29be29af1e84162f06b86f306183b1df5d22 100644 (file)
@@ -4,7 +4,7 @@ ORC unwinder
 Overview
 --------
 
-The kernel CONFIG_ORC_UNWINDER option enables the ORC unwinder, which is
+The kernel CONFIG_UNWINDER_ORC option enables the ORC unwinder, which is
 similar in concept to a DWARF unwinder.  The difference is that the
 format of the ORC data is much simpler than DWARF, which in turn allows
 the ORC unwinder to be much simpler and faster.
index b0798e281aa6a64f566fdcc231c056817cc785aa..3448e675b4623ce81b5e0bc1116c52a12c411801 100644 (file)
@@ -34,7 +34,7 @@ ff92000000000000 - ffd1ffffffffffff (=54 bits) vmalloc/ioremap space
 ffd2000000000000 - ffd3ffffffffffff (=49 bits) hole
 ffd4000000000000 - ffd5ffffffffffff (=49 bits) virtual memory map (512TB)
 ... unused hole ...
-ffd8000000000000 - fff7ffffffffffff (=53 bits) kasan shadow memory (8PB)
+ffdf000000000000 - fffffc0000000000 (=53 bits) kasan shadow memory (8PB)
 ... unused hole ...
 ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks
 ... unused hole ...
index 2f4e462aa4a214d188bbed5aa612b60b34374448..ee5d9d2aabb1918ded8e5508de386c2a1961654d 100644 (file)
@@ -3444,7 +3444,8 @@ M:        Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Supported
-F:     drivers/clocksource
+F:     drivers/clocksource/
+F:     Documentation/devicetree/bindings/timer/
 
 CMPC ACPI DRIVER
 M:     Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
@@ -3636,6 +3637,8 @@ F:        drivers/cpufreq/arm_big_little_dt.c
 
 CPU POWER MONITORING SUBSYSTEM
 M:     Thomas Renninger <trenn@suse.com>
+M:     Shuah Khan <shuahkh@osg.samsung.com>
+M:     Shuah Khan <shuah@kernel.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
 F:     tools/power/cpupower/
@@ -4234,7 +4237,7 @@ S:        Maintained
 F:     drivers/dma/
 F:     include/linux/dmaengine.h
 F:     Documentation/devicetree/bindings/dma/
-F:     Documentation/dmaengine/
+F:     Documentation/driver-api/dmaengine/
 T:     git git://git.infradead.org/users/vkoul/slave-dma.git
 
 DMA MAPPING HELPERS
@@ -4906,13 +4909,19 @@ L:      linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/highbank*
 
-EDAC-CAVIUM
+EDAC-CAVIUM OCTEON
 M:     Ralf Baechle <ralf@linux-mips.org>
 M:     David Daney <david.daney@cavium.com>
 L:     linux-edac@vger.kernel.org
 L:     linux-mips@linux-mips.org
 S:     Supported
 F:     drivers/edac/octeon_edac*
+
+EDAC-CAVIUM THUNDERX
+M:     David Daney <david.daney@cavium.com>
+M:     Jan Glauber <jglauber@cavium.com>
+L:     linux-edac@vger.kernel.org
+S:     Supported
 F:     drivers/edac/thunderx_edac*
 
 EDAC-CORE
@@ -5213,8 +5222,7 @@ F:        fs/ext4/
 
 Extended Verification Module (EVM)
 M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
-L:     linux-ima-devel@lists.sourceforge.net
-L:     linux-security-module@vger.kernel.org
+L:     linux-integrity@vger.kernel.org
 S:     Supported
 F:     security/integrity/evm/
 
@@ -6841,9 +6849,7 @@ L:        linux-crypto@vger.kernel.org
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
 M:     Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
-L:     linux-ima-devel@lists.sourceforge.net
-L:     linux-ima-user@lists.sourceforge.net
-L:     linux-security-module@vger.kernel.org
+L:     linux-integrity@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
 S:     Supported
 F:     security/integrity/ima/
@@ -7626,8 +7632,7 @@ F:        kernel/kexec*
 
 KEYS-ENCRYPTED
 M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
-M:     David Safford <safford@us.ibm.com>
-L:     linux-security-module@vger.kernel.org
+L:     linux-integrity@vger.kernel.org
 L:     keyrings@vger.kernel.org
 S:     Supported
 F:     Documentation/security/keys/trusted-encrypted.rst
@@ -7635,9 +7640,8 @@ F:        include/keys/encrypted-type.h
 F:     security/keys/encrypted-keys/
 
 KEYS-TRUSTED
-M:     David Safford <safford@us.ibm.com>
 M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
-L:     linux-security-module@vger.kernel.org
+L:     linux-integrity@vger.kernel.org
 L:     keyrings@vger.kernel.org
 S:     Supported
 F:     Documentation/security/keys/trusted-encrypted.rst
@@ -7745,6 +7749,11 @@ S:       Maintained
 F:     Documentation/scsi/53c700.txt
 F:     drivers/scsi/53c700*
 
+LEAKING_ADDRESSES
+M:     Tobin C. Harding <me@tobin.cc>
+S:     Maintained
+F:     scripts/leaking_addresses.pl
+
 LED SUBSYSTEM
 M:     Richard Purdie <rpurdie@rpsys.net>
 M:     Jacek Anaszewski <jacek.anaszewski@gmail.com>
@@ -10031,7 +10040,11 @@ T:     git git://github.com/openrisc/linux.git
 L:     openrisc@lists.librecores.org
 W:     http://openrisc.io
 S:     Maintained
+F:     Documentation/devicetree/bindings/openrisc/
+F:     Documentation/openrisc/
 F:     arch/openrisc/
+F:     drivers/irqchip/irq-ompic.c
+F:     drivers/irqchip/irq-or1k-*
 
 OPENVSWITCH
 M:     Pravin Shelar <pshelar@nicira.com>
@@ -10049,7 +10062,7 @@ M:      Stephen Boyd <sboyd@codeaurora.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git
-F:     drivers/base/power/opp/
+F:     drivers/opp/
 F:     include/linux/pm_opp.h
 F:     Documentation/power/opp.txt
 F:     Documentation/devicetree/bindings/opp/
@@ -10336,7 +10349,6 @@ F:      drivers/pci/host/vmd.c
 
 PCI DRIVER FOR MICROSEMI SWITCHTEC
 M:     Kurt Schwemmer <kurt.schwemmer@microsemi.com>
-M:     Stephen Bates <stephen.bates@microsemi.com>
 M:     Logan Gunthorpe <logang@deltatee.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
@@ -10401,6 +10413,7 @@ F:      drivers/pci/dwc/*keystone*
 
 PCI ENDPOINT SUBSYSTEM
 M:     Kishon Vijay Abraham I <kishon@ti.com>
+M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
 L:     linux-pci@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
 S:     Supported
@@ -10452,6 +10465,15 @@ F:     include/linux/pci*
 F:     arch/x86/pci/
 F:     arch/x86/kernel/quirks.c
 
+PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
+M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+L:     linux-pci@vger.kernel.org
+Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
+S:     Supported
+F:     drivers/pci/host/
+F:     drivers/pci/dwc/
+
 PCIE DRIVER FOR AXIS ARTPEC
 M:     Niklas Cassel <niklas.cassel@axis.com>
 M:     Jesper Nilsson <jesper.nilsson@axis.com>
@@ -10471,7 +10493,6 @@ F:      drivers/pci/host/pci-thunder-*
 
 PCIE DRIVER FOR HISILICON
 M:     Zhou Wang <wangzhou1@hisilicon.com>
-M:     Gabriele Paoloni <gabriele.paoloni@huawei.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
@@ -12048,6 +12069,12 @@ L:     linux-mmc@vger.kernel.org
 S:     Maintained
 F:     drivers/mmc/host/sdhci-spear.c
 
+SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) TI OMAP DRIVER
+M:     Kishon Vijay Abraham I <kishon@ti.com>
+L:     linux-mmc@vger.kernel.org
+S:     Maintained
+F:     drivers/mmc/host/sdhci-omap.c
+
 SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER
 M:     Scott Bauer <scott.bauer@intel.com>
 M:     Jonathan Derrick <jonathan.derrick@intel.com>
@@ -13598,23 +13625,14 @@ F:    drivers/platform/x86/toshiba-wmi.c
 
 TPM DEVICE DRIVER
 M:     Peter Huewe <peterhuewe@gmx.de>
-M:     Marcel Selhorst <tpmdd@selhorst.net>
 M:     Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
 R:     Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
-W:     http://tpmdd.sourceforge.net
-L:     tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
-Q:     https://patchwork.kernel.org/project/tpmdd-devel/list/
+L:     linux-integrity@vger.kernel.org
+Q:     https://patchwork.kernel.org/project/linux-integrity/list/
 T:     git git://git.infradead.org/users/jjs/linux-tpmdd.git
 S:     Maintained
 F:     drivers/char/tpm/
 
-TPM IBM_VTPM DEVICE DRIVER
-M:     Ashley Lai <ashleydlai@gmail.com>
-W:     http://tpmdd.sourceforge.net
-L:     tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
-S:     Maintained
-F:     drivers/char/tpm/tpm_ibmvtpm*
-
 TRACING
 M:     Steven Rostedt <rostedt@goodmis.org>
 M:     Ingo Molnar <mingo@redhat.com>
@@ -14324,6 +14342,7 @@ L:      virtualization@lists.linux-foundation.org
 L:     kvm@vger.kernel.org
 S:     Supported
 F:     drivers/s390/virtio/
+F:     arch/s390/include/uapi/asm/virtio-ccw.h
 
 VIRTIO GPU DRIVER
 M:     David Airlie <airlied@linux.ie>
index bee2033e7d1de0e6a459a78919000890390d1433..7917d4a1d8d2383caeb71eb2cc0f45cbc8dacc33 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 4
 PATCHLEVEL = 14
 SUBLEVEL = 0
-EXTRAVERSION = -rc8
+EXTRAVERSION =
 NAME = Fearless Coyote
 
 # *DOCUMENTATION*
@@ -934,8 +934,8 @@ ifdef CONFIG_STACK_VALIDATION
   ifeq ($(has_libelf),1)
     objtool_target := tools/objtool FORCE
   else
-    ifdef CONFIG_ORC_UNWINDER
-      $(error "Cannot generate ORC metadata for CONFIG_ORC_UNWINDER=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
+    ifdef CONFIG_UNWINDER_ORC
+      $(error "Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
     else
       $(warning "Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
     endif
@@ -1459,7 +1459,8 @@ $(help-board-dirs): help-%:
 
 # Documentation targets
 # ---------------------------------------------------------------------------
-DOC_TARGETS := xmldocs latexdocs pdfdocs htmldocs epubdocs cleandocs linkcheckdocs
+DOC_TARGETS := xmldocs latexdocs pdfdocs htmldocs epubdocs cleandocs \
+              linkcheckdocs dochelp refcheckdocs
 PHONY += $(DOC_TARGETS)
 $(DOC_TARGETS): scripts_basic FORCE
        $(Q)$(MAKE) $(build)=Documentation $@
index 057370a0ac4ec7cf133f6f4c2ee9106a1d576958..400b9e1b2f275d2f253a54087c137bedf0a491ea 100644 (file)
@@ -91,7 +91,7 @@ config STATIC_KEYS_SELFTEST
 config OPTPROBES
        def_bool y
        depends on KPROBES && HAVE_OPTPROBES
-       depends on !PREEMPT
+       select TASKS_RCU if PREEMPT
 
 config KPROBES_ON_FTRACE
        def_bool y
index 85867d3cea649a093d90ff8c053475084ed3b9e0..767bfdd42992de7fb4084dfecb4caa6c13655129 100644 (file)
  * than regular operations.
  */
 
+/*
+ * To ensure dependency ordering is preserved for the _relaxed and
+ * _release atomics, an smp_read_barrier_depends() is unconditionally
+ * inserted into the _relaxed variants, which are used to build the
+ * barriered versions. To avoid redundant back-to-back fences, we can
+ * define the _acquire and _fence versions explicitly.
+ */
+#define __atomic_op_acquire(op, args...)       op##_relaxed(args)
+#define __atomic_op_fence                      __atomic_op_release
 
 #define ATOMIC_INIT(i)         { (i) }
 #define ATOMIC64_INIT(i)       { (i) }
@@ -61,6 +70,7 @@ static inline int atomic_##op##_return_relaxed(int i, atomic_t *v)    \
        ".previous"                                                     \
        :"=&r" (temp), "=m" (v->counter), "=&r" (result)                \
        :"Ir" (i), "m" (v->counter) : "memory");                        \
+       smp_read_barrier_depends();                                     \
        return result;                                                  \
 }
 
@@ -78,6 +88,7 @@ static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v)     \
        ".previous"                                                     \
        :"=&r" (temp), "=m" (v->counter), "=&r" (result)                \
        :"Ir" (i), "m" (v->counter) : "memory");                        \
+       smp_read_barrier_depends();                                     \
        return result;                                                  \
 }
 
@@ -112,6 +123,7 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v)       \
        ".previous"                                                     \
        :"=&r" (temp), "=m" (v->counter), "=&r" (result)                \
        :"Ir" (i), "m" (v->counter) : "memory");                        \
+       smp_read_barrier_depends();                                     \
        return result;                                                  \
 }
 
@@ -129,6 +141,7 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v)        \
        ".previous"                                                     \
        :"=&r" (temp), "=m" (v->counter), "=&r" (result)                \
        :"Ir" (i), "m" (v->counter) : "memory");                        \
+       smp_read_barrier_depends();                                     \
        return result;                                                  \
 }
 
index 3925f06afd6ba17d3a7dd4c7eab1751d24309a99..cf8fc8f9a2ed566067a3a67724f3a4a4389fab54 100644 (file)
@@ -22,7 +22,7 @@
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 
-static inline void __down_read(struct rw_semaphore *sem)
+static inline int ___down_read(struct rw_semaphore *sem)
 {
        long oldcount;
 #ifndef        CONFIG_SMP
@@ -42,10 +42,24 @@ static inline void __down_read(struct rw_semaphore *sem)
        :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
        :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
 #endif
-       if (unlikely(oldcount < 0))
+       return (oldcount < 0);
+}
+
+static inline void __down_read(struct rw_semaphore *sem)
+{
+       if (unlikely(___down_read(sem)))
                rwsem_down_read_failed(sem);
 }
 
+static inline int __down_read_killable(struct rw_semaphore *sem)
+{
+       if (unlikely(___down_read(sem)))
+               if (IS_ERR(rwsem_down_read_failed_killable(sem)))
+                       return -EINTR;
+
+       return 0;
+}
+
 /*
  * trylock for reading -- returns 1 if successful, 0 if contention
  */
@@ -95,9 +109,10 @@ static inline void __down_write(struct rw_semaphore *sem)
 
 static inline int __down_write_killable(struct rw_semaphore *sem)
 {
-       if (unlikely(___down_write(sem)))
+       if (unlikely(___down_write(sem))) {
                if (IS_ERR(rwsem_down_write_failed_killable(sem)))
                        return -EINTR;
+       }
 
        return 0;
 }
index aa4304afbea6468dc47492ec979d1361b01aefda..1221cbb86a6f6f5dd675ee1bd5c283ff09af4751 100644 (file)
@@ -14,7 +14,6 @@
  * We make no fairness assumptions. They have a cost.
  */
 
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 #define arch_spin_is_locked(x) ((x)->lock != 0)
 
 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
@@ -55,16 +54,6 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
 
 /***********************************************************/
 
-static inline int arch_read_can_lock(arch_rwlock_t *lock)
-{
-       return (lock->lock & 1) == 0;
-}
-
-static inline int arch_write_can_lock(arch_rwlock_t *lock)
-{
-       return lock->lock == 0;
-}
-
 static inline void arch_read_lock(arch_rwlock_t *lock)
 {
        long regx;
@@ -171,7 +160,4 @@ static inline void arch_write_unlock(arch_rwlock_t * lock)
        lock->lock = 0;
 }
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
 #endif /* _ALPHA_SPINLOCK_H */
index 47efc8451b7034b752337e0958af0d653470bc57..2ba04a7db62128148ac303e79e95c2cb2ee2d534 100644 (file)
@@ -14,7 +14,6 @@
 #include <asm/barrier.h>
 
 #define arch_spin_is_locked(x) ((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
-#define arch_spin_lock_flags(lock, flags)      arch_spin_lock(lock)
 
 #ifdef CONFIG_ARC_HAS_LLSC
 
@@ -410,14 +409,4 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
 
 #endif
 
-#define arch_read_can_lock(x)  ((x)->counter > 0)
-#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
-
-#define arch_read_lock_flags(lock, flags)      arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags)     arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SPINLOCK_H */
index 6df9d94a953763eca43b20f02f1897308ab1ee7a..efe8b4200a676529a9f3f0af52d50faca176a1e3 100644 (file)
@@ -250,7 +250,7 @@ static void ipi_send_msg_one(int cpu, enum ipi_msg_type msg)
         * and read back old value
         */
        do {
-               new = old = ACCESS_ONCE(*ipi_data_ptr);
+               new = old = READ_ONCE(*ipi_data_ptr);
                new |= 1U << msg;
        } while (cmpxchg(ipi_data_ptr, old, new) != old);
 
index 6c7b06854fced378be0aa62efe1c9929f183979b..51936bde1eb27d86bc79d48ebd01c4d973c082e9 100644 (file)
@@ -826,28 +826,6 @@ static int locomo_match(struct device *_dev, struct device_driver *_drv)
        return dev->devid == drv->devid;
 }
 
-static int locomo_bus_suspend(struct device *dev, pm_message_t state)
-{
-       struct locomo_dev *ldev = LOCOMO_DEV(dev);
-       struct locomo_driver *drv = LOCOMO_DRV(dev->driver);
-       int ret = 0;
-
-       if (drv && drv->suspend)
-               ret = drv->suspend(ldev, state);
-       return ret;
-}
-
-static int locomo_bus_resume(struct device *dev)
-{
-       struct locomo_dev *ldev = LOCOMO_DEV(dev);
-       struct locomo_driver *drv = LOCOMO_DRV(dev->driver);
-       int ret = 0;
-
-       if (drv && drv->resume)
-               ret = drv->resume(ldev);
-       return ret;
-}
-
 static int locomo_bus_probe(struct device *dev)
 {
        struct locomo_dev *ldev = LOCOMO_DEV(dev);
@@ -875,8 +853,6 @@ struct bus_type locomo_bus_type = {
        .match          = locomo_match,
        .probe          = locomo_bus_probe,
        .remove         = locomo_bus_remove,
-       .suspend        = locomo_bus_suspend,
-       .resume         = locomo_bus_resume,
 };
 
 int locomo_driver_register(struct locomo_driver *driver)
index eee269321923b8375e043ad50148031aa00407db..1070044f5c3f4926efc7a8d2a2e1be4cff01b4f1 100644 (file)
@@ -196,6 +196,11 @@ static inline void gic_write_ctlr(u32 val)
        isb();
 }
 
+static inline u32 gic_read_ctlr(void)
+{
+       return read_sysreg(ICC_CTLR);
+}
+
 static inline void gic_write_grpen1(u32 val)
 {
        write_sysreg(val, ICC_IGRPEN1);
index 74e51d6bd93fd072fc95de22f67806dc89807e85..f8712e3c29cfec59749576e56bbda43a5a52d5fa 100644 (file)
@@ -189,8 +189,6 @@ struct locomo_driver {
        unsigned int            devid;
        int (*probe)(struct locomo_dev *);
        int (*remove)(struct locomo_dev *);
-       int (*suspend)(struct locomo_dev *, pm_message_t);
-       int (*resume)(struct locomo_dev *);
 };
 
 #define LOCOMO_DRV(_d) container_of((_d), struct locomo_driver, drv)
index e9c9a117bd25d5b69e8ba5313990f18f8db7311d..c7cdbb43ae7c4bed34bb95dbee6b4248a96d9489 100644 (file)
@@ -126,8 +126,7 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 /*
  * kprobe-based event tracer support
  */
-#include <linux/stddef.h>
-#include <linux/types.h>
+#include <linux/compiler.h>
 #define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0))
 
 extern int regs_query_register_offset(const char *name);
index 25cb465c8538b22cc68de7cdd39e2852a8382f16..099c78fcf62d43cd0a123b4d520d44a5d853a813 100644 (file)
@@ -53,8 +53,6 @@ static inline void dsb_sev(void)
  * memory.
  */
 
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
        unsigned long tmp;
@@ -74,7 +72,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
 
        while (lockval.tickets.next != lockval.tickets.owner) {
                wfe();
-               lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);
+               lockval.tickets.owner = READ_ONCE(lock->tickets.owner);
        }
 
        smp_mb();
@@ -194,9 +192,6 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
        dsb_sev();
 }
 
-/* write_can_lock - would write_trylock() succeed? */
-#define arch_write_can_lock(x)         (ACCESS_ONCE((x)->lock) == 0)
-
 /*
  * Read locks are a bit more hairy:
  *  - Exclusively load the lock value.
@@ -274,14 +269,4 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
        }
 }
 
-/* read_can_lock - would read_trylock() succeed? */
-#define arch_read_can_lock(x)          (ACCESS_ONCE((x)->lock) < 0x80000000)
-
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SPINLOCK_H */
index f59ab9bcbaf956b8cac5568e62c54de17a7cd648..5d88d2f22b2cc5d62ccc883cded7693605134084 100644 (file)
@@ -25,6 +25,14 @@ void init_cpu_topology(void);
 void store_cpu_topology(unsigned int cpuid);
 const struct cpumask *cpu_coregroup_mask(int cpu);
 
+#include <linux/arch_topology.h>
+
+/* Replace task scheduler's default frequency-invariant accounting */
+#define arch_scale_freq_capacity topology_get_freq_scale
+
+/* Replace task scheduler's default cpu-invariant accounting */
+#define arch_scale_cpu_capacity topology_get_cpu_scale
+
 #else
 
 static inline void init_cpu_topology(void) { }
index 948c648fea009d6ac36fd6bbd11e1f8c5058be1c..0fcd82f013883c58229aa8647d50047af010dde2 100644 (file)
@@ -154,30 +154,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
        set_fs(fs);
 }
 
-static void dump_instr(const char *lvl, struct pt_regs *regs)
+static void __dump_instr(const char *lvl, struct pt_regs *regs)
 {
        unsigned long addr = instruction_pointer(regs);
        const int thumb = thumb_mode(regs);
        const int width = thumb ? 4 : 8;
-       mm_segment_t fs;
        char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
        int i;
 
        /*
-        * We need to switch to kernel mode so that we can use __get_user
-        * to safely read from kernel space.  Note that we now dump the
-        * code first, just in case the backtrace kills us.
+        * Note that we now dump the code first, just in case the backtrace
+        * kills us.
         */
-       fs = get_fs();
-       set_fs(KERNEL_DS);
 
        for (i = -4; i < 1 + !!thumb; i++) {
                unsigned int val, bad;
 
                if (thumb)
-                       bad = __get_user(val, &((u16 *)addr)[i]);
+                       bad = get_user(val, &((u16 *)addr)[i]);
                else
-                       bad = __get_user(val, &((u32 *)addr)[i]);
+                       bad = get_user(val, &((u32 *)addr)[i]);
 
                if (!bad)
                        p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
@@ -188,8 +184,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
                }
        }
        printk("%sCode: %s\n", lvl, str);
+}
 
-       set_fs(fs);
+static void dump_instr(const char *lvl, struct pt_regs *regs)
+{
+       mm_segment_t fs;
+
+       if (!user_mode(regs)) {
+               fs = get_fs();
+               set_fs(KERNEL_DS);
+               __dump_instr(lvl, regs);
+               set_fs(fs);
+       } else {
+               __dump_instr(lvl, regs);
+       }
 }
 
 #ifdef CONFIG_ARM_UNWIND
index 96a3d73ef4bf43eeab172bd5c3df4457b7023931..e7b350f18f5f82b993f36e5f1f258c3e58836c16 100644 (file)
@@ -136,19 +136,14 @@ struct pci_ops dc21285_ops = {
 static struct timer_list serr_timer;
 static struct timer_list perr_timer;
 
-static void dc21285_enable_error(unsigned long __data)
+static void dc21285_enable_error(struct timer_list *timer)
 {
-       switch (__data) {
-       case IRQ_PCI_SERR:
-               del_timer(&serr_timer);
-               break;
-
-       case IRQ_PCI_PERR:
-               del_timer(&perr_timer);
-               break;
-       }
+       del_timer(timer);
 
-       enable_irq(__data);
+       if (timer == &serr_timer)
+               enable_irq(IRQ_PCI_SERR);
+       else if (timer == &perr_timer)
+               enable_irq(IRQ_PCI_PERR);
 }
 
 /*
@@ -323,13 +318,8 @@ void __init dc21285_preinit(void)
                *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS;
        }
 
-       init_timer(&serr_timer);
-       init_timer(&perr_timer);
-
-       serr_timer.data = IRQ_PCI_SERR;
-       serr_timer.function = dc21285_enable_error;
-       perr_timer.data = IRQ_PCI_PERR;
-       perr_timer.function = dc21285_enable_error;
+       timer_setup(&serr_timer, dc21285_enable_error, 0);
+       timer_setup(&perr_timer, dc21285_enable_error, 0);
 
        /*
         * We don't care if these fail.
index 45801b27ee5ced633fae6a7c6ca238cf203f0056..b5f89fdbbb4b9d1cfa16864be13e1cb4f93b156e 100644 (file)
@@ -286,88 +286,6 @@ static void __init imx6q_init_machine(void)
        imx6q_axi_init();
 }
 
-#define OCOTP_CFG3                     0x440
-#define OCOTP_CFG3_SPEED_SHIFT         16
-#define OCOTP_CFG3_SPEED_1P2GHZ                0x3
-#define OCOTP_CFG3_SPEED_996MHZ                0x2
-#define OCOTP_CFG3_SPEED_852MHZ                0x1
-
-static void __init imx6q_opp_check_speed_grading(struct device *cpu_dev)
-{
-       struct device_node *np;
-       void __iomem *base;
-       u32 val;
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
-       if (!np) {
-               pr_warn("failed to find ocotp node\n");
-               return;
-       }
-
-       base = of_iomap(np, 0);
-       if (!base) {
-               pr_warn("failed to map ocotp\n");
-               goto put_node;
-       }
-
-       /*
-        * SPEED_GRADING[1:0] defines the max speed of ARM:
-        * 2b'11: 1200000000Hz;
-        * 2b'10: 996000000Hz;
-        * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
-        * 2b'00: 792000000Hz;
-        * We need to set the max speed of ARM according to fuse map.
-        */
-       val = readl_relaxed(base + OCOTP_CFG3);
-       val >>= OCOTP_CFG3_SPEED_SHIFT;
-       val &= 0x3;
-
-       if ((val != OCOTP_CFG3_SPEED_1P2GHZ) && cpu_is_imx6q())
-               if (dev_pm_opp_disable(cpu_dev, 1200000000))
-                       pr_warn("failed to disable 1.2 GHz OPP\n");
-       if (val < OCOTP_CFG3_SPEED_996MHZ)
-               if (dev_pm_opp_disable(cpu_dev, 996000000))
-                       pr_warn("failed to disable 996 MHz OPP\n");
-       if (cpu_is_imx6q()) {
-               if (val != OCOTP_CFG3_SPEED_852MHZ)
-                       if (dev_pm_opp_disable(cpu_dev, 852000000))
-                               pr_warn("failed to disable 852 MHz OPP\n");
-       }
-       iounmap(base);
-put_node:
-       of_node_put(np);
-}
-
-static void __init imx6q_opp_init(void)
-{
-       struct device_node *np;
-       struct device *cpu_dev = get_cpu_device(0);
-
-       if (!cpu_dev) {
-               pr_warn("failed to get cpu0 device\n");
-               return;
-       }
-       np = of_node_get(cpu_dev->of_node);
-       if (!np) {
-               pr_warn("failed to find cpu0 node\n");
-               return;
-       }
-
-       if (dev_pm_opp_of_add_table(cpu_dev)) {
-               pr_warn("failed to init OPP table\n");
-               goto put_node;
-       }
-
-       imx6q_opp_check_speed_grading(cpu_dev);
-
-put_node:
-       of_node_put(np);
-}
-
-static struct platform_device imx6q_cpufreq_pdev = {
-       .name = "imx6q-cpufreq",
-};
-
 static void __init imx6q_init_late(void)
 {
        /*
@@ -377,10 +295,8 @@ static void __init imx6q_init_late(void)
        if (imx_get_soc_revision() > IMX_CHIP_REVISION_1_1)
                imx6q_cpuidle_init();
 
-       if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) {
-               imx6q_opp_init();
-               platform_device_register(&imx6q_cpufreq_pdev);
-       }
+       if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
+               platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
 }
 
 static void __init imx6q_map_io(void)
index db488ecc98b54ea6f832bcba1b5e45d4edafd4f0..19839bba7f17e0092d682bb284d10c496073ada7 100644 (file)
@@ -175,7 +175,7 @@ static int power_button_countdown;
 #define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
 
 static void dsmg600_power_handler(unsigned long data);
-static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
+static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler);
 
 static void dsmg600_power_handler(unsigned long data)
 {
index 1b8170d65c748c06f4f300057b11706785701f1c..b6d73124131727ce2923d1c990ba33d684be0eb5 100644 (file)
@@ -198,7 +198,7 @@ static int power_button_countdown;
 #define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
 
 static void nas100d_power_handler(unsigned long data);
-static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler, 0, 0);
+static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler);
 
 static void nas100d_power_handler(unsigned long data)
 {
index d6159f8ef0c245405d5b0c00d32497562f280a05..df45682e99a54e0b44d4c34cd2632e7b7f78c358 100644 (file)
@@ -381,14 +381,11 @@ static struct pxafb_mach_info sharp_lm8v31 = {
 
 #define        MMC_POLL_RATE           msecs_to_jiffies(1000)
 
-static void lubbock_mmc_poll(unsigned long);
 static irq_handler_t mmc_detect_int;
+static void *mmc_detect_int_data;
+static struct timer_list mmc_timer;
 
-static struct timer_list mmc_timer = {
-       .function       = lubbock_mmc_poll,
-};
-
-static void lubbock_mmc_poll(unsigned long data)
+static void lubbock_mmc_poll(struct timer_list *unused)
 {
        unsigned long flags;
 
@@ -401,7 +398,7 @@ static void lubbock_mmc_poll(unsigned long data)
        if (LUB_IRQ_SET_CLR & (1 << 0))
                mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE);
        else {
-               (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data);
+               (void) mmc_detect_int(LUBBOCK_SD_IRQ, mmc_detect_int_data);
                enable_irq(LUBBOCK_SD_IRQ);
        }
 }
@@ -421,8 +418,8 @@ static int lubbock_mci_init(struct device *dev,
 {
        /* detect card insert/eject */
        mmc_detect_int = detect_int;
-       init_timer(&mmc_timer);
-       mmc_timer.data = (unsigned long) data;
+       mmc_detect_int_data = data;
+       timer_setup(&mmc_timer, lubbock_mmc_poll, 0);
        return request_irq(LUBBOCK_SD_IRQ, lubbock_detect_int,
                           0, "lubbock-sd-detect", data);
 }
index 249b7bd5fbc4cf1c2b4b94dbb7a163f9b62a9b39..398ba9ba26327c9cb415282ca94bfb88802dbebf 100644 (file)
@@ -341,7 +341,7 @@ static void sharpsl_charge_toggle(struct work_struct *private_)
        sharpsl_pm.charge_start_time = jiffies;
 }
 
-static void sharpsl_ac_timer(unsigned long data)
+static void sharpsl_ac_timer(struct timer_list *unused)
 {
        int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
 
@@ -366,7 +366,7 @@ static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void sharpsl_chrg_full_timer(unsigned long data)
+static void sharpsl_chrg_full_timer(struct timer_list *unused)
 {
        dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
 
@@ -841,9 +841,9 @@ static int sharpsl_pm_probe(struct platform_device *pdev)
        sharpsl_pm.charge_mode = CHRG_OFF;
        sharpsl_pm.flags = 0;
 
-       setup_timer(&sharpsl_pm.ac_timer, sharpsl_ac_timer, 0UL);
+       timer_setup(&sharpsl_pm.ac_timer, sharpsl_ac_timer, 0);
 
-       setup_timer(&sharpsl_pm.chrg_full_timer, sharpsl_chrg_full_timer, 0UL);
+       timer_setup(&sharpsl_pm.chrg_full_timer, sharpsl_chrg_full_timer, 0);
 
        led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
 
index 2d45d18b1a5e0a1b954fe3f691b933bb03488c08..6b7df6fd2448676e4814d7a93aeda8caa7301fbe 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/platform_data/pcf857x.h>
 #include <linux/platform_data/at24.h>
 #include <linux/smc91x.h>
+#include <linux/gpio/machine.h>
 #include <linux/gpio.h>
 #include <linux/leds.h>
 
@@ -52,7 +53,6 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/mfd/da903x.h>
-#include <linux/platform_data/sht15.h>
 
 #include "devices.h"
 #include "generic.h"
@@ -137,17 +137,18 @@ static unsigned long sg2_im2_unified_pin_config[] __initdata = {
        GPIO10_GPIO, /* large basic connector pin 23 */
 };
 
-static struct sht15_platform_data platform_data_sht15 = {
-       .gpio_data =  100,
-       .gpio_sck  =  98,
+static struct gpiod_lookup_table sht15_gpiod_table = {
+       .dev_id = "sht15",
+       .table = {
+               /* FIXME: should this have |GPIO_OPEN_DRAIN set? */
+               GPIO_LOOKUP("gpio-pxa", 100, "data", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio-pxa", 98, "clk", GPIO_ACTIVE_HIGH),
+       },
 };
 
 static struct platform_device sht15 = {
        .name = "sht15",
        .id = -1,
-       .dev = {
-               .platform_data = &platform_data_sht15,
-       },
 };
 
 static struct regulator_consumer_supply stargate2_sensor_3_con[] = {
@@ -608,6 +609,7 @@ static void __init imote2_init(void)
 
        imote2_stargate2_init();
 
+       gpiod_add_lookup_table(&sht15_gpiod_table);
        platform_add_devices(imote2_devices, ARRAY_SIZE(imote2_devices));
 
        i2c_register_board_info(0, imote2_i2c_board_info,
@@ -988,6 +990,7 @@ static void __init stargate2_init(void)
 
        imote2_stargate2_init();
 
+       gpiod_add_lookup_table(&sht15_gpiod_table);
        platform_add_devices(ARRAY_AND_SIZE(stargate2_devices));
 
        i2c_register_board_info(0, ARRAY_AND_SIZE(stargate2_i2c_board_info));
index 3a4ed4c33a68e51e0f213c9c6407a618eb4c4507..e348bcfe389da51b96cbc2c0bddbbb93a9e7cf5c 100644 (file)
@@ -120,18 +120,12 @@ static int rmobile_pd_power_up(struct generic_pm_domain *genpd)
        return __rmobile_pd_power_up(to_rmobile_pd(genpd), true);
 }
 
-static bool rmobile_pd_active_wakeup(struct device *dev)
-{
-       return true;
-}
-
 static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
 {
        struct generic_pm_domain *genpd = &rmobile_pd->genpd;
        struct dev_power_governor *gov = rmobile_pd->gov;
 
-       genpd->flags |= GENPD_FLAG_PM_CLK;
-       genpd->dev_ops.active_wakeup    = rmobile_pd_active_wakeup;
+       genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
        genpd->power_off                = rmobile_pd_power_down;
        genpd->power_on                 = rmobile_pd_power_up;
        genpd->attach_dev               = cpg_mstp_attach_dev;
index 76e4c83cd5c8dd54e1f644618beef62087e0b0b2..3f24addd7972b9bb3ede7b79cf9983e781389956 100644 (file)
@@ -179,7 +179,7 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
        bool entered_lp2 = false;
 
        if (tegra_pending_sgi())
-               ACCESS_ONCE(abort_flag) = true;
+               WRITE_ONCE(abort_flag, true);
 
        cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
 
index 1c98a87786ca768adb622f1720df442a272bfb75..9ed0129bed3ce3d2904740c9efa24256c3088e18 100644 (file)
@@ -227,7 +227,6 @@ static bool test_regs_ok;
 static int test_func_instance;
 static int pre_handler_called;
 static int post_handler_called;
-static int jprobe_func_called;
 static int kretprobe_handler_called;
 static int tests_failed;
 
@@ -370,50 +369,6 @@ static int test_kprobe(long (*func)(long, long))
        return 0;
 }
 
-static void __kprobes jprobe_func(long r0, long r1)
-{
-       jprobe_func_called = test_func_instance;
-       if (r0 == FUNC_ARG1 && r1 == FUNC_ARG2)
-               test_regs_ok = true;
-       jprobe_return();
-}
-
-static struct jprobe the_jprobe = {
-       .entry          = jprobe_func,
-};
-
-static int test_jprobe(long (*func)(long, long))
-{
-       int ret;
-
-       the_jprobe.kp.addr = (kprobe_opcode_t *)func;
-       ret = register_jprobe(&the_jprobe);
-       if (ret < 0) {
-               pr_err("FAIL: register_jprobe failed with %d\n", ret);
-               return ret;
-       }
-
-       ret = call_test_func(func, true);
-
-       unregister_jprobe(&the_jprobe);
-       the_jprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
-
-       if (!ret)
-               return -EINVAL;
-       if (jprobe_func_called != test_func_instance) {
-               pr_err("FAIL: jprobe handler function not called\n");
-               return -EINVAL;
-       }
-       if (!call_test_func(func, false))
-               return -EINVAL;
-       if (jprobe_func_called == test_func_instance) {
-               pr_err("FAIL: probe called after unregistering\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int __kprobes
 kretprobe_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
@@ -451,7 +406,7 @@ static int test_kretprobe(long (*func)(long, long))
        }
        if (!call_test_func(func, false))
                return -EINVAL;
-       if (jprobe_func_called == test_func_instance) {
+       if (kretprobe_handler_called == test_func_instance) {
                pr_err("FAIL: kretprobe called after unregistering\n");
                return -EINVAL;
        }
@@ -468,18 +423,6 @@ static int run_api_tests(long (*func)(long, long))
        if (ret < 0)
                return ret;
 
-       pr_info("    jprobe\n");
-       ret = test_jprobe(func);
-#if defined(CONFIG_THUMB2_KERNEL) && !defined(MODULE)
-       if (ret == -EINVAL) {
-               pr_err("FAIL: Known longtime bug with jprobe on Thumb kernels\n");
-               tests_failed = ret;
-               ret = 0;
-       }
-#endif
-       if (ret < 0)
-               return ret;
-
        pr_info("    kretprobe\n");
        ret = test_kretprobe(func);
        if (ret < 0)
index 79214d5ff097044dc59e0394c87749e68d8f4d92..a9dd619c6c290042d052f03c351d1dae4760f7e5 100644 (file)
@@ -35,7 +35,7 @@ static notrace u32 __vdso_read_begin(const struct vdso_data *vdata)
 {
        u32 seq;
 repeat:
-       seq = ACCESS_ONCE(vdata->seq_count);
+       seq = READ_ONCE(vdata->seq_count);
        if (seq & 1) {
                cpu_relax();
                goto repeat;
index 0df64a6a56d4985b9c9da0ea3b9092adddb71194..6205f521b648d6afd0733dc9e786911319a1ea02 100644 (file)
@@ -22,7 +22,24 @@ config ARM64
        select ARCH_HAS_STRICT_MODULE_RWX
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if ACPI_APEI_SEA
+       select ARCH_INLINE_READ_LOCK if !PREEMPT
+       select ARCH_INLINE_READ_LOCK_BH if !PREEMPT
+       select ARCH_INLINE_READ_LOCK_IRQ if !PREEMPT
+       select ARCH_INLINE_READ_LOCK_IRQSAVE if !PREEMPT
+       select ARCH_INLINE_READ_UNLOCK if !PREEMPT
+       select ARCH_INLINE_READ_UNLOCK_BH if !PREEMPT
+       select ARCH_INLINE_READ_UNLOCK_IRQ if !PREEMPT
+       select ARCH_INLINE_READ_UNLOCK_IRQRESTORE if !PREEMPT
+       select ARCH_INLINE_WRITE_LOCK if !PREEMPT
+       select ARCH_INLINE_WRITE_LOCK_BH if !PREEMPT
+       select ARCH_INLINE_WRITE_LOCK_IRQ if !PREEMPT
+       select ARCH_INLINE_WRITE_LOCK_IRQSAVE if !PREEMPT
+       select ARCH_INLINE_WRITE_UNLOCK if !PREEMPT
+       select ARCH_INLINE_WRITE_UNLOCK_BH if !PREEMPT
+       select ARCH_INLINE_WRITE_UNLOCK_IRQ if !PREEMPT
+       select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE if !PREEMPT
        select ARCH_USE_CMPXCHG_LOCKREF
+       select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_SUPPORTS_MEMORY_FAILURE
        select ARCH_SUPPORTS_ATOMIC_RMW
        select ARCH_SUPPORTS_NUMA_BALANCING
@@ -539,6 +556,25 @@ config QCOM_QDF2400_ERRATUM_0065
 
          If unsure, say Y.
 
+
+config SOCIONEXT_SYNQUACER_PREITS
+       bool "Socionext Synquacer: Workaround for GICv3 pre-ITS"
+       default y
+       help
+         Socionext Synquacer SoCs implement a separate h/w block to generate
+         MSI doorbell writes with non-zero values for the device ID.
+
+         If unsure, say Y.
+
+config HISILICON_ERRATUM_161600802
+       bool "Hip07 161600802: Erroneous redistributor VLPI base"
+       default y
+       help
+         The HiSilicon Hip07 SoC usees the wrong redistributor base
+         when issued ITS commands such as VMOVP and VMAPP, and requires
+         a 128kB offset to be applied to the target address in this commands.
+
+         If unsure, say Y.
 endmenu
 
 
index 6b54ee8c1262dd1587b9081ef8894166b0c14211..1d03ef54295ade1f4f819264400fdaba06faffb2 100644 (file)
@@ -161,6 +161,9 @@ config ARCH_SEATTLE
 config ARCH_SHMOBILE
        bool
 
+config ARCH_SYNQUACER
+       bool "Socionext SynQuacer SoC Family"
+
 config ARCH_RENESAS
        bool "Renesas SoC Platforms"
        select ARCH_SHMOBILE
index b99a27372965ec82473112094d302a5a3e596092..26396ef53bdeb60df3b825faaa56046ccb58e8bf 100644 (file)
                };
 
                mmc0: mmc@11230000 {
-                       compatible = "mediatek,mt8173-mmc",
-                                    "mediatek,mt8135-mmc";
+                       compatible = "mediatek,mt8173-mmc";
                        reg = <0 0x11230000 0 0x1000>;
                        interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_LOW>;
                        clocks = <&pericfg CLK_PERI_MSDC30_0>,
                };
 
                mmc1: mmc@11240000 {
-                       compatible = "mediatek,mt8173-mmc",
-                                    "mediatek,mt8135-mmc";
+                       compatible = "mediatek,mt8173-mmc";
                        reg = <0 0x11240000 0 0x1000>;
                        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_LOW>;
                        clocks = <&pericfg CLK_PERI_MSDC30_1>,
                };
 
                mmc2: mmc@11250000 {
-                       compatible = "mediatek,mt8173-mmc",
-                                    "mediatek,mt8135-mmc";
+                       compatible = "mediatek,mt8173-mmc";
                        reg = <0 0x11250000 0 0x1000>;
                        interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_LOW>;
                        clocks = <&pericfg CLK_PERI_MSDC30_2>,
                };
 
                mmc3: mmc@11260000 {
-                       compatible = "mediatek,mt8173-mmc",
-                                    "mediatek,mt8135-mmc";
+                       compatible = "mediatek,mt8173-mmc";
                        reg = <0 0x11260000 0 0x1000>;
                        interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_LOW>;
                        clocks = <&pericfg CLK_PERI_MSDC30_3>,
index 2326e39d58929e3c7d10ce94579e5a4a34901e36..e63d0a8312de81bade74507304d3871e3ceec010 100644 (file)
@@ -16,6 +16,7 @@ generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += msi.h
 generic-y += preempt.h
+generic-y += qrwlock.h
 generic-y += rwsem.h
 generic-y += segment.h
 generic-y += serial.h
index 59cca1d6ec547270adbd56a4e2265b9f9fc34375..32f465a80e4e86d5b13fd2d92925b16cceb0bf07 100644 (file)
@@ -126,18 +126,6 @@ static inline const char *acpi_get_enable_method(int cpu)
  */
 #define acpi_disable_cmcff 1
 pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);
-
-/*
- * Despite its name, this function must still broadcast the TLB
- * invalidation in order to ensure other CPUs don't end up with junk
- * entries as a result of speculation. Unusually, its also called in
- * IRQ context (ghes_iounmap_irq) so if we ever need to use IPIs for
- * TLB broadcasting, then we're in trouble here.
- */
-static inline void arch_apei_flush_tlb_one(unsigned long addr)
-{
-       flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
-}
 #endif /* CONFIG_ACPI_APEI */
 
 #ifdef CONFIG_ACPI_NUMA
index b7e3f74822dafa6525558d356068958acd58c949..9becba9ab392f531a1c9aee64acc316792cb8003 100644 (file)
@@ -87,6 +87,11 @@ static inline void gic_write_ctlr(u32 val)
        isb();
 }
 
+static inline u32 gic_read_ctlr(void)
+{
+       return read_sysreg_s(SYS_ICC_CTLR_EL1);
+}
+
 static inline void gic_write_grpen1(u32 val)
 {
        write_sysreg_s(val, SYS_ICC_IGRPEN1_EL1);
index caf86be815ba2cfa26d6cbcab8ee1cd7f6bdf158..4052ec39e8dbb06feb74e1161dcf26ac94744fb2 100644 (file)
@@ -51,6 +51,13 @@ enum fixed_addresses {
 
        FIX_EARLYCON_MEM_BASE,
        FIX_TEXT_POKE0,
+
+#ifdef CONFIG_ACPI_APEI_GHES
+       /* Used for GHES mapping from assorted contexts */
+       FIX_APEI_GHES_IRQ,
+       FIX_APEI_GHES_NMI,
+#endif /* CONFIG_ACPI_APEI_GHES */
+
        __end_of_permanent_fixed_addresses,
 
        /*
index 95ad7102b63cec8f844e211e10ba5987ea812c62..fdb827c7832fd19a495771ceafbec4202da35c5e 100644 (file)
@@ -27,8 +27,6 @@
  * instructions.
  */
 
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
        unsigned int tmp;
@@ -139,176 +137,7 @@ static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 }
 #define arch_spin_is_contended arch_spin_is_contended
 
-/*
- * Write lock implementation.
- *
- * Write locks set bit 31. Unlocking, is done by writing 0 since the lock is
- * exclusively held.
- *
- * The memory barriers are implicit with the load-acquire and store-release
- * instructions.
- */
-
-static inline void arch_write_lock(arch_rwlock_t *rw)
-{
-       unsigned int tmp;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       "       sevl\n"
-       "1:     wfe\n"
-       "2:     ldaxr   %w0, %1\n"
-       "       cbnz    %w0, 1b\n"
-       "       stxr    %w0, %w2, %1\n"
-       "       cbnz    %w0, 2b\n"
-       __nops(1),
-       /* LSE atomics */
-       "1:     mov     %w0, wzr\n"
-       "2:     casa    %w0, %w2, %1\n"
-       "       cbz     %w0, 3f\n"
-       "       ldxr    %w0, %1\n"
-       "       cbz     %w0, 2b\n"
-       "       wfe\n"
-       "       b       1b\n"
-       "3:")
-       : "=&r" (tmp), "+Q" (rw->lock)
-       : "r" (0x80000000)
-       : "memory");
-}
-
-static inline int arch_write_trylock(arch_rwlock_t *rw)
-{
-       unsigned int tmp;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       "1:     ldaxr   %w0, %1\n"
-       "       cbnz    %w0, 2f\n"
-       "       stxr    %w0, %w2, %1\n"
-       "       cbnz    %w0, 1b\n"
-       "2:",
-       /* LSE atomics */
-       "       mov     %w0, wzr\n"
-       "       casa    %w0, %w2, %1\n"
-       __nops(2))
-       : "=&r" (tmp), "+Q" (rw->lock)
-       : "r" (0x80000000)
-       : "memory");
-
-       return !tmp;
-}
-
-static inline void arch_write_unlock(arch_rwlock_t *rw)
-{
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       "       stlr    wzr, %0",
-       "       swpl    wzr, wzr, %0")
-       : "=Q" (rw->lock) :: "memory");
-}
-
-/* write_can_lock - would write_trylock() succeed? */
-#define arch_write_can_lock(x)         ((x)->lock == 0)
-
-/*
- * Read lock implementation.
- *
- * It exclusively loads the lock value, increments it and stores the new value
- * back if positive and the CPU still exclusively owns the location. If the
- * value is negative, the lock is already held.
- *
- * During unlocking there may be multiple active read locks but no write lock.
- *
- * The memory barriers are implicit with the load-acquire and store-release
- * instructions.
- *
- * Note that in UNDEFINED cases, such as unlocking a lock twice, the LL/SC
- * and LSE implementations may exhibit different behaviour (although this
- * will have no effect on lockdep).
- */
-static inline void arch_read_lock(arch_rwlock_t *rw)
-{
-       unsigned int tmp, tmp2;
-
-       asm volatile(
-       "       sevl\n"
-       ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       "1:     wfe\n"
-       "2:     ldaxr   %w0, %2\n"
-       "       add     %w0, %w0, #1\n"
-       "       tbnz    %w0, #31, 1b\n"
-       "       stxr    %w1, %w0, %2\n"
-       "       cbnz    %w1, 2b\n"
-       __nops(1),
-       /* LSE atomics */
-       "1:     wfe\n"
-       "2:     ldxr    %w0, %2\n"
-       "       adds    %w1, %w0, #1\n"
-       "       tbnz    %w1, #31, 1b\n"
-       "       casa    %w0, %w1, %2\n"
-       "       sbc     %w0, %w1, %w0\n"
-       "       cbnz    %w0, 2b")
-       : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
-       :
-       : "cc", "memory");
-}
-
-static inline void arch_read_unlock(arch_rwlock_t *rw)
-{
-       unsigned int tmp, tmp2;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       "1:     ldxr    %w0, %2\n"
-       "       sub     %w0, %w0, #1\n"
-       "       stlxr   %w1, %w0, %2\n"
-       "       cbnz    %w1, 1b",
-       /* LSE atomics */
-       "       movn    %w0, #0\n"
-       "       staddl  %w0, %2\n"
-       __nops(2))
-       : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
-       :
-       : "memory");
-}
-
-static inline int arch_read_trylock(arch_rwlock_t *rw)
-{
-       unsigned int tmp, tmp2;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       "       mov     %w1, #1\n"
-       "1:     ldaxr   %w0, %2\n"
-       "       add     %w0, %w0, #1\n"
-       "       tbnz    %w0, #31, 2f\n"
-       "       stxr    %w1, %w0, %2\n"
-       "       cbnz    %w1, 1b\n"
-       "2:",
-       /* LSE atomics */
-       "       ldr     %w0, %2\n"
-       "       adds    %w1, %w0, #1\n"
-       "       tbnz    %w1, #31, 1f\n"
-       "       casa    %w0, %w1, %2\n"
-       "       sbc     %w1, %w1, %w0\n"
-       __nops(1)
-       "1:")
-       : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
-       :
-       : "cc", "memory");
-
-       return !tmp2;
-}
-
-/* read_can_lock - would read_trylock() succeed? */
-#define arch_read_can_lock(x)          ((x)->lock < 0x80000000)
-
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
+#include <asm/qrwlock.h>
 
 /* See include/linux/spinlock.h */
 #define smp_mb__after_spinlock()       smp_mb()
index 55be59a35e3fe98c094b3b64a15cf02bfd62c7c8..6b856012c51b9f80e658a10e22609e6d4debc0ed 100644 (file)
@@ -36,10 +36,6 @@ typedef struct {
 
 #define __ARCH_SPIN_LOCK_UNLOCKED      { 0 , 0 }
 
-typedef struct {
-       volatile unsigned int lock;
-} arch_rwlock_t;
-
-#define __ARCH_RW_LOCK_UNLOCKED                { 0 }
+#include <asm-generic/qrwlock_types.h>
 
 #endif
index b3202284568b2e86708b6bc59800053995aa739b..c4f2d50491eb113fad8894b6df20cca4083e0858 100644 (file)
@@ -33,6 +33,14 @@ int pcibus_to_node(struct pci_bus *bus);
 
 #endif /* CONFIG_NUMA */
 
+#include <linux/arch_topology.h>
+
+/* Replace task scheduler's default frequency-invariant accounting */
+#define arch_scale_freq_capacity topology_get_freq_scale
+
+/* Replace task scheduler's default cpu-invariant accounting */
+#define arch_scale_cpu_capacity topology_get_cpu_scale
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_ARM_TOPOLOGY_H */
index f1eb15e0e8642d2a74c7d19d18e8e8d3ae5a7062..267d2b79d52d6e3918a18a2c590d797bdec6d3cb 100644 (file)
@@ -778,6 +778,10 @@ void __init early_fixmap_init(void)
        }
 }
 
+/*
+ * Unusually, this is also called in IRQ context (ghes_iounmap_irq) so if we
+ * ever need to use IPIs for TLB broadcasting, then we're in trouble here.
+ */
 void __set_fixmap(enum fixed_addresses idx,
                               phys_addr_t phys, pgprot_t flags)
 {
index f6431439d15d48339ab4b161af70447baaa00e6a..839d1441af3a8edf24b55472ede0e9398f95bfb0 100644 (file)
@@ -36,8 +36,6 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
        __raw_spin_lock_asm(&lock->lock);
 }
 
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
 static inline int arch_spin_trylock(arch_spinlock_t *lock)
 {
        return __raw_spin_trylock_asm(&lock->lock);
@@ -48,23 +46,11 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
        __raw_spin_unlock_asm(&lock->lock);
 }
 
-static inline int arch_read_can_lock(arch_rwlock_t *rw)
-{
-       return __raw_uncached_fetch_asm(&rw->lock) > 0;
-}
-
-static inline int arch_write_can_lock(arch_rwlock_t *rw)
-{
-       return __raw_uncached_fetch_asm(&rw->lock) == RW_LOCK_BIAS;
-}
-
 static inline void arch_read_lock(arch_rwlock_t *rw)
 {
        __raw_read_lock_asm(&rw->lock);
 }
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-
 static inline int arch_read_trylock(arch_rwlock_t *rw)
 {
        return __raw_read_trylock_asm(&rw->lock);
@@ -80,8 +66,6 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
        __raw_write_lock_asm(&rw->lock);
 }
 
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
 static inline int arch_write_trylock(arch_rwlock_t *rw)
 {
        return __raw_write_trylock_asm(&rw->lock);
@@ -92,10 +76,6 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
        __raw_write_unlock_asm(&rw->lock);
 }
 
-#define arch_spin_relax(lock)          cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif
 
 #endif /*  !__BFIN_SPINLOCK_H */
index 53a8d588588787cba2b22202c2ee675fba83e6df..48020863f53a875b2d372ee70c32a148153deac9 100644 (file)
@@ -86,16 +86,6 @@ static inline int arch_read_trylock(arch_rwlock_t *lock)
        return temp;
 }
 
-static inline int arch_read_can_lock(arch_rwlock_t *rwlock)
-{
-       return rwlock->lock == 0;
-}
-
-static inline int arch_write_can_lock(arch_rwlock_t *rwlock)
-{
-       return rwlock->lock == 0;
-}
-
 /*  Stuffs a -1 in the lock value?  */
 static inline void arch_write_lock(arch_rwlock_t *lock)
 {
@@ -177,11 +167,6 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
 /*
  * SMP spinlocks are intended to allow only a single CPU at the lock
  */
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
 #define arch_spin_is_locked(x) ((x)->lock != 0)
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
 #endif
index 1efc444f5fa1a5120108c094cbc72ff124e298a6..49583c5a5d446afa2fec5b0ef220229848c53a01 100644 (file)
@@ -47,7 +47,7 @@ config IA64
        select ARCH_TASK_STRUCT_ALLOCATOR
        select ARCH_THREAD_STACK_ALLOCATOR
        select ARCH_CLOCKSOURCE_DATA
-       select GENERIC_TIME_VSYSCALL_OLD
+       select GENERIC_TIME_VSYSCALL
        select SYSCTL_ARCH_UNALIGN_NO_WARN
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
index 7d6fceb3d5671c12e5e69330cfa1f79382e31673..917910607e0ea94a5bb349540d5d6cdbaec79de8 100644 (file)
 /*
  * lock for reading
  */
-static inline void
-__down_read (struct rw_semaphore *sem)
+static inline int
+___down_read (struct rw_semaphore *sem)
 {
        long result = ia64_fetchadd8_acq((unsigned long *)&sem->count.counter, 1);
 
-       if (result < 0)
+       return (result < 0);
+}
+
+static inline void
+__down_read (struct rw_semaphore *sem)
+{
+       if (___down_read(sem))
                rwsem_down_read_failed(sem);
 }
 
+static inline int
+__down_read_killable (struct rw_semaphore *sem)
+{
+       if (___down_read(sem))
+               if (IS_ERR(rwsem_down_read_failed_killable(sem)))
+                       return -EINTR;
+
+       return 0;
+}
+
 /*
  * lock for writing
  */
@@ -73,9 +89,10 @@ __down_write (struct rw_semaphore *sem)
 static inline int
 __down_write_killable (struct rw_semaphore *sem)
 {
-       if (___down_write(sem))
+       if (___down_write(sem)) {
                if (IS_ERR(rwsem_down_write_failed_killable(sem)))
                        return -EINTR;
+       }
 
        return 0;
 }
index cc6c4dbf53af47b3faed582db57de62d32837a46..cd71ab5faf627f4f744150e05cb053f85b2bb10a 100644 (file)
@@ -17,6 +17,8 @@
 #include <asm/sn/types.h>
 #include <asm/sn/shub_mmr.h>
 
+struct nodepda_s;
+
 #define IBCT_NOTIFY             (0x1UL << 4)
 #define IBCT_ZFIL_MODE          (0x1UL << 0)
 
@@ -210,7 +212,7 @@ struct bteinfo_s {
  */
 extern bte_result_t bte_copy(u64, u64, u64, u64, void *);
 extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64);
-extern void bte_error_handler(unsigned long);
+extern void bte_error_handler(struct nodepda_s *);
 
 #define bte_zero(dest, len, mode, notification) \
        bte_copy(0, dest, len, ((mode) | BTE_ZERO_FILL), notification)
index aa057abd948ec8eb01447e978e50f29616b0cd8a..afd0b3121b4c9565cd5c20d85e813e92fea50039 100644 (file)
@@ -62,7 +62,7 @@ static __always_inline void __ticket_spin_lock(arch_spinlock_t *lock)
 
 static __always_inline int __ticket_spin_trylock(arch_spinlock_t *lock)
 {
-       int tmp = ACCESS_ONCE(lock->lock);
+       int tmp = READ_ONCE(lock->lock);
 
        if (!(((tmp >> TICKET_SHIFT) ^ tmp) & TICKET_MASK))
                return ia64_cmpxchg(acq, &lock->lock, tmp, tmp + 1, sizeof (tmp)) == tmp;
@@ -74,19 +74,19 @@ static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
        unsigned short  *p = (unsigned short *)&lock->lock + 1, tmp;
 
        asm volatile ("ld2.bias %0=[%1]" : "=r"(tmp) : "r"(p));
-       ACCESS_ONCE(*p) = (tmp + 2) & ~1;
+       WRITE_ONCE(*p, (tmp + 2) & ~1);
 }
 
 static inline int __ticket_spin_is_locked(arch_spinlock_t *lock)
 {
-       long tmp = ACCESS_ONCE(lock->lock);
+       long tmp = READ_ONCE(lock->lock);
 
        return !!(((tmp >> TICKET_SHIFT) ^ tmp) & TICKET_MASK);
 }
 
 static inline int __ticket_spin_is_contended(arch_spinlock_t *lock)
 {
-       long tmp = ACCESS_ONCE(lock->lock);
+       long tmp = READ_ONCE(lock->lock);
 
        return ((tmp - (tmp >> TICKET_SHIFT)) & TICKET_MASK) > 1;
 }
@@ -127,9 +127,7 @@ static __always_inline void arch_spin_lock_flags(arch_spinlock_t *lock,
 {
        arch_spin_lock(lock);
 }
-
-#define arch_read_can_lock(rw)         (*(volatile int *)(rw) >= 0)
-#define arch_write_can_lock(rw)        (*(volatile int *)(rw) == 0)
+#define arch_spin_lock_flags   arch_spin_lock_flags
 
 #ifdef ASM_SUPPORTED
 
@@ -157,6 +155,7 @@ arch_read_lock_flags(arch_rwlock_t *lock, unsigned long flags)
                : "p6", "p7", "r2", "memory");
 }
 
+#define arch_read_lock_flags arch_read_lock_flags
 #define arch_read_lock(lock) arch_read_lock_flags(lock, 0)
 
 #else /* !ASM_SUPPORTED */
@@ -209,6 +208,7 @@ arch_write_lock_flags(arch_rwlock_t *lock, unsigned long flags)
                : "ar.ccv", "p6", "p7", "r2", "r29", "memory");
 }
 
+#define arch_write_lock_flags arch_write_lock_flags
 #define arch_write_lock(rw) arch_write_lock_flags(rw, 0)
 
 #define arch_write_trylock(rw)                                                 \
@@ -232,8 +232,6 @@ static inline void arch_write_unlock(arch_rwlock_t *x)
 
 #else /* !ASM_SUPPORTED */
 
-#define arch_write_lock_flags(l, flags) arch_write_lock(l)
-
 #define arch_write_lock(l)                                                             \
 ({                                                                                     \
        __u64 ia64_val, ia64_set_val = ia64_dep_mi(-1, 0, 31, 1);                       \
@@ -273,8 +271,4 @@ static inline int arch_read_trylock(arch_rwlock_t *x)
        return (u32)ia64_cmpxchg4_acq((__u32 *)(x), new.word, old.word) == old.word;
 }
 
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /*  _ASM_IA64_SPINLOCK_H */
index b385ff2bf6ce206de3e90d22b8abc777e9c900ce..f7693f49c573693259e4182d468b3d99f5cbe03a 100644 (file)
@@ -212,6 +212,8 @@ void foo(void)
        BLANK();
        DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET,
               offsetof (struct timespec, tv_nsec));
+       DEFINE(IA64_TIME_SN_SPEC_SNSEC_OFFSET,
+              offsetof (struct time_sn_spec, snsec));
 
        DEFINE(CLONE_SETTLS_BIT, 19);
 #if CLONE_SETTLS != (1<<19)
index c0e7c9af2bb997ad9e713a5b8c40788279f36ef1..fe742ffafc7af0aadecb9e22d043ebfc8b327553 100644 (file)
@@ -236,9 +236,9 @@ ENTRY(fsys_gettimeofday)
        MOV_FROM_ITC(p8, p6, r2, r10)   // CPU_TIMER. 36 clocks latency!!!
 (p9)   ld8 r2 = [r30]          // MMIO_TIMER. Could also have latency issues..
 (p13)  ld8 r25 = [r19]         // get itc_lastcycle value
-       ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET     // tv_sec
+       ld8 r9 = [r22],IA64_TIME_SN_SPEC_SNSEC_OFFSET   // sec
        ;;
-       ld8 r8 = [r22],-IA64_TIMESPEC_TV_NSEC_OFFSET    // tv_nsec
+       ld8 r8 = [r22],-IA64_TIME_SN_SPEC_SNSEC_OFFSET  // snsec
 (p13)  sub r3 = r25,r2         // Diff needed before comparison (thanks davidm)
        ;;
 (p13)  cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
@@ -266,9 +266,9 @@ EX(.fail_efault, probe.w.fault r31, 3)
        mf
        ;;
        ld4 r10 = [r20]         // gtod_lock.sequence
-       shr.u r2 = r2,r23       // shift by factor
-       ;;
        add r8 = r8,r2          // Add xtime.nsecs
+       ;;
+       shr.u r8 = r8,r23       // shift by factor
        cmp4.ne p7,p0 = r28,r10
 (p7)   br.cond.dpnt.few .time_redo     // sequence number changed, redo
        // End critical section.
index 0914c02a1eb0b09323b0fc7415a82a674e9f3a12..cc2861445965464b4ce2db003a9c236c4d3cd540 100644 (file)
@@ -6,10 +6,16 @@
  * fsyscall gettimeofday data
  */
 
+/* like timespec, but includes "shifted nanoseconds" */
+struct time_sn_spec {
+       u64     sec;
+       u64     snsec;
+};
+
 struct fsyscall_gtod_data_t {
        seqcount_t      seq;
-       struct timespec wall_time;
-       struct timespec monotonic_time;
+       struct time_sn_spec wall_time;
+       struct time_sn_spec monotonic_time;
        u64             clk_mask;
        u32             clk_mult;
        u32             clk_shift;
index 555b11180156086bd394389b1036bac8e5be995b..6115464d5f03d3f8a62d1d7593a2c355eecaa516 100644 (file)
@@ -1513,7 +1513,7 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg)
  *
  */
 static void
-ia64_mca_cmc_poll (unsigned long dummy)
+ia64_mca_cmc_poll (struct timer_list *unused)
 {
        /* Trigger a CMC interrupt cascade  */
        platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CMCP_VECTOR,
@@ -1590,7 +1590,7 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg)
  *
  */
 static void
-ia64_mca_cpe_poll (unsigned long dummy)
+ia64_mca_cpe_poll (struct timer_list *unused)
 {
        /* Trigger a CPE interrupt cascade  */
        platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CPEP_VECTOR,
@@ -2098,7 +2098,7 @@ ia64_mca_late_init(void)
                return 0;
 
        /* Setup the CMCI/P vector and handler */
-       setup_timer(&cmc_poll_timer, ia64_mca_cmc_poll, 0UL);
+       timer_setup(&cmc_poll_timer, ia64_mca_cmc_poll, 0);
 
        /* Unmask/enable the vector */
        cmc_polling_enabled = 0;
@@ -2109,7 +2109,7 @@ ia64_mca_late_init(void)
 #ifdef CONFIG_ACPI
        /* Setup the CPEI/P vector and handler */
        cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI);
-       setup_timer(&cpe_poll_timer, ia64_mca_cpe_poll, 0UL);
+       timer_setup(&cpe_poll_timer, ia64_mca_cpe_poll, 0);
 
        {
                unsigned int irq;
index 63dc9cdc95c53827d2df180c4c115bc5c290585e..52c404b08904cce1802d100896c9a036dae41230 100644 (file)
@@ -263,7 +263,7 @@ salinfo_timeout_check(struct salinfo_data *data)
 }
 
 static void
-salinfo_timeout (unsigned long arg)
+salinfo_timeout(struct timer_list *unused)
 {
        ia64_mlogbuf_dump();
        salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
@@ -623,9 +623,8 @@ salinfo_init(void)
 
        *sdir++ = salinfo_dir;
 
-       init_timer(&salinfo_timer);
+       timer_setup(&salinfo_timer, salinfo_timeout, 0);
        salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
-       salinfo_timer.function = &salinfo_timeout;
        add_timer(&salinfo_timer);
 
        i = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "ia64/salinfo:online",
index aa7be020a9042b12b0c0ac8b05e380f0a5c0f8dc..c6ecb97151a25774bf75ce5a1663210db4f6bce3 100644 (file)
@@ -430,30 +430,32 @@ void update_vsyscall_tz(void)
 {
 }
 
-void update_vsyscall_old(struct timespec *wall, struct timespec *wtm,
-                        struct clocksource *c, u32 mult, u64 cycle_last)
+void update_vsyscall(struct timekeeper *tk)
 {
        write_seqcount_begin(&fsyscall_gtod_data.seq);
 
-        /* copy fsyscall clock data */
-        fsyscall_gtod_data.clk_mask = c->mask;
-        fsyscall_gtod_data.clk_mult = mult;
-        fsyscall_gtod_data.clk_shift = c->shift;
-        fsyscall_gtod_data.clk_fsys_mmio = c->archdata.fsys_mmio;
-        fsyscall_gtod_data.clk_cycle_last = cycle_last;
-
-       /* copy kernel time structures */
-        fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;
-        fsyscall_gtod_data.wall_time.tv_nsec = wall->tv_nsec;
-       fsyscall_gtod_data.monotonic_time.tv_sec = wtm->tv_sec
-                                                       + wall->tv_sec;
-       fsyscall_gtod_data.monotonic_time.tv_nsec = wtm->tv_nsec
-                                                       + wall->tv_nsec;
+       /* copy vsyscall data */
+       fsyscall_gtod_data.clk_mask = tk->tkr_mono.mask;
+       fsyscall_gtod_data.clk_mult = tk->tkr_mono.mult;
+       fsyscall_gtod_data.clk_shift = tk->tkr_mono.shift;
+       fsyscall_gtod_data.clk_fsys_mmio = tk->tkr_mono.clock->archdata.fsys_mmio;
+       fsyscall_gtod_data.clk_cycle_last = tk->tkr_mono.cycle_last;
+
+       fsyscall_gtod_data.wall_time.sec = tk->xtime_sec;
+       fsyscall_gtod_data.wall_time.snsec = tk->tkr_mono.xtime_nsec;
+
+       fsyscall_gtod_data.monotonic_time.sec = tk->xtime_sec
+                                             + tk->wall_to_monotonic.tv_sec;
+       fsyscall_gtod_data.monotonic_time.snsec = tk->tkr_mono.xtime_nsec
+                                               + ((u64)tk->wall_to_monotonic.tv_nsec
+                                                       << tk->tkr_mono.shift);
 
        /* normalize */
-       while (fsyscall_gtod_data.monotonic_time.tv_nsec >= NSEC_PER_SEC) {
-               fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC;
-               fsyscall_gtod_data.monotonic_time.tv_sec++;
+       while (fsyscall_gtod_data.monotonic_time.snsec >=
+                                       (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
+               fsyscall_gtod_data.monotonic_time.snsec -=
+                                       ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift;
+               fsyscall_gtod_data.monotonic_time.sec++;
        }
 
        write_seqcount_end(&fsyscall_gtod_data.seq);
index b2eb48490754225196824eac6b9825118ead7ecc..9146192b86f5532e44b681a807fe77fa84d55223 100644 (file)
@@ -219,7 +219,7 @@ retry_bteop:
                                BTE_LNSTAT_LOAD(bte), *bte->most_rcnt_na) );
                        bte->bte_error_count++;
                        bte->bh_error = IBLS_ERROR;
-                       bte_error_handler((unsigned long)NODEPDA(bte->bte_cnode));
+                       bte_error_handler(NODEPDA(bte->bte_cnode));
                        *bte->most_rcnt_na = BTE_WORD_AVAILABLE;
                        goto retry_bteop;
                }
@@ -414,6 +414,12 @@ EXPORT_SYMBOL(bte_unaligned_copy);
  * Block Transfer Engine initialization functions.
  *
  ***********************************************************************/
+static void bte_recovery_timeout(struct timer_list *t)
+{
+       struct nodepda_s *nodepda = from_timer(nodepda, t, bte_recovery_timer);
+
+       bte_error_handler(nodepda);
+}
 
 /*
  * bte_init_node(nodepda, cnode)
@@ -436,9 +442,7 @@ void bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode)
         * will point at this one bte_recover structure to get the lock.
         */
        spin_lock_init(&mynodepda->bte_recovery_lock);
-       init_timer(&mynodepda->bte_recovery_timer);
-       mynodepda->bte_recovery_timer.function = bte_error_handler;
-       mynodepda->bte_recovery_timer.data = (unsigned long)mynodepda;
+       timer_setup(&mynodepda->bte_recovery_timer, bte_recovery_timeout, 0);
 
        for (i = 0; i < BTES_PER_NODE; i++) {
                u64 *base_addr;
index 4cb09f3f1efc636b9090adcfd2fe80e07e278760..d92786c09b344d05ff048979d24597787cae4e57 100644 (file)
  * transfers to be queued.
  */
 
-void bte_error_handler(unsigned long);
-
 /*
  * Wait until all BTE related CRBs are completed
  * and then reset the interfaces.
  */
-int shub1_bte_error_handler(unsigned long _nodepda)
+static int shub1_bte_error_handler(struct nodepda_s *err_nodepda)
 {
-       struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
        struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
        nasid_t nasid;
        int i;
@@ -131,9 +128,8 @@ int shub1_bte_error_handler(unsigned long _nodepda)
  * Wait until all BTE related CRBs are completed
  * and then reset the interfaces.
  */
-int shub2_bte_error_handler(unsigned long _nodepda)
+static int shub2_bte_error_handler(struct nodepda_s *err_nodepda)
 {
-       struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
        struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
        struct bteinfo_s *bte;
        nasid_t nasid;
@@ -170,9 +166,8 @@ int shub2_bte_error_handler(unsigned long _nodepda)
  * Wait until all BTE related CRBs are completed
  * and then reset the interfaces.
  */
-void bte_error_handler(unsigned long _nodepda)
+void bte_error_handler(struct nodepda_s *err_nodepda)
 {
-       struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
        spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock;
        int i;
        unsigned long irq_flags;
@@ -199,12 +194,12 @@ void bte_error_handler(unsigned long _nodepda)
        }
 
        if (is_shub1()) {
-               if (shub1_bte_error_handler(_nodepda)) {
+               if (shub1_bte_error_handler(err_nodepda)) {
                        spin_unlock_irqrestore(recovery_lock, irq_flags);
                        return;
                }
        } else {
-               if (shub2_bte_error_handler(_nodepda)) {
+               if (shub2_bte_error_handler(err_nodepda)) {
                        spin_unlock_irqrestore(recovery_lock, irq_flags);
                        return;
                }
@@ -255,6 +250,6 @@ bte_crb_error_handler(cnodeid_t cnode, int btenum,
 
        BTE_PRINTK(("Got an error on cnode %d bte %d: HW error type 0x%x\n",
                bte->bte_cnode, bte->bte_num, ioe->ie_errortype));
-       bte_error_handler((unsigned long) NODEPDA(cnode));
+       bte_error_handler(NODEPDA(cnode));
 }
 
index f925dec2da920461069fa72537021f1c43594c37..97fa56dddf50ab23c22d94e74cd6b7ce9fb151c0 100644 (file)
@@ -50,7 +50,7 @@ static irqreturn_t hub_eint_handler(int irq, void *arg)
                        if ((int)ret_stuff.v0)
                                panic("%s: Fatal TIO Error", __func__);
                } else
-                       bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
+                       bte_error_handler(NODEPDA(nasid_to_cnodeid(nasid)));
 
        return IRQ_HANDLED;
 }
index 5b799d4deb747c481f3ad7a47d1c75374fa92715..bc3bd930c74cf9003acb60f53c43f19390d61ce0 100644 (file)
@@ -72,7 +72,7 @@ static void sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
        ia64_sn_plat_cpei_handler();
 }
 
-static void sn_cpei_timer_handler(unsigned long dummy)
+static void sn_cpei_timer_handler(struct timer_list *unused)
 {
        sn_cpei_handler(-1, NULL, NULL);
        mod_timer(&sn_cpei_timer, jiffies + CPEI_INTERVAL);
@@ -80,9 +80,8 @@ static void sn_cpei_timer_handler(unsigned long dummy)
 
 void sn_init_cpei_timer(void)
 {
-       init_timer(&sn_cpei_timer);
+       timer_setup(&sn_cpei_timer, sn_cpei_timer_handler, 0);
        sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
-       sn_cpei_timer.function = sn_cpei_timer_handler;
        add_timer(&sn_cpei_timer);
 }
 
index 604af84427ff3c3ea5e03469edfc1fb147dae723..0189f410f8f58901f1c53f7c5e54a978a9abefa2 100644 (file)
@@ -29,7 +29,6 @@
  */
 
 #define arch_spin_is_locked(x)         (*(volatile int *)(&(x)->slock) <= 0)
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 /**
  * arch_spin_trylock - Try spin lock and return a result
@@ -138,18 +137,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
  * semaphore.h for details.  -ben
  */
 
-/**
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_read_can_lock(x) ((int)(x)->lock > 0)
-
-/**
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
-
 static inline void arch_read_lock(arch_rwlock_t *rw)
 {
        unsigned long tmp0, tmp1;
@@ -318,11 +305,4 @@ static inline int arch_write_trylock(arch_rwlock_t *lock)
        return 0;
 }
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* _ASM_M32R_SPINLOCK_H */
index ff5f0896318bdd70b5b5ea4ea8155241cf9431f4..21f00349af525ddaed288506eb8a6c0299093564 100644 (file)
@@ -284,7 +284,7 @@ config M548x
 
 config M5441x
        bool "MCF5441x"
-       depends on !MMU
+       select MMU_COLDFIRE if MMU
        select GENERIC_CLOCKEVENTS
        select HAVE_CACHE_CB
        help
index 5cd57b4d3615625c21ff6193c6739e455082da25..64a6414677360be9c2fe6b710f18a8eb07157193 100644 (file)
@@ -266,6 +266,12 @@ config AMCORE
        help
          Support for the Sysam AMCORE open-hardware generic board.
 
+config STMARK2
+        bool "Sysam stmark2 board support"
+        depends on M5441x
+        help
+          Support for the Sysam stmark2 open-hardware generic board.
+
 config FIREBEE
        bool "FireBee board support"
        depends on M547x
index 90a60d758f8b95f9ce637fbcd045723f0c482a44..a23f48181fd6a4c39fa672bc9c2757ffd18e384b 100644 (file)
@@ -66,7 +66,7 @@ void __init amiga_init_sound(void)
 }
 
 static void nosound( unsigned long ignored );
-static DEFINE_TIMER(sound_timer, nosound, 0, 0);
+static DEFINE_TIMER(sound_timer, nosound);
 
 void amiga_mksound( unsigned int hz, unsigned int ticks )
 {
index f8cef9681416c7b1753f0648c4cd166210e3dd9a..573eabca1a3a60fc824a3588d5beca9b4ddd5f68 100644 (file)
@@ -35,7 +35,8 @@ obj-$(CONFIG_NETtel)  += nettel.o
 obj-$(CONFIG_CLEOPATRA)        += nettel.o
 obj-$(CONFIG_FIREBEE)  += firebee.o
 obj-$(CONFIG_MCF8390)  += mcf8390.o
-obj-$(CONFIG_AMCORE)    += amcore.o
+obj-$(CONFIG_AMCORE)   += amcore.o
+obj-$(CONFIG_STMARK2)  += stmark2.o
 
 obj-$(CONFIG_PCI)      += pci.o
 
index 315d14b0dca06b523237ec0a9202b49ba203ce39..55392af845fb5bc4b381070dea206c9ceacfdd45 100644 (file)
@@ -27,7 +27,7 @@ DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
 DEFINE_CLK(0, "intc.1", 19, MCF_CLK);
 DEFINE_CLK(0, "intc.2", 20, MCF_CLK);
 DEFINE_CLK(0, "imx1-i2c.0", 22, MCF_CLK);
-DEFINE_CLK(0, "mcfdspi.0", 23, MCF_CLK);
+DEFINE_CLK(0, "fsl-dspi.0", 23, MCF_CLK);
 DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
 DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
 DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
@@ -140,6 +140,7 @@ static struct clk * const enable_clks[] __initconst = {
        &__clk_0_18, /* intc0 */
        &__clk_0_19, /* intc0 */
        &__clk_0_20, /* intc0 */
+       &__clk_0_23, /* dspi.0 */
        &__clk_0_24, /* uart0 */
        &__clk_0_25, /* uart1 */
        &__clk_0_26, /* uart2 */
index e53ffed13ba882fe7eb218b8bd7850aeafaa3e98..adad03ca6e11956e606aa15c219fb4971ba73f52 100644 (file)
@@ -96,10 +96,6 @@ static void mcf54xx_reset(void)
 
 void __init config_BSP(char *commandp, int size)
 {
-#ifdef CONFIG_MMU
-       cf_bootmem_alloc();
-       mmu_context_init();
-#endif
        mach_reset = mcf54xx_reset;
        mach_sched_init = hw_timer_init;
        m54xx_uarts_init();
diff --git a/arch/m68k/coldfire/stmark2.c b/arch/m68k/coldfire/stmark2.c
new file mode 100644 (file)
index 0000000..a8d2b3d
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * stmark2.c -- Support for Sysam AMCORE open board
+ *
+ * (C) Copyright 2017, Angelo Dureghello <angelo@sysam.it>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-fsl-dspi.h>
+#include <linux/spi/flash.h>
+#include <asm/mcfsim.h>
+
+/*
+ * Partitioning of parallel NOR flash (39VF3201B)
+ */
+static struct mtd_partition stmark2_partitions[] = {
+       {
+               .name = "U-Boot (1024K)",
+               .size = 0x100000,
+               .offset = 0x0
+       }, {
+               .name = "Kernel+initramfs (7168K)",
+               .size = 0x700000,
+               .offset = MTDPART_OFS_APPEND
+       }, {
+               .name = "Flash Free Space (8192K)",
+               .size = MTDPART_SIZ_FULL,
+               .offset = MTDPART_OFS_APPEND
+       }
+};
+
+static struct flash_platform_data stmark2_spi_flash_data = {
+       .name = "is25lp128",
+       .parts = stmark2_partitions,
+       .nr_parts = ARRAY_SIZE(stmark2_partitions),
+       .type = "is25lp128",
+};
+
+static struct spi_board_info stmark2_board_info[] __initdata = {
+       {
+               .modalias = "m25p80",
+               .max_speed_hz = 5000000,
+               .bus_num = 0,
+               .chip_select = 1,
+               .platform_data = &stmark2_spi_flash_data,
+               .mode = SPI_MODE_3,
+       }
+};
+
+/* SPI controller data, SPI (0) */
+static struct fsl_dspi_platform_data dspi_spi0_info = {
+       .cs_num = 4,
+       .bus_num = 0,
+       .sck_cs_delay = 100,
+       .cs_sck_delay = 100,
+};
+
+static struct resource dspi_spi0_resource[] = {
+       [0] = {
+               .start = MCFDSPI_BASE0,
+               .end   = MCFDSPI_BASE0 + 0xFF,
+               .flags = IORESOURCE_MEM,
+               },
+       [1] = {
+               .start = 12,
+               .end   = 13,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = MCF_IRQ_DSPI0,
+               .end   = MCF_IRQ_DSPI0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+/* SPI controller, id = bus number */
+static struct platform_device dspi_spi0_device = {
+       .name = "fsl-dspi",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(dspi_spi0_resource),
+       .resource = dspi_spi0_resource,
+       .dev = {
+               .platform_data = &dspi_spi0_info,
+       },
+};
+
+static struct platform_device *stmark2_devices[] __initdata = {
+       &dspi_spi0_device,
+};
+
+/*
+ * Note: proper pin-mux setup is mandatory for proper SPI functionality.
+ */
+static int __init init_stmark2(void)
+{
+       /* DSPI0, all pins as DSPI, and using CS1 */
+       __raw_writeb(0x80, MCFGPIO_PAR_DSPIOWL);
+       __raw_writeb(0xfc, MCFGPIO_PAR_DSPIOWH);
+
+       /* Board gpio setup */
+       __raw_writeb(0x00, MCFGPIO_PAR_BE);
+       __raw_writeb(0x00, MCFGPIO_PAR_FBCTL);
+       __raw_writeb(0x00, MCFGPIO_PAR_CS);
+       __raw_writeb(0x00, MCFGPIO_PAR_CANI2C);
+
+       platform_add_devices(stmark2_devices, ARRAY_SIZE(stmark2_devices));
+
+       spi_register_board_info(stmark2_board_info,
+                               ARRAY_SIZE(stmark2_board_info));
+
+       return 0;
+}
+
+late_initcall(init_stmark2);
index 54191f6fc7159abef9e852066247cf94b6ab78dd..5b5fa9831b4d1f1dfe449c52ebfefe2b4a6a6965 100644 (file)
@@ -123,6 +123,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -302,6 +303,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -400,6 +402,7 @@ CONFIG_ARIADNE=y
 # CONFIG_NET_VENDOR_CIRRUS is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
 # CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -451,6 +454,7 @@ CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PPS_CLIENT_PARPORT=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FB_CIRRUS=y
 CONFIG_FB_AMIGA=y
@@ -607,12 +611,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index fb466390442834ac5a5af5143a978e54630c78cf..72a7764b74edfd7fd274f9e14f939dcdbddd17de 100644 (file)
@@ -121,6 +121,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -300,6 +301,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -377,6 +379,7 @@ CONFIG_VETH=m
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -419,6 +422,7 @@ CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -566,12 +570,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 4ab393e86e52ab379aab820b77b1877e017bc46f..884b43a2f0d923bf52a97d41c2f42fc9d3247d28 100644 (file)
@@ -121,6 +121,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -300,6 +301,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -387,6 +389,7 @@ CONFIG_ATARILANCE=y
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -434,6 +437,7 @@ CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PPS_CLIENT_PARPORT=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FB_ATARI=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -588,12 +592,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 1dd8d697545bc86f3b3dee431af99fe223d97a68..fcfa60d31499bce4a6f4661cae8e2a42f16f24bd 100644 (file)
@@ -119,6 +119,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -298,6 +299,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -376,6 +378,7 @@ CONFIG_VETH=m
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 CONFIG_BVME6000_NET=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -417,6 +420,7 @@ CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_HID=m
 CONFIG_HIDRAW=y
 CONFIG_UHID=m
@@ -558,12 +562,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 02b39f50076e5615391e7774b09f6bf8fbecb8fa..9d597bbbbbfe6b2670cabfe5b02741590c562bce 100644 (file)
@@ -121,6 +121,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -300,6 +301,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -378,6 +380,7 @@ CONFIG_HPLANCE=y
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -422,6 +425,7 @@ CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -568,12 +572,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 044dcb2bf8fbec556553ca5a88281733f0eef68b..45da20d1286ceb6ab437a47f5e77e6020a49aba0 100644 (file)
@@ -120,6 +120,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -302,6 +303,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -395,6 +397,7 @@ CONFIG_MACMACE=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
 CONFIG_MAC89x0=y
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -444,6 +447,7 @@ CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FB_VALKYRIE=y
 CONFIG_FB_MAC=y
@@ -590,12 +594,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 3ad04682077a24ac9b6e51854303ed744b9463a9..fda880c1086156a2fc9149f789f421bbbe362555 100644 (file)
@@ -130,6 +130,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -312,6 +313,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -436,6 +438,7 @@ CONFIG_MACMACE=y
 CONFIG_MAC89x0=y
 # CONFIG_NET_VENDOR_EZCHIP is not set
 # CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 CONFIG_BVME6000_NET=y
 CONFIG_MVME16x_NET=y
 # CONFIG_NET_VENDOR_MARVELL is not set
@@ -501,6 +504,7 @@ CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PPS_CLIENT_PARPORT=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FB_CIRRUS=y
 CONFIG_FB_AMIGA=y
@@ -670,12 +674,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index dc2dd61948cdb84442289bd065fbd50f5c8c0a92..7d5e4863efec03bdd3027b070ac00b7a13dd1ca5 100644 (file)
@@ -118,6 +118,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -297,6 +298,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -376,6 +378,7 @@ CONFIG_MVME147_NET=y
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -417,6 +420,7 @@ CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_HID=m
 CONFIG_HIDRAW=y
 CONFIG_UHID=m
@@ -558,12 +562,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 54e7b523fc3d83ab61019d1711118da6cb81af01..7763b71a9c4973e8cf83870a24a5afe6503d0033 100644 (file)
@@ -119,6 +119,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -298,6 +299,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -376,6 +378,7 @@ CONFIG_VETH=m
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 CONFIG_MVME16x_NET=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -417,6 +420,7 @@ CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_HID=m
 CONFIG_HIDRAW=y
 CONFIG_UHID=m
@@ -558,12 +562,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index d63d8a15f6dbc2896420be1c6daeb37f14538faf..17eaebfa3e198f1134711d34ce06b1eab49b88c1 100644 (file)
@@ -119,6 +119,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -298,6 +299,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -386,6 +388,7 @@ CONFIG_VETH=m
 # CONFIG_NET_VENDOR_CIRRUS is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
 # CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -434,6 +437,7 @@ CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PPS_CLIENT_PARPORT=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -581,12 +585,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/stmark2_defconfig b/arch/m68k/configs/stmark2_defconfig
new file mode 100644 (file)
index 0000000..55e55db
--- /dev/null
@@ -0,0 +1,92 @@
+CONFIG_LOCALVERSION="stmark2-001"
+CONFIG_DEFAULT_HOSTNAME="stmark2"
+CONFIG_SYSVIPC=y
+# CONFIG_FHANDLE is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="../uClinux-dist/romfs"
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_AIO is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_BLK_CMDLINE_PARSER=y
+# CONFIG_MMU is not set
+CONFIG_M5441x=y
+CONFIG_CLOCK_FREQ=240000000
+CONFIG_STMARK2=y
+CONFIG_RAMBASE=0x40000000
+CONFIG_RAMSIZE=0x8000000
+CONFIG_VECTORBASE=0x40000000
+CONFIG_KERNELBASE=0x40001000
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_UEVENT_HELPER is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_LE_BYTE_SWAP=y
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_I2 is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_ROM=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PLATRAM=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NOR=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_DEVMEM is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_BAUDRATE=115200
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_SPI=y
+CONFIG_SPI_DEBUG=y
+CONFIG_SPI_FSL_DSPI=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+# CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_FSCACHE=y
+# CONFIG_PROC_SYSCTL is not set
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_PANIC_ON_OOPS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="console=ttyS0,115200 root=/dev/ram0 rw rootfstype=ramfs rdinit=/bin/init devtmpfs.mount=1"
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_ECHAINIV is not set
+CONFIG_CRYPTO_ANSI_CPRNG=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC16=y
index d0924c22f52a7a43640aa429282480f822ecbe3c..d1cb7a04ae1d3835dc455968c899e0a3316f8728 100644 (file)
@@ -116,6 +116,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -295,6 +296,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -373,6 +375,7 @@ CONFIG_SUN3LANCE=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 CONFIG_SUN3_82586=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -416,6 +419,7 @@ CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -559,12 +563,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 3001ee1e5dc52a69e5ff9109b728401c5180861c..ea3a331c62d5b1c906b0c5de2ef37c8ddd0d3422 100644 (file)
@@ -116,6 +116,7 @@ CONFIG_NFT_HASH=m
 CONFIG_NFT_FIB_INET=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -295,6 +296,7 @@ CONFIG_MPLS=y
 CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NSH=m
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_AF_KCM=m
 # CONFIG_WIRELESS is not set
@@ -374,6 +376,7 @@ CONFIG_SUN3LANCE=y
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HUAWEI is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -416,6 +419,7 @@ CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
+# CONFIG_RC_CORE is not set
 CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -560,12 +564,10 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_MCRYPTD=m
 CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_KEYWRAP=m
-CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
index 4e9095b9480a4f79f38b5e74a0fe6b4b97301f49..c87556d5581c4cea798e550c65ed117cd2df3a4f 100644 (file)
 #define MCFGPIO_IRQ_VECBASE    (MCFINT_VECBASE - MCFGPIO_IRQ_MIN)
 #define MCFGPIO_PIN_MAX                87
 
+/*
+ *  DSPI module.
+ */
+#define MCFDSPI_BASE0          0xfc05c000
+#define MCF_IRQ_DSPI0          (MCFINT0_VECBASE + MCFINT0_DSPI0)
+
 #endif /* m5441xsim_h */
index 73dae2abeba3b98e5f730aad711c805a4d2591ad..32f1c79c818f13a3a027d30c47260588403dd216 100644 (file)
@@ -159,6 +159,7 @@ extern void iop_complete_message(struct iop_msg *);
 extern void iop_upload_code(uint, __u8 *, uint, __u16);
 extern void iop_download_code(uint, __u8 *, uint, __u16);
 extern __u8 *iop_compare_code(uint, __u8 *, uint, __u16);
+extern void iop_ism_irq_poll(uint);
 
 extern void iop_register_interrupts(void);
 
index 10f9930ec49a3ebcc7a9bb4749fd4793f1b638dc..283352ab0d5d83161722ce59598de1d88cb6ae51 100644 (file)
@@ -106,6 +106,7 @@ static inline void mmu_write(u32 a, u32 v)
 }
 
 void cf_bootmem_alloc(void);
+void cf_mmu_context_init(void);
 int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word);
 
 #endif
index 836acea8f758e321b74fd5daca970d2c75889d47..f5b1852b466355502b804eeb9e6c16cb4b764cfe 100644 (file)
@@ -92,7 +92,6 @@ static inline void activate_mm(struct mm_struct *active_mm,
 
 #define deactivate_mm(tsk, mm) do { } while (0)
 
-extern void mmu_context_init(void);
 #define prepare_arch_switch(next) load_ksp_mmu(next)
 
 static inline void load_ksp_mmu(struct task_struct *task)
index 854e09f403e7eb70dfbf08a0be26e36a0f9ede26..19a92982629a3e4424ccdc6176f207ca8550f277 100644 (file)
@@ -4,3 +4,8 @@
 #else
 #include "setup_no.c"
 #endif
+
+#if IS_ENABLED(CONFIG_INPUT_M68K_BEEP)
+void (*mach_beep)(unsigned int, unsigned int);
+EXPORT_SYMBOL(mach_beep);
+#endif
index 657a9843ebfa89d9df67f922ce2862acdb66f37a..dd25bfc22fb45118c32bd9b44923e1ed11775ddd 100644 (file)
@@ -106,10 +106,6 @@ EXPORT_SYMBOL(mach_heartbeat);
 #ifdef CONFIG_M68K_L2_CACHE
 void (*mach_l2_flush) (int);
 #endif
-#if IS_ENABLED(CONFIG_INPUT_M68K_BEEP)
-void (*mach_beep)(unsigned int, unsigned int);
-EXPORT_SYMBOL(mach_beep);
-#endif
 #if defined(CONFIG_ISA) && defined(MULTI_ISA)
 int isa_type;
 int isa_sex;
@@ -344,6 +340,8 @@ void __init setup_arch(char **cmdline_p)
 #ifdef CONFIG_COLDFIRE
        case MACH_M54XX:
        case MACH_M5441X:
+               cf_bootmem_alloc();
+               cf_mmu_context_init();
                config_BSP(NULL, 0);
                break;
 #endif
index 850f0dc284ca9e2e49f492e0a1954306f79c1028..c7ea6475ef9baf90707083f8cc6ab2451147d2d9 100644 (file)
@@ -37,7 +37,7 @@ void __init baboon_init(void)
        baboon = (struct baboon *) BABOON_BASE;
        baboon_present = 1;
 
-       printk("Baboon detected at %p\n", baboon);
+       pr_debug("Baboon detected at %p\n", baboon);
 }
 
 /*
index 22123f7e8f750c4c16fb456952810af9e777e415..16cd5cea52076d95908b790419a4344483411618 100644 (file)
@@ -898,8 +898,8 @@ static void __init mac_identify(void)
                mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize);
 
        iop_init();
-       via_init();
        oss_init();
+       via_init();
        psc_init();
        baboon_init();
 
index 4c1e606e7d03bd803f79e97fac1127ddacbc9da6..9bfa170157688f1b16859e04d2dd0d3dec10cda8 100644 (file)
@@ -273,10 +273,10 @@ void __init iop_init(void)
        int i;
 
        if (iop_scc_present) {
-               pr_info("IOP: detected SCC IOP at %p\n", iop_base[IOP_NUM_SCC]);
+               pr_debug("SCC IOP detected at %p\n", iop_base[IOP_NUM_SCC]);
        }
        if (iop_ism_present) {
-               pr_info("IOP: detected ISM IOP at %p\n", iop_base[IOP_NUM_ISM]);
+               pr_debug("ISM IOP detected at %p\n", iop_base[IOP_NUM_ISM]);
                iop_start(iop_base[IOP_NUM_ISM]);
                iop_alive(iop_base[IOP_NUM_ISM]); /* clears the alive flag */
        }
@@ -598,3 +598,12 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id)
        }
        return IRQ_HANDLED;
 }
+
+void iop_ism_irq_poll(uint iop_num)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       iop_ism_irq(0, (void *)iop_num);
+       local_irq_restore(flags);
+}
index fa2b9604fd24331415a0e8d29250028ff4216b43..d176686496410a5131047d02d345b40b8e4065b2 100644 (file)
@@ -57,7 +57,7 @@ static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int );
 /*
  * our timer to start/continue/stop the bell
  */
-static DEFINE_TIMER(mac_sound_timer, mac_nosound, 0, 0);
+static DEFINE_TIMER(mac_sound_timer, mac_nosound);
 
 /*
  * Sort of initialize the sound chip (called from mac_mksound on the first
index 34c0993dc689d07e097893c651ab2cdc18c780dc..3f81892527ad260fe6e0561c1ad71e071623a5e3 100644 (file)
@@ -32,18 +32,18 @@ volatile struct mac_oss *oss;
 
 /*
  * Initialize the OSS
- *
- * The OSS "detection" code is actually in via_init() which is always called
- * before us. Thus we can count on oss_present being valid on entry.
  */
 
 void __init oss_init(void)
 {
        int i;
 
-       if (!oss_present) return;
+       if (macintosh_config->ident != MAC_MODEL_IIFX)
+               return;
 
        oss = (struct mac_oss *) OSS_BASE;
+       pr_debug("OSS detected at %p", oss);
+       oss_present = 1;
 
        /* Disable all interrupts. Unlike a VIA it looks like we    */
        /* do this by setting the source's interrupt level to zero. */
@@ -52,14 +52,6 @@ void __init oss_init(void)
                oss->irq_level[i] = 0;
 }
 
-/*
- * Initialize OSS for Nubus access
- */
-
-void __init oss_nubus_init(void)
-{
-}
-
 /*
  * Handle miscellaneous OSS interrupts.
  */
index 439a2a2e58743d9686cc5e5290a6bebd5a979405..8d547df4e16c23c65be11a90c6ee65e2704ff972 100644 (file)
@@ -42,7 +42,7 @@ static void psc_debug_dump(void)
                return;
 
        for (i = 0x30 ; i < 0x70 ; i += 0x10) {
-               printk("PSC #%d:  IFR = 0x%02X IER = 0x%02X\n",
+               printk(KERN_DEBUG "PSC #%d:  IFR = 0x%02X IER = 0x%02X\n",
                        i >> 4,
                        (int) psc_read_byte(pIFRbase + i),
                        (int) psc_read_byte(pIERbase + i));
@@ -59,14 +59,12 @@ static __init void psc_dma_die_die_die(void)
 {
        int i;
 
-       printk("Killing all PSC DMA channels...");
        for (i = 0 ; i < 9 ; i++) {
                psc_write_word(PSC_CTL_BASE + (i << 4), 0x8800);
                psc_write_word(PSC_CTL_BASE + (i << 4), 0x1000);
                psc_write_word(PSC_CMD_BASE + (i << 5), 0x1100);
                psc_write_word(PSC_CMD_BASE + (i << 5) + 0x10, 0x1100);
        }
-       printk("done!\n");
 }
 
 /*
@@ -92,7 +90,7 @@ void __init psc_init(void)
 
        psc = (void *) PSC_BASE;
 
-       printk("PSC detected at %p\n", psc);
+       pr_debug("PSC detected at %p\n", psc);
 
        psc_dma_die_die_die();
 
index 9f59a662ace57dbc4b2dbfb7c0bb006216ec7e0f..acdabbeecfd2e3c9a82ad528f8d2c05d1a335980 100644 (file)
@@ -107,6 +107,7 @@ static int gIER,gIFR,gBufA,gBufB;
 static u8 nubus_disabled;
 
 void via_debug_dump(void);
+static void via_nubus_init(void);
 
 /*
  * Initialize the VIAs
@@ -114,29 +115,25 @@ void via_debug_dump(void);
  * First we figure out where they actually _are_ as well as what type of
  * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.)
  * Then we pretty much clear them out and disable all IRQ sources.
- *
- * Note: the OSS is actually "detected" here and not in oss_init(). It just
- *      seems more logical to do it here since via_init() needs to know
- *      these things anyways.
  */
 
 void __init via_init(void)
 {
-       switch(macintosh_config->via_type) {
+       via1 = (void *)VIA1_BASE;
+       pr_debug("VIA1 detected at %p\n", via1);
+
+       if (oss_present) {
+               via2 = NULL;
+               rbv_present = 0;
+       } else {
+               switch (macintosh_config->via_type) {
 
                /* IIci, IIsi, IIvx, IIvi (P6xx), LC series */
 
                case MAC_VIA_IICI:
-                       via1 = (void *) VIA1_BASE;
-                       if (macintosh_config->ident == MAC_MODEL_IIFX) {
-                               via2 = NULL;
-                               rbv_present = 0;
-                               oss_present = 1;
-                       } else {
-                               via2 = (void *) RBV_BASE;
-                               rbv_present = 1;
-                               oss_present = 0;
-                       }
+                       via2 = (void *)RBV_BASE;
+                       pr_debug("VIA2 (RBV) detected at %p\n", via2);
+                       rbv_present = 1;
                        if (macintosh_config->ident == MAC_MODEL_LCIII) {
                                rbv_clear = 0x00;
                        } else {
@@ -155,29 +152,19 @@ void __init via_init(void)
 
                case MAC_VIA_QUADRA:
                case MAC_VIA_II:
-                       via1 = (void *) VIA1_BASE;
                        via2 = (void *) VIA2_BASE;
+                       pr_debug("VIA2 detected at %p\n", via2);
                        rbv_present = 0;
-                       oss_present = 0;
                        rbv_clear = 0x00;
                        gIER = vIER;
                        gIFR = vIFR;
                        gBufA = vBufA;
                        gBufB = vBufB;
                        break;
+
                default:
                        panic("UNKNOWN VIA TYPE");
-       }
-
-       printk(KERN_INFO "VIA1 at %p is a 6522 or clone\n", via1);
-
-       printk(KERN_INFO "VIA2 at %p is ", via2);
-       if (rbv_present) {
-               printk("an RBV\n");
-       } else if (oss_present) {
-               printk("an OSS\n");
-       } else {
-               printk("a 6522 or clone\n");
+               }
        }
 
 #ifdef DEBUG_VIA
@@ -253,6 +240,8 @@ void __init via_init(void)
                via2[vACR] &= ~0x03; /* disable port A & B latches */
        }
 
+       via_nubus_init();
+
        /* Everything below this point is VIA2 only... */
 
        if (rbv_present)
@@ -304,9 +293,9 @@ void via_debug_dump(void)
                (uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
        printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
                (uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
-       if (oss_present) {
-               printk(KERN_DEBUG "VIA2: <OSS>\n");
-       } else if (rbv_present) {
+       if (!via2)
+               return;
+       if (rbv_present) {
                printk(KERN_DEBUG "VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
                        (uint) via2[rIFR], (uint) via2[rIER]);
                printk(KERN_DEBUG "      SIFR = 0x%02X SIER = 0x%02X\n",
@@ -374,7 +363,7 @@ int via_get_cache_disable(void)
  * Initialize VIA2 for Nubus access
  */
 
-void __init via_nubus_init(void)
+static void __init via_nubus_init(void)
 {
        /* unlock nubus transactions */
 
index 8d1408583cf42c96ce9a7f54b06f3dab862cf629..2925d795d71a2bff61796dd651ecbfe70ca6901f 100644 (file)
@@ -170,7 +170,7 @@ void __init cf_bootmem_alloc(void)
        max_pfn = max_low_pfn = PFN_DOWN(_ramend);
        high_memory = (void *)_ramend;
 
-       m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6;
+       m68k_virt_to_node_shift = fls(_ramend - 1) - 6;
        module_fixup(NULL, __start_fixup, __stop_fixup);
 
        /* setup bootmem data */
@@ -184,7 +184,7 @@ void __init cf_bootmem_alloc(void)
  * Initialize the context management stuff.
  * The following was taken from arch/ppc/mmu_context.c
  */
-void __init mmu_context_init(void)
+void __init cf_mmu_context_init(void)
 {
        /*
         * Some processors have too few contexts to reserve one for
index 349938c35f2dde38776610a0832bfdc8db0922aa..4497c232d9c1a311fb4d60bc403b05ed84557c00 100644 (file)
  * locked.
  */
 
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
-#define        arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define        arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SPINLOCK_H */
index 029935560b7f9d44c14899aebea028f0604a0f58..dfd780eab350420b803d11eb2061b13f9686aaa8 100644 (file)
@@ -137,21 +137,6 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
                      : "memory");
 }
 
-/* write_can_lock - would write_trylock() succeed? */
-static inline int arch_write_can_lock(arch_rwlock_t *rw)
-{
-       int ret;
-
-       asm volatile ("LNKGETD  %0, [%1]\n"
-                     "CMP      %0, #0\n"
-                     "MOV      %0, #1\n"
-                     "XORNZ     %0, %0, %0\n"
-                     : "=&d" (ret)
-                     : "da" (&rw->lock)
-                     : "cc");
-       return ret;
-}
-
 /*
  * Read locks are a bit more hairy:
  *  - Exclusively load the lock value.
@@ -225,26 +210,4 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
        return tmp;
 }
 
-/* read_can_lock - would read_trylock() succeed? */
-static inline int arch_read_can_lock(arch_rwlock_t *rw)
-{
-       int tmp;
-
-       asm volatile ("LNKGETD  %0, [%1]\n"
-                     "CMP      %0, %2\n"
-                     "MOV      %0, #1\n"
-                     "XORZ     %0, %0, %0\n"
-                     : "=&d" (tmp)
-                     : "da" (&rw->lock), "bd" (0x80000000)
-                     : "cc");
-       return tmp;
-}
-
-#define        arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define        arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SPINLOCK_LNKGET_H */
index 12de9862d19028c7a88dcc789a730960bd2d7c63..c0bd81bbe18c047b7e61bd82cfb5968f7e8fe4ce 100644 (file)
@@ -105,16 +105,6 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
        rw->lock = 0;
 }
 
-/* write_can_lock - would write_trylock() succeed? */
-static inline int arch_write_can_lock(arch_rwlock_t *rw)
-{
-       unsigned int ret;
-
-       barrier();
-       ret = rw->lock;
-       return (ret == 0);
-}
-
 /*
  * Read locks are a bit more hairy:
  *  - Exclusively load the lock value.
@@ -172,14 +162,4 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
        return (ret < 0x80000000);
 }
 
-/* read_can_lock - would read_trylock() succeed? */
-static inline int arch_read_can_lock(arch_rwlock_t *rw)
-{
-       unsigned int ret;
-
-       barrier();
-       ret = rw->lock;
-       return (ret < 0x80000000);
-}
-
 #endif /* __ASM_SPINLOCK_LOCK1_H */
index df7acea3747ad0b4547f3c67846215063d16d296..4674f1efbe7a597b0387936d79af53b3f62db6b5 100644 (file)
@@ -575,6 +575,7 @@ static int __init ar7_register_uarts(void)
        uart_port.type          = PORT_AR7;
        uart_port.uartclk       = clk_get_rate(bus_clk) / 2;
        uart_port.iotype        = UPIO_MEM32;
+       uart_port.flags         = UPF_FIXED_TYPE;
        uart_port.regshift      = 2;
 
        uart_port.line          = 0;
@@ -653,6 +654,10 @@ static int __init ar7_register_devices(void)
        u32 val;
        int res;
 
+       res = ar7_gpio_init();
+       if (res)
+               pr_warn("unable to register gpios: %d\n", res);
+
        res = ar7_register_uarts();
        if (res)
                pr_err("unable to setup uart(s): %d\n", res);
index 4fd83336131acf21bb09fba4070fe4b7ba471b63..dd53987a690ffdc12c5f87fd8ebade8d156faab5 100644 (file)
@@ -246,8 +246,6 @@ void __init prom_init(void)
        ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
        ar7_init_env((struct env_var *)fw_arg2);
        console_config();
-
-       ar7_gpio_init();
 }
 
 #define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
index a7d21da16b6a07eb6c63989ee4810e22e8e9aed1..ee81297d9117ef0b2e26e40619a2f4391e4ca80f 100644 (file)
 #include <asm/qrwlock.h>
 #include <asm/qspinlock.h>
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* _ASM_SPINLOCK_H */
index b7cd6cf77b83e9946f66bad049b02f5bb7f0407b..91bf0c2c265cbbe3e2e32ea596dabe22f8aa8662 100644 (file)
@@ -99,7 +99,7 @@ static inline u32 vdso_data_read_begin(const union mips_vdso_data *data)
        u32 seq;
 
        while (true) {
-               seq = ACCESS_ONCE(data->seq_count);
+               seq = READ_ONCE(data->seq_count);
                if (likely(!(seq & 1))) {
                        /* Paired with smp_wmb() in vdso_data_write_*(). */
                        smp_rmb();
index 9dd624c2fe567e9f4ad41f414704c98e265df1a1..421e06dfee728a973452c11e8b51a128efaae032 100644 (file)
@@ -166,7 +166,7 @@ int cps_pm_enter_state(enum cps_pm_state state)
        nc_core_ready_count = nc_addr;
 
        /* Ensure ready_count is zero-initialised before the assembly runs */
-       ACCESS_ONCE(*nc_core_ready_count) = 0;
+       WRITE_ONCE(*nc_core_ready_count, 0);
        coupled_barrier(&per_cpu(pm_barrier, core), online);
 
        /* Run the generated entry code */
index 406072e26752052c83b04ffacc254d901a668509..87dcac2447c8df20a572139d5053624e91acf2ca 100644 (file)
@@ -591,11 +591,11 @@ void __init bmips_cpu_setup(void)
 
                /* Flush and enable RAC */
                cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG);
-               __raw_writel(cfg | 0x100, BMIPS_RAC_CONFIG);
+               __raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG);
                __raw_readl(cbr + BMIPS_RAC_CONFIG);
 
                cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG);
-               __raw_writel(cfg | 0xf, BMIPS_RAC_CONFIG);
+               __raw_writel(cfg | 0xf, cbr + BMIPS_RAC_CONFIG);
                __raw_readl(cbr + BMIPS_RAC_CONFIG);
 
                cfg = __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE);
index d4f807191ecd74694075ba3ca2748ff0b80bcbb1..063de44675cefbd256dde16690f6070fac0725f7 100644 (file)
@@ -36,10 +36,10 @@ void mips_display_message(const char *str)
        }
 }
 
-static void scroll_display_message(unsigned long data);
-static DEFINE_TIMER(mips_scroll_timer, scroll_display_message, HZ, 0);
+static void scroll_display_message(unsigned long unused);
+static DEFINE_TIMER(mips_scroll_timer, scroll_display_message);
 
-static void scroll_display_message(unsigned long data)
+static void scroll_display_message(unsigned long unused)
 {
        mips_display_message(&display_string[display_count++]);
        if (display_count == max_display_count)
index 03a39ac5ead92e50d53cb4b0046686a568b68842..c374f3ceec38cf6ae5040e16665521ea69cefecf 100644 (file)
@@ -38,6 +38,7 @@
 #define PANIC_FREQ             (HZ / 8)
 
 static struct timer_list power_timer, blink_timer, debounce_timer;
+static unsigned long blink_timer_timeout;
 
 #define MACHINE_PANICED                1
 #define MACHINE_SHUTTING_DOWN  2
@@ -81,21 +82,21 @@ static void __noreturn sgi_machine_halt(void)
        ArcEnterInteractiveMode();
 }
 
-static void power_timeout(unsigned long data)
+static void power_timeout(struct timer_list *unused)
 {
        sgi_machine_power_off();
 }
 
-static void blink_timeout(unsigned long data)
+static void blink_timeout(struct timer_list *unused)
 {
        /* XXX fix this for fullhouse  */
        sgi_ioc_reset ^= (SGIOC_RESET_LC0OFF|SGIOC_RESET_LC1OFF);
        sgioc->reset = sgi_ioc_reset;
 
-       mod_timer(&blink_timer, jiffies + data);
+       mod_timer(&blink_timer, jiffies + blink_timer_timeout);
 }
 
-static void debounce(unsigned long data)
+static void debounce(struct timer_list *unused)
 {
        del_timer(&debounce_timer);
        if (sgint->istat1 & SGINT_ISTAT1_PWR) {
@@ -128,11 +129,10 @@ static inline void power_button(void)
        }
 
        machine_state |= MACHINE_SHUTTING_DOWN;
-       blink_timer.data = POWERDOWN_FREQ;
-       blink_timeout(POWERDOWN_FREQ);
+       blink_timer_timeout = POWERDOWN_FREQ;
+       blink_timeout(&blink_timer);
 
-       init_timer(&power_timer);
-       power_timer.function = power_timeout;
+       timer_setup(&power_timer, power_timeout, 0);
        power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
        add_timer(&power_timer);
 }
@@ -147,8 +147,7 @@ static irqreturn_t panel_int(int irq, void *dev_id)
        if (sgint->istat1 & SGINT_ISTAT1_PWR) {
                /* Wait until interrupt goes away */
                disable_irq_nosync(SGI_PANEL_IRQ);
-               init_timer(&debounce_timer);
-               debounce_timer.function = debounce;
+               timer_setup(&debounce_timer, debounce, 0);
                debounce_timer.expires = jiffies + 5;
                add_timer(&debounce_timer);
        }
@@ -171,8 +170,8 @@ static int panic_event(struct notifier_block *this, unsigned long event,
                return NOTIFY_DONE;
        machine_state |= MACHINE_PANICED;
 
-       blink_timer.data = PANIC_FREQ;
-       blink_timeout(PANIC_FREQ);
+       blink_timer_timeout = PANIC_FREQ;
+       blink_timeout(&blink_timer);
 
        return NOTIFY_DONE;
 }
@@ -195,8 +194,7 @@ static int __init reboot_setup(void)
                return res;
        }
 
-       init_timer(&blink_timer);
-       blink_timer.function = blink_timeout;
+       timer_setup(&blink_timer, blink_timeout, 0);
        atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
        return 0;
index b3b442def42383794289c6c07ea9a44ee5c4a873..20d8637340be40b4b96aa09f9c5f4b6d61436273 100644 (file)
@@ -38,6 +38,7 @@
 extern struct platform_device ip32_rtc_device;
 
 static struct timer_list power_timer, blink_timer;
+static unsigned long blink_timer_timeout;
 static int has_panicked, shutting_down;
 
 static __noreturn void ip32_poweroff(void *data)
@@ -71,11 +72,11 @@ static void ip32_machine_restart(char *cmd)
        unreachable();
 }
 
-static void blink_timeout(unsigned long data)
+static void blink_timeout(struct timer_list *unused)
 {
        unsigned long led = mace->perif.ctrl.misc ^ MACEISA_LED_RED;
        mace->perif.ctrl.misc = led;
-       mod_timer(&blink_timer, jiffies + data);
+       mod_timer(&blink_timer, jiffies + blink_timer_timeout);
 }
 
 static void ip32_machine_halt(void)
@@ -83,7 +84,7 @@ static void ip32_machine_halt(void)
        ip32_poweroff(&ip32_rtc_device);
 }
 
-static void power_timeout(unsigned long data)
+static void power_timeout(struct timer_list *unused)
 {
        ip32_poweroff(&ip32_rtc_device);
 }
@@ -99,11 +100,10 @@ void ip32_prepare_poweroff(void)
        }
 
        shutting_down = 1;
-       blink_timer.data = POWERDOWN_FREQ;
-       blink_timeout(POWERDOWN_FREQ);
+       blink_timer_timeout = POWERDOWN_FREQ;
+       blink_timeout(&blink_timer);
 
-       init_timer(&power_timer);
-       power_timer.function = power_timeout;
+       timer_setup(&power_timer, power_timeout, 0);
        power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
        add_timer(&power_timer);
 }
@@ -121,8 +121,8 @@ static int panic_event(struct notifier_block *this, unsigned long event,
        led = mace->perif.ctrl.misc | MACEISA_LED_GREEN;
        mace->perif.ctrl.misc = led;
 
-       blink_timer.data = PANIC_FREQ;
-       blink_timeout(PANIC_FREQ);
+       blink_timer_timeout = PANIC_FREQ;
+       blink_timeout(&blink_timer);
 
        return NOTIFY_DONE;
 }
@@ -143,8 +143,7 @@ static __init int ip32_reboot_setup(void)
        _machine_halt = ip32_machine_halt;
        pm_power_off = ip32_machine_halt;
 
-       init_timer(&blink_timer);
-       blink_timer.function = blink_timeout;
+       timer_setup(&blink_timer, blink_timeout, 0);
        atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 
        return 0;
index fe413b41df6cbbc50551f734d793e3b6c0c8d3d1..879cd0df53ba21c284a9ed2802a5e54566982aae 100644 (file)
@@ -84,6 +84,7 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *lock,
                : "d" (flags), "a"(&lock->slock), "i"(EPSW_IE | MN10300_CLI_LEVEL)
                : "memory", "cc");
 }
+#define arch_spin_lock_flags   arch_spin_lock_flags
 
 #ifdef __KERNEL__
 
@@ -98,18 +99,6 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *lock,
  * read-locks.
  */
 
-/**
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_read_can_lock(x) ((int)(x)->lock > 0)
-
-/**
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
-
 /*
  * On mn10300, we implement read-write locks as a 32-bit counter
  * with the high bit (sign) being the "contended" bit.
@@ -183,9 +172,6 @@ static inline int arch_write_trylock(arch_rwlock_t *lock)
        return 0;
 }
 
-#define arch_read_lock_flags(lock, flags)  arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
 #define _raw_spin_relax(lock)  cpu_relax()
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
index 7ecf69879e2d6ff077296a79605d8f367b70fdd4..d7ef1232a82a56da071ad58d0c9dc0b434430944 100644 (file)
@@ -543,7 +543,7 @@ static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
 
 try_again:
        /* pull chars out of the hat */
-       ix = ACCESS_ONCE(port->rx_outp);
+       ix = READ_ONCE(port->rx_outp);
        if (CIRC_CNT(port->rx_inp, ix, MNSC_BUFFER_SIZE) == 0) {
                if (push && !tport->low_latency)
                        tty_flip_buffer_push(tport);
@@ -1724,7 +1724,7 @@ static int mn10300_serial_poll_get_char(struct uart_port *_port)
        if (mn10300_serial_int_tbl[port->rx_irq].port != NULL) {
                do {
                        /* pull chars out of the hat */
-                       ix = ACCESS_ONCE(port->rx_outp);
+                       ix = READ_ONCE(port->rx_outp);
                        if (CIRC_CNT(port->rx_inp, ix, MNSC_BUFFER_SIZE) == 0)
                                return NO_POLL_CHAR;
 
index df2136ab1dcca223481ad65633368a8cf037359a..339df7324e9c2004bf0b182fc274b4f5c1497d54 100644 (file)
@@ -22,13 +22,19 @@ config OPENRISC
        select HAVE_UID16
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
+       select GENERIC_CLOCKEVENTS_BROADCAST
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
+       select GENERIC_SMP_IDLE_THREAD
        select MODULES_USE_ELF_RELA
        select HAVE_DEBUG_STACKOVERFLOW
        select OR1K_PIC
        select CPU_NO_EFFICIENT_FFS if !OPENRISC_HAVE_INST_FF1
        select NO_BOOTMEM
+       select ARCH_USE_QUEUED_SPINLOCKS
+       select ARCH_USE_QUEUED_RWLOCKS
+       select OMPIC if SMP
+       select ARCH_WANT_FRAME_POINTERS
 
 config CPU_BIG_ENDIAN
        def_bool y
@@ -56,6 +62,12 @@ config TRACE_IRQFLAGS_SUPPORT
 config GENERIC_CSUM
         def_bool y
 
+config STACKTRACE_SUPPORT
+       def_bool y
+
+config LOCKDEP_SUPPORT
+       def_bool  y
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
@@ -73,6 +85,17 @@ config OR1K_1200
 
 endchoice
 
+config DCACHE_WRITETHROUGH
+       bool "Have write through data caches"
+       default n
+       help
+         Select this if your implementation features write through data caches.
+         Selecting 'N' here will allow the kernel to force flushing of data
+         caches at relevant times. Most OpenRISC implementations support write-
+         through data caches.
+
+         If unsure say N here
+
 config OPENRISC_BUILTIN_DTB
         string "Builtin DTB"
         default ""
@@ -105,8 +128,19 @@ config OPENRISC_HAVE_INST_DIV
 endmenu
 
 config NR_CPUS
-       int
-       default "1"
+       int "Maximum number of CPUs (2-32)"
+       range 2 32
+       depends on SMP
+       default "2"
+
+config SMP
+       bool "Symmetric Multi-Processing support"
+       help
+         This enables support for systems with more than one CPU. If you have
+         a system with only one CPU, say N. If you have a system with more
+         than one CPU, say Y.
+
+         If you don't know what to do here, say N.
 
 source kernel/Kconfig.hz
 source kernel/Kconfig.preempt
@@ -125,6 +159,17 @@ config OPENRISC_NO_SPR_SR_DSX
          Say N here if you know that your OpenRISC processor has
          SPR_SR_DSX bit implemented. Say Y if you are unsure.
 
+config OPENRISC_HAVE_SHADOW_GPRS
+       bool "Support for shadow gpr files" if !SMP
+       default y if SMP
+       help
+         Say Y here if your OpenRISC processor features shadowed
+         register files. They will in such case be used as a
+         scratch reg storage on exception entry.
+
+         On SMP systems, this feature is mandatory.
+         On a unicore system it's safe to say N here if you are unsure.
+
 config CMDLINE
         string "Default kernel command string"
         default ""
index 89076a66eee266d79782949f93a9cbba30371b1a..cf88029628643b1120b15407eab08e50f44886fc 100644 (file)
@@ -25,6 +25,7 @@ LDFLAGS_vmlinux :=
 LIBGCC                 := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 
 KBUILD_CFLAGS  += -pipe -ffixed-r10 -D__linux__
+CHECKFLAGS     += -mbig-endian
 
 ifeq ($(CONFIG_OPENRISC_HAVE_INST_MUL),y)
        KBUILD_CFLAGS += $(call cc-option,-mhard-mul)
index 9f4b856da5805db4c01b42ba387f3c913536a426..d8aa8309c9d30981c9129b8610fd4b306e884f8d 100644 (file)
@@ -6,8 +6,13 @@
        #size-cells = <1>;
        interrupt-parent = <&pic>;
 
+       aliases {
+               uart0 = &serial0;
+       };
+
        chosen {
-               bootargs = "console=uart,mmio,0x90000000,115200";
+               bootargs = "earlycon";
+               stdout-path = "uart0:115200";
        };
 
        memory@0 {
diff --git a/arch/openrisc/boot/dts/simple_smp.dts b/arch/openrisc/boot/dts/simple_smp.dts
new file mode 100644 (file)
index 0000000..defbb92
--- /dev/null
@@ -0,0 +1,63 @@
+/dts-v1/;
+/ {
+       compatible = "opencores,or1ksim";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&pic>;
+
+       aliases {
+               uart0 = &serial0;
+       };
+
+       chosen {
+               bootargs = "earlycon";
+               stdout-path = "uart0:115200";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x02000000>;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cpu@0 {
+                       compatible = "opencores,or1200-rtlsvn481";
+                       reg = <0>;
+                       clock-frequency = <20000000>;
+               };
+               cpu@1 {
+                       compatible = "opencores,or1200-rtlsvn481";
+                       reg = <1>;
+                       clock-frequency = <20000000>;
+               };
+       };
+
+       ompic: ompic@98000000 {
+               compatible = "openrisc,ompic";
+               reg = <0x98000000 16>;
+               interrupt-controller;
+               #interrupt-cells = <0>;
+               interrupts = <1>;
+       };
+
+       /*
+        * OR1K PIC is built into CPU and accessed via special purpose
+        * registers.  It is not addressable and, hence, has no 'reg'
+        * property.
+        */
+       pic: pic {
+               compatible = "opencores,or1k-pic-level";
+               #interrupt-cells = <1>;
+               interrupt-controller;
+       };
+
+       serial0: serial@90000000 {
+               compatible = "opencores,uart16550-rtlsvn105", "ns16550a";
+               reg = <0x90000000 0x100>;
+               interrupts = <2>;
+               clock-frequency = <20000000>;
+       };
+
+};
diff --git a/arch/openrisc/configs/simple_smp_defconfig b/arch/openrisc/configs/simple_smp_defconfig
new file mode 100644 (file)
index 0000000..b6e3c7e
--- /dev/null
@@ -0,0 +1,66 @@
+CONFIG_CROSS_COMPILE="or1k-linux-"
+CONFIG_LOCALVERSION="-simple-smp"
+CONFIG_NO_HZ=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_EXPERT=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_EPOLL is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+CONFIG_MODULES=y
+# CONFIG_BLOCK is not set
+CONFIG_OPENRISC_BUILTIN_DTB="simple_smp"
+CONFIG_SMP=y
+CONFIG_HZ_100=y
+CONFIG_OPENRISC_HAVE_SHADOW_GPRS=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_CUBIC is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_NETDEVICES=y
+CONFIG_ETHOC=y
+CONFIG_MICREL_PHY=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_XZ_DEC=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_RCU_TRACE is not set
index 5bea416a779270713ea614d3260e8f16fb0c766a..6eb16719549e49eaecc9febe46b071081d50cc98 100644 (file)
@@ -1,7 +1,6 @@
 generic-y += barrier.h
 generic-y += bug.h
 generic-y += bugs.h
-generic-y += cacheflush.h
 generic-y += checksum.h
 generic-y += clkdev.h
 generic-y += current.h
@@ -28,6 +27,10 @@ generic-y += module.h
 generic-y += pci.h
 generic-y += percpu.h
 generic-y += preempt.h
+generic-y += qspinlock_types.h
+generic-y += qspinlock.h
+generic-y += qrwlock_types.h
+generic-y += qrwlock.h
 generic-y += sections.h
 generic-y += segment.h
 generic-y += string.h
diff --git a/arch/openrisc/include/asm/cacheflush.h b/arch/openrisc/include/asm/cacheflush.h
new file mode 100644 (file)
index 0000000..70f46fd
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * OpenRISC Linux
+ *
+ * Linux architectural port borrowing liberally from similar works of
+ * others.  All original copyrights apply as per the original source
+ * declaration.
+ *
+ * OpenRISC implementation:
+ * Copyright (C) Jan Henrik Weinstock <jan.weinstock@rwth-aachen.de>
+ * et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __ASM_CACHEFLUSH_H
+#define __ASM_CACHEFLUSH_H
+
+#include <linux/mm.h>
+
+/*
+ * Helper function for flushing or invalidating entire pages from data
+ * and instruction caches. SMP needs a little extra work, since we need
+ * to flush the pages on all cpus.
+ */
+extern void local_dcache_page_flush(struct page *page);
+extern void local_icache_page_inv(struct page *page);
+
+/*
+ * Data cache flushing always happen on the local cpu. Instruction cache
+ * invalidations need to be broadcasted to all other cpu in the system in
+ * case of SMP configurations.
+ */
+#ifndef CONFIG_SMP
+#define dcache_page_flush(page)      local_dcache_page_flush(page)
+#define icache_page_inv(page)        local_icache_page_inv(page)
+#else  /* CONFIG_SMP */
+#define dcache_page_flush(page)      local_dcache_page_flush(page)
+#define icache_page_inv(page)        smp_icache_page_inv(page)
+extern void smp_icache_page_inv(struct page *page);
+#endif /* CONFIG_SMP */
+
+/*
+ * Synchronizes caches. Whenever a cpu writes executable code to memory, this
+ * should be called to make sure the processor sees the newly written code.
+ */
+static inline void sync_icache_dcache(struct page *page)
+{
+       if (!IS_ENABLED(CONFIG_DCACHE_WRITETHROUGH))
+               dcache_page_flush(page);
+       icache_page_inv(page);
+}
+
+/*
+ * Pages with this bit set need not be flushed/invalidated, since
+ * they have not changed since last flush. New pages start with
+ * PG_arch_1 not set and are therefore dirty by default.
+ */
+#define PG_dc_clean                  PG_arch_1
+
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
+static inline void flush_dcache_page(struct page *page)
+{
+       clear_bit(PG_dc_clean, &page->flags);
+}
+
+/*
+ * Other interfaces are not required since we do not have virtually
+ * indexed or tagged caches. So we can use the default here.
+ */
+#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 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)
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len)           \
+       do {                                                         \
+               memcpy(dst, src, len);                               \
+               if (vma->vm_flags & VM_EXEC)                         \
+                       sync_icache_dcache(page);                    \
+       } while (0)
+
+#define copy_from_user_page(vma, page, vaddr, dst, src, len)         \
+       memcpy(dst, src, len)
+
+#endif /* __ASM_CACHEFLUSH_H */
index f0a5d8b844d6b85b16eb6c170f8af86f73ad8440..d29f7db53906b77d19dd920ad98bb37e41b45e4a 100644 (file)
@@ -1,32 +1,29 @@
 /*
+ * 1,2 and 4 byte cmpxchg and xchg implementations for OpenRISC.
+ *
  * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
  *
  * This file is licensed under the terms of the GNU General Public License
  * version 2.  This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
+ *
+ * Note:
+ * The portable implementations of 1 and 2 byte xchg and cmpxchg using a 4
+ * byte cmpxchg is sourced heavily from the sh and mips implementations.
  */
 
 #ifndef __ASM_OPENRISC_CMPXCHG_H
 #define __ASM_OPENRISC_CMPXCHG_H
 
 #include  <linux/types.h>
-
-/*
- * This function doesn't exist, so you'll get a linker error
- * if something tries to do an invalid cmpxchg().
- */
-extern void __cmpxchg_called_with_bad_pointer(void);
+#include  <linux/bitops.h>
 
 #define __HAVE_ARCH_CMPXCHG 1
 
-static inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+static inline unsigned long cmpxchg_u32(volatile void *ptr,
+               unsigned long old, unsigned long new)
 {
-       if (size != 4) {
-               __cmpxchg_called_with_bad_pointer();
-               return old;
-       }
-
        __asm__ __volatile__(
                "1:     l.lwa %0, 0(%1)         \n"
                "       l.sfeq %0, %2           \n"
@@ -43,6 +40,97 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
        return old;
 }
 
+static inline unsigned long xchg_u32(volatile void *ptr,
+               unsigned long val)
+{
+       __asm__ __volatile__(
+               "1:     l.lwa %0, 0(%1)         \n"
+               "       l.swa 0(%1), %2         \n"
+               "       l.bnf 1b                \n"
+               "        l.nop                  \n"
+               : "=&r"(val)
+               : "r"(ptr), "r"(val)
+               : "cc", "memory");
+
+       return val;
+}
+
+static inline u32 cmpxchg_small(volatile void *ptr, u32 old, u32 new,
+                               int size)
+{
+       int off = (unsigned long)ptr % sizeof(u32);
+       volatile u32 *p = ptr - off;
+#ifdef __BIG_ENDIAN
+       int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
+#else
+       int bitoff = off * BITS_PER_BYTE;
+#endif
+       u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
+       u32 load32, old32, new32;
+       u32 ret;
+
+       load32 = READ_ONCE(*p);
+
+       while (true) {
+               ret = (load32 & bitmask) >> bitoff;
+               if (old != ret)
+                       return ret;
+
+               old32 = (load32 & ~bitmask) | (old << bitoff);
+               new32 = (load32 & ~bitmask) | (new << bitoff);
+
+               /* Do 32 bit cmpxchg */
+               load32 = cmpxchg_u32(p, old32, new32);
+               if (load32 == old32)
+                       return old;
+       }
+}
+
+/* xchg */
+
+static inline u32 xchg_small(volatile void *ptr, u32 x, int size)
+{
+       int off = (unsigned long)ptr % sizeof(u32);
+       volatile u32 *p = ptr - off;
+#ifdef __BIG_ENDIAN
+       int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
+#else
+       int bitoff = off * BITS_PER_BYTE;
+#endif
+       u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
+       u32 oldv, newv;
+       u32 ret;
+
+       do {
+               oldv = READ_ONCE(*p);
+               ret = (oldv & bitmask) >> bitoff;
+               newv = (oldv & ~bitmask) | (x << bitoff);
+       } while (cmpxchg_u32(p, oldv, newv) != oldv);
+
+       return ret;
+}
+
+/*
+ * This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg().
+ */
+extern unsigned long __cmpxchg_called_with_bad_pointer(void)
+       __compiletime_error("Bad argument size for cmpxchg");
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+               unsigned long new, int size)
+{
+       switch (size) {
+       case 1:
+       case 2:
+               return cmpxchg_small(ptr, old, new, size);
+       case 4:
+               return cmpxchg_u32(ptr, old, new);
+       default:
+               return __cmpxchg_called_with_bad_pointer();
+       }
+}
+
 #define cmpxchg(ptr, o, n)                                             \
        ({                                                              \
                (__typeof__(*(ptr))) __cmpxchg((ptr),                   \
@@ -55,32 +143,27 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
  * This function doesn't exist, so you'll get a linker error if
  * something tries to do an invalidly-sized xchg().
  */
-extern void __xchg_called_with_bad_pointer(void);
+extern unsigned long __xchg_called_with_bad_pointer(void)
+       __compiletime_error("Bad argument size for xchg");
 
-static inline unsigned long __xchg(unsigned long val, volatile void *ptr,
-                                  int size)
+static inline unsigned long __xchg(volatile void *ptr, unsigned long with,
+               int size)
 {
-       if (size != 4) {
-               __xchg_called_with_bad_pointer();
-               return val;
+       switch (size) {
+       case 1:
+       case 2:
+               return xchg_small(ptr, with, size);
+       case 4:
+               return xchg_u32(ptr, with);
+       default:
+               return __xchg_called_with_bad_pointer();
        }
-
-       __asm__ __volatile__(
-               "1:     l.lwa %0, 0(%1)         \n"
-               "       l.swa 0(%1), %2         \n"
-               "       l.bnf 1b                \n"
-               "        l.nop                  \n"
-               : "=&r"(val)
-               : "r"(ptr), "r"(val)
-               : "cc", "memory");
-
-       return val;
 }
 
 #define xchg(ptr, with)                                                \
        ({                                                              \
-               (__typeof__(*(ptr))) __xchg((unsigned long)(with),      \
-                                           (ptr),                      \
+               (__typeof__(*(ptr))) __xchg((ptr),                      \
+                                           (unsigned long)(with),      \
                                            sizeof(*(ptr)));            \
        })
 
index ec10679d6429d5f67bf43f77e990c6eecf0a004f..4ea0a33eba6c3f493e4a94f45565c9068dfd1be7 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef __ASM_OPENRISC_CPUINFO_H
 #define __ASM_OPENRISC_CPUINFO_H
 
-struct cpuinfo {
+struct cpuinfo_or1k {
        u32 clock_frequency;
 
        u32 icache_size;
@@ -29,8 +29,11 @@ struct cpuinfo {
        u32 dcache_size;
        u32 dcache_block_size;
        u32 dcache_ways;
+
+       u16 coreid;
 };
 
-extern struct cpuinfo cpuinfo;
+extern struct cpuinfo_or1k cpuinfo_or1k[NR_CPUS];
+extern void setup_cpuinfo(void);
 
 #endif /* __ASM_OPENRISC_CPUINFO_H */
index e94b814d2e3c4181561404550215e23d38e42147..c380d8caf84f6f1149b0925817fb0a7f27062562 100644 (file)
@@ -34,7 +34,7 @@ extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,
  * registers like cr3 on the i386
  */
 
-extern volatile pgd_t *current_pgd;   /* defined in arch/openrisc/mm/fault.c */
+extern volatile pgd_t *current_pgd[]; /* defined in arch/openrisc/mm/fault.c */
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
index 71a6f08de8f21a896f955f7a95792b7e62054a3a..21c71303012f7a17796a0f7961459da4453c59fb 100644 (file)
@@ -94,7 +94,7 @@ extern void paging_init(void);
  * 64 MB of vmalloc area is comparable to what's available on other arches.
  */
 
-#define VMALLOC_START  (PAGE_OFFSET-0x04000000)
+#define VMALLOC_START  (PAGE_OFFSET-0x04000000UL)
 #define VMALLOC_END    (PAGE_OFFSET)
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 
@@ -416,15 +416,19 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */
 
 struct vm_area_struct;
 
-/*
- * or32 doesn't have any external MMU info: the kernel page
- * tables contain all the necessary information.
- *
- * Actually I am not sure on what this could be used for.
- */
+static inline void update_tlb(struct vm_area_struct *vma,
+       unsigned long address, pte_t *pte)
+{
+}
+
+extern void update_cache(struct vm_area_struct *vma,
+       unsigned long address, pte_t *pte);
+
 static inline void update_mmu_cache(struct vm_area_struct *vma,
        unsigned long address, pte_t *pte)
 {
+       update_tlb(vma, address, pte);
+       update_cache(vma, address, pte);
 }
 
 /* __PHX__ FIXME, SWAP, this probably doesn't work */
index 270a45241639c6899ec43d5e52a577d93241ffa7..cb5932f5447a2cbeb08ba59bf399e92491171172 100644 (file)
@@ -29,7 +29,7 @@
  * it needs to be correct to get the early console working.
  */
 
-#define BASE_BAUD (cpuinfo.clock_frequency/16)
+#define BASE_BAUD (cpuinfo_or1k[smp_processor_id()].clock_frequency/16)
 
 #endif /* __KERNEL__ */
 
diff --git a/arch/openrisc/include/asm/smp.h b/arch/openrisc/include/asm/smp.h
new file mode 100644 (file)
index 0000000..e21d2f1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ *
+ * 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.
+ */
+
+#ifndef __ASM_OPENRISC_SMP_H
+#define __ASM_OPENRISC_SMP_H
+
+#include <asm/spr.h>
+#include <asm/spr_defs.h>
+
+#define raw_smp_processor_id() (current_thread_info()->cpu)
+#define hard_smp_processor_id()        mfspr(SPR_COREID)
+
+extern void smp_init_cpus(void);
+
+extern void arch_send_call_function_single_ipi(int cpu);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+
+extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int));
+extern void handle_IPI(unsigned int ipi_msg);
+
+#endif /* __ASM_OPENRISC_SMP_H */
index fd00a3a24123e7efd7359beed04ae7ff2894af95..9b761e0e22c358230b7d6a305281988a142cb6a8 100644 (file)
 #ifndef __ASM_OPENRISC_SPINLOCK_H
 #define __ASM_OPENRISC_SPINLOCK_H
 
-#error "or32 doesn't do SMP yet"
+#include <asm/qspinlock.h>
+
+#include <asm/qrwlock.h>
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#define arch_spin_relax(lock)  cpu_relax()
+#define arch_read_relax(lock)  cpu_relax()
+#define arch_write_relax(lock) cpu_relax()
+
 
 #endif
diff --git a/arch/openrisc/include/asm/spinlock_types.h b/arch/openrisc/include/asm/spinlock_types.h
new file mode 100644 (file)
index 0000000..7c6fb12
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _ASM_OPENRISC_SPINLOCK_TYPES_H
+#define _ASM_OPENRISC_SPINLOCK_TYPES_H
+
+#include <asm/qspinlock_types.h>
+#include <asm/qrwlock_types.h>
+
+#endif /* _ASM_OPENRISC_SPINLOCK_TYPES_H */
index 367dac70326af01731e8d841fa8fd5ce49c36222..154b5a1ee579ae891a8bd4d92707a153def0b56b 100644 (file)
 #define SPR_ICCFGR     (SPRGROUP_SYS + 6)
 #define SPR_DCFGR      (SPRGROUP_SYS + 7)
 #define SPR_PCCFGR     (SPRGROUP_SYS + 8)
+#define SPR_VR2                (SPRGROUP_SYS + 9)
+#define SPR_AVR                (SPRGROUP_SYS + 10)
+#define SPR_EVBAR      (SPRGROUP_SYS + 11)
+#define SPR_AECR       (SPRGROUP_SYS + 12)
+#define SPR_AESR       (SPRGROUP_SYS + 13)
 #define SPR_NPC         (SPRGROUP_SYS + 16)  /* CZ 21/06/01 */
 #define SPR_SR         (SPRGROUP_SYS + 17)  /* CZ 21/06/01 */
 #define SPR_PPC         (SPRGROUP_SYS + 18)  /* CZ 21/06/01 */
@@ -61,6 +66,8 @@
 #define SPR_EEAR_LAST  (SPRGROUP_SYS + 63)
 #define SPR_ESR_BASE   (SPRGROUP_SYS + 64)
 #define SPR_ESR_LAST   (SPRGROUP_SYS + 79)
+#define SPR_COREID     (SPRGROUP_SYS + 128)
+#define SPR_NUMCORES   (SPRGROUP_SYS + 129)
 #define SPR_GPR_BASE   (SPRGROUP_SYS + 1024)
 
 /* Data MMU group */
 #define SPR_VR_CFG     0x00ff0000  /* Processor configuration */
 #define SPR_VR_RES     0x0000ffc0  /* Reserved */
 #define SPR_VR_REV     0x0000003f  /* Processor revision */
+#define SPR_VR_UVRP    0x00000040  /* Updated Version Registers Present */
 
 #define SPR_VR_VER_OFF 24
 #define SPR_VR_CFG_OFF 16
 #define SPR_VR_REV_OFF 0
 
+/*
+ * Bit definitions for the Version Register 2
+ */
+#define SPR_VR2_CPUID  0xff000000  /* Processor ID */
+#define SPR_VR2_VER    0x00ffffff  /* Processor version */
+
 /*
  * Bit definitions for the Unit Present Register
  *
index 6e619a79a4010bf63767205c289d841a567ae124..c229aa6bb502b744e748d2e37aeff7625a19ce47 100644 (file)
@@ -74,7 +74,7 @@ struct thread_info {
        .task           = &tsk,                         \
        .flags          = 0,                            \
        .cpu            = 0,                            \
-       .preempt_count  = 1,                            \
+       .preempt_count  = INIT_PREEMPT_COUNT,           \
        .addr_limit     = KERNEL_DS,                    \
        .ksp            = 0,                            \
 }
diff --git a/arch/openrisc/include/asm/time.h b/arch/openrisc/include/asm/time.h
new file mode 100644 (file)
index 0000000..313ee97
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * OpenRISC timer API
+ *
+ * Copyright (C) 2017 by Stafford Horne (shorne@gmail.com)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __ASM_OR1K_TIME_H
+#define __ASM_OR1K_TIME_H
+
+extern void openrisc_clockevent_init(void);
+
+extern void openrisc_timer_set(unsigned long count);
+extern void openrisc_timer_set_next(unsigned long delta);
+
+#ifdef CONFIG_SMP
+extern void synchronise_count_master(int cpu);
+extern void synchronise_count_slave(int cpu);
+#endif
+
+#endif /* __ASM_OR1K_TIME_H */
index 6a2accd6cb6735da35b084078ee0c4a4383436a3..94227f0eaf6da5c0aa85b8f49548984831c0a1bd 100644 (file)
  *  - flush_tlb_page(vma, vmaddr) flushes one page
  *  - flush_tlb_range(mm, start, end) flushes a range of pages
  */
+extern void local_flush_tlb_all(void);
+extern void local_flush_tlb_mm(struct mm_struct *mm);
+extern void local_flush_tlb_page(struct vm_area_struct *vma,
+                                unsigned long addr);
+extern void local_flush_tlb_range(struct vm_area_struct *vma,
+                                 unsigned long start,
+                                 unsigned long end);
 
-void flush_tlb_all(void);
-void flush_tlb_mm(struct mm_struct *mm);
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
-void flush_tlb_range(struct vm_area_struct *vma,
-                    unsigned long start,
-                    unsigned long end);
+#ifndef CONFIG_SMP
+#define flush_tlb_all  local_flush_tlb_all
+#define flush_tlb_mm   local_flush_tlb_mm
+#define flush_tlb_page local_flush_tlb_page
+#define flush_tlb_range        local_flush_tlb_range
+#else
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                           unsigned long end);
+#endif
 
 static inline void flush_tlb(void)
 {
diff --git a/arch/openrisc/include/asm/unwinder.h b/arch/openrisc/include/asm/unwinder.h
new file mode 100644 (file)
index 0000000..165ec6f
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * OpenRISC unwinder.h
+ *
+ * Architecture API for unwinding stacks.
+ *
+ * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __ASM_OPENRISC_UNWINDER_H
+#define __ASM_OPENRISC_UNWINDER_H
+
+void unwind_stack(void *data, unsigned long *stack,
+                 void (*trace)(void *data, unsigned long addr,
+                               int reliable));
+
+#endif /* __ASM_OPENRISC_UNWINDER_H */
index c4ea6cabad4623fc3e65f78121ecefaa49f61edb..2d172e79f58d014f344446d8849bb7645dfabd7a 100644 (file)
@@ -7,8 +7,10 @@ extra-y        := head.o vmlinux.lds
 
 obj-y  := setup.o or32_ksyms.o process.o dma.o \
           traps.o time.o irq.o entry.o ptrace.o signal.o \
-          sys_call_table.o
+          sys_call_table.o unwinder.o
 
+obj-$(CONFIG_SMP)              += smp.o sync-timer.o
+obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_OF)               += prom.o
 
index b10369b7e31b287796482fe65d83e89ed97e1d33..a945f00011b426e501bf2ac1e2bce398a78a7487 100644 (file)
@@ -32,6 +32,7 @@ page_set_nocache(pte_t *pte, unsigned long addr,
                 unsigned long next, struct mm_walk *walk)
 {
        unsigned long cl;
+       struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
 
        pte_val(*pte) |= _PAGE_CI;
 
@@ -42,7 +43,7 @@ page_set_nocache(pte_t *pte, unsigned long addr,
        flush_tlb_page(NULL, addr);
 
        /* Flush page out of dcache */
-       for (cl = __pa(addr); cl < __pa(next); cl += cpuinfo.dcache_block_size)
+       for (cl = __pa(addr); cl < __pa(next); cl += cpuinfo->dcache_block_size)
                mtspr(SPR_DCBFR, cl);
 
        return 0;
@@ -140,6 +141,7 @@ or1k_map_page(struct device *dev, struct page *page,
 {
        unsigned long cl;
        dma_addr_t addr = page_to_phys(page) + offset;
+       struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
 
        if (attrs & DMA_ATTR_SKIP_CPU_SYNC)
                return addr;
@@ -148,13 +150,13 @@ or1k_map_page(struct device *dev, struct page *page,
        case DMA_TO_DEVICE:
                /* Flush the dcache for the requested range */
                for (cl = addr; cl < addr + size;
-                    cl += cpuinfo.dcache_block_size)
+                    cl += cpuinfo->dcache_block_size)
                        mtspr(SPR_DCBFR, cl);
                break;
        case DMA_FROM_DEVICE:
                /* Invalidate the dcache for the requested range */
                for (cl = addr; cl < addr + size;
-                    cl += cpuinfo.dcache_block_size)
+                    cl += cpuinfo->dcache_block_size)
                        mtspr(SPR_DCBIR, cl);
                break;
        default:
@@ -213,9 +215,10 @@ or1k_sync_single_for_cpu(struct device *dev,
 {
        unsigned long cl;
        dma_addr_t addr = dma_handle;
+       struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
 
        /* Invalidate the dcache for the requested range */
-       for (cl = addr; cl < addr + size; cl += cpuinfo.dcache_block_size)
+       for (cl = addr; cl < addr + size; cl += cpuinfo->dcache_block_size)
                mtspr(SPR_DCBIR, cl);
 }
 
@@ -226,9 +229,10 @@ or1k_sync_single_for_device(struct device *dev,
 {
        unsigned long cl;
        dma_addr_t addr = dma_handle;
+       struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
 
        /* Flush the dcache for the requested range */
-       for (cl = addr; cl < addr + size; cl += cpuinfo.dcache_block_size)
+       for (cl = addr; cl < addr + size; cl += cpuinfo->dcache_block_size)
                mtspr(SPR_DCBFR, cl);
 }
 
index 1b7160c79646be4e136d0f813b4b55c0bfd63827..690d55272ba688a2adc88bca00e66cc61903c711 100644 (file)
 
 /* =========================================================[ macros ]=== */
 
+#ifdef CONFIG_TRACE_IRQFLAGS
+/*
+ * Trace irq on/off creating a stack frame.
+ */
+#define TRACE_IRQS_OP(trace_op)                                        \
+       l.sw    -8(r1),r2       /* store frame pointer */               ;\
+       l.sw    -4(r1),r9       /* store return address */              ;\
+       l.addi  r2,r1,0         /* move sp to fp */                     ;\
+       l.jal   trace_op                                                ;\
+        l.addi r1,r1,-8                                                ;\
+       l.ori   r1,r2,0         /* restore sp */                        ;\
+       l.lwz   r9,-4(r1)       /* restore return address */            ;\
+       l.lwz   r2,-8(r1)       /* restore fp */                        ;\
+/*
+ * Trace irq on/off and save registers we need that would otherwise be
+ * clobbered.
+ */
+#define TRACE_IRQS_SAVE(t1,trace_op)                                   \
+       l.sw    -12(r1),t1      /* save extra reg */                    ;\
+       l.sw    -8(r1),r2       /* store frame pointer */               ;\
+       l.sw    -4(r1),r9       /* store return address */              ;\
+       l.addi  r2,r1,0         /* move sp to fp */                     ;\
+       l.jal   trace_op                                                ;\
+        l.addi r1,r1,-12                                               ;\
+       l.ori   r1,r2,0         /* restore sp */                        ;\
+       l.lwz   r9,-4(r1)       /* restore return address */            ;\
+       l.lwz   r2,-8(r1)       /* restore fp */                        ;\
+       l.lwz   t1,-12(r1)      /* restore extra reg */
+
+#define TRACE_IRQS_OFF TRACE_IRQS_OP(trace_hardirqs_off)
+#define TRACE_IRQS_ON  TRACE_IRQS_OP(trace_hardirqs_on)
+#define TRACE_IRQS_ON_SYSCALL                                          \
+       TRACE_IRQS_SAVE(r10,trace_hardirqs_on)                          ;\
+       l.lwz   r3,PT_GPR3(r1)                                          ;\
+       l.lwz   r4,PT_GPR4(r1)                                          ;\
+       l.lwz   r5,PT_GPR5(r1)                                          ;\
+       l.lwz   r6,PT_GPR6(r1)                                          ;\
+       l.lwz   r7,PT_GPR7(r1)                                          ;\
+       l.lwz   r8,PT_GPR8(r1)                                          ;\
+       l.lwz   r11,PT_GPR11(r1)
+#define TRACE_IRQS_OFF_ENTRY                                           \
+       l.lwz   r5,PT_SR(r1)                                            ;\
+       l.andi  r3,r5,(SPR_SR_IEE|SPR_SR_TEE)                           ;\
+       l.sfeq  r5,r0           /* skip trace if irqs were already off */;\
+       l.bf    1f                                                      ;\
+        l.nop                                                          ;\
+       TRACE_IRQS_SAVE(r4,trace_hardirqs_off)                          ;\
+1:
+#else
+#define TRACE_IRQS_OFF
+#define TRACE_IRQS_ON
+#define TRACE_IRQS_OFF_ENTRY
+#define TRACE_IRQS_ON_SYSCALL
+#endif
+
 /*
  * We need to disable interrupts at beginning of RESTORE_ALL
  * since interrupt might come in after we've loaded EPC return address
@@ -124,6 +179,7 @@ handler:                                                    ;\
        /* r30 already save */                                  ;\
 /*        l.sw    PT_GPR30(r1),r30*/                                   ;\
        l.sw    PT_GPR31(r1),r31                                        ;\
+       TRACE_IRQS_OFF_ENTRY                                            ;\
        /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
        l.addi  r30,r0,-1                                       ;\
        l.sw    PT_ORIG_GPR11(r1),r30
@@ -557,9 +613,6 @@ _string_syscall_return:
        .align 4
 
 ENTRY(_sys_call_handler)
-       /* syscalls run with interrupts enabled */
-       ENABLE_INTERRUPTS(r29)          // enable interrupts, r29 is temp
-
        /* r1, EPCR, ESR a already saved */
        l.sw    PT_GPR2(r1),r2
        /* r3-r8 must be saved because syscall restart relies
@@ -597,6 +650,10 @@ ENTRY(_sys_call_handler)
 /*     l.sw    PT_GPR30(r1),r30 */
 
 _syscall_check_trace_enter:
+       /* syscalls run with interrupts enabled */
+       TRACE_IRQS_ON_SYSCALL
+       ENABLE_INTERRUPTS(r29)          // enable interrupts, r29 is temp
+
        /* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */
        l.lwz   r30,TI_FLAGS(r10)
        l.andi  r30,r30,_TIF_SYSCALL_TRACE
@@ -657,6 +714,7 @@ _syscall_check_trace_leave:
 _syscall_check_work:
        /* Here we need to disable interrupts */
        DISABLE_INTERRUPTS(r27,r29)
+       TRACE_IRQS_OFF
        l.lwz   r30,TI_FLAGS(r10)
        l.andi  r30,r30,_TIF_WORK_MASK
        l.sfne  r30,r0
@@ -871,6 +929,7 @@ UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00)
 
 _resume_userspace:
        DISABLE_INTERRUPTS(r3,r4)
+       TRACE_IRQS_OFF
        l.lwz   r4,TI_FLAGS(r10)
        l.andi  r13,r4,_TIF_WORK_MASK
        l.sfeqi r13,0
@@ -909,6 +968,15 @@ _work_pending:
         l.lwz  r8,PT_GPR8(r1)
 
 _restore_all:
+#ifdef CONFIG_TRACE_IRQFLAGS
+       l.lwz   r4,PT_SR(r1)
+       l.andi  r3,r4,(SPR_SR_IEE|SPR_SR_TEE)
+       l.sfeq  r3,r0           /* skip trace if irqs were off */
+       l.bf    skip_hardirqs_on
+        l.nop
+       TRACE_IRQS_ON
+skip_hardirqs_on:
+#endif
        RESTORE_ALL
        /* This returns to userspace code */
 
index 1e87913576e304e47ea7da5518436d3e0fe3f94e..fb02b2a1d6f2d875372b125cf837feb119d0164e 100644 (file)
 
 /* ============================================[ tmp store locations ]=== */
 
+#define SPR_SHADOW_GPR(x)      ((x) + SPR_GPR_BASE + 32)
+
 /*
  * emergency_print temporary stores
  */
+#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS
+#define EMERGENCY_PRINT_STORE_GPR4     l.mtspr r0,r4,SPR_SHADOW_GPR(14)
+#define EMERGENCY_PRINT_LOAD_GPR4      l.mfspr r4,r0,SPR_SHADOW_GPR(14)
+
+#define EMERGENCY_PRINT_STORE_GPR5     l.mtspr r0,r5,SPR_SHADOW_GPR(15)
+#define EMERGENCY_PRINT_LOAD_GPR5      l.mfspr r5,r0,SPR_SHADOW_GPR(15)
+
+#define EMERGENCY_PRINT_STORE_GPR6     l.mtspr r0,r6,SPR_SHADOW_GPR(16)
+#define EMERGENCY_PRINT_LOAD_GPR6      l.mfspr r6,r0,SPR_SHADOW_GPR(16)
+
+#define EMERGENCY_PRINT_STORE_GPR7     l.mtspr r0,r7,SPR_SHADOW_GPR(7)
+#define EMERGENCY_PRINT_LOAD_GPR7      l.mfspr r7,r0,SPR_SHADOW_GPR(7)
+
+#define EMERGENCY_PRINT_STORE_GPR8     l.mtspr r0,r8,SPR_SHADOW_GPR(8)
+#define EMERGENCY_PRINT_LOAD_GPR8      l.mfspr r8,r0,SPR_SHADOW_GPR(8)
+
+#define EMERGENCY_PRINT_STORE_GPR9     l.mtspr r0,r9,SPR_SHADOW_GPR(9)
+#define EMERGENCY_PRINT_LOAD_GPR9      l.mfspr r9,r0,SPR_SHADOW_GPR(9)
+
+#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */
 #define EMERGENCY_PRINT_STORE_GPR4     l.sw    0x20(r0),r4
 #define EMERGENCY_PRINT_LOAD_GPR4      l.lwz   r4,0x20(r0)
 
 #define EMERGENCY_PRINT_STORE_GPR9     l.sw    0x34(r0),r9
 #define EMERGENCY_PRINT_LOAD_GPR9      l.lwz   r9,0x34(r0)
 
+#endif
 
 /*
  * TLB miss handlers temorary stores
  */
-#define EXCEPTION_STORE_GPR9           l.sw    0x10(r0),r9
-#define EXCEPTION_LOAD_GPR9            l.lwz   r9,0x10(r0)
+#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS
+#define EXCEPTION_STORE_GPR2           l.mtspr r0,r2,SPR_SHADOW_GPR(2)
+#define EXCEPTION_LOAD_GPR2            l.mfspr r2,r0,SPR_SHADOW_GPR(2)
+
+#define EXCEPTION_STORE_GPR3           l.mtspr r0,r3,SPR_SHADOW_GPR(3)
+#define EXCEPTION_LOAD_GPR3            l.mfspr r3,r0,SPR_SHADOW_GPR(3)
+
+#define EXCEPTION_STORE_GPR4           l.mtspr r0,r4,SPR_SHADOW_GPR(4)
+#define EXCEPTION_LOAD_GPR4            l.mfspr r4,r0,SPR_SHADOW_GPR(4)
+
+#define EXCEPTION_STORE_GPR5           l.mtspr r0,r5,SPR_SHADOW_GPR(5)
+#define EXCEPTION_LOAD_GPR5            l.mfspr r5,r0,SPR_SHADOW_GPR(5)
+
+#define EXCEPTION_STORE_GPR6           l.mtspr r0,r6,SPR_SHADOW_GPR(6)
+#define EXCEPTION_LOAD_GPR6            l.mfspr r6,r0,SPR_SHADOW_GPR(6)
 
+#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */
 #define EXCEPTION_STORE_GPR2           l.sw    0x64(r0),r2
 #define EXCEPTION_LOAD_GPR2            l.lwz   r2,0x64(r0)
 
 #define EXCEPTION_STORE_GPR6           l.sw    0x74(r0),r6
 #define EXCEPTION_LOAD_GPR6            l.lwz   r6,0x74(r0)
 
+#endif
 
 /*
  * EXCEPTION_HANDLE temporary stores
  */
 
+#ifdef CONFIG_OPENRISC_HAVE_SHADOW_GPRS
+#define EXCEPTION_T_STORE_GPR30                l.mtspr r0,r30,SPR_SHADOW_GPR(30)
+#define EXCEPTION_T_LOAD_GPR30(reg)    l.mfspr reg,r0,SPR_SHADOW_GPR(30)
+
+#define EXCEPTION_T_STORE_GPR10                l.mtspr r0,r10,SPR_SHADOW_GPR(10)
+#define EXCEPTION_T_LOAD_GPR10(reg)    l.mfspr reg,r0,SPR_SHADOW_GPR(10)
+
+#define EXCEPTION_T_STORE_SP           l.mtspr r0,r1,SPR_SHADOW_GPR(1)
+#define EXCEPTION_T_LOAD_SP(reg)       l.mfspr reg,r0,SPR_SHADOW_GPR(1)
+
+#else /* !CONFIG_OPENRISC_HAVE_SHADOW_GPRS */
 #define EXCEPTION_T_STORE_GPR30                l.sw    0x78(r0),r30
 #define EXCEPTION_T_LOAD_GPR30(reg)    l.lwz   reg,0x78(r0)
 
 #define EXCEPTION_T_STORE_GPR10                l.sw    0x7c(r0),r10
 #define EXCEPTION_T_LOAD_GPR10(reg)    l.lwz   reg,0x7c(r0)
 
-#define EXCEPTION_T_STORE_SP           l.sw    0x80(r0),r1
+#define EXCEPTION_T_STORE_SP           l.sw    0x80(r0),r1
 #define EXCEPTION_T_LOAD_SP(reg)       l.lwz   reg,0x80(r0)
-
-/*
- * For UNHANLDED_EXCEPTION
- */
-
-#define EXCEPTION_T_STORE_GPR31                l.sw    0x84(r0),r31
-#define EXCEPTION_T_LOAD_GPR31(reg)    l.lwz   reg,0x84(r0)
+#endif
 
 /* =========================================================[ macros ]=== */
 
-
+#ifdef CONFIG_SMP
+#define GET_CURRENT_PGD(reg,t1)                                        \
+       LOAD_SYMBOL_2_GPR(reg,current_pgd)                      ;\
+       l.mfspr t1,r0,SPR_COREID                                ;\
+       l.slli  t1,t1,2                                         ;\
+       l.add   reg,reg,t1                                      ;\
+       tophys  (t1,reg)                                        ;\
+       l.lwz   reg,0(t1)
+#else
 #define GET_CURRENT_PGD(reg,t1)                                        \
        LOAD_SYMBOL_2_GPR(reg,current_pgd)                      ;\
        tophys  (t1,reg)                                        ;\
        l.lwz   reg,0(t1)
+#endif
 
+/* Load r10 from current_thread_info_set - clobbers r1 and r30 */
+#ifdef CONFIG_SMP
+#define GET_CURRENT_THREAD_INFO                                        \
+       LOAD_SYMBOL_2_GPR(r1,current_thread_info_set)           ;\
+       tophys  (r30,r1)                                        ;\
+       l.mfspr r10,r0,SPR_COREID                               ;\
+       l.slli  r10,r10,2                                       ;\
+       l.add   r30,r30,r10                                     ;\
+       /* r10: current_thread_info  */                         ;\
+       l.lwz   r10,0(r30)
+#else
+#define GET_CURRENT_THREAD_INFO                                        \
+       LOAD_SYMBOL_2_GPR(r1,current_thread_info_set)           ;\
+       tophys  (r30,r1)                                        ;\
+       /* r10: current_thread_info  */                         ;\
+       l.lwz   r10,0(r30)
+#endif
 
 /*
  * DSCR: this is a common hook for handling exceptions. it will save
        l.bnf   2f                            /* kernel_mode */ ;\
         EXCEPTION_T_STORE_SP                 /* delay slot */  ;\
 1: /* user_mode:   */                                          ;\
-       LOAD_SYMBOL_2_GPR(r1,current_thread_info_set)           ;\
-       tophys  (r30,r1)                                        ;\
-       /* r10: current_thread_info  */                         ;\
-       l.lwz   r10,0(r30)                                      ;\
+       GET_CURRENT_THREAD_INFO                                 ;\
        tophys  (r30,r10)                                       ;\
        l.lwz   r1,(TI_KSP)(r30)                                ;\
        /* fall through */                                      ;\
  *
  */
 #define UNHANDLED_EXCEPTION(handler)                           \
-       EXCEPTION_T_STORE_GPR31                                 ;\
+       EXCEPTION_T_STORE_GPR30                                 ;\
        EXCEPTION_T_STORE_GPR10                                 ;\
        EXCEPTION_T_STORE_SP                                    ;\
        /* temporary store r3, r9 into r1, r10 */               ;\
        /* r1: KSP, r10: current, r31: __pa(KSP) */             ;\
        /* r12: temp, syscall indicator, r13 temp */            ;\
        l.addi  r1,r1,-(INT_FRAME_SIZE)                         ;\
-       /* r1 is KSP, r31 is __pa(KSP) */                       ;\
-       tophys  (r31,r1)                                        ;\
-       l.sw    PT_GPR12(r31),r12                                       ;\
+       /* r1 is KSP, r30 is __pa(KSP) */                       ;\
+       tophys  (r30,r1)                                        ;\
+       l.sw    PT_GPR12(r30),r12                                       ;\
        l.mfspr r12,r0,SPR_EPCR_BASE                            ;\
-       l.sw    PT_PC(r31),r12                                  ;\
+       l.sw    PT_PC(r30),r12                                  ;\
        l.mfspr r12,r0,SPR_ESR_BASE                             ;\
-       l.sw    PT_SR(r31),r12                                  ;\
+       l.sw    PT_SR(r30),r12                                  ;\
        /* save r31 */                                          ;\
-       EXCEPTION_T_LOAD_GPR31(r12)                             ;\
-       l.sw    PT_GPR31(r31),r12                                       ;\
+       EXCEPTION_T_LOAD_GPR30(r12)                             ;\
+       l.sw    PT_GPR30(r30),r12                                       ;\
        /* save r10 as was prior to exception */                ;\
        EXCEPTION_T_LOAD_GPR10(r12)                             ;\
-       l.sw    PT_GPR10(r31),r12                                       ;\
+       l.sw    PT_GPR10(r30),r12                                       ;\
        /* save PT_SP as was prior to exception */                      ;\
        EXCEPTION_T_LOAD_SP(r12)                                ;\
-       l.sw    PT_SP(r31),r12                                  ;\
-       l.sw    PT_GPR13(r31),r13                                       ;\
+       l.sw    PT_SP(r30),r12                                  ;\
+       l.sw    PT_GPR13(r30),r13                                       ;\
        /* --> */                                               ;\
        /* save exception r4, set r4 = EA */                    ;\
-       l.sw    PT_GPR4(r31),r4                                 ;\
+       l.sw    PT_GPR4(r30),r4                                 ;\
        l.mfspr r4,r0,SPR_EEAR_BASE                             ;\
        /* r12 == 1 if we come from syscall */                  ;\
        CLEAR_GPR(r12)                                          ;\
        /* ----- play a MMU trick ----- */                      ;\
-       l.ori   r31,r0,(EXCEPTION_SR)                           ;\
-       l.mtspr r0,r31,SPR_ESR_BASE                             ;\
+       l.ori   r30,r0,(EXCEPTION_SR)                           ;\
+       l.mtspr r0,r30,SPR_ESR_BASE                             ;\
        /* r31: EA address of handler */                        ;\
-       LOAD_SYMBOL_2_GPR(r31,handler)                          ;\
-       l.mtspr r0,r31,SPR_EPCR_BASE                            ;\
+       LOAD_SYMBOL_2_GPR(r30,handler)                          ;\
+       l.mtspr r0,r30,SPR_EPCR_BASE                            ;\
        l.rfe
 
 /* =====================================================[ exceptions] === */
@@ -487,6 +553,12 @@ _start:
        CLEAR_GPR(r30)
        CLEAR_GPR(r31)
 
+#ifdef CONFIG_SMP
+       l.mfspr r26,r0,SPR_COREID
+       l.sfeq  r26,r0
+       l.bnf   secondary_wait
+        l.nop
+#endif
        /*
         * set up initial ksp and current
         */
@@ -638,6 +710,100 @@ _flush_tlb:
        l.jr    r9
         l.nop
 
+#ifdef CONFIG_SMP
+secondary_wait:
+       /* Doze the cpu until we are asked to run */
+       /* If we dont have power management skip doze */
+       l.mfspr r25,r0,SPR_UPR
+       l.andi  r25,r25,SPR_UPR_PMP
+       l.sfeq  r25,r0
+       l.bf    secondary_check_release
+        l.nop
+
+       /* Setup special secondary exception handler */
+       LOAD_SYMBOL_2_GPR(r3, _secondary_evbar)
+       tophys(r25,r3)
+       l.mtspr r0,r25,SPR_EVBAR
+
+       /* Enable Interrupts */
+       l.mfspr r25,r0,SPR_SR
+       l.ori   r25,r25,SPR_SR_IEE
+       l.mtspr r0,r25,SPR_SR
+
+       /* Unmask interrupts interrupts */
+       l.mfspr r25,r0,SPR_PICMR
+       l.ori   r25,r25,0xffff
+       l.mtspr r0,r25,SPR_PICMR
+
+       /* Doze */
+       l.mfspr r25,r0,SPR_PMR
+       LOAD_SYMBOL_2_GPR(r3, SPR_PMR_DME)
+       l.or    r25,r25,r3
+       l.mtspr r0,r25,SPR_PMR
+
+       /* Wakeup - Restore exception handler */
+       l.mtspr r0,r0,SPR_EVBAR
+
+secondary_check_release:
+       /*
+        * Check if we actually got the release signal, if not go-back to
+        * sleep.
+        */
+       l.mfspr r25,r0,SPR_COREID
+       LOAD_SYMBOL_2_GPR(r3, secondary_release)
+       tophys(r4, r3)
+       l.lwz   r3,0(r4)
+       l.sfeq  r25,r3
+       l.bnf   secondary_wait
+        l.nop
+       /* fall through to secondary_init */
+
+secondary_init:
+       /*
+        * set up initial ksp and current
+        */
+       LOAD_SYMBOL_2_GPR(r10, secondary_thread_info)
+       tophys  (r30,r10)
+       l.lwz   r10,0(r30)
+       l.addi  r1,r10,THREAD_SIZE
+       tophys  (r30,r10)
+       l.sw    TI_KSP(r30),r1
+
+       l.jal   _ic_enable
+        l.nop
+
+       l.jal   _dc_enable
+        l.nop
+
+       l.jal   _flush_tlb
+        l.nop
+
+       /*
+        * enable dmmu & immu
+        */
+       l.mfspr r30,r0,SPR_SR
+       l.movhi r28,hi(SPR_SR_DME | SPR_SR_IME)
+       l.ori   r28,r28,lo(SPR_SR_DME | SPR_SR_IME)
+       l.or    r30,r30,r28
+       /*
+        * This is a bit tricky, we need to switch over from physical addresses
+        * to virtual addresses on the fly.
+        * To do that, we first set up ESR with the IME and DME bits set.
+        * Then EPCR is set to secondary_start and then a l.rfe is issued to
+        * "jump" to that.
+        */
+       l.mtspr r0,r30,SPR_ESR_BASE
+       LOAD_SYMBOL_2_GPR(r30, secondary_start)
+       l.mtspr r0,r30,SPR_EPCR_BASE
+       l.rfe
+
+secondary_start:
+       LOAD_SYMBOL_2_GPR(r30, secondary_start_kernel)
+       l.jr    r30
+        l.nop
+
+#endif
+
 /* ========================================[ cache ]=== */
 
        /* alignment here so we don't change memory offsets with
@@ -1533,6 +1699,17 @@ ENTRY(_early_uart_init)
        l.jr    r9
        l.nop
 
+       .align  0x1000
+       .global _secondary_evbar
+_secondary_evbar:
+
+       .space 0x800
+       /* Just disable interrupts and Return */
+       l.ori   r3,r0,SPR_SR_SM
+       l.mtspr r0,r3,SPR_ESR_BASE
+       l.rfe
+
+
        .section .rodata
 _string_unhandled_exception:
        .string "\n\rRunarunaround: Unhandled exception 0x\0"
index dbf5ee95a0d5f2ba8e2e6f453234afa954e04f45..9d28ab14d139cb4b6ed842f7f56c444858e17dc0 100644 (file)
@@ -93,7 +93,7 @@ static void __init setup_memory(void)
        memblock_dump_all();
 }
 
-struct cpuinfo cpuinfo;
+struct cpuinfo_or1k cpuinfo_or1k[NR_CPUS];
 
 static void print_cpuinfo(void)
 {
@@ -101,12 +101,13 @@ static void print_cpuinfo(void)
        unsigned long vr = mfspr(SPR_VR);
        unsigned int version;
        unsigned int revision;
+       struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
 
        version = (vr & SPR_VR_VER) >> 24;
        revision = (vr & SPR_VR_REV);
 
        printk(KERN_INFO "CPU: OpenRISC-%x (revision %d) @%d MHz\n",
-              version, revision, cpuinfo.clock_frequency / 1000000);
+              version, revision, cpuinfo->clock_frequency / 1000000);
 
        if (!(upr & SPR_UPR_UP)) {
                printk(KERN_INFO
@@ -117,15 +118,15 @@ static void print_cpuinfo(void)
        if (upr & SPR_UPR_DCP)
                printk(KERN_INFO
                       "-- dcache: %4d bytes total, %2d bytes/line, %d way(s)\n",
-                      cpuinfo.dcache_size, cpuinfo.dcache_block_size,
-                      cpuinfo.dcache_ways);
+                      cpuinfo->dcache_size, cpuinfo->dcache_block_size,
+                      cpuinfo->dcache_ways);
        else
                printk(KERN_INFO "-- dcache disabled\n");
        if (upr & SPR_UPR_ICP)
                printk(KERN_INFO
                       "-- icache: %4d bytes total, %2d bytes/line, %d way(s)\n",
-                      cpuinfo.icache_size, cpuinfo.icache_block_size,
-                      cpuinfo.icache_ways);
+                      cpuinfo->icache_size, cpuinfo->icache_block_size,
+                      cpuinfo->icache_ways);
        else
                printk(KERN_INFO "-- icache disabled\n");
 
@@ -153,38 +154,58 @@ static void print_cpuinfo(void)
                printk(KERN_INFO "-- custom unit(s)\n");
 }
 
+static struct device_node *setup_find_cpu_node(int cpu)
+{
+       u32 hwid;
+       struct device_node *cpun;
+       struct device_node *cpus = of_find_node_by_path("/cpus");
+
+       for_each_available_child_of_node(cpus, cpun) {
+               if (of_property_read_u32(cpun, "reg", &hwid))
+                       continue;
+               if (hwid == cpu)
+                       return cpun;
+       }
+
+       return NULL;
+}
+
 void __init setup_cpuinfo(void)
 {
        struct device_node *cpu;
        unsigned long iccfgr, dccfgr;
        unsigned long cache_set_size;
+       int cpu_id = smp_processor_id();
+       struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[cpu_id];
 
-       cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481");
+       cpu = setup_find_cpu_node(cpu_id);
        if (!cpu)
-               panic("No compatible CPU found in device tree...\n");
+               panic("Couldn't find CPU%d in device tree...\n", cpu_id);
 
        iccfgr = mfspr(SPR_ICCFGR);
-       cpuinfo.icache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
+       cpuinfo->icache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
        cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
-       cpuinfo.icache_block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7);
-       cpuinfo.icache_size =
-           cache_set_size * cpuinfo.icache_ways * cpuinfo.icache_block_size;
+       cpuinfo->icache_block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7);
+       cpuinfo->icache_size =
+           cache_set_size * cpuinfo->icache_ways * cpuinfo->icache_block_size;
 
        dccfgr = mfspr(SPR_DCCFGR);
-       cpuinfo.dcache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
+       cpuinfo->dcache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
        cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
-       cpuinfo.dcache_block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7);
-       cpuinfo.dcache_size =
-           cache_set_size * cpuinfo.dcache_ways * cpuinfo.dcache_block_size;
+       cpuinfo->dcache_block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7);
+       cpuinfo->dcache_size =
+           cache_set_size * cpuinfo->dcache_ways * cpuinfo->dcache_block_size;
 
        if (of_property_read_u32(cpu, "clock-frequency",
-                                &cpuinfo.clock_frequency)) {
+                                &cpuinfo->clock_frequency)) {
                printk(KERN_WARNING
                       "Device tree missing CPU 'clock-frequency' parameter."
                       "Assuming frequency 25MHZ"
                       "This is probably not what you want.");
        }
 
+       cpuinfo->coreid = mfspr(SPR_COREID);
+
        of_node_put(cpu);
 
        print_cpuinfo();
@@ -251,8 +272,8 @@ void __init detect_unit_config(unsigned long upr, unsigned long mask,
 void calibrate_delay(void)
 {
        const int *val;
-       struct device_node *cpu = NULL;
-       cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481");
+       struct device_node *cpu = setup_find_cpu_node(smp_processor_id());
+
        val = of_get_property(cpu, "clock-frequency", NULL);
        if (!val)
                panic("no cpu 'clock-frequency' parameter in device tree");
@@ -268,6 +289,10 @@ void __init setup_arch(char **cmdline_p)
 
        setup_cpuinfo();
 
+#ifdef CONFIG_SMP
+       smp_init_cpus();
+#endif
+
        /* process 1's initial memory region is the kernel code/data */
        init_mm.start_code = (unsigned long)_stext;
        init_mm.end_code = (unsigned long)_etext;
@@ -302,54 +327,78 @@ void __init setup_arch(char **cmdline_p)
 
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
-       unsigned long vr;
-       int version, revision;
+       unsigned int vr, cpucfgr;
+       unsigned int avr;
+       unsigned int version;
+       struct cpuinfo_or1k *cpuinfo = v;
 
        vr = mfspr(SPR_VR);
-       version = (vr & SPR_VR_VER) >> 24;
-       revision = vr & SPR_VR_REV;
-
-       seq_printf(m,
-                 "cpu\t\t: OpenRISC-%x\n"
-                 "revision\t: %d\n"
-                 "frequency\t: %ld\n"
-                 "dcache size\t: %d bytes\n"
-                 "dcache block size\t: %d bytes\n"
-                 "dcache ways\t: %d\n"
-                 "icache size\t: %d bytes\n"
-                 "icache block size\t: %d bytes\n"
-                 "icache ways\t: %d\n"
-                 "immu\t\t: %d entries, %lu ways\n"
-                 "dmmu\t\t: %d entries, %lu ways\n"
-                 "bogomips\t: %lu.%02lu\n",
-                 version,
-                 revision,
-                 loops_per_jiffy * HZ,
-                 cpuinfo.dcache_size,
-                 cpuinfo.dcache_block_size,
-                 cpuinfo.dcache_ways,
-                 cpuinfo.icache_size,
-                 cpuinfo.icache_block_size,
-                 cpuinfo.icache_ways,
-                 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2),
-                 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW),
-                 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2),
-                 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW),
-                 (loops_per_jiffy * HZ) / 500000,
-                 ((loops_per_jiffy * HZ) / 5000) % 100);
+       cpucfgr = mfspr(SPR_CPUCFGR);
+
+#ifdef CONFIG_SMP
+       seq_printf(m, "processor\t\t: %d\n", cpuinfo->coreid);
+#endif
+       if (vr & SPR_VR_UVRP) {
+               vr = mfspr(SPR_VR2);
+               version = vr & SPR_VR2_VER;
+               avr = mfspr(SPR_AVR);
+               seq_printf(m, "cpu architecture\t: "
+                          "OpenRISC 1000 (%d.%d-rev%d)\n",
+                          (avr >> 24) & 0xff,
+                          (avr >> 16) & 0xff,
+                          (avr >> 8) & 0xff);
+               seq_printf(m, "cpu implementation id\t: 0x%x\n",
+                          (vr & SPR_VR2_CPUID) >> 24);
+               seq_printf(m, "cpu version\t\t: 0x%x\n", version);
+       } else {
+               version = (vr & SPR_VR_VER) >> 24;
+               seq_printf(m, "cpu\t\t\t: OpenRISC-%x\n", version);
+               seq_printf(m, "revision\t\t: %d\n", vr & SPR_VR_REV);
+       }
+       seq_printf(m, "frequency\t\t: %ld\n", loops_per_jiffy * HZ);
+       seq_printf(m, "dcache size\t\t: %d bytes\n", cpuinfo->dcache_size);
+       seq_printf(m, "dcache block size\t: %d bytes\n",
+                  cpuinfo->dcache_block_size);
+       seq_printf(m, "dcache ways\t\t: %d\n", cpuinfo->dcache_ways);
+       seq_printf(m, "icache size\t\t: %d bytes\n", cpuinfo->icache_size);
+       seq_printf(m, "icache block size\t: %d bytes\n",
+                  cpuinfo->icache_block_size);
+       seq_printf(m, "icache ways\t\t: %d\n", cpuinfo->icache_ways);
+       seq_printf(m, "immu\t\t\t: %d entries, %lu ways\n",
+                  1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2),
+                  1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW));
+       seq_printf(m, "dmmu\t\t\t: %d entries, %lu ways\n",
+                  1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2),
+                  1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW));
+       seq_printf(m, "bogomips\t\t: %lu.%02lu\n",
+                  (loops_per_jiffy * HZ) / 500000,
+                  ((loops_per_jiffy * HZ) / 5000) % 100);
+
+       seq_puts(m, "features\t\t: ");
+       seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OB32S ? "orbis32" : "");
+       seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OB64S ? "orbis64" : "");
+       seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OF32S ? "orfpx32" : "");
+       seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OF64S ? "orfpx64" : "");
+       seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OV64S ? "orvdx64" : "");
+       seq_puts(m, "\n");
+
+       seq_puts(m, "\n");
+
        return 0;
 }
 
-static void *c_start(struct seq_file *m, loff_t * pos)
+static void *c_start(struct seq_file *m, loff_t *pos)
 {
-       /* We only have one CPU... */
-       return *pos < 1 ? (void *)1 : NULL;
+       *pos = cpumask_next(*pos - 1, cpu_online_mask);
+       if ((*pos) < nr_cpu_ids)
+               return &cpuinfo_or1k[*pos];
+       return NULL;
 }
 
-static void *c_next(struct seq_file *m, void *v, loff_t * pos)
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       ++*pos;
-       return NULL;
+       (*pos)++;
+       return c_start(m, pos);
 }
 
 static void c_stop(struct seq_file *m, void *v)
diff --git a/arch/openrisc/kernel/smp.c b/arch/openrisc/kernel/smp.c
new file mode 100644 (file)
index 0000000..7d518ee
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
+ *
+ * Based on arm64 and arc implementations
+ * Copyright (C) 2013 ARM Ltd.
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <asm/cpuinfo.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/time.h>
+
+static void (*smp_cross_call)(const struct cpumask *, unsigned int);
+
+unsigned long secondary_release = -1;
+struct thread_info *secondary_thread_info;
+
+enum ipi_msg_type {
+       IPI_WAKEUP,
+       IPI_RESCHEDULE,
+       IPI_CALL_FUNC,
+       IPI_CALL_FUNC_SINGLE,
+};
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static void boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       /*
+        * set synchronisation state between this boot processor
+        * and the secondary one
+        */
+       spin_lock(&boot_lock);
+
+       secondary_release = cpu;
+       smp_cross_call(cpumask_of(cpu), IPI_WAKEUP);
+
+       /*
+        * now the secondary core is starting up let it run its
+        * calibrations, then wait for it to finish
+        */
+       spin_unlock(&boot_lock);
+}
+
+void __init smp_prepare_boot_cpu(void)
+{
+}
+
+void __init smp_init_cpus(void)
+{
+       int i;
+
+       for (i = 0; i < NR_CPUS; i++)
+               set_cpu_possible(i, true);
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+       int i;
+
+       /*
+        * Initialise the present map, which describes the set of CPUs
+        * actually populated at the present time.
+        */
+       for (i = 0; i < max_cpus; i++)
+               set_cpu_present(i, true);
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+static DECLARE_COMPLETION(cpu_running);
+
+int __cpu_up(unsigned int cpu, struct task_struct *idle)
+{
+       if (smp_cross_call == NULL) {
+               pr_warn("CPU%u: failed to start, IPI controller missing",
+                       cpu);
+               return -EIO;
+       }
+
+       secondary_thread_info = task_thread_info(idle);
+       current_pgd[cpu] = init_mm.pgd;
+
+       boot_secondary(cpu, idle);
+       if (!wait_for_completion_timeout(&cpu_running,
+                                       msecs_to_jiffies(1000))) {
+               pr_crit("CPU%u: failed to start\n", cpu);
+               return -EIO;
+       }
+       synchronise_count_master(cpu);
+
+       return 0;
+}
+
+asmlinkage __init void secondary_start_kernel(void)
+{
+       struct mm_struct *mm = &init_mm;
+       unsigned int cpu = smp_processor_id();
+       /*
+        * All kernel threads share the same mm context; grab a
+        * reference and switch to it.
+        */
+       atomic_inc(&mm->mm_count);
+       current->active_mm = mm;
+       cpumask_set_cpu(cpu, mm_cpumask(mm));
+
+       pr_info("CPU%u: Booted secondary processor\n", cpu);
+
+       setup_cpuinfo();
+       openrisc_clockevent_init();
+
+       notify_cpu_starting(cpu);
+
+       /*
+        * OK, now it's safe to let the boot CPU continue
+        */
+       complete(&cpu_running);
+
+       synchronise_count_slave(cpu);
+       set_cpu_online(cpu, true);
+
+       local_irq_enable();
+
+       preempt_disable();
+       /*
+        * OK, it's off to the idle thread for us
+        */
+       cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
+}
+
+void handle_IPI(unsigned int ipi_msg)
+{
+       unsigned int cpu = smp_processor_id();
+
+       switch (ipi_msg) {
+       case IPI_WAKEUP:
+               break;
+
+       case IPI_RESCHEDULE:
+               scheduler_ipi();
+               break;
+
+       case IPI_CALL_FUNC:
+               generic_smp_call_function_interrupt();
+               break;
+
+       case IPI_CALL_FUNC_SINGLE:
+               generic_smp_call_function_single_interrupt();
+               break;
+
+       default:
+               WARN(1, "CPU%u: Unknown IPI message 0x%x\n", cpu, ipi_msg);
+               break;
+       }
+}
+
+void smp_send_reschedule(int cpu)
+{
+       smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
+}
+
+static void stop_this_cpu(void *dummy)
+{
+       /* Remove this CPU */
+       set_cpu_online(smp_processor_id(), false);
+
+       local_irq_disable();
+       /* CPU Doze */
+       if (mfspr(SPR_UPR) & SPR_UPR_PMP)
+               mtspr(SPR_PMR, mfspr(SPR_PMR) | SPR_PMR_DME);
+       /* If that didn't work, infinite loop */
+       while (1)
+               ;
+}
+
+void smp_send_stop(void)
+{
+       smp_call_function(stop_this_cpu, NULL, 0);
+}
+
+/* not supported, yet */
+int setup_profiling_timer(unsigned int multiplier)
+{
+       return -EINVAL;
+}
+
+void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
+{
+       smp_cross_call = fn;
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+       smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+}
+
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+       smp_cross_call(mask, IPI_CALL_FUNC);
+}
+
+/* TLB flush operations - Performed on each CPU*/
+static inline void ipi_flush_tlb_all(void *ignored)
+{
+       local_flush_tlb_all();
+}
+
+void flush_tlb_all(void)
+{
+       on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+}
+
+/*
+ * FIXME: implement proper functionality instead of flush_tlb_all.
+ * *But*, as things currently stands, the local_tlb_flush_* functions will
+ * all boil down to local_tlb_flush_all anyway.
+ */
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+       on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma,
+                    unsigned long start, unsigned long end)
+{
+       on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+}
+
+/* Instruction cache invalidate - performed on each cpu */
+static void ipi_icache_page_inv(void *arg)
+{
+       struct page *page = arg;
+
+       local_icache_page_inv(page);
+}
+
+void smp_icache_page_inv(struct page *page)
+{
+       on_each_cpu(ipi_icache_page_inv, page, 1);
+}
+EXPORT_SYMBOL(smp_icache_page_inv);
diff --git a/arch/openrisc/kernel/stacktrace.c b/arch/openrisc/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..43f140a
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Stack trace utility for OpenRISC
+ *
+ * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Losely based on work from sh and powerpc.
+ */
+
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/stacktrace.h>
+
+#include <asm/processor.h>
+#include <asm/unwinder.h>
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ */
+static void
+save_stack_address(void *data, unsigned long addr, int reliable)
+{
+       struct stack_trace *trace = data;
+
+       if (!reliable)
+               return;
+
+       if (trace->skip > 0) {
+               trace->skip--;
+               return;
+       }
+
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = addr;
+}
+
+void save_stack_trace(struct stack_trace *trace)
+{
+       unwind_stack(trace, (unsigned long *) &trace, save_stack_address);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+
+static void
+save_stack_address_nosched(void *data, unsigned long addr, int reliable)
+{
+       struct stack_trace *trace = (struct stack_trace *)data;
+
+       if (!reliable)
+               return;
+
+       if (in_sched_functions(addr))
+               return;
+
+       if (trace->skip > 0) {
+               trace->skip--;
+               return;
+       }
+
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = addr;
+}
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       unsigned long *sp = NULL;
+
+       if (tsk == current)
+               sp = (unsigned long *) &sp;
+       else
+               sp = (unsigned long *) KSTK_ESP(tsk);
+
+       unwind_stack(trace, sp, save_stack_address_nosched);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
+
+void
+save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
+{
+       unwind_stack(trace, (unsigned long *) regs->sp,
+                    save_stack_address_nosched);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_regs);
diff --git a/arch/openrisc/kernel/sync-timer.c b/arch/openrisc/kernel/sync-timer.c
new file mode 100644 (file)
index 0000000..ed8d835
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * OR1K timer synchronisation
+ *
+ * Based on work from MIPS implementation.
+ *
+ * All CPUs will have their count registers synchronised to the CPU0 next time
+ * value. This can cause a small timewarp for CPU0. All other CPU's should
+ * not have done anything significant (but they may have had interrupts
+ * enabled briefly - prom_smp_finish() should not be responsible for enabling
+ * interrupts...)
+ */
+
+#include <linux/kernel.h>
+#include <linux/irqflags.h>
+#include <linux/cpumask.h>
+
+#include <asm/time.h>
+#include <asm/timex.h>
+#include <linux/atomic.h>
+#include <asm/barrier.h>
+
+#include <asm/spr.h>
+
+static unsigned int initcount;
+static atomic_t count_count_start = ATOMIC_INIT(0);
+static atomic_t count_count_stop = ATOMIC_INIT(0);
+
+#define COUNTON 100
+#define NR_LOOPS 3
+
+void synchronise_count_master(int cpu)
+{
+       int i;
+       unsigned long flags;
+
+       pr_info("Synchronize counters for CPU %u: ", cpu);
+
+       local_irq_save(flags);
+
+       /*
+        * We loop a few times to get a primed instruction cache,
+        * then the last pass is more or less synchronised and
+        * the master and slaves each set their cycle counters to a known
+        * value all at once. This reduces the chance of having random offsets
+        * between the processors, and guarantees that the maximum
+        * delay between the cycle counters is never bigger than
+        * the latency of information-passing (cachelines) between
+        * two CPUs.
+        */
+
+       for (i = 0; i < NR_LOOPS; i++) {
+               /* slaves loop on '!= 2' */
+               while (atomic_read(&count_count_start) != 1)
+                       mb();
+               atomic_set(&count_count_stop, 0);
+               smp_wmb();
+
+               /* Let the slave writes its count register */
+               atomic_inc(&count_count_start);
+
+               /* Count will be initialised to current timer */
+               if (i == 1)
+                       initcount = get_cycles();
+
+               /*
+                * Everyone initialises count in the last loop:
+                */
+               if (i == NR_LOOPS-1)
+                       openrisc_timer_set(initcount);
+
+               /*
+                * Wait for slave to leave the synchronization point:
+                */
+               while (atomic_read(&count_count_stop) != 1)
+                       mb();
+               atomic_set(&count_count_start, 0);
+               smp_wmb();
+               atomic_inc(&count_count_stop);
+       }
+       /* Arrange for an interrupt in a short while */
+       openrisc_timer_set_next(COUNTON);
+
+       local_irq_restore(flags);
+
+       /*
+        * i386 code reported the skew here, but the
+        * count registers were almost certainly out of sync
+        * so no point in alarming people
+        */
+       pr_cont("done.\n");
+}
+
+void synchronise_count_slave(int cpu)
+{
+       int i;
+
+       /*
+        * Not every cpu is online at the time this gets called,
+        * so we first wait for the master to say everyone is ready
+        */
+
+       for (i = 0; i < NR_LOOPS; i++) {
+               atomic_inc(&count_count_start);
+               while (atomic_read(&count_count_start) != 2)
+                       mb();
+
+               /*
+                * Everyone initialises count in the last loop:
+                */
+               if (i == NR_LOOPS-1)
+                       openrisc_timer_set(initcount);
+
+               atomic_inc(&count_count_stop);
+               while (atomic_read(&count_count_stop) != 2)
+                       mb();
+       }
+       /* Arrange for an interrupt in a short while */
+       openrisc_timer_set_next(COUNTON);
+}
+#undef NR_LOOPS
index 687c11d048d7c2493c7d302e3c0cd053f99ef360..6baecea270801ae56ab1ef39383442f846d1999a 100644 (file)
 
 #include <asm/cpuinfo.h>
 
-static int openrisc_timer_set_next_event(unsigned long delta,
-                                        struct clock_event_device *dev)
+/* Test the timer ticks to count, used in sync routine */
+inline void openrisc_timer_set(unsigned long count)
+{
+       mtspr(SPR_TTCR, count);
+}
+
+/* Set the timer to trigger in delta cycles */
+inline void openrisc_timer_set_next(unsigned long delta)
 {
        u32 c;
 
@@ -44,7 +50,12 @@ static int openrisc_timer_set_next_event(unsigned long delta,
         * Keep timer in continuous mode always.
         */
        mtspr(SPR_TTMR, SPR_TTMR_CR | SPR_TTMR_IE | c);
+}
 
+static int openrisc_timer_set_next_event(unsigned long delta,
+                                        struct clock_event_device *dev)
+{
+       openrisc_timer_set_next(delta);
        return 0;
 }
 
@@ -53,13 +64,32 @@ static int openrisc_timer_set_next_event(unsigned long delta,
  * timers) we cannot enable the PERIODIC feature.  The tick timer can run using
  * one-shot events, so no problem.
  */
+DEFINE_PER_CPU(struct clock_event_device, clockevent_openrisc_timer);
 
-static struct clock_event_device clockevent_openrisc_timer = {
-       .name = "openrisc_timer_clockevent",
-       .features = CLOCK_EVT_FEAT_ONESHOT,
-       .rating = 300,
-       .set_next_event = openrisc_timer_set_next_event,
-};
+void openrisc_clockevent_init(void)
+{
+       unsigned int cpu = smp_processor_id();
+       struct clock_event_device *evt =
+               &per_cpu(clockevent_openrisc_timer, cpu);
+       struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[cpu];
+
+       mtspr(SPR_TTMR, SPR_TTMR_CR);
+
+#ifdef CONFIG_SMP
+       evt->broadcast = tick_broadcast;
+#endif
+       evt->name = "openrisc_timer_clockevent",
+       evt->features = CLOCK_EVT_FEAT_ONESHOT,
+       evt->rating = 300,
+       evt->set_next_event = openrisc_timer_set_next_event,
+
+       evt->cpumask = cpumask_of(cpu);
+
+       /* We only have 28 bits */
+       clockevents_config_and_register(evt, cpuinfo->clock_frequency,
+                                       100, 0x0fffffff);
+
+}
 
 static inline void timer_ack(void)
 {
@@ -83,7 +113,9 @@ static inline void timer_ack(void)
 irqreturn_t __irq_entry timer_interrupt(struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
-       struct clock_event_device *evt = &clockevent_openrisc_timer;
+       unsigned int cpu = smp_processor_id();
+       struct clock_event_device *evt =
+               &per_cpu(clockevent_openrisc_timer, cpu);
 
        timer_ack();
 
@@ -99,24 +131,12 @@ irqreturn_t __irq_entry timer_interrupt(struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-static __init void openrisc_clockevent_init(void)
-{
-       clockevent_openrisc_timer.cpumask = cpumask_of(0);
-
-       /* We only have 28 bits */
-       clockevents_config_and_register(&clockevent_openrisc_timer,
-                                       cpuinfo.clock_frequency,
-                                       100, 0x0fffffff);
-
-}
-
 /**
  * Clocksource: Based on OpenRISC timer/counter
  *
  * This sets up the OpenRISC Tick Timer as a clock source.  The tick timer
  * is 32 bits wide and runs at the CPU clock frequency.
  */
-
 static u64 openrisc_timer_read(struct clocksource *cs)
 {
        return (u64) mfspr(SPR_TTCR);
@@ -132,7 +152,9 @@ static struct clocksource openrisc_timer = {
 
 static int __init openrisc_timer_init(void)
 {
-       if (clocksource_register_hz(&openrisc_timer, cpuinfo.clock_frequency))
+       struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
+
+       if (clocksource_register_hz(&openrisc_timer, cpuinfo->clock_frequency))
                panic("failed to register clocksource");
 
        /* Enable the incrementer: 'continuous' mode with interrupt disabled */
index 803e9e756f7785a9250c95ccd93f4cacc18f70d2..4085d72fa5ae8a30bc3011f3e8cf44ca331568d5 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/unwinder.h>
 
 extern char _etext, _stext;
 
@@ -45,61 +46,20 @@ int kstack_depth_to_print = 0x180;
 int lwa_flag;
 unsigned long __user *lwa_addr;
 
-static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+void print_trace(void *data, unsigned long addr, int reliable)
 {
-       return p > (void *)tinfo && p < (void *)tinfo + THREAD_SIZE - 3;
-}
-
-void show_trace(struct task_struct *task, unsigned long *stack)
-{
-       struct thread_info *context;
-       unsigned long addr;
-
-       context = (struct thread_info *)
-           ((unsigned long)stack & (~(THREAD_SIZE - 1)));
-
-       while (valid_stack_ptr(context, stack)) {
-               addr = *stack++;
-               if (__kernel_text_address(addr)) {
-                       printk(" [<%08lx>]", addr);
-                       print_symbol(" %s", addr);
-                       printk("\n");
-               }
-       }
-       printk(" =======================\n");
+       pr_emerg("[<%p>] %s%pS\n", (void *) addr, reliable ? "" : "? ",
+              (void *) addr);
 }
 
 /* displays a short stack trace */
 void show_stack(struct task_struct *task, unsigned long *esp)
 {
-       unsigned long addr, *stack;
-       int i;
-
        if (esp == NULL)
                esp = (unsigned long *)&esp;
 
-       stack = esp;
-
-       printk("Stack dump [0x%08lx]:\n", (unsigned long)esp);
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (kstack_end(stack))
-                       break;
-               if (__get_user(addr, stack)) {
-                       /* This message matches "failing address" marked
-                          s390 in ksymoops, so lines containing it will
-                          not be filtered out by ksymoops.  */
-                       printk("Failing address 0x%lx\n", (unsigned long)stack);
-                       break;
-               }
-               stack++;
-
-               printk("sp + %02d: 0x%08lx\n", i * 4, addr);
-       }
-       printk("\n");
-
-       show_trace(task, esp);
-
-       return;
+       pr_emerg("Call trace:\n");
+       unwind_stack(NULL, esp, print_trace);
 }
 
 void show_trace_task(struct task_struct *tsk)
@@ -115,7 +75,7 @@ void show_registers(struct pt_regs *regs)
        int in_kernel = 1;
        unsigned long esp;
 
-       esp = (unsigned long)(&regs->sp);
+       esp = (unsigned long)(regs->sp);
        if (user_mode(regs))
                in_kernel = 0;
 
diff --git a/arch/openrisc/kernel/unwinder.c b/arch/openrisc/kernel/unwinder.c
new file mode 100644 (file)
index 0000000..8ae15c2
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * OpenRISC unwinder.c
+ *
+ * Reusable arch specific api for unwinding stacks.
+ *
+ * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/sched/task_stack.h>
+#include <linux/kernel.h>
+
+#include <asm/unwinder.h>
+
+#ifdef CONFIG_FRAME_POINTER
+struct or1k_frameinfo {
+       unsigned long *fp;
+       unsigned long ra;
+       unsigned long top;
+};
+
+/*
+ * Verify a frameinfo structure.  The return address should be a valid text
+ * address.  The frame pointer may be null if its the last frame, otherwise
+ * the frame pointer should point to a location in the stack after the the
+ * top of the next frame up.
+ */
+static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
+{
+       return (frameinfo->fp == NULL ||
+               (!kstack_end(frameinfo->fp) &&
+                frameinfo->fp > &frameinfo->top)) &&
+              __kernel_text_address(frameinfo->ra);
+}
+
+/*
+ * Create a stack trace doing scanning which is frame pointer aware. We can
+ * get reliable stack traces by matching the previously found frame
+ * pointer with the top of the stack address every time we find a valid
+ * or1k_frameinfo.
+ *
+ * Ideally the stack parameter will be passed as FP, but it can not be
+ * guaranteed.  Therefore we scan each address looking for the first sign
+ * of a return address.
+ *
+ * The OpenRISC stack frame looks something like the following.  The
+ * location SP is held in r1 and location FP is held in r2 when frame pointers
+ * enabled.
+ *
+ * SP   -> (top of stack)
+ *      -  (callee saved registers)
+ *      -  (local variables)
+ * FP-8 -> previous FP             \
+ * FP-4 -> return address          |- or1k_frameinfo
+ * FP   -> (previous top of stack) /
+ */
+void unwind_stack(void *data, unsigned long *stack,
+                 void (*trace)(void *data, unsigned long addr, int reliable))
+{
+       unsigned long *next_fp = NULL;
+       struct or1k_frameinfo *frameinfo = NULL;
+       int reliable = 0;
+
+       while (!kstack_end(stack)) {
+               frameinfo = container_of(stack,
+                                        struct or1k_frameinfo,
+                                        top);
+
+               if (__kernel_text_address(frameinfo->ra)) {
+                       if (or1k_frameinfo_valid(frameinfo) &&
+                           (next_fp == NULL ||
+                            next_fp == &frameinfo->top)) {
+                               reliable = 1;
+                               next_fp = frameinfo->fp;
+                       } else
+                               reliable = 0;
+
+                       trace(data, frameinfo->ra, reliable);
+               }
+               stack++;
+       }
+}
+
+#else /* CONFIG_FRAME_POINTER */
+
+/*
+ * Create a stack trace by doing a simple scan treating all text addresses
+ * as return addresses.
+ */
+void unwind_stack(void *data, unsigned long *stack,
+                  void (*trace)(void *data, unsigned long addr, int reliable))
+{
+       unsigned long addr;
+
+       while (!kstack_end(stack)) {
+               addr = *stack++;
+               if (__kernel_text_address(addr))
+                       trace(data, addr, 0);
+       }
+}
+#endif /* CONFIG_FRAME_POINTER */
+
index 8b13fdf43ec61592713fa7d2e8b640adb2ed3a06..a92bd621aa1f6e5e64a7ade5ad392c5d5c46e918 100644 (file)
@@ -25,7 +25,7 @@
 
 int read_current_timer(unsigned long *timer_value)
 {
-       *timer_value = mfspr(SPR_TTCR);
+       *timer_value = get_cycles();
        return 0;
 }
 
index 324ba26345291a27caafef1edfd0a8884fe7c7f9..a31b2a42e966f1604d67db63fa645738dfc2964e 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the linux openrisc-specific parts of the memory manager.
 #
 
-obj-y  := fault.o tlb.o init.o ioremap.o
+obj-y  := fault.o cache.o tlb.o init.o ioremap.o
diff --git a/arch/openrisc/mm/cache.c b/arch/openrisc/mm/cache.c
new file mode 100644 (file)
index 0000000..b747bf1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * OpenRISC cache.c
+ *
+ * Linux architectural port borrowing liberally from similar works of
+ * others.  All original copyrights apply as per the original source
+ * declaration.
+ *
+ * Modifications for the OpenRISC architecture:
+ * Copyright (C) 2015 Jan Henrik Weinstock <jan.weinstock@rwth-aachen.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.
+ */
+
+#include <asm/spr.h>
+#include <asm/spr_defs.h>
+#include <asm/cache.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+static void cache_loop(struct page *page, const unsigned int reg)
+{
+       unsigned long paddr = page_to_pfn(page) << PAGE_SHIFT;
+       unsigned long line = paddr & ~(L1_CACHE_BYTES - 1);
+
+       while (line < paddr + PAGE_SIZE) {
+               mtspr(reg, line);
+               line += L1_CACHE_BYTES;
+       }
+}
+
+void local_dcache_page_flush(struct page *page)
+{
+       cache_loop(page, SPR_DCBFR);
+}
+EXPORT_SYMBOL(local_dcache_page_flush);
+
+void local_icache_page_inv(struct page *page)
+{
+       cache_loop(page, SPR_ICBIR);
+}
+EXPORT_SYMBOL(local_icache_page_inv);
+
+void update_cache(struct vm_area_struct *vma, unsigned long address,
+       pte_t *pte)
+{
+       unsigned long pfn = pte_val(*pte) >> PAGE_SHIFT;
+       struct page *page = pfn_to_page(pfn);
+       int dirty = !test_and_set_bit(PG_dc_clean, &page->flags);
+
+       /*
+        * Since icaches do not snoop for updated data on OpenRISC, we
+        * must write back and invalidate any dirty pages manually. We
+        * can skip data pages, since they will not end up in icaches.
+        */
+       if ((vma->vm_flags & VM_EXEC) && dirty)
+               sync_icache_dcache(page);
+}
+
index e310ab499385c5432a8d18c07a8081a0b9e5a3a5..d0021dfae20ad24649f20eab77f234ea2c598a22 100644 (file)
@@ -33,7 +33,7 @@ unsigned long pte_errors;     /* updated by do_page_fault() */
 /* __PHX__ :: - check the vmalloc_fault in do_page_fault()
  *            - also look into include/asm-or32/mmu_context.h
  */
-volatile pgd_t *current_pgd;
+volatile pgd_t *current_pgd[NR_CPUS];
 
 extern void die(char *, struct pt_regs *, long);
 
@@ -319,7 +319,7 @@ vmalloc_fault:
 
                phx_mmu("vmalloc_fault");
 */
-               pgd = (pgd_t *)current_pgd + offset;
+               pgd = (pgd_t *)current_pgd[smp_processor_id()] + offset;
                pgd_k = init_mm.pgd + offset;
 
                /* Since we're two-level, we don't need to do both
index f67d82b9d22fb10ee719882c2389dc7a40ca2843..6972d5d6f23f7343306c750945a22862e1f9e46e 100644 (file)
@@ -147,7 +147,7 @@ void __init paging_init(void)
         * (even if it is most probably not used until the next
         *  switch_mm)
         */
-       current_pgd = init_mm.pgd;
+       current_pgd[smp_processor_id()] = init_mm.pgd;
 
        end = (unsigned long)__va(max_low_pfn * PAGE_SIZE);
 
index 683bd4d31c7cb021080c30c73f81ecd1e878b078..6c253a2e86bc4e1a2cba5e509f09fdbe5c148635 100644 (file)
@@ -49,7 +49,7 @@
  *
  */
 
-void flush_tlb_all(void)
+void local_flush_tlb_all(void)
 {
        int i;
        unsigned long num_tlb_sets;
@@ -86,7 +86,7 @@ void flush_tlb_all(void)
 #define flush_itlb_page_no_eir(addr) \
        mtspr_off(SPR_ITLBMR_BASE(0), ITLB_OFFSET(addr), 0);
 
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 {
        if (have_dtlbeir)
                flush_dtlb_page_eir(addr);
@@ -99,8 +99,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
                flush_itlb_page_no_eir(addr);
 }
 
-void flush_tlb_range(struct vm_area_struct *vma,
-                    unsigned long start, unsigned long end)
+void local_flush_tlb_range(struct vm_area_struct *vma,
+                          unsigned long start, unsigned long end)
 {
        int addr;
        bool dtlbeir;
@@ -129,13 +129,13 @@ void flush_tlb_range(struct vm_area_struct *vma,
  * This should be changed to loop over over mm and call flush_tlb_range.
  */
 
-void flush_tlb_mm(struct mm_struct *mm)
+void local_flush_tlb_mm(struct mm_struct *mm)
 {
 
        /* Was seeing bugs with the mm struct passed to us. Scrapped most of
           this function. */
        /* Several architctures do this */
-       flush_tlb_all();
+       local_flush_tlb_all();
 }
 
 /* called in schedule() just before actually doing the switch_to */
@@ -149,14 +149,14 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
         * might be invalid at points where we still need to derefer
         * the pgd.
         */
-       current_pgd = next->pgd;
+       current_pgd[smp_processor_id()] = next->pgd;
 
        /* We don't have context support implemented, so flush all
         * entries belonging to previous map
         */
 
        if (prev != next)
-               flush_tlb_mm(prev);
+               local_flush_tlb_mm(prev);
 
 }
 
index bc54addd589f69daf4fb7aae0c23d47ea5c631a1..88bae6676c9b6ef3823f6a8590882d43b0d83b22 100644 (file)
@@ -261,7 +261,7 @@ atomic64_set(atomic64_t *v, s64 i)
 static __inline__ s64
 atomic64_read(const atomic64_t *v)
 {
-       return ACCESS_ONCE((v)->counter);
+       return READ_ONCE((v)->counter);
 }
 
 #define atomic64_inc(v)                (atomic64_add(   1,(v)))
index af03359e6ac5685d6fa93361b5a0f4f4817a8cae..6f84b6acc86ed1e291b70818b7715400e0f7b7e6 100644 (file)
@@ -32,6 +32,7 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *x,
                                cpu_relax();
        mb();
 }
+#define arch_spin_lock_flags arch_spin_lock_flags
 
 static inline void arch_spin_unlock(arch_spinlock_t *x)
 {
@@ -169,25 +170,4 @@ static __inline__ int arch_write_trylock(arch_rwlock_t *rw)
        return result;
 }
 
-/*
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-static __inline__ int arch_read_can_lock(arch_rwlock_t *rw)
-{
-       return rw->counter >= 0;
-}
-
-/*
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-static __inline__ int arch_write_can_lock(arch_rwlock_t *rw)
-{
-       return !rw->counter;
-}
-
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
 #endif /* __ASM_SPINLOCK_H */
index 10a5ae9553fd657211524e4af5257958815e134a..27a2dd616a7d1732dc27dc332fcbd162375a7caf 100644 (file)
@@ -92,7 +92,7 @@ static int pdc_console_setup(struct console *co, char *options)
 #define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
 
 static void pdc_console_poll(unsigned long unused);
-static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0);
+static DEFINE_TIMER(pdc_console_timer, pdc_console_poll);
 static struct tty_port tty_port;
 
 static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
index edbe571bcc54a7b8eb41e3f0c35f1105ac9b3af7..b9ebc3085fb7932e632527df1f309e76260912d4 100644 (file)
@@ -161,6 +161,7 @@ void arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags)
                local_irq_restore(flags_dis);
        }
 }
+#define arch_spin_lock_flags arch_spin_lock_flags
 
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
@@ -181,9 +182,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
  * read-locks.
  */
 
-#define arch_read_can_lock(rw)         ((rw)->lock >= 0)
-#define arch_write_can_lock(rw)        (!(rw)->lock)
-
 #ifdef CONFIG_PPC64
 #define __DO_SIGN_EXTEND       "extsw  %0,%0\n"
 #define WRLOCK_TOKEN           LOCK_TOKEN      /* it's negative */
@@ -302,9 +300,6 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
        rw->lock = 0;
 }
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
 #define arch_spin_relax(lock)  __spin_yield(lock)
 #define arch_read_relax(lock)  __rw_yield(lock)
 #define arch_write_relax(lock) __rw_yield(lock)
index 992c0d258e5d564c3b57526e968b26e78bb9292d..e4395f937d63a3d8381854c7bfb89334217e2e16 100644 (file)
@@ -91,11 +91,13 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
  * and that value will be returned. If all free regions are visited without
  * func returning non-zero, then zero will be returned.
  */
-int arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *))
+int arch_kexec_walk_mem(struct kexec_buf *kbuf,
+                       int (*func)(struct resource *, void *))
 {
        int ret = 0;
        u64 i;
        phys_addr_t mstart, mend;
+       struct resource res = { };
 
        if (kbuf->top_down) {
                for_each_free_mem_range_reverse(i, NUMA_NO_NODE, 0,
@@ -105,7 +107,9 @@ int arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *))
                         * range while in kexec, end points to the last byte
                         * in the range.
                         */
-                       ret = func(mstart, mend - 1, kbuf);
+                       res.start = mstart;
+                       res.end = mend - 1;
+                       ret = func(&res, kbuf);
                        if (ret)
                                break;
                }
@@ -117,7 +121,9 @@ int arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *))
                         * range while in kexec, end points to the last byte
                         * in the range.
                         */
-                       ret = func(mstart, mend - 1, kbuf);
+                       res.start = mstart;
+                       res.end = mend - 1;
+                       ret = func(&res, kbuf);
                        if (ret)
                                break;
                }
index 1643e9e5365573659bbdf79d6e5dfddb5ee4eafc..3f1c4fcbe0aa50616c45ce4369bbdb0ecdd15ad4 100644 (file)
@@ -78,7 +78,7 @@ static unsigned long lock_rtas(void)
 
        local_irq_save(flags);
        preempt_disable();
-       arch_spin_lock_flags(&rtas.lock, flags);
+       arch_spin_lock(&rtas.lock);
        return flags;
 }
 
index 57190f384f633e75170cff96dffc26fa540ef976..1d89163d67f2b5449d02bf683e6bc872df31f1a0 100644 (file)
@@ -262,9 +262,8 @@ static void wd_timer_reset(unsigned int cpu, struct timer_list *t)
        add_timer_on(t, cpu);
 }
 
-static void wd_timer_fn(unsigned long data)
+static void wd_timer_fn(struct timer_list *t)
 {
-       struct timer_list *t = this_cpu_ptr(&wd_timer);
        int cpu = smp_processor_id();
 
        watchdog_timer_interrupt(cpu);
@@ -288,7 +287,7 @@ static void start_watchdog_timer_on(unsigned int cpu)
 
        per_cpu(wd_timer_tb, cpu) = get_tb();
 
-       setup_pinned_timer(t, wd_timer_fn, 0);
+       timer_setup(t, wd_timer_fn, TIMER_PINNED);
        wd_timer_reset(cpu, t);
 }
 
index 7c62967d672caa818d12c26620520603fb3c49c7..59247af5fd45076f063ff3567f143cfe2328bd92 100644 (file)
@@ -646,6 +646,16 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
                hnow_v = hpte_new_to_old_v(hnow_v, hnow_r);
                hnow_r = hpte_new_to_old_r(hnow_r);
        }
+
+       /*
+        * If the HPT is being resized, don't update the HPTE,
+        * instead let the guest retry after the resize operation is complete.
+        * The synchronization for hpte_setup_done test vs. set is provided
+        * by the HPTE lock.
+        */
+       if (!kvm->arch.hpte_setup_done)
+               goto out_unlock;
+
        if ((hnow_v & ~HPTE_V_HVLOCK) != hpte[0] || hnow_r != hpte[1] ||
            rev->guest_rpte != hpte[2])
                /* HPTE has been changed under us; let the guest retry */
index 73bf1ebfa78fcc7ef74dd51713d800ea12e9e745..8d43cf205d348779e1316c81fc95ab6133eb0784 100644 (file)
@@ -2705,11 +2705,14 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
         * Hard-disable interrupts, and check resched flag and signals.
         * If we need to reschedule or deliver a signal, clean up
         * and return without going into the guest(s).
+        * If the hpte_setup_done flag has been cleared, don't go into the
+        * guest because that means a HPT resize operation is in progress.
         */
        local_irq_disable();
        hard_irq_disable();
        if (lazy_irq_pending() || need_resched() ||
-           recheck_signals(&core_info)) {
+           recheck_signals(&core_info) ||
+           (!kvm_is_radix(vc->kvm) && !vc->kvm->arch.hpte_setup_done)) {
                local_irq_enable();
                vc->vcore_state = VCORE_INACTIVE;
                /* Unlock all except the primary vcore */
@@ -3078,7 +3081,7 @@ out:
 
 static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
-       int n_ceded, i;
+       int n_ceded, i, r;
        struct kvmppc_vcore *vc;
        struct kvm_vcpu *v;
 
@@ -3132,6 +3135,20 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        while (vcpu->arch.state == KVMPPC_VCPU_RUNNABLE &&
               !signal_pending(current)) {
+               /* See if the HPT and VRMA are ready to go */
+               if (!kvm_is_radix(vcpu->kvm) &&
+                   !vcpu->kvm->arch.hpte_setup_done) {
+                       spin_unlock(&vc->lock);
+                       r = kvmppc_hv_setup_htab_rma(vcpu);
+                       spin_lock(&vc->lock);
+                       if (r) {
+                               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+                               kvm_run->fail_entry.hardware_entry_failure_reason = 0;
+                               vcpu->arch.ret = r;
+                               break;
+                       }
+               }
+
                if (vc->vcore_state == VCORE_PREEMPT && vc->runner == NULL)
                        kvmppc_vcore_end_preempt(vc);
 
@@ -3249,13 +3266,6 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
        /* Order vcpus_running vs. hpte_setup_done, see kvmppc_alloc_reset_hpt */
        smp_mb();
 
-       /* On the first time here, set up HTAB and VRMA */
-       if (!kvm_is_radix(vcpu->kvm) && !vcpu->kvm->arch.hpte_setup_done) {
-               r = kvmppc_hv_setup_htab_rma(vcpu);
-               if (r)
-                       goto out;
-       }
-
        flush_all_to_thread(current);
 
        /* Save userspace EBB and other register values */
@@ -3303,7 +3313,6 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
        }
        mtspr(SPRN_VRSAVE, user_vrsave);
 
- out:
        vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
        atomic_dec(&vcpu->kvm->arch.vcpus_running);
        return r;
index a51df9ef529d9356cb54c75721510e50cfa69b8d..73016451f33005844ad13b31f22a31011ccaccaa 100644 (file)
@@ -1452,7 +1452,7 @@ static void topology_schedule_update(void)
        schedule_work(&topology_work);
 }
 
-static void topology_timer_fn(unsigned long ignored)
+static void topology_timer_fn(struct timer_list *unused)
 {
        if (prrn_enabled && cpumask_weight(&cpu_associativity_changes_mask))
                topology_schedule_update();
@@ -1462,14 +1462,11 @@ static void topology_timer_fn(unsigned long ignored)
                reset_topology_timer();
        }
 }
-static struct timer_list topology_timer =
-       TIMER_INITIALIZER(topology_timer_fn, 0, 0);
+static struct timer_list topology_timer;
 
 static void reset_topology_timer(void)
 {
-       topology_timer.data = 0;
-       topology_timer.expires = jiffies + 60 * HZ;
-       mod_timer(&topology_timer, topology_timer.expires);
+       mod_timer(&topology_timer, jiffies + 60 * HZ);
 }
 
 #ifdef CONFIG_SMP
@@ -1529,7 +1526,8 @@ int start_topology_update(void)
                        prrn_enabled = 0;
                        vphn_enabled = 1;
                        setup_cpu_associativity_change_counters();
-                       init_timer_deferrable(&topology_timer);
+                       timer_setup(&topology_timer, topology_timer_fn,
+                                   TIMER_DEFERRABLE);
                        reset_topology_timer();
                }
        }
index 7a9cde0cfbd110c97d9229baa1f14633e295a3fe..acd3206dfae3477452f11c4a96dfc1638cafae00 100644 (file)
@@ -43,7 +43,7 @@ ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
        if (!opal_memcons)
                return -ENODEV;
 
-       out_pos = be32_to_cpu(ACCESS_ONCE(opal_memcons->out_pos));
+       out_pos = be32_to_cpu(READ_ONCE(opal_memcons->out_pos));
 
        /* Now we've read out_pos, put a barrier in before reading the new
         * data it points to in conbuf. */
index ae55e715cc748e0148601c9cd05de1f969f60560..863a62a6de3cc3f8daa92a9f9ae8c34065dff989 100644 (file)
@@ -68,6 +68,7 @@ config S390
        select ARCH_BINFMT_ELF_STATE
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ELF_RANDOMIZE
+       select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA
        select ARCH_HAS_KCOV
@@ -143,7 +144,6 @@ config S390
        select HAVE_DYNAMIC_FTRACE
        select HAVE_DYNAMIC_FTRACE_WITH_REGS
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
-       select HAVE_EXIT_THREAD
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
@@ -538,6 +538,22 @@ config ARCH_RANDOM
 
          If unsure, say Y.
 
+config ALTERNATIVES
+       def_bool y
+       prompt "Patch optimized instructions for running CPU type"
+       help
+         When enabled the kernel code is compiled with additional
+         alternative instructions blocks optimized for newer CPU types.
+         These alternative instructions blocks are patched at kernel boot
+         time when running CPU supports them. This mechanism is used to
+         optimize some critical code paths (i.e. spinlocks) for newer CPUs
+         even if kernel is build to support older machine generations.
+
+         This mechanism could be disabled by appending "noaltinstr"
+         option to the kernel command line.
+
+         If unsure, say Y.
+
 endmenu
 
 menu "Memory setup"
@@ -809,18 +825,6 @@ config PFAULT
          Everybody who wants to run Linux under VM != VM4.2 should select
          this option.
 
-config SHARED_KERNEL
-       bool "VM shared kernel support"
-       depends on !JUMP_LABEL
-       help
-         Select this option, if you want to share the text segment of the
-         Linux kernel between different VM guests. This reduces memory
-         usage with lots of guests but greatly increases kernel size.
-         Also if a kernel was IPL'ed from a shared segment the kexec system
-         call will not work.
-         You should only select this option if you know what you are
-         doing and want to exploit this feature.
-
 config CMM
        def_tristate n
        prompt "Cooperative memory management"
@@ -930,17 +934,4 @@ config S390_GUEST
          Select this option if you want to run the kernel as a guest under
          the KVM hypervisor.
 
-config S390_GUEST_OLD_TRANSPORT
-       def_bool y
-       prompt "Guest support for old s390 virtio transport (DEPRECATED)"
-       depends on S390_GUEST
-       help
-         Enable this option to add support for the old s390-virtio
-         transport (i.e. virtio devices NOT based on virtio-ccw). This
-         type of virtio devices is only available on the experimental
-         kuli userspace or with old (< 2.6) qemu. If you are running
-         with a modern version of qemu (which supports virtio-ccw since
-         1.4 and uses it by default since version 2.4), you probably won't
-         need this.
-
 endmenu
index dac821cfcd430310a95624754d7dd814bcd7705b..6b3f41985f28e17763b0f71973d56186ed28c7dc 100644 (file)
@@ -21,7 +21,7 @@ KBUILD_CFLAGS += -m64
 KBUILD_AFLAGS  += -m64
 UTS_MACHINE    := s390x
 STACK_SIZE     := 16384
-CHECKFLAGS     += -D__s390__ -D__s390x__
+CHECKFLAGS     += -D__s390__ -D__s390x__ -mbig-endian
 
 export LD_BFD
 
@@ -133,6 +133,7 @@ archclean:
 
 archprepare:
        $(Q)$(MAKE) $(build)=$(tools) include/generated/facilities.h
+       $(Q)$(MAKE) $(build)=$(tools) include/generated/dis.h
 
 # Don't use tabs in echo arguments
 define archhelp
index 3df10c989893cf8577eee9c92ba1cbf2ea47cfda..29e3dc99b9164b2d902c6f492c5511eefa906af0 100644 (file)
@@ -12,7 +12,7 @@ targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4
 targets += misc.o piggy.o sizes.h head.o
 
 KBUILD_CFLAGS := -m64 -D__KERNEL__ -O2
-KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING -D__NO_FORTIFY
 KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -msoft-float
 KBUILD_CFLAGS += $(call cc-option,-mpacked-stack)
 KBUILD_CFLAGS += $(call cc-option,-ffreestanding)
index 77633200f42cbf5d581b28bb3401135949f13d1b..cecf38b9ec82d50e24fdb068c157a7680274cb75 100644 (file)
@@ -170,9 +170,7 @@ unsigned long decompress_kernel(void)
        free_mem_ptr = (unsigned long) &_end;
        free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
 
-       puts("Uncompressing Linux... ");
        __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error);
-       puts("Ok, booting the kernel.\n");
        return (unsigned long) output;
 }
 
index 282072206df7076e732b8fcd121ca49b1693634a..84eccc88c065083594fd71f895857813af2edcdb 100644 (file)
@@ -69,7 +69,6 @@ CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_CLEANCACHE=y
 CONFIG_FRONTSWAP=y
-CONFIG_CMA=y
 CONFIG_CMA_DEBUG=y
 CONFIG_CMA_DEBUGFS=y
 CONFIG_MEM_SOFT_DIRTY=y
@@ -379,7 +378,6 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_OSD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
 CONFIG_BLK_DEV_RAM_DAX=y
@@ -416,7 +414,6 @@ CONFIG_SCSI_OSD_ULD=m
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
 CONFIG_MD_MULTIPATH=m
 CONFIG_MD_FAULTY=m
 CONFIG_BLK_DEV_DM=m
@@ -483,6 +480,8 @@ CONFIG_INFINIBAND=m
 CONFIG_INFINIBAND_USER_ACCESS=m
 CONFIG_MLX4_INFINIBAND=m
 CONFIG_MLX5_INFINIBAND=m
+CONFIG_VFIO=m
+CONFIG_VFIO_PCI=m
 CONFIG_VIRTIO_BALLOON=m
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
@@ -599,7 +598,6 @@ CONFIG_DETECT_HUNG_TASK=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_ON_OOPS=y
 CONFIG_DEBUG_TIMEKEEPING=y
-CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_LOCK_STAT=y
@@ -629,10 +627,8 @@ CONFIG_SCHED_TRACER=y
 CONFIG_FTRACE_SYSCALLS=y
 CONFIG_STACK_TRACER=y
 CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_UPROBE_EVENTS=y
 CONFIG_FUNCTION_PROFILER=y
 CONFIG_HIST_TRIGGERS=y
-CONFIG_TRACE_ENUM_MAP_FILE=y
 CONFIG_LKDTM=m
 CONFIG_TEST_LIST_SORT=y
 CONFIG_TEST_SORT=y
@@ -649,6 +645,7 @@ CONFIG_ENCRYPTED_KEYS=m
 CONFIG_SECURITY=y
 CONFIG_SECURITY_NETWORK=y
 CONFIG_HARDENED_USERCOPY=y
+CONFIG_FORTIFY_SOURCE=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SELINUX_BOOTPARAM=y
 CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
@@ -705,12 +702,12 @@ CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
+CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_SHA1_S390=m
 CONFIG_CRYPTO_SHA256_S390=m
 CONFIG_CRYPTO_SHA512_S390=m
 CONFIG_CRYPTO_DES_S390=m
 CONFIG_CRYPTO_AES_S390=m
-CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_ASYMMETRIC_KEY_TYPE=y
index 3c6b78189fbcc805225b9b2e05d5812c5a5f9b67..f7202358e6d74ff0e367f12ba6f83d260583fde2 100644 (file)
@@ -70,7 +70,6 @@ CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_CLEANCACHE=y
 CONFIG_FRONTSWAP=y
-CONFIG_CMA=y
 CONFIG_MEM_SOFT_DIRTY=y
 CONFIG_ZSWAP=y
 CONFIG_ZBUD=m
@@ -376,7 +375,6 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_OSD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
 CONFIG_BLK_DEV_RAM_DAX=y
@@ -412,7 +410,6 @@ CONFIG_SCSI_OSD_ULD=m
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
 CONFIG_MD_MULTIPATH=m
 CONFIG_MD_FAULTY=m
 CONFIG_BLK_DEV_DM=m
@@ -479,6 +476,8 @@ CONFIG_INFINIBAND=m
 CONFIG_INFINIBAND_USER_ACCESS=m
 CONFIG_MLX4_INFINIBAND=m
 CONFIG_MLX5_INFINIBAND=m
+CONFIG_VFIO=m
+CONFIG_VFIO_PCI=m
 CONFIG_VIRTIO_BALLOON=m
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
@@ -575,10 +574,8 @@ CONFIG_SCHED_TRACER=y
 CONFIG_FTRACE_SYSCALLS=y
 CONFIG_STACK_TRACER=y
 CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_UPROBE_EVENTS=y
 CONFIG_FUNCTION_PROFILER=y
 CONFIG_HIST_TRIGGERS=y
-CONFIG_TRACE_ENUM_MAP_FILE=y
 CONFIG_LKDTM=m
 CONFIG_PERCPU_TEST=m
 CONFIG_ATOMIC64_SELFTEST=y
@@ -650,12 +647,12 @@ CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
+CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_SHA1_S390=m
 CONFIG_CRYPTO_SHA256_S390=m
 CONFIG_CRYPTO_SHA512_S390=m
 CONFIG_CRYPTO_DES_S390=m
 CONFIG_CRYPTO_AES_S390=m
-CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRC7=m
index 653d72bcc007db3b2e39aa7225b447c18c9d9cb2..03100fe74ea8f8441798378d8cfd30be095e16d4 100644 (file)
@@ -68,7 +68,6 @@ CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_CLEANCACHE=y
 CONFIG_FRONTSWAP=y
-CONFIG_CMA=y
 CONFIG_MEM_SOFT_DIRTY=y
 CONFIG_ZSWAP=y
 CONFIG_ZBUD=m
@@ -374,7 +373,6 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_OSD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
 CONFIG_BLK_DEV_RAM_DAX=y
@@ -410,7 +408,6 @@ CONFIG_SCSI_OSD_ULD=m
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
 CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
 CONFIG_MD_MULTIPATH=m
 CONFIG_MD_FAULTY=m
 CONFIG_BLK_DEV_DM=m
@@ -477,6 +474,8 @@ CONFIG_INFINIBAND=m
 CONFIG_INFINIBAND_USER_ACCESS=m
 CONFIG_MLX4_INFINIBAND=m
 CONFIG_MLX5_INFINIBAND=m
+CONFIG_VFIO=m
+CONFIG_VFIO_PCI=m
 CONFIG_VIRTIO_BALLOON=m
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
@@ -573,10 +572,8 @@ CONFIG_SCHED_TRACER=y
 CONFIG_FTRACE_SYSCALLS=y
 CONFIG_STACK_TRACER=y
 CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_UPROBE_EVENTS=y
 CONFIG_FUNCTION_PROFILER=y
 CONFIG_HIST_TRIGGERS=y
-CONFIG_TRACE_ENUM_MAP_FILE=y
 CONFIG_LKDTM=m
 CONFIG_PERCPU_TEST=m
 CONFIG_ATOMIC64_SELFTEST=y
@@ -648,12 +645,12 @@ CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
+CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_SHA1_S390=m
 CONFIG_CRYPTO_SHA256_S390=m
 CONFIG_CRYPTO_SHA512_S390=m
 CONFIG_CRYPTO_DES_S390=m
 CONFIG_CRYPTO_AES_S390=m
-CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRC7=m
index 591cbdf615af046d4e0662241b03c3b113280333..b48e20dd94e96a52f845782c2dd134b015794004 100644 (file)
@@ -4,9 +4,11 @@
  * s390 implementation of the AES Cipher Algorithm.
  *
  * s390 Version:
- *   Copyright IBM Corp. 2005, 2007
+ *   Copyright IBM Corp. 2005, 2017
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *             Sebastian Siewior (sebastian@breakpoint.cc> SW-Fallback
+ *             Patrick Steuer <patrick.steuer@de.ibm.com>
+ *             Harald Freudenberger <freude@de.ibm.com>
  *
  * Derived from "crypto/aes_generic.c"
  *
 
 #include <crypto/aes.h>
 #include <crypto/algapi.h>
+#include <crypto/ghash.h>
+#include <crypto/internal/aead.h>
 #include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/cpufeature.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/fips.h>
+#include <linux/string.h>
 #include <crypto/xts.h>
 #include <asm/cpacf.h>
 
 static u8 *ctrblk;
 static DEFINE_SPINLOCK(ctrblk_lock);
 
-static cpacf_mask_t km_functions, kmc_functions, kmctr_functions;
+static cpacf_mask_t km_functions, kmc_functions, kmctr_functions,
+                   kma_functions;
 
 struct s390_aes_ctx {
        u8 key[AES_MAX_KEY_SIZE];
@@ -55,6 +62,17 @@ struct s390_xts_ctx {
        struct crypto_skcipher *fallback;
 };
 
+struct gcm_sg_walk {
+       struct scatter_walk walk;
+       unsigned int walk_bytes;
+       u8 *walk_ptr;
+       unsigned int walk_bytes_remain;
+       u8 buf[AES_BLOCK_SIZE];
+       unsigned int buf_bytes;
+       u8 *ptr;
+       unsigned int nbytes;
+};
+
 static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key,
                unsigned int key_len)
 {
@@ -771,6 +789,267 @@ static struct crypto_alg ctr_aes_alg = {
        }
 };
 
+static int gcm_aes_setkey(struct crypto_aead *tfm, const u8 *key,
+                         unsigned int keylen)
+{
+       struct s390_aes_ctx *ctx = crypto_aead_ctx(tfm);
+
+       switch (keylen) {
+       case AES_KEYSIZE_128:
+               ctx->fc = CPACF_KMA_GCM_AES_128;
+               break;
+       case AES_KEYSIZE_192:
+               ctx->fc = CPACF_KMA_GCM_AES_192;
+               break;
+       case AES_KEYSIZE_256:
+               ctx->fc = CPACF_KMA_GCM_AES_256;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       memcpy(ctx->key, key, keylen);
+       ctx->key_len = keylen;
+       return 0;
+}
+
+static int gcm_aes_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
+{
+       switch (authsize) {
+       case 4:
+       case 8:
+       case 12:
+       case 13:
+       case 14:
+       case 15:
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void gcm_sg_walk_start(struct gcm_sg_walk *gw, struct scatterlist *sg,
+                             unsigned int len)
+{
+       memset(gw, 0, sizeof(*gw));
+       gw->walk_bytes_remain = len;
+       scatterwalk_start(&gw->walk, sg);
+}
+
+static int gcm_sg_walk_go(struct gcm_sg_walk *gw, unsigned int minbytesneeded)
+{
+       int n;
+
+       /* minbytesneeded <= AES_BLOCK_SIZE */
+       if (gw->buf_bytes && gw->buf_bytes >= minbytesneeded) {
+               gw->ptr = gw->buf;
+               gw->nbytes = gw->buf_bytes;
+               goto out;
+       }
+
+       if (gw->walk_bytes_remain == 0) {
+               gw->ptr = NULL;
+               gw->nbytes = 0;
+               goto out;
+       }
+
+       gw->walk_bytes = scatterwalk_clamp(&gw->walk, gw->walk_bytes_remain);
+       if (!gw->walk_bytes) {
+               scatterwalk_start(&gw->walk, sg_next(gw->walk.sg));
+               gw->walk_bytes = scatterwalk_clamp(&gw->walk,
+                                                  gw->walk_bytes_remain);
+       }
+       gw->walk_ptr = scatterwalk_map(&gw->walk);
+
+       if (!gw->buf_bytes && gw->walk_bytes >= minbytesneeded) {
+               gw->ptr = gw->walk_ptr;
+               gw->nbytes = gw->walk_bytes;
+               goto out;
+       }
+
+       while (1) {
+               n = min(gw->walk_bytes, AES_BLOCK_SIZE - gw->buf_bytes);
+               memcpy(gw->buf + gw->buf_bytes, gw->walk_ptr, n);
+               gw->buf_bytes += n;
+               gw->walk_bytes_remain -= n;
+               scatterwalk_unmap(&gw->walk);
+               scatterwalk_advance(&gw->walk, n);
+               scatterwalk_done(&gw->walk, 0, gw->walk_bytes_remain);
+
+               if (gw->buf_bytes >= minbytesneeded) {
+                       gw->ptr = gw->buf;
+                       gw->nbytes = gw->buf_bytes;
+                       goto out;
+               }
+
+               gw->walk_bytes = scatterwalk_clamp(&gw->walk,
+                                                  gw->walk_bytes_remain);
+               if (!gw->walk_bytes) {
+                       scatterwalk_start(&gw->walk, sg_next(gw->walk.sg));
+                       gw->walk_bytes = scatterwalk_clamp(&gw->walk,
+                                                       gw->walk_bytes_remain);
+               }
+               gw->walk_ptr = scatterwalk_map(&gw->walk);
+       }
+
+out:
+       return gw->nbytes;
+}
+
+static void gcm_sg_walk_done(struct gcm_sg_walk *gw, unsigned int bytesdone)
+{
+       int n;
+
+       if (gw->ptr == NULL)
+               return;
+
+       if (gw->ptr == gw->buf) {
+               n = gw->buf_bytes - bytesdone;
+               if (n > 0) {
+                       memmove(gw->buf, gw->buf + bytesdone, n);
+                       gw->buf_bytes -= n;
+               } else
+                       gw->buf_bytes = 0;
+       } else {
+               gw->walk_bytes_remain -= bytesdone;
+               scatterwalk_unmap(&gw->walk);
+               scatterwalk_advance(&gw->walk, bytesdone);
+               scatterwalk_done(&gw->walk, 0, gw->walk_bytes_remain);
+       }
+}
+
+static int gcm_aes_crypt(struct aead_request *req, unsigned int flags)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct s390_aes_ctx *ctx = crypto_aead_ctx(tfm);
+       unsigned int ivsize = crypto_aead_ivsize(tfm);
+       unsigned int taglen = crypto_aead_authsize(tfm);
+       unsigned int aadlen = req->assoclen;
+       unsigned int pclen = req->cryptlen;
+       int ret = 0;
+
+       unsigned int len, in_bytes, out_bytes,
+                    min_bytes, bytes, aad_bytes, pc_bytes;
+       struct gcm_sg_walk gw_in, gw_out;
+       u8 tag[GHASH_DIGEST_SIZE];
+
+       struct {
+               u32 _[3];               /* reserved */
+               u32 cv;                 /* Counter Value */
+               u8 t[GHASH_DIGEST_SIZE];/* Tag */
+               u8 h[AES_BLOCK_SIZE];   /* Hash-subkey */
+               u64 taadl;              /* Total AAD Length */
+               u64 tpcl;               /* Total Plain-/Cipher-text Length */
+               u8 j0[GHASH_BLOCK_SIZE];/* initial counter value */
+               u8 k[AES_MAX_KEY_SIZE]; /* Key */
+       } param;
+
+       /*
+        * encrypt
+        *   req->src: aad||plaintext
+        *   req->dst: aad||ciphertext||tag
+        * decrypt
+        *   req->src: aad||ciphertext||tag
+        *   req->dst: aad||plaintext, return 0 or -EBADMSG
+        * aad, plaintext and ciphertext may be empty.
+        */
+       if (flags & CPACF_DECRYPT)
+               pclen -= taglen;
+       len = aadlen + pclen;
+
+       memset(&param, 0, sizeof(param));
+       param.cv = 1;
+       param.taadl = aadlen * 8;
+       param.tpcl = pclen * 8;
+       memcpy(param.j0, req->iv, ivsize);
+       *(u32 *)(param.j0 + ivsize) = 1;
+       memcpy(param.k, ctx->key, ctx->key_len);
+
+       gcm_sg_walk_start(&gw_in, req->src, len);
+       gcm_sg_walk_start(&gw_out, req->dst, len);
+
+       do {
+               min_bytes = min_t(unsigned int,
+                                 aadlen > 0 ? aadlen : pclen, AES_BLOCK_SIZE);
+               in_bytes = gcm_sg_walk_go(&gw_in, min_bytes);
+               out_bytes = gcm_sg_walk_go(&gw_out, min_bytes);
+               bytes = min(in_bytes, out_bytes);
+
+               if (aadlen + pclen <= bytes) {
+                       aad_bytes = aadlen;
+                       pc_bytes = pclen;
+                       flags |= CPACF_KMA_LAAD | CPACF_KMA_LPC;
+               } else {
+                       if (aadlen <= bytes) {
+                               aad_bytes = aadlen;
+                               pc_bytes = (bytes - aadlen) &
+                                          ~(AES_BLOCK_SIZE - 1);
+                               flags |= CPACF_KMA_LAAD;
+                       } else {
+                               aad_bytes = bytes & ~(AES_BLOCK_SIZE - 1);
+                               pc_bytes = 0;
+                       }
+               }
+
+               if (aad_bytes > 0)
+                       memcpy(gw_out.ptr, gw_in.ptr, aad_bytes);
+
+               cpacf_kma(ctx->fc | flags, &param,
+                         gw_out.ptr + aad_bytes,
+                         gw_in.ptr + aad_bytes, pc_bytes,
+                         gw_in.ptr, aad_bytes);
+
+               gcm_sg_walk_done(&gw_in, aad_bytes + pc_bytes);
+               gcm_sg_walk_done(&gw_out, aad_bytes + pc_bytes);
+               aadlen -= aad_bytes;
+               pclen -= pc_bytes;
+       } while (aadlen + pclen > 0);
+
+       if (flags & CPACF_DECRYPT) {
+               scatterwalk_map_and_copy(tag, req->src, len, taglen, 0);
+               if (crypto_memneq(tag, param.t, taglen))
+                       ret = -EBADMSG;
+       } else
+               scatterwalk_map_and_copy(param.t, req->dst, len, taglen, 1);
+
+       memzero_explicit(&param, sizeof(param));
+       return ret;
+}
+
+static int gcm_aes_encrypt(struct aead_request *req)
+{
+       return gcm_aes_crypt(req, CPACF_ENCRYPT);
+}
+
+static int gcm_aes_decrypt(struct aead_request *req)
+{
+       return gcm_aes_crypt(req, CPACF_DECRYPT);
+}
+
+static struct aead_alg gcm_aes_aead = {
+       .setkey                 = gcm_aes_setkey,
+       .setauthsize            = gcm_aes_setauthsize,
+       .encrypt                = gcm_aes_encrypt,
+       .decrypt                = gcm_aes_decrypt,
+
+       .ivsize                 = GHASH_BLOCK_SIZE - sizeof(u32),
+       .maxauthsize            = GHASH_DIGEST_SIZE,
+       .chunksize              = AES_BLOCK_SIZE,
+
+       .base                   = {
+               .cra_flags              = CRYPTO_ALG_TYPE_AEAD,
+               .cra_blocksize          = 1,
+               .cra_ctxsize            = sizeof(struct s390_aes_ctx),
+               .cra_priority           = 900,
+               .cra_name               = "gcm(aes)",
+               .cra_driver_name        = "gcm-aes-s390",
+               .cra_module             = THIS_MODULE,
+       },
+};
+
 static struct crypto_alg *aes_s390_algs_ptr[5];
 static int aes_s390_algs_num;
 
@@ -790,16 +1069,19 @@ static void aes_s390_fini(void)
                crypto_unregister_alg(aes_s390_algs_ptr[aes_s390_algs_num]);
        if (ctrblk)
                free_page((unsigned long) ctrblk);
+
+       crypto_unregister_aead(&gcm_aes_aead);
 }
 
 static int __init aes_s390_init(void)
 {
        int ret;
 
-       /* Query available functions for KM, KMC and KMCTR */
+       /* Query available functions for KM, KMC, KMCTR and KMA */
        cpacf_query(CPACF_KM, &km_functions);
        cpacf_query(CPACF_KMC, &kmc_functions);
        cpacf_query(CPACF_KMCTR, &kmctr_functions);
+       cpacf_query(CPACF_KMA, &kma_functions);
 
        if (cpacf_test_func(&km_functions, CPACF_KM_AES_128) ||
            cpacf_test_func(&km_functions, CPACF_KM_AES_192) ||
@@ -840,6 +1122,14 @@ static int __init aes_s390_init(void)
                        goto out_err;
        }
 
+       if (cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_128) ||
+           cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_192) ||
+           cpacf_test_func(&kma_functions, CPACF_KMA_GCM_AES_256)) {
+               ret = crypto_register_aead(&gcm_aes_aead);
+               if (ret)
+                       goto out_err;
+       }
+
        return 0;
 out_err:
        aes_s390_fini();
index 20244a38c88698f887e002bce2423afeb199ace3..46a3178d8bc6e6860b898bd8377d62dd2e5b6260 100644 (file)
@@ -53,7 +53,6 @@ CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_CLEANCACHE=y
 CONFIG_FRONTSWAP=y
-CONFIG_CMA=y
 CONFIG_ZSWAP=y
 CONFIG_ZBUD=m
 CONFIG_ZSMALLOC=m
@@ -163,7 +162,6 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_PANIC_ON_OOPS=y
-CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_LOCK_STAT=y
 CONFIG_DEBUG_LOCKDEP=y
@@ -179,7 +177,6 @@ CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
 CONFIG_STACK_TRACER=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_FUNCTION_PROFILER=y
-CONFIG_TRACE_ENUM_MAP_FILE=y
 CONFIG_KPROBES_SANITY_TEST=y
 CONFIG_S390_PTDUMP=y
 CONFIG_CRYPTO_CRYPTD=m
index 6e2c9f7e47fa03a7dcc51691da104aa9d3b6fcbf..41c211a4d8b17023ff2fde819d8c103527c09878 100644 (file)
@@ -15,6 +15,7 @@ generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
 generic-y += preempt.h
+generic-y += rwsem.h
 generic-y += trace_clock.h
 generic-y += unaligned.h
 generic-y += word-at-a-time.h
diff --git a/arch/s390/include/asm/alternative.h b/arch/s390/include/asm/alternative.h
new file mode 100644 (file)
index 0000000..6c268f6
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef _ASM_S390_ALTERNATIVE_H
+#define _ASM_S390_ALTERNATIVE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/stringify.h>
+
+struct alt_instr {
+       s32 instr_offset;       /* original instruction */
+       s32 repl_offset;        /* offset to replacement instruction */
+       u16 facility;           /* facility bit set for replacement */
+       u8  instrlen;           /* length of original instruction */
+       u8  replacementlen;     /* length of new instruction */
+} __packed;
+
+#ifdef CONFIG_ALTERNATIVES
+extern void apply_alternative_instructions(void);
+extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
+#else
+static inline void apply_alternative_instructions(void) {};
+static inline void apply_alternatives(struct alt_instr *start,
+                                     struct alt_instr *end) {};
+#endif
+/*
+ * |661:       |662:     |6620      |663:
+ * +-----------+---------------------+
+ * | oldinstr  | oldinstr_padding    |
+ * |          +----------+----------+
+ * |          |          |          |
+ * |          | >6 bytes |6/4/2 nops|
+ * |          |6 bytes jg----------->
+ * +-----------+---------------------+
+ *              ^^ static padding ^^
+ *
+ * .altinstr_replacement section
+ * +---------------------+-----------+
+ * |6641:                           |6651:
+ * | alternative instr 1            |
+ * +-----------+---------+- - - - - -+
+ * |6642:               |6652:      |
+ * | alternative instr 2 | padding
+ * +---------------------+- - - - - -+
+ *                       ^ runtime ^
+ *
+ * .altinstructions section
+ * +---------------------------------+
+ * | alt_instr entries for each      |
+ * | alternative instr              |
+ * +---------------------------------+
+ */
+
+#define b_altinstr(num)        "664"#num
+#define e_altinstr(num)        "665"#num
+
+#define e_oldinstr_pad_end     "663"
+#define oldinstr_len           "662b-661b"
+#define oldinstr_total_len     e_oldinstr_pad_end"b-661b"
+#define altinstr_len(num)      e_altinstr(num)"b-"b_altinstr(num)"b"
+#define oldinstr_pad_len(num) \
+       "-(((" altinstr_len(num) ")-(" oldinstr_len ")) > 0) * " \
+       "((" altinstr_len(num) ")-(" oldinstr_len "))"
+
+#define INSTR_LEN_SANITY_CHECK(len)                                    \
+       ".if " len " > 254\n"                                           \
+       "\t.error \"cpu alternatives does not support instructions "    \
+               "blocks > 254 bytes\"\n"                                \
+       ".endif\n"                                                      \
+       ".if (" len ") %% 2\n"                                          \
+       "\t.error \"cpu alternatives instructions length is odd\"\n"    \
+       ".endif\n"
+
+#define OLDINSTR_PADDING(oldinstr, num)                                        \
+       ".if " oldinstr_pad_len(num) " > 6\n"                           \
+       "\tjg " e_oldinstr_pad_end "f\n"                                \
+       "6620:\n"                                                       \
+       "\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \
+       ".else\n"                                                       \
+       "\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n"        \
+       "\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n"   \
+       "\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n"  \
+       ".endif\n"
+
+#define OLDINSTR(oldinstr, num)                                                \
+       "661:\n\t" oldinstr "\n662:\n"                                  \
+       OLDINSTR_PADDING(oldinstr, num)                                 \
+       e_oldinstr_pad_end ":\n"                                        \
+       INSTR_LEN_SANITY_CHECK(oldinstr_len)
+
+#define OLDINSTR_2(oldinstr, num1, num2)                               \
+       "661:\n\t" oldinstr "\n662:\n"                                  \
+       ".if " altinstr_len(num1) " < " altinstr_len(num2) "\n"         \
+       OLDINSTR_PADDING(oldinstr, num2)                                \
+       ".else\n"                                                       \
+       OLDINSTR_PADDING(oldinstr, num1)                                \
+       ".endif\n"                                                      \
+       e_oldinstr_pad_end ":\n"                                        \
+       INSTR_LEN_SANITY_CHECK(oldinstr_len)
+
+#define ALTINSTR_ENTRY(facility, num)                                  \
+       "\t.long 661b - .\n"                    /* old instruction */   \
+       "\t.long " b_altinstr(num)"b - .\n"     /* alt instruction */   \
+       "\t.word " __stringify(facility) "\n"   /* facility bit    */   \
+       "\t.byte " oldinstr_total_len "\n"      /* source len      */   \
+       "\t.byte " altinstr_len(num) "\n"       /* alt instruction len */
+
+#define ALTINSTR_REPLACEMENT(altinstr, num)    /* replacement */       \
+       b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n"      \
+       INSTR_LEN_SANITY_CHECK(altinstr_len(num))
+
+#ifdef CONFIG_ALTERNATIVES
+/* alternative assembly primitive: */
+#define ALTERNATIVE(oldinstr, altinstr, facility) \
+       ".pushsection .altinstr_replacement, \"ax\"\n"                  \
+       ALTINSTR_REPLACEMENT(altinstr, 1)                               \
+       ".popsection\n"                                                 \
+       OLDINSTR(oldinstr, 1)                                           \
+       ".pushsection .altinstructions,\"a\"\n"                         \
+       ALTINSTR_ENTRY(facility, 1)                                     \
+       ".popsection\n"
+
+#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\
+       ".pushsection .altinstr_replacement, \"ax\"\n"                  \
+       ALTINSTR_REPLACEMENT(altinstr1, 1)                              \
+       ALTINSTR_REPLACEMENT(altinstr2, 2)                              \
+       ".popsection\n"                                                 \
+       OLDINSTR_2(oldinstr, 1, 2)                                      \
+       ".pushsection .altinstructions,\"a\"\n"                         \
+       ALTINSTR_ENTRY(facility1, 1)                                    \
+       ALTINSTR_ENTRY(facility2, 2)                                    \
+       ".popsection\n"
+#else
+/* Alternative instructions are disabled, let's put just oldinstr in */
+#define ALTERNATIVE(oldinstr, altinstr, facility) \
+       oldinstr "\n"
+
+#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \
+       oldinstr "\n"
+#endif
+
+/*
+ * Alternative instructions for different CPU types or capabilities.
+ *
+ * This allows to use optimized instructions even on generic binary
+ * kernels.
+ *
+ * oldinstr is padded with jump and nops at compile time if altinstr is
+ * longer. altinstr is padded with jump and nops at run-time during patching.
+ *
+ * For non barrier like inlines please define new variants
+ * without volatile and memory clobber.
+ */
+#define alternative(oldinstr, altinstr, facility)                      \
+       asm volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory")
+
+#define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \
+       asm volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1,          \
+                                  altinstr2, facility2) ::: "memory")
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_S390_ALTERNATIVE_H */
index e9f7d7a57f999789a8494de34e8f9454efb8137f..09aed1095336259411eee0d9fdbb0fd37fc35179 100644 (file)
@@ -28,42 +28,42 @@ static void s390_arch_random_generate(u8 *buf, unsigned int nbytes)
 
 static inline bool arch_has_random(void)
 {
-       if (static_branch_likely(&s390_arch_random_available))
-               return true;
        return false;
 }
 
 static inline bool arch_has_random_seed(void)
 {
-       return arch_has_random();
+       if (static_branch_likely(&s390_arch_random_available))
+               return true;
+       return false;
 }
 
 static inline bool arch_get_random_long(unsigned long *v)
 {
-       if (static_branch_likely(&s390_arch_random_available)) {
-               s390_arch_random_generate((u8 *)v, sizeof(*v));
-               return true;
-       }
        return false;
 }
 
 static inline bool arch_get_random_int(unsigned int *v)
 {
-       if (static_branch_likely(&s390_arch_random_available)) {
-               s390_arch_random_generate((u8 *)v, sizeof(*v));
-               return true;
-       }
        return false;
 }
 
 static inline bool arch_get_random_seed_long(unsigned long *v)
 {
-       return arch_get_random_long(v);
+       if (static_branch_likely(&s390_arch_random_available)) {
+               s390_arch_random_generate((u8 *)v, sizeof(*v));
+               return true;
+       }
+       return false;
 }
 
 static inline bool arch_get_random_seed_int(unsigned int *v)
 {
-       return arch_get_random_int(v);
+       if (static_branch_likely(&s390_arch_random_available)) {
+               s390_arch_random_generate((u8 *)v, sizeof(*v));
+               return true;
+       }
+       return false;
 }
 
 #endif /* CONFIG_ARCH_RANDOM */
index f479e4c0b87e7e4a120eb92eba3dab89c366b710..d3f09526ee19fadab79306c30038f26475a3e9a7 100644 (file)
@@ -40,19 +40,24 @@ __ATOMIC_OPS(__atomic64_xor, long, "laxg")
 #undef __ATOMIC_OPS
 #undef __ATOMIC_OP
 
-static inline void __atomic_add_const(int val, int *ptr)
-{
-       asm volatile(
-               "       asi     %[ptr],%[val]\n"
-               : [ptr] "+Q" (*ptr) : [val] "i" (val) : "cc");
+#define __ATOMIC_CONST_OP(op_name, op_type, op_string, op_barrier)     \
+static inline void op_name(op_type val, op_type *ptr)                  \
+{                                                                      \
+       asm volatile(                                                   \
+               op_string "     %[ptr],%[val]\n"                        \
+               op_barrier                                              \
+               : [ptr] "+Q" (*ptr) : [val] "i" (val) : "cc", "memory");\
 }
 
-static inline void __atomic64_add_const(long val, long *ptr)
-{
-       asm volatile(
-               "       agsi    %[ptr],%[val]\n"
-               : [ptr] "+Q" (*ptr) : [val] "i" (val) : "cc");
-}
+#define __ATOMIC_CONST_OPS(op_name, op_type, op_string)                        \
+       __ATOMIC_CONST_OP(op_name, op_type, op_string, "\n")            \
+       __ATOMIC_CONST_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n")
+
+__ATOMIC_CONST_OPS(__atomic_add_const, int, "asi")
+__ATOMIC_CONST_OPS(__atomic64_add_const, long, "agsi")
+
+#undef __ATOMIC_CONST_OPS
+#undef __ATOMIC_CONST_OP
 
 #else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
 
@@ -108,6 +113,11 @@ __ATOMIC64_OPS(__atomic64_xor, "xgr")
 
 #undef __ATOMIC64_OPS
 
+#define __atomic_add_const(val, ptr)           __atomic_add(val, ptr)
+#define __atomic_add_const_barrier(val, ptr)   __atomic_add(val, ptr)
+#define __atomic64_add_const(val, ptr)         __atomic64_add(val, ptr)
+#define __atomic64_add_const_barrier(val, ptr) __atomic64_add(val, ptr)
+
 #endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
 
 static inline int __atomic_cmpxchg(int *ptr, int old, int new)
index b00777ce93b46f4d1433f35300cff31ea84545f0..99aa817dad32334db02283d689703e72893c28a7 100644 (file)
@@ -42,6 +42,7 @@ struct ccwgroup_device {
  * @thaw: undo work done in @freeze
  * @restore: callback for restoring after hibernation
  * @driver: embedded driver structure
+ * @ccw_driver: supported ccw_driver (optional)
  */
 struct ccwgroup_driver {
        int (*setup) (struct ccwgroup_device *);
@@ -56,6 +57,7 @@ struct ccwgroup_driver {
        int (*restore)(struct ccwgroup_device *);
 
        struct device_driver driver;
+       struct ccw_driver *ccw_driver;
 };
 
 extern int  ccwgroup_driver_register   (struct ccwgroup_driver *cdriver);
index 056670ebba67b27e1e1679a69dc57682c4673f7e..3cc52e37b4b2a6c4f209b4df3e153d05729d3d59 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * CP Assist for Cryptographic Functions (CPACF)
  *
- * Copyright IBM Corp. 2003, 2016
+ * Copyright IBM Corp. 2003, 2017
  * Author(s): Thomas Spatzier
  *           Jan Glauber
  *           Harald Freudenberger (freude@de.ibm.com)
 #define CPACF_PRNO_TRNG_Q_R2C_RATIO    0x70
 #define CPACF_PRNO_TRNG                        0x72
 
+/*
+ * Function codes for the KMA (CIPHER MESSAGE WITH AUTHENTICATION)
+ * instruction
+ */
+#define CPACF_KMA_QUERY                0x00
+#define CPACF_KMA_GCM_AES_128  0x12
+#define CPACF_KMA_GCM_AES_192  0x13
+#define CPACF_KMA_GCM_AES_256  0x14
+
+/*
+ * Flags for the KMA (CIPHER MESSAGE WITH AUTHENTICATION) instruction
+ */
+#define CPACF_KMA_LPC  0x100   /* Last-Plaintext/Ciphertext */
+#define CPACF_KMA_LAAD 0x200   /* Last-AAD */
+#define CPACF_KMA_HS   0x400   /* Hash-subkey Supplied */
+
 typedef struct { unsigned char bytes[16]; } cpacf_mask_t;
 
 /**
@@ -179,6 +195,8 @@ static inline int __cpacf_check_opcode(unsigned int opcode)
                return test_facility(77);       /* check for MSA4 */
        case CPACF_PRNO:
                return test_facility(57);       /* check for MSA5 */
+       case CPACF_KMA:
+               return test_facility(146);      /* check for MSA8 */
        default:
                BUG();
        }
@@ -470,4 +488,36 @@ static inline void cpacf_pckmo(long func, void *param)
                : "cc", "memory");
 }
 
+/**
+ * cpacf_kma() - executes the KMA (CIPHER MESSAGE WITH AUTHENTICATION)
+ *              instruction
+ * @func: the function code passed to KMA; see CPACF_KMA_xxx defines
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ * @aad: address of additional authenticated data memory area
+ * @aad_len: length of aad operand in bytes
+ */
+static inline void cpacf_kma(unsigned long func, void *param, u8 *dest,
+                            const u8 *src, unsigned long src_len,
+                            const u8 *aad, unsigned long aad_len)
+{
+       register unsigned long r0 asm("0") = (unsigned long) func;
+       register unsigned long r1 asm("1") = (unsigned long) param;
+       register unsigned long r2 asm("2") = (unsigned long) src;
+       register unsigned long r3 asm("3") = (unsigned long) src_len;
+       register unsigned long r4 asm("4") = (unsigned long) aad;
+       register unsigned long r5 asm("5") = (unsigned long) aad_len;
+       register unsigned long r6 asm("6") = (unsigned long) dest;
+
+       asm volatile(
+               "0:     .insn   rrf,%[opc] << 16,%[dst],%[src],%[aad],0\n"
+               "       brc     1,0b\n" /* handle partial completion */
+               : [dst] "+a" (r6), [src] "+a" (r2), [slen] "+d" (r3),
+                 [aad] "+a" (r4), [alen] "+d" (r5)
+               : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KMA)
+               : "cc", "memory");
+}
+
 #endif /* _ASM_S390_CPACF_H */
index 93e0d72f6c9484b900a328f0f2aef65aa1dc5749..99c93d0346f9feda966ec81f3a881035712d5528 100644 (file)
@@ -8,6 +8,18 @@
 #ifndef __ASM_CTL_REG_H
 #define __ASM_CTL_REG_H
 
+#include <linux/const.h>
+
+#define CR2_GUARDED_STORAGE            _BITUL(63 - 59)
+
+#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)
+
+#ifndef __ASSEMBLY__
+
 #include <linux/bug.h>
 
 #define __ctl_load(array, low, high) do {                              \
@@ -55,7 +67,11 @@ void smp_ctl_clear_bit(int cr, int bit);
 union ctlreg0 {
        unsigned long val;
        struct {
-               unsigned long      : 32;
+               unsigned long      : 8;
+               unsigned long tcx  : 1; /* Transactional-Execution control */
+               unsigned long pifo : 1; /* Transactional-Execution Program-
+                                          Interruption-Filtering Override */
+               unsigned long      : 22;
                unsigned long      : 3;
                unsigned long lap  : 1; /* Low-address-protection control */
                unsigned long      : 4;
@@ -71,6 +87,19 @@ union ctlreg0 {
        };
 };
 
+union ctlreg2 {
+       unsigned long val;
+       struct {
+               unsigned long       : 33;
+               unsigned long ducto : 25;
+               unsigned long       : 1;
+               unsigned long gse   : 1;
+               unsigned long       : 1;
+               unsigned long tds   : 1;
+               unsigned long tdc   : 2;
+       };
+};
+
 #ifdef CONFIG_SMP
 # define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit)
 # define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit)
@@ -79,4 +108,5 @@ union ctlreg0 {
 # define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
 #endif
 
+#endif /* __ASSEMBLY__ */
 #endif /* __ASM_CTL_REG_H */
index a4ed25dd32785268bc6693028fb691f34fb2596a..c305d39f50160dacc8d47c124dd691a4c3e572ca 100644 (file)
 #include <linux/refcount.h>
 #include <uapi/asm/debug.h>
 
-#define DEBUG_MAX_LEVEL            6  /* debug levels range from 0 to 6 */
-#define DEBUG_OFF_LEVEL            -1 /* level where debug is switched off */
-#define DEBUG_FLUSH_ALL            -1 /* parameter to flush all areas */
-#define DEBUG_MAX_VIEWS            10 /* max number of views in proc fs */
-#define DEBUG_MAX_NAME_LEN         64 /* max length for a debugfs file name */
-#define DEBUG_DEFAULT_LEVEL        3  /* initial debug level */
+#define DEBUG_MAX_LEVEL                   6  /* debug levels range from 0 to 6 */
+#define DEBUG_OFF_LEVEL                   -1 /* level where debug is switched off */
+#define DEBUG_FLUSH_ALL                   -1 /* parameter to flush all areas */
+#define DEBUG_MAX_VIEWS                   10 /* max number of views in proc fs */
+#define DEBUG_MAX_NAME_LEN        64 /* max length for a debugfs file name */
+#define DEBUG_DEFAULT_LEVEL       3  /* initial debug level */
 
 #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
 
-#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
-                                             /* the entry information */
+#define DEBUG_DATA(entry) (char *)(entry + 1) /* data is stored behind */
+                                             /* the entry information */
 
 typedef struct __debug_entry debug_entry_t;
 
 struct debug_view;
 
-typedef struct debug_info {    
-       struct debug_infonext;
-       struct debug_infoprev;
+typedef struct debug_info {
+       struct debug_info *next;
+       struct debug_info *prev;
        refcount_t ref_count;
-       spinlock_t lock;                        
+       spinlock_t lock;
        int level;
        int nr_areas;
        int pages_per_area;
        int buf_size;
-       int entry_size; 
-       debug_entry_t*** areas;
+       int entry_size;
+       debug_entry_t ***areas;
        int active_area;
        int *active_pages;
        int *active_entries;
-       struct dentrydebugfs_root_entry;
-       struct dentrydebugfs_entries[DEBUG_MAX_VIEWS];
-       struct debug_view* views[DEBUG_MAX_VIEWS];      
+       struct dentry *debugfs_root_entry;
+       struct dentry *debugfs_entries[DEBUG_MAX_VIEWS];
+       struct debug_view *views[DEBUG_MAX_VIEWS];
        char name[DEBUG_MAX_NAME_LEN];
        umode_t mode;
 } debug_info_t;
 
-typedef int (debug_header_proc_t) (debug_info_tid,
-                                  struct debug_viewview,
+typedef int (debug_header_proc_t) (debug_info_t *id,
+                                  struct debug_view *view,
                                   int area,
-                                  debug_entry_tentry,
-                                  charout_buf);
-
-typedef int (debug_format_proc_t) (debug_info_tid,
-                                  struct debug_view* view, char* out_buf,
-                                  const charin_buf);
-typedef int (debug_prolog_proc_t) (debug_info_tid,
-                                  struct debug_viewview,
-                                  charout_buf);
-typedef int (debug_input_proc_t) (debug_info_tid,
-                                 struct debug_viewview,
-                                 struct filefile,
+                                  debug_entry_t *entry,
+                                  char *out_buf);
+
+typedef int (debug_format_proc_t) (debug_info_t *id,
+                                  struct debug_view *view, char *out_buf,
+                                  const char *in_buf);
+typedef int (debug_prolog_proc_t) (debug_info_t *id,
+                                  struct debug_view *view,
+                                  char *out_buf);
+typedef int (debug_input_proc_t) (debug_info_t *id,
+                                 struct debug_view *view,
+                                 struct file *file,
                                  const char __user *user_buf,
-                                 size_t in_buf_size, loff_t* offset);
+                                 size_t in_buf_size, loff_t *offset);
+
+int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
+                        int area, debug_entry_t *entry, char *out_buf);
 
-int debug_dflt_header_fn(debug_info_t* id, struct debug_view* view,
-                        int area, debug_entry_t* entry, char* out_buf);                                                
-                               
 struct debug_view {
        char name[DEBUG_MAX_NAME_LEN];
-       debug_prolog_proc_tprolog_proc;
-       debug_header_proc_theader_proc;
-       debug_format_proc_tformat_proc;
-       debug_input_proc_t*  input_proc;
-       void*                private_data;
+       debug_prolog_proc_t *prolog_proc;
+       debug_header_proc_t *header_proc;
+       debug_format_proc_t *format_proc;
+       debug_input_proc_t  *input_proc;
+       void                *private_data;
 };
 
 extern struct debug_view debug_hex_ascii_view;
@@ -87,65 +87,67 @@ extern struct debug_view debug_sprintf_view;
 
 /* do NOT use the _common functions */
 
-debug_entry_t* debug_event_common(debug_info_t* id, int level, 
-                                  const void* data, int length);
+debug_entry_t *debug_event_common(debug_info_t *id, int level,
+                                 const void *data, int length);
 
-debug_entry_t* debug_exception_common(debug_info_t* id, int level, 
-                                      const void* data, int length);
+debug_entry_t *debug_exception_common(debug_info_t *id, int level,
+                                     const void *data, int length);
 
 /* Debug Feature API: */
 
 debug_info_t *debug_register(const char *name, int pages, int nr_areas,
-                             int buf_size);
+                            int buf_size);
 
 debug_info_t *debug_register_mode(const char *name, int pages, int nr_areas,
                                  int buf_size, umode_t mode, uid_t uid,
                                  gid_t gid);
 
-void debug_unregister(debug_info_tid);
+void debug_unregister(debug_info_t *id);
 
-void debug_set_level(debug_info_tid, int new_level);
+void debug_set_level(debug_info_t *id, int new_level);
 
 void debug_set_critical(void);
 void debug_stop_all(void);
 
-static inline bool debug_level_enabled(debug_info_tid, int level)
+static inline bool debug_level_enabled(debug_info_t *id, int level)
 {
        return level <= id->level;
 }
 
-static inline debug_entry_t*
-debug_event(debug_info_t* id, int level, void* data, int length)
+static inline debug_entry_t *debug_event(debug_info_t *id, int level,
+                                        void *data, int length)
 {
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
                return NULL;
-        return debug_event_common(id,level,data,length);
+       return debug_event_common(id, level, data, length);
 }
 
-static inline debug_entry_t*
-debug_int_event(debug_info_t* id, int level, unsigned int tag)
+static inline debug_entry_t *debug_int_event(debug_info_t *id, int level,
+                                            unsigned int tag)
 {
-        unsigned int t=tag;
+       unsigned int t = tag;
+
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
                return NULL;
-        return debug_event_common(id,level,&t,sizeof(unsigned int));
+       return debug_event_common(id, level, &t, sizeof(unsigned int));
 }
 
-static inline debug_entry_t *
-debug_long_event (debug_info_t* id, int level, unsigned long tag)
+static inline debug_entry_t *debug_long_event(debug_info_t *id, int level,
+                                             unsigned long tag)
 {
-        unsigned long t=tag;
+       unsigned long t = tag;
+
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
                return NULL;
-        return debug_event_common(id,level,&t,sizeof(unsigned long));
+       return debug_event_common(id, level, &t, sizeof(unsigned long));
 }
 
-static inline debug_entry_t*
-debug_text_event(debug_info_t* id, int level, const char* txt)
+static inline debug_entry_t *debug_text_event(debug_info_t *id, int level,
+                                             const char *txt)
 {
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
                return NULL;
-        return debug_event_common(id,level,txt,strlen(txt));
+       return debug_event_common(id, level, txt, strlen(txt));
 }
 
 /*
@@ -161,6 +163,7 @@ __debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
        debug_entry_t *__ret;                                           \
        debug_info_t *__id = _id;                                       \
        int __level = _level;                                           \
+                                                                       \
        if ((!__id) || (__level > __id->level))                         \
                __ret = NULL;                                           \
        else                                                            \
@@ -169,38 +172,40 @@ __debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
        __ret;                                                          \
 })
 
-static inline debug_entry_t*
-debug_exception(debug_info_t* id, int level, void* data, int length)
+static inline debug_entry_t *debug_exception(debug_info_t *id, int level,
+                                            void *data, int length)
 {
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
                return NULL;
-        return debug_exception_common(id,level,data,length);
+       return debug_exception_common(id, level, data, length);
 }
 
-static inline debug_entry_t*
-debug_int_exception(debug_info_t* id, int level, unsigned int tag)
+static inline debug_entry_t *debug_int_exception(debug_info_t *id, int level,
+                                                unsigned int tag)
 {
-        unsigned int t=tag;
+       unsigned int t = tag;
+
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
                return NULL;
-        return debug_exception_common(id,level,&t,sizeof(unsigned int));
+       return debug_exception_common(id, level, &t, sizeof(unsigned int));
 }
 
-static inline debug_entry_t *
-debug_long_exception (debug_info_t* id, int level, unsigned long tag)
+static inline debug_entry_t *debug_long_exception (debug_info_t *id, int level,
+                                                  unsigned long tag)
 {
-        unsigned long t=tag;
+       unsigned long t = tag;
+
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
                return NULL;
-        return debug_exception_common(id,level,&t,sizeof(unsigned long));
+       return debug_exception_common(id, level, &t, sizeof(unsigned long));
 }
 
-static inline debug_entry_t*
-debug_text_exception(debug_info_t* id, int level, const char* txt)
+static inline debug_entry_t *debug_text_exception(debug_info_t *id, int level,
+                                                 const char *txt)
 {
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
                return NULL;
-        return debug_exception_common(id,level,txt,strlen(txt));
+       return debug_exception_common(id, level, txt, strlen(txt));
 }
 
 /*
@@ -216,6 +221,7 @@ __debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
        debug_entry_t *__ret;                                           \
        debug_info_t *__id = _id;                                       \
        int __level = _level;                                           \
+                                                                       \
        if ((!__id) || (__level > __id->level))                         \
                __ret = NULL;                                           \
        else                                                            \
@@ -224,13 +230,13 @@ __debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
        __ret;                                                          \
 })
 
-int debug_register_view(debug_info_t* id, struct debug_view* view);
-int debug_unregister_view(debug_info_t* id, struct debug_view* view);
+int debug_register_view(debug_info_t *id, struct debug_view *view);
+int debug_unregister_view(debug_info_t *id, struct debug_view *view);
 
 /*
    define the debug levels:
    - 0 No debugging output to console or syslog
-   - 1 Log internal errors to syslog, ignore check conditions 
+   - 1 Log internal errors to syslog, ignore check conditions
    - 2 Log internal errors and check conditions to syslog
    - 3 Log internal errors to console, log check conditions to syslog
    - 4 Log internal errors and check conditions to console
@@ -248,17 +254,17 @@ int debug_unregister_view(debug_info_t* id, struct debug_view* view);
 #define INTERNAL_DEBMSG(x,y...) "D" __FILE__ "%d: " x, __LINE__, y
 
 #if DEBUG_LEVEL > 0
-#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER x )
-#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER x )
-#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER x )
-#define PRINT_FATAL(x...) panic ( PRINTK_HEADER x )
+#define PRINT_DEBUG(x...)      printk(KERN_DEBUG PRINTK_HEADER x)
+#define PRINT_INFO(x...)       printk(KERN_INFO PRINTK_HEADER x)
+#define PRINT_WARN(x...)       printk(KERN_WARNING PRINTK_HEADER x)
+#define PRINT_ERR(x...)                printk(KERN_ERR PRINTK_HEADER x)
+#define PRINT_FATAL(x...)      panic(PRINTK_HEADER x)
 #else
-#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#endif                         /* DASD_DEBUG */
-
-#endif                         /* DEBUG_H */
+#define PRINT_DEBUG(x...)      printk(KERN_DEBUG PRINTK_HEADER x)
+#define PRINT_INFO(x...)       printk(KERN_DEBUG PRINTK_HEADER x)
+#define PRINT_WARN(x...)       printk(KERN_DEBUG PRINTK_HEADER x)
+#define PRINT_ERR(x...)                printk(KERN_DEBUG PRINTK_HEADER x)
+#define PRINT_FATAL(x...)      printk(KERN_DEBUG PRINTK_HEADER x)
+#endif /* DASD_DEBUG */
+
+#endif /* DEBUG_H */
index 78d1b2d725b9997f5e9327f9aea5b22511ee6463..b0480c60a8e106a1690d6b483d59383f647eb8c6 100644 (file)
@@ -9,32 +9,7 @@
 #ifndef __ASM_S390_DIS_H__
 #define __ASM_S390_DIS_H__
 
-/* Type of operand */
-#define OPERAND_GPR    0x1     /* Operand printed as %rx */
-#define OPERAND_FPR    0x2     /* Operand printed as %fx */
-#define OPERAND_AR     0x4     /* Operand printed as %ax */
-#define OPERAND_CR     0x8     /* Operand printed as %cx */
-#define OPERAND_VR     0x10    /* Operand printed as %vx */
-#define OPERAND_DISP   0x20    /* Operand printed as displacement */
-#define OPERAND_BASE   0x40    /* Operand printed as base register */
-#define OPERAND_INDEX  0x80    /* Operand printed as index register */
-#define OPERAND_PCREL  0x100   /* Operand printed as pc-relative symbol */
-#define OPERAND_SIGNED 0x200   /* Operand printed as signed value */
-#define OPERAND_LENGTH 0x400   /* Operand printed as length (+1) */
-
-
-struct s390_operand {
-       int bits;               /* The number of bits in the operand. */
-       int shift;              /* The number of bits to shift. */
-       int flags;              /* One bit syntax flags. */
-};
-
-struct s390_insn {
-       const char name[5];
-       unsigned char opfrag;
-       unsigned char format;
-};
-
+#include <generated/dis.h>
 
 static inline int insn_length(unsigned char code)
 {
@@ -45,7 +20,6 @@ struct pt_regs;
 
 void show_code(struct pt_regs *regs);
 void print_fn_code(unsigned char *code, unsigned long len);
-int insn_to_mnemonic(unsigned char *instruction, char *buf, unsigned int len);
 struct s390_insn *find_insn(unsigned char *code);
 
 static inline int is_known_insn(unsigned char *code)
index 5a8d92758a5844de149a68fdff9a90a69cce71d4..186c7b5f55117b52f9f6d0897323c788684a1a04 100644 (file)
@@ -13,6 +13,8 @@
 #include <asm/cio.h>
 #include <asm/setup.h>
 
+#define NSS_NAME_SIZE  8
+
 #define IPL_PARMBLOCK_ORIGIN   0x2000
 
 #define IPL_PARM_BLK_FCP_LEN (sizeof(struct ipl_list_hdr) + \
@@ -106,7 +108,6 @@ extern size_t append_ipl_scpdata(char *, size_t);
 enum {
        IPL_DEVNO_VALID         = 1,
        IPL_PARMBLOCK_VALID     = 2,
-       IPL_NSS_VALID           = 4,
 };
 
 enum ipl_type {
index 28792ef82c837a2f2c11a5765098434018d02598..921391f2341eb8c4e886ee1bb4b67554f2d35d91 100644 (file)
@@ -63,8 +63,6 @@ typedef u16 kprobe_opcode_t;
 
 #define kretprobe_blacklist_size 0
 
-#define KPROBE_SWAP_INST       0x10
-
 /* Architecture specific copy of original instruction */
 struct arch_specific_insn {
        /* copy of original instruction */
index 51375e766e905a955a4df21fa185c669bfaa9544..fd006a272024a3fefd10ef2217c1b49c15adef82 100644 (file)
@@ -736,7 +736,6 @@ struct kvm_arch{
        wait_queue_head_t ipte_wq;
        int ipte_lock_count;
        struct mutex ipte_mutex;
-       struct ratelimit_state sthyi_limit;
        spinlock_t start_stop_lock;
        struct sie_page2 *sie_page2;
        struct kvm_s390_cpu_model model;
index 917f7344cab6fbf627ee29f788f1de467b0690e0..9eb36a1592c797a7d1e70e86b2c905a8266d4760 100644 (file)
@@ -134,8 +134,9 @@ struct lowcore {
        __u8    pad_0x03b4[0x03b8-0x03b4];      /* 0x03b4 */
        __u64   gmap;                           /* 0x03b8 */
        __u32   spinlock_lockval;               /* 0x03c0 */
-       __u32   fpu_flags;                      /* 0x03c4 */
-       __u8    pad_0x03c8[0x0400-0x03c8];      /* 0x03c8 */
+       __u32   spinlock_index;                 /* 0x03c4 */
+       __u32   fpu_flags;                      /* 0x03c8 */
+       __u8    pad_0x03cc[0x0400-0x03cc];      /* 0x03cc */
 
        /* Per cpu primary space access list */
        __u32   paste[16];                      /* 0x0400 */
index c8a7beadd3d4ce4f6112056fcd47950d3ea670e8..1e5dc4537bf21ba8f7d947b67a333a1d56938847 100644 (file)
 #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_CR14_CR_PENDING_SUB_MASK  (1 << 28)
-#define MCCK_CR14_RECOVERY_SUB_MASK    (1 << 27)
-#define MCCK_CR14_DEGRAD_SUB_MASK      (1 << 26)
-#define MCCK_CR14_EXT_DAMAGE_SUB_MASK  (1 << 25)
-#define MCCK_CR14_WARN_SUB_MASK                (1 << 24)
+#define MCCK_CODE_CR_VALID             _BITUL(63 - 29)
+#define MCCK_CODE_GS_VALID             _BITUL(63 - 36)
+#define MCCK_CODE_FC_VALID             _BITUL(63 - 43)
 
 #ifndef __ASSEMBLY__
 
@@ -87,6 +84,8 @@ union mci {
 
 #define MCESA_ORIGIN_MASK      (~0x3ffUL)
 #define MCESA_LC_MASK          (0xfUL)
+#define MCESA_MIN_SIZE         (1024)
+#define MCESA_MAX_SIZE         (2048)
 
 struct mcesa {
        u8 vector_save_area[1024];
@@ -95,8 +94,12 @@ struct mcesa {
 
 struct pt_regs;
 
-extern void s390_handle_mcck(void);
-extern void s390_do_machine_check(struct pt_regs *regs);
+void nmi_alloc_boot_cpu(struct lowcore *lc);
+int nmi_alloc_per_cpu(struct lowcore *lc);
+void nmi_free_per_cpu(struct lowcore *lc);
+
+void s390_handle_mcck(void);
+void s390_do_machine_check(struct pt_regs *regs);
 
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_S390_NMI_H */
index 6c2c38060f8beb41d4820766c80c6d8d15379e7b..5dfe4758827709f6b0cf8cc57c16b4acf6666137 100644 (file)
@@ -19,11 +19,7 @@ extern debug_info_t *pci_debug_err_id;
 
 static inline void zpci_err_hex(void *addr, int len)
 {
-       while (len > 0) {
-               debug_event(pci_debug_err_id, 0, (void *) addr, len);
-               len -= pci_debug_err_id->buf_size;
-               addr += pci_debug_err_id->buf_size;
-       }
+       debug_event(pci_debug_err_id, 0, addr, len);
 }
 
 #endif
index 419e83fa47217f2435cabc6478b57b04a3d1c39a..ba22a6ea51a144921d0722a35eea5e8265673454 100644 (file)
@@ -82,6 +82,6 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range);
 int zpci_load(u64 *data, u64 req, u64 offset);
 int zpci_store(u64 data, u64 req, u64 offset);
 int zpci_store_block(const u64 *data, u64 req, u64 offset);
-void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc);
+int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc);
 
 #endif
index bbe99cb8219d967ded4e04e995a010c159a05ff5..c7b4333d1de0aafe38ecccf606dde62053404be0 100644 (file)
@@ -13,6 +13,7 @@
 #define _S390_PGALLOC_H
 
 #include <linux/threads.h>
+#include <linux/string.h>
 #include <linux/gfp.h>
 #include <linux/mm.h>
 
@@ -28,24 +29,9 @@ void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long);
 void page_table_free_pgste(struct page *page);
 extern int page_table_allocate_pgste;
 
-static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
-{
-       struct addrtype { char _[256]; };
-       int i;
-
-       for (i = 0; i < n; i += 256) {
-               *s = val;
-               asm volatile(
-                       "mvc    8(248,%[s]),0(%[s])\n"
-                       : "+m" (*(struct addrtype *) s)
-                       : [s] "a" (s));
-               s += 256 / sizeof(long);
-       }
-}
-
 static inline void crst_table_init(unsigned long *crst, unsigned long entry)
 {
-       clear_table(crst, entry, _CRST_TABLE_SIZE);
+       memset64((u64 *)crst, entry, _CRST_ENTRIES);
 }
 
 static inline unsigned long pgd_entry_type(struct mm_struct *mm)
index 9cf92abe23c32ab495b5e4640f7904ab37cd0d54..f25bfe888933fe92dda958003b3dcad3e19ac2fc 100644 (file)
@@ -22,6 +22,7 @@
 #define CIF_IGNORE_IRQ         5       /* ignore interrupt (for udelay) */
 #define CIF_ENABLED_WAIT       6       /* in enabled wait state */
 #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)
@@ -31,6 +32,7 @@
 #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)
 
 #ifndef __ASSEMBLY__
 
@@ -219,10 +221,10 @@ void show_registers(struct pt_regs *regs);
 void show_cacheinfo(struct seq_file *m);
 
 /* Free all resources held by a thread. */
-extern void release_thread(struct task_struct *);
+static inline void release_thread(struct task_struct *tsk) { }
 
-/* Free guarded storage control block for current */
-void exit_thread_gs(void);
+/* Free guarded storage control block */
+void guarded_storage_release(struct task_struct *tsk);
 
 unsigned long get_wchan(struct task_struct *p);
 #define task_pt_regs(tsk) ((struct pt_regs *) \
index ea8896ba5afc77678017b72ec1bc571d4d39aac5..6b1540337ed6c79e5b508a731e27d47b7a43a9db 100644 (file)
@@ -6,55 +6,55 @@
 #define S390_RUNTIME_INSTR_STOP                0x2
 
 struct runtime_instr_cb {
-       __u64 buf_current;
-       __u64 buf_origin;
-       __u64 buf_limit;
+       __u64 rca;
+       __u64 roa;
+       __u64 rla;
 
-       __u32 valid             : 1;
-       __u32 pstate            : 1;
-       __u32 pstate_set_buf    : 1;
-       __u32 home_space        : 1;
-       __u32 altered           : 1;
-       __u32                   : 3;
-       __u32 pstate_sample     : 1;
-       __u32 sstate_sample     : 1;
-       __u32 pstate_collect    : 1;
-       __u32 sstate_collect    : 1;
-       __u32                   : 1;
-       __u32 halted_int        : 1;
-       __u32 int_requested     : 1;
-       __u32 buffer_full_int   : 1;
+       __u32 v                 : 1;
+       __u32 s                 : 1;
+       __u32 k                 : 1;
+       __u32 h                 : 1;
+       __u32 a                 : 1;
+       __u32 reserved1         : 3;
+       __u32 ps                : 1;
+       __u32 qs                : 1;
+       __u32 pc                : 1;
+       __u32 qc                : 1;
+       __u32 reserved2         : 1;
+       __u32 g                 : 1;
+       __u32 u                 : 1;
+       __u32 l                 : 1;
        __u32 key               : 4;
-       __u32                   : 9;
+       __u32 reserved3         : 8;
+       __u32 t                 : 1;
        __u32 rgs               : 3;
 
-       __u32 mode              : 4;
-       __u32 next              : 1;
+       __u32 m                 : 4;
+       __u32 n                 : 1;
        __u32 mae               : 1;
-       __u32                   : 2;
-       __u32 call_type_br      : 1;
-       __u32 return_type_br    : 1;
-       __u32 other_type_br     : 1;
-       __u32 bc_other_type     : 1;
-       __u32 emit              : 1;
-       __u32 tx_abort          : 1;
-       __u32                   : 2;
-       __u32 bp_xn             : 1;
-       __u32 bp_xt             : 1;
-       __u32 bp_ti             : 1;
-       __u32 bp_ni             : 1;
-       __u32 suppr_y           : 1;
-       __u32 suppr_z           : 1;
+       __u32 reserved4         : 2;
+       __u32 c                 : 1;
+       __u32 r                 : 1;
+       __u32 b                 : 1;
+       __u32 j                 : 1;
+       __u32 e                 : 1;
+       __u32 x                 : 1;
+       __u32 reserved5         : 2;
+       __u32 bpxn              : 1;
+       __u32 bpxt              : 1;
+       __u32 bpti              : 1;
+       __u32 bpni              : 1;
+       __u32 reserved6         : 2;
 
-       __u32 dc_miss_extra     : 1;
-       __u32 lat_lev_ignore    : 1;
-       __u32 ic_lat_lev        : 4;
-       __u32 dc_lat_lev        : 4;
+       __u32 d                 : 1;
+       __u32 f                 : 1;
+       __u32 ic                : 4;
+       __u32 dc                : 4;
 
-       __u64 reserved1;
-       __u64 scaling_factor;
+       __u64 reserved7;
+       __u64 sf;
        __u64 rsic;
-       __u64 reserved2;
+       __u64 reserved8;
 } __packed __aligned(8);
 
 extern struct runtime_instr_cb runtime_instr_empty_cb;
@@ -86,6 +86,8 @@ static inline void restore_ri_cb(struct runtime_instr_cb *cb_next,
                load_runtime_instr_cb(&runtime_instr_empty_cb);
 }
 
-void exit_thread_runtime_instr(void);
+struct task_struct;
+
+void runtime_instr_release(struct task_struct *tsk);
 
 #endif /* _RUNTIME_INSTR_H */
diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h
deleted file mode 100644 (file)
index f731b7b..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _S390_RWSEM_H
-#define _S390_RWSEM_H
-
-/*
- *  S390 version
- *    Copyright IBM Corp. 2002
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- *
- *  Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
- */
-
-/*
- *
- * The MSW of the count is the negated number of active writers and waiting
- * lockers, and the LSW is the total number of active locks
- *
- * The lock count is initialized to 0 (no active and no waiting lockers).
- *
- * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
- * uncontended lock. This can be determined because XADD returns the old value.
- * Readers increment by 1 and see a positive value when uncontended, negative
- * if there are writers (and maybe) readers waiting (in which case it goes to
- * sleep).
- *
- * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
- * be extended to 65534 by manually checking the whole MSW rather than relying
- * on the S flag.
- *
- * The value of ACTIVE_BIAS supports up to 65535 active processes.
- *
- * This should be totally fair - if anything is waiting, a process that wants a
- * lock will go to the back of the queue. When the currently active lock is
- * released, if there's a writer at the front of the queue, then that and only
- * that will be woken up; if there's a bunch of consecutive readers at the
- * front, then they'll all be woken up, but no other readers will be.
- */
-
-#ifndef _LINUX_RWSEM_H
-#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
-#endif
-
-#define RWSEM_UNLOCKED_VALUE   0x0000000000000000L
-#define RWSEM_ACTIVE_BIAS      0x0000000000000001L
-#define RWSEM_ACTIVE_MASK      0x00000000ffffffffL
-#define RWSEM_WAITING_BIAS     (-0x0000000100000000L)
-#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS        (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
-       signed long old, new;
-
-       asm volatile(
-               "       lg      %0,%2\n"
-               "0:     lgr     %1,%0\n"
-               "       aghi    %1,%4\n"
-               "       csg     %0,%1,%2\n"
-               "       jl      0b"
-               : "=&d" (old), "=&d" (new), "=Q" (sem->count)
-               : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
-               : "cc", "memory");
-       if (old < 0)
-               rwsem_down_read_failed(sem);
-}
-
-/*
- * trylock for reading -- returns 1 if successful, 0 if contention
- */
-static inline int __down_read_trylock(struct rw_semaphore *sem)
-{
-       signed long old, new;
-
-       asm volatile(
-               "       lg      %0,%2\n"
-               "0:     ltgr    %1,%0\n"
-               "       jm      1f\n"
-               "       aghi    %1,%4\n"
-               "       csg     %0,%1,%2\n"
-               "       jl      0b\n"
-               "1:"
-               : "=&d" (old), "=&d" (new), "=Q" (sem->count)
-               : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
-               : "cc", "memory");
-       return old >= 0 ? 1 : 0;
-}
-
-/*
- * lock for writing
- */
-static inline long ___down_write(struct rw_semaphore *sem)
-{
-       signed long old, new, tmp;
-
-       tmp = RWSEM_ACTIVE_WRITE_BIAS;
-       asm volatile(
-               "       lg      %0,%2\n"
-               "0:     lgr     %1,%0\n"
-               "       ag      %1,%4\n"
-               "       csg     %0,%1,%2\n"
-               "       jl      0b"
-               : "=&d" (old), "=&d" (new), "=Q" (sem->count)
-               : "Q" (sem->count), "m" (tmp)
-               : "cc", "memory");
-
-       return old;
-}
-
-static inline void __down_write(struct rw_semaphore *sem)
-{
-       if (___down_write(sem))
-               rwsem_down_write_failed(sem);
-}
-
-static inline int __down_write_killable(struct rw_semaphore *sem)
-{
-       if (___down_write(sem))
-               if (IS_ERR(rwsem_down_write_failed_killable(sem)))
-                       return -EINTR;
-
-       return 0;
-}
-
-/*
- * trylock for writing -- returns 1 if successful, 0 if contention
- */
-static inline int __down_write_trylock(struct rw_semaphore *sem)
-{
-       signed long old;
-
-       asm volatile(
-               "       lg      %0,%1\n"
-               "0:     ltgr    %0,%0\n"
-               "       jnz     1f\n"
-               "       csg     %0,%3,%1\n"
-               "       jl      0b\n"
-               "1:"
-               : "=&d" (old), "=Q" (sem->count)
-               : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
-               : "cc", "memory");
-       return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
-}
-
-/*
- * unlock after reading
- */
-static inline void __up_read(struct rw_semaphore *sem)
-{
-       signed long old, new;
-
-       asm volatile(
-               "       lg      %0,%2\n"
-               "0:     lgr     %1,%0\n"
-               "       aghi    %1,%4\n"
-               "       csg     %0,%1,%2\n"
-               "       jl      0b"
-               : "=&d" (old), "=&d" (new), "=Q" (sem->count)
-               : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
-               : "cc", "memory");
-       if (new < 0)
-               if ((new & RWSEM_ACTIVE_MASK) == 0)
-                       rwsem_wake(sem);
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
-       signed long old, new, tmp;
-
-       tmp = -RWSEM_ACTIVE_WRITE_BIAS;
-       asm volatile(
-               "       lg      %0,%2\n"
-               "0:     lgr     %1,%0\n"
-               "       ag      %1,%4\n"
-               "       csg     %0,%1,%2\n"
-               "       jl      0b"
-               : "=&d" (old), "=&d" (new), "=Q" (sem->count)
-               : "Q" (sem->count), "m" (tmp)
-               : "cc", "memory");
-       if (new < 0)
-               if ((new & RWSEM_ACTIVE_MASK) == 0)
-                       rwsem_wake(sem);
-}
-
-/*
- * downgrade write lock to read lock
- */
-static inline void __downgrade_write(struct rw_semaphore *sem)
-{
-       signed long old, new, tmp;
-
-       tmp = -RWSEM_WAITING_BIAS;
-       asm volatile(
-               "       lg      %0,%2\n"
-               "0:     lgr     %1,%0\n"
-               "       ag      %1,%4\n"
-               "       csg     %0,%1,%2\n"
-               "       jl      0b"
-               : "=&d" (old), "=&d" (new), "=Q" (sem->count)
-               : "Q" (sem->count), "m" (tmp)
-               : "cc", "memory");
-       if (new > 1)
-               rwsem_downgrade_wake(sem);
-}
-
-#endif /* _S390_RWSEM_H */
index 0ac3e8166e855caa26d9d0b206a6e81917d28f6c..54f81f8ed6622de13648f2f680a867acee7d1230 100644 (file)
@@ -4,6 +4,6 @@
 
 #include <asm-generic/sections.h>
 
-extern char _eshared[], _ehead[];
+extern char _ehead[];
 
 #endif
index f2c2b7cd90992dff3cb08eb6b99dba7fa5d6f2d6..8bc87dcb10ebdb002c52f54ead162f28c6559b22 100644 (file)
@@ -98,9 +98,6 @@ extern char vmpoff_cmd[];
 #define SET_CONSOLE_VT220      do { console_mode = 4; } while (0)
 #define SET_CONSOLE_HVC                do { console_mode = 5; } while (0)
 
-#define NSS_NAME_SIZE  8
-extern char kernel_nss_name[];
-
 #ifdef CONFIG_PFAULT
 extern int pfault_init(void);
 extern void pfault_fini(void);
index babe83ed416c82bb7521ccfa130f695c9fec2343..3907ead27ffa3b7ec3a746728782054bd57ec22b 100644 (file)
@@ -28,6 +28,7 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
 extern void smp_call_online_cpu(void (*func)(void *), void *);
 extern void smp_call_ipl_cpu(void (*func)(void *), void *);
+extern void smp_emergency_stop(void);
 
 extern int smp_find_processor_id(u16 address);
 extern int smp_store_status(int cpu);
@@ -53,6 +54,10 @@ static inline void smp_call_online_cpu(void (*func)(void *), void *data)
        func(data);
 }
 
+static inline void smp_emergency_stop(void)
+{
+}
+
 static inline int smp_find_processor_id(u16 address) { return 0; }
 static inline int smp_store_status(int cpu) { return 0; }
 static inline int smp_vcpu_scheduled(int cpu) { return 1; }
index f3f5e0155b10721d175f4c4fb0ac80427e665e37..0a29588aa00b64e21ffba5b31d77be94982f47a0 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/atomic_ops.h>
 #include <asm/barrier.h>
 #include <asm/processor.h>
+#include <asm/alternative.h>
 
 #define SPINLOCK_LOCKVAL (S390_lowcore.spinlock_lockval)
 
@@ -36,20 +37,16 @@ bool arch_vcpu_is_preempted(int cpu);
  * (the type definitions are in asm/spinlock_types.h)
  */
 
-void arch_lock_relax(int cpu);
+void arch_spin_relax(arch_spinlock_t *lock);
+#define arch_spin_relax        arch_spin_relax
 
 void arch_spin_lock_wait(arch_spinlock_t *);
 int arch_spin_trylock_retry(arch_spinlock_t *);
-void arch_spin_lock_wait_flags(arch_spinlock_t *, unsigned long flags);
-
-static inline void arch_spin_relax(arch_spinlock_t *lock)
-{
-       arch_lock_relax(lock->lock);
-}
+void arch_spin_lock_setup(int cpu);
 
 static inline u32 arch_spin_lockval(int cpu)
 {
-       return ~cpu;
+       return cpu + 1;
 }
 
 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
@@ -65,8 +62,7 @@ static inline int arch_spin_is_locked(arch_spinlock_t *lp)
 static inline int arch_spin_trylock_once(arch_spinlock_t *lp)
 {
        barrier();
-       return likely(arch_spin_value_unlocked(*lp) &&
-                     __atomic_cmpxchg_bool(&lp->lock, 0, SPINLOCK_LOCKVAL));
+       return likely(__atomic_cmpxchg_bool(&lp->lock, 0, SPINLOCK_LOCKVAL));
 }
 
 static inline void arch_spin_lock(arch_spinlock_t *lp)
@@ -79,8 +75,9 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *lp,
                                        unsigned long flags)
 {
        if (!arch_spin_trylock_once(lp))
-               arch_spin_lock_wait_flags(lp, flags);
+               arch_spin_lock_wait(lp);
 }
+#define arch_spin_lock_flags   arch_spin_lock_flags
 
 static inline int arch_spin_trylock(arch_spinlock_t *lp)
 {
@@ -93,11 +90,10 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
 {
        typecheck(int, lp->lock);
        asm volatile(
-#ifdef CONFIG_HAVE_MARCH_ZEC12_FEATURES
-               "       .long   0xb2fa0070\n"   /* NIAI 7 */
-#endif
-               "       st      %1,%0\n"
-               : "=Q" (lp->lock) : "d" (0) : "cc", "memory");
+               ALTERNATIVE("", ".long 0xb2fa0070", 49) /* NIAI 7 */
+               "       sth     %1,%0\n"
+               : "=Q" (((unsigned short *) &lp->lock)[1])
+               : "d" (0) : "cc", "memory");
 }
 
 /*
@@ -111,168 +107,53 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
  * read-locks.
  */
 
-/**
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_read_can_lock(x) ((int)(x)->lock >= 0)
-
-/**
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_write_can_lock(x) ((x)->lock == 0)
-
-extern int _raw_read_trylock_retry(arch_rwlock_t *lp);
-extern int _raw_write_trylock_retry(arch_rwlock_t *lp);
-
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-static inline int arch_read_trylock_once(arch_rwlock_t *rw)
-{
-       int old = ACCESS_ONCE(rw->lock);
-       return likely(old >= 0 &&
-                     __atomic_cmpxchg_bool(&rw->lock, old, old + 1));
-}
-
-static inline int arch_write_trylock_once(arch_rwlock_t *rw)
-{
-       int old = ACCESS_ONCE(rw->lock);
-       return likely(old == 0 &&
-                     __atomic_cmpxchg_bool(&rw->lock, 0, 0x80000000));
-}
-
-#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
-
-#define __RAW_OP_OR    "lao"
-#define __RAW_OP_AND   "lan"
-#define __RAW_OP_ADD   "laa"
-
-#define __RAW_LOCK(ptr, op_val, op_string)             \
-({                                                     \
-       int old_val;                                    \
-                                                       \
-       typecheck(int *, ptr);                          \
-       asm volatile(                                   \
-               op_string "     %0,%2,%1\n"             \
-               "bcr    14,0\n"                         \
-               : "=d" (old_val), "+Q" (*ptr)           \
-               : "d" (op_val)                          \
-               : "cc", "memory");                      \
-       old_val;                                        \
-})
-
-#define __RAW_UNLOCK(ptr, op_val, op_string)           \
-({                                                     \
-       int old_val;                                    \
-                                                       \
-       typecheck(int *, ptr);                          \
-       asm volatile(                                   \
-               op_string "     %0,%2,%1\n"             \
-               : "=d" (old_val), "+Q" (*ptr)           \
-               : "d" (op_val)                          \
-               : "cc", "memory");                      \
-       old_val;                                        \
-})
+#define arch_read_relax(rw) barrier()
+#define arch_write_relax(rw) barrier()
 
-extern void _raw_read_lock_wait(arch_rwlock_t *lp);
-extern void _raw_write_lock_wait(arch_rwlock_t *lp, int prev);
+void arch_read_lock_wait(arch_rwlock_t *lp);
+void arch_write_lock_wait(arch_rwlock_t *lp);
 
 static inline void arch_read_lock(arch_rwlock_t *rw)
 {
        int old;
 
-       old = __RAW_LOCK(&rw->lock, 1, __RAW_OP_ADD);
-       if (old 0)
-               _raw_read_lock_wait(rw);
+       old = __atomic_add(1, &rw->cnts);
+       if (old & 0xffff0000)
+               arch_read_lock_wait(rw);
 }
 
 static inline void arch_read_unlock(arch_rwlock_t *rw)
 {
-       __RAW_UNLOCK(&rw->lock, -1, __RAW_OP_ADD);
+       __atomic_add_const_barrier(-1, &rw->cnts);
 }
 
 static inline void arch_write_lock(arch_rwlock_t *rw)
 {
-       int old;
-
-       old = __RAW_LOCK(&rw->lock, 0x80000000, __RAW_OP_OR);
-       if (old != 0)
-               _raw_write_lock_wait(rw, old);
-       rw->owner = SPINLOCK_LOCKVAL;
+       if (!__atomic_cmpxchg_bool(&rw->cnts, 0, 0x30000))
+               arch_write_lock_wait(rw);
 }
 
 static inline void arch_write_unlock(arch_rwlock_t *rw)
 {
-       rw->owner = 0;
-       __RAW_UNLOCK(&rw->lock, 0x7fffffff, __RAW_OP_AND);
+       __atomic_add_barrier(-0x30000, &rw->cnts);
 }
 
-#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
-
-extern void _raw_read_lock_wait(arch_rwlock_t *lp);
-extern void _raw_write_lock_wait(arch_rwlock_t *lp);
-
-static inline void arch_read_lock(arch_rwlock_t *rw)
-{
-       if (!arch_read_trylock_once(rw))
-               _raw_read_lock_wait(rw);
-}
 
-static inline void arch_read_unlock(arch_rwlock_t *rw)
+static inline int arch_read_trylock(arch_rwlock_t *rw)
 {
        int old;
 
-       do {
-               old = ACCESS_ONCE(rw->lock);
-       } while (!__atomic_cmpxchg_bool(&rw->lock, old, old - 1));
-}
-
-static inline void arch_write_lock(arch_rwlock_t *rw)
-{
-       if (!arch_write_trylock_once(rw))
-               _raw_write_lock_wait(rw);
-       rw->owner = SPINLOCK_LOCKVAL;
-}
-
-static inline void arch_write_unlock(arch_rwlock_t *rw)
-{
-       typecheck(int, rw->lock);
-
-       rw->owner = 0;
-       asm volatile(
-               "st     %1,%0\n"
-               : "+Q" (rw->lock)
-               : "d" (0)
-               : "cc", "memory");
-}
-
-#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
-
-static inline int arch_read_trylock(arch_rwlock_t *rw)
-{
-       if (!arch_read_trylock_once(rw))
-               return _raw_read_trylock_retry(rw);
-       return 1;
+       old = READ_ONCE(rw->cnts);
+       return (!(old & 0xffff0000) &&
+               __atomic_cmpxchg_bool(&rw->cnts, old, old + 1));
 }
 
 static inline int arch_write_trylock(arch_rwlock_t *rw)
 {
-       if (!arch_write_trylock_once(rw) && !_raw_write_trylock_retry(rw))
-               return 0;
-       rw->owner = SPINLOCK_LOCKVAL;
-       return 1;
-}
-
-static inline void arch_read_relax(arch_rwlock_t *rw)
-{
-       arch_lock_relax(rw->owner);
-}
+       int old;
 
-static inline void arch_write_relax(arch_rwlock_t *rw)
-{
-       arch_lock_relax(rw->owner);
+       old = READ_ONCE(rw->cnts);
+       return !old && __atomic_cmpxchg_bool(&rw->cnts, 0, 0x30000);
 }
 
 #endif /* __ASM_SPINLOCK_H */
index 1861a0c5dd475730013eb762e8a8398d0acdbe2c..cfed272e4fd592d9d5844485e64921c30a61ccc2 100644 (file)
@@ -13,8 +13,8 @@ typedef struct {
 #define __ARCH_SPIN_LOCK_UNLOCKED { .lock = 0, }
 
 typedef struct {
-       int lock;
-       int owner;
+       int cnts;
+       arch_spinlock_t wait;
 } arch_rwlock_t;
 
 #define __ARCH_RW_LOCK_UNLOCKED                { 0 }
index 27ce494198f5a67db5220755ba9b7207131e4b44..50f26fc9acb27f72e390f9cc83e2bf6a792bac8b 100644 (file)
@@ -18,6 +18,9 @@
 #define __HAVE_ARCH_MEMMOVE    /* gcc builtin & arch function */
 #define __HAVE_ARCH_MEMSCAN    /* inline & arch function */
 #define __HAVE_ARCH_MEMSET     /* gcc builtin & arch function */
+#define __HAVE_ARCH_MEMSET16   /* arch function */
+#define __HAVE_ARCH_MEMSET32   /* arch function */
+#define __HAVE_ARCH_MEMSET64   /* arch function */
 #define __HAVE_ARCH_STRCAT     /* inline & arch function */
 #define __HAVE_ARCH_STRCMP     /* arch function */
 #define __HAVE_ARCH_STRCPY     /* inline & arch function */
 #define __HAVE_ARCH_STRSTR     /* arch function */
 
 /* Prototypes for non-inlined arch strings functions. */
-extern int memcmp(const void *, const void *, size_t);
-extern void *memcpy(void *, const void *, size_t);
-extern void *memset(void *, int, size_t);
-extern void *memmove(void *, const void *, size_t);
-extern int strcmp(const char *,const char *);
-extern size_t strlcat(char *, const char *, size_t);
-extern size_t strlcpy(char *, const char *, size_t);
-extern char *strncat(char *, const char *, size_t);
-extern char *strncpy(char *, const char *, size_t);
-extern char *strrchr(const char *, int);
-extern char *strstr(const char *, const char *);
+int memcmp(const void *s1, const void *s2, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+void *memset(void *s, int c, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+int strcmp(const char *s1, const char *s2);
+size_t strlcat(char *dest, const char *src, size_t n);
+size_t strlcpy(char *dest, const char *src, size_t size);
+char *strncat(char *dest, const char *src, size_t n);
+char *strncpy(char *dest, const char *src, size_t n);
+char *strrchr(const char *s, int c);
+char *strstr(const char *s1, const char *s2);
 
 #undef __HAVE_ARCH_STRCHR
 #undef __HAVE_ARCH_STRNCHR
@@ -50,7 +53,26 @@ extern char *strstr(const char *, const char *);
 #undef __HAVE_ARCH_STRSEP
 #undef __HAVE_ARCH_STRSPN
 
-#if !defined(IN_ARCH_STRING_C)
+void *__memset16(uint16_t *s, uint16_t v, size_t count);
+void *__memset32(uint32_t *s, uint32_t v, size_t count);
+void *__memset64(uint64_t *s, uint64_t v, size_t count);
+
+static inline void *memset16(uint16_t *s, uint16_t v, size_t count)
+{
+       return __memset16(s, v, count * sizeof(v));
+}
+
+static inline void *memset32(uint32_t *s, uint32_t v, size_t count)
+{
+       return __memset32(s, v, count * sizeof(v));
+}
+
+static inline void *memset64(uint64_t *s, uint64_t v, size_t count)
+{
+       return __memset64(s, v, count * sizeof(v));
+}
+
+#if !defined(IN_ARCH_STRING_C) && (!defined(CONFIG_FORTIFY_SOURCE) || defined(__NO_FORTIFY))
 
 static inline void *memchr(const void * s, int c, size_t n)
 {
index c21fe1d57c0096f3e5e17185bbddbd156d6622c8..ec7b476c1ac571b82e219a786ad2525a0ff9ceb2 100644 (file)
@@ -37,8 +37,8 @@ static inline void restore_access_regs(unsigned int *acrs)
                save_ri_cb(prev->thread.ri_cb);                         \
                save_gs_cb(prev->thread.gs_cb);                         \
        }                                                               \
+       update_cr_regs(next);                                           \
        if (next->mm) {                                                 \
-               update_cr_regs(next);                                   \
                set_cpu_flag(CIF_FPU);                                  \
                restore_access_regs(&next->thread.acrs[0]);             \
                restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);  \
index 2b498e58b91424b30d1f832aaf9eb1bda2fdf60a..a702cb9d4269240c462764878b50e02971f5d8ae 100644 (file)
@@ -156,7 +156,8 @@ static inline unsigned char topology_mnest_limit(void)
 struct topology_core {
        unsigned char nl;
        unsigned char reserved0[3];
-       unsigned char :6;
+       unsigned char :5;
+       unsigned char d:1;
        unsigned char pp:2;
        unsigned char reserved1;
        unsigned short origin;
@@ -198,4 +199,5 @@ struct service_level {
 int register_service_level(struct service_level *);
 int unregister_service_level(struct service_level *);
 
+int sthyi_fill(void *dst, u64 *rc);
 #endif /* __ASM_S390_SYSINFO_H */
index 55de4eb73604d924dc70bc8554dc578750620c4d..1807229b292f005a4a0658ac221c3cb0481a39bf 100644 (file)
@@ -17,6 +17,7 @@ struct cpu_topology_s390 {
        unsigned short book_id;
        unsigned short drawer_id;
        unsigned short node_id;
+       unsigned short dedicated : 1;
        cpumask_t thread_mask;
        cpumask_t core_mask;
        cpumask_t book_mask;
@@ -35,6 +36,7 @@ extern cpumask_t cpus_with_topology;
 #define topology_book_cpumask(cpu)       (&cpu_topology[cpu].book_mask)
 #define topology_drawer_id(cpu)                  (cpu_topology[cpu].drawer_id)
 #define topology_drawer_cpumask(cpu)     (&cpu_topology[cpu].drawer_mask)
+#define topology_cpu_dedicated(cpu)      (cpu_topology[cpu].dedicated)
 
 #define mc_capable() 1
 
index bb2ce72300b0f05a8ef3a8dd54a21f24281abe9b..ae6261ef97d558bb8d52e38286503ed13fca8373 100644 (file)
@@ -47,6 +47,7 @@ struct vdso_per_cpu_data {
 
 extern struct vdso_data *vdso_data;
 
+void vdso_alloc_boot_cpu(struct lowcore *lowcore);
 int vdso_alloc_per_cpu(struct lowcore *lowcore);
 void vdso_free_per_cpu(struct lowcore *lowcore);
 
diff --git a/arch/s390/include/uapi/asm/kvm_virtio.h b/arch/s390/include/uapi/asm/kvm_virtio.h
deleted file mode 100644 (file)
index 7328367..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * definition for virtio for kvm on s390
- *
- * Copyright IBM Corp. 2008
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (version 2 only)
- * as published by the Free Software Foundation.
- *
- *    Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
- */
-
-#ifndef __KVM_S390_VIRTIO_H
-#define __KVM_S390_VIRTIO_H
-
-#include <linux/types.h>
-
-struct kvm_device_desc {
-       /* The device type: console, network, disk etc.  Type 0 terminates. */
-       __u8 type;
-       /* The number of virtqueues (first in config array) */
-       __u8 num_vq;
-       /*
-        * The number of bytes of feature bits.  Multiply by 2: one for host
-        * features and one for guest acknowledgements.
-        */
-       __u8 feature_len;
-       /* The number of bytes of the config array after virtqueues. */
-       __u8 config_len;
-       /* A status byte, written by the Guest. */
-       __u8 status;
-       __u8 config[0];
-};
-
-/*
- * This is how we expect the device configuration field for a virtqueue
- * to be laid out in config space.
- */
-struct kvm_vqconfig {
-       /* The token returned with an interrupt. Set by the guest */
-       __u64 token;
-       /* The address of the virtio ring */
-       __u64 address;
-       /* The number of entries in the virtio_ring */
-       __u16 num;
-
-};
-
-#define KVM_S390_VIRTIO_NOTIFY         0
-#define KVM_S390_VIRTIO_RESET          1
-#define KVM_S390_VIRTIO_SET_STATUS     2
-
-/* The alignment to use between consumer and producer parts of vring.
- * This is pagesize for historical reasons. */
-#define KVM_S390_VIRTIO_RING_ALIGN     4096
-
-
-/* These values are supposed to be in ext_params on an interrupt */
-#define VIRTIO_PARAM_MASK              0xff
-#define VIRTIO_PARAM_VRING_INTERRUPT   0x0
-#define VIRTIO_PARAM_CONFIG_CHANGED    0x1
-#define VIRTIO_PARAM_DEV_ADD           0x2
-
-#endif
diff --git a/arch/s390/include/uapi/asm/sthyi.h b/arch/s390/include/uapi/asm/sthyi.h
new file mode 100644 (file)
index 0000000..ec113db
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _UAPI_ASM_STHYI_H
+#define _UAPI_ASM_STHYI_H
+
+#define STHYI_FC_CP_IFL_CAP    0
+
+#endif /* _UAPI_ASM_STHYI_H */
index b52bce8ee941a66746f5fee24655ded7ad01650c..725120939051f5c6f707b1972f2794fd6dc86a2a 100644 (file)
 #define __NR_pwritev2          377
 #define __NR_s390_guarded_storage      378
 #define __NR_statx             379
-#define NR_syscalls 380
+#define __NR_s390_sthyi                380
+#define NR_syscalls 381
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index 4ce2d05929a7a21853e15d10d317fa0a31591d7d..83bc82001c06ff1c7bd3dee875a6a6901adce115 100644 (file)
@@ -34,6 +34,8 @@ AFLAGS_REMOVE_head.o  += $(CC_FLAGS_MARCH)
 AFLAGS_head.o          += -march=z900
 endif
 
+CFLAGS_als.o           += -D__NO_FORTIFY
+
 #
 # Passing null pointers is ok for smp code, since we access the lowcore here.
 #
@@ -56,7 +58,7 @@ obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
 obj-y  += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
 obj-y  += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o
 obj-y  += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
-obj-y  += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o
+obj-y  += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
 obj-y  += entry.o reipl.o relocate_kernel.o kdebugfs.o
 
 extra-y                                += head.o head64.o vmlinux.lds
@@ -75,6 +77,7 @@ obj-$(CONFIG_KPROBES)         += kprobes.o
 obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o ftrace.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 obj-$(CONFIG_UPROBES)          += uprobes.o
+obj-$(CONFIG_ALTERNATIVES)     += alternative.o
 
 obj-$(CONFIG_PERF_EVENTS)      += perf_event.o perf_cpum_cf.o perf_cpum_sf.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_cpum_cf_events.o
diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c
new file mode 100644 (file)
index 0000000..315986a
--- /dev/null
@@ -0,0 +1,110 @@
+#include <linux/module.h>
+#include <asm/alternative.h>
+#include <asm/facility.h>
+
+#define MAX_PATCH_LEN (255 - 1)
+
+static int __initdata_or_module alt_instr_disabled;
+
+static int __init disable_alternative_instructions(char *str)
+{
+       alt_instr_disabled = 1;
+       return 0;
+}
+
+early_param("noaltinstr", disable_alternative_instructions);
+
+struct brcl_insn {
+       u16 opc;
+       s32 disp;
+} __packed;
+
+static u16 __initdata_or_module nop16 = 0x0700;
+static u32 __initdata_or_module nop32 = 0x47000000;
+static struct brcl_insn __initdata_or_module nop48 = {
+       0xc004, 0
+};
+
+static const void *nops[] __initdata_or_module = {
+       &nop16,
+       &nop32,
+       &nop48
+};
+
+static void __init_or_module add_jump_padding(void *insns, unsigned int len)
+{
+       struct brcl_insn brcl = {
+               0xc0f4,
+               len / 2
+       };
+
+       memcpy(insns, &brcl, sizeof(brcl));
+       insns += sizeof(brcl);
+       len -= sizeof(brcl);
+
+       while (len > 0) {
+               memcpy(insns, &nop16, 2);
+               insns += 2;
+               len -= 2;
+       }
+}
+
+static void __init_or_module add_padding(void *insns, unsigned int len)
+{
+       if (len > 6)
+               add_jump_padding(insns, len);
+       else if (len >= 2)
+               memcpy(insns, nops[len / 2 - 1], len);
+}
+
+static void __init_or_module __apply_alternatives(struct alt_instr *start,
+                                                 struct alt_instr *end)
+{
+       struct alt_instr *a;
+       u8 *instr, *replacement;
+       u8 insnbuf[MAX_PATCH_LEN];
+
+       /*
+        * The scan order should be from start to end. A later scanned
+        * alternative code can overwrite previously scanned alternative code.
+        */
+       for (a = start; a < end; a++) {
+               int insnbuf_sz = 0;
+
+               instr = (u8 *)&a->instr_offset + a->instr_offset;
+               replacement = (u8 *)&a->repl_offset + a->repl_offset;
+
+               if (!test_facility(a->facility))
+                       continue;
+
+               if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) {
+                       WARN_ONCE(1, "cpu alternatives instructions length is "
+                                    "odd, skipping patching\n");
+                       continue;
+               }
+
+               memcpy(insnbuf, replacement, a->replacementlen);
+               insnbuf_sz = a->replacementlen;
+
+               if (a->instrlen > a->replacementlen) {
+                       add_padding(insnbuf + a->replacementlen,
+                                   a->instrlen - a->replacementlen);
+                       insnbuf_sz += a->instrlen - a->replacementlen;
+               }
+
+               s390_kernel_write(instr, insnbuf, insnbuf_sz);
+       }
+}
+
+void __init_or_module apply_alternatives(struct alt_instr *start,
+                                        struct alt_instr *end)
+{
+       if (!alt_instr_disabled)
+               __apply_alternatives(start, end);
+}
+
+extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
+void __init apply_alternative_instructions(void)
+{
+       apply_alternatives(__alt_instructions, __alt_instructions_end);
+}
index 0e6d2b032484a8bfc02ac1c8683c3dd1c8c34b91..33ec80df7ed443ffc161d99ee3fc591381cec0b8 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/vdso.h>
 #include <asm/pgtable.h>
 #include <asm/gmap.h>
+#include <asm/nmi.h>
 
 /*
  * Make sure that the compiler is new enough. We want a compiler that
@@ -159,6 +160,7 @@ int main(void)
        OFFSET(__LC_LAST_UPDATE_CLOCK, lowcore, last_update_clock);
        OFFSET(__LC_INT_CLOCK, lowcore, int_clock);
        OFFSET(__LC_MCCK_CLOCK, lowcore, mcck_clock);
+       OFFSET(__LC_CLOCK_COMPARATOR, lowcore, clock_comparator);
        OFFSET(__LC_BOOT_CLOCK, lowcore, boot_clock);
        OFFSET(__LC_CURRENT, lowcore, current_task);
        OFFSET(__LC_KERNEL_STACK, lowcore, kernel_stack);
@@ -194,6 +196,9 @@ int main(void)
        OFFSET(__LC_CREGS_SAVE_AREA, lowcore, cregs_save_area);
        OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb);
        BLANK();
+       /* extended machine check save area */
+       OFFSET(__MCESA_GS_SAVE_AREA, mcesa, guarded_storage_save_area);
+       BLANK();
        /* gmap/sie offsets */
        OFFSET(__GMAP_ASCE, gmap, asce);
        OFFSET(__SIE_PROG0C, kvm_s390_sie_block, prog0c);
index d049185839715fb8aeb783d495632ec6581215f4..11e9d8b5c1b0633ba4eb41eb26c73fc9e78a3a78 100644 (file)
@@ -181,3 +181,4 @@ COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags);
 COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags);
 COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb);
 COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
+COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags);
index 05a9cf4ae9c2409c86fcbde39c37b26e0ef0693e..58b9e127b61517c3f1cbe41a76757f7db156df76 100644 (file)
@@ -5,7 +5,7 @@
  *    Copyright IBM Corp. 1999, 2012
  *
  *    Author(s): Michael Holzheu (holzheu@de.ibm.com),
- *               Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ *              Holger Smolinski (Holger.Smolinski@de.ibm.com)
  *
  *    Bugreports to: <Linux390@de.ibm.com>
  */
 
 typedef struct file_private_info {
        loff_t offset;                  /* offset of last read in file */
-       int    act_area;                /* number of last formated area */
-       int    act_page;                /* act page in given area */
-       int    act_entry;               /* last formated entry (offset */
-                                        /* relative to beginning of last */
-                                        /* formated page) */
-       size_t act_entry_offset;        /* up to this offset we copied */
+       int    act_area;                /* number of last formated area */
+       int    act_page;                /* act page in given area */
+       int    act_entry;               /* last formated entry (offset */
+                                       /* relative to beginning of last */
+                                       /* formated page) */
+       size_t act_entry_offset;        /* up to this offset we copied */
                                        /* in last read the last formated */
                                        /* entry to userland */
        char   temp_buf[2048];          /* buffer for output */
-       debug_info_t *debug_info_org;   /* original debug information */
+       debug_info_t *debug_info_org;   /* original debug information */
        debug_info_t *debug_info_snap;  /* snapshot of debug information */
        struct debug_view *view;        /* used view of debug info */
 } file_private_info_t;
 
-typedef struct
-{
+typedef struct {
        char *string;
-       /* 
-        * This assumes that all args are converted into longs 
-        * on L/390 this is the case for all types of parameter 
-        * except of floats, and long long (32 bit) 
+       /*
+        * This assumes that all args are converted into longs
+        * on L/390 this is the case for all types of parameter
+        * except of floats, and long long (32 bit)
         *
         */
        long args[0];
 } debug_sprintf_entry_t;
 
-
 /* internal function prototyes */
 
 static int debug_init(void);
 static ssize_t debug_output(struct file *file, char __user *user_buf,
-                       size_t user_len, loff_t * offset);
+                           size_t user_len, loff_t *offset);
 static ssize_t debug_input(struct file *file, const char __user *user_buf,
-                       size_t user_len, loff_t * offset);
+                          size_t user_len, loff_t *offset);
 static int debug_open(struct inode *inode, struct file *file);
 static int debug_close(struct inode *inode, struct file *file);
 static debug_info_t *debug_info_create(const char *name, int pages_per_area,
-                       int nr_areas, int buf_size, umode_t mode);
+                                      int nr_areas, int buf_size, umode_t mode);
 static void debug_info_get(debug_info_t *);
 static void debug_info_put(debug_info_t *);
-static int debug_prolog_level_fn(debug_info_t * id,
-                       struct debug_view *view, char *out_buf);
-static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
-                       struct file *file, const char __user *user_buf,
-                       size_t user_buf_size, loff_t * offset);
-static int debug_prolog_pages_fn(debug_info_t * id,
-                       struct debug_view *view, char *out_buf);
-static int debug_input_pages_fn(debug_info_t * id, struct debug_view *view,
-                       struct file *file, const char __user *user_buf,
-                       size_t user_buf_size, loff_t * offset);
-static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
-                       struct file *file, const char __user *user_buf,
-                       size_t user_buf_size, loff_t * offset);
-static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
-                       char *out_buf, const char *in_buf);
-static int debug_raw_format_fn(debug_info_t * id,
-                       struct debug_view *view, char *out_buf,
-                       const char *in_buf);
-static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
-                       int area, debug_entry_t * entry, char *out_buf);
-
-static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
-                       char *out_buf, debug_sprintf_entry_t *curr_event);
+static int debug_prolog_level_fn(debug_info_t *id,
+                                struct debug_view *view, char *out_buf);
+static int debug_input_level_fn(debug_info_t *id, struct debug_view *view,
+                               struct file *file, const char __user *user_buf,
+                               size_t user_buf_size, loff_t *offset);
+static int debug_prolog_pages_fn(debug_info_t *id,
+                                struct debug_view *view, char *out_buf);
+static int debug_input_pages_fn(debug_info_t *id, struct debug_view *view,
+                               struct file *file, const char __user *user_buf,
+                               size_t user_buf_size, loff_t *offset);
+static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view,
+                               struct file *file, const char __user *user_buf,
+                               size_t user_buf_size, loff_t *offset);
+static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
+                                    char *out_buf, const char *in_buf);
+static int debug_raw_format_fn(debug_info_t *id,
+                              struct debug_view *view, char *out_buf,
+                              const char *in_buf);
+static int debug_raw_header_fn(debug_info_t *id, struct debug_view *view,
+                              int area, debug_entry_t *entry, char *out_buf);
+
+static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
+                                  char *out_buf, debug_sprintf_entry_t *curr_event);
 
 /* globals */
 
@@ -142,19 +140,19 @@ static struct debug_view debug_pages_view = {
 };
 
 static struct debug_view debug_flush_view = {
-        "flush",
-        NULL,
-        NULL,
-        NULL,
-        &debug_input_flush_fn,
-        NULL
+       "flush",
+       NULL,
+       NULL,
+       NULL,
+       &debug_input_flush_fn,
+       NULL
 };
 
 struct debug_view debug_sprintf_view = {
        "sprintf",
        NULL,
        &debug_dflt_header_fn,
-       (debug_format_proc_t*)&debug_sprintf_format_fn,
+       (debug_format_proc_t *)&debug_sprintf_format_fn,
        NULL,
        NULL
 };
@@ -165,18 +163,18 @@ static unsigned int __used debug_feature_version = __DEBUG_FEATURE_VERSION;
 
 /* static globals */
 
-static debug_info_t *debug_area_first = NULL;
-static debug_info_t *debug_area_last = NULL;
+static debug_info_t *debug_area_first;
+static debug_info_t *debug_area_last;
 static DEFINE_MUTEX(debug_mutex);
 
 static int initialized;
 static int debug_critical;
 
 static const struct file_operations debug_file_ops = {
-       .owner   = THIS_MODULE,
-       .read    = debug_output,
-       .write   = debug_input,
-       .open    = debug_open,
+       .owner   = THIS_MODULE,
+       .read    = debug_output,
+       .write   = debug_input,
+       .open    = debug_open,
        .release = debug_close,
        .llseek  = no_llseek,
 };
@@ -191,29 +189,23 @@ static struct dentry *debug_debugfs_root_entry;
  *   areas[areanumber][pagenumber][pageoffset]
  */
 
-static debug_entry_t***
-debug_areas_alloc(int pages_per_area, int nr_areas)
+static debug_entry_t ***debug_areas_alloc(int pages_per_area, int nr_areas)
 {
-       debug_entry_t*** areas;
-       int i,j;
+       debug_entry_t ***areas;
+       int i, j;
 
-       areas = kmalloc(nr_areas *
-                                       sizeof(debug_entry_t**),
-                                       GFP_KERNEL);
+       areas = kmalloc(nr_areas * sizeof(debug_entry_t **), GFP_KERNEL);
        if (!areas)
                goto fail_malloc_areas;
        for (i = 0; i < nr_areas; i++) {
-               areas[i] = kmalloc(pages_per_area *
-                               sizeof(debug_entry_t*),GFP_KERNEL);
-               if (!areas[i]) {
+               areas[i] = kmalloc(pages_per_area * sizeof(debug_entry_t *), GFP_KERNEL);
+               if (!areas[i])
                        goto fail_malloc_areas2;
-               }
-               for(j = 0; j < pages_per_area; j++) {
+               for (j = 0; j < pages_per_area; j++) {
                        areas[i][j] = kzalloc(PAGE_SIZE, GFP_KERNEL);
-                       if(!areas[i][j]) {
-                               for(j--; j >=0 ; j--) {
+                       if (!areas[i][j]) {
+                               for (j--; j >= 0 ; j--)
                                        kfree(areas[i][j]);
-                               }
                                kfree(areas[i]);
                                goto fail_malloc_areas2;
                        }
@@ -222,62 +214,55 @@ debug_areas_alloc(int pages_per_area, int nr_areas)
        return areas;
 
 fail_malloc_areas2:
-       for(i--; i >= 0; i--){
-               for(j=0; j < pages_per_area;j++){
+       for (i--; i >= 0; i--) {
+               for (j = 0; j < pages_per_area; j++)
                        kfree(areas[i][j]);
-               }
                kfree(areas[i]);
        }
        kfree(areas);
 fail_malloc_areas:
        return NULL;
-
 }
 
-
 /*
  * debug_info_alloc
  * - alloc new debug-info
  */
-
-static debug_info_t*
-debug_info_alloc(const char *name, int pages_per_area, int nr_areas,
-                int buf_size, int level, int mode)
+static debug_info_t *debug_info_alloc(const char *name, int pages_per_area,
+                                     int nr_areas, int buf_size, int level,
+                                     int mode)
 {
-       debug_info_trc;
+       debug_info_t *rc;
 
        /* alloc everything */
-
        rc = kmalloc(sizeof(debug_info_t), GFP_KERNEL);
-       if(!rc)
+       if (!rc)
                goto fail_malloc_rc;
        rc->active_entries = kcalloc(nr_areas, sizeof(int), GFP_KERNEL);
-       if(!rc->active_entries)
+       if (!rc->active_entries)
                goto fail_malloc_active_entries;
        rc->active_pages = kcalloc(nr_areas, sizeof(int), GFP_KERNEL);
-       if(!rc->active_pages)
+       if (!rc->active_pages)
                goto fail_malloc_active_pages;
-       if((mode == ALL_AREAS) && (pages_per_area != 0)){
+       if ((mode == ALL_AREAS) && (pages_per_area != 0)) {
                rc->areas = debug_areas_alloc(pages_per_area, nr_areas);
-               if(!rc->areas)
+               if (!rc->areas)
                        goto fail_malloc_areas;
        } else {
                rc->areas = NULL;
        }
 
        /* initialize members */
-
        spin_lock_init(&rc->lock);
        rc->pages_per_area = pages_per_area;
-       rc->nr_areas       = nr_areas;
+       rc->nr_areas       = nr_areas;
        rc->active_area    = 0;
-       rc->level          = level;
-       rc->buf_size       = buf_size;
-       rc->entry_size     = sizeof(debug_entry_t) + buf_size;
+       rc->level          = level;
+       rc->buf_size       = buf_size;
+       rc->entry_size     = sizeof(debug_entry_t) + buf_size;
        strlcpy(rc->name, name, sizeof(rc->name));
        memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
-       memset(rc->debugfs_entries, 0 ,DEBUG_MAX_VIEWS *
-               sizeof(struct dentry*));
+       memset(rc->debugfs_entries, 0, DEBUG_MAX_VIEWS * sizeof(struct dentry *));
        refcount_set(&(rc->ref_count), 0);
 
        return rc;
@@ -296,18 +281,15 @@ fail_malloc_rc:
  * debug_areas_free
  * - free all debug areas
  */
-
-static void
-debug_areas_free(debug_info_t* db_info)
+static void debug_areas_free(debug_info_t *db_info)
 {
-       int i,j;
+       int i, j;
 
-       if(!db_info->areas)
+       if (!db_info->areas)
                return;
        for (i = 0; i < db_info->nr_areas; i++) {
-               for(j = 0; j < db_info->pages_per_area; j++) {
+               for (j = 0; j < db_info->pages_per_area; j++)
                        kfree(db_info->areas[i][j]);
-               }
                kfree(db_info->areas[i]);
        }
        kfree(db_info->areas);
@@ -318,9 +300,8 @@ debug_areas_free(debug_info_t* db_info)
  * debug_info_free
  * - free memory debug-info
  */
-
-static void
-debug_info_free(debug_info_t* db_info){
+static void debug_info_free(debug_info_t *db_info)
+{
        debug_areas_free(db_info);
        kfree(db_info->active_entries);
        kfree(db_info->active_pages);
@@ -332,35 +313,34 @@ debug_info_free(debug_info_t* db_info){
  * - create new debug-info
  */
 
-static debug_info_t*
-debug_info_create(const char *name, int pages_per_area, int nr_areas,
-                 int buf_size, umode_t mode)
+static debug_info_t *debug_info_create(const char *name, int pages_per_area,
+                                      int nr_areas, int buf_size, umode_t mode)
 {
-       debug_info_trc;
+       debug_info_t *rc;
 
-        rc = debug_info_alloc(name, pages_per_area, nr_areas, buf_size,
-                               DEBUG_DEFAULT_LEVEL, ALL_AREAS);
-        if(!rc) 
+       rc = debug_info_alloc(name, pages_per_area, nr_areas, buf_size,
+                             DEBUG_DEFAULT_LEVEL, ALL_AREAS);
+       if (!rc)
                goto out;
 
        rc->mode = mode & ~S_IFMT;
 
        /* create root directory */
-        rc->debugfs_root_entry = debugfs_create_dir(rc->name,
-                                       debug_debugfs_root_entry);
+       rc->debugfs_root_entry = debugfs_create_dir(rc->name,
+                                                   debug_debugfs_root_entry);
 
        /* append new element to linked list */
-        if (!debug_area_first) {
-                /* first element in list */
-                debug_area_first = rc;
-                rc->prev = NULL;
-        } else {
-                /* append element to end of list */
-                debug_area_last->next = rc;
-                rc->prev = debug_area_last;
-        }
-        debug_area_last = rc;
-        rc->next = NULL;
+       if (!debug_area_first) {
+               /* first element in list */
+               debug_area_first = rc;
+               rc->prev = NULL;
+       } else {
+               /* append element to end of list */
+               debug_area_last->next = rc;
+               rc->prev = debug_area_last;
+       }
+       debug_area_last = rc;
+       rc->next = NULL;
 
        refcount_set(&rc->ref_count, 1);
 out:
@@ -371,24 +351,22 @@ out:
  * debug_info_copy
  * - copy debug-info
  */
-
-static debug_info_t*
-debug_info_copy(debug_info_t* in, int mode)
+static debug_info_t *debug_info_copy(debug_info_t *in, int mode)
 {
-        int i,j;
-        debug_info_t* rc;
-        unsigned long flags;
+       unsigned long flags;
+       debug_info_t *rc;
+       int i, j;
 
        /* get a consistent copy of the debug areas */
        do {
                rc = debug_info_alloc(in->name, in->pages_per_area,
                        in->nr_areas, in->buf_size, in->level, mode);
                spin_lock_irqsave(&in->lock, flags);
-               if(!rc)
+               if (!rc)
                        goto out;
                /* has something changed in the meantime ? */
-               if((rc->pages_per_area == in->pages_per_area) &&
-                  (rc->nr_areas == in->nr_areas)) {
+               if ((rc->pages_per_area == in->pages_per_area) &&
+                   (rc->nr_areas == in->nr_areas)) {
                        break;
                }
                spin_unlock_irqrestore(&in->lock, flags);
@@ -396,25 +374,22 @@ debug_info_copy(debug_info_t* in, int mode)
        } while (1);
 
        if (mode == NO_AREAS)
-                goto out;
+               goto out;
 
-        for(i = 0; i < in->nr_areas; i++){
-               for(j = 0; j < in->pages_per_area; j++) {
-                       memcpy(rc->areas[i][j], in->areas[i][j],PAGE_SIZE);
-               }
-        }
+       for (i = 0; i < in->nr_areas; i++) {
+               for (j = 0; j < in->pages_per_area; j++)
+                       memcpy(rc->areas[i][j], in->areas[i][j], PAGE_SIZE);
+       }
 out:
-        spin_unlock_irqrestore(&in->lock, flags);
-        return rc;
+       spin_unlock_irqrestore(&in->lock, flags);
+       return rc;
 }
 
 /*
  * debug_info_get
  * - increments reference count for debug-info
  */
-
-static void
-debug_info_get(debug_info_t * db_info)
+static void debug_info_get(debug_info_t *db_info)
 {
        if (db_info)
                refcount_inc(&db_info->ref_count);
@@ -424,9 +399,7 @@ debug_info_get(debug_info_t * db_info)
  * debug_info_put:
  * - decreases reference count for debug-info and frees it if necessary
  */
-
-static void
-debug_info_put(debug_info_t *db_info)
+static void debug_info_put(debug_info_t *db_info)
 {
        int i;
 
@@ -439,12 +412,14 @@ debug_info_put(debug_info_t *db_info)
                        debugfs_remove(db_info->debugfs_entries[i]);
                }
                debugfs_remove(db_info->debugfs_root_entry);
-               if(db_info == debug_area_first)
+               if (db_info == debug_area_first)
                        debug_area_first = db_info->next;
-               if(db_info == debug_area_last)
+               if (db_info == debug_area_last)
                        debug_area_last = db_info->prev;
-               if(db_info->prev) db_info->prev->next = db_info->next;
-               if(db_info->next) db_info->next->prev = db_info->prev;
+               if (db_info->prev)
+                       db_info->prev->next = db_info->next;
+               if (db_info->next)
+                       db_info->next->prev = db_info->prev;
                debug_info_free(db_info);
        }
 }
@@ -453,71 +428,68 @@ debug_info_put(debug_info_t *db_info)
  * debug_format_entry:
  * - format one debug entry and return size of formated data
  */
-
-static int
-debug_format_entry(file_private_info_t *p_info)
+static int debug_format_entry(file_private_info_t *p_info)
 {
-       debug_info_t *id_snap   = p_info->debug_info_snap;
+       debug_info_t *id_snap   = p_info->debug_info_snap;
        struct debug_view *view = p_info->view;
        debug_entry_t *act_entry;
        size_t len = 0;
-       if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
+
+       if (p_info->act_entry == DEBUG_PROLOG_ENTRY) {
                /* print prolog */
-               if (view->prolog_proc)
-                       len += view->prolog_proc(id_snap,view,p_info->temp_buf);
+               if (view->prolog_proc)
+                       len += view->prolog_proc(id_snap, view, p_info->temp_buf);
                goto out;
        }
        if (!id_snap->areas) /* this is true, if we have a prolog only view */
                goto out;    /* or if 'pages_per_area' is 0 */
-       act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area]
-                               [p_info->act_page] + p_info->act_entry);
-                        
+       act_entry = (debug_entry_t *) ((char *)id_snap->areas[p_info->act_area]
+                                      [p_info->act_page] + p_info->act_entry);
+
        if (act_entry->id.stck == 0LL)
-                       goto out;  /* empty entry */
+               goto out; /* empty entry */
        if (view->header_proc)
                len += view->header_proc(id_snap, view, p_info->act_area,
-                                       act_entry, p_info->temp_buf + len);
+                                        act_entry, p_info->temp_buf + len);
        if (view->format_proc)
                len += view->format_proc(id_snap, view, p_info->temp_buf + len,
-                                               DEBUG_DATA(act_entry));
+                                        DEBUG_DATA(act_entry));
 out:
-        return len;
+       return len;
 }
 
 /*
  * debug_next_entry:
  * - goto next entry in p_info
  */
-
-static inline int
-debug_next_entry(file_private_info_t *p_info)
+static inline int debug_next_entry(file_private_info_t *p_info)
 {
        debug_info_t *id;
 
        id = p_info->debug_info_snap;
-       if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
+       if (p_info->act_entry == DEBUG_PROLOG_ENTRY) {
                p_info->act_entry = 0;
                p_info->act_page  = 0;
                goto out;
        }
-       if(!id->areas)
+       if (!id->areas)
                return 1;
        p_info->act_entry += id->entry_size;
        /* switch to next page, if we reached the end of the page  */
-       if (p_info->act_entry > (PAGE_SIZE - id->entry_size)){
+       if (p_info->act_entry > (PAGE_SIZE - id->entry_size)) {
                /* next page */
                p_info->act_entry = 0;
                p_info->act_page += 1;
-               if((p_info->act_page % id->pages_per_area) == 0) {
+               if ((p_info->act_page % id->pages_per_area) == 0) {
                        /* next area */
-                       p_info->act_area++;
-                       p_info->act_page=0;
+                       p_info->act_area++;
+                       p_info->act_page = 0;
                }
-               if(p_info->act_area >= id->nr_areas)
+               if (p_info->act_area >= id->nr_areas)
                        return 1;
        }
 out:
-       return 0;       
+       return 0;
 }
 
 /*
@@ -525,26 +497,24 @@ out:
  * - called for user read()
  * - copies formated debug entries to the user buffer
  */
-
-static ssize_t
-debug_output(struct file *file,                /* file descriptor */
-           char __user *user_buf,      /* user buffer */
-           size_t  len,                /* length of buffer */
-           loff_t *offset)             /* offset in the file */
+static ssize_t debug_output(struct file *file,         /* file descriptor */
+                           char __user *user_buf,      /* user buffer */
+                           size_t len,                 /* length of buffer */
+                           loff_t *offset)             /* offset in the file */
 {
        size_t count = 0;
        size_t entry_offset;
        file_private_info_t *p_info;
 
-       p_info = ((file_private_info_t *) file->private_data);
-       if (*offset != p_info->offset) 
+       p_info = (file_private_info_t *) file->private_data;
+       if (*offset != p_info->offset)
                return -EPIPE;
-       if(p_info->act_area >= p_info->debug_info_snap->nr_areas)
+       if (p_info->act_area >= p_info->debug_info_snap->nr_areas)
                return 0;
        entry_offset = p_info->act_entry_offset;
-       while(count < len){
-               int formatted_line_size;
+       while (count < len) {
                int formatted_line_residue;
+               int formatted_line_size;
                int user_buf_residue;
                size_t copy_size;
 
@@ -552,21 +522,21 @@ debug_output(struct file *file,           /* file descriptor */
                formatted_line_residue = formatted_line_size - entry_offset;
                user_buf_residue = len-count;
                copy_size = min(user_buf_residue, formatted_line_residue);
-               if(copy_size){
+               if (copy_size) {
                        if (copy_to_user(user_buf + count, p_info->temp_buf
-                                       + entry_offset, copy_size))
+                                        + entry_offset, copy_size))
                                return -EFAULT;
                        count += copy_size;
                        entry_offset += copy_size;
                }
-               if(copy_size == formatted_line_residue){
+               if (copy_size == formatted_line_residue) {
                        entry_offset = 0;
-                       if(debug_next_entry(p_info))
+                       if (debug_next_entry(p_info))
                                goto out;
                }
        }
 out:
-       p_info->offset           = *offset + count;
+       p_info->offset           = *offset + count;
        p_info->act_entry_offset = entry_offset;
        *offset = p_info->offset;
        return count;
@@ -577,24 +547,23 @@ out:
  * - called for user write()
  * - calls input function of view
  */
-
-static ssize_t
-debug_input(struct file *file, const char __user *user_buf, size_t length,
-               loff_t *offset)
+static ssize_t debug_input(struct file *file, const char __user *user_buf,
+                          size_t length, loff_t *offset)
 {
-       int rc = 0;
        file_private_info_t *p_info;
+       int rc = 0;
 
        mutex_lock(&debug_mutex);
        p_info = ((file_private_info_t *) file->private_data);
-       if (p_info->view->input_proc)
+       if (p_info->view->input_proc) {
                rc = p_info->view->input_proc(p_info->debug_info_org,
                                              p_info->view, file, user_buf,
                                              length, offset);
-       else
+       } else {
                rc = -EPERM;
+       }
        mutex_unlock(&debug_mutex);
-       return rc;              /* number of input characters */
+       return rc; /* number of input characters */
 }
 
 /*
@@ -603,13 +572,11 @@ debug_input(struct file *file, const char __user *user_buf, size_t length,
  * - copies formated output to private_data area of the file
  *   handle
  */
-
-static int
-debug_open(struct inode *inode, struct file *file)
+static int debug_open(struct inode *inode, struct file *file)
 {
-       int i, rc = 0;
-       file_private_info_t *p_info;
        debug_info_t *debug_info, *debug_info_snapshot;
+       file_private_info_t *p_info;
+       int i, rc = 0;
 
        mutex_lock(&debug_mutex);
        debug_info = file_inode(file)->i_private;
@@ -617,10 +584,8 @@ debug_open(struct inode *inode, struct file *file)
        for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
                if (!debug_info->views[i])
                        continue;
-               else if (debug_info->debugfs_entries[i] ==
-                        file->f_path.dentry) {
-                       goto found;     /* found view ! */
-               }
+               else if (debug_info->debugfs_entries[i] == file->f_path.dentry)
+                       goto found; /* found view ! */
        }
        /* no entry found */
        rc = -EINVAL;
@@ -628,31 +593,28 @@ debug_open(struct inode *inode, struct file *file)
 
 found:
 
-       /* Make snapshot of current debug areas to get it consistent.     */
+       /* Make snapshot of current debug areas to get it consistent.     */
        /* To copy all the areas is only needed, if we have a view which  */
        /* formats the debug areas. */
 
-       if(!debug_info->views[i]->format_proc &&
-               !debug_info->views[i]->header_proc){
+       if (!debug_info->views[i]->format_proc && !debug_info->views[i]->header_proc)
                debug_info_snapshot = debug_info_copy(debug_info, NO_AREAS);
-       } else {
+       else
                debug_info_snapshot = debug_info_copy(debug_info, ALL_AREAS);
-       }
 
-       if(!debug_info_snapshot){
+       if (!debug_info_snapshot) {
                rc = -ENOMEM;
                goto out;
        }
-       p_info = kmalloc(sizeof(file_private_info_t),
-                                               GFP_KERNEL);
-       if(!p_info){
+       p_info = kmalloc(sizeof(file_private_info_t), GFP_KERNEL);
+       if (!p_info) {
                debug_info_free(debug_info_snapshot);
                rc = -ENOMEM;
                goto out;
        }
        p_info->offset = 0;
        p_info->debug_info_snap = debug_info_snapshot;
-       p_info->debug_info_org  = debug_info;
+       p_info->debug_info_org  = debug_info;
        p_info->view = debug_info->views[i];
        p_info->act_area = 0;
        p_info->act_page = 0;
@@ -671,17 +633,16 @@ out:
  * - called for user close()
  * - deletes  private_data area of the file handle
  */
-
-static int
-debug_close(struct inode *inode, struct file *file)
+static int debug_close(struct inode *inode, struct file *file)
 {
        file_private_info_t *p_info;
+
        p_info = (file_private_info_t *) file->private_data;
-       if(p_info->debug_info_snap)
+       if (p_info->debug_info_snap)
                debug_info_free(p_info->debug_info_snap);
        debug_info_put(p_info->debug_info_org);
        kfree(file->private_data);
-       return 0;               /* success */
+       return 0; /* success */
 }
 
 /*
@@ -690,7 +651,6 @@ debug_close(struct inode *inode, struct file *file)
  *   The mode parameter allows to specify access rights for the s390dbf files
  * - Returns handle for debug area
  */
-
 debug_info_t *debug_register_mode(const char *name, int pages_per_area,
                                  int nr_areas, int buf_size, umode_t mode,
                                  uid_t uid, gid_t gid)
@@ -704,18 +664,16 @@ debug_info_t *debug_register_mode(const char *name, int pages_per_area,
        BUG_ON(!initialized);
        mutex_lock(&debug_mutex);
 
-        /* create new debug_info */
-
+       /* create new debug_info */
        rc = debug_info_create(name, pages_per_area, nr_areas, buf_size, mode);
-       if(!rc) 
+       if (!rc)
                goto out;
        debug_register_view(rc, &debug_level_view);
-        debug_register_view(rc, &debug_flush_view);
+       debug_register_view(rc, &debug_flush_view);
        debug_register_view(rc, &debug_pages_view);
 out:
-        if (!rc){
+       if (!rc)
                pr_err("Registering debug feature %s failed\n", name);
-        }
        mutex_unlock(&debug_mutex);
        return rc;
 }
@@ -726,7 +684,6 @@ EXPORT_SYMBOL(debug_register_mode);
  * - creates and initializes debug area for the caller
  * - returns handle for debug area
  */
-
 debug_info_t *debug_register(const char *name, int pages_per_area,
                             int nr_areas, int buf_size)
 {
@@ -739,18 +696,13 @@ EXPORT_SYMBOL(debug_register);
  * debug_unregister:
  * - give back debug area
  */
-
-void
-debug_unregister(debug_info_t * id)
+void debug_unregister(debug_info_t *id)
 {
        if (!id)
-               goto out;
+               return;
        mutex_lock(&debug_mutex);
        debug_info_put(id);
        mutex_unlock(&debug_mutex);
-
-out:
-       return;
 }
 EXPORT_SYMBOL(debug_unregister);
 
@@ -758,18 +710,17 @@ EXPORT_SYMBOL(debug_unregister);
  * debug_set_size:
  * - set area size (number of pages) and number of areas
  */
-static int
-debug_set_size(debug_info_t* id, int nr_areas, int pages_per_area)
+static int debug_set_size(debug_info_t *id, int nr_areas, int pages_per_area)
 {
+       debug_entry_t ***new_areas;
        unsigned long flags;
-       debug_entry_t *** new_areas;
-       int rc=0;
+       int rc = 0;
 
-       if(!id || (nr_areas <= 0) || (pages_per_area < 0))
+       if (!id || (nr_areas <= 0) || (pages_per_area < 0))
                return -EINVAL;
-       if(pages_per_area > 0){
+       if (pages_per_area > 0) {
                new_areas = debug_areas_alloc(pages_per_area, nr_areas);
-               if(!new_areas) {
+               if (!new_areas) {
                        pr_info("Allocating memory for %i pages failed\n",
                                pages_per_area);
                        rc = -ENOMEM;
@@ -778,16 +729,16 @@ debug_set_size(debug_info_t* id, int nr_areas, int pages_per_area)
        } else {
                new_areas = NULL;
        }
-       spin_lock_irqsave(&id->lock,flags);
+       spin_lock_irqsave(&id->lock, flags);
        debug_areas_free(id);
        id->areas = new_areas;
        id->nr_areas = nr_areas;
        id->pages_per_area = pages_per_area;
        id->active_area = 0;
-       memset(id->active_entries,0,sizeof(int)*id->nr_areas);
+       memset(id->active_entries, 0, sizeof(int)*id->nr_areas);
        memset(id->active_pages, 0, sizeof(int)*id->nr_areas);
-       spin_unlock_irqrestore(&id->lock,flags);
-       pr_info("%s: set new size (%i pages)\n" ,id->name, pages_per_area);
+       spin_unlock_irqrestore(&id->lock, flags);
+       pr_info("%s: set new size (%i pages)\n"id->name, pages_per_area);
 out:
        return rc;
 }
@@ -796,24 +747,23 @@ out:
  * debug_set_level:
  * - set actual debug level
  */
-
-void
-debug_set_level(debug_info_t* id, int new_level)
+void debug_set_level(debug_info_t *id, int new_level)
 {
        unsigned long flags;
-       if(!id)
-               return; 
-       spin_lock_irqsave(&id->lock,flags);
-        if(new_level == DEBUG_OFF_LEVEL){
-                id->level = DEBUG_OFF_LEVEL;
-               pr_info("%s: switched off\n",id->name);
-        } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+
+       if (!id)
+               return;
+       spin_lock_irqsave(&id->lock, flags);
+       if (new_level == DEBUG_OFF_LEVEL) {
+               id->level = DEBUG_OFF_LEVEL;
+               pr_info("%s: switched off\n", id->name);
+       } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
                pr_info("%s: level %i is out of range (%i - %i)\n",
-                        id->name, new_level, 0, DEBUG_MAX_LEVEL);
-        } else {
-                id->level = new_level;
-        }
-       spin_unlock_irqrestore(&id->lock,flags);
+                       id->name, new_level, 0, DEBUG_MAX_LEVEL);
+       } else {
+               id->level = new_level;
+       }
+       spin_unlock_irqrestore(&id->lock, flags);
 }
 EXPORT_SYMBOL(debug_set_level);
 
@@ -821,12 +771,10 @@ EXPORT_SYMBOL(debug_set_level);
  * proceed_active_entry:
  * - set active entry to next in the ring buffer
  */
-
-static inline void
-proceed_active_entry(debug_info_t * id)
+static inline void proceed_active_entry(debug_info_t *id)
 {
        if ((id->active_entries[id->active_area] += id->entry_size)
-           > (PAGE_SIZE - id->entry_size)){
+           > (PAGE_SIZE - id->entry_size)) {
                id->active_entries[id->active_area] = 0;
                id->active_pages[id->active_area] =
                        (id->active_pages[id->active_area] + 1) %
@@ -838,9 +786,7 @@ proceed_active_entry(debug_info_t * id)
  * proceed_active_area:
  * - set active area to next in the ring buffer
  */
-
-static inline void
-proceed_active_area(debug_info_t * id)
+static inline void proceed_active_area(debug_info_t *id)
 {
        id->active_area++;
        id->active_area = id->active_area % id->nr_areas;
@@ -849,13 +795,11 @@ proceed_active_area(debug_info_t * id)
 /*
  * get_active_entry:
  */
-
-static inline debug_entry_t*
-get_active_entry(debug_info_t * id)
+static inline debug_entry_t *get_active_entry(debug_info_t *id)
 {
        return (debug_entry_t *) (((char *) id->areas[id->active_area]
-                                       [id->active_pages[id->active_area]]) +
-                                       id->active_entries[id->active_area]);
+                                  [id->active_pages[id->active_area]]) +
+                                 id->active_entries[id->active_area]);
 }
 
 /*
@@ -863,23 +807,22 @@ get_active_entry(debug_info_t * id)
  * - set timestamp, caller address, cpu number etc.
  */
 
-static inline void
-debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
-                       int exception)
+static inline void debug_finish_entry(debug_info_t *id, debug_entry_t *active,
+                                     int level, int exception)
 {
        active->id.stck = get_tod_clock_fast() -
                *(unsigned long long *) &tod_clock_base[1];
        active->id.fields.cpuid = smp_processor_id();
        active->caller = __builtin_return_address(0);
        active->id.fields.exception = exception;
-       active->id.fields.level     = level;
+       active->id.fields.level = level;
        proceed_active_entry(id);
-       if(exception)
+       if (exception)
                proceed_active_area(id);
 }
 
-static int debug_stoppable=1;
-static int debug_active=1;
+static int debug_stoppable = 1;
+static int debug_active = 1;
 
 #define CTL_S390DBF_STOPPABLE 5678
 #define CTL_S390DBF_ACTIVE 5679
@@ -889,9 +832,8 @@ static int debug_active=1;
  * always allow read, allow write only if debug_stoppable is set or
  * if debug_active is already off
  */
-static int
-s390dbf_procactive(struct ctl_table *table, int write,
-                     void __user *buffer, size_t *lenp, loff_t *ppos)
+static int s390dbf_procactive(struct ctl_table *table, int write,
+                             void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        if (!write || debug_stoppable || !debug_active)
                return proc_dointvec(table, write, buffer, lenp, ppos);
@@ -899,39 +841,37 @@ s390dbf_procactive(struct ctl_table *table, int write,
                return 0;
 }
 
-
 static struct ctl_table s390dbf_table[] = {
        {
-               .procname       = "debug_stoppable",
+               .procname       = "debug_stoppable",
                .data           = &debug_stoppable,
                .maxlen         = sizeof(int),
-               .mode           = S_IRUGO | S_IWUSR,
-               .proc_handler   = proc_dointvec,
+               .mode           = S_IRUGO | S_IWUSR,
+               .proc_handler   = proc_dointvec,
        },
-        {
-               .procname       = "debug_active",
+       {
+               .procname       = "debug_active",
                .data           = &debug_active,
                .maxlen         = sizeof(int),
-               .mode           = S_IRUGO | S_IWUSR,
-               .proc_handler   = s390dbf_procactive,
+               .mode           = S_IRUGO | S_IWUSR,
+               .proc_handler   = s390dbf_procactive,
        },
        { }
 };
 
 static struct ctl_table s390dbf_dir_table[] = {
        {
-               .procname       = "s390dbf",
-               .maxlen         = 0,
-               .mode           = S_IRUGO | S_IXUGO,
-               .child          = s390dbf_table,
+               .procname       = "s390dbf",
+               .maxlen         = 0,
+               .mode           = S_IRUGO | S_IXUGO,
+               .child          = s390dbf_table,
        },
        { }
 };
 
 static struct ctl_table_header *s390dbf_sysctl_header;
 
-void
-debug_stop_all(void)
+void debug_stop_all(void)
 {
        if (debug_stoppable)
                debug_active = 0;
@@ -947,26 +887,31 @@ void debug_set_critical(void)
  * debug_event_common:
  * - write debug entry with given size
  */
-
-debug_entry_t*
-debug_event_common(debug_info_t * id, int level, const void *buf, int len)
+debug_entry_t *debug_event_common(debug_info_t *id, int level, const void *buf,
+                                 int len)
 {
-       unsigned long flags;
        debug_entry_t *active;
+       unsigned long flags;
 
        if (!debug_active || !id->areas)
                return NULL;
        if (debug_critical) {
                if (!spin_trylock_irqsave(&id->lock, flags))
                        return NULL;
-       } else
+       } else {
                spin_lock_irqsave(&id->lock, flags);
-       active = get_active_entry(id);
-       memset(DEBUG_DATA(active), 0, id->buf_size);
-       memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
-       debug_finish_entry(id, active, level, 0);
-       spin_unlock_irqrestore(&id->lock, flags);
+       }
+       do {
+               active = get_active_entry(id);
+               memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
+               if (len < id->buf_size)
+                       memset((DEBUG_DATA(active)) + len, 0, id->buf_size - len);
+               debug_finish_entry(id, active, level, 0);
+               len -= id->buf_size;
+               buf += id->buf_size;
+       } while (len > 0);
 
+       spin_unlock_irqrestore(&id->lock, flags);
        return active;
 }
 EXPORT_SYMBOL(debug_event_common);
@@ -975,26 +920,31 @@ EXPORT_SYMBOL(debug_event_common);
  * debug_exception_common:
  * - write debug entry with given size and switch to next debug area
  */
-
-debug_entry_t
-*debug_exception_common(debug_info_t * id, int level, const void *buf, int len)
+debug_entry_t *debug_exception_common(debug_info_t *id, int level,
+                                     const void *buf, int len)
 {
-       unsigned long flags;
        debug_entry_t *active;
+       unsigned long flags;
 
        if (!debug_active || !id->areas)
                return NULL;
        if (debug_critical) {
                if (!spin_trylock_irqsave(&id->lock, flags))
                        return NULL;
-       } else
+       } else {
                spin_lock_irqsave(&id->lock, flags);
-       active = get_active_entry(id);
-       memset(DEBUG_DATA(active), 0, id->buf_size);
-       memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
-       debug_finish_entry(id, active, level, 1);
-       spin_unlock_irqrestore(&id->lock, flags);
+       }
+       do {
+               active = get_active_entry(id);
+               memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
+               if (len < id->buf_size)
+                       memset((DEBUG_DATA(active)) + len, 0, id->buf_size - len);
+               debug_finish_entry(id, active, level, len <= id->buf_size);
+               len -= id->buf_size;
+               buf += id->buf_size;
+       } while (len > 0);
 
+       spin_unlock_irqrestore(&id->lock, flags);
        return active;
 }
 EXPORT_SYMBOL(debug_exception_common);
@@ -1002,47 +952,44 @@ EXPORT_SYMBOL(debug_exception_common);
 /*
  * counts arguments in format string for sprintf view
  */
-
-static inline int
-debug_count_numargs(char *string)
+static inline int debug_count_numargs(char *string)
 {
-       int numargs=0;
+       int numargs = 0;
 
-       while(*string) {
-               if(*string++=='%')
+       while (*string) {
+               if (*string++ == '%')
                        numargs++;
        }
-       return(numargs);
+       return numargs;
 }
 
 /*
  * debug_sprintf_event:
  */
-
-debug_entry_t*
-__debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
+debug_entry_t *__debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
 {
-       va_list   ap;
-       int numargs,idx;
-       unsigned long flags;
        debug_sprintf_entry_t *curr_event;
        debug_entry_t *active;
+       unsigned long flags;
+       int numargs, idx;
+       va_list ap;
 
        if (!debug_active || !id->areas)
                return NULL;
-       numargs=debug_count_numargs(string);
+       numargs = debug_count_numargs(string);
 
        if (debug_critical) {
                if (!spin_trylock_irqsave(&id->lock, flags))
                        return NULL;
-       } else
+       } else {
                spin_lock_irqsave(&id->lock, flags);
+       }
        active = get_active_entry(id);
-       curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active);
-       va_start(ap,string);
-       curr_event->string=string;
-       for(idx=0;idx<min(numargs,(int)(id->buf_size / sizeof(long))-1);idx++)
-               curr_event->args[idx]=va_arg(ap,long);
+       curr_event = (debug_sprintf_entry_t *) DEBUG_DATA(active);
+       va_start(ap, string);
+       curr_event->string = string;
+       for (idx = 0; idx < min(numargs, (int)(id->buf_size / sizeof(long)) - 1); idx++)
+               curr_event->args[idx] = va_arg(ap, long);
        va_end(ap);
        debug_finish_entry(id, active, level, 0);
        spin_unlock_irqrestore(&id->lock, flags);
@@ -1054,32 +1001,31 @@ EXPORT_SYMBOL(__debug_sprintf_event);
 /*
  * debug_sprintf_exception:
  */
-
-debug_entry_t*
-__debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
+debug_entry_t *__debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
 {
-       va_list   ap;
-       int numargs,idx;
-       unsigned long flags;
        debug_sprintf_entry_t *curr_event;
        debug_entry_t *active;
+       unsigned long flags;
+       int numargs, idx;
+       va_list ap;
 
        if (!debug_active || !id->areas)
                return NULL;
 
-       numargs=debug_count_numargs(string);
+       numargs = debug_count_numargs(string);
 
        if (debug_critical) {
                if (!spin_trylock_irqsave(&id->lock, flags))
                        return NULL;
-       } else
+       } else {
                spin_lock_irqsave(&id->lock, flags);
+       }
        active = get_active_entry(id);
-       curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active);
-       va_start(ap,string);
-       curr_event->string=string;
-       for(idx=0;idx<min(numargs,(int)(id->buf_size / sizeof(long))-1);idx++)
-               curr_event->args[idx]=va_arg(ap,long);
+       curr_event = (debug_sprintf_entry_t *)DEBUG_DATA(active);
+       va_start(ap, string);
+       curr_event->string = string;
+       for (idx = 0; idx < min(numargs, (int)(id->buf_size / sizeof(long)) - 1); idx++)
+               curr_event->args[idx] = va_arg(ap, long);
        va_end(ap);
        debug_finish_entry(id, active, level, 1);
        spin_unlock_irqrestore(&id->lock, flags);
@@ -1091,15 +1037,13 @@ EXPORT_SYMBOL(__debug_sprintf_exception);
 /*
  * debug_register_view:
  */
-
-int
-debug_register_view(debug_info_t * id, struct debug_view *view)
+int debug_register_view(debug_info_t *id, struct debug_view *view)
 {
-       int rc = 0;
-       int i;
        unsigned long flags;
-       umode_t mode;
        struct dentry *pde;
+       umode_t mode;
+       int rc = 0;
+       int i;
 
        if (!id)
                goto out;
@@ -1109,10 +1053,10 @@ debug_register_view(debug_info_t * id, struct debug_view *view)
        if (!view->input_proc)
                mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
        pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry,
-                               id , &debug_file_ops);
-       if (!pde){
+                                 id, &debug_file_ops);
+       if (!pde) {
                pr_err("Registering view %s/%s failed due to out of "
-                      "memory\n", id->name,view->name);
+                      "memory\n", id->name, view->name);
                rc = -1;
                goto out;
        }
@@ -1140,9 +1084,7 @@ EXPORT_SYMBOL(debug_register_view);
 /*
  * debug_unregister_view:
  */
-
-int
-debug_unregister_view(debug_info_t * id, struct debug_view *view)
+int debug_unregister_view(debug_info_t *id, struct debug_view *view)
 {
        struct dentry *dentry = NULL;
        unsigned long flags;
@@ -1155,9 +1097,9 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view)
                if (id->views[i] == view)
                        break;
        }
-       if (i == DEBUG_MAX_VIEWS)
+       if (i == DEBUG_MAX_VIEWS) {
                rc = -1;
-       else {
+       else {
                dentry = id->debugfs_entries[i];
                id->views[i] = NULL;
                id->debugfs_entries[i] = NULL;
@@ -1169,10 +1111,10 @@ out:
 }
 EXPORT_SYMBOL(debug_unregister_view);
 
-static inline char *
-debug_get_user_string(const char __user *user_buf, size_t user_len)
+static inline char *debug_get_user_string(const char __user *user_buf,
+                                         size_t user_len)
 {
-       charbuffer;
+       char *buffer;
 
        buffer = kmalloc(user_len + 1, GFP_KERNEL);
        if (!buffer)
@@ -1186,19 +1128,17 @@ debug_get_user_string(const char __user *user_buf, size_t user_len)
                buffer[user_len - 1] = 0;
        else
                buffer[user_len] = 0;
-        return buffer;
+       return buffer;
 }
 
-static inline int
-debug_get_uint(char *buf)
+static inline int debug_get_uint(char *buf)
 {
        int rc;
 
        buf = skip_spaces(buf);
        rc = simple_strtoul(buf, &buf, 10);
-       if(*buf){
+       if (*buf)
                rc = -EINVAL;
-       }
        return rc;
 }
 
@@ -1211,9 +1151,8 @@ debug_get_uint(char *buf)
  * prints out actual debug level
  */
 
-static int
-debug_prolog_pages_fn(debug_info_t * id,
-                                struct debug_view *view, char *out_buf)
+static int debug_prolog_pages_fn(debug_info_t *id, struct debug_view *view,
+                                char *out_buf)
 {
        return sprintf(out_buf, "%i\n", id->pages_per_area);
 }
@@ -1222,32 +1161,31 @@ debug_prolog_pages_fn(debug_info_t * id,
  * reads new size (number of pages per debug area)
  */
 
-static int
-debug_input_pages_fn(debug_info_t * id, struct debug_view *view,
-                       struct file *file, const char __user *user_buf,
-                       size_t user_len, loff_t * offset)
+static int debug_input_pages_fn(debug_info_t *id, struct debug_view *view,
+                               struct file *file, const char __user *user_buf,
+                               size_t user_len, loff_t *offset)
 {
+       int rc, new_pages;
        char *str;
-       int rc,new_pages;
 
        if (user_len > 0x10000)
-                user_len = 0x10000;
-       if (*offset != 0){
+               user_len = 0x10000;
+       if (*offset != 0) {
                rc = -EPIPE;
                goto out;
        }
-       str = debug_get_user_string(user_buf,user_len);
-       if(IS_ERR(str)){
+       str = debug_get_user_string(user_buf, user_len);
+       if (IS_ERR(str)) {
                rc = PTR_ERR(str);
                goto out;
        }
        new_pages = debug_get_uint(str);
-       if(new_pages < 0){
+       if (new_pages < 0) {
                rc = -EINVAL;
                goto free_str;
        }
-       rc = debug_set_size(id,id->nr_areas, new_pages);
-       if(rc != 0){
+       rc = debug_set_size(id, id->nr_areas, new_pages);
+       if (rc != 0) {
                rc = -EINVAL;
                goto free_str;
        }
@@ -1262,52 +1200,47 @@ out:
 /*
  * prints out actual debug level
  */
-
-static int
-debug_prolog_level_fn(debug_info_t * id, struct debug_view *view, char *out_buf)
+static int debug_prolog_level_fn(debug_info_t *id, struct debug_view *view,
+                                char *out_buf)
 {
        int rc = 0;
 
-       if(id->level == DEBUG_OFF_LEVEL) {
-               rc = sprintf(out_buf,"-\n");
-       }
-       else {
+       if (id->level == DEBUG_OFF_LEVEL)
+               rc = sprintf(out_buf, "-\n");
+       else
                rc = sprintf(out_buf, "%i\n", id->level);
-       }
        return rc;
 }
 
 /*
  * reads new debug level
  */
-
-static int
-debug_input_level_fn(debug_info_t * id, struct debug_view *view,
-                       struct file *file, const char __user *user_buf,
-                       size_t user_len, loff_t * offset)
+static int debug_input_level_fn(debug_info_t *id, struct debug_view *view,
+                               struct file *file, const char __user *user_buf,
+                               size_t user_len, loff_t *offset)
 {
+       int rc, new_level;
        char *str;
-       int rc,new_level;
 
        if (user_len > 0x10000)
-                user_len = 0x10000;
-       if (*offset != 0){
+               user_len = 0x10000;
+       if (*offset != 0) {
                rc = -EPIPE;
                goto out;
        }
-       str = debug_get_user_string(user_buf,user_len);
-       if(IS_ERR(str)){
+       str = debug_get_user_string(user_buf, user_len);
+       if (IS_ERR(str)) {
                rc = PTR_ERR(str);
                goto out;
        }
-       if(str[0] == '-'){
+       if (str[0] == '-') {
                debug_set_level(id, DEBUG_OFF_LEVEL);
                rc = user_len;
                goto free_str;
        } else {
                new_level = debug_get_uint(str);
        }
-       if(new_level < 0) {
+       if (new_level < 0) {
                pr_warn("%s is not a valid level for a debug feature\n", str);
                rc = -EINVAL;
        } else {
@@ -1321,99 +1254,90 @@ out:
        return rc;              /* number of input characters */
 }
 
-
 /*
  * flushes debug areas
  */
-static void debug_flush(debug_info_t* id, int area)
+static void debug_flush(debug_info_t *id, int area)
 {
-        unsigned long flags;
-        int i,j;
-
-        if(!id || !id->areas)
-                return;
-        spin_lock_irqsave(&id->lock,flags);
-        if(area == DEBUG_FLUSH_ALL){
-                id->active_area = 0;
-                memset(id->active_entries, 0, id->nr_areas * sizeof(int));
-                for (i = 0; i < id->nr_areas; i++) {
+       unsigned long flags;
+       int i, j;
+
+       if (!id || !id->areas)
+               return;
+       spin_lock_irqsave(&id->lock, flags);
+       if (area == DEBUG_FLUSH_ALL) {
+               id->active_area = 0;
+               memset(id->active_entries, 0, id->nr_areas * sizeof(int));
+               for (i = 0; i < id->nr_areas; i++) {
                        id->active_pages[i] = 0;
-                       for(j = 0; j < id->pages_per_area; j++) {
-                               memset(id->areas[i][j], 0, PAGE_SIZE);
-                       }
+                       for (j = 0; j < id->pages_per_area; j++)
+                               memset(id->areas[i][j], 0, PAGE_SIZE);
                }
-        } else if(area >= 0 && area < id->nr_areas) {
-                id->active_entries[area] = 0;
+       } else if (area >= 0 && area < id->nr_areas) {
+               id->active_entries[area] = 0;
                id->active_pages[area] = 0;
-               for(i = 0; i < id->pages_per_area; i++) {
-                       memset(id->areas[area][i],0,PAGE_SIZE);
-               }
-        }
-        spin_unlock_irqrestore(&id->lock,flags);
+               for (i = 0; i < id->pages_per_area; i++)
+                       memset(id->areas[area][i], 0, PAGE_SIZE);
+       }
+       spin_unlock_irqrestore(&id->lock, flags);
 }
 
 /*
- * view function: flushes debug areas 
+ * view function: flushes debug areas
  */
-
-static int
-debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
-                       struct file *file, const char __user *user_buf,
-                       size_t user_len, loff_t * offset)
+static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view,
+                               struct file *file, const char __user *user_buf,
+                               size_t user_len, loff_t *offset)
 {
-        char input_buf[1];
-        int rc = user_len;
+       char input_buf[1];
+       int rc = user_len;
 
        if (user_len > 0x10000)
-                user_len = 0x10000;
-        if (*offset != 0){
+               user_len = 0x10000;
+       if (*offset != 0) {
                rc = -EPIPE;
-                goto out;
+               goto out;
+       }
+       if (copy_from_user(input_buf, user_buf, 1)) {
+               rc = -EFAULT;
+               goto out;
+       }
+       if (input_buf[0] == '-') {
+               debug_flush(id, DEBUG_FLUSH_ALL);
+               goto out;
+       }
+       if (isdigit(input_buf[0])) {
+               int area = ((int) input_buf[0] - (int) '0');
+
+               debug_flush(id, area);
+               goto out;
        }
-        if (copy_from_user(input_buf, user_buf, 1)){
-                rc = -EFAULT;
-                goto out;
-        }
-        if(input_buf[0] == '-') { 
-                debug_flush(id, DEBUG_FLUSH_ALL);
-                goto out;
-        }
-        if (isdigit(input_buf[0])) {
-                int area = ((int) input_buf[0] - (int) '0');
-                debug_flush(id, area);
-                goto out;
-        }
 
        pr_info("Flushing debug data failed because %c is not a valid "
                 "area\n", input_buf[0]);
 
 out:
-        *offset += user_len;
-        return rc;              /* number of input characters */
+       *offset += user_len;
+       return rc;              /* number of input characters */
 }
 
 /*
  * prints debug header in raw format
  */
-
-static int
-debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
-                       int area, debug_entry_t * entry, char *out_buf)
+static int debug_raw_header_fn(debug_info_t *id, struct debug_view *view,
+                              int area, debug_entry_t *entry, char *out_buf)
 {
-        int rc;
+       int rc;
 
        rc = sizeof(debug_entry_t);
-       memcpy(out_buf,entry,sizeof(debug_entry_t));
-        return rc;
+       memcpy(out_buf, entry, sizeof(debug_entry_t));
+       return rc;
 }
 
 /*
  * prints debug data in raw format
  */
-
-static int
-debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+static int debug_raw_format_fn(debug_info_t *id, struct debug_view *view,
                               char *out_buf, const char *in_buf)
 {
        int rc;
@@ -1426,20 +1350,17 @@ debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
 /*
  * prints debug data in hex/ascii format
  */
-
-static int
-debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
-                         char *out_buf, const char *in_buf)
+static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
+                                    char *out_buf, const char *in_buf)
 {
        int i, rc = 0;
 
-       for (i = 0; i < id->buf_size; i++) {
-                rc += sprintf(out_buf + rc, "%02x ",
-                              ((unsigned char *) in_buf)[i]);
-        }
+       for (i = 0; i < id->buf_size; i++)
+               rc += sprintf(out_buf + rc, "%02x ", ((unsigned char *) in_buf)[i]);
        rc += sprintf(out_buf + rc, "| ");
        for (i = 0; i < id->buf_size; i++) {
                unsigned char c = in_buf[i];
+
                if (isascii(c) && isprint(c))
                        rc += sprintf(out_buf + rc, "%c", c);
                else
@@ -1452,16 +1373,14 @@ debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
 /*
  * prints header for debug entry
  */
-
-int
-debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
-                        int area, debug_entry_t * entry, char *out_buf)
+int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
+                        int area, debug_entry_t *entry, char *out_buf)
 {
        unsigned long base, sec, usec;
-       char *except_str;
        unsigned long caller;
-       int rc = 0;
        unsigned int level;
+       char *except_str;
+       int rc = 0;
 
        level = entry->id.fields.level;
        base = (*(unsigned long *) &tod_clock_base[0]) >> 4;
@@ -1487,19 +1406,18 @@ EXPORT_SYMBOL(debug_dflt_header_fn);
 
 #define DEBUG_SPRINTF_MAX_ARGS 10
 
-static int
-debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
-                        char *out_buf, debug_sprintf_entry_t *curr_event)
+static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
+                                  char *out_buf, debug_sprintf_entry_t *curr_event)
 {
-       int num_longs, num_used_args = 0,i, rc = 0;
+       int num_longs, num_used_args = 0, i, rc = 0;
        int index[DEBUG_SPRINTF_MAX_ARGS];
 
        /* count of longs fit into one entry */
-       num_longs = id->buf_size /  sizeof(long); 
+       num_longs = id->buf_size / sizeof(long);
 
-       if(num_longs < 1)
+       if (num_longs < 1)
                goto out; /* bufsize of entry too small */
-       if(num_longs == 1) {
+       if (num_longs == 1) {
                /* no args, we use only the string */
                strcpy(out_buf, curr_event->string);
                rc = strlen(curr_event->string);
@@ -1507,22 +1425,20 @@ debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
        }
 
        /* number of arguments used for sprintf (without the format string) */
-       num_used_args   = min(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1));
+       num_used_args = min(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1));
 
-       memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int));
+       memset(index, 0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int));
 
-       for(i = 0; i < num_used_args; i++)
+       for (i = 0; i < num_used_args; i++)
                index[i] = i;
 
-       rc =  sprintf(out_buf, curr_event->string, curr_event->args[index[0]],
-               curr_event->args[index[1]], curr_event->args[index[2]],
-               curr_event->args[index[3]], curr_event->args[index[4]],
-               curr_event->args[index[5]], curr_event->args[index[6]],
-               curr_event->args[index[7]], curr_event->args[index[8]],
-               curr_event->args[index[9]]);
-
+       rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]],
+                    curr_event->args[index[1]], curr_event->args[index[2]],
+                    curr_event->args[index[3]], curr_event->args[index[4]],
+                    curr_event->args[index[5]], curr_event->args[index[6]],
+                    curr_event->args[index[7]], curr_event->args[index[8]],
+                    curr_event->args[index[9]]);
 out:
-
        return rc;
 }
 
index f7e82302a71ef80004f5443770cd988bcc90ed53..b811d3a8417d5614fdbb560aaa96937d4929ae5c 100644 (file)
 #include <linux/reboot.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
-
 #include <linux/uaccess.h>
+#include <linux/atomic.h>
 #include <asm/dis.h>
 #include <asm/io.h>
-#include <linux/atomic.h>
 #include <asm/cpcmd.h>
 #include <asm/lowcore.h>
 #include <asm/debug.h>
 #include <asm/irq.h>
 
+/* Type of operand */
+#define OPERAND_GPR    0x1     /* Operand printed as %rx */
+#define OPERAND_FPR    0x2     /* Operand printed as %fx */
+#define OPERAND_AR     0x4     /* Operand printed as %ax */
+#define OPERAND_CR     0x8     /* Operand printed as %cx */
+#define OPERAND_VR     0x10    /* Operand printed as %vx */
+#define OPERAND_DISP   0x20    /* Operand printed as displacement */
+#define OPERAND_BASE   0x40    /* Operand printed as base register */
+#define OPERAND_INDEX  0x80    /* Operand printed as index register */
+#define OPERAND_PCREL  0x100   /* Operand printed as pc-relative symbol */
+#define OPERAND_SIGNED 0x200   /* Operand printed as signed value */
+#define OPERAND_LENGTH 0x400   /* Operand printed as length (+1) */
+
+struct s390_operand {
+       unsigned char bits;     /* The number of bits in the operand. */
+       unsigned char shift;    /* The number of bits to shift. */
+       unsigned short flags;   /* One bit syntax flags. */
+};
+
+struct s390_insn {
+       union {
+               const char name[5];
+               struct {
+                       unsigned char zero;
+                       unsigned int offset;
+               } __packed;
+       };
+       unsigned char opfrag;
+       unsigned char format;
+};
+
+struct s390_opcode_offset {
+       unsigned char opcode;
+       unsigned char mask;
+       unsigned char byte;
+       unsigned short offset;
+       unsigned short count;
+} __packed;
+
 enum {
-       UNUSED, /* Indicates the end of the operand list */
-       R_8,    /* GPR starting at position 8 */
-       R_12,   /* GPR starting at position 12 */
-       R_16,   /* GPR starting at position 16 */
-       R_20,   /* GPR starting at position 20 */
-       R_24,   /* GPR starting at position 24 */
-       R_28,   /* GPR starting at position 28 */
-       R_32,   /* GPR starting at position 32 */
-       F_8,    /* FPR starting at position 8 */
-       F_12,   /* FPR starting at position 12 */
-       F_16,   /* FPR starting at position 16 */
-       F_20,   /* FPR starting at position 16 */
-       F_24,   /* FPR starting at position 24 */
-       F_28,   /* FPR starting at position 28 */
-       F_32,   /* FPR starting at position 32 */
+       UNUSED,
        A_8,    /* Access reg. starting at position 8 */
        A_12,   /* Access reg. starting at position 12 */
        A_24,   /* Access reg. starting at position 24 */
        A_28,   /* Access reg. starting at position 28 */
-       C_8,    /* Control reg. starting at position 8 */
-       C_12,   /* Control reg. starting at position 12 */
-       V_8,    /* Vector reg. starting at position 8, extension bit at 36 */
-       V_12,   /* Vector reg. starting at position 12, extension bit at 37 */
-       V_16,   /* Vector reg. starting at position 16, extension bit at 38 */
-       V_32,   /* Vector reg. starting at position 32, extension bit at 39 */
-       W_12,   /* Vector reg. at bit 12, extension at bit 37, used as index */
        B_16,   /* Base register starting at position 16 */
        B_32,   /* Base register starting at position 32 */
-       X_12,   /* Index register starting at position 12 */
+       C_8,    /* Control reg. starting at position 8 */
+       C_12,   /* Control reg. starting at position 12 */
+       D20_20, /* 20 bit displacement starting at 20 */
        D_20,   /* Displacement starting at position 20 */
        D_36,   /* Displacement starting at position 36 */
-       D20_20, /* 20 bit displacement starting at 20 */
+       F_8,    /* FPR starting at position 8 */
+       F_12,   /* FPR starting at position 12 */
+       F_16,   /* FPR starting at position 16 */
+       F_24,   /* FPR starting at position 24 */
+       F_28,   /* FPR starting at position 28 */
+       F_32,   /* FPR starting at position 32 */
+       I8_8,   /* 8 bit signed value starting at 8 */
+       I8_32,  /* 8 bit signed value starting at 32 */
+       I16_16, /* 16 bit signed value starting at 16 */
+       I16_32, /* 16 bit signed value starting at 32 */
+       I32_16, /* 32 bit signed value starting at 16 */
+       J12_12, /* 12 bit PC relative offset at 12 */
+       J16_16, /* 16 bit PC relative offset at 16 */
+       J16_32, /* 16 bit PC relative offset at 32 */
+       J24_24, /* 24 bit PC relative offset at 24 */
+       J32_16, /* 32 bit PC relative offset at 16 */
        L4_8,   /* 4 bit length starting at position 8 */
        L4_12,  /* 4 bit length starting at position 12 */
        L8_8,   /* 8 bit length starting at position 8 */
+       R_8,    /* GPR starting at position 8 */
+       R_12,   /* GPR starting at position 12 */
+       R_16,   /* GPR starting at position 16 */
+       R_24,   /* GPR starting at position 24 */
+       R_28,   /* GPR starting at position 28 */
        U4_8,   /* 4 bit unsigned value starting at 8 */
        U4_12,  /* 4 bit unsigned value starting at 12 */
        U4_16,  /* 4 bit unsigned value starting at 16 */
@@ -78,1651 +117,226 @@ enum {
        U8_8,   /* 8 bit unsigned value starting at 8 */
        U8_16,  /* 8 bit unsigned value starting at 16 */
        U8_24,  /* 8 bit unsigned value starting at 24 */
+       U8_28,  /* 8 bit unsigned value starting at 28 */
        U8_32,  /* 8 bit unsigned value starting at 32 */
-       I8_8,   /* 8 bit signed value starting at 8 */
-       I8_16,  /* 8 bit signed value starting at 16 */
-       I8_24,  /* 8 bit signed value starting at 24 */
-       I8_32,  /* 8 bit signed value starting at 32 */
-       J12_12, /* PC relative offset at 12 */
-       I16_16, /* 16 bit signed value starting at 16 */
-       I16_32, /* 32 bit signed value starting at 16 */
-       U16_16, /* 16 bit unsigned value starting at 16 */
-       U16_32, /* 32 bit unsigned value starting at 16 */
-       J16_16, /* PC relative jump offset at 16 */
-       J16_32, /* PC relative offset at 16 */
-       I24_24, /* 24 bit signed value starting at 24 */
-       J32_16, /* PC relative long offset at 16 */
-       I32_16, /* 32 bit signed value starting at 16 */
-       U32_16, /* 32 bit unsigned value starting at 16 */
-       M_16,   /* 4 bit optional mask starting at 16 */
-       M_20,   /* 4 bit optional mask starting at 20 */
-       M_24,   /* 4 bit optional mask starting at 24 */
-       M_28,   /* 4 bit optional mask starting at 28 */
-       M_32,   /* 4 bit optional mask starting at 32 */
-       RO_28,  /* optional GPR starting at position 28 */
-};
-
-/*
- * Enumeration of the different instruction formats.
- * For details consult the principles of operation.
- */
-enum {
-       INSTR_INVALID,
-       INSTR_E,
-       INSTR_IE_UU,
-       INSTR_MII_UPI,
-       INSTR_RIE_R0IU, INSTR_RIE_R0UU, INSTR_RIE_RRP, INSTR_RIE_RRPU,
-       INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU, INSTR_RIE_RRI0,
-       INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, INSTR_RIL_UP,
-       INSTR_RIS_R0RDU, INSTR_RIS_R0UU, INSTR_RIS_RURDI, INSTR_RIS_RURDU,
-       INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP,
-       INSTR_RRE_00, INSTR_RRE_0R, INSTR_RRE_AA, INSTR_RRE_AR, INSTR_RRE_F0,
-       INSTR_RRE_FF, INSTR_RRE_FR, INSTR_RRE_R0, INSTR_RRE_RA, INSTR_RRE_RF,
-       INSTR_RRE_RR, INSTR_RRE_RR_OPT,
-       INSTR_RRF_0UFF, INSTR_RRF_F0FF, INSTR_RRF_F0FF2, INSTR_RRF_F0FR,
-       INSTR_RRF_FFRU, INSTR_RRF_FUFF, INSTR_RRF_FUFF2, INSTR_RRF_M0RR,
-       INSTR_RRF_R0RR, INSTR_RRF_R0RR2, INSTR_RRF_RMRR, INSTR_RRF_RURR,
-       INSTR_RRF_U0FF, INSTR_RRF_U0RF, INSTR_RRF_U0RR, INSTR_RRF_UUFF,
-       INSTR_RRF_UUFR, INSTR_RRF_UURF,
-       INSTR_RRR_F0FF, INSTR_RRS_RRRDU,
-       INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR,
-       INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD,
-       INSTR_RSI_RRP,
-       INSTR_RSL_LRDFU, INSTR_RSL_R0RD,
-       INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD,
-       INSTR_RSY_RDRM, INSTR_RSY_RMRD,
-       INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
-       INSTR_RS_RURD,
-       INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM,
-       INSTR_RXF_FRRDF,
-       INSTR_RXY_FRRD, INSTR_RXY_RRRD, INSTR_RXY_URRD,
-       INSTR_RX_FRRD, INSTR_RX_RRRD, INSTR_RX_URRD,
-       INSTR_SIL_RDI, INSTR_SIL_RDU,
-       INSTR_SIY_IRD, INSTR_SIY_URD,
-       INSTR_SI_URD,
-       INSTR_SMI_U0RDP,
-       INSTR_SSE_RDRD,
-       INSTR_SSF_RRDRD, INSTR_SSF_RRDRD2,
-       INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, INSTR_SS_LLRDRD, INSTR_SS_RRRDRD,
-       INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3,
-       INSTR_S_00, INSTR_S_RD,
-       INSTR_VRI_V0IM, INSTR_VRI_V0I0, INSTR_VRI_V0IIM, INSTR_VRI_VVIM,
-       INSTR_VRI_VVV0IM, INSTR_VRI_VVV0I0, INSTR_VRI_VVIMM,
-       INSTR_VRR_VV00MMM, INSTR_VRR_VV000MM, INSTR_VRR_VV0000M,
-       INSTR_VRR_VV00000, INSTR_VRR_VVV0M0M, INSTR_VRR_VV00M0M,
-       INSTR_VRR_VVV000M, INSTR_VRR_VVV000V, INSTR_VRR_VVV0000,
-       INSTR_VRR_VVV0MMM, INSTR_VRR_VVV00MM, INSTR_VRR_VVVMM0V,
-       INSTR_VRR_VVVM0MV, INSTR_VRR_VVVM00V, INSTR_VRR_VRR0000,
-       INSTR_VRS_VVRDM, INSTR_VRS_VVRD0, INSTR_VRS_VRRDM, INSTR_VRS_VRRD0,
-       INSTR_VRS_RVRDM,
-       INSTR_VRV_VVRDM, INSTR_VRV_VWRDM,
-       INSTR_VRX_VRRDM, INSTR_VRX_VRRD0,
+       U12_16, /* 12 bit unsigned value starting at 16 */
+       U16_16, /* 16 bit unsigned value starting at 16 */
+       U16_32, /* 16 bit unsigned value starting at 32 */
+       U32_16, /* 32 bit unsigned value starting at 16 */
+       VX_12,  /* Vector index register starting at position 12 */
+       V_8,    /* Vector reg. starting at position 8 */
+       V_12,   /* Vector reg. starting at position 12 */
+       V_16,   /* Vector reg. starting at position 16 */
+       V_32,   /* Vector reg. starting at position 32 */
+       X_12,   /* Index register starting at position 12 */
 };
 
-static const struct s390_operand operands[] =
-{
-       [UNUSED]  = { 0, 0, 0 },
-       [R_8]    = {  4,  8, OPERAND_GPR },
-       [R_12]   = {  4, 12, OPERAND_GPR },
-       [R_16]   = {  4, 16, OPERAND_GPR },
-       [R_20]   = {  4, 20, OPERAND_GPR },
-       [R_24]   = {  4, 24, OPERAND_GPR },
-       [R_28]   = {  4, 28, OPERAND_GPR },
-       [R_32]   = {  4, 32, OPERAND_GPR },
-       [F_8]    = {  4,  8, OPERAND_FPR },
-       [F_12]   = {  4, 12, OPERAND_FPR },
-       [F_16]   = {  4, 16, OPERAND_FPR },
-       [F_20]   = {  4, 16, OPERAND_FPR },
-       [F_24]   = {  4, 24, OPERAND_FPR },
-       [F_28]   = {  4, 28, OPERAND_FPR },
-       [F_32]   = {  4, 32, OPERAND_FPR },
+static const struct s390_operand operands[] = {
+       [UNUSED] = {  0,  0, 0 },
        [A_8]    = {  4,  8, OPERAND_AR },
        [A_12]   = {  4, 12, OPERAND_AR },
        [A_24]   = {  4, 24, OPERAND_AR },
        [A_28]   = {  4, 28, OPERAND_AR },
-       [C_8]    = {  4,  8, OPERAND_CR },
-       [C_12]   = {  4, 12, OPERAND_CR },
-       [V_8]    = {  4,  8, OPERAND_VR },
-       [V_12]   = {  4, 12, OPERAND_VR },
-       [V_16]   = {  4, 16, OPERAND_VR },
-       [V_32]   = {  4, 32, OPERAND_VR },
-       [W_12]   = {  4, 12, OPERAND_INDEX | OPERAND_VR },
        [B_16]   = {  4, 16, OPERAND_BASE | OPERAND_GPR },
        [B_32]   = {  4, 32, OPERAND_BASE | OPERAND_GPR },
-       [X_12]   = {  4, 12, OPERAND_INDEX | OPERAND_GPR },
+       [C_8]    = {  4,  8, OPERAND_CR },
+       [C_12]   = {  4, 12, OPERAND_CR },
+       [D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED },
        [D_20]   = { 12, 20, OPERAND_DISP },
        [D_36]   = { 12, 36, OPERAND_DISP },
-       [D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED },
+       [F_8]    = {  4,  8, OPERAND_FPR },
+       [F_12]   = {  4, 12, OPERAND_FPR },
+       [F_16]   = {  4, 16, OPERAND_FPR },
+       [F_24]   = {  4, 24, OPERAND_FPR },
+       [F_28]   = {  4, 28, OPERAND_FPR },
+       [F_32]   = {  4, 32, OPERAND_FPR },
+       [I8_8]   = {  8,  8, OPERAND_SIGNED },
+       [I8_32]  = {  8, 32, OPERAND_SIGNED },
+       [I16_16] = { 16, 16, OPERAND_SIGNED },
+       [I16_32] = { 16, 32, OPERAND_SIGNED },
+       [I32_16] = { 32, 16, OPERAND_SIGNED },
+       [J12_12] = { 12, 12, OPERAND_PCREL },
+       [J16_16] = { 16, 16, OPERAND_PCREL },
+       [J16_32] = { 16, 32, OPERAND_PCREL },
+       [J24_24] = { 24, 24, OPERAND_PCREL },
+       [J32_16] = { 32, 16, OPERAND_PCREL },
        [L4_8]   = {  4,  8, OPERAND_LENGTH },
-       [L4_12]  = {  4, 12, OPERAND_LENGTH },
+       [L4_12]  = {  4, 12, OPERAND_LENGTH },
        [L8_8]   = {  8,  8, OPERAND_LENGTH },
+       [R_8]    = {  4,  8, OPERAND_GPR },
+       [R_12]   = {  4, 12, OPERAND_GPR },
+       [R_16]   = {  4, 16, OPERAND_GPR },
+       [R_24]   = {  4, 24, OPERAND_GPR },
+       [R_28]   = {  4, 28, OPERAND_GPR },
        [U4_8]   = {  4,  8, 0 },
-       [U4_12]  = {  4, 12, 0 },
-       [U4_16]  = {  4, 16, 0 },
-       [U4_20]  = {  4, 20, 0 },
-       [U4_24]  = {  4, 24, 0 },
-       [U4_28]  = {  4, 28, 0 },
-       [U4_32]  = {  4, 32, 0 },
-       [U4_36]  = {  4, 36, 0 },
+       [U4_12]  = {  4, 12, 0 },
+       [U4_16]  = {  4, 16, 0 },
+       [U4_20]  = {  4, 20, 0 },
+       [U4_24]  = {  4, 24, 0 },
+       [U4_28]  = {  4, 28, 0 },
+       [U4_32]  = {  4, 32, 0 },
+       [U4_36]  = {  4, 36, 0 },
        [U8_8]   = {  8,  8, 0 },
-       [U8_16]  = {  8, 16, 0 },
-       [U8_24]  = {  8, 24, 0 },
-       [U8_32]  = {  8, 32, 0 },
-       [J12_12] = { 12, 12, OPERAND_PCREL },
-       [I8_8]   = {  8,  8, OPERAND_SIGNED },
-       [I8_16]  = {  8, 16, OPERAND_SIGNED },
-       [I8_24]  = {  8, 24, OPERAND_SIGNED },
-       [I8_32]  = {  8, 32, OPERAND_SIGNED },
-       [I16_32] = { 16, 32, OPERAND_SIGNED },
-       [I16_16] = { 16, 16, OPERAND_SIGNED },
+       [U8_16]  = {  8, 16, 0 },
+       [U8_24]  = {  8, 24, 0 },
+       [U8_28]  = {  8, 28, 0 },
+       [U8_32]  = {  8, 32, 0 },
+       [U12_16] = { 12, 16, 0 },
        [U16_16] = { 16, 16, 0 },
        [U16_32] = { 16, 32, 0 },
-       [J16_16] = { 16, 16, OPERAND_PCREL },
-       [J16_32] = { 16, 32, OPERAND_PCREL },
-       [I24_24] = { 24, 24, OPERAND_SIGNED },
-       [J32_16] = { 32, 16, OPERAND_PCREL },
-       [I32_16] = { 32, 16, OPERAND_SIGNED },
        [U32_16] = { 32, 16, 0 },
-       [M_16]   = {  4, 16, 0 },
-       [M_20]   = {  4, 20, 0 },
-       [M_24]   = {  4, 24, 0 },
-       [M_28]   = {  4, 28, 0 },
-       [M_32]   = {  4, 32, 0 },
-       [RO_28]  = {  4, 28, OPERAND_GPR }
-};
-
-static const unsigned char formats[][7] = {
-       [INSTR_E]         = { 0xff, 0,0,0,0,0,0 },
-       [INSTR_IE_UU]     = { 0xff, U4_24,U4_28,0,0,0,0 },
-       [INSTR_MII_UPI]   = { 0xff, U4_8,J12_12,I24_24 },
-       [INSTR_RIE_R0IU]  = { 0xff, R_8,I16_16,U4_32,0,0,0 },
-       [INSTR_RIE_R0UU]  = { 0xff, R_8,U16_16,U4_32,0,0,0 },
-       [INSTR_RIE_RRI0]  = { 0xff, R_8,R_12,I16_16,0,0,0 },
-       [INSTR_RIE_RRPU]  = { 0xff, R_8,R_12,U4_32,J16_16,0,0 },
-       [INSTR_RIE_RRP]   = { 0xff, R_8,R_12,J16_16,0,0,0 },
-       [INSTR_RIE_RRUUU] = { 0xff, R_8,R_12,U8_16,U8_24,U8_32,0 },
-       [INSTR_RIE_RUPI]  = { 0xff, R_8,I8_32,U4_12,J16_16,0,0 },
-       [INSTR_RIE_RUPU]  = { 0xff, R_8,U8_32,U4_12,J16_16,0,0 },
-       [INSTR_RIL_RI]    = { 0x0f, R_8,I32_16,0,0,0,0 },
-       [INSTR_RIL_RP]    = { 0x0f, R_8,J32_16,0,0,0,0 },
-       [INSTR_RIL_RU]    = { 0x0f, R_8,U32_16,0,0,0,0 },
-       [INSTR_RIL_UP]    = { 0x0f, U4_8,J32_16,0,0,0,0 },
-       [INSTR_RIS_R0RDU] = { 0xff, R_8,U8_32,D_20,B_16,0,0 },
-       [INSTR_RIS_RURDI] = { 0xff, R_8,I8_32,U4_12,D_20,B_16,0 },
-       [INSTR_RIS_RURDU] = { 0xff, R_8,U8_32,U4_12,D_20,B_16,0 },
-       [INSTR_RI_RI]     = { 0x0f, R_8,I16_16,0,0,0,0 },
-       [INSTR_RI_RP]     = { 0x0f, R_8,J16_16,0,0,0,0 },
-       [INSTR_RI_RU]     = { 0x0f, R_8,U16_16,0,0,0,0 },
-       [INSTR_RI_UP]     = { 0x0f, U4_8,J16_16,0,0,0,0 },
-       [INSTR_RRE_00]    = { 0xff, 0,0,0,0,0,0 },
-       [INSTR_RRE_0R]    = { 0xff, R_28,0,0,0,0,0 },
-       [INSTR_RRE_AA]    = { 0xff, A_24,A_28,0,0,0,0 },
-       [INSTR_RRE_AR]    = { 0xff, A_24,R_28,0,0,0,0 },
-       [INSTR_RRE_F0]    = { 0xff, F_24,0,0,0,0,0 },
-       [INSTR_RRE_FF]    = { 0xff, F_24,F_28,0,0,0,0 },
-       [INSTR_RRE_FR]    = { 0xff, F_24,R_28,0,0,0,0 },
-       [INSTR_RRE_R0]    = { 0xff, R_24,0,0,0,0,0 },
-       [INSTR_RRE_RA]    = { 0xff, R_24,A_28,0,0,0,0 },
-       [INSTR_RRE_RF]    = { 0xff, R_24,F_28,0,0,0,0 },
-       [INSTR_RRE_RR]    = { 0xff, R_24,R_28,0,0,0,0 },
-       [INSTR_RRE_RR_OPT]= { 0xff, R_24,RO_28,0,0,0,0 },
-       [INSTR_RRF_0UFF]  = { 0xff, F_24,F_28,U4_20,0,0,0 },
-       [INSTR_RRF_F0FF2] = { 0xff, F_24,F_16,F_28,0,0,0 },
-       [INSTR_RRF_F0FF]  = { 0xff, F_16,F_24,F_28,0,0,0 },
-       [INSTR_RRF_F0FR]  = { 0xff, F_24,F_16,R_28,0,0,0 },
-       [INSTR_RRF_FFRU]  = { 0xff, F_24,F_16,R_28,U4_20,0,0 },
-       [INSTR_RRF_FUFF]  = { 0xff, F_24,F_16,F_28,U4_20,0,0 },
-       [INSTR_RRF_FUFF2] = { 0xff, F_24,F_28,F_16,U4_20,0,0 },
-       [INSTR_RRF_M0RR]  = { 0xff, R_24,R_28,M_16,0,0,0 },
-       [INSTR_RRF_R0RR]  = { 0xff, R_24,R_16,R_28,0,0,0 },
-       [INSTR_RRF_R0RR2] = { 0xff, R_24,R_28,R_16,0,0,0 },
-       [INSTR_RRF_RMRR]  = { 0xff, R_24,R_16,R_28,M_20,0,0 },
-       [INSTR_RRF_RURR]  = { 0xff, R_24,R_28,R_16,U4_20,0,0 },
-       [INSTR_RRF_U0FF]  = { 0xff, F_24,U4_16,F_28,0,0,0 },
-       [INSTR_RRF_U0RF]  = { 0xff, R_24,U4_16,F_28,0,0,0 },
-       [INSTR_RRF_U0RR]  = { 0xff, R_24,R_28,U4_16,0,0,0 },
-       [INSTR_RRF_UUFF]  = { 0xff, F_24,U4_16,F_28,U4_20,0,0 },
-       [INSTR_RRF_UUFR]  = { 0xff, F_24,U4_16,R_28,U4_20,0,0 },
-       [INSTR_RRF_UURF]  = { 0xff, R_24,U4_16,F_28,U4_20,0,0 },
-       [INSTR_RRR_F0FF]  = { 0xff, F_24,F_28,F_16,0,0,0 },
-       [INSTR_RRS_RRRDU] = { 0xff, R_8,R_12,U4_32,D_20,B_16,0 },
-       [INSTR_RR_FF]     = { 0xff, F_8,F_12,0,0,0,0 },
-       [INSTR_RR_R0]     = { 0xff, R_8, 0,0,0,0,0 },
-       [INSTR_RR_RR]     = { 0xff, R_8,R_12,0,0,0,0 },
-       [INSTR_RR_U0]     = { 0xff, U8_8, 0,0,0,0,0 },
-       [INSTR_RR_UR]     = { 0xff, U4_8,R_12,0,0,0,0 },
-       [INSTR_RSE_CCRD]  = { 0xff, C_8,C_12,D_20,B_16,0,0 },
-       [INSTR_RSE_RRRD]  = { 0xff, R_8,R_12,D_20,B_16,0,0 },
-       [INSTR_RSE_RURD]  = { 0xff, R_8,U4_12,D_20,B_16,0,0 },
-       [INSTR_RSI_RRP]   = { 0xff, R_8,R_12,J16_16,0,0,0 },
-       [INSTR_RSL_LRDFU] = { 0xff, F_32,D_20,L4_8,B_16,U4_36,0 },
-       [INSTR_RSL_R0RD]  = { 0xff, D_20,L4_8,B_16,0,0,0 },
-       [INSTR_RSY_AARD]  = { 0xff, A_8,A_12,D20_20,B_16,0,0 },
-       [INSTR_RSY_CCRD]  = { 0xff, C_8,C_12,D20_20,B_16,0,0 },
-       [INSTR_RSY_RDRM]  = { 0xff, R_8,D20_20,B_16,U4_12,0,0 },
-       [INSTR_RSY_RMRD]  = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
-       [INSTR_RSY_RRRD]  = { 0xff, R_8,R_12,D20_20,B_16,0,0 },
-       [INSTR_RSY_RURD]  = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
-       [INSTR_RS_AARD]   = { 0xff, A_8,A_12,D_20,B_16,0,0 },
-       [INSTR_RS_CCRD]   = { 0xff, C_8,C_12,D_20,B_16,0,0 },
-       [INSTR_RS_R0RD]   = { 0xff, R_8,D_20,B_16,0,0,0 },
-       [INSTR_RS_RRRD]   = { 0xff, R_8,R_12,D_20,B_16,0,0 },
-       [INSTR_RS_RURD]   = { 0xff, R_8,U4_12,D_20,B_16,0,0 },
-       [INSTR_RXE_FRRD]  = { 0xff, F_8,D_20,X_12,B_16,0,0 },
-       [INSTR_RXE_RRRD]  = { 0xff, R_8,D_20,X_12,B_16,0,0 },
-       [INSTR_RXE_RRRDM] = { 0xff, R_8,D_20,X_12,B_16,M_32,0 },
-       [INSTR_RXF_FRRDF] = { 0xff, F_32,F_8,D_20,X_12,B_16,0 },
-       [INSTR_RXY_FRRD]  = { 0xff, F_8,D20_20,X_12,B_16,0,0 },
-       [INSTR_RXY_RRRD]  = { 0xff, R_8,D20_20,X_12,B_16,0,0 },
-       [INSTR_RXY_URRD]  = { 0xff, U4_8,D20_20,X_12,B_16,0,0 },
-       [INSTR_RX_FRRD]   = { 0xff, F_8,D_20,X_12,B_16,0,0 },
-       [INSTR_RX_RRRD]   = { 0xff, R_8,D_20,X_12,B_16,0,0 },
-       [INSTR_RX_URRD]   = { 0xff, U4_8,D_20,X_12,B_16,0,0 },
-       [INSTR_SIL_RDI]   = { 0xff, D_20,B_16,I16_32,0,0,0 },
-       [INSTR_SIL_RDU]   = { 0xff, D_20,B_16,U16_32,0,0,0 },
-       [INSTR_SIY_IRD]   = { 0xff, D20_20,B_16,I8_8,0,0,0 },
-       [INSTR_SIY_URD]   = { 0xff, D20_20,B_16,U8_8,0,0,0 },
-       [INSTR_SI_URD]    = { 0xff, D_20,B_16,U8_8,0,0,0 },
-       [INSTR_SMI_U0RDP] = { 0xff, U4_8,J16_32,D_20,B_16,0,0 },
-       [INSTR_SSE_RDRD]  = { 0xff, D_20,B_16,D_36,B_32,0,0 },
-       [INSTR_SSF_RRDRD] = { 0x0f, D_20,B_16,D_36,B_32,R_8,0 },
-       [INSTR_SSF_RRDRD2]= { 0x0f, R_8,D_20,B_16,D_36,B_32,0 },
-       [INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 },
-       [INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 },
-       [INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 },
-       [INSTR_SS_RRRDRD2]= { 0xff, R_8,D_20,B_16,R_12,D_36,B_32 },
-       [INSTR_SS_RRRDRD3]= { 0xff, R_8,R_12,D_20,B_16,D_36,B_32 },
-       [INSTR_SS_RRRDRD] = { 0xff, D_20,R_8,B_16,D_36,B_32,R_12 },
-       [INSTR_S_00]      = { 0xff, 0,0,0,0,0,0 },
-       [INSTR_S_RD]      = { 0xff, D_20,B_16,0,0,0,0 },
-       [INSTR_VRI_V0IM]  = { 0xff, V_8,I16_16,M_32,0,0,0 },
-       [INSTR_VRI_V0I0]  = { 0xff, V_8,I16_16,0,0,0,0 },
-       [INSTR_VRI_V0IIM] = { 0xff, V_8,I8_16,I8_24,M_32,0,0 },
-       [INSTR_VRI_VVIM]  = { 0xff, V_8,I16_16,V_12,M_32,0,0 },
-       [INSTR_VRI_VVV0IM]= { 0xff, V_8,V_12,V_16,I8_24,M_32,0 },
-       [INSTR_VRI_VVV0I0]= { 0xff, V_8,V_12,V_16,I8_24,0,0 },
-       [INSTR_VRI_VVIMM] = { 0xff, V_8,V_12,I16_16,M_32,M_28,0 },
-       [INSTR_VRR_VV00MMM]={ 0xff, V_8,V_12,M_32,M_28,M_24,0 },
-       [INSTR_VRR_VV000MM]={ 0xff, V_8,V_12,M_32,M_28,0,0 },
-       [INSTR_VRR_VV0000M]={ 0xff, V_8,V_12,M_32,0,0,0 },
-       [INSTR_VRR_VV00000]={ 0xff, V_8,V_12,0,0,0,0 },
-       [INSTR_VRR_VVV0M0M]={ 0xff, V_8,V_12,V_16,M_32,M_24,0 },
-       [INSTR_VRR_VV00M0M]={ 0xff, V_8,V_12,M_32,M_24,0,0 },
-       [INSTR_VRR_VVV000M]={ 0xff, V_8,V_12,V_16,M_32,0,0 },
-       [INSTR_VRR_VVV000V]={ 0xff, V_8,V_12,V_16,V_32,0,0 },
-       [INSTR_VRR_VVV0000]={ 0xff, V_8,V_12,V_16,0,0,0 },
-       [INSTR_VRR_VVV0MMM]={ 0xff, V_8,V_12,V_16,M_32,M_28,M_24 },
-       [INSTR_VRR_VVV00MM]={ 0xff, V_8,V_12,V_16,M_32,M_28,0 },
-       [INSTR_VRR_VVVMM0V]={ 0xff, V_8,V_12,V_16,V_32,M_20,M_24 },
-       [INSTR_VRR_VVVM0MV]={ 0xff, V_8,V_12,V_16,V_32,M_28,M_20 },
-       [INSTR_VRR_VVVM00V]={ 0xff, V_8,V_12,V_16,V_32,M_20,0 },
-       [INSTR_VRR_VRR0000]={ 0xff, V_8,R_12,R_16,0,0,0 },
-       [INSTR_VRS_VVRDM] = { 0xff, V_8,V_12,D_20,B_16,M_32,0 },
-       [INSTR_VRS_VVRD0] = { 0xff, V_8,V_12,D_20,B_16,0,0 },
-       [INSTR_VRS_VRRDM] = { 0xff, V_8,R_12,D_20,B_16,M_32,0 },
-       [INSTR_VRS_VRRD0] = { 0xff, V_8,R_12,D_20,B_16,0,0 },
-       [INSTR_VRS_RVRDM] = { 0xff, R_8,V_12,D_20,B_16,M_32,0 },
-       [INSTR_VRV_VVRDM] = { 0xff, V_8,V_12,D_20,B_16,M_32,0 },
-       [INSTR_VRV_VWRDM] = { 0xff, V_8,D_20,W_12,B_16,M_32,0 },
-       [INSTR_VRX_VRRDM] = { 0xff, V_8,D_20,X_12,B_16,M_32,0 },
-       [INSTR_VRX_VRRD0] = { 0xff, V_8,D_20,X_12,B_16,0,0 },
-};
-
-enum {
-       LONG_INSN_ALGHSIK,
-       LONG_INSN_ALHHHR,
-       LONG_INSN_ALHHLR,
-       LONG_INSN_ALHSIK,
-       LONG_INSN_ALSIHN,
-       LONG_INSN_CDFBRA,
-       LONG_INSN_CDGBRA,
-       LONG_INSN_CDGTRA,
-       LONG_INSN_CDLFBR,
-       LONG_INSN_CDLFTR,
-       LONG_INSN_CDLGBR,
-       LONG_INSN_CDLGTR,
-       LONG_INSN_CEFBRA,
-       LONG_INSN_CEGBRA,
-       LONG_INSN_CELFBR,
-       LONG_INSN_CELGBR,
-       LONG_INSN_CFDBRA,
-       LONG_INSN_CFEBRA,
-       LONG_INSN_CFXBRA,
-       LONG_INSN_CGDBRA,
-       LONG_INSN_CGDTRA,
-       LONG_INSN_CGEBRA,
-       LONG_INSN_CGXBRA,
-       LONG_INSN_CGXTRA,
-       LONG_INSN_CLFDBR,
-       LONG_INSN_CLFDTR,
-       LONG_INSN_CLFEBR,
-       LONG_INSN_CLFHSI,
-       LONG_INSN_CLFXBR,
-       LONG_INSN_CLFXTR,
-       LONG_INSN_CLGDBR,
-       LONG_INSN_CLGDTR,
-       LONG_INSN_CLGEBR,
-       LONG_INSN_CLGFRL,
-       LONG_INSN_CLGHRL,
-       LONG_INSN_CLGHSI,
-       LONG_INSN_CLGXBR,
-       LONG_INSN_CLGXTR,
-       LONG_INSN_CLHHSI,
-       LONG_INSN_CXFBRA,
-       LONG_INSN_CXGBRA,
-       LONG_INSN_CXGTRA,
-       LONG_INSN_CXLFBR,
-       LONG_INSN_CXLFTR,
-       LONG_INSN_CXLGBR,
-       LONG_INSN_CXLGTR,
-       LONG_INSN_FIDBRA,
-       LONG_INSN_FIEBRA,
-       LONG_INSN_FIXBRA,
-       LONG_INSN_LDXBRA,
-       LONG_INSN_LEDBRA,
-       LONG_INSN_LEXBRA,
-       LONG_INSN_LLGFAT,
-       LONG_INSN_LLGFRL,
-       LONG_INSN_LLGHRL,
-       LONG_INSN_LLGTAT,
-       LONG_INSN_POPCNT,
-       LONG_INSN_RIEMIT,
-       LONG_INSN_RINEXT,
-       LONG_INSN_RISBGN,
-       LONG_INSN_RISBHG,
-       LONG_INSN_RISBLG,
-       LONG_INSN_SLHHHR,
-       LONG_INSN_SLHHLR,
-       LONG_INSN_TABORT,
-       LONG_INSN_TBEGIN,
-       LONG_INSN_TBEGINC,
-       LONG_INSN_PCISTG,
-       LONG_INSN_MPCIFC,
-       LONG_INSN_STPCIFC,
-       LONG_INSN_PCISTB,
-       LONG_INSN_VPOPCT,
-       LONG_INSN_VERLLV,
-       LONG_INSN_VESRAV,
-       LONG_INSN_VESRLV,
-       LONG_INSN_VSBCBI,
-       LONG_INSN_STCCTM
-};
-
-static char *long_insn_name[] = {
-       [LONG_INSN_ALGHSIK] = "alghsik",
-       [LONG_INSN_ALHHHR] = "alhhhr",
-       [LONG_INSN_ALHHLR] = "alhhlr",
-       [LONG_INSN_ALHSIK] = "alhsik",
-       [LONG_INSN_ALSIHN] = "alsihn",
-       [LONG_INSN_CDFBRA] = "cdfbra",
-       [LONG_INSN_CDGBRA] = "cdgbra",
-       [LONG_INSN_CDGTRA] = "cdgtra",
-       [LONG_INSN_CDLFBR] = "cdlfbr",
-       [LONG_INSN_CDLFTR] = "cdlftr",
-       [LONG_INSN_CDLGBR] = "cdlgbr",
-       [LONG_INSN_CDLGTR] = "cdlgtr",
-       [LONG_INSN_CEFBRA] = "cefbra",
-       [LONG_INSN_CEGBRA] = "cegbra",
-       [LONG_INSN_CELFBR] = "celfbr",
-       [LONG_INSN_CELGBR] = "celgbr",
-       [LONG_INSN_CFDBRA] = "cfdbra",
-       [LONG_INSN_CFEBRA] = "cfebra",
-       [LONG_INSN_CFXBRA] = "cfxbra",
-       [LONG_INSN_CGDBRA] = "cgdbra",
-       [LONG_INSN_CGDTRA] = "cgdtra",
-       [LONG_INSN_CGEBRA] = "cgebra",
-       [LONG_INSN_CGXBRA] = "cgxbra",
-       [LONG_INSN_CGXTRA] = "cgxtra",
-       [LONG_INSN_CLFDBR] = "clfdbr",
-       [LONG_INSN_CLFDTR] = "clfdtr",
-       [LONG_INSN_CLFEBR] = "clfebr",
-       [LONG_INSN_CLFHSI] = "clfhsi",
-       [LONG_INSN_CLFXBR] = "clfxbr",
-       [LONG_INSN_CLFXTR] = "clfxtr",
-       [LONG_INSN_CLGDBR] = "clgdbr",
-       [LONG_INSN_CLGDTR] = "clgdtr",
-       [LONG_INSN_CLGEBR] = "clgebr",
-       [LONG_INSN_CLGFRL] = "clgfrl",
-       [LONG_INSN_CLGHRL] = "clghrl",
-       [LONG_INSN_CLGHSI] = "clghsi",
-       [LONG_INSN_CLGXBR] = "clgxbr",
-       [LONG_INSN_CLGXTR] = "clgxtr",
-       [LONG_INSN_CLHHSI] = "clhhsi",
-       [LONG_INSN_CXFBRA] = "cxfbra",
-       [LONG_INSN_CXGBRA] = "cxgbra",
-       [LONG_INSN_CXGTRA] = "cxgtra",
-       [LONG_INSN_CXLFBR] = "cxlfbr",
-       [LONG_INSN_CXLFTR] = "cxlftr",
-       [LONG_INSN_CXLGBR] = "cxlgbr",
-       [LONG_INSN_CXLGTR] = "cxlgtr",
-       [LONG_INSN_FIDBRA] = "fidbra",
-       [LONG_INSN_FIEBRA] = "fiebra",
-       [LONG_INSN_FIXBRA] = "fixbra",
-       [LONG_INSN_LDXBRA] = "ldxbra",
-       [LONG_INSN_LEDBRA] = "ledbra",
-       [LONG_INSN_LEXBRA] = "lexbra",
-       [LONG_INSN_LLGFAT] = "llgfat",
-       [LONG_INSN_LLGFRL] = "llgfrl",
-       [LONG_INSN_LLGHRL] = "llghrl",
-       [LONG_INSN_LLGTAT] = "llgtat",
-       [LONG_INSN_POPCNT] = "popcnt",
-       [LONG_INSN_RIEMIT] = "riemit",
-       [LONG_INSN_RINEXT] = "rinext",
-       [LONG_INSN_RISBGN] = "risbgn",
-       [LONG_INSN_RISBHG] = "risbhg",
-       [LONG_INSN_RISBLG] = "risblg",
-       [LONG_INSN_SLHHHR] = "slhhhr",
-       [LONG_INSN_SLHHLR] = "slhhlr",
-       [LONG_INSN_TABORT] = "tabort",
-       [LONG_INSN_TBEGIN] = "tbegin",
-       [LONG_INSN_TBEGINC] = "tbeginc",
-       [LONG_INSN_PCISTG] = "pcistg",
-       [LONG_INSN_MPCIFC] = "mpcifc",
-       [LONG_INSN_STPCIFC] = "stpcifc",
-       [LONG_INSN_PCISTB] = "pcistb",
-       [LONG_INSN_VPOPCT] = "vpopct",
-       [LONG_INSN_VERLLV] = "verllv",
-       [LONG_INSN_VESRAV] = "vesrav",
-       [LONG_INSN_VESRLV] = "vesrlv",
-       [LONG_INSN_VSBCBI] = "vsbcbi",
-       [LONG_INSN_STCCTM] = "stcctm",
-};
-
-static struct s390_insn opcode[] = {
-       { "bprp", 0xc5, INSTR_MII_UPI },
-       { "bpp", 0xc7, INSTR_SMI_U0RDP },
-       { "trtr", 0xd0, INSTR_SS_L0RDRD },
-       { "lmd", 0xef, INSTR_SS_RRRDRD3 },
-       { "spm", 0x04, INSTR_RR_R0 },
-       { "balr", 0x05, INSTR_RR_RR },
-       { "bctr", 0x06, INSTR_RR_RR },
-       { "bcr", 0x07, INSTR_RR_UR },
-       { "svc", 0x0a, INSTR_RR_U0 },
-       { "bsm", 0x0b, INSTR_RR_RR },
-       { "bassm", 0x0c, INSTR_RR_RR },
-       { "basr", 0x0d, INSTR_RR_RR },
-       { "mvcl", 0x0e, INSTR_RR_RR },
-       { "clcl", 0x0f, INSTR_RR_RR },
-       { "lpr", 0x10, INSTR_RR_RR },
-       { "lnr", 0x11, INSTR_RR_RR },
-       { "ltr", 0x12, INSTR_RR_RR },
-       { "lcr", 0x13, INSTR_RR_RR },
-       { "nr", 0x14, INSTR_RR_RR },
-       { "clr", 0x15, INSTR_RR_RR },
-       { "or", 0x16, INSTR_RR_RR },
-       { "xr", 0x17, INSTR_RR_RR },
-       { "lr", 0x18, INSTR_RR_RR },
-       { "cr", 0x19, INSTR_RR_RR },
-       { "ar", 0x1a, INSTR_RR_RR },
-       { "sr", 0x1b, INSTR_RR_RR },
-       { "mr", 0x1c, INSTR_RR_RR },
-       { "dr", 0x1d, INSTR_RR_RR },
-       { "alr", 0x1e, INSTR_RR_RR },
-       { "slr", 0x1f, INSTR_RR_RR },
-       { "lpdr", 0x20, INSTR_RR_FF },
-       { "lndr", 0x21, INSTR_RR_FF },
-       { "ltdr", 0x22, INSTR_RR_FF },
-       { "lcdr", 0x23, INSTR_RR_FF },
-       { "hdr", 0x24, INSTR_RR_FF },
-       { "ldxr", 0x25, INSTR_RR_FF },
-       { "mxr", 0x26, INSTR_RR_FF },
-       { "mxdr", 0x27, INSTR_RR_FF },
-       { "ldr", 0x28, INSTR_RR_FF },
-       { "cdr", 0x29, INSTR_RR_FF },
-       { "adr", 0x2a, INSTR_RR_FF },
-       { "sdr", 0x2b, INSTR_RR_FF },
-       { "mdr", 0x2c, INSTR_RR_FF },
-       { "ddr", 0x2d, INSTR_RR_FF },
-       { "awr", 0x2e, INSTR_RR_FF },
-       { "swr", 0x2f, INSTR_RR_FF },
-       { "lper", 0x30, INSTR_RR_FF },
-       { "lner", 0x31, INSTR_RR_FF },
-       { "lter", 0x32, INSTR_RR_FF },
-       { "lcer", 0x33, INSTR_RR_FF },
-       { "her", 0x34, INSTR_RR_FF },
-       { "ledr", 0x35, INSTR_RR_FF },
-       { "axr", 0x36, INSTR_RR_FF },
-       { "sxr", 0x37, INSTR_RR_FF },
-       { "ler", 0x38, INSTR_RR_FF },
-       { "cer", 0x39, INSTR_RR_FF },
-       { "aer", 0x3a, INSTR_RR_FF },
-       { "ser", 0x3b, INSTR_RR_FF },
-       { "mder", 0x3c, INSTR_RR_FF },
-       { "der", 0x3d, INSTR_RR_FF },
-       { "aur", 0x3e, INSTR_RR_FF },
-       { "sur", 0x3f, INSTR_RR_FF },
-       { "sth", 0x40, INSTR_RX_RRRD },
-       { "la", 0x41, INSTR_RX_RRRD },
-       { "stc", 0x42, INSTR_RX_RRRD },
-       { "ic", 0x43, INSTR_RX_RRRD },
-       { "ex", 0x44, INSTR_RX_RRRD },
-       { "bal", 0x45, INSTR_RX_RRRD },
-       { "bct", 0x46, INSTR_RX_RRRD },
-       { "bc", 0x47, INSTR_RX_URRD },
-       { "lh", 0x48, INSTR_RX_RRRD },
-       { "ch", 0x49, INSTR_RX_RRRD },
-       { "ah", 0x4a, INSTR_RX_RRRD },
-       { "sh", 0x4b, INSTR_RX_RRRD },
-       { "mh", 0x4c, INSTR_RX_RRRD },
-       { "bas", 0x4d, INSTR_RX_RRRD },
-       { "cvd", 0x4e, INSTR_RX_RRRD },
-       { "cvb", 0x4f, INSTR_RX_RRRD },
-       { "st", 0x50, INSTR_RX_RRRD },
-       { "lae", 0x51, INSTR_RX_RRRD },
-       { "n", 0x54, INSTR_RX_RRRD },
-       { "cl", 0x55, INSTR_RX_RRRD },
-       { "o", 0x56, INSTR_RX_RRRD },
-       { "x", 0x57, INSTR_RX_RRRD },
-       { "l", 0x58, INSTR_RX_RRRD },
-       { "c", 0x59, INSTR_RX_RRRD },
-       { "a", 0x5a, INSTR_RX_RRRD },
-       { "s", 0x5b, INSTR_RX_RRRD },
-       { "m", 0x5c, INSTR_RX_RRRD },
-       { "d", 0x5d, INSTR_RX_RRRD },
-       { "al", 0x5e, INSTR_RX_RRRD },
-       { "sl", 0x5f, INSTR_RX_RRRD },
-       { "std", 0x60, INSTR_RX_FRRD },
-       { "mxd", 0x67, INSTR_RX_FRRD },
-       { "ld", 0x68, INSTR_RX_FRRD },
-       { "cd", 0x69, INSTR_RX_FRRD },
-       { "ad", 0x6a, INSTR_RX_FRRD },
-       { "sd", 0x6b, INSTR_RX_FRRD },
-       { "md", 0x6c, INSTR_RX_FRRD },
-       { "dd", 0x6d, INSTR_RX_FRRD },
-       { "aw", 0x6e, INSTR_RX_FRRD },
-       { "sw", 0x6f, INSTR_RX_FRRD },
-       { "ste", 0x70, INSTR_RX_FRRD },
-       { "ms", 0x71, INSTR_RX_RRRD },
-       { "le", 0x78, INSTR_RX_FRRD },
-       { "ce", 0x79, INSTR_RX_FRRD },
-       { "ae", 0x7a, INSTR_RX_FRRD },
-       { "se", 0x7b, INSTR_RX_FRRD },
-       { "mde", 0x7c, INSTR_RX_FRRD },
-       { "de", 0x7d, INSTR_RX_FRRD },
-       { "au", 0x7e, INSTR_RX_FRRD },
-       { "su", 0x7f, INSTR_RX_FRRD },
-       { "ssm", 0x80, INSTR_S_RD },
-       { "lpsw", 0x82, INSTR_S_RD },
-       { "diag", 0x83, INSTR_RS_RRRD },
-       { "brxh", 0x84, INSTR_RSI_RRP },
-       { "brxle", 0x85, INSTR_RSI_RRP },
-       { "bxh", 0x86, INSTR_RS_RRRD },
-       { "bxle", 0x87, INSTR_RS_RRRD },
-       { "srl", 0x88, INSTR_RS_R0RD },
-       { "sll", 0x89, INSTR_RS_R0RD },
-       { "sra", 0x8a, INSTR_RS_R0RD },
-       { "sla", 0x8b, INSTR_RS_R0RD },
-       { "srdl", 0x8c, INSTR_RS_R0RD },
-       { "sldl", 0x8d, INSTR_RS_R0RD },
-       { "srda", 0x8e, INSTR_RS_R0RD },
-       { "slda", 0x8f, INSTR_RS_R0RD },
-       { "stm", 0x90, INSTR_RS_RRRD },
-       { "tm", 0x91, INSTR_SI_URD },
-       { "mvi", 0x92, INSTR_SI_URD },
-       { "ts", 0x93, INSTR_S_RD },
-       { "ni", 0x94, INSTR_SI_URD },
-       { "cli", 0x95, INSTR_SI_URD },
-       { "oi", 0x96, INSTR_SI_URD },
-       { "xi", 0x97, INSTR_SI_URD },
-       { "lm", 0x98, INSTR_RS_RRRD },
-       { "trace", 0x99, INSTR_RS_RRRD },
-       { "lam", 0x9a, INSTR_RS_AARD },
-       { "stam", 0x9b, INSTR_RS_AARD },
-       { "mvcle", 0xa8, INSTR_RS_RRRD },
-       { "clcle", 0xa9, INSTR_RS_RRRD },
-       { "stnsm", 0xac, INSTR_SI_URD },
-       { "stosm", 0xad, INSTR_SI_URD },
-       { "sigp", 0xae, INSTR_RS_RRRD },
-       { "mc", 0xaf, INSTR_SI_URD },
-       { "lra", 0xb1, INSTR_RX_RRRD },
-       { "stctl", 0xb6, INSTR_RS_CCRD },
-       { "lctl", 0xb7, INSTR_RS_CCRD },
-       { "cs", 0xba, INSTR_RS_RRRD },
-       { "cds", 0xbb, INSTR_RS_RRRD },
-       { "clm", 0xbd, INSTR_RS_RURD },
-       { "stcm", 0xbe, INSTR_RS_RURD },
-       { "icm", 0xbf, INSTR_RS_RURD },
-       { "mvn", 0xd1, INSTR_SS_L0RDRD },
-       { "mvc", 0xd2, INSTR_SS_L0RDRD },
-       { "mvz", 0xd3, INSTR_SS_L0RDRD },
-       { "nc", 0xd4, INSTR_SS_L0RDRD },
-       { "clc", 0xd5, INSTR_SS_L0RDRD },
-       { "oc", 0xd6, INSTR_SS_L0RDRD },
-       { "xc", 0xd7, INSTR_SS_L0RDRD },
-       { "mvck", 0xd9, INSTR_SS_RRRDRD },
-       { "mvcp", 0xda, INSTR_SS_RRRDRD },
-       { "mvcs", 0xdb, INSTR_SS_RRRDRD },
-       { "tr", 0xdc, INSTR_SS_L0RDRD },
-       { "trt", 0xdd, INSTR_SS_L0RDRD },
-       { "ed", 0xde, INSTR_SS_L0RDRD },
-       { "edmk", 0xdf, INSTR_SS_L0RDRD },
-       { "pku", 0xe1, INSTR_SS_L0RDRD },
-       { "unpku", 0xe2, INSTR_SS_L0RDRD },
-       { "mvcin", 0xe8, INSTR_SS_L0RDRD },
-       { "pka", 0xe9, INSTR_SS_L0RDRD },
-       { "unpka", 0xea, INSTR_SS_L0RDRD },
-       { "plo", 0xee, INSTR_SS_RRRDRD2 },
-       { "srp", 0xf0, INSTR_SS_LIRDRD },
-       { "mvo", 0xf1, INSTR_SS_LLRDRD },
-       { "pack", 0xf2, INSTR_SS_LLRDRD },
-       { "unpk", 0xf3, INSTR_SS_LLRDRD },
-       { "zap", 0xf8, INSTR_SS_LLRDRD },
-       { "cp", 0xf9, INSTR_SS_LLRDRD },
-       { "ap", 0xfa, INSTR_SS_LLRDRD },
-       { "sp", 0xfb, INSTR_SS_LLRDRD },
-       { "mp", 0xfc, INSTR_SS_LLRDRD },
-       { "dp", 0xfd, INSTR_SS_LLRDRD },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_01[] = {
-       { "ptff", 0x04, INSTR_E },
-       { "pfpo", 0x0a, INSTR_E },
-       { "sam64", 0x0e, INSTR_E },
-       { "pr", 0x01, INSTR_E },
-       { "upt", 0x02, INSTR_E },
-       { "sckpf", 0x07, INSTR_E },
-       { "tam", 0x0b, INSTR_E },
-       { "sam24", 0x0c, INSTR_E },
-       { "sam31", 0x0d, INSTR_E },
-       { "trap2", 0xff, INSTR_E },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_a5[] = {
-       { "iihh", 0x00, INSTR_RI_RU },
-       { "iihl", 0x01, INSTR_RI_RU },
-       { "iilh", 0x02, INSTR_RI_RU },
-       { "iill", 0x03, INSTR_RI_RU },
-       { "nihh", 0x04, INSTR_RI_RU },
-       { "nihl", 0x05, INSTR_RI_RU },
-       { "nilh", 0x06, INSTR_RI_RU },
-       { "nill", 0x07, INSTR_RI_RU },
-       { "oihh", 0x08, INSTR_RI_RU },
-       { "oihl", 0x09, INSTR_RI_RU },
-       { "oilh", 0x0a, INSTR_RI_RU },
-       { "oill", 0x0b, INSTR_RI_RU },
-       { "llihh", 0x0c, INSTR_RI_RU },
-       { "llihl", 0x0d, INSTR_RI_RU },
-       { "llilh", 0x0e, INSTR_RI_RU },
-       { "llill", 0x0f, INSTR_RI_RU },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_a7[] = {
-       { "tmhh", 0x02, INSTR_RI_RU },
-       { "tmhl", 0x03, INSTR_RI_RU },
-       { "brctg", 0x07, INSTR_RI_RP },
-       { "lghi", 0x09, INSTR_RI_RI },
-       { "aghi", 0x0b, INSTR_RI_RI },
-       { "mghi", 0x0d, INSTR_RI_RI },
-       { "cghi", 0x0f, INSTR_RI_RI },
-       { "tmlh", 0x00, INSTR_RI_RU },
-       { "tmll", 0x01, INSTR_RI_RU },
-       { "brc", 0x04, INSTR_RI_UP },
-       { "bras", 0x05, INSTR_RI_RP },
-       { "brct", 0x06, INSTR_RI_RP },
-       { "lhi", 0x08, INSTR_RI_RI },
-       { "ahi", 0x0a, INSTR_RI_RI },
-       { "mhi", 0x0c, INSTR_RI_RI },
-       { "chi", 0x0e, INSTR_RI_RI },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_aa[] = {
-       { { 0, LONG_INSN_RINEXT }, 0x00, INSTR_RI_RI },
-       { "rion", 0x01, INSTR_RI_RI },
-       { "tric", 0x02, INSTR_RI_RI },
-       { "rioff", 0x03, INSTR_RI_RI },
-       { { 0, LONG_INSN_RIEMIT }, 0x04, INSTR_RI_RI },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_b2[] = {
-       { "stckf", 0x7c, INSTR_S_RD },
-       { "lpp", 0x80, INSTR_S_RD },
-       { "lcctl", 0x84, INSTR_S_RD },
-       { "lpctl", 0x85, INSTR_S_RD },
-       { "qsi", 0x86, INSTR_S_RD },
-       { "lsctl", 0x87, INSTR_S_RD },
-       { "qctri", 0x8e, INSTR_S_RD },
-       { "stfle", 0xb0, INSTR_S_RD },
-       { "lpswe", 0xb2, INSTR_S_RD },
-       { "srnmb", 0xb8, INSTR_S_RD },
-       { "srnmt", 0xb9, INSTR_S_RD },
-       { "lfas", 0xbd, INSTR_S_RD },
-       { "scctr", 0xe0, INSTR_RRE_RR },
-       { "spctr", 0xe1, INSTR_RRE_RR },
-       { "ecctr", 0xe4, INSTR_RRE_RR },
-       { "epctr", 0xe5, INSTR_RRE_RR },
-       { "ppa", 0xe8, INSTR_RRF_U0RR },
-       { "etnd", 0xec, INSTR_RRE_R0 },
-       { "ecpga", 0xed, INSTR_RRE_RR },
-       { "tend", 0xf8, INSTR_S_00 },
-       { "niai", 0xfa, INSTR_IE_UU },
-       { { 0, LONG_INSN_TABORT }, 0xfc, INSTR_S_RD },
-       { "stidp", 0x02, INSTR_S_RD },
-       { "sck", 0x04, INSTR_S_RD },
-       { "stck", 0x05, INSTR_S_RD },
-       { "sckc", 0x06, INSTR_S_RD },
-       { "stckc", 0x07, INSTR_S_RD },
-       { "spt", 0x08, INSTR_S_RD },
-       { "stpt", 0x09, INSTR_S_RD },
-       { "spka", 0x0a, INSTR_S_RD },
-       { "ipk", 0x0b, INSTR_S_00 },
-       { "ptlb", 0x0d, INSTR_S_00 },
-       { "spx", 0x10, INSTR_S_RD },
-       { "stpx", 0x11, INSTR_S_RD },
-       { "stap", 0x12, INSTR_S_RD },
-       { "sie", 0x14, INSTR_S_RD },
-       { "pc", 0x18, INSTR_S_RD },
-       { "sac", 0x19, INSTR_S_RD },
-       { "cfc", 0x1a, INSTR_S_RD },
-       { "servc", 0x20, INSTR_RRE_RR },
-       { "ipte", 0x21, INSTR_RRE_RR },
-       { "ipm", 0x22, INSTR_RRE_R0 },
-       { "ivsk", 0x23, INSTR_RRE_RR },
-       { "iac", 0x24, INSTR_RRE_R0 },
-       { "ssar", 0x25, INSTR_RRE_R0 },
-       { "epar", 0x26, INSTR_RRE_R0 },
-       { "esar", 0x27, INSTR_RRE_R0 },
-       { "pt", 0x28, INSTR_RRE_RR },
-       { "iske", 0x29, INSTR_RRE_RR },
-       { "rrbe", 0x2a, INSTR_RRE_RR },
-       { "sske", 0x2b, INSTR_RRF_M0RR },
-       { "tb", 0x2c, INSTR_RRE_0R },
-       { "dxr", 0x2d, INSTR_RRE_FF },
-       { "pgin", 0x2e, INSTR_RRE_RR },
-       { "pgout", 0x2f, INSTR_RRE_RR },
-       { "csch", 0x30, INSTR_S_00 },
-       { "hsch", 0x31, INSTR_S_00 },
-       { "msch", 0x32, INSTR_S_RD },
-       { "ssch", 0x33, INSTR_S_RD },
-       { "stsch", 0x34, INSTR_S_RD },
-       { "tsch", 0x35, INSTR_S_RD },
-       { "tpi", 0x36, INSTR_S_RD },
-       { "sal", 0x37, INSTR_S_00 },
-       { "rsch", 0x38, INSTR_S_00 },
-       { "stcrw", 0x39, INSTR_S_RD },
-       { "stcps", 0x3a, INSTR_S_RD },
-       { "rchp", 0x3b, INSTR_S_00 },
-       { "schm", 0x3c, INSTR_S_00 },
-       { "bakr", 0x40, INSTR_RRE_RR },
-       { "cksm", 0x41, INSTR_RRE_RR },
-       { "sqdr", 0x44, INSTR_RRE_FF },
-       { "sqer", 0x45, INSTR_RRE_FF },
-       { "stura", 0x46, INSTR_RRE_RR },
-       { "msta", 0x47, INSTR_RRE_R0 },
-       { "palb", 0x48, INSTR_RRE_00 },
-       { "ereg", 0x49, INSTR_RRE_RR },
-       { "esta", 0x4a, INSTR_RRE_RR },
-       { "lura", 0x4b, INSTR_RRE_RR },
-       { "tar", 0x4c, INSTR_RRE_AR },
-       { "cpya", 0x4d, INSTR_RRE_AA },
-       { "sar", 0x4e, INSTR_RRE_AR },
-       { "ear", 0x4f, INSTR_RRE_RA },
-       { "csp", 0x50, INSTR_RRE_RR },
-       { "msr", 0x52, INSTR_RRE_RR },
-       { "mvpg", 0x54, INSTR_RRE_RR },
-       { "mvst", 0x55, INSTR_RRE_RR },
-       { "cuse", 0x57, INSTR_RRE_RR },
-       { "bsg", 0x58, INSTR_RRE_RR },
-       { "bsa", 0x5a, INSTR_RRE_RR },
-       { "clst", 0x5d, INSTR_RRE_RR },
-       { "srst", 0x5e, INSTR_RRE_RR },
-       { "cmpsc", 0x63, INSTR_RRE_RR },
-       { "siga", 0x74, INSTR_S_RD },
-       { "xsch", 0x76, INSTR_S_00 },
-       { "rp", 0x77, INSTR_S_RD },
-       { "stcke", 0x78, INSTR_S_RD },
-       { "sacf", 0x79, INSTR_S_RD },
-       { "stsi", 0x7d, INSTR_S_RD },
-       { "srnm", 0x99, INSTR_S_RD },
-       { "stfpc", 0x9c, INSTR_S_RD },
-       { "lfpc", 0x9d, INSTR_S_RD },
-       { "tre", 0xa5, INSTR_RRE_RR },
-       { "cuutf", 0xa6, INSTR_RRF_M0RR },
-       { "cutfu", 0xa7, INSTR_RRF_M0RR },
-       { "stfl", 0xb1, INSTR_S_RD },
-       { "trap4", 0xff, INSTR_S_RD },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_b3[] = {
-       { "maylr", 0x38, INSTR_RRF_F0FF },
-       { "mylr", 0x39, INSTR_RRF_F0FF },
-       { "mayr", 0x3a, INSTR_RRF_F0FF },
-       { "myr", 0x3b, INSTR_RRF_F0FF },
-       { "mayhr", 0x3c, INSTR_RRF_F0FF },
-       { "myhr", 0x3d, INSTR_RRF_F0FF },
-       { "lpdfr", 0x70, INSTR_RRE_FF },
-       { "lndfr", 0x71, INSTR_RRE_FF },
-       { "cpsdr", 0x72, INSTR_RRF_F0FF2 },
-       { "lcdfr", 0x73, INSTR_RRE_FF },
-       { "sfasr", 0x85, INSTR_RRE_R0 },
-       { { 0, LONG_INSN_CELFBR }, 0x90, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CDLFBR }, 0x91, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CXLFBR }, 0x92, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CEFBRA }, 0x94, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CDFBRA }, 0x95, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CXFBRA }, 0x96, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CFEBRA }, 0x98, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CFDBRA }, 0x99, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CFXBRA }, 0x9a, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CLFEBR }, 0x9c, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CLFDBR }, 0x9d, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CLFXBR }, 0x9e, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CELGBR }, 0xa0, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CDLGBR }, 0xa1, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CXLGBR }, 0xa2, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CEGBRA }, 0xa4, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CDGBRA }, 0xa5, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CXGBRA }, 0xa6, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CGEBRA }, 0xa8, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CGDBRA }, 0xa9, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CGXBRA }, 0xaa, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CLGEBR }, 0xac, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CLGDBR }, 0xad, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CLGXBR }, 0xae, INSTR_RRF_UUFR },
-       { "ldgr", 0xc1, INSTR_RRE_FR },
-       { "cegr", 0xc4, INSTR_RRE_FR },
-       { "cdgr", 0xc5, INSTR_RRE_FR },
-       { "cxgr", 0xc6, INSTR_RRE_FR },
-       { "cger", 0xc8, INSTR_RRF_U0RF },
-       { "cgdr", 0xc9, INSTR_RRF_U0RF },
-       { "cgxr", 0xca, INSTR_RRF_U0RF },
-       { "lgdr", 0xcd, INSTR_RRE_RF },
-       { "mdtra", 0xd0, INSTR_RRF_FUFF2 },
-       { "ddtra", 0xd1, INSTR_RRF_FUFF2 },
-       { "adtra", 0xd2, INSTR_RRF_FUFF2 },
-       { "sdtra", 0xd3, INSTR_RRF_FUFF2 },
-       { "ldetr", 0xd4, INSTR_RRF_0UFF },
-       { "ledtr", 0xd5, INSTR_RRF_UUFF },
-       { "ltdtr", 0xd6, INSTR_RRE_FF },
-       { "fidtr", 0xd7, INSTR_RRF_UUFF },
-       { "mxtra", 0xd8, INSTR_RRF_FUFF2 },
-       { "dxtra", 0xd9, INSTR_RRF_FUFF2 },
-       { "axtra", 0xda, INSTR_RRF_FUFF2 },
-       { "sxtra", 0xdb, INSTR_RRF_FUFF2 },
-       { "lxdtr", 0xdc, INSTR_RRF_0UFF },
-       { "ldxtr", 0xdd, INSTR_RRF_UUFF },
-       { "ltxtr", 0xde, INSTR_RRE_FF },
-       { "fixtr", 0xdf, INSTR_RRF_UUFF },
-       { "kdtr", 0xe0, INSTR_RRE_FF },
-       { { 0, LONG_INSN_CGDTRA }, 0xe1, INSTR_RRF_UURF },
-       { "cudtr", 0xe2, INSTR_RRE_RF },
-       { "csdtr", 0xe3, INSTR_RRE_RF },
-       { "cdtr", 0xe4, INSTR_RRE_FF },
-       { "eedtr", 0xe5, INSTR_RRE_RF },
-       { "esdtr", 0xe7, INSTR_RRE_RF },
-       { "kxtr", 0xe8, INSTR_RRE_FF },
-       { { 0, LONG_INSN_CGXTRA }, 0xe9, INSTR_RRF_UUFR },
-       { "cuxtr", 0xea, INSTR_RRE_RF },
-       { "csxtr", 0xeb, INSTR_RRE_RF },
-       { "cxtr", 0xec, INSTR_RRE_FF },
-       { "eextr", 0xed, INSTR_RRE_RF },
-       { "esxtr", 0xef, INSTR_RRE_RF },
-       { { 0, LONG_INSN_CDGTRA }, 0xf1, INSTR_RRF_UUFR },
-       { "cdutr", 0xf2, INSTR_RRE_FR },
-       { "cdstr", 0xf3, INSTR_RRE_FR },
-       { "cedtr", 0xf4, INSTR_RRE_FF },
-       { "qadtr", 0xf5, INSTR_RRF_FUFF },
-       { "iedtr", 0xf6, INSTR_RRF_F0FR },
-       { "rrdtr", 0xf7, INSTR_RRF_FFRU },
-       { { 0, LONG_INSN_CXGTRA }, 0xf9, INSTR_RRF_UURF },
-       { "cxutr", 0xfa, INSTR_RRE_FR },
-       { "cxstr", 0xfb, INSTR_RRE_FR },
-       { "cextr", 0xfc, INSTR_RRE_FF },
-       { "qaxtr", 0xfd, INSTR_RRF_FUFF },
-       { "iextr", 0xfe, INSTR_RRF_F0FR },
-       { "rrxtr", 0xff, INSTR_RRF_FFRU },
-       { "lpebr", 0x00, INSTR_RRE_FF },
-       { "lnebr", 0x01, INSTR_RRE_FF },
-       { "ltebr", 0x02, INSTR_RRE_FF },
-       { "lcebr", 0x03, INSTR_RRE_FF },
-       { "ldebr", 0x04, INSTR_RRE_FF },
-       { "lxdbr", 0x05, INSTR_RRE_FF },
-       { "lxebr", 0x06, INSTR_RRE_FF },
-       { "mxdbr", 0x07, INSTR_RRE_FF },
-       { "kebr", 0x08, INSTR_RRE_FF },
-       { "cebr", 0x09, INSTR_RRE_FF },
-       { "aebr", 0x0a, INSTR_RRE_FF },
-       { "sebr", 0x0b, INSTR_RRE_FF },
-       { "mdebr", 0x0c, INSTR_RRE_FF },
-       { "debr", 0x0d, INSTR_RRE_FF },
-       { "maebr", 0x0e, INSTR_RRF_F0FF },
-       { "msebr", 0x0f, INSTR_RRF_F0FF },
-       { "lpdbr", 0x10, INSTR_RRE_FF },
-       { "lndbr", 0x11, INSTR_RRE_FF },
-       { "ltdbr", 0x12, INSTR_RRE_FF },
-       { "lcdbr", 0x13, INSTR_RRE_FF },
-       { "sqebr", 0x14, INSTR_RRE_FF },
-       { "sqdbr", 0x15, INSTR_RRE_FF },
-       { "sqxbr", 0x16, INSTR_RRE_FF },
-       { "meebr", 0x17, INSTR_RRE_FF },
-       { "kdbr", 0x18, INSTR_RRE_FF },
-       { "cdbr", 0x19, INSTR_RRE_FF },
-       { "adbr", 0x1a, INSTR_RRE_FF },
-       { "sdbr", 0x1b, INSTR_RRE_FF },
-       { "mdbr", 0x1c, INSTR_RRE_FF },
-       { "ddbr", 0x1d, INSTR_RRE_FF },
-       { "madbr", 0x1e, INSTR_RRF_F0FF },
-       { "msdbr", 0x1f, INSTR_RRF_F0FF },
-       { "lder", 0x24, INSTR_RRE_FF },
-       { "lxdr", 0x25, INSTR_RRE_FF },
-       { "lxer", 0x26, INSTR_RRE_FF },
-       { "maer", 0x2e, INSTR_RRF_F0FF },
-       { "mser", 0x2f, INSTR_RRF_F0FF },
-       { "sqxr", 0x36, INSTR_RRE_FF },
-       { "meer", 0x37, INSTR_RRE_FF },
-       { "madr", 0x3e, INSTR_RRF_F0FF },
-       { "msdr", 0x3f, INSTR_RRF_F0FF },
-       { "lpxbr", 0x40, INSTR_RRE_FF },
-       { "lnxbr", 0x41, INSTR_RRE_FF },
-       { "ltxbr", 0x42, INSTR_RRE_FF },
-       { "lcxbr", 0x43, INSTR_RRE_FF },
-       { { 0, LONG_INSN_LEDBRA }, 0x44, INSTR_RRF_UUFF },
-       { { 0, LONG_INSN_LDXBRA }, 0x45, INSTR_RRF_UUFF },
-       { { 0, LONG_INSN_LEXBRA }, 0x46, INSTR_RRF_UUFF },
-       { { 0, LONG_INSN_FIXBRA }, 0x47, INSTR_RRF_UUFF },
-       { "kxbr", 0x48, INSTR_RRE_FF },
-       { "cxbr", 0x49, INSTR_RRE_FF },
-       { "axbr", 0x4a, INSTR_RRE_FF },
-       { "sxbr", 0x4b, INSTR_RRE_FF },
-       { "mxbr", 0x4c, INSTR_RRE_FF },
-       { "dxbr", 0x4d, INSTR_RRE_FF },
-       { "tbedr", 0x50, INSTR_RRF_U0FF },
-       { "tbdr", 0x51, INSTR_RRF_U0FF },
-       { "diebr", 0x53, INSTR_RRF_FUFF },
-       { { 0, LONG_INSN_FIEBRA }, 0x57, INSTR_RRF_UUFF },
-       { "thder", 0x58, INSTR_RRE_FF },
-       { "thdr", 0x59, INSTR_RRE_FF },
-       { "didbr", 0x5b, INSTR_RRF_FUFF },
-       { { 0, LONG_INSN_FIDBRA }, 0x5f, INSTR_RRF_UUFF },
-       { "lpxr", 0x60, INSTR_RRE_FF },
-       { "lnxr", 0x61, INSTR_RRE_FF },
-       { "ltxr", 0x62, INSTR_RRE_FF },
-       { "lcxr", 0x63, INSTR_RRE_FF },
-       { "lxr", 0x65, INSTR_RRE_FF },
-       { "lexr", 0x66, INSTR_RRE_FF },
-       { "fixr", 0x67, INSTR_RRE_FF },
-       { "cxr", 0x69, INSTR_RRE_FF },
-       { "lzer", 0x74, INSTR_RRE_F0 },
-       { "lzdr", 0x75, INSTR_RRE_F0 },
-       { "lzxr", 0x76, INSTR_RRE_F0 },
-       { "fier", 0x77, INSTR_RRE_FF },
-       { "fidr", 0x7f, INSTR_RRE_FF },
-       { "sfpc", 0x84, INSTR_RRE_RR_OPT },
-       { "efpc", 0x8c, INSTR_RRE_RR_OPT },
-       { "cefbr", 0x94, INSTR_RRE_RF },
-       { "cdfbr", 0x95, INSTR_RRE_RF },
-       { "cxfbr", 0x96, INSTR_RRE_RF },
-       { "cfebr", 0x98, INSTR_RRF_U0RF },
-       { "cfdbr", 0x99, INSTR_RRF_U0RF },
-       { "cfxbr", 0x9a, INSTR_RRF_U0RF },
-       { "cefr", 0xb4, INSTR_RRE_FR },
-       { "cdfr", 0xb5, INSTR_RRE_FR },
-       { "cxfr", 0xb6, INSTR_RRE_FR },
-       { "cfer", 0xb8, INSTR_RRF_U0RF },
-       { "cfdr", 0xb9, INSTR_RRF_U0RF },
-       { "cfxr", 0xba, INSTR_RRF_U0RF },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_b9[] = {
-       { "lpgr", 0x00, INSTR_RRE_RR },
-       { "lngr", 0x01, INSTR_RRE_RR },
-       { "ltgr", 0x02, INSTR_RRE_RR },
-       { "lcgr", 0x03, INSTR_RRE_RR },
-       { "lgr", 0x04, INSTR_RRE_RR },
-       { "lurag", 0x05, INSTR_RRE_RR },
-       { "lgbr", 0x06, INSTR_RRE_RR },
-       { "lghr", 0x07, INSTR_RRE_RR },
-       { "agr", 0x08, INSTR_RRE_RR },
-       { "sgr", 0x09, INSTR_RRE_RR },
-       { "algr", 0x0a, INSTR_RRE_RR },
-       { "slgr", 0x0b, INSTR_RRE_RR },
-       { "msgr", 0x0c, INSTR_RRE_RR },
-       { "dsgr", 0x0d, INSTR_RRE_RR },
-       { "eregg", 0x0e, INSTR_RRE_RR },
-       { "lrvgr", 0x0f, INSTR_RRE_RR },
-       { "lpgfr", 0x10, INSTR_RRE_RR },
-       { "lngfr", 0x11, INSTR_RRE_RR },
-       { "ltgfr", 0x12, INSTR_RRE_RR },
-       { "lcgfr", 0x13, INSTR_RRE_RR },
-       { "lgfr", 0x14, INSTR_RRE_RR },
-       { "llgfr", 0x16, INSTR_RRE_RR },
-       { "llgtr", 0x17, INSTR_RRE_RR },
-       { "agfr", 0x18, INSTR_RRE_RR },
-       { "sgfr", 0x19, INSTR_RRE_RR },
-       { "algfr", 0x1a, INSTR_RRE_RR },
-       { "slgfr", 0x1b, INSTR_RRE_RR },
-       { "msgfr", 0x1c, INSTR_RRE_RR },
-       { "dsgfr", 0x1d, INSTR_RRE_RR },
-       { "cgr", 0x20, INSTR_RRE_RR },
-       { "clgr", 0x21, INSTR_RRE_RR },
-       { "sturg", 0x25, INSTR_RRE_RR },
-       { "lbr", 0x26, INSTR_RRE_RR },
-       { "lhr", 0x27, INSTR_RRE_RR },
-       { "cgfr", 0x30, INSTR_RRE_RR },
-       { "clgfr", 0x31, INSTR_RRE_RR },
-       { "cfdtr", 0x41, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CLGDTR }, 0x42, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CLFDTR }, 0x43, INSTR_RRF_UURF },
-       { "bctgr", 0x46, INSTR_RRE_RR },
-       { "cfxtr", 0x49, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CLGXTR }, 0x4a, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CLFXTR }, 0x4b, INSTR_RRF_UUFR },
-       { "cdftr", 0x51, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CDLGTR }, 0x52, INSTR_RRF_UUFR },
-       { { 0, LONG_INSN_CDLFTR }, 0x53, INSTR_RRF_UUFR },
-       { "cxftr", 0x59, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CXLGTR }, 0x5a, INSTR_RRF_UURF },
-       { { 0, LONG_INSN_CXLFTR }, 0x5b, INSTR_RRF_UUFR },
-       { "cgrt", 0x60, INSTR_RRF_U0RR },
-       { "clgrt", 0x61, INSTR_RRF_U0RR },
-       { "crt", 0x72, INSTR_RRF_U0RR },
-       { "clrt", 0x73, INSTR_RRF_U0RR },
-       { "ngr", 0x80, INSTR_RRE_RR },
-       { "ogr", 0x81, INSTR_RRE_RR },
-       { "xgr", 0x82, INSTR_RRE_RR },
-       { "flogr", 0x83, INSTR_RRE_RR },
-       { "llgcr", 0x84, INSTR_RRE_RR },
-       { "llghr", 0x85, INSTR_RRE_RR },
-       { "mlgr", 0x86, INSTR_RRE_RR },
-       { "dlgr", 0x87, INSTR_RRE_RR },
-       { "alcgr", 0x88, INSTR_RRE_RR },
-       { "slbgr", 0x89, INSTR_RRE_RR },
-       { "cspg", 0x8a, INSTR_RRE_RR },
-       { "idte", 0x8e, INSTR_RRF_R0RR },
-       { "crdte", 0x8f, INSTR_RRF_RMRR },
-       { "llcr", 0x94, INSTR_RRE_RR },
-       { "llhr", 0x95, INSTR_RRE_RR },
-       { "esea", 0x9d, INSTR_RRE_R0 },
-       { "ptf", 0xa2, INSTR_RRE_R0 },
-       { "lptea", 0xaa, INSTR_RRF_RURR },
-       { "rrbm", 0xae, INSTR_RRE_RR },
-       { "pfmf", 0xaf, INSTR_RRE_RR },
-       { "cu14", 0xb0, INSTR_RRF_M0RR },
-       { "cu24", 0xb1, INSTR_RRF_M0RR },
-       { "cu41", 0xb2, INSTR_RRE_RR },
-       { "cu42", 0xb3, INSTR_RRE_RR },
-       { "trtre", 0xbd, INSTR_RRF_M0RR },
-       { "srstu", 0xbe, INSTR_RRE_RR },
-       { "trte", 0xbf, INSTR_RRF_M0RR },
-       { "ahhhr", 0xc8, INSTR_RRF_R0RR2 },
-       { "shhhr", 0xc9, INSTR_RRF_R0RR2 },
-       { { 0, LONG_INSN_ALHHHR }, 0xca, INSTR_RRF_R0RR2 },
-       { { 0, LONG_INSN_SLHHHR }, 0xcb, INSTR_RRF_R0RR2 },
-       { "chhr", 0xcd, INSTR_RRE_RR },
-       { "clhhr", 0xcf, INSTR_RRE_RR },
-       { { 0, LONG_INSN_PCISTG }, 0xd0, INSTR_RRE_RR },
-       { "pcilg", 0xd2, INSTR_RRE_RR },
-       { "rpcit", 0xd3, INSTR_RRE_RR },
-       { "ahhlr", 0xd8, INSTR_RRF_R0RR2 },
-       { "shhlr", 0xd9, INSTR_RRF_R0RR2 },
-       { { 0, LONG_INSN_ALHHLR }, 0xda, INSTR_RRF_R0RR2 },
-       { { 0, LONG_INSN_SLHHLR }, 0xdb, INSTR_RRF_R0RR2 },
-       { "chlr", 0xdd, INSTR_RRE_RR },
-       { "clhlr", 0xdf, INSTR_RRE_RR },
-       { { 0, LONG_INSN_POPCNT }, 0xe1, INSTR_RRE_RR },
-       { "locgr", 0xe2, INSTR_RRF_M0RR },
-       { "ngrk", 0xe4, INSTR_RRF_R0RR2 },
-       { "ogrk", 0xe6, INSTR_RRF_R0RR2 },
-       { "xgrk", 0xe7, INSTR_RRF_R0RR2 },
-       { "agrk", 0xe8, INSTR_RRF_R0RR2 },
-       { "sgrk", 0xe9, INSTR_RRF_R0RR2 },
-       { "algrk", 0xea, INSTR_RRF_R0RR2 },
-       { "slgrk", 0xeb, INSTR_RRF_R0RR2 },
-       { "locr", 0xf2, INSTR_RRF_M0RR },
-       { "nrk", 0xf4, INSTR_RRF_R0RR2 },
-       { "ork", 0xf6, INSTR_RRF_R0RR2 },
-       { "xrk", 0xf7, INSTR_RRF_R0RR2 },
-       { "ark", 0xf8, INSTR_RRF_R0RR2 },
-       { "srk", 0xf9, INSTR_RRF_R0RR2 },
-       { "alrk", 0xfa, INSTR_RRF_R0RR2 },
-       { "slrk", 0xfb, INSTR_RRF_R0RR2 },
-       { "kmac", 0x1e, INSTR_RRE_RR },
-       { "lrvr", 0x1f, INSTR_RRE_RR },
-       { "km", 0x2e, INSTR_RRE_RR },
-       { "kmc", 0x2f, INSTR_RRE_RR },
-       { "kimd", 0x3e, INSTR_RRE_RR },
-       { "klmd", 0x3f, INSTR_RRE_RR },
-       { "epsw", 0x8d, INSTR_RRE_RR },
-       { "trtt", 0x90, INSTR_RRF_M0RR },
-       { "trto", 0x91, INSTR_RRF_M0RR },
-       { "trot", 0x92, INSTR_RRF_M0RR },
-       { "troo", 0x93, INSTR_RRF_M0RR },
-       { "mlr", 0x96, INSTR_RRE_RR },
-       { "dlr", 0x97, INSTR_RRE_RR },
-       { "alcr", 0x98, INSTR_RRE_RR },
-       { "slbr", 0x99, INSTR_RRE_RR },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_c0[] = {
-       { "lgfi", 0x01, INSTR_RIL_RI },
-       { "xihf", 0x06, INSTR_RIL_RU },
-       { "xilf", 0x07, INSTR_RIL_RU },
-       { "iihf", 0x08, INSTR_RIL_RU },
-       { "iilf", 0x09, INSTR_RIL_RU },
-       { "nihf", 0x0a, INSTR_RIL_RU },
-       { "nilf", 0x0b, INSTR_RIL_RU },
-       { "oihf", 0x0c, INSTR_RIL_RU },
-       { "oilf", 0x0d, INSTR_RIL_RU },
-       { "llihf", 0x0e, INSTR_RIL_RU },
-       { "llilf", 0x0f, INSTR_RIL_RU },
-       { "larl", 0x00, INSTR_RIL_RP },
-       { "brcl", 0x04, INSTR_RIL_UP },
-       { "brasl", 0x05, INSTR_RIL_RP },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_c2[] = {
-       { "msgfi", 0x00, INSTR_RIL_RI },
-       { "msfi", 0x01, INSTR_RIL_RI },
-       { "slgfi", 0x04, INSTR_RIL_RU },
-       { "slfi", 0x05, INSTR_RIL_RU },
-       { "agfi", 0x08, INSTR_RIL_RI },
-       { "afi", 0x09, INSTR_RIL_RI },
-       { "algfi", 0x0a, INSTR_RIL_RU },
-       { "alfi", 0x0b, INSTR_RIL_RU },
-       { "cgfi", 0x0c, INSTR_RIL_RI },
-       { "cfi", 0x0d, INSTR_RIL_RI },
-       { "clgfi", 0x0e, INSTR_RIL_RU },
-       { "clfi", 0x0f, INSTR_RIL_RU },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_c4[] = {
-       { "llhrl", 0x02, INSTR_RIL_RP },
-       { "lghrl", 0x04, INSTR_RIL_RP },
-       { "lhrl", 0x05, INSTR_RIL_RP },
-       { { 0, LONG_INSN_LLGHRL }, 0x06, INSTR_RIL_RP },
-       { "sthrl", 0x07, INSTR_RIL_RP },
-       { "lgrl", 0x08, INSTR_RIL_RP },
-       { "stgrl", 0x0b, INSTR_RIL_RP },
-       { "lgfrl", 0x0c, INSTR_RIL_RP },
-       { "lrl", 0x0d, INSTR_RIL_RP },
-       { { 0, LONG_INSN_LLGFRL }, 0x0e, INSTR_RIL_RP },
-       { "strl", 0x0f, INSTR_RIL_RP },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_c6[] = {
-       { "exrl", 0x00, INSTR_RIL_RP },
-       { "pfdrl", 0x02, INSTR_RIL_UP },
-       { "cghrl", 0x04, INSTR_RIL_RP },
-       { "chrl", 0x05, INSTR_RIL_RP },
-       { { 0, LONG_INSN_CLGHRL }, 0x06, INSTR_RIL_RP },
-       { "clhrl", 0x07, INSTR_RIL_RP },
-       { "cgrl", 0x08, INSTR_RIL_RP },
-       { "clgrl", 0x0a, INSTR_RIL_RP },
-       { "cgfrl", 0x0c, INSTR_RIL_RP },
-       { "crl", 0x0d, INSTR_RIL_RP },
-       { { 0, LONG_INSN_CLGFRL }, 0x0e, INSTR_RIL_RP },
-       { "clrl", 0x0f, INSTR_RIL_RP },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_c8[] = {
-       { "mvcos", 0x00, INSTR_SSF_RRDRD },
-       { "ectg", 0x01, INSTR_SSF_RRDRD },
-       { "csst", 0x02, INSTR_SSF_RRDRD },
-       { "lpd", 0x04, INSTR_SSF_RRDRD2 },
-       { "lpdg", 0x05, INSTR_SSF_RRDRD2 },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_cc[] = {
-       { "brcth", 0x06, INSTR_RIL_RP },
-       { "aih", 0x08, INSTR_RIL_RI },
-       { "alsih", 0x0a, INSTR_RIL_RI },
-       { { 0, LONG_INSN_ALSIHN }, 0x0b, INSTR_RIL_RI },
-       { "cih", 0x0d, INSTR_RIL_RI },
-       { "clih", 0x0f, INSTR_RIL_RI },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_e3[] = {
-       { "ltg", 0x02, INSTR_RXY_RRRD },
-       { "lrag", 0x03, INSTR_RXY_RRRD },
-       { "lg", 0x04, INSTR_RXY_RRRD },
-       { "cvby", 0x06, INSTR_RXY_RRRD },
-       { "ag", 0x08, INSTR_RXY_RRRD },
-       { "sg", 0x09, INSTR_RXY_RRRD },
-       { "alg", 0x0a, INSTR_RXY_RRRD },
-       { "slg", 0x0b, INSTR_RXY_RRRD },
-       { "msg", 0x0c, INSTR_RXY_RRRD },
-       { "dsg", 0x0d, INSTR_RXY_RRRD },
-       { "cvbg", 0x0e, INSTR_RXY_RRRD },
-       { "lrvg", 0x0f, INSTR_RXY_RRRD },
-       { "lt", 0x12, INSTR_RXY_RRRD },
-       { "lray", 0x13, INSTR_RXY_RRRD },
-       { "lgf", 0x14, INSTR_RXY_RRRD },
-       { "lgh", 0x15, INSTR_RXY_RRRD },
-       { "llgf", 0x16, INSTR_RXY_RRRD },
-       { "llgt", 0x17, INSTR_RXY_RRRD },
-       { "agf", 0x18, INSTR_RXY_RRRD },
-       { "sgf", 0x19, INSTR_RXY_RRRD },
-       { "algf", 0x1a, INSTR_RXY_RRRD },
-       { "slgf", 0x1b, INSTR_RXY_RRRD },
-       { "msgf", 0x1c, INSTR_RXY_RRRD },
-       { "dsgf", 0x1d, INSTR_RXY_RRRD },
-       { "cg", 0x20, INSTR_RXY_RRRD },
-       { "clg", 0x21, INSTR_RXY_RRRD },
-       { "stg", 0x24, INSTR_RXY_RRRD },
-       { "ntstg", 0x25, INSTR_RXY_RRRD },
-       { "cvdy", 0x26, INSTR_RXY_RRRD },
-       { "cvdg", 0x2e, INSTR_RXY_RRRD },
-       { "strvg", 0x2f, INSTR_RXY_RRRD },
-       { "cgf", 0x30, INSTR_RXY_RRRD },
-       { "clgf", 0x31, INSTR_RXY_RRRD },
-       { "ltgf", 0x32, INSTR_RXY_RRRD },
-       { "cgh", 0x34, INSTR_RXY_RRRD },
-       { "pfd", 0x36, INSTR_RXY_URRD },
-       { "strvh", 0x3f, INSTR_RXY_RRRD },
-       { "bctg", 0x46, INSTR_RXY_RRRD },
-       { "sty", 0x50, INSTR_RXY_RRRD },
-       { "msy", 0x51, INSTR_RXY_RRRD },
-       { "ny", 0x54, INSTR_RXY_RRRD },
-       { "cly", 0x55, INSTR_RXY_RRRD },
-       { "oy", 0x56, INSTR_RXY_RRRD },
-       { "xy", 0x57, INSTR_RXY_RRRD },
-       { "ly", 0x58, INSTR_RXY_RRRD },
-       { "cy", 0x59, INSTR_RXY_RRRD },
-       { "ay", 0x5a, INSTR_RXY_RRRD },
-       { "sy", 0x5b, INSTR_RXY_RRRD },
-       { "mfy", 0x5c, INSTR_RXY_RRRD },
-       { "aly", 0x5e, INSTR_RXY_RRRD },
-       { "sly", 0x5f, INSTR_RXY_RRRD },
-       { "sthy", 0x70, INSTR_RXY_RRRD },
-       { "lay", 0x71, INSTR_RXY_RRRD },
-       { "stcy", 0x72, INSTR_RXY_RRRD },
-       { "icy", 0x73, INSTR_RXY_RRRD },
-       { "laey", 0x75, INSTR_RXY_RRRD },
-       { "lb", 0x76, INSTR_RXY_RRRD },
-       { "lgb", 0x77, INSTR_RXY_RRRD },
-       { "lhy", 0x78, INSTR_RXY_RRRD },
-       { "chy", 0x79, INSTR_RXY_RRRD },
-       { "ahy", 0x7a, INSTR_RXY_RRRD },
-       { "shy", 0x7b, INSTR_RXY_RRRD },
-       { "mhy", 0x7c, INSTR_RXY_RRRD },
-       { "ng", 0x80, INSTR_RXY_RRRD },
-       { "og", 0x81, INSTR_RXY_RRRD },
-       { "xg", 0x82, INSTR_RXY_RRRD },
-       { "lgat", 0x85, INSTR_RXY_RRRD },
-       { "mlg", 0x86, INSTR_RXY_RRRD },
-       { "dlg", 0x87, INSTR_RXY_RRRD },
-       { "alcg", 0x88, INSTR_RXY_RRRD },
-       { "slbg", 0x89, INSTR_RXY_RRRD },
-       { "stpq", 0x8e, INSTR_RXY_RRRD },
-       { "lpq", 0x8f, INSTR_RXY_RRRD },
-       { "llgc", 0x90, INSTR_RXY_RRRD },
-       { "llgh", 0x91, INSTR_RXY_RRRD },
-       { "llc", 0x94, INSTR_RXY_RRRD },
-       { "llh", 0x95, INSTR_RXY_RRRD },
-       { { 0, LONG_INSN_LLGTAT }, 0x9c, INSTR_RXY_RRRD },
-       { { 0, LONG_INSN_LLGFAT }, 0x9d, INSTR_RXY_RRRD },
-       { "lat", 0x9f, INSTR_RXY_RRRD },
-       { "lbh", 0xc0, INSTR_RXY_RRRD },
-       { "llch", 0xc2, INSTR_RXY_RRRD },
-       { "stch", 0xc3, INSTR_RXY_RRRD },
-       { "lhh", 0xc4, INSTR_RXY_RRRD },
-       { "llhh", 0xc6, INSTR_RXY_RRRD },
-       { "sthh", 0xc7, INSTR_RXY_RRRD },
-       { "lfhat", 0xc8, INSTR_RXY_RRRD },
-       { "lfh", 0xca, INSTR_RXY_RRRD },
-       { "stfh", 0xcb, INSTR_RXY_RRRD },
-       { "chf", 0xcd, INSTR_RXY_RRRD },
-       { "clhf", 0xcf, INSTR_RXY_RRRD },
-       { { 0, LONG_INSN_MPCIFC }, 0xd0, INSTR_RXY_RRRD },
-       { { 0, LONG_INSN_STPCIFC }, 0xd4, INSTR_RXY_RRRD },
-       { "lrv", 0x1e, INSTR_RXY_RRRD },
-       { "lrvh", 0x1f, INSTR_RXY_RRRD },
-       { "strv", 0x3e, INSTR_RXY_RRRD },
-       { "ml", 0x96, INSTR_RXY_RRRD },
-       { "dl", 0x97, INSTR_RXY_RRRD },
-       { "alc", 0x98, INSTR_RXY_RRRD },
-       { "slb", 0x99, INSTR_RXY_RRRD },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_e5[] = {
-       { "strag", 0x02, INSTR_SSE_RDRD },
-       { "mvhhi", 0x44, INSTR_SIL_RDI },
-       { "mvghi", 0x48, INSTR_SIL_RDI },
-       { "mvhi", 0x4c, INSTR_SIL_RDI },
-       { "chhsi", 0x54, INSTR_SIL_RDI },
-       { { 0, LONG_INSN_CLHHSI }, 0x55, INSTR_SIL_RDU },
-       { "cghsi", 0x58, INSTR_SIL_RDI },
-       { { 0, LONG_INSN_CLGHSI }, 0x59, INSTR_SIL_RDU },
-       { "chsi", 0x5c, INSTR_SIL_RDI },
-       { { 0, LONG_INSN_CLFHSI }, 0x5d, INSTR_SIL_RDU },
-       { { 0, LONG_INSN_TBEGIN }, 0x60, INSTR_SIL_RDU },
-       { { 0, LONG_INSN_TBEGINC }, 0x61, INSTR_SIL_RDU },
-       { "lasp", 0x00, INSTR_SSE_RDRD },
-       { "tprot", 0x01, INSTR_SSE_RDRD },
-       { "mvcsk", 0x0e, INSTR_SSE_RDRD },
-       { "mvcdk", 0x0f, INSTR_SSE_RDRD },
-       { "", 0, INSTR_INVALID }
-};
-
-static struct s390_insn opcode_e7[] = {
-       { "lcbb", 0x27, INSTR_RXE_RRRDM },
-       { "vgef", 0x13, INSTR_VRV_VVRDM },
-       { "vgeg", 0x12, INSTR_VRV_VVRDM },
-       { "vgbm", 0x44, INSTR_VRI_V0I0 },
-       { "vgm", 0x46, INSTR_VRI_V0IIM },
-       { "vl", 0x06, INSTR_VRX_VRRD0 },
-       { "vlr", 0x56, INSTR_VRR_VV00000 },
-       { "vlrp", 0x05, INSTR_VRX_VRRDM },
-       { "vleb", 0x00, INSTR_VRX_VRRDM },
-       { "vleh", 0x01, INSTR_VRX_VRRDM },
-       { "vlef", 0x03, INSTR_VRX_VRRDM },
-       { "vleg", 0x02, INSTR_VRX_VRRDM },
-       { "vleib", 0x40, INSTR_VRI_V0IM },
-       { "vleih", 0x41, INSTR_VRI_V0IM },
-       { "vleif", 0x43, INSTR_VRI_V0IM },
-       { "vleig", 0x42, INSTR_VRI_V0IM },
-       { "vlgv", 0x21, INSTR_VRS_RVRDM },
-       { "vllez", 0x04, INSTR_VRX_VRRDM },
-       { "vlm", 0x36, INSTR_VRS_VVRD0 },
-       { "vlbb", 0x07, INSTR_VRX_VRRDM },
-       { "vlvg", 0x22, INSTR_VRS_VRRDM },
-       { "vlvgp", 0x62, INSTR_VRR_VRR0000 },
-       { "vll", 0x37, INSTR_VRS_VRRD0 },
-       { "vmrh", 0x61, INSTR_VRR_VVV000M },
-       { "vmrl", 0x60, INSTR_VRR_VVV000M },
-       { "vpk", 0x94, INSTR_VRR_VVV000M },
-       { "vpks", 0x97, INSTR_VRR_VVV0M0M },
-       { "vpkls", 0x95, INSTR_VRR_VVV0M0M },
-       { "vperm", 0x8c, INSTR_VRR_VVV000V },
-       { "vpdi", 0x84, INSTR_VRR_VVV000M },
-       { "vrep", 0x4d, INSTR_VRI_VVIM },
-       { "vrepi", 0x45, INSTR_VRI_V0IM },
-       { "vscef", 0x1b, INSTR_VRV_VWRDM },
-       { "vsceg", 0x1a, INSTR_VRV_VWRDM },
-       { "vsel", 0x8d, INSTR_VRR_VVV000V },
-       { "vseg", 0x5f, INSTR_VRR_VV0000M },
-       { "vst", 0x0e, INSTR_VRX_VRRD0 },
-       { "vsteb", 0x08, INSTR_VRX_VRRDM },
-       { "vsteh", 0x09, INSTR_VRX_VRRDM },
-       { "vstef", 0x0b, INSTR_VRX_VRRDM },
-       { "vsteg", 0x0a, INSTR_VRX_VRRDM },
-       { "vstm", 0x3e, INSTR_VRS_VVRD0 },
-       { "vstl", 0x3f, INSTR_VRS_VRRD0 },
-       { "vuph", 0xd7, INSTR_VRR_VV0000M },
-       { "vuplh", 0xd5, INSTR_VRR_VV0000M },
-       { "vupl", 0xd6, INSTR_VRR_VV0000M },
-       { "vupll", 0xd4, INSTR_VRR_VV0000M },
-       { "va", 0xf3, INSTR_VRR_VVV000M },
-       { "vacc", 0xf1, INSTR_VRR_VVV000M },
-       { "vac", 0xbb, INSTR_VRR_VVVM00V },
-       { "vaccc", 0xb9, INSTR_VRR_VVVM00V },
-       { "vn", 0x68, INSTR_VRR_VVV0000 },
-       { "vnc", 0x69, INSTR_VRR_VVV0000 },
-       { "vavg", 0xf2, INSTR_VRR_VVV000M },
-       { "vavgl", 0xf0, INSTR_VRR_VVV000M },
-       { "vcksm", 0x66, INSTR_VRR_VVV0000 },
-       { "vec", 0xdb, INSTR_VRR_VV0000M },
-       { "vecl", 0xd9, INSTR_VRR_VV0000M },
-       { "vceq", 0xf8, INSTR_VRR_VVV0M0M },
-       { "vch", 0xfb, INSTR_VRR_VVV0M0M },
-       { "vchl", 0xf9, INSTR_VRR_VVV0M0M },
-       { "vclz", 0x53, INSTR_VRR_VV0000M },
-       { "vctz", 0x52, INSTR_VRR_VV0000M },
-       { "vx", 0x6d, INSTR_VRR_VVV0000 },
-       { "vgfm", 0xb4, INSTR_VRR_VVV000M },
-       { "vgfma", 0xbc, INSTR_VRR_VVVM00V },
-       { "vlc", 0xde, INSTR_VRR_VV0000M },
-       { "vlp", 0xdf, INSTR_VRR_VV0000M },
-       { "vmx", 0xff, INSTR_VRR_VVV000M },
-       { "vmxl", 0xfd, INSTR_VRR_VVV000M },
-       { "vmn", 0xfe, INSTR_VRR_VVV000M },
-       { "vmnl", 0xfc, INSTR_VRR_VVV000M },
-       { "vmal", 0xaa, INSTR_VRR_VVVM00V },
-       { "vmae", 0xae, INSTR_VRR_VVVM00V },
-       { "vmale", 0xac, INSTR_VRR_VVVM00V },
-       { "vmah", 0xab, INSTR_VRR_VVVM00V },
-       { "vmalh", 0xa9, INSTR_VRR_VVVM00V },
-       { "vmao", 0xaf, INSTR_VRR_VVVM00V },
-       { "vmalo", 0xad, INSTR_VRR_VVVM00V },
-       { "vmh", 0xa3, INSTR_VRR_VVV000M },
-       { "vmlh", 0xa1, INSTR_VRR_VVV000M },
-       { "vml", 0xa2, INSTR_VRR_VVV000M },
-       { "vme", 0xa6, INSTR_VRR_VVV000M },
-       { "vmle", 0xa4, INSTR_VRR_VVV000M },
-       { "vmo", 0xa7, INSTR_VRR_VVV000M },
-       { "vmlo", 0xa5, INSTR_VRR_VVV000M },
-       { "vno", 0x6b, INSTR_VRR_VVV0000 },
-       { "vo", 0x6a, INSTR_VRR_VVV0000 },
-       { { 0, LONG_INSN_VPOPCT }, 0x50, INSTR_VRR_VV0000M },
-       { { 0, LONG_INSN_VERLLV }, 0x73, INSTR_VRR_VVV000M },
-       { "verll", 0x33, INSTR_VRS_VVRDM },
-       { "verim", 0x72, INSTR_VRI_VVV0IM },
-       { "veslv", 0x70, INSTR_VRR_VVV000M },
-       { "vesl", 0x30, INSTR_VRS_VVRDM },
-       { { 0, LONG_INSN_VESRAV }, 0x7a, INSTR_VRR_VVV000M },
-       { "vesra", 0x3a, INSTR_VRS_VVRDM },
-       { { 0, LONG_INSN_VESRLV }, 0x78, INSTR_VRR_VVV000M },
-       { "vesrl", 0x38, INSTR_VRS_VVRDM },
-       { "vsl", 0x74, INSTR_VRR_VVV0000 },
-       { "vslb", 0x75, INSTR_VRR_VVV0000 },
-       { "vsldb", 0x77, INSTR_VRI_VVV0I0 },
-       { "vsra", 0x7e, INSTR_VRR_VVV0000 },
-       { "vsrab", 0x7f, INSTR_VRR_VVV0000 },
-       { "vsrl", 0x7c, INSTR_VRR_VVV0000 },
-       { "vsrlb", 0x7d, INSTR_VRR_VVV0000 },
-       { "vs", 0xf7, INSTR_VRR_VVV000M },
-       { "vscb", 0xf5, INSTR_VRR_VVV000M },
-       { "vsb", 0xbf, INSTR_VRR_VVVM00V },
-       { { 0, LONG_INSN_VSBCBI }, 0xbd, INSTR_VRR_VVVM00V },
-       { "vsumg", 0x65, INSTR_VRR_VVV000M },
-       { "vsumq", 0x67, INSTR_VRR_VVV000M },
-       { "vsum", 0x64, INSTR_VRR_VVV000M },
-       { "vtm", 0xd8, INSTR_VRR_VV00000 },
-       { "vfae", 0x82, INSTR_VRR_VVV0M0M },
-       { "vfee", 0x80, INSTR_VRR_VVV0M0M },
-       { "vfene", 0x81, INSTR_VRR_VVV0M0M },
-       { "vistr", 0x5c, INSTR_VRR_VV00M0M },
-       { "vstrc", 0x8a, INSTR_VRR_VVVMM0V },
-       { "vfa", 0xe3, INSTR_VRR_VVV00MM },
-       { "wfc", 0xcb, INSTR_VRR_VV000MM },
-       { "wfk", 0xca, INSTR_VRR_VV000MM },
-       { "vfce", 0xe8, INSTR_VRR_VVV0MMM },
-       { "vfch", 0xeb, INSTR_VRR_VVV0MMM },
-       { "vfche", 0xea, INSTR_VRR_VVV0MMM },
-       { "vcdg", 0xc3, INSTR_VRR_VV00MMM },
-       { "vcdlg", 0xc1, INSTR_VRR_VV00MMM },
-       { "vcgd", 0xc2, INSTR_VRR_VV00MMM },
-       { "vclgd", 0xc0, INSTR_VRR_VV00MMM },
-       { "vfd", 0xe5, INSTR_VRR_VVV00MM },
-       { "vfi", 0xc7, INSTR_VRR_VV00MMM },
-       { "vlde", 0xc4, INSTR_VRR_VV000MM },
-       { "vled", 0xc5, INSTR_VRR_VV00MMM },
-       { "vfm", 0xe7, INSTR_VRR_VVV00MM },
-       { "vfma", 0x8f, INSTR_VRR_VVVM0MV },
-       { "vfms", 0x8e, INSTR_VRR_VVVM0MV },
-       { "vfpso", 0xcc, INSTR_VRR_VV00MMM },
-       { "vfsq", 0xce, INSTR_VRR_VV000MM },
-       { "vfs", 0xe2, INSTR_VRR_VVV00MM },
-       { "vftci", 0x4a, INSTR_VRI_VVIMM },
-};
-
-static struct s390_insn opcode_eb[] = {
-       { "lmg", 0x04, INSTR_RSY_RRRD },
-       { "srag", 0x0a, INSTR_RSY_RRRD },
-       { "slag", 0x0b, INSTR_RSY_RRRD },
-       { "srlg", 0x0c, INSTR_RSY_RRRD },
-       { "sllg", 0x0d, INSTR_RSY_RRRD },
-       { "tracg", 0x0f, INSTR_RSY_RRRD },
-       { "csy", 0x14, INSTR_RSY_RRRD },
-       { "rllg", 0x1c, INSTR_RSY_RRRD },
-       { "clmh", 0x20, INSTR_RSY_RURD },
-       { "clmy", 0x21, INSTR_RSY_RURD },
-       { "clt", 0x23, INSTR_RSY_RURD },
-       { "stmg", 0x24, INSTR_RSY_RRRD },
-       { "stctg", 0x25, INSTR_RSY_CCRD },
-       { "stmh", 0x26, INSTR_RSY_RRRD },
-       { "clgt", 0x2b, INSTR_RSY_RURD },
-       { "stcmh", 0x2c, INSTR_RSY_RURD },
-       { "stcmy", 0x2d, INSTR_RSY_RURD },
-       { "lctlg", 0x2f, INSTR_RSY_CCRD },
-       { "csg", 0x30, INSTR_RSY_RRRD },
-       { "cdsy", 0x31, INSTR_RSY_RRRD },
-       { "cdsg", 0x3e, INSTR_RSY_RRRD },
-       { "bxhg", 0x44, INSTR_RSY_RRRD },
-       { "bxleg", 0x45, INSTR_RSY_RRRD },
-       { "ecag", 0x4c, INSTR_RSY_RRRD },
-       { "tmy", 0x51, INSTR_SIY_URD },
-       { "mviy", 0x52, INSTR_SIY_URD },
-       { "niy", 0x54, INSTR_SIY_URD },
-       { "cliy", 0x55, INSTR_SIY_URD },
-       { "oiy", 0x56, INSTR_SIY_URD },
-       { "xiy", 0x57, INSTR_SIY_URD },
-       { "asi", 0x6a, INSTR_SIY_IRD },
-       { "alsi", 0x6e, INSTR_SIY_IRD },
-       { "agsi", 0x7a, INSTR_SIY_IRD },
-       { "algsi", 0x7e, INSTR_SIY_IRD },
-       { "icmh", 0x80, INSTR_RSY_RURD },
-       { "icmy", 0x81, INSTR_RSY_RURD },
-       { "clclu", 0x8f, INSTR_RSY_RRRD },
-       { "stmy", 0x90, INSTR_RSY_RRRD },
-       { "lmh", 0x96, INSTR_RSY_RRRD },
-       { "lmy", 0x98, INSTR_RSY_RRRD },
-       { "lamy", 0x9a, INSTR_RSY_AARD },
-       { "stamy", 0x9b, INSTR_RSY_AARD },
-       { { 0, LONG_INSN_PCISTB }, 0xd0, INSTR_RSY_RRRD },
-       { "sic", 0xd1, INSTR_RSY_RRRD },
-       { "srak", 0xdc, INSTR_RSY_RRRD },
-       { "slak", 0xdd, INSTR_RSY_RRRD },
-       { "srlk", 0xde, INSTR_RSY_RRRD },
-       { "sllk", 0xdf, INSTR_RSY_RRRD },
-       { "locg", 0xe2, INSTR_RSY_RDRM },
-       { "stocg", 0xe3, INSTR_RSY_RDRM },
-       { "lang", 0xe4, INSTR_RSY_RRRD },
-       { "laog", 0xe6, INSTR_RSY_RRRD },
-       { "laxg", 0xe7, INSTR_RSY_RRRD },
-       { "laag", 0xe8, INSTR_RSY_RRRD },
-       { "laalg", 0xea, INSTR_RSY_RRRD },
-       { "loc", 0xf2, INSTR_RSY_RDRM },
-       { "stoc", 0xf3, INSTR_RSY_RDRM },
-       { "lan", 0xf4, INSTR_RSY_RRRD },
-       { "lao", 0xf6, INSTR_RSY_RRRD },
-       { "lax", 0xf7, INSTR_RSY_RRRD },
-       { "laa", 0xf8, INSTR_RSY_RRRD },
-       { "laal", 0xfa, INSTR_RSY_RRRD },
-       { "lric", 0x60, INSTR_RSY_RDRM },
-       { "stric", 0x61, INSTR_RSY_RDRM },
-       { "mric", 0x62, INSTR_RSY_RDRM },
-       { { 0, LONG_INSN_STCCTM }, 0x17, INSTR_RSY_RMRD },
-       { "rll", 0x1d, INSTR_RSY_RRRD },
-       { "mvclu", 0x8e, INSTR_RSY_RRRD },
-       { "tp", 0xc0, INSTR_RSL_R0RD },
-       { "", 0, INSTR_INVALID }
+       [VX_12]  = {  4, 12, OPERAND_INDEX | OPERAND_VR },
+       [V_8]    = {  4,  8, OPERAND_VR },
+       [V_12]   = {  4, 12, OPERAND_VR },
+       [V_16]   = {  4, 16, OPERAND_VR },
+       [V_32]   = {  4, 32, OPERAND_VR },
+       [X_12]   = {  4, 12, OPERAND_INDEX | OPERAND_GPR },
 };
 
-static struct s390_insn opcode_ec[] = {
-       { "brxhg", 0x44, INSTR_RIE_RRP },
-       { "brxlg", 0x45, INSTR_RIE_RRP },
-       { { 0, LONG_INSN_RISBLG }, 0x51, INSTR_RIE_RRUUU },
-       { "rnsbg", 0x54, INSTR_RIE_RRUUU },
-       { "risbg", 0x55, INSTR_RIE_RRUUU },
-       { "rosbg", 0x56, INSTR_RIE_RRUUU },
-       { "rxsbg", 0x57, INSTR_RIE_RRUUU },
-       { { 0, LONG_INSN_RISBGN }, 0x59, INSTR_RIE_RRUUU },
-       { { 0, LONG_INSN_RISBHG }, 0x5D, INSTR_RIE_RRUUU },
-       { "cgrj", 0x64, INSTR_RIE_RRPU },
-       { "clgrj", 0x65, INSTR_RIE_RRPU },
-       { "cgit", 0x70, INSTR_RIE_R0IU },
-       { "clgit", 0x71, INSTR_RIE_R0UU },
-       { "cit", 0x72, INSTR_RIE_R0IU },
-       { "clfit", 0x73, INSTR_RIE_R0UU },
-       { "crj", 0x76, INSTR_RIE_RRPU },
-       { "clrj", 0x77, INSTR_RIE_RRPU },
-       { "cgij", 0x7c, INSTR_RIE_RUPI },
-       { "clgij", 0x7d, INSTR_RIE_RUPU },
-       { "cij", 0x7e, INSTR_RIE_RUPI },
-       { "clij", 0x7f, INSTR_RIE_RUPU },
-       { "ahik", 0xd8, INSTR_RIE_RRI0 },
-       { "aghik", 0xd9, INSTR_RIE_RRI0 },
-       { { 0, LONG_INSN_ALHSIK }, 0xda, INSTR_RIE_RRI0 },
-       { { 0, LONG_INSN_ALGHSIK }, 0xdb, INSTR_RIE_RRI0 },
-       { "cgrb", 0xe4, INSTR_RRS_RRRDU },
-       { "clgrb", 0xe5, INSTR_RRS_RRRDU },
-       { "crb", 0xf6, INSTR_RRS_RRRDU },
-       { "clrb", 0xf7, INSTR_RRS_RRRDU },
-       { "cgib", 0xfc, INSTR_RIS_RURDI },
-       { "clgib", 0xfd, INSTR_RIS_RURDU },
-       { "cib", 0xfe, INSTR_RIS_RURDI },
-       { "clib", 0xff, INSTR_RIS_RURDU },
-       { "", 0, INSTR_INVALID }
+static const unsigned char formats[][6] = {
+       [INSTR_E]            = { 0, 0, 0, 0, 0, 0 },
+       [INSTR_IE_UU]        = { U4_24, U4_28, 0, 0, 0, 0 },
+       [INSTR_MII_UPP]      = { U4_8, J12_12, J24_24 },
+       [INSTR_RIE_R0IU]     = { R_8, I16_16, U4_32, 0, 0, 0 },
+       [INSTR_RIE_R0UU]     = { R_8, U16_16, U4_32, 0, 0, 0 },
+       [INSTR_RIE_RRI0]     = { R_8, R_12, I16_16, 0, 0, 0 },
+       [INSTR_RIE_RRP]      = { R_8, R_12, J16_16, 0, 0, 0 },
+       [INSTR_RIE_RRPU]     = { R_8, R_12, U4_32, J16_16, 0, 0 },
+       [INSTR_RIE_RRUUU]    = { R_8, R_12, U8_16, U8_24, U8_32, 0 },
+       [INSTR_RIE_RUI0]     = { R_8, I16_16, U4_12, 0, 0, 0 },
+       [INSTR_RIE_RUPI]     = { R_8, I8_32, U4_12, J16_16, 0, 0 },
+       [INSTR_RIE_RUPU]     = { R_8, U8_32, U4_12, J16_16, 0, 0 },
+       [INSTR_RIL_RI]       = { R_8, I32_16, 0, 0, 0, 0 },
+       [INSTR_RIL_RP]       = { R_8, J32_16, 0, 0, 0, 0 },
+       [INSTR_RIL_RU]       = { R_8, U32_16, 0, 0, 0, 0 },
+       [INSTR_RIL_UP]       = { U4_8, J32_16, 0, 0, 0, 0 },
+       [INSTR_RIS_RURDI]    = { R_8, I8_32, U4_12, D_20, B_16, 0 },
+       [INSTR_RIS_RURDU]    = { R_8, U8_32, U4_12, D_20, B_16, 0 },
+       [INSTR_RI_RI]        = { R_8, I16_16, 0, 0, 0, 0 },
+       [INSTR_RI_RP]        = { R_8, J16_16, 0, 0, 0, 0 },
+       [INSTR_RI_RU]        = { R_8, U16_16, 0, 0, 0, 0 },
+       [INSTR_RI_UP]        = { U4_8, J16_16, 0, 0, 0, 0 },
+       [INSTR_RRE_00]       = { 0, 0, 0, 0, 0, 0 },
+       [INSTR_RRE_AA]       = { A_24, A_28, 0, 0, 0, 0 },
+       [INSTR_RRE_AR]       = { A_24, R_28, 0, 0, 0, 0 },
+       [INSTR_RRE_F0]       = { F_24, 0, 0, 0, 0, 0 },
+       [INSTR_RRE_FF]       = { F_24, F_28, 0, 0, 0, 0 },
+       [INSTR_RRE_FR]       = { F_24, R_28, 0, 0, 0, 0 },
+       [INSTR_RRE_R0]       = { R_24, 0, 0, 0, 0, 0 },
+       [INSTR_RRE_RA]       = { R_24, A_28, 0, 0, 0, 0 },
+       [INSTR_RRE_RF]       = { R_24, F_28, 0, 0, 0, 0 },
+       [INSTR_RRE_RR]       = { R_24, R_28, 0, 0, 0, 0 },
+       [INSTR_RRF_0UFF]     = { F_24, F_28, U4_20, 0, 0, 0 },
+       [INSTR_RRF_0URF]     = { R_24, F_28, U4_20, 0, 0, 0 },
+       [INSTR_RRF_F0FF]     = { F_16, F_24, F_28, 0, 0, 0 },
+       [INSTR_RRF_F0FF2]    = { F_24, F_16, F_28, 0, 0, 0 },
+       [INSTR_RRF_F0FR]     = { F_24, F_16, R_28, 0, 0, 0 },
+       [INSTR_RRF_FFRU]     = { F_24, F_16, R_28, U4_20, 0, 0 },
+       [INSTR_RRF_FUFF]     = { F_24, F_16, F_28, U4_20, 0, 0 },
+       [INSTR_RRF_FUFF2]    = { F_24, F_28, F_16, U4_20, 0, 0 },
+       [INSTR_RRF_R0RR]     = { R_24, R_16, R_28, 0, 0, 0 },
+       [INSTR_RRF_R0RR2]    = { R_24, R_28, R_16, 0, 0, 0 },
+       [INSTR_RRF_RURR]     = { R_24, R_28, R_16, U4_20, 0, 0 },
+       [INSTR_RRF_RURR2]    = { R_24, R_16, R_28, U4_20, 0, 0 },
+       [INSTR_RRF_U0FF]     = { F_24, U4_16, F_28, 0, 0, 0 },
+       [INSTR_RRF_U0RF]     = { R_24, U4_16, F_28, 0, 0, 0 },
+       [INSTR_RRF_U0RR]     = { R_24, R_28, U4_16, 0, 0, 0 },
+       [INSTR_RRF_UUFF]     = { F_24, U4_16, F_28, U4_20, 0, 0 },
+       [INSTR_RRF_UUFR]     = { F_24, U4_16, R_28, U4_20, 0, 0 },
+       [INSTR_RRF_UURF]     = { R_24, U4_16, F_28, U4_20, 0, 0 },
+       [INSTR_RRS_RRRDU]    = { R_8, R_12, U4_32, D_20, B_16 },
+       [INSTR_RR_FF]        = { F_8, F_12, 0, 0, 0, 0 },
+       [INSTR_RR_R0]        = { R_8,  0, 0, 0, 0, 0 },
+       [INSTR_RR_RR]        = { R_8, R_12, 0, 0, 0, 0 },
+       [INSTR_RR_U0]        = { U8_8,  0, 0, 0, 0, 0 },
+       [INSTR_RR_UR]        = { U4_8, R_12, 0, 0, 0, 0 },
+       [INSTR_RSI_RRP]      = { R_8, R_12, J16_16, 0, 0, 0 },
+       [INSTR_RSL_LRDFU]    = { F_32, D_20, L8_8, B_16, U4_36, 0 },
+       [INSTR_RSL_R0RD]     = { D_20, L4_8, B_16, 0, 0, 0 },
+       [INSTR_RSY_AARD]     = { A_8, A_12, D20_20, B_16, 0, 0 },
+       [INSTR_RSY_CCRD]     = { C_8, C_12, D20_20, B_16, 0, 0 },
+       [INSTR_RSY_RDRU]     = { R_8, D20_20, B_16, U4_12, 0, 0 },
+       [INSTR_RSY_RRRD]     = { R_8, R_12, D20_20, B_16, 0, 0 },
+       [INSTR_RSY_RURD]     = { R_8, U4_12, D20_20, B_16, 0, 0 },
+       [INSTR_RSY_RURD2]    = { R_8, D20_20, B_16, U4_12, 0, 0 },
+       [INSTR_RS_AARD]      = { A_8, A_12, D_20, B_16, 0, 0 },
+       [INSTR_RS_CCRD]      = { C_8, C_12, D_20, B_16, 0, 0 },
+       [INSTR_RS_R0RD]      = { R_8, D_20, B_16, 0, 0, 0 },
+       [INSTR_RS_RRRD]      = { R_8, R_12, D_20, B_16, 0, 0 },
+       [INSTR_RS_RURD]      = { R_8, U4_12, D_20, B_16, 0, 0 },
+       [INSTR_RXE_FRRD]     = { F_8, D_20, X_12, B_16, 0, 0 },
+       [INSTR_RXE_RRRDU]    = { R_8, D_20, X_12, B_16, U4_32, 0 },
+       [INSTR_RXF_FRRDF]    = { F_32, F_8, D_20, X_12, B_16, 0 },
+       [INSTR_RXY_FRRD]     = { F_8, D20_20, X_12, B_16, 0, 0 },
+       [INSTR_RXY_RRRD]     = { R_8, D20_20, X_12, B_16, 0, 0 },
+       [INSTR_RXY_URRD]     = { U4_8, D20_20, X_12, B_16, 0, 0 },
+       [INSTR_RX_FRRD]      = { F_8, D_20, X_12, B_16, 0, 0 },
+       [INSTR_RX_RRRD]      = { R_8, D_20, X_12, B_16, 0, 0 },
+       [INSTR_RX_URRD]      = { U4_8, D_20, X_12, B_16, 0, 0 },
+       [INSTR_SIL_RDI]      = { D_20, B_16, I16_32, 0, 0, 0 },
+       [INSTR_SIL_RDU]      = { D_20, B_16, U16_32, 0, 0, 0 },
+       [INSTR_SIY_IRD]      = { D20_20, B_16, I8_8, 0, 0, 0 },
+       [INSTR_SIY_URD]      = { D20_20, B_16, U8_8, 0, 0, 0 },
+       [INSTR_SI_RD]        = { D_20, B_16, 0, 0, 0, 0 },
+       [INSTR_SI_URD]       = { D_20, B_16, U8_8, 0, 0, 0 },
+       [INSTR_SMI_U0RDP]    = { U4_8, J16_32, D_20, B_16, 0, 0 },
+       [INSTR_SSE_RDRD]     = { D_20, B_16, D_36, B_32, 0, 0 },
+       [INSTR_SSF_RRDRD]    = { D_20, B_16, D_36, B_32, R_8, 0 },
+       [INSTR_SSF_RRDRD2]   = { R_8, D_20, B_16, D_36, B_32, 0 },
+       [INSTR_SS_L0RDRD]    = { D_20, L8_8, B_16, D_36, B_32, 0 },
+       [INSTR_SS_L2RDRD]    = { D_20, B_16, D_36, L8_8, B_32, 0 },
+       [INSTR_SS_LIRDRD]    = { D_20, L4_8, B_16, D_36, B_32, U4_12 },
+       [INSTR_SS_LLRDRD]    = { D_20, L4_8, B_16, D_36, L4_12, B_32 },
+       [INSTR_SS_RRRDRD]    = { D_20, R_8, B_16, D_36, B_32, R_12 },
+       [INSTR_SS_RRRDRD2]   = { R_8, D_20, B_16, R_12, D_36, B_32 },
+       [INSTR_SS_RRRDRD3]   = { R_8, R_12, D_20, B_16, D_36, B_32 },
+       [INSTR_S_00]         = { 0, 0, 0, 0, 0, 0 },
+       [INSTR_S_RD]         = { D_20, B_16, 0, 0, 0, 0 },
+       [INSTR_VRI_V0IU]     = { V_8, I16_16, U4_32, 0, 0, 0 },
+       [INSTR_VRI_V0U]      = { V_8, U16_16, 0, 0, 0, 0 },
+       [INSTR_VRI_V0UU2]    = { V_8, U16_16, U4_32, 0, 0, 0 },
+       [INSTR_VRI_V0UUU]    = { V_8, U8_16, U8_24, U4_32, 0, 0 },
+       [INSTR_VRI_VR0UU]    = { V_8, R_12, U8_28, U4_24, 0, 0 },
+       [INSTR_VRI_VVUU]     = { V_8, V_12, U16_16, U4_32, 0, 0 },
+       [INSTR_VRI_VVUUU]    = { V_8, V_12, U12_16, U4_32, U4_28, 0 },
+       [INSTR_VRI_VVUUU2]   = { V_8, V_12, U8_28, U8_16, U4_24, 0 },
+       [INSTR_VRI_VVV0U]    = { V_8, V_12, V_16, U8_24, 0, 0 },
+       [INSTR_VRI_VVV0UU]   = { V_8, V_12, V_16, U8_24, U4_32, 0 },
+       [INSTR_VRI_VVV0UU2]  = { V_8, V_12, V_16, U8_28, U4_24, 0 },
+       [INSTR_VRR_0V]       = { V_12, 0, 0, 0, 0, 0 },
+       [INSTR_VRR_0VV0U]    = { V_12, V_16, U4_24, 0, 0, 0 },
+       [INSTR_VRR_RV0U]     = { R_8, V_12, U4_24, 0, 0, 0 },
+       [INSTR_VRR_VRR]      = { V_8, R_12, R_16, 0, 0, 0 },
+       [INSTR_VRR_VV]       = { V_8, V_12, 0, 0, 0, 0 },
+       [INSTR_VRR_VV0U]     = { V_8, V_12, U4_32, 0, 0, 0 },
+       [INSTR_VRR_VV0U0U]   = { V_8, V_12, U4_32, U4_24, 0, 0 },
+       [INSTR_VRR_VV0UU2]   = { V_8, V_12, U4_32, U4_28, 0, 0 },
+       [INSTR_VRR_VV0UUU]   = { V_8, V_12, U4_32, U4_28, U4_24, 0 },
+       [INSTR_VRR_VVV]      = { V_8, V_12, V_16, 0, 0, 0 },
+       [INSTR_VRR_VVV0U]    = { V_8, V_12, V_16, U4_32, 0, 0 },
+       [INSTR_VRR_VVV0U0U]  = { V_8, V_12, V_16, U4_32, U4_24, 0 },
+       [INSTR_VRR_VVV0UU]   = { V_8, V_12, V_16, U4_32, U4_28, 0 },
+       [INSTR_VRR_VVV0UUU]  = { V_8, V_12, V_16, U4_32, U4_28, U4_24 },
+       [INSTR_VRR_VVV0V]    = { V_8, V_12, V_16, V_32, 0, 0 },
+       [INSTR_VRR_VVVU0UV]  = { V_8, V_12, V_16, V_32, U4_28, U4_20 },
+       [INSTR_VRR_VVVU0V]   = { V_8, V_12, V_16, V_32, U4_20, 0 },
+       [INSTR_VRR_VVVUU0V]  = { V_8, V_12, V_16, V_32, U4_20, U4_24 },
+       [INSTR_VRS_RRDV]     = { V_32, R_12, D_20, B_16, 0, 0 },
+       [INSTR_VRS_RVRDU]    = { R_8, V_12, D_20, B_16, U4_32, 0 },
+       [INSTR_VRS_VRRD]     = { V_8, R_12, D_20, B_16, 0, 0 },
+       [INSTR_VRS_VRRDU]    = { V_8, R_12, D_20, B_16, U4_32, 0 },
+       [INSTR_VRS_VVRD]     = { V_8, V_12, D_20, B_16, 0, 0 },
+       [INSTR_VRS_VVRDU]    = { V_8, V_12, D_20, B_16, U4_32, 0 },
+       [INSTR_VRV_VVXRDU]   = { V_8, D_20, VX_12, B_16, U4_32, 0 },
+       [INSTR_VRX_VRRD]     = { V_8, D_20, X_12, B_16, 0, 0 },
+       [INSTR_VRX_VRRDU]    = { V_8, D_20, X_12, B_16, U4_32, 0 },
+       [INSTR_VRX_VV]       = { V_8, V_12, 0, 0, 0, 0 },
+       [INSTR_VSI_URDV]     = { V_32, D_20, B_16, U8_8, 0, 0 },
 };
 
-static struct s390_insn opcode_ed[] = {
-       { "mayl", 0x38, INSTR_RXF_FRRDF },
-       { "myl", 0x39, INSTR_RXF_FRRDF },
-       { "may", 0x3a, INSTR_RXF_FRRDF },
-       { "my", 0x3b, INSTR_RXF_FRRDF },
-       { "mayh", 0x3c, INSTR_RXF_FRRDF },
-       { "myh", 0x3d, INSTR_RXF_FRRDF },
-       { "sldt", 0x40, INSTR_RXF_FRRDF },
-       { "srdt", 0x41, INSTR_RXF_FRRDF },
-       { "slxt", 0x48, INSTR_RXF_FRRDF },
-       { "srxt", 0x49, INSTR_RXF_FRRDF },
-       { "tdcet", 0x50, INSTR_RXE_FRRD },
-       { "tdget", 0x51, INSTR_RXE_FRRD },
-       { "tdcdt", 0x54, INSTR_RXE_FRRD },
-       { "tdgdt", 0x55, INSTR_RXE_FRRD },
-       { "tdcxt", 0x58, INSTR_RXE_FRRD },
-       { "tdgxt", 0x59, INSTR_RXE_FRRD },
-       { "ley", 0x64, INSTR_RXY_FRRD },
-       { "ldy", 0x65, INSTR_RXY_FRRD },
-       { "stey", 0x66, INSTR_RXY_FRRD },
-       { "stdy", 0x67, INSTR_RXY_FRRD },
-       { "czdt", 0xa8, INSTR_RSL_LRDFU },
-       { "czxt", 0xa9, INSTR_RSL_LRDFU },
-       { "cdzt", 0xaa, INSTR_RSL_LRDFU },
-       { "cxzt", 0xab, INSTR_RSL_LRDFU },
-       { "ldeb", 0x04, INSTR_RXE_FRRD },
-       { "lxdb", 0x05, INSTR_RXE_FRRD },
-       { "lxeb", 0x06, INSTR_RXE_FRRD },
-       { "mxdb", 0x07, INSTR_RXE_FRRD },
-       { "keb", 0x08, INSTR_RXE_FRRD },
-       { "ceb", 0x09, INSTR_RXE_FRRD },
-       { "aeb", 0x0a, INSTR_RXE_FRRD },
-       { "seb", 0x0b, INSTR_RXE_FRRD },
-       { "mdeb", 0x0c, INSTR_RXE_FRRD },
-       { "deb", 0x0d, INSTR_RXE_FRRD },
-       { "maeb", 0x0e, INSTR_RXF_FRRDF },
-       { "mseb", 0x0f, INSTR_RXF_FRRDF },
-       { "tceb", 0x10, INSTR_RXE_FRRD },
-       { "tcdb", 0x11, INSTR_RXE_FRRD },
-       { "tcxb", 0x12, INSTR_RXE_FRRD },
-       { "sqeb", 0x14, INSTR_RXE_FRRD },
-       { "sqdb", 0x15, INSTR_RXE_FRRD },
-       { "meeb", 0x17, INSTR_RXE_FRRD },
-       { "kdb", 0x18, INSTR_RXE_FRRD },
-       { "cdb", 0x19, INSTR_RXE_FRRD },
-       { "adb", 0x1a, INSTR_RXE_FRRD },
-       { "sdb", 0x1b, INSTR_RXE_FRRD },
-       { "mdb", 0x1c, INSTR_RXE_FRRD },
-       { "ddb", 0x1d, INSTR_RXE_FRRD },
-       { "madb", 0x1e, INSTR_RXF_FRRDF },
-       { "msdb", 0x1f, INSTR_RXF_FRRDF },
-       { "lde", 0x24, INSTR_RXE_FRRD },
-       { "lxd", 0x25, INSTR_RXE_FRRD },
-       { "lxe", 0x26, INSTR_RXE_FRRD },
-       { "mae", 0x2e, INSTR_RXF_FRRDF },
-       { "mse", 0x2f, INSTR_RXF_FRRDF },
-       { "sqe", 0x34, INSTR_RXE_FRRD },
-       { "sqd", 0x35, INSTR_RXE_FRRD },
-       { "mee", 0x37, INSTR_RXE_FRRD },
-       { "mad", 0x3e, INSTR_RXF_FRRDF },
-       { "msd", 0x3f, INSTR_RXF_FRRDF },
-       { "", 0, INSTR_INVALID }
-};
+static char long_insn_name[][7] = LONG_INSN_INITIALIZER;
+static struct s390_insn opcode[] = OPCODE_TABLE_INITIALIZER;
+static struct s390_opcode_offset opcode_offset[] = OPCODE_OFFSET_INITIALIZER;
 
 /* Extracts an operand value from an instruction.  */
 static unsigned int extract_operand(unsigned char *code,
@@ -1777,114 +391,27 @@ static unsigned int extract_operand(unsigned char *code,
 
 struct s390_insn *find_insn(unsigned char *code)
 {
-       unsigned char opfrag = code[1];
-       unsigned char opmask;
-       struct s390_insn *table;
+       struct s390_opcode_offset *entry;
+       struct s390_insn *insn;
+       unsigned char opfrag;
+       int i;
 
-       switch (code[0]) {
-       case 0x01:
-               table = opcode_01;
-               break;
-       case 0xa5:
-               table = opcode_a5;
-               break;
-       case 0xa7:
-               table = opcode_a7;
-               break;
-       case 0xaa:
-               table = opcode_aa;
-               break;
-       case 0xb2:
-               table = opcode_b2;
-               break;
-       case 0xb3:
-               table = opcode_b3;
-               break;
-       case 0xb9:
-               table = opcode_b9;
-               break;
-       case 0xc0:
-               table = opcode_c0;
-               break;
-       case 0xc2:
-               table = opcode_c2;
-               break;
-       case 0xc4:
-               table = opcode_c4;
-               break;
-       case 0xc6:
-               table = opcode_c6;
-               break;
-       case 0xc8:
-               table = opcode_c8;
-               break;
-       case 0xcc:
-               table = opcode_cc;
-               break;
-       case 0xe3:
-               table = opcode_e3;
-               opfrag = code[5];
-               break;
-       case 0xe5:
-               table = opcode_e5;
-               break;
-       case 0xe7:
-               table = opcode_e7;
-               opfrag = code[5];
-               break;
-       case 0xeb:
-               table = opcode_eb;
-               opfrag = code[5];
-               break;
-       case 0xec:
-               table = opcode_ec;
-               opfrag = code[5];
-               break;
-       case 0xed:
-               table = opcode_ed;
-               opfrag = code[5];
-               break;
-       default:
-               table = opcode;
-               opfrag = code[0];
-               break;
-       }
-       while (table->format != INSTR_INVALID) {
-               opmask = formats[table->format][0];
-               if (table->opfrag == (opfrag & opmask))
-                       return table;
-               table++;
+       for (i = 0; i < ARRAY_SIZE(opcode_offset); i++) {
+               entry = &opcode_offset[i];
+               if (entry->opcode == code[0] || entry->opcode == 0)
+                       break;
        }
-       return NULL;
-}
 
-/**
- * insn_to_mnemonic - decode an s390 instruction
- * @instruction: instruction to decode
- * @buf: buffer to fill with mnemonic
- * @len: length of buffer
- *
- * Decode the instruction at @instruction and store the corresponding
- * mnemonic into @buf of length @len.
- * @buf is left unchanged if the instruction could not be decoded.
- * Returns:
- *  %0 on success, %-ENOENT if the instruction was not found.
- */
-int insn_to_mnemonic(unsigned char *instruction, char *buf, unsigned int len)
-{
-       struct s390_insn *insn;
+       opfrag = *(code + entry->byte) & entry->mask;
 
-       insn = find_insn(instruction);
-       if (!insn)
-               return -ENOENT;
-       if (insn->name[0] == '\0')
-               snprintf(buf, len, "%s",
-                        long_insn_name[(int) insn->name[1]]);
-       else
-               snprintf(buf, len, "%.5s", insn->name);
-       return 0;
+       insn = &opcode[entry->offset];
+       for (i = 0; i < entry->count; i++) {
+               if (insn->opfrag == opfrag)
+                       return insn;
+               insn++;
+       }
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(insn_to_mnemonic);
 
 static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
 {
@@ -1899,14 +426,14 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
        ptr = buffer;
        insn = find_insn(code);
        if (insn) {
-               if (insn->name[0] == '\0')
-                       ptr += sprintf(ptr, "%s\t",
-                                      long_insn_name[(int) insn->name[1]]);
+               if (insn->zero == 0)
+                       ptr += sprintf(ptr, "%.7s\t",
+                                      long_insn_name[insn->offset]);
                else
                        ptr += sprintf(ptr, "%.5s\t", insn->name);
                /* Extract the operands. */
                separator = 0;
-               for (ops = formats[insn->format] + 1, i = 0;
+               for (ops = formats[insn->format], i = 0;
                     *ops != 0 && i < 6; ops++, i++) {
                        operand = operands + *ops;
                        value = extract_operand(code, operand);
index b945448b9eae8cea488ac32ba7ede48fc6e133e3..497a9204759188e1813370d90b8853fd03417576 100644 (file)
 #include <asm/facility.h>
 #include "entry.h"
 
-/*
- * Create a Kernel NSS if the SAVESYS= parameter is defined
- */
-#define DEFSYS_CMD_SIZE                128
-#define SAVESYS_CMD_SIZE       32
-
-char kernel_nss_name[NSS_NAME_SIZE + 1];
-
 static void __init setup_boot_command_line(void);
 
 /*
@@ -59,134 +51,6 @@ static void __init reset_tod_clock(void)
        S390_lowcore.last_update_clock = TOD_UNIX_EPOCH;
 }
 
-#ifdef CONFIG_SHARED_KERNEL
-int __init savesys_ipl_nss(char *cmd, const int cmdlen);
-
-asm(
-       "       .section .init.text,\"ax\",@progbits\n"
-       "       .align  4\n"
-       "       .type   savesys_ipl_nss, @function\n"
-       "savesys_ipl_nss:\n"
-       "       stmg    6,15,48(15)\n"
-       "       lgr     14,3\n"
-       "       sam31\n"
-       "       diag    2,14,0x8\n"
-       "       sam64\n"
-       "       lgr     2,14\n"
-       "       lmg     6,15,48(15)\n"
-       "       br      14\n"
-       "       .size   savesys_ipl_nss, .-savesys_ipl_nss\n"
-       "       .previous\n");
-
-static __initdata char upper_command_line[COMMAND_LINE_SIZE];
-
-static noinline __init void create_kernel_nss(void)
-{
-       unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
-#ifdef CONFIG_BLK_DEV_INITRD
-       unsigned int sinitrd_pfn, einitrd_pfn;
-#endif
-       int response;
-       int hlen;
-       size_t len;
-       char *savesys_ptr;
-       char defsys_cmd[DEFSYS_CMD_SIZE];
-       char savesys_cmd[SAVESYS_CMD_SIZE];
-
-       /* Do nothing if we are not running under VM */
-       if (!MACHINE_IS_VM)
-               return;
-
-       /* Convert COMMAND_LINE to upper case */
-       for (i = 0; i < strlen(boot_command_line); i++)
-               upper_command_line[i] = toupper(boot_command_line[i]);
-
-       savesys_ptr = strstr(upper_command_line, "SAVESYS=");
-
-       if (!savesys_ptr)
-               return;
-
-       savesys_ptr += 8;    /* Point to the beginning of the NSS name */
-       for (i = 0; i < NSS_NAME_SIZE; i++) {
-               if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
-                       break;
-               kernel_nss_name[i] = savesys_ptr[i];
-       }
-
-       stext_pfn = PFN_DOWN(__pa(&_stext));
-       eshared_pfn = PFN_DOWN(__pa(&_eshared));
-       end_pfn = PFN_UP(__pa(&_end));
-       min_size = end_pfn << 2;
-
-       hlen = snprintf(defsys_cmd, DEFSYS_CMD_SIZE,
-                       "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
-                       kernel_nss_name, stext_pfn - 1, stext_pfn,
-                       eshared_pfn - 1, eshared_pfn, end_pfn);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (INITRD_START && INITRD_SIZE) {
-               sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
-               einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
-               min_size = einitrd_pfn << 2;
-               hlen += snprintf(defsys_cmd + hlen, DEFSYS_CMD_SIZE - hlen,
-                                " EW %.5X-%.5X", sinitrd_pfn, einitrd_pfn);
-       }
-#endif
-
-       snprintf(defsys_cmd + hlen, DEFSYS_CMD_SIZE - hlen,
-                " EW MINSIZE=%.7iK PARMREGS=0-13", min_size);
-       defsys_cmd[DEFSYS_CMD_SIZE - 1] = '\0';
-       snprintf(savesys_cmd, SAVESYS_CMD_SIZE, "SAVESYS %s \n IPL %s",
-                kernel_nss_name, kernel_nss_name);
-       savesys_cmd[SAVESYS_CMD_SIZE - 1] = '\0';
-
-       __cpcmd(defsys_cmd, NULL, 0, &response);
-
-       if (response != 0) {
-               pr_err("Defining the Linux kernel NSS failed with rc=%d\n",
-                       response);
-               kernel_nss_name[0] = '\0';
-               return;
-       }
-
-       len = strlen(savesys_cmd);
-       ASCEBC(savesys_cmd, len);
-       response = savesys_ipl_nss(savesys_cmd, len);
-
-       /* On success: response is equal to the command size,
-        *             max SAVESYS_CMD_SIZE
-        * On error: response contains the numeric portion of cp error message.
-        *           for SAVESYS it will be >= 263
-        *           for missing privilege class, it will be 1
-        */
-       if (response > SAVESYS_CMD_SIZE || response == 1) {
-               pr_err("Saving the Linux kernel NSS failed with rc=%d\n",
-                       response);
-               kernel_nss_name[0] = '\0';
-               return;
-       }
-
-       /* re-initialize cputime accounting. */
-       get_tod_clock_ext(tod_clock_base);
-       S390_lowcore.last_update_clock = *(__u64 *) &tod_clock_base[1];
-       S390_lowcore.last_update_timer = 0x7fffffffffffffffULL;
-       S390_lowcore.user_timer = 0;
-       S390_lowcore.system_timer = 0;
-       asm volatile("SPT 0(%0)" : : "a" (&S390_lowcore.last_update_timer));
-
-       /* re-setup boot command line with new ipl vm parms */
-       ipl_update_parameters();
-       setup_boot_command_line();
-
-       ipl_flags = IPL_NSS_VALID;
-}
-
-#else /* CONFIG_SHARED_KERNEL */
-
-static inline void create_kernel_nss(void) { }
-
-#endif /* CONFIG_SHARED_KERNEL */
-
 /*
  * Clear bss memory
  */
@@ -375,8 +239,10 @@ static __init void detect_machine_facilities(void)
                S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
        if (test_facility(40))
                S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
-       if (test_facility(50) && test_facility(73))
+       if (test_facility(50) && test_facility(73)) {
                S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
+               __ctl_set_bit(0, 55);
+       }
        if (test_facility(51))
                S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
        if (test_facility(129)) {
@@ -549,10 +415,6 @@ static void __init setup_boot_command_line(void)
        append_to_cmdline(append_ipl_scpdata);
 }
 
-/*
- * Save ipl parameters, clear bss memory, initialize storage keys
- * and create a kernel NSS at startup if the SAVESYS= parm is defined
- */
 void __init startup_init(void)
 {
        reset_tod_clock();
@@ -569,7 +431,6 @@ void __init startup_init(void)
        setup_arch_string();
        ipl_update_parameters();
        setup_boot_command_line();
-       create_kernel_nss();
        detect_diag9c();
        detect_diag44();
        detect_machine_facilities();
index 7c6904d616d877330ae5768a9ad348e298a1562e..f498d201f98d09e527c26f815b048a8f48494499 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/linkage.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
+#include <asm/ctl_reg.h>
 #include <asm/errno.h>
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
@@ -952,15 +953,56 @@ load_fpu_regs:
  */
 ENTRY(mcck_int_handler)
        STCK    __LC_MCCK_CLOCK
-       la      %r1,4095                # revalidate r1
-       spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # revalidate cpu timer
-       lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
+       la      %r1,4095                # validate r1
+       spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # validate cpu timer
+       sckc    __LC_CLOCK_COMPARATOR                   # validate comparator
+       lam     %a0,%a15,__LC_AREGS_SAVE_AREA-4095(%r1) # validate acrs
+       lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# validate gprs
        lg      %r12,__LC_CURRENT
        larl    %r13,cleanup_critical
        lmg     %r8,%r9,__LC_MCK_OLD_PSW
        TSTMSK  __LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE
        jo      .Lmcck_panic            # yes -> rest of mcck code invalid
-       lghi    %r14,__LC_CPU_TIMER_SAVE_AREA
+       TSTMSK  __LC_MCCK_CODE,MCCK_CODE_CR_VALID
+       jno     .Lmcck_panic            # control registers invalid -> panic
+       la      %r14,4095
+       lctlg   %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r14) # validate ctl regs
+       ptlb
+       lg      %r11,__LC_MCESAD-4095(%r14) # extended machine check save area
+       nill    %r11,0xfc00             # MCESA_ORIGIN_MASK
+       TSTMSK  __LC_CREGS_SAVE_AREA+16-4095(%r14),CR2_GUARDED_STORAGE
+       jno     0f
+       TSTMSK  __LC_MCCK_CODE,MCCK_CODE_GS_VALID
+       jno     0f
+       .insn    rxy,0xe3000000004d,0,__MCESA_GS_SAVE_AREA(%r11) # LGSC
+0:     l       %r14,__LC_FP_CREG_SAVE_AREA-4095(%r14)
+       TSTMSK  __LC_MCCK_CODE,MCCK_CODE_FC_VALID
+       jo      0f
+       sr      %r14,%r14
+0:     sfpc    %r14
+       TSTMSK  __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
+       jo      0f
+       lghi    %r14,__LC_FPREGS_SAVE_AREA
+       ld      %f0,0(%r14)
+       ld      %f1,8(%r14)
+       ld      %f2,16(%r14)
+       ld      %f3,24(%r14)
+       ld      %f4,32(%r14)
+       ld      %f5,40(%r14)
+       ld      %f6,48(%r14)
+       ld      %f7,56(%r14)
+       ld      %f8,64(%r14)
+       ld      %f9,72(%r14)
+       ld      %f10,80(%r14)
+       ld      %f11,88(%r14)
+       ld      %f12,96(%r14)
+       ld      %f13,104(%r14)
+       ld      %f14,112(%r14)
+       ld      %f15,120(%r14)
+       j       1f
+0:     VLM     %v0,%v15,0,%r11
+       VLM     %v16,%v31,256,%r11
+1:     lghi    %r14,__LC_CPU_TIMER_SAVE_AREA
        mvc     __LC_MCCK_ENTER_TIMER(8),0(%r14)
        TSTMSK  __LC_MCCK_CODE,MCCK_CODE_CPU_TIMER_VALID
        jo      3f
@@ -976,9 +1018,13 @@ ENTRY(mcck_int_handler)
        la      %r14,__LC_LAST_UPDATE_TIMER
 2:     spt     0(%r14)
        mvc     __LC_MCCK_ENTER_TIMER(8),0(%r14)
-3:     TSTMSK  __LC_MCCK_CODE,(MCCK_CODE_PSW_MWP_VALID|MCCK_CODE_PSW_IA_VALID)
-       jno     .Lmcck_panic            # no -> skip cleanup critical
-       SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_MCCK_ENTER_TIMER
+3:     TSTMSK  __LC_MCCK_CODE,MCCK_CODE_PSW_MWP_VALID
+       jno     .Lmcck_panic
+       tmhh    %r8,0x0001              # interrupting from user ?
+       jnz     4f
+       TSTMSK  __LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID
+       jno     .Lmcck_panic
+4:     SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_MCCK_ENTER_TIMER
 .Lmcck_skip:
        lghi    %r14,__LC_GPREGS_SAVE_AREA+64
        stmg    %r0,%r7,__PT_R0(%r11)
index 905bde78249099780e33d2c149d4e123122a8148..e87758f8fbdccfa9540989bef0984a360d7ed686 100644 (file)
@@ -78,6 +78,7 @@ long sys_s390_runtime_instr(int command, int signum);
 long sys_s390_guarded_storage(int command, struct gs_cb __user *);
 long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
 long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
+long sys_s390_sthyi(unsigned long function_code, void __user *buffer, u64 __user *return_code, unsigned long flags);
 
 DECLARE_PER_CPU(u64, mt_cycles[8]);
 
index bff39b66c9ffdebe0faeab48d13e7c61312faf87..d14dd1c2e5240b8d8383f41e09f35a0627992e1c 100644 (file)
 #include <asm/guarded_storage.h>
 #include "entry.h"
 
-void exit_thread_gs(void)
+void guarded_storage_release(struct task_struct *tsk)
 {
-       kfree(current->thread.gs_cb);
-       kfree(current->thread.gs_bc_cb);
-       current->thread.gs_cb = current->thread.gs_bc_cb = NULL;
+       kfree(tsk->thread.gs_cb);
+       kfree(tsk->thread.gs_bc_cb);
 }
 
 static int gs_enable(void)
index 8e622bb52f7a95fd59c2f89aec95f04c616633cf..310e59e6eb4b20bb7f17debb8ec412546289baf8 100644 (file)
@@ -279,8 +279,6 @@ static __init enum ipl_type get_ipl_type(void)
 {
        struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
 
-       if (ipl_flags & IPL_NSS_VALID)
-               return IPL_TYPE_NSS;
        if (!(ipl_flags & IPL_DEVNO_VALID))
                return IPL_TYPE_UNKNOWN;
        if (!(ipl_flags & IPL_PARMBLOCK_VALID))
@@ -533,22 +531,6 @@ static struct attribute_group ipl_ccw_attr_group_lpar = {
        .attrs = ipl_ccw_attrs_lpar
 };
 
-/* NSS ipl device attributes */
-
-DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
-
-static struct attribute *ipl_nss_attrs[] = {
-       &sys_ipl_type_attr.attr,
-       &sys_ipl_nss_name_attr.attr,
-       &sys_ipl_ccw_loadparm_attr.attr,
-       &sys_ipl_vm_parm_attr.attr,
-       NULL,
-};
-
-static struct attribute_group ipl_nss_attr_group = {
-       .attrs = ipl_nss_attrs,
-};
-
 /* UNKNOWN ipl device attributes */
 
 static struct attribute *ipl_unknown_attrs[] = {
@@ -598,9 +580,6 @@ static int __init ipl_init(void)
        case IPL_TYPE_FCP_DUMP:
                rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
                break;
-       case IPL_TYPE_NSS:
-               rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group);
-               break;
        default:
                rc = sysfs_create_group(&ipl_kset->kobj,
                                        &ipl_unknown_attr_group);
@@ -1172,18 +1151,6 @@ static int __init reipl_nss_init(void)
                return rc;
 
        reipl_block_ccw_init(reipl_block_nss);
-       if (ipl_info.type == IPL_TYPE_NSS) {
-               memset(reipl_block_nss->ipl_info.ccw.nss_name,
-                       ' ', NSS_NAME_SIZE);
-               memcpy(reipl_block_nss->ipl_info.ccw.nss_name,
-                       kernel_nss_name, strlen(kernel_nss_name));
-               ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
-               reipl_block_nss->ipl_info.ccw.vm_flags |=
-                       DIAG308_VM_FLAGS_NSS_VALID;
-
-               reipl_block_ccw_fill_parms(reipl_block_nss);
-       }
-
        reipl_capabilities |= IPL_TYPE_NSS;
        return 0;
 }
@@ -1971,9 +1938,6 @@ void __init setup_ipl(void)
                ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
                break;
        case IPL_TYPE_NSS:
-               strncpy(ipl_info.data.nss.name, kernel_nss_name,
-                       sizeof(ipl_info.data.nss.name));
-               break;
        case IPL_TYPE_UNKNOWN:
                /* We have no info to copy */
                break;
index 6842e4501e2e53a82f1da1de7b25860f3f96a034..1a6521af17514a722c02e1b032fe3514d6857a15 100644 (file)
@@ -161,8 +161,6 @@ struct swap_insn_args {
 
 static int swap_instruction(void *data)
 {
-       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
-       unsigned long status = kcb->kprobe_status;
        struct swap_insn_args *args = data;
        struct ftrace_insn new_insn, *insn;
        struct kprobe *p = args->p;
@@ -185,9 +183,7 @@ static int swap_instruction(void *data)
                        ftrace_generate_nop_insn(&new_insn);
        }
 skip_ftrace:
-       kcb->kprobe_status = KPROBE_SWAP_INST;
        s390_kernel_write(p->addr, &new_insn, len);
-       kcb->kprobe_status = status;
        return 0;
 }
 NOKPROBE_SYMBOL(swap_instruction);
@@ -574,9 +570,6 @@ static int kprobe_trap_handler(struct pt_regs *regs, int trapnr)
        const struct exception_table_entry *entry;
 
        switch(kcb->kprobe_status) {
-       case KPROBE_SWAP_INST:
-               /* We are here because the instruction replacement failed */
-               return 0;
        case KPROBE_HIT_SS:
        case KPROBE_REENTER:
                /*
index ae7dff110054fd33d1c231feae3eab27933b0748..bf9622f0e6b16aa291037d880f8ffe3ec75c1046 100644 (file)
@@ -153,14 +153,13 @@ static void lgr_timer_set(void);
 /*
  * LGR timer callback
  */
-static void lgr_timer_fn(unsigned long ignored)
+static void lgr_timer_fn(struct timer_list *unused)
 {
        lgr_info_log();
        lgr_timer_set();
 }
 
-static struct timer_list lgr_timer =
-       TIMER_DEFERRED_INITIALIZER(lgr_timer_fn, 0, 0);
+static struct timer_list lgr_timer;
 
 /*
  * Setup next LGR timer
@@ -181,6 +180,7 @@ static int __init lgr_init(void)
        debug_register_view(lgr_dbf, &debug_hex_ascii_view);
        lgr_info_get(&lgr_info_last);
        debug_event(lgr_dbf, 1, &lgr_info_last, sizeof(lgr_info_last));
+       timer_setup(&lgr_timer, lgr_timer_fn, TIMER_DEFERRABLE);
        lgr_timer_set();
        return 0;
 }
index b0ba2c26b45e4ebe2b20b709c4618cf96eba5df2..a80050bbe2e40e768490aa6c136b70470fff49d7 100644 (file)
@@ -106,7 +106,7 @@ static void __do_machine_kdump(void *image)
 static noinline void __machine_kdump(void *image)
 {
        struct mcesa *mcesa;
-       unsigned long cr2_old, cr2_new;
+       union ctlreg2 cr2_old, cr2_new;
        int this_cpu, cpu;
 
        lgr_info_log();
@@ -123,11 +123,12 @@ static noinline void __machine_kdump(void *image)
        if (MACHINE_HAS_VX)
                save_vx_regs((__vector128 *) mcesa->vector_save_area);
        if (MACHINE_HAS_GS) {
-               __ctl_store(cr2_old, 2, 2);
-               cr2_new = cr2_old | (1UL << 4);
-               __ctl_load(cr2_new, 2, 2);
+               __ctl_store(cr2_old.val, 2, 2);
+               cr2_new = cr2_old;
+               cr2_new.gse = 1;
+               __ctl_load(cr2_new.val, 2, 2);
                save_gs_cb((struct gs_cb *) mcesa->guarded_storage_save_area);
-               __ctl_load(cr2_old, 2, 2);
+               __ctl_load(cr2_old.val, 2, 2);
        }
        /*
         * To create a good backchain for this CPU in the dump store_status
@@ -145,7 +146,7 @@ static noinline void __machine_kdump(void *image)
 /*
  * Check if kdump checksums are valid: We call purgatory with parameter "0"
  */
-static int kdump_csum_valid(struct kimage *image)
+static bool kdump_csum_valid(struct kimage *image)
 {
 #ifdef CONFIG_CRASH_DUMP
        int (*start_kdump)(int) = (void *)image->start;
@@ -154,9 +155,9 @@ static int kdump_csum_valid(struct kimage *image)
        __arch_local_irq_stnsm(0xfb); /* disable DAT */
        rc = start_kdump(0);
        __arch_local_irq_stosm(0x04); /* enable DAT */
-       return rc ? 0 : -EINVAL;
+       return rc == 0;
 #else
-       return -EINVAL;
+       return false;
 #endif
 }
 
@@ -219,10 +220,6 @@ int machine_kexec_prepare(struct kimage *image)
 {
        void *reboot_code_buffer;
 
-       /* Can't replace kernel image since it is read-only. */
-       if (ipl_flags & IPL_NSS_VALID)
-               return -EOPNOTSUPP;
-
        if (image->type == KEXEC_TYPE_CRASH)
                return machine_kexec_prepare_kdump();
 
@@ -269,6 +266,7 @@ static void __do_machine_kexec(void *data)
        s390_reset_system();
        data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page);
 
+       __arch_local_irq_stnsm(0xfb); /* disable DAT - avoid no-execute */
        /* Call the moving routine */
        (*data_mover)(&image->head, image->start);
 
index 1a27f307a92079e79ead66c5e50e4f54e992530c..6d9f73bb4142ab1b95a9dfd2dadc61853175961c 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/kernel.h>
 #include <linux/moduleloader.h>
 #include <linux/bug.h>
+#include <asm/alternative.h>
 
 #if 0
 #define DEBUGP printk
@@ -429,6 +430,22 @@ int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
+       const Elf_Shdr *s;
+       char *secstrings;
+
+       if (IS_ENABLED(CONFIG_ALTERNATIVES)) {
+               secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+               for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+                       if (!strcmp(".altinstructions",
+                                   secstrings + s->sh_name)) {
+                               /* patch .altinstructions */
+                               void *aseg = (void *)s->sh_addr;
+
+                               apply_alternatives(aseg, aseg + s->sh_size);
+                       }
+               }
+       }
+
        jump_label_apply_nops(me);
        return 0;
 }
index 31d03a84126c5a96545b6496628ea38a5cd046dc..3f3cda41f32a5441284da606138fec7e8c7598c0 100644 (file)
@@ -12,6 +12,9 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/hardirq.h>
+#include <linux/log2.h>
+#include <linux/kprobes.h>
+#include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/module.h>
 #include <linux/sched/signal.h>
@@ -37,13 +40,94 @@ struct mcck_struct {
 };
 
 static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
+static struct kmem_cache *mcesa_cache;
+static unsigned long mcesa_origin_lc;
 
-static void s390_handle_damage(void)
+static inline int nmi_needs_mcesa(void)
 {
-       smp_send_stop();
+       return MACHINE_HAS_VX || MACHINE_HAS_GS;
+}
+
+static inline unsigned long nmi_get_mcesa_size(void)
+{
+       if (MACHINE_HAS_GS)
+               return MCESA_MAX_SIZE;
+       return MCESA_MIN_SIZE;
+}
+
+/*
+ * The initial machine check extended save area for the boot CPU.
+ * It will be replaced by nmi_init() with an allocated structure.
+ * The structure is required for machine check happening early in
+ * the boot process.
+ */
+static struct mcesa boot_mcesa __initdata __aligned(MCESA_MAX_SIZE);
+
+void __init nmi_alloc_boot_cpu(struct lowcore *lc)
+{
+       if (!nmi_needs_mcesa())
+               return;
+       lc->mcesad = (unsigned long) &boot_mcesa;
+       if (MACHINE_HAS_GS)
+               lc->mcesad |= ilog2(MCESA_MAX_SIZE);
+}
+
+static int __init nmi_init(void)
+{
+       unsigned long origin, cr0, size;
+
+       if (!nmi_needs_mcesa())
+               return 0;
+       size = nmi_get_mcesa_size();
+       if (size > MCESA_MIN_SIZE)
+               mcesa_origin_lc = ilog2(size);
+       /* create slab cache for the machine-check-extended-save-areas */
+       mcesa_cache = kmem_cache_create("nmi_save_areas", size, size, 0, NULL);
+       if (!mcesa_cache)
+               panic("Couldn't create nmi save area cache");
+       origin = (unsigned long) kmem_cache_alloc(mcesa_cache, GFP_KERNEL);
+       if (!origin)
+               panic("Couldn't allocate nmi save area");
+       /* The pointer is stored with mcesa_bits ORed in */
+       kmemleak_not_leak((void *) origin);
+       __ctl_store(cr0, 0, 0);
+       __ctl_clear_bit(0, 28); /* disable lowcore protection */
+       /* Replace boot_mcesa on the boot CPU */
+       S390_lowcore.mcesad = origin | mcesa_origin_lc;
+       __ctl_load(cr0, 0, 0);
+       return 0;
+}
+early_initcall(nmi_init);
+
+int nmi_alloc_per_cpu(struct lowcore *lc)
+{
+       unsigned long origin;
+
+       if (!nmi_needs_mcesa())
+               return 0;
+       origin = (unsigned long) kmem_cache_alloc(mcesa_cache, GFP_KERNEL);
+       if (!origin)
+               return -ENOMEM;
+       /* The pointer is stored with mcesa_bits ORed in */
+       kmemleak_not_leak((void *) origin);
+       lc->mcesad = origin | mcesa_origin_lc;
+       return 0;
+}
+
+void nmi_free_per_cpu(struct lowcore *lc)
+{
+       if (!nmi_needs_mcesa())
+               return;
+       kmem_cache_free(mcesa_cache, (void *)(lc->mcesad & MCESA_ORIGIN_MASK));
+}
+
+static notrace void s390_handle_damage(void)
+{
+       smp_emergency_stop();
        disabled_wait((unsigned long) __builtin_return_address(0));
        while (1);
 }
+NOKPROBE_SYMBOL(s390_handle_damage);
 
 /*
  * Main machine check handler function. Will be called with interrupts enabled
@@ -100,18 +184,16 @@ void s390_handle_mcck(void)
 EXPORT_SYMBOL_GPL(s390_handle_mcck);
 
 /*
- * returns 0 if all registers could be validated
+ * returns 0 if all required registers are available
  * returns 1 otherwise
  */
-static int notrace s390_validate_registers(union mci mci, int umode)
+static int notrace s390_check_registers(union mci mci, int umode)
 {
+       union ctlreg2 cr2;
        int kill_task;
-       u64 zero;
        void *fpt_save_area;
-       struct mcesa *mcesa;
 
        kill_task = 0;
-       zero = 0;
 
        if (!mci.gr) {
                /*
@@ -122,18 +204,13 @@ static int notrace s390_validate_registers(union mci mci, int umode)
                        s390_handle_damage();
                kill_task = 1;
        }
-       /* Validate control registers */
+       /* Check control registers */
        if (!mci.cr) {
                /*
                 * Control registers have unknown contents.
                 * Can't recover and therefore stopping machine.
                 */
                s390_handle_damage();
-       } else {
-               asm volatile(
-                       "       lctlg   0,15,0(%0)\n"
-                       "       ptlb\n"
-                       : : "a" (&S390_lowcore.cregs_save_area) : "memory");
        }
        if (!mci.fp) {
                /*
@@ -141,7 +218,6 @@ static int notrace s390_validate_registers(union mci mci, int umode)
                 * kernel currently uses floating point registers the
                 * system is stopped. If the process has its floating
                 * pointer registers loaded it is terminated.
-                * Otherwise just revalidate the registers.
                 */
                if (S390_lowcore.fpu_flags & KERNEL_VXR_V0V7)
                        s390_handle_damage();
@@ -155,72 +231,29 @@ static int notrace s390_validate_registers(union mci mci, int umode)
                 * If the kernel currently uses the floating pointer
                 * registers and needs the FPC register the system is
                 * stopped. If the process has its floating pointer
-                * registers loaded it is terminated. Otherwiese the
-                * FPC is just revalidated.
+                * registers loaded it is terminated.
                 */
                if (S390_lowcore.fpu_flags & KERNEL_FPC)
                        s390_handle_damage();
-               asm volatile("lfpc %0" : : "Q" (zero));
                if (!test_cpu_flag(CIF_FPU))
                        kill_task = 1;
-       } else {
-               asm volatile("lfpc %0"
-                            : : "Q" (S390_lowcore.fpt_creg_save_area));
        }
 
-       mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK);
-       if (!MACHINE_HAS_VX) {
-               /* Validate floating point registers */
-               asm volatile(
-                       "       ld      0,0(%0)\n"
-                       "       ld      1,8(%0)\n"
-                       "       ld      2,16(%0)\n"
-                       "       ld      3,24(%0)\n"
-                       "       ld      4,32(%0)\n"
-                       "       ld      5,40(%0)\n"
-                       "       ld      6,48(%0)\n"
-                       "       ld      7,56(%0)\n"
-                       "       ld      8,64(%0)\n"
-                       "       ld      9,72(%0)\n"
-                       "       ld      10,80(%0)\n"
-                       "       ld      11,88(%0)\n"
-                       "       ld      12,96(%0)\n"
-                       "       ld      13,104(%0)\n"
-                       "       ld      14,112(%0)\n"
-                       "       ld      15,120(%0)\n"
-                       : : "a" (fpt_save_area) : "memory");
-       } else {
-               /* Validate vector registers */
-               union ctlreg0 cr0;
-
+       if (MACHINE_HAS_VX) {
                if (!mci.vr) {
                        /*
                         * Vector registers can't be restored. If the kernel
                         * currently uses vector registers the system is
                         * stopped. If the process has its vector registers
-                        * loaded it is terminated. Otherwise just revalidate
-                        * the registers.
+                        * loaded it is terminated.
                         */
                        if (S390_lowcore.fpu_flags & KERNEL_VXR)
                                s390_handle_damage();
                        if (!test_cpu_flag(CIF_FPU))
                                kill_task = 1;
                }
-               cr0.val = S390_lowcore.cregs_save_area[0];
-               cr0.afp = cr0.vx = 1;
-               __ctl_load(cr0.val, 0, 0);
-               asm volatile(
-                       "       la      1,%0\n"
-                       "       .word   0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
-                       "       .word   0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
-                       : : "Q" (*(struct vx_array *) mcesa->vector_save_area)
-                       : "1");
-               __ctl_load(S390_lowcore.cregs_save_area[0], 0, 0);
        }
-       /* Validate access registers */
-       asm volatile(
-               "       lam     0,15,0(%0)"
-               : : "a" (&S390_lowcore.access_regs_save_area));
+       /* Check if access registers are valid */
        if (!mci.ar) {
                /*
                 * Access registers have unknown contents.
@@ -228,53 +261,41 @@ static int notrace s390_validate_registers(union mci mci, int umode)
                 */
                kill_task = 1;
        }
-       /* Validate guarded storage registers */
-       if (MACHINE_HAS_GS && (S390_lowcore.cregs_save_area[2] & (1UL << 4))) {
-               if (!mci.gs)
+       /* Check guarded storage registers */
+       cr2.val = S390_lowcore.cregs_save_area[2];
+       if (cr2.gse) {
+               if (!mci.gs) {
                        /*
                         * Guarded storage register can't be restored and
                         * the current processes uses guarded storage.
                         * It has to be terminated.
                         */
                        kill_task = 1;
-               else
-                       load_gs_cb((struct gs_cb *)
-                                  mcesa->guarded_storage_save_area);
+               }
        }
-       /*
-        * We don't even try to validate the TOD register, since we simply
-        * can't write something sensible into that register.
-        */
-       /*
-        * See if we can validate the TOD programmable register with its
-        * old contents (should be zero) otherwise set it to zero.
-        */
-       if (!mci.pr)
-               asm volatile(
-                       "       sr      0,0\n"
-                       "       sckpf"
-                       : : : "0", "cc");
-       else
-               asm volatile(
-                       "       l       0,%0\n"
-                       "       sckpf"
-                       : : "Q" (S390_lowcore.tod_progreg_save_area)
-                       : "0", "cc");
-       /* Validate clock comparator register */
-       set_clock_comparator(S390_lowcore.clock_comparator);
        /* Check if old PSW is valid */
-       if (!mci.wp)
+       if (!mci.wp) {
                /*
                 * Can't tell if we come from user or kernel mode
                 * -> stopping machine.
                 */
                s390_handle_damage();
+       }
+       /* Check for invalid kernel instruction address */
+       if (!mci.ia && !umode) {
+               /*
+                * The instruction address got lost while running
+                * in the kernel -> stopping machine.
+                */
+               s390_handle_damage();
+       }
 
        if (!mci.ms || !mci.pm || !mci.ia)
                kill_task = 1;
 
        return kill_task;
 }
+NOKPROBE_SYMBOL(s390_check_registers);
 
 /*
  * Backup the guest's machine check info to its description block
@@ -300,6 +321,7 @@ static void notrace s390_backup_mcck_info(struct pt_regs *regs)
        mcck_backup->failing_storage_address
                        = S390_lowcore.failing_storage_address;
 }
+NOKPROBE_SYMBOL(s390_backup_mcck_info);
 
 #define MAX_IPD_COUNT  29
 #define MAX_IPD_TIME   (5 * 60 * USEC_PER_SEC) /* 5 minutes */
@@ -372,7 +394,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
                        s390_handle_damage();
                }
        }
-       if (s390_validate_registers(mci, user_mode(regs))) {
+       if (s390_check_registers(mci, user_mode(regs))) {
                /*
                 * Couldn't restore all register contents for the
                 * user space process -> mark task for termination.
@@ -443,6 +465,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
        clear_cpu_flag(CIF_MCCK_GUEST);
        nmi_exit();
 }
+NOKPROBE_SYMBOL(s390_do_machine_check);
 
 static int __init machine_check_init(void)
 {
index 08bfa17ba0a0699937b1bfb725fadd4c94957479..94f90cefbffcb55e0584b16942ff5920cffc3408 100644 (file)
 
 /* BEGIN: CPUM_CF COUNTER DEFINITIONS =================================== */
 
-CPUMF_EVENT_ATTR(cf, CPU_CYCLES, 0x0000);
-CPUMF_EVENT_ATTR(cf, INSTRUCTIONS, 0x0001);
-CPUMF_EVENT_ATTR(cf, L1I_DIR_WRITES, 0x0002);
-CPUMF_EVENT_ATTR(cf, L1I_PENALTY_CYCLES, 0x0003);
-CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_CPU_CYCLES, 0x0020);
-CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_INSTRUCTIONS, 0x0021);
-CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_L1I_DIR_WRITES, 0x0022);
-CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_L1I_PENALTY_CYCLES, 0x0023);
-CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_L1D_DIR_WRITES, 0x0024);
-CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_L1D_PENALTY_CYCLES, 0x0025);
-CPUMF_EVENT_ATTR(cf, L1D_DIR_WRITES, 0x0004);
-CPUMF_EVENT_ATTR(cf, L1D_PENALTY_CYCLES, 0x0005);
-CPUMF_EVENT_ATTR(cf, PRNG_FUNCTIONS, 0x0040);
-CPUMF_EVENT_ATTR(cf, PRNG_CYCLES, 0x0041);
-CPUMF_EVENT_ATTR(cf, PRNG_BLOCKED_FUNCTIONS, 0x0042);
-CPUMF_EVENT_ATTR(cf, PRNG_BLOCKED_CYCLES, 0x0043);
-CPUMF_EVENT_ATTR(cf, SHA_FUNCTIONS, 0x0044);
-CPUMF_EVENT_ATTR(cf, SHA_CYCLES, 0x0045);
-CPUMF_EVENT_ATTR(cf, SHA_BLOCKED_FUNCTIONS, 0x0046);
-CPUMF_EVENT_ATTR(cf, SHA_BLOCKED_CYCLES, 0x0047);
-CPUMF_EVENT_ATTR(cf, DEA_FUNCTIONS, 0x0048);
-CPUMF_EVENT_ATTR(cf, DEA_CYCLES, 0x0049);
-CPUMF_EVENT_ATTR(cf, DEA_BLOCKED_FUNCTIONS, 0x004a);
-CPUMF_EVENT_ATTR(cf, DEA_BLOCKED_CYCLES, 0x004b);
-CPUMF_EVENT_ATTR(cf, AES_FUNCTIONS, 0x004c);
-CPUMF_EVENT_ATTR(cf, AES_CYCLES, 0x004d);
-CPUMF_EVENT_ATTR(cf, AES_BLOCKED_FUNCTIONS, 0x004e);
-CPUMF_EVENT_ATTR(cf, AES_BLOCKED_CYCLES, 0x004f);
+CPUMF_EVENT_ATTR(cf_fvn1, CPU_CYCLES, 0x0000);
+CPUMF_EVENT_ATTR(cf_fvn1, INSTRUCTIONS, 0x0001);
+CPUMF_EVENT_ATTR(cf_fvn1, L1I_DIR_WRITES, 0x0002);
+CPUMF_EVENT_ATTR(cf_fvn1, L1I_PENALTY_CYCLES, 0x0003);
+CPUMF_EVENT_ATTR(cf_fvn1, PROBLEM_STATE_CPU_CYCLES, 0x0020);
+CPUMF_EVENT_ATTR(cf_fvn1, PROBLEM_STATE_INSTRUCTIONS, 0x0021);
+CPUMF_EVENT_ATTR(cf_fvn1, PROBLEM_STATE_L1I_DIR_WRITES, 0x0022);
+CPUMF_EVENT_ATTR(cf_fvn1, PROBLEM_STATE_L1I_PENALTY_CYCLES, 0x0023);
+CPUMF_EVENT_ATTR(cf_fvn1, PROBLEM_STATE_L1D_DIR_WRITES, 0x0024);
+CPUMF_EVENT_ATTR(cf_fvn1, PROBLEM_STATE_L1D_PENALTY_CYCLES, 0x0025);
+CPUMF_EVENT_ATTR(cf_fvn1, L1D_DIR_WRITES, 0x0004);
+CPUMF_EVENT_ATTR(cf_fvn1, L1D_PENALTY_CYCLES, 0x0005);
+CPUMF_EVENT_ATTR(cf_fvn3, CPU_CYCLES, 0x0000);
+CPUMF_EVENT_ATTR(cf_fvn3, INSTRUCTIONS, 0x0001);
+CPUMF_EVENT_ATTR(cf_fvn3, L1I_DIR_WRITES, 0x0002);
+CPUMF_EVENT_ATTR(cf_fvn3, L1I_PENALTY_CYCLES, 0x0003);
+CPUMF_EVENT_ATTR(cf_fvn3, PROBLEM_STATE_CPU_CYCLES, 0x0020);
+CPUMF_EVENT_ATTR(cf_fvn3, PROBLEM_STATE_INSTRUCTIONS, 0x0021);
+CPUMF_EVENT_ATTR(cf_fvn3, L1D_DIR_WRITES, 0x0004);
+CPUMF_EVENT_ATTR(cf_fvn3, L1D_PENALTY_CYCLES, 0x0005);
+CPUMF_EVENT_ATTR(cf_svn_generic, PRNG_FUNCTIONS, 0x0040);
+CPUMF_EVENT_ATTR(cf_svn_generic, PRNG_CYCLES, 0x0041);
+CPUMF_EVENT_ATTR(cf_svn_generic, PRNG_BLOCKED_FUNCTIONS, 0x0042);
+CPUMF_EVENT_ATTR(cf_svn_generic, PRNG_BLOCKED_CYCLES, 0x0043);
+CPUMF_EVENT_ATTR(cf_svn_generic, SHA_FUNCTIONS, 0x0044);
+CPUMF_EVENT_ATTR(cf_svn_generic, SHA_CYCLES, 0x0045);
+CPUMF_EVENT_ATTR(cf_svn_generic, SHA_BLOCKED_FUNCTIONS, 0x0046);
+CPUMF_EVENT_ATTR(cf_svn_generic, SHA_BLOCKED_CYCLES, 0x0047);
+CPUMF_EVENT_ATTR(cf_svn_generic, DEA_FUNCTIONS, 0x0048);
+CPUMF_EVENT_ATTR(cf_svn_generic, DEA_CYCLES, 0x0049);
+CPUMF_EVENT_ATTR(cf_svn_generic, DEA_BLOCKED_FUNCTIONS, 0x004a);
+CPUMF_EVENT_ATTR(cf_svn_generic, DEA_BLOCKED_CYCLES, 0x004b);
+CPUMF_EVENT_ATTR(cf_svn_generic, AES_FUNCTIONS, 0x004c);
+CPUMF_EVENT_ATTR(cf_svn_generic, AES_CYCLES, 0x004d);
+CPUMF_EVENT_ATTR(cf_svn_generic, AES_BLOCKED_FUNCTIONS, 0x004e);
+CPUMF_EVENT_ATTR(cf_svn_generic, AES_BLOCKED_CYCLES, 0x004f);
 CPUMF_EVENT_ATTR(cf_z10, L1I_L2_SOURCED_WRITES, 0x0080);
 CPUMF_EVENT_ATTR(cf_z10, L1D_L2_SOURCED_WRITES, 0x0081);
 CPUMF_EVENT_ATTR(cf_z10, L1I_L3_LOCAL_WRITES, 0x0082);
@@ -171,36 +179,105 @@ CPUMF_EVENT_ATTR(cf_z13, TX_C_TABORT_NO_SPECIAL, 0x00db);
 CPUMF_EVENT_ATTR(cf_z13, TX_C_TABORT_SPECIAL, 0x00dc);
 CPUMF_EVENT_ATTR(cf_z13, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
 CPUMF_EVENT_ATTR(cf_z13, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
+CPUMF_EVENT_ATTR(cf_z14, L1D_WRITES_RO_EXCL, 0x0080);
+CPUMF_EVENT_ATTR(cf_z14, DTLB2_WRITES, 0x0081);
+CPUMF_EVENT_ATTR(cf_z14, DTLB2_MISSES, 0x0082);
+CPUMF_EVENT_ATTR(cf_z14, DTLB2_HPAGE_WRITES, 0x0083);
+CPUMF_EVENT_ATTR(cf_z14, DTLB2_GPAGE_WRITES, 0x0084);
+CPUMF_EVENT_ATTR(cf_z14, L1D_L2D_SOURCED_WRITES, 0x0085);
+CPUMF_EVENT_ATTR(cf_z14, ITLB2_WRITES, 0x0086);
+CPUMF_EVENT_ATTR(cf_z14, ITLB2_MISSES, 0x0087);
+CPUMF_EVENT_ATTR(cf_z14, L1I_L2I_SOURCED_WRITES, 0x0088);
+CPUMF_EVENT_ATTR(cf_z14, TLB2_PTE_WRITES, 0x0089);
+CPUMF_EVENT_ATTR(cf_z14, TLB2_CRSTE_WRITES, 0x008a);
+CPUMF_EVENT_ATTR(cf_z14, TLB2_ENGINES_BUSY, 0x008b);
+CPUMF_EVENT_ATTR(cf_z14, TX_C_TEND, 0x008c);
+CPUMF_EVENT_ATTR(cf_z14, TX_NC_TEND, 0x008d);
+CPUMF_EVENT_ATTR(cf_z14, L1C_TLB2_MISSES, 0x008f);
+CPUMF_EVENT_ATTR(cf_z14, L1D_ONCHIP_L3_SOURCED_WRITES, 0x0090);
+CPUMF_EVENT_ATTR(cf_z14, L1D_ONCHIP_MEMORY_SOURCED_WRITES, 0x0091);
+CPUMF_EVENT_ATTR(cf_z14, L1D_ONCHIP_L3_SOURCED_WRITES_IV, 0x0092);
+CPUMF_EVENT_ATTR(cf_z14, L1D_ONCLUSTER_L3_SOURCED_WRITES, 0x0093);
+CPUMF_EVENT_ATTR(cf_z14, L1D_ONCLUSTER_MEMORY_SOURCED_WRITES, 0x0094);
+CPUMF_EVENT_ATTR(cf_z14, L1D_ONCLUSTER_L3_SOURCED_WRITES_IV, 0x0095);
+CPUMF_EVENT_ATTR(cf_z14, L1D_OFFCLUSTER_L3_SOURCED_WRITES, 0x0096);
+CPUMF_EVENT_ATTR(cf_z14, L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES, 0x0097);
+CPUMF_EVENT_ATTR(cf_z14, L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV, 0x0098);
+CPUMF_EVENT_ATTR(cf_z14, L1D_OFFDRAWER_L3_SOURCED_WRITES, 0x0099);
+CPUMF_EVENT_ATTR(cf_z14, L1D_OFFDRAWER_MEMORY_SOURCED_WRITES, 0x009a);
+CPUMF_EVENT_ATTR(cf_z14, L1D_OFFDRAWER_L3_SOURCED_WRITES_IV, 0x009b);
+CPUMF_EVENT_ATTR(cf_z14, L1D_ONDRAWER_L4_SOURCED_WRITES, 0x009c);
+CPUMF_EVENT_ATTR(cf_z14, L1D_OFFDRAWER_L4_SOURCED_WRITES, 0x009d);
+CPUMF_EVENT_ATTR(cf_z14, L1D_ONCHIP_L3_SOURCED_WRITES_RO, 0x009e);
+CPUMF_EVENT_ATTR(cf_z14, L1I_ONCHIP_L3_SOURCED_WRITES, 0x00a2);
+CPUMF_EVENT_ATTR(cf_z14, L1I_ONCHIP_MEMORY_SOURCED_WRITES, 0x00a3);
+CPUMF_EVENT_ATTR(cf_z14, L1I_ONCHIP_L3_SOURCED_WRITES_IV, 0x00a4);
+CPUMF_EVENT_ATTR(cf_z14, L1I_ONCLUSTER_L3_SOURCED_WRITES, 0x00a5);
+CPUMF_EVENT_ATTR(cf_z14, L1I_ONCLUSTER_MEMORY_SOURCED_WRITES, 0x00a6);
+CPUMF_EVENT_ATTR(cf_z14, L1I_ONCLUSTER_L3_SOURCED_WRITES_IV, 0x00a7);
+CPUMF_EVENT_ATTR(cf_z14, L1I_OFFCLUSTER_L3_SOURCED_WRITES, 0x00a8);
+CPUMF_EVENT_ATTR(cf_z14, L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES, 0x00a9);
+CPUMF_EVENT_ATTR(cf_z14, L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV, 0x00aa);
+CPUMF_EVENT_ATTR(cf_z14, L1I_OFFDRAWER_L3_SOURCED_WRITES, 0x00ab);
+CPUMF_EVENT_ATTR(cf_z14, L1I_OFFDRAWER_MEMORY_SOURCED_WRITES, 0x00ac);
+CPUMF_EVENT_ATTR(cf_z14, L1I_OFFDRAWER_L3_SOURCED_WRITES_IV, 0x00ad);
+CPUMF_EVENT_ATTR(cf_z14, L1I_ONDRAWER_L4_SOURCED_WRITES, 0x00ae);
+CPUMF_EVENT_ATTR(cf_z14, L1I_OFFDRAWER_L4_SOURCED_WRITES, 0x00af);
+CPUMF_EVENT_ATTR(cf_z14, BCD_DFP_EXECUTION_SLOTS, 0x00e0);
+CPUMF_EVENT_ATTR(cf_z14, VX_BCD_EXECUTION_SLOTS, 0x00e1);
+CPUMF_EVENT_ATTR(cf_z14, DECIMAL_INSTRUCTIONS, 0x00e2);
+CPUMF_EVENT_ATTR(cf_z14, LAST_HOST_TRANSLATIONS, 0x00e9);
+CPUMF_EVENT_ATTR(cf_z14, TX_NC_TABORT, 0x00f3);
+CPUMF_EVENT_ATTR(cf_z14, TX_C_TABORT_NO_SPECIAL, 0x00f4);
+CPUMF_EVENT_ATTR(cf_z14, TX_C_TABORT_SPECIAL, 0x00f5);
+CPUMF_EVENT_ATTR(cf_z14, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
+CPUMF_EVENT_ATTR(cf_z14, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
 
-static struct attribute *cpumcf_pmu_event_attr[] __initdata = {
-       CPUMF_EVENT_PTR(cf, CPU_CYCLES),
-       CPUMF_EVENT_PTR(cf, INSTRUCTIONS),
-       CPUMF_EVENT_PTR(cf, L1I_DIR_WRITES),
-       CPUMF_EVENT_PTR(cf, L1I_PENALTY_CYCLES),
-       CPUMF_EVENT_PTR(cf, PROBLEM_STATE_CPU_CYCLES),
-       CPUMF_EVENT_PTR(cf, PROBLEM_STATE_INSTRUCTIONS),
-       CPUMF_EVENT_PTR(cf, PROBLEM_STATE_L1I_DIR_WRITES),
-       CPUMF_EVENT_PTR(cf, PROBLEM_STATE_L1I_PENALTY_CYCLES),
-       CPUMF_EVENT_PTR(cf, PROBLEM_STATE_L1D_DIR_WRITES),
-       CPUMF_EVENT_PTR(cf, PROBLEM_STATE_L1D_PENALTY_CYCLES),
-       CPUMF_EVENT_PTR(cf, L1D_DIR_WRITES),
-       CPUMF_EVENT_PTR(cf, L1D_PENALTY_CYCLES),
-       CPUMF_EVENT_PTR(cf, PRNG_FUNCTIONS),
-       CPUMF_EVENT_PTR(cf, PRNG_CYCLES),
-       CPUMF_EVENT_PTR(cf, PRNG_BLOCKED_FUNCTIONS),
-       CPUMF_EVENT_PTR(cf, PRNG_BLOCKED_CYCLES),
-       CPUMF_EVENT_PTR(cf, SHA_FUNCTIONS),
-       CPUMF_EVENT_PTR(cf, SHA_CYCLES),
-       CPUMF_EVENT_PTR(cf, SHA_BLOCKED_FUNCTIONS),
-       CPUMF_EVENT_PTR(cf, SHA_BLOCKED_CYCLES),
-       CPUMF_EVENT_PTR(cf, DEA_FUNCTIONS),
-       CPUMF_EVENT_PTR(cf, DEA_CYCLES),
-       CPUMF_EVENT_PTR(cf, DEA_BLOCKED_FUNCTIONS),
-       CPUMF_EVENT_PTR(cf, DEA_BLOCKED_CYCLES),
-       CPUMF_EVENT_PTR(cf, AES_FUNCTIONS),
-       CPUMF_EVENT_PTR(cf, AES_CYCLES),
-       CPUMF_EVENT_PTR(cf, AES_BLOCKED_FUNCTIONS),
-       CPUMF_EVENT_PTR(cf, AES_BLOCKED_CYCLES),
+static struct attribute *cpumcf_fvn1_pmu_event_attr[] __initdata = {
+       CPUMF_EVENT_PTR(cf_fvn1, CPU_CYCLES),
+       CPUMF_EVENT_PTR(cf_fvn1, INSTRUCTIONS),
+       CPUMF_EVENT_PTR(cf_fvn1, L1I_DIR_WRITES),
+       CPUMF_EVENT_PTR(cf_fvn1, L1I_PENALTY_CYCLES),
+       CPUMF_EVENT_PTR(cf_fvn1, PROBLEM_STATE_CPU_CYCLES),
+       CPUMF_EVENT_PTR(cf_fvn1, PROBLEM_STATE_INSTRUCTIONS),
+       CPUMF_EVENT_PTR(cf_fvn1, PROBLEM_STATE_L1I_DIR_WRITES),
+       CPUMF_EVENT_PTR(cf_fvn1, PROBLEM_STATE_L1I_PENALTY_CYCLES),
+       CPUMF_EVENT_PTR(cf_fvn1, PROBLEM_STATE_L1D_DIR_WRITES),
+       CPUMF_EVENT_PTR(cf_fvn1, PROBLEM_STATE_L1D_PENALTY_CYCLES),
+       CPUMF_EVENT_PTR(cf_fvn1, L1D_DIR_WRITES),
+       CPUMF_EVENT_PTR(cf_fvn1, L1D_PENALTY_CYCLES),
+       NULL,
+};
+
+static struct attribute *cpumcf_fvn3_pmu_event_attr[] __initdata = {
+       CPUMF_EVENT_PTR(cf_fvn3, CPU_CYCLES),
+       CPUMF_EVENT_PTR(cf_fvn3, INSTRUCTIONS),
+       CPUMF_EVENT_PTR(cf_fvn3, L1I_DIR_WRITES),
+       CPUMF_EVENT_PTR(cf_fvn3, L1I_PENALTY_CYCLES),
+       CPUMF_EVENT_PTR(cf_fvn3, PROBLEM_STATE_CPU_CYCLES),
+       CPUMF_EVENT_PTR(cf_fvn3, PROBLEM_STATE_INSTRUCTIONS),
+       CPUMF_EVENT_PTR(cf_fvn3, L1D_DIR_WRITES),
+       CPUMF_EVENT_PTR(cf_fvn3, L1D_PENALTY_CYCLES),
+       NULL,
+};
+
+static struct attribute *cpumcf_svn_generic_pmu_event_attr[] __initdata = {
+       CPUMF_EVENT_PTR(cf_svn_generic, PRNG_FUNCTIONS),
+       CPUMF_EVENT_PTR(cf_svn_generic, PRNG_CYCLES),
+       CPUMF_EVENT_PTR(cf_svn_generic, PRNG_BLOCKED_FUNCTIONS),
+       CPUMF_EVENT_PTR(cf_svn_generic, PRNG_BLOCKED_CYCLES),
+       CPUMF_EVENT_PTR(cf_svn_generic, SHA_FUNCTIONS),
+       CPUMF_EVENT_PTR(cf_svn_generic, SHA_CYCLES),
+       CPUMF_EVENT_PTR(cf_svn_generic, SHA_BLOCKED_FUNCTIONS),
+       CPUMF_EVENT_PTR(cf_svn_generic, SHA_BLOCKED_CYCLES),
+       CPUMF_EVENT_PTR(cf_svn_generic, DEA_FUNCTIONS),
+       CPUMF_EVENT_PTR(cf_svn_generic, DEA_CYCLES),
+       CPUMF_EVENT_PTR(cf_svn_generic, DEA_BLOCKED_FUNCTIONS),
+       CPUMF_EVENT_PTR(cf_svn_generic, DEA_BLOCKED_CYCLES),
+       CPUMF_EVENT_PTR(cf_svn_generic, AES_FUNCTIONS),
+       CPUMF_EVENT_PTR(cf_svn_generic, AES_CYCLES),
+       CPUMF_EVENT_PTR(cf_svn_generic, AES_BLOCKED_FUNCTIONS),
+       CPUMF_EVENT_PTR(cf_svn_generic, AES_BLOCKED_CYCLES),
        NULL,
 };
 
@@ -353,6 +430,63 @@ static struct attribute *cpumcf_z13_pmu_event_attr[] __initdata = {
        NULL,
 };
 
+static struct attribute *cpumcf_z14_pmu_event_attr[] __initdata = {
+       CPUMF_EVENT_PTR(cf_z14, L1D_WRITES_RO_EXCL),
+       CPUMF_EVENT_PTR(cf_z14, DTLB2_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, DTLB2_MISSES),
+       CPUMF_EVENT_PTR(cf_z14, DTLB2_HPAGE_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, DTLB2_GPAGE_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_L2D_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, ITLB2_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, ITLB2_MISSES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_L2I_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, TLB2_PTE_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, TLB2_CRSTE_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, TLB2_ENGINES_BUSY),
+       CPUMF_EVENT_PTR(cf_z14, TX_C_TEND),
+       CPUMF_EVENT_PTR(cf_z14, TX_NC_TEND),
+       CPUMF_EVENT_PTR(cf_z14, L1C_TLB2_MISSES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_ONCHIP_L3_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_ONCHIP_MEMORY_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_ONCHIP_L3_SOURCED_WRITES_IV),
+       CPUMF_EVENT_PTR(cf_z14, L1D_ONCLUSTER_L3_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_ONCLUSTER_MEMORY_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_ONCLUSTER_L3_SOURCED_WRITES_IV),
+       CPUMF_EVENT_PTR(cf_z14, L1D_OFFCLUSTER_L3_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV),
+       CPUMF_EVENT_PTR(cf_z14, L1D_OFFDRAWER_L3_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_OFFDRAWER_MEMORY_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_OFFDRAWER_L3_SOURCED_WRITES_IV),
+       CPUMF_EVENT_PTR(cf_z14, L1D_ONDRAWER_L4_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_OFFDRAWER_L4_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1D_ONCHIP_L3_SOURCED_WRITES_RO),
+       CPUMF_EVENT_PTR(cf_z14, L1I_ONCHIP_L3_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_ONCHIP_MEMORY_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_ONCHIP_L3_SOURCED_WRITES_IV),
+       CPUMF_EVENT_PTR(cf_z14, L1I_ONCLUSTER_L3_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_ONCLUSTER_MEMORY_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_ONCLUSTER_L3_SOURCED_WRITES_IV),
+       CPUMF_EVENT_PTR(cf_z14, L1I_OFFCLUSTER_L3_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV),
+       CPUMF_EVENT_PTR(cf_z14, L1I_OFFDRAWER_L3_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_OFFDRAWER_MEMORY_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_OFFDRAWER_L3_SOURCED_WRITES_IV),
+       CPUMF_EVENT_PTR(cf_z14, L1I_ONDRAWER_L4_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, L1I_OFFDRAWER_L4_SOURCED_WRITES),
+       CPUMF_EVENT_PTR(cf_z14, BCD_DFP_EXECUTION_SLOTS),
+       CPUMF_EVENT_PTR(cf_z14, VX_BCD_EXECUTION_SLOTS),
+       CPUMF_EVENT_PTR(cf_z14, DECIMAL_INSTRUCTIONS),
+       CPUMF_EVENT_PTR(cf_z14, LAST_HOST_TRANSLATIONS),
+       CPUMF_EVENT_PTR(cf_z14, TX_NC_TABORT),
+       CPUMF_EVENT_PTR(cf_z14, TX_C_TABORT_NO_SPECIAL),
+       CPUMF_EVENT_PTR(cf_z14, TX_C_TABORT_SPECIAL),
+       CPUMF_EVENT_PTR(cf_z14, MT_DIAG_CYCLES_ONE_THR_ACTIVE),
+       CPUMF_EVENT_PTR(cf_z14, MT_DIAG_CYCLES_TWO_THR_ACTIVE),
+       NULL,
+};
+
 /* END: CPUM_CF COUNTER DEFINITIONS ===================================== */
 
 static struct attribute_group cpumcf_pmu_events_group = {
@@ -379,7 +513,8 @@ static const struct attribute_group *cpumcf_pmu_attr_groups[] = {
 
 
 static __init struct attribute **merge_attr(struct attribute **a,
-                                           struct attribute **b)
+                                           struct attribute **b,
+                                           struct attribute **c)
 {
        struct attribute **new;
        int j, i;
@@ -388,6 +523,8 @@ static __init struct attribute **merge_attr(struct attribute **a,
                ;
        for (i = 0; b[i]; i++)
                j++;
+       for (i = 0; c[i]; i++)
+               j++;
        j++;
 
        new = kmalloc(sizeof(struct attribute *) * j, GFP_KERNEL);
@@ -398,6 +535,8 @@ static __init struct attribute **merge_attr(struct attribute **a,
                new[j++] = a[i];
        for (i = 0; b[i]; i++)
                new[j++] = b[i];
+       for (i = 0; c[i]; i++)
+               new[j++] = c[i];
        new[j] = NULL;
 
        return new;
@@ -405,10 +544,26 @@ static __init struct attribute **merge_attr(struct attribute **a,
 
 __init const struct attribute_group **cpumf_cf_event_group(void)
 {
-       struct attribute **combined, **model;
+       struct attribute **combined, **model, **cfvn, **csvn;
        struct attribute *none[] = { NULL };
+       struct cpumf_ctr_info ci;
        struct cpuid cpu_id;
 
+       /* Determine generic counters set(s) */
+       qctri(&ci);
+       switch (ci.cfvn) {
+       case 1:
+               cfvn = cpumcf_fvn1_pmu_event_attr;
+               break;
+       case 3:
+               cfvn = cpumcf_fvn3_pmu_event_attr;
+               break;
+       default:
+               cfvn = none;
+       }
+       csvn = cpumcf_svn_generic_pmu_event_attr;
+
+       /* Determine model-specific counter set(s) */
        get_cpu_id(&cpu_id);
        switch (cpu_id.machine) {
        case 0x2097:
@@ -427,12 +582,15 @@ __init const struct attribute_group **cpumf_cf_event_group(void)
        case 0x2965:
                model = cpumcf_z13_pmu_event_attr;
                break;
+       case 0x3906:
+               model = cpumcf_z14_pmu_event_attr;
+               break;
        default:
                model = none;
                break;
        }
 
-       combined = merge_attr(cpumcf_pmu_event_attr, model);
+       combined = merge_attr(cfvn, csvn, model);
        if (combined)
                cpumcf_pmu_events_group.attrs = combined;
        return cpumcf_pmu_attr_groups;
index 7e1e40323b78e1bb7a3910e1191dfbe40027b748..bd4bbf61aaf368cba69d27edb2cd80dfac014493 100644 (file)
@@ -823,12 +823,8 @@ static int cpumsf_pmu_event_init(struct perf_event *event)
        }
 
        /* Check online status of the CPU to which the event is pinned */
-       if (event->cpu >= 0) {
-               if ((unsigned int)event->cpu >= nr_cpumask_bits)
+       if (event->cpu >= 0 && !cpu_online(event->cpu))
                        return -ENODEV;
-               if (!cpu_online(event->cpu))
-                       return -ENODEV;
-       }
 
        /* Force reset of idle/hv excludes regardless of what the
         * user requested.
index a4a84fb080468374afa966475d4f2fb710da536e..70576a2f69cf6851ea2917197ed418de1459bf44 100644 (file)
@@ -44,27 +44,14 @@ asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
 
 extern void kernel_thread_starter(void);
 
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(struct task_struct *tsk)
-{
-       if (tsk == current) {
-               exit_thread_runtime_instr();
-               exit_thread_gs();
-       }
-}
-
 void flush_thread(void)
 {
 }
 
-void release_thread(struct task_struct *dead_task)
-{
-}
-
 void arch_release_task_struct(struct task_struct *tsk)
 {
+       runtime_instr_release(tsk);
+       guarded_storage_release(tsk);
 }
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
@@ -100,6 +87,7 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long new_stackp,
        memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
        memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
        clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
+       p->thread.per_flags = 0;
        /* Initialize per thread user and system timer values */
        p->thread.user_timer = 0;
        p->thread.guest_timer = 0;
index 1427d60ce628ce91ce2ff4f6b28994a0442bfd7d..26c0523c14882d1b967ef8cb81a5cb6b387017a2 100644 (file)
@@ -31,6 +31,9 @@
 #include <linux/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/switch_to.h>
+#include <asm/runtime_instr.h>
+#include <asm/facility.h>
+
 #include "entry.h"
 
 #ifdef CONFIG_COMPAT
@@ -45,42 +48,42 @@ void update_cr_regs(struct task_struct *task)
        struct pt_regs *regs = task_pt_regs(task);
        struct thread_struct *thread = &task->thread;
        struct per_regs old, new;
-       unsigned long cr0_old, cr0_new;
-       unsigned long cr2_old, cr2_new;
+       union ctlreg0 cr0_old, cr0_new;
+       union ctlreg2 cr2_old, cr2_new;
        int cr0_changed, cr2_changed;
 
-       __ctl_store(cr0_old, 0, 0);
-       __ctl_store(cr2_old, 2, 2);
+       __ctl_store(cr0_old.val, 0, 0);
+       __ctl_store(cr2_old.val, 2, 2);
        cr0_new = cr0_old;
        cr2_new = cr2_old;
        /* Take care of the enable/disable of transactional execution. */
        if (MACHINE_HAS_TE) {
                /* Set or clear transaction execution TXC bit 8. */
-               cr0_new |= (1UL << 55);
+               cr0_new.tcx = 1;
                if (task->thread.per_flags & PER_FLAG_NO_TE)
-                       cr0_new &= ~(1UL << 55);
+                       cr0_new.tcx = 0;
                /* Set or clear transaction execution TDC bits 62 and 63. */
-               cr2_new &= ~3UL;
+               cr2_new.tdc = 0;
                if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
                        if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
-                               cr2_new |= 1UL;
+                               cr2_new.tdc = 1;
                        else
-                               cr2_new |= 2UL;
+                               cr2_new.tdc = 2;
                }
        }
        /* Take care of enable/disable of guarded storage. */
        if (MACHINE_HAS_GS) {
-               cr2_new &= ~(1UL << 4);
+               cr2_new.gse = 0;
                if (task->thread.gs_cb)
-                       cr2_new |= (1UL << 4);
+                       cr2_new.gse = 1;
        }
        /* Load control register 0/2 iff changed */
-       cr0_changed = cr0_new != cr0_old;
-       cr2_changed = cr2_new != cr2_old;
+       cr0_changed = cr0_new.val != cr0_old.val;
+       cr2_changed = cr2_new.val != cr2_old.val;
        if (cr0_changed)
-               __ctl_load(cr0_new, 0, 0);
+               __ctl_load(cr0_new.val, 0, 0);
        if (cr2_changed)
-               __ctl_load(cr2_new, 2, 2);
+               __ctl_load(cr2_new.val, 2, 2);
        /* Copy user specified PER registers */
        new.control = thread->per_user.control;
        new.start = thread->per_user.start;
@@ -1172,26 +1175,37 @@ static int s390_gs_cb_set(struct task_struct *target,
                          unsigned int pos, unsigned int count,
                          const void *kbuf, const void __user *ubuf)
 {
-       struct gs_cb *data = target->thread.gs_cb;
+       struct gs_cb gs_cb = { }, *data = NULL;
        int rc;
 
        if (!MACHINE_HAS_GS)
                return -ENODEV;
-       if (!data) {
+       if (!target->thread.gs_cb) {
                data = kzalloc(sizeof(*data), GFP_KERNEL);
                if (!data)
                        return -ENOMEM;
-               data->gsd = 25;
-               target->thread.gs_cb = data;
-               if (target == current)
-                       __ctl_set_bit(2, 4);
-       } else if (target == current) {
-               save_gs_cb(data);
        }
+       if (!target->thread.gs_cb)
+               gs_cb.gsd = 25;
+       else if (target == current)
+               save_gs_cb(&gs_cb);
+       else
+               gs_cb = *target->thread.gs_cb;
        rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                               data, 0, sizeof(struct gs_cb));
-       if (target == current)
-               restore_gs_cb(data);
+                               &gs_cb, 0, sizeof(gs_cb));
+       if (rc) {
+               kfree(data);
+               return -EFAULT;
+       }
+       preempt_disable();
+       if (!target->thread.gs_cb)
+               target->thread.gs_cb = data;
+       *target->thread.gs_cb = gs_cb;
+       if (target == current) {
+               __ctl_set_bit(2, 4);
+               restore_gs_cb(target->thread.gs_cb);
+       }
+       preempt_enable();
        return rc;
 }
 
@@ -1229,6 +1243,96 @@ static int s390_gs_bc_set(struct task_struct *target,
                                  data, 0, sizeof(struct gs_cb));
 }
 
+static bool is_ri_cb_valid(struct runtime_instr_cb *cb)
+{
+       return (cb->rca & 0x1f) == 0 &&
+               (cb->roa & 0xfff) == 0 &&
+               (cb->rla & 0xfff) == 0xfff &&
+               cb->s == 1 &&
+               cb->k == 1 &&
+               cb->h == 0 &&
+               cb->reserved1 == 0 &&
+               cb->ps == 1 &&
+               cb->qs == 0 &&
+               cb->pc == 1 &&
+               cb->qc == 0 &&
+               cb->reserved2 == 0 &&
+               cb->key == PAGE_DEFAULT_KEY &&
+               cb->reserved3 == 0 &&
+               cb->reserved4 == 0 &&
+               cb->reserved5 == 0 &&
+               cb->reserved6 == 0 &&
+               cb->reserved7 == 0 &&
+               cb->reserved8 == 0 &&
+               cb->rla >= cb->roa &&
+               cb->rca >= cb->roa &&
+               cb->rca <= cb->rla+1 &&
+               cb->m < 3;
+}
+
+static int s390_runtime_instr_get(struct task_struct *target,
+                               const struct user_regset *regset,
+                               unsigned int pos, unsigned int count,
+                               void *kbuf, void __user *ubuf)
+{
+       struct runtime_instr_cb *data = target->thread.ri_cb;
+
+       if (!test_facility(64))
+               return -ENODEV;
+       if (!data)
+               return -ENODATA;
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  data, 0, sizeof(struct runtime_instr_cb));
+}
+
+static int s390_runtime_instr_set(struct task_struct *target,
+                                 const struct user_regset *regset,
+                                 unsigned int pos, unsigned int count,
+                                 const void *kbuf, const void __user *ubuf)
+{
+       struct runtime_instr_cb ri_cb = { }, *data = NULL;
+       int rc;
+
+       if (!test_facility(64))
+               return -ENODEV;
+
+       if (!target->thread.ri_cb) {
+               data = kzalloc(sizeof(*data), GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+       }
+
+       if (target->thread.ri_cb) {
+               if (target == current)
+                       store_runtime_instr_cb(&ri_cb);
+               else
+                       ri_cb = *target->thread.ri_cb;
+       }
+
+       rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &ri_cb, 0, sizeof(struct runtime_instr_cb));
+       if (rc) {
+               kfree(data);
+               return -EFAULT;
+       }
+
+       if (!is_ri_cb_valid(&ri_cb)) {
+               kfree(data);
+               return -EINVAL;
+       }
+
+       preempt_disable();
+       if (!target->thread.ri_cb)
+               target->thread.ri_cb = data;
+       *target->thread.ri_cb = ri_cb;
+       if (target == current)
+               load_runtime_instr_cb(target->thread.ri_cb);
+       preempt_enable();
+
+       return 0;
+}
+
 static const struct user_regset s390_regsets[] = {
        {
                .core_note_type = NT_PRSTATUS,
@@ -1302,6 +1406,14 @@ static const struct user_regset s390_regsets[] = {
                .get = s390_gs_bc_get,
                .set = s390_gs_bc_set,
        },
+       {
+               .core_note_type = NT_S390_RI_CB,
+               .n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
+               .size = sizeof(__u64),
+               .align = sizeof(__u64),
+               .get = s390_runtime_instr_get,
+               .set = s390_runtime_instr_set,
+       },
 };
 
 static const struct user_regset_view user_s390_view = {
@@ -1538,6 +1650,14 @@ static const struct user_regset s390_compat_regsets[] = {
                .get = s390_gs_cb_get,
                .set = s390_gs_cb_set,
        },
+       {
+               .core_note_type = NT_S390_RI_CB,
+               .n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
+               .size = sizeof(__u64),
+               .align = sizeof(__u64),
+               .get = s390_runtime_instr_get,
+               .set = s390_runtime_instr_set,
+       },
 };
 
 static const struct user_regset_view user_s390_compat_view = {
index ca37e5d5b40cc3ff37ec4873fdd2ed81c69f4f80..9c2c96da23d0292ebfae28de8f50219d47e7d8bf 100644 (file)
@@ -29,7 +29,6 @@
 ENTRY(relocate_kernel)
                basr    %r13,0          # base address
        .base:
-               stnsm   sys_msk-.base(%r13),0xfb        # disable DAT
                stctg   %c0,%c15,ctlregs-.base(%r13)
                stmg    %r0,%r15,gprregs-.base(%r13)
                lghi    %r0,3
@@ -103,8 +102,6 @@ ENTRY(relocate_kernel)
                .align  8
        load_psw:
                .long   0x00080000,0x80000000
-       sys_msk:
-               .quad   0
        ctlregs:
                .rept   16
                .quad   0
index 32aefb215e59ffead32c88a02224da70200a5643..09f5bf0d5c0c87bc0bfe9a78f9d7edca7ef47c56 100644 (file)
 /* empty control block to disable RI by loading it */
 struct runtime_instr_cb runtime_instr_empty_cb;
 
+void runtime_instr_release(struct task_struct *tsk)
+{
+       kfree(tsk->thread.ri_cb);
+}
+
 static void disable_runtime_instr(void)
 {
-       struct pt_regs *regs = task_pt_regs(current);
+       struct task_struct *task = current;
+       struct pt_regs *regs;
 
+       if (!task->thread.ri_cb)
+               return;
+       regs = task_pt_regs(task);
+       preempt_disable();
        load_runtime_instr_cb(&runtime_instr_empty_cb);
+       kfree(task->thread.ri_cb);
+       task->thread.ri_cb = NULL;
+       preempt_enable();
 
        /*
         * Make sure the RI bit is deleted from the PSW. If the user did not
@@ -37,24 +50,13 @@ static void disable_runtime_instr(void)
 
 static void init_runtime_instr_cb(struct runtime_instr_cb *cb)
 {
-       cb->buf_limit = 0xfff;
-       cb->pstate = 1;
-       cb->pstate_set_buf = 1;
-       cb->pstate_sample = 1;
-       cb->pstate_collect = 1;
+       cb->rla = 0xfff;
+       cb->s = 1;
+       cb->k = 1;
+       cb->ps = 1;
+       cb->pc = 1;
        cb->key = PAGE_DEFAULT_KEY;
-       cb->valid = 1;
-}
-
-void exit_thread_runtime_instr(void)
-{
-       struct task_struct *task = current;
-
-       if (!task->thread.ri_cb)
-               return;
-       disable_runtime_instr();
-       kfree(task->thread.ri_cb);
-       task->thread.ri_cb = NULL;
+       cb->v = 1;
 }
 
 SYSCALL_DEFINE1(s390_runtime_instr, int, command)
@@ -65,9 +67,7 @@ SYSCALL_DEFINE1(s390_runtime_instr, int, command)
                return -EOPNOTSUPP;
 
        if (command == S390_RUNTIME_INSTR_STOP) {
-               preempt_disable();
-               exit_thread_runtime_instr();
-               preempt_enable();
+               disable_runtime_instr();
                return 0;
        }
 
index 164a1e16b53edfb2d60da9e1a459630023bc392a..090053cf279bb1d7077082dcc1a90ababb716478 100644 (file)
 #include <asm/mmu_context.h>
 #include <asm/cpcmd.h>
 #include <asm/lowcore.h>
+#include <asm/nmi.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/sections.h>
 #include <asm/ebcdic.h>
-#include <asm/kvm_virtio.h>
 #include <asm/diag.h>
 #include <asm/os_info.h>
 #include <asm/sclp.h>
 #include <asm/sysinfo.h>
 #include <asm/numa.h>
+#include <asm/alternative.h>
 #include "entry.h"
 
 /*
@@ -339,16 +340,8 @@ static void __init setup_lowcore(void)
        lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
        memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
               MAX_FACILITY_BIT/8);
-       if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
-               unsigned long bits, size;
-
-               bits = MACHINE_HAS_GS ? 11 : 10;
-               size = 1UL << bits;
-               lc->mcesad = (__u64) memblock_virt_alloc(size, size);
-               if (MACHINE_HAS_GS)
-                       lc->mcesad |= bits;
-       }
-       lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];
+       nmi_alloc_boot_cpu(lc);
+       vdso_alloc_boot_cpu(lc);
        lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
        lc->async_enter_timer = S390_lowcore.async_enter_timer;
        lc->exit_timer = S390_lowcore.exit_timer;
@@ -380,6 +373,8 @@ static void __init setup_lowcore(void)
 
 #ifdef CONFIG_SMP
        lc->spinlock_lockval = arch_spin_lockval(0);
+       lc->spinlock_index = 0;
+       arch_spin_lock_setup(0);
 #endif
 
        set_prefix((u32)(unsigned long) lc);
@@ -764,7 +759,7 @@ static int __init setup_hwcaps(void)
        /*
         * Transactional execution support HWCAP_S390_TE is bit 10.
         */
-       if (test_facility(50) && test_facility(73))
+       if (MACHINE_HAS_TE)
                elf_hwcap |= HWCAP_S390_TE;
 
        /*
@@ -955,6 +950,8 @@ void __init setup_arch(char **cmdline_p)
        conmode_default();
        set_preferred_console();
 
+       apply_alternative_instructions();
+
        /* Setup zfcpdump support */
        setup_zfcpdump();
 
index 092c4154abd74c0ceda7592946f91a64674fdb58..cd4334e80b64cdb7908842f44015183be17c62f2 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/sched/task_stack.h>
 #include <linux/crash_dump.h>
 #include <linux/memblock.h>
+#include <linux/kprobes.h>
 #include <asm/asm-offsets.h>
 #include <asm/diag.h>
 #include <asm/switch_to.h>
@@ -81,8 +82,6 @@ struct pcpu {
 static u8 boot_core_type;
 static struct pcpu pcpu_devices[NR_CPUS];
 
-static struct kmem_cache *pcpu_mcesa_cache;
-
 unsigned int smp_cpu_mt_shift;
 EXPORT_SYMBOL(smp_cpu_mt_shift);
 
@@ -193,10 +192,8 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
 static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
 {
        unsigned long async_stack, panic_stack;
-       unsigned long mcesa_origin, mcesa_bits;
        struct lowcore *lc;
 
-       mcesa_origin = mcesa_bits = 0;
        if (pcpu != &pcpu_devices[0]) {
                pcpu->lowcore = (struct lowcore *)
                        __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
@@ -204,39 +201,30 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
                panic_stack = __get_free_page(GFP_KERNEL);
                if (!pcpu->lowcore || !panic_stack || !async_stack)
                        goto out;
-               if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
-                       mcesa_origin = (unsigned long)
-                               kmem_cache_alloc(pcpu_mcesa_cache, GFP_KERNEL);
-                       if (!mcesa_origin)
-                               goto out;
-                       /* The pointer is stored with mcesa_bits ORed in */
-                       kmemleak_not_leak((void *) mcesa_origin);
-                       mcesa_bits = MACHINE_HAS_GS ? 11 : 0;
-               }
        } else {
                async_stack = pcpu->lowcore->async_stack - ASYNC_FRAME_OFFSET;
                panic_stack = pcpu->lowcore->panic_stack - PANIC_FRAME_OFFSET;
-               mcesa_origin = pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK;
-               mcesa_bits = pcpu->lowcore->mcesad & MCESA_LC_MASK;
        }
        lc = pcpu->lowcore;
        memcpy(lc, &S390_lowcore, 512);
        memset((char *) lc + 512, 0, sizeof(*lc) - 512);
        lc->async_stack = async_stack + ASYNC_FRAME_OFFSET;
        lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET;
-       lc->mcesad = mcesa_origin | mcesa_bits;
        lc->cpu_nr = cpu;
        lc->spinlock_lockval = arch_spin_lockval(cpu);
-       if (vdso_alloc_per_cpu(lc))
+       lc->spinlock_index = 0;
+       if (nmi_alloc_per_cpu(lc))
                goto out;
+       if (vdso_alloc_per_cpu(lc))
+               goto out_mcesa;
        lowcore_ptr[cpu] = lc;
        pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc);
        return 0;
+
+out_mcesa:
+       nmi_free_per_cpu(lc);
 out:
        if (pcpu != &pcpu_devices[0]) {
-               if (mcesa_origin)
-                       kmem_cache_free(pcpu_mcesa_cache,
-                                       (void *) mcesa_origin);
                free_page(panic_stack);
                free_pages(async_stack, ASYNC_ORDER);
                free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
@@ -248,17 +236,12 @@ out:
 
 static void pcpu_free_lowcore(struct pcpu *pcpu)
 {
-       unsigned long mcesa_origin;
-
        pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
        lowcore_ptr[pcpu - pcpu_devices] = NULL;
        vdso_free_per_cpu(pcpu->lowcore);
+       nmi_free_per_cpu(pcpu->lowcore);
        if (pcpu == &pcpu_devices[0])
                return;
-       if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
-               mcesa_origin = pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK;
-               kmem_cache_free(pcpu_mcesa_cache, (void *) mcesa_origin);
-       }
        free_page(pcpu->lowcore->panic_stack-PANIC_FRAME_OFFSET);
        free_pages(pcpu->lowcore->async_stack-ASYNC_FRAME_OFFSET, ASYNC_ORDER);
        free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
@@ -274,6 +257,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
        cpumask_set_cpu(cpu, mm_cpumask(&init_mm));
        lc->cpu_nr = cpu;
        lc->spinlock_lockval = arch_spin_lockval(cpu);
+       lc->spinlock_index = 0;
        lc->percpu_offset = __per_cpu_offset[cpu];
        lc->kernel_asce = S390_lowcore.kernel_asce;
        lc->machine_flags = S390_lowcore.machine_flags;
@@ -282,6 +266,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
        save_access_regs((unsigned int *) lc->access_regs_save_area);
        memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
               MAX_FACILITY_BIT/8);
+       arch_spin_lock_setup(cpu);
 }
 
 static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
@@ -423,13 +408,17 @@ void smp_yield_cpu(int cpu)
  * Send cpus emergency shutdown signal. This gives the cpus the
  * opportunity to complete outstanding interrupts.
  */
-static void smp_emergency_stop(cpumask_t *cpumask)
+void notrace smp_emergency_stop(void)
 {
+       cpumask_t cpumask;
        u64 end;
        int cpu;
 
+       cpumask_copy(&cpumask, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpumask);
+
        end = get_tod_clock() + (1000000UL << 12);
-       for_each_cpu(cpu, cpumask) {
+       for_each_cpu(cpu, &cpumask) {
                struct pcpu *pcpu = pcpu_devices + cpu;
                set_bit(ec_stop_cpu, &pcpu->ec_mask);
                while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL,
@@ -438,21 +427,21 @@ static void smp_emergency_stop(cpumask_t *cpumask)
                        cpu_relax();
        }
        while (get_tod_clock() < end) {
-               for_each_cpu(cpu, cpumask)
+               for_each_cpu(cpu, &cpumask)
                        if (pcpu_stopped(pcpu_devices + cpu))
-                               cpumask_clear_cpu(cpu, cpumask);
-               if (cpumask_empty(cpumask))
+                               cpumask_clear_cpu(cpu, &cpumask);
+               if (cpumask_empty(&cpumask))
                        break;
                cpu_relax();
        }
 }
+NOKPROBE_SYMBOL(smp_emergency_stop);
 
 /*
  * Stop all cpus but the current one.
  */
 void smp_send_stop(void)
 {
-       cpumask_t cpumask;
        int cpu;
 
        /* Disable all interrupts/machine checks */
@@ -460,17 +449,16 @@ void smp_send_stop(void)
        trace_hardirqs_off();
 
        debug_set_critical();
-       cpumask_copy(&cpumask, cpu_online_mask);
-       cpumask_clear_cpu(smp_processor_id(), &cpumask);
 
        if (oops_in_progress)
-               smp_emergency_stop(&cpumask);
+               smp_emergency_stop();
 
        /* stop all processors */
-       for_each_cpu(cpu, &cpumask) {
-               struct pcpu *pcpu = pcpu_devices + cpu;
-               pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
-               while (!pcpu_stopped(pcpu))
+       for_each_online_cpu(cpu) {
+               if (cpu == smp_processor_id())
+                       continue;
+               pcpu_sigp_retry(pcpu_devices + cpu, SIGP_STOP, 0);
+               while (!pcpu_stopped(pcpu_devices + cpu))
                        cpu_relax();
        }
 }
@@ -804,6 +792,8 @@ void __init smp_detect_cpus(void)
  */
 static void smp_start_secondary(void *cpuvoid)
 {
+       int cpu = smp_processor_id();
+
        S390_lowcore.last_update_clock = get_tod_clock();
        S390_lowcore.restart_stack = (unsigned long) restart_stack;
        S390_lowcore.restart_fn = (unsigned long) do_restart;
@@ -817,8 +807,12 @@ static void smp_start_secondary(void *cpuvoid)
        init_cpu_timer();
        vtime_init();
        pfault_init();
-       notify_cpu_starting(smp_processor_id());
-       set_cpu_online(smp_processor_id(), true);
+       notify_cpu_starting(cpu);
+       if (topology_cpu_dedicated(cpu))
+               set_cpu_flag(CIF_DEDICATED_CPU);
+       else
+               clear_cpu_flag(CIF_DEDICATED_CPU);
+       set_cpu_online(cpu, true);
        inc_irq_stat(CPU_RST);
        local_irq_enable();
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
@@ -927,22 +921,12 @@ void __init smp_fill_possible_mask(void)
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       unsigned long size;
-
        /* request the 0x1201 emergency signal external interrupt */
        if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt))
                panic("Couldn't request external interrupt 0x1201");
        /* request the 0x1202 external call external interrupt */
        if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt))
                panic("Couldn't request external interrupt 0x1202");
-       /* create slab cache for the machine-check-extended-save-areas */
-       if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
-               size = 1UL << (MACHINE_HAS_GS ? 11 : 10);
-               pcpu_mcesa_cache = kmem_cache_create("nmi_save_areas",
-                                                    size, size, 0, NULL);
-               if (!pcpu_mcesa_cache)
-                       panic("Couldn't create nmi save area cache");
-       }
 }
 
 void __init smp_prepare_boot_cpu(void)
@@ -965,6 +949,7 @@ void __init smp_setup_processor_id(void)
        pcpu_devices[0].address = stap();
        S390_lowcore.cpu_nr = 0;
        S390_lowcore.spinlock_lockval = arch_spin_lockval(0);
+       S390_lowcore.spinlock_index = 0;
 }
 
 /*
similarity index 77%
rename from arch/s390/kvm/sthyi.c
rename to arch/s390/kernel/sthyi.c
index 395926b8c1ed48f7994210c8ff6c7de7ae43e709..12981e197f0125dcaea9f0bcb13f49207be00cec 100644 (file)
@@ -8,22 +8,19 @@
  * Copyright IBM Corp. 2016
  * Author(s): Janosch Frank <frankja@linux.vnet.ibm.com>
  */
-#include <linux/kvm_host.h>
 #include <linux/errno.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
-#include <linux/ratelimit.h>
-
-#include <asm/kvm_host.h>
+#include <linux/syscalls.h>
+#include <linux/mutex.h>
 #include <asm/asm-offsets.h>
 #include <asm/sclp.h>
 #include <asm/diag.h>
 #include <asm/sysinfo.h>
 #include <asm/ebcdic.h>
-
-#include "kvm-s390.h"
-#include "gaccess.h"
-#include "trace.h"
+#include <asm/facility.h>
+#include <asm/sthyi.h>
+#include "entry.h"
 
 #define DED_WEIGHT 0xffff
 /*
@@ -144,6 +141,21 @@ struct lpar_cpu_inf {
        struct cpu_inf ifl;
 };
 
+/*
+ * STHYI requires extensive locking in the higher hypervisors
+ * and is very computational/memory expensive. Therefore we
+ * cache the retrieved data whose valid period is 1s.
+ */
+#define CACHE_VALID_JIFFIES    HZ
+
+struct sthyi_info {
+       void *info;
+       unsigned long end;
+};
+
+static DEFINE_MUTEX(sthyi_mutex);
+static struct sthyi_info sthyi_cache;
+
 static inline u64 cpu_id(u8 ctidx, void *diag224_buf)
 {
        return *((u64 *)(diag224_buf + (ctidx + 1) * DIAG204_CPU_NAME_LEN));
@@ -382,88 +394,124 @@ out:
        vfree(diag204_buf);
 }
 
-static int sthyi(u64 vaddr)
+static int sthyi(u64 vaddr, u64 *rc)
 {
        register u64 code asm("0") = 0;
        register u64 addr asm("2") = vaddr;
+       register u64 rcode asm("3");
        int cc;
 
        asm volatile(
                ".insn   rre,0xB2560000,%[code],%[addr]\n"
                "ipm     %[cc]\n"
                "srl     %[cc],28\n"
-               : [cc] "=d" (cc)
+               : [cc] "=d" (cc), "=d" (rcode)
                : [code] "d" (code), [addr] "a" (addr)
-               : "3", "memory", "cc");
+               : "memory", "cc");
+       *rc = rcode;
        return cc;
 }
 
-int handle_sthyi(struct kvm_vcpu *vcpu)
+static int fill_dst(void *dst, u64 *rc)
 {
-       int reg1, reg2, r = 0;
-       u64 code, addr, cc = 0;
-       struct sthyi_sctns *sctns = NULL;
-
-       if (!test_kvm_facility(vcpu->kvm, 74))
-               return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
+       struct sthyi_sctns *sctns = (struct sthyi_sctns *)dst;
 
        /*
-        * STHYI requires extensive locking in the higher hypervisors
-        * and is very computational/memory expensive. Therefore we
-        * ratelimit the executions per VM.
+        * If the facility is on, we don't want to emulate the instruction.
+        * We ask the hypervisor to provide the data.
         */
-       if (!__ratelimit(&vcpu->kvm->arch.sthyi_limit)) {
-               kvm_s390_retry_instr(vcpu);
+       if (test_facility(74))
+               return sthyi((u64)dst, rc);
+
+       fill_hdr(sctns);
+       fill_stsi(sctns);
+       fill_diag(sctns);
+       *rc = 0;
+       return 0;
+}
+
+static int sthyi_init_cache(void)
+{
+       if (sthyi_cache.info)
                return 0;
-       }
+       sthyi_cache.info = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!sthyi_cache.info)
+               return -ENOMEM;
+       sthyi_cache.end = jiffies - 1; /* expired */
+       return 0;
+}
 
-       kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
-       code = vcpu->run->s.regs.gprs[reg1];
-       addr = vcpu->run->s.regs.gprs[reg2];
+static int sthyi_update_cache(u64 *rc)
+{
+       int r;
 
-       vcpu->stat.instruction_sthyi++;
-       VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
-       trace_kvm_s390_handle_sthyi(vcpu, code, addr);
+       memset(sthyi_cache.info, 0, PAGE_SIZE);
+       r = fill_dst(sthyi_cache.info, rc);
+       if (r)
+               return r;
+       sthyi_cache.end = jiffies + CACHE_VALID_JIFFIES;
+       return r;
+}
 
-       if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
-               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+/*
+ * sthyi_fill - Fill page with data returned by the STHYI instruction
+ *
+ * @dst: Pointer to zeroed page
+ * @rc:  Pointer for storing the return code of the instruction
+ *
+ * Fills the destination with system information returned by the STHYI
+ * instruction. The data is generated by emulation or execution of STHYI,
+ * if available. The return value is the condition code that would be
+ * returned, the rc parameter is the return code which is passed in
+ * register R2 + 1.
+ */
+int sthyi_fill(void *dst, u64 *rc)
+{
+       int r;
 
-       if (code & 0xffff) {
-               cc = 3;
+       mutex_lock(&sthyi_mutex);
+       r = sthyi_init_cache();
+       if (r)
                goto out;
-       }
 
-       if (addr & ~PAGE_MASK)
-               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+       if (time_is_before_jiffies(sthyi_cache.end)) {
+               /* cache expired */
+               r = sthyi_update_cache(rc);
+               if (r)
+                       goto out;
+       }
+       *rc = 0;
+       memcpy(dst, sthyi_cache.info, PAGE_SIZE);
+out:
+       mutex_unlock(&sthyi_mutex);
+       return r;
+}
+EXPORT_SYMBOL_GPL(sthyi_fill);
 
-       sctns = (void *)get_zeroed_page(GFP_KERNEL);
-       if (!sctns)
+SYSCALL_DEFINE4(s390_sthyi, unsigned long, function_code, void __user *, buffer,
+               u64 __user *, return_code, unsigned long, flags)
+{
+       u64 sthyi_rc;
+       void *info;
+       int r;
+
+       if (flags)
+               return -EINVAL;
+       if (function_code != STHYI_FC_CP_IFL_CAP)
+               return -EOPNOTSUPP;
+       info = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!info)
                return -ENOMEM;
-
-       /*
-        * If we are a guest, we don't want to emulate an emulated
-        * instruction. We ask the hypervisor to provide the data.
-        */
-       if (test_facility(74)) {
-               cc = sthyi((u64)sctns);
+       r = sthyi_fill(info, &sthyi_rc);
+       if (r < 0)
+               goto out;
+       if (return_code && put_user(sthyi_rc, return_code)) {
+               r = -EFAULT;
                goto out;
        }
-
-       fill_hdr(sctns);
-       fill_stsi(sctns);
-       fill_diag(sctns);
-
+       if (copy_to_user(buffer, info, PAGE_SIZE))
+               r = -EFAULT;
 out:
-       if (!cc) {
-               r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
-               if (r) {
-                       free_page((unsigned long)sctns);
-                       return kvm_s390_inject_prog_cond(vcpu, r);
-               }
-       }
-
-       free_page((unsigned long)sctns);
-       vcpu->run->s.regs.gprs[reg2 + 1] = cc ? 4 : 0;
-       kvm_s390_set_psw_cc(vcpu, cc);
+       free_page((unsigned long)info);
        return r;
 }
index a8af9c825628e7043d3084126324cbcd26e76d76..ce329c876d8c16d8405d07cd320d0ebd0cbaccdd 100644 (file)
@@ -153,7 +153,7 @@ int pfn_is_nosave(unsigned long pfn)
 {
        unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin));
        unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end));
-       unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1;
+       unsigned long end_rodata_pfn = PFN_DOWN(__pa(&__end_rodata)) - 1;
        unsigned long stext_pfn = PFN_DOWN(__pa(&_stext));
 
        /* Always save lowcore pages (LC protection might be enabled). */
@@ -161,9 +161,9 @@ int pfn_is_nosave(unsigned long pfn)
                return 0;
        if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn)
                return 1;
-       /* Skip memory holes and read-only pages (NSS, DCSS, ...). */
-       if (pfn >= stext_pfn && pfn <= eshared_pfn)
-               return ipl_info.type == IPL_TYPE_NSS ? 1 : 0;
+       /* Skip memory holes and read-only pages (DCSS, ...). */
+       if (pfn >= stext_pfn && pfn <= end_rodata_pfn)
+               return 0;
        if (tprot(PFN_PHYS(pfn)))
                return 1;
        return 0;
index d39f121e67a987ce7037ae3ae11b5f2cca91e5bb..308a7b63348b3f1950c979dd947d22466f89059f 100644 (file)
@@ -389,3 +389,4 @@ SYSCALL(sys_preadv2,compat_sys_preadv2)
 SYSCALL(sys_pwritev2,compat_sys_pwritev2)
 SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */
 SYSCALL(sys_statx,compat_sys_statx)
+SYSCALL(sys_s390_sthyi,compat_sys_s390_sthyi)
index ed0bdd220e1a643788655fbefaef328dd38c7951..f9b393d4a078365ff8f83db8feaae839a20e0274 100644 (file)
@@ -133,6 +133,7 @@ static void add_cpus_to_mask(struct topology_core *tl_core,
                        topo->socket_id = socket->id;
                        topo->core_id = rcore;
                        topo->thread_id = lcpu + i;
+                       topo->dedicated = tl_core->d;
                        cpumask_set_cpu(lcpu + i, &drawer->mask);
                        cpumask_set_cpu(lcpu + i, &book->mask);
                        cpumask_set_cpu(lcpu + i, &socket->mask);
@@ -273,6 +274,14 @@ void store_topology(struct sysinfo_15_1_x *info)
        stsi(info, 15, 1, topology_mnest_limit());
 }
 
+static void __arch_update_dedicated_flag(void *arg)
+{
+       if (topology_cpu_dedicated(smp_processor_id()))
+               set_cpu_flag(CIF_DEDICATED_CPU);
+       else
+               clear_cpu_flag(CIF_DEDICATED_CPU);
+}
+
 static int __arch_update_cpu_topology(void)
 {
        struct sysinfo_15_1_x *info = tl_info;
@@ -298,6 +307,7 @@ int arch_update_cpu_topology(void)
        int cpu, rc;
 
        rc = __arch_update_cpu_topology();
+       on_each_cpu(__arch_update_dedicated_flag, NULL, 0);
        for_each_online_cpu(cpu) {
                dev = get_cpu_device(cpu);
                kobject_uevent(&dev->kobj, KOBJ_CHANGE);
@@ -320,15 +330,14 @@ static void topology_flush_work(void)
        flush_work(&topology_work);
 }
 
-static void topology_timer_fn(unsigned long ignored)
+static void topology_timer_fn(struct timer_list *unused)
 {
        if (ptf(PTF_CHECK))
                topology_schedule_update();
        set_topology_timer();
 }
 
-static struct timer_list topology_timer =
-       TIMER_DEFERRED_INITIALIZER(topology_timer_fn, 0, 0);
+static struct timer_list topology_timer;
 
 static atomic_t topology_poll = ATOMIC_INIT(0);
 
@@ -435,9 +444,39 @@ static struct attribute_group topology_cpu_attr_group = {
        .attrs = topology_cpu_attrs,
 };
 
+static ssize_t cpu_dedicated_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       int cpu = dev->id;
+       ssize_t count;
+
+       mutex_lock(&smp_cpu_state_mutex);
+       count = sprintf(buf, "%d\n", topology_cpu_dedicated(cpu));
+       mutex_unlock(&smp_cpu_state_mutex);
+       return count;
+}
+static DEVICE_ATTR(dedicated, 0444, cpu_dedicated_show, NULL);
+
+static struct attribute *topology_extra_cpu_attrs[] = {
+       &dev_attr_dedicated.attr,
+       NULL,
+};
+
+static struct attribute_group topology_extra_cpu_attr_group = {
+       .attrs = topology_extra_cpu_attrs,
+};
+
 int topology_cpu_init(struct cpu *cpu)
 {
-       return sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group);
+       int rc;
+
+       rc = sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group);
+       if (rc || !MACHINE_HAS_TOPOLOGY)
+               return rc;
+       rc = sysfs_create_group(&cpu->dev.kobj, &topology_extra_cpu_attr_group);
+       if (rc)
+               sysfs_remove_group(&cpu->dev.kobj, &topology_cpu_attr_group);
+       return rc;
 }
 
 static const struct cpumask *cpu_thread_mask(int cpu)
@@ -509,6 +548,7 @@ void __init topology_init_early(void)
        alloc_masks(info, &drawer_info, 3);
 out:
        __arch_update_cpu_topology();
+       __arch_update_dedicated_flag(NULL);
 }
 
 static inline int topology_get_mode(int enabled)
@@ -597,6 +637,7 @@ static struct ctl_table topology_dir_table[] = {
 
 static int __init topology_init(void)
 {
+       timer_setup(&topology_timer, topology_timer_fn, TIMER_DEFERRABLE);
        if (MACHINE_HAS_TOPOLOGY)
                set_topology_timer();
        else
index eacda05b45d7e0ac81b8b60f632a43fc0c268b6c..0520854a4dab27f7ac0feef52311a765686aebf1 100644 (file)
@@ -140,6 +140,20 @@ static void __init vdso_init_data(struct vdso_data *vd)
  */
 #define SEGMENT_ORDER  2
 
+/*
+ * The initial vdso_data structure for the boot CPU. Eventually
+ * it is replaced with a properly allocated structure in vdso_init.
+ * This is necessary because a valid S390_lowcore.vdso_per_cpu_data
+ * pointer is required to be able to return from an interrupt or
+ * program check. See the exit paths in entry.S.
+ */
+struct vdso_data boot_vdso_data __initdata;
+
+void __init vdso_alloc_boot_cpu(struct lowcore *lowcore)
+{
+       lowcore->vdso_per_cpu_data = (unsigned long) &boot_vdso_data;
+}
+
 int vdso_alloc_per_cpu(struct lowcore *lowcore)
 {
        unsigned long segment_table, page_table, page_frame;
@@ -166,10 +180,8 @@ int vdso_alloc_per_cpu(struct lowcore *lowcore)
        vd->node_id = cpu_to_node(vd->cpu_nr);
 
        /* Set up access register mode page table */
-       clear_table((unsigned long *) segment_table, _SEGMENT_ENTRY_EMPTY,
-                   PAGE_SIZE << SEGMENT_ORDER);
-       clear_table((unsigned long *) page_table, _PAGE_INVALID,
-                   256*sizeof(unsigned long));
+       memset64((u64 *)segment_table, _SEGMENT_ENTRY_EMPTY, _CRST_ENTRIES);
+       memset64((u64 *)page_table, _PAGE_INVALID, PTRS_PER_PTE);
 
        *(unsigned long *) segment_table = _SEGMENT_ENTRY + page_table;
        *(unsigned long *) page_table = _PAGE_PROTECT + page_frame;
index 96a713a470e77a67a56c0b18f3db29b02ccf2471..a049ff005f03df571ab58a52180b42e44b63bf6d 100644 (file)
@@ -60,12 +60,7 @@ SECTIONS
 
        RO_DATA_SECTION(PAGE_SIZE)
 
-#ifdef CONFIG_SHARED_KERNEL
-       . = ALIGN(0x100000);    /* VM shared segments are 1MB aligned */
-#endif
-
        . = ALIGN(PAGE_SIZE);
-       _eshared = .;           /* End of shareable data */
        _sdata = .;             /* Start of data section */
 
        . = ALIGN(PAGE_SIZE);
@@ -105,6 +100,29 @@ SECTIONS
                EXIT_DATA
        }
 
+       /*
+        * struct alt_inst entries. From the header (alternative.h):
+        * "Alternative instructions for different CPU types or capabilities"
+        * Think locking instructions on spinlocks.
+        * Note, that it is a part of __init region.
+        */
+       . = ALIGN(8);
+       .altinstructions : {
+               __alt_instructions = .;
+               *(.altinstructions)
+               __alt_instructions_end = .;
+       }
+
+       /*
+        * And here are the replacement instructions. The linker sticks
+        * them as binary blobs. The .altinstructions has enough data to
+        * get the address and the length of them to patch the kernel safely.
+        * Note, that it is a part of __init region.
+        */
+       .altinstr_replacement : {
+               *(.altinstr_replacement)
+       }
+
        /* early.c uses stsi, which requires page aligned data. */
        . = ALIGN(PAGE_SIZE);
        INIT_DATA_SECTION(0x100)
index 09a9e6dfc09f66c9370031360c418f8a226179c0..6048b1c6e58062bac1258b003a4ebc3814896712 100644 (file)
@@ -12,6 +12,6 @@ common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o  $(KVM)/async_pf.o $(KVM)/irqch
 ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
 kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o
-kvm-objs += diag.o gaccess.o guestdbg.o sthyi.o vsie.o
+kvm-objs += diag.o gaccess.o guestdbg.o vsie.o
 
 obj-$(CONFIG_KVM) += kvm.o
index a4752bf6b526d0e45164ed146931a2d0ea177706..8fe034beb623217f42bc990c58dea9984426ef30 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/kvm_host.h>
 #include <asm/asm-offsets.h>
 #include <asm/irq.h>
+#include <asm/sysinfo.h>
 
 #include "kvm-s390.h"
 #include "gaccess.h"
@@ -360,6 +361,61 @@ static int handle_partial_execution(struct kvm_vcpu *vcpu)
        return -EOPNOTSUPP;
 }
 
+/*
+ * Handle the sthyi instruction that provides the guest with system
+ * information, like current CPU resources available at each level of
+ * the machine.
+ */
+int handle_sthyi(struct kvm_vcpu *vcpu)
+{
+       int reg1, reg2, r = 0;
+       u64 code, addr, cc = 0, rc = 0;
+       struct sthyi_sctns *sctns = NULL;
+
+       if (!test_kvm_facility(vcpu->kvm, 74))
+               return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
+
+       kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
+       code = vcpu->run->s.regs.gprs[reg1];
+       addr = vcpu->run->s.regs.gprs[reg2];
+
+       vcpu->stat.instruction_sthyi++;
+       VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
+       trace_kvm_s390_handle_sthyi(vcpu, code, addr);
+
+       if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       if (code & 0xffff) {
+               cc = 3;
+               rc = 4;
+               goto out;
+       }
+
+       if (addr & ~PAGE_MASK)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       sctns = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!sctns)
+               return -ENOMEM;
+
+       cc = sthyi_fill(sctns, &rc);
+
+out:
+       if (!cc) {
+               r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
+               if (r) {
+                       free_page((unsigned long)sctns);
+                       return kvm_s390_inject_prog_cond(vcpu, r);
+               }
+       }
+
+       free_page((unsigned long)sctns);
+       vcpu->run->s.regs.gprs[reg2 + 1] = rc;
+       kvm_s390_set_psw_cc(vcpu, cc);
+       return r;
+}
+
 static int handle_operexc(struct kvm_vcpu *vcpu)
 {
        psw_t oldpsw, newpsw;
index a832ad031cee78f5cc6fe17b93fb315e17fdd50a..329b2843fee2161093f13ef55db77977f6c5449a 100644 (file)
@@ -2483,11 +2483,11 @@ void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
 
        mci.val = mcck_info->mcic;
        if (mci.sr)
-               cr14 |= MCCK_CR14_RECOVERY_SUB_MASK;
+               cr14 |= CR14_RECOVERY_SUBMASK;
        if (mci.dg)
-               cr14 |= MCCK_CR14_DEGRAD_SUB_MASK;
+               cr14 |= CR14_DEGRADATION_SUBMASK;
        if (mci.w)
-               cr14 |= MCCK_CR14_WARN_SUB_MASK;
+               cr14 |= CR14_WARNING_SUBMASK;
 
        mchk = mci.ck ? &inti.mchk : &irq.u.mchk;
        mchk->cr14 = cr14;
index 40d0a1a97889b04f5e0bf1beb9d509721e1d5ff8..4bc70afe0a104dcb2680cc7c8762983b952eb180 100644 (file)
@@ -1884,8 +1884,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
        rc = -ENOMEM;
 
-       ratelimit_state_init(&kvm->arch.sthyi_limit, 5 * HZ, 500);
-
        kvm->arch.use_esca = 0; /* start with basic SCA */
        if (!sclp.has_64bscao)
                alloc_flags |= GFP_DMA;
@@ -3283,7 +3281,7 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
         */
        if ((kvm_run->kvm_dirty_regs & KVM_SYNC_RICCB) &&
            test_kvm_facility(vcpu->kvm, 64) &&
-           riccb->valid &&
+           riccb->v &&
            !(vcpu->arch.sie_block->ecb3 & ECB3_RI)) {
                VCPU_EVENT(vcpu, 3, "%s", "ENABLE: RI (sync_regs)");
                vcpu->arch.sie_block->ecb3 |= ECB3_RI;
index 9f8fdd7b231134da9b2d2d4d8971a05546b33c6b..10d65dfbc306736bc31e1a7f363c2b48516c52e7 100644 (file)
@@ -242,6 +242,8 @@ static inline void kvm_s390_retry_instr(struct kvm_vcpu *vcpu)
        kvm_s390_rewind_psw(vcpu, kvm_s390_get_ilen(vcpu));
 }
 
+int handle_sthyi(struct kvm_vcpu *vcpu);
+
 /* implemented in priv.c */
 int is_valid_psw(psw_t *psw);
 int kvm_s390_handle_aa(struct kvm_vcpu *vcpu);
@@ -268,9 +270,6 @@ void kvm_s390_vsie_destroy(struct kvm *kvm);
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
 
-/* implemented in sthyi.c */
-int handle_sthyi(struct kvm_vcpu *vcpu);
-
 /* implemented in kvm-s390.c */
 void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
                                 const struct kvm_s390_vm_tod_clock *gtod);
index d66751397e721e7eee8a2ea117ab8d4c8549f248..495c9c4bacc7b34bcfe4d966adeb28431b1dc032 100644 (file)
@@ -79,21 +79,25 @@ ENTRY(memset)
        ex      %r4,0(%r3)
        br      %r14
 .Lmemset_fill:
-       stc     %r3,0(%r2)
        cghi    %r4,1
        lgr     %r1,%r2
-       ber     %r14
+       je      .Lmemset_fill_exit
        aghi    %r4,-2
-       srlg    %r3,%r4,8
-       ltgr    %r3,%r3
+       srlg    %r5,%r4,8
+       ltgr    %r5,%r5
        jz      .Lmemset_fill_remainder
 .Lmemset_fill_loop:
-       mvc     1(256,%r1),0(%r1)
+       stc     %r3,0(%r1)
+       mvc     1(255,%r1),0(%r1)
        la      %r1,256(%r1)
-       brctg   %r3,.Lmemset_fill_loop
+       brctg   %r5,.Lmemset_fill_loop
 .Lmemset_fill_remainder:
-       larl    %r3,.Lmemset_mvc
-       ex      %r4,0(%r3)
+       stc     %r3,0(%r1)
+       larl    %r5,.Lmemset_mvc
+       ex      %r4,0(%r5)
+       br      %r14
+.Lmemset_fill_exit:
+       stc     %r3,0(%r1)
        br      %r14
 .Lmemset_xc:
        xc      0(1,%r1),0(%r1)
@@ -127,3 +131,47 @@ ENTRY(memcpy)
 .Lmemcpy_mvc:
        mvc     0(1,%r1),0(%r3)
 EXPORT_SYMBOL(memcpy)
+
+/*
+ * __memset16/32/64
+ *
+ * void *__memset16(uint16_t *s, uint16_t v, size_t count)
+ * void *__memset32(uint32_t *s, uint32_t v, size_t count)
+ * void *__memset64(uint64_t *s, uint64_t v, size_t count)
+ */
+.macro __MEMSET bits,bytes,insn
+ENTRY(__memset\bits)
+       ltgr    %r4,%r4
+       bzr     %r14
+       cghi    %r4,\bytes
+       je      .L__memset_exit\bits
+       aghi    %r4,-(\bytes+1)
+       srlg    %r5,%r4,8
+       ltgr    %r5,%r5
+       lgr     %r1,%r2
+       jz      .L__memset_remainder\bits
+.L__memset_loop\bits:
+       \insn   %r3,0(%r1)
+       mvc     \bytes(256-\bytes,%r1),0(%r1)
+       la      %r1,256(%r1)
+       brctg   %r5,.L__memset_loop\bits
+.L__memset_remainder\bits:
+       \insn   %r3,0(%r1)
+       larl    %r5,.L__memset_mvc\bits
+       ex      %r4,0(%r5)
+       br      %r14
+.L__memset_exit\bits:
+       \insn   %r3,0(%r2)
+       br      %r14
+.L__memset_mvc\bits:
+       mvc     \bytes(1,%r1),0(%r1)
+.endm
+
+__MEMSET 16,2,sth
+EXPORT_SYMBOL(__memset16)
+
+__MEMSET 32,4,st
+EXPORT_SYMBOL(__memset32)
+
+__MEMSET 64,8,stg
+EXPORT_SYMBOL(__memset64)
index 1dc85f552f4817fb7187b800155db64bfe958789..84c0faeaf7ea7c6dab061e6cc4993fcf642cc140 100644 (file)
@@ -9,8 +9,11 @@
 #include <linux/types.h>
 #include <linux/export.h>
 #include <linux/spinlock.h>
+#include <linux/jiffies.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/percpu.h>
+#include <asm/alternative.h>
 #include <asm/io.h>
 
 int spin_retry = -1;
@@ -33,14 +36,46 @@ static int __init spin_retry_setup(char *str)
 }
 __setup("spin_retry=", spin_retry_setup);
 
+struct spin_wait {
+       struct spin_wait *next, *prev;
+       int node_id;
+} __aligned(32);
+
+static DEFINE_PER_CPU_ALIGNED(struct spin_wait, spin_wait[4]);
+
+#define _Q_LOCK_CPU_OFFSET     0
+#define _Q_LOCK_STEAL_OFFSET   16
+#define _Q_TAIL_IDX_OFFSET     18
+#define _Q_TAIL_CPU_OFFSET     20
+
+#define _Q_LOCK_CPU_MASK       0x0000ffff
+#define _Q_LOCK_STEAL_ADD      0x00010000
+#define _Q_LOCK_STEAL_MASK     0x00030000
+#define _Q_TAIL_IDX_MASK       0x000c0000
+#define _Q_TAIL_CPU_MASK       0xfff00000
+
+#define _Q_LOCK_MASK           (_Q_LOCK_CPU_MASK | _Q_LOCK_STEAL_MASK)
+#define _Q_TAIL_MASK           (_Q_TAIL_IDX_MASK | _Q_TAIL_CPU_MASK)
+
+void arch_spin_lock_setup(int cpu)
+{
+       struct spin_wait *node;
+       int ix;
+
+       node = per_cpu_ptr(&spin_wait[0], cpu);
+       for (ix = 0; ix < 4; ix++, node++) {
+               memset(node, 0, sizeof(*node));
+               node->node_id = ((cpu + 1) << _Q_TAIL_CPU_OFFSET) +
+                       (ix << _Q_TAIL_IDX_OFFSET);
+       }
+}
+
 static inline int arch_load_niai4(int *lock)
 {
        int owner;
 
        asm volatile(
-#ifdef CONFIG_HAVE_MARCH_ZEC12_FEATURES
-               "       .long   0xb2fa0040\n"   /* NIAI 4 */
-#endif
+               ALTERNATIVE("", ".long 0xb2fa0040", 49) /* NIAI 4 */
                "       l       %0,%1\n"
                : "=d" (owner) : "Q" (*lock) : "memory");
        return owner;
@@ -51,9 +86,7 @@ static inline int arch_cmpxchg_niai8(int *lock, int old, int new)
        int expected = old;
 
        asm volatile(
-#ifdef CONFIG_HAVE_MARCH_ZEC12_FEATURES
-               "       .long   0xb2fa0080\n"   /* NIAI 8 */
-#endif
+               ALTERNATIVE("", ".long 0xb2fa0080", 49) /* NIAI 8 */
                "       cs      %0,%3,%1\n"
                : "=d" (old), "=Q" (*lock)
                : "0" (old), "d" (new), "Q" (*lock)
@@ -61,75 +94,160 @@ static inline int arch_cmpxchg_niai8(int *lock, int old, int new)
        return expected == old;
 }
 
-void arch_spin_lock_wait(arch_spinlock_t *lp)
+static inline struct spin_wait *arch_spin_decode_tail(int lock)
 {
-       int cpu = SPINLOCK_LOCKVAL;
-       int owner, count;
+       int ix, cpu;
+
+       ix = (lock & _Q_TAIL_IDX_MASK) >> _Q_TAIL_IDX_OFFSET;
+       cpu = (lock & _Q_TAIL_CPU_MASK) >> _Q_TAIL_CPU_OFFSET;
+       return per_cpu_ptr(&spin_wait[ix], cpu - 1);
+}
+
+static inline int arch_spin_yield_target(int lock, struct spin_wait *node)
+{
+       if (lock & _Q_LOCK_CPU_MASK)
+               return lock & _Q_LOCK_CPU_MASK;
+       if (node == NULL || node->prev == NULL)
+               return 0;       /* 0 -> no target cpu */
+       while (node->prev)
+               node = node->prev;
+       return node->node_id >> _Q_TAIL_CPU_OFFSET;
+}
+
+static inline void arch_spin_lock_queued(arch_spinlock_t *lp)
+{
+       struct spin_wait *node, *next;
+       int lockval, ix, node_id, tail_id, old, new, owner, count;
+
+       ix = S390_lowcore.spinlock_index++;
+       barrier();
+       lockval = SPINLOCK_LOCKVAL;     /* cpu + 1 */
+       node = this_cpu_ptr(&spin_wait[ix]);
+       node->prev = node->next = NULL;
+       node_id = node->node_id;
+
+       /* Enqueue the node for this CPU in the spinlock wait queue */
+       while (1) {
+               old = READ_ONCE(lp->lock);
+               if ((old & _Q_LOCK_CPU_MASK) == 0 &&
+                   (old & _Q_LOCK_STEAL_MASK) != _Q_LOCK_STEAL_MASK) {
+                       /*
+                        * The lock is free but there may be waiters.
+                        * With no waiters simply take the lock, if there
+                        * are waiters try to steal the lock. The lock may
+                        * be stolen three times before the next queued
+                        * waiter will get the lock.
+                        */
+                       new = (old ? (old + _Q_LOCK_STEAL_ADD) : 0) | lockval;
+                       if (__atomic_cmpxchg_bool(&lp->lock, old, new))
+                               /* Got the lock */
+                               goto out;
+                       /* lock passing in progress */
+                       continue;
+               }
+               /* Make the node of this CPU the new tail. */
+               new = node_id | (old & _Q_LOCK_MASK);
+               if (__atomic_cmpxchg_bool(&lp->lock, old, new))
+                       break;
+       }
+       /* Set the 'next' pointer of the tail node in the queue */
+       tail_id = old & _Q_TAIL_MASK;
+       if (tail_id != 0) {
+               node->prev = arch_spin_decode_tail(tail_id);
+               WRITE_ONCE(node->prev->next, node);
+       }
 
        /* Pass the virtual CPU to the lock holder if it is not running */
-       owner = arch_load_niai4(&lp->lock);
-       if (owner && arch_vcpu_is_preempted(~owner))
-               smp_yield_cpu(~owner);
+       owner = arch_spin_yield_target(old, node);
+       if (owner && arch_vcpu_is_preempted(owner - 1))
+               smp_yield_cpu(owner - 1);
 
+       /* Spin on the CPU local node->prev pointer */
+       if (tail_id != 0) {
+               count = spin_retry;
+               while (READ_ONCE(node->prev) != NULL) {
+                       if (count-- >= 0)
+                               continue;
+                       count = spin_retry;
+                       /* Query running state of lock holder again. */
+                       owner = arch_spin_yield_target(old, node);
+                       if (owner && arch_vcpu_is_preempted(owner - 1))
+                               smp_yield_cpu(owner - 1);
+               }
+       }
+
+       /* Spin on the lock value in the spinlock_t */
        count = spin_retry;
        while (1) {
-               owner = arch_load_niai4(&lp->lock);
-               /* Try to get the lock if it is free. */
+               old = READ_ONCE(lp->lock);
+               owner = old & _Q_LOCK_CPU_MASK;
                if (!owner) {
-                       if (arch_cmpxchg_niai8(&lp->lock, 0, cpu))
-                               return;
+                       tail_id = old & _Q_TAIL_MASK;
+                       new = ((tail_id != node_id) ? tail_id : 0) | lockval;
+                       if (__atomic_cmpxchg_bool(&lp->lock, old, new))
+                               /* Got the lock */
+                               break;
                        continue;
                }
                if (count-- >= 0)
                        continue;
                count = spin_retry;
-               /*
-                * For multiple layers of hypervisors, e.g. z/VM + LPAR
-                * yield the CPU unconditionally. For LPAR rely on the
-                * sense running status.
-                */
-               if (!MACHINE_IS_LPAR || arch_vcpu_is_preempted(~owner))
-                       smp_yield_cpu(~owner);
+               if (!MACHINE_IS_LPAR || arch_vcpu_is_preempted(owner - 1))
+                       smp_yield_cpu(owner - 1);
        }
+
+       /* Pass lock_spin job to next CPU in the queue */
+       if (node_id && tail_id != node_id) {
+               /* Wait until the next CPU has set up the 'next' pointer */
+               while ((next = READ_ONCE(node->next)) == NULL)
+                       ;
+               next->prev = NULL;
+       }
+
+ out:
+       S390_lowcore.spinlock_index--;
 }
-EXPORT_SYMBOL(arch_spin_lock_wait);
 
-void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
+static inline void arch_spin_lock_classic(arch_spinlock_t *lp)
 {
-       int cpu = SPINLOCK_LOCKVAL;
-       int owner, count;
+       int lockval, old, new, owner, count;
 
-       local_irq_restore(flags);
+       lockval = SPINLOCK_LOCKVAL;     /* cpu + 1 */
 
        /* Pass the virtual CPU to the lock holder if it is not running */
-       owner = arch_load_niai4(&lp->lock);
-       if (owner && arch_vcpu_is_preempted(~owner))
-               smp_yield_cpu(~owner);
+       owner = arch_spin_yield_target(READ_ONCE(lp->lock), NULL);
+       if (owner && arch_vcpu_is_preempted(owner - 1))
+               smp_yield_cpu(owner - 1);
 
        count = spin_retry;
        while (1) {
-               owner = arch_load_niai4(&lp->lock);
+               old = arch_load_niai4(&lp->lock);
+               owner = old & _Q_LOCK_CPU_MASK;
                /* Try to get the lock if it is free. */
                if (!owner) {
-                       local_irq_disable();
-                       if (arch_cmpxchg_niai8(&lp->lock, 0, cpu))
-                               return;
-                       local_irq_restore(flags);
+                       new = (old & _Q_TAIL_MASK) | lockval;
+                       if (arch_cmpxchg_niai8(&lp->lock, old, new))
+                               /* Got the lock */
+                              return;
                        continue;
                }
                if (count-- >= 0)
                        continue;
                count = spin_retry;
-               /*
-                * For multiple layers of hypervisors, e.g. z/VM + LPAR
-                * yield the CPU unconditionally. For LPAR rely on the
-                * sense running status.
-                */
-               if (!MACHINE_IS_LPAR || arch_vcpu_is_preempted(~owner))
-                       smp_yield_cpu(~owner);
+               if (!MACHINE_IS_LPAR || arch_vcpu_is_preempted(owner - 1))
+                       smp_yield_cpu(owner - 1);
        }
 }
-EXPORT_SYMBOL(arch_spin_lock_wait_flags);
+
+void arch_spin_lock_wait(arch_spinlock_t *lp)
+{
+       /* Use classic spinlocks + niai if the steal time is >= 10% */
+       if (test_cpu_flag(CIF_DEDICATED_CPU))
+               arch_spin_lock_queued(lp);
+       else
+               arch_spin_lock_classic(lp);
+}
+EXPORT_SYMBOL(arch_spin_lock_wait);
 
 int arch_spin_trylock_retry(arch_spinlock_t *lp)
 {
@@ -148,126 +266,59 @@ int arch_spin_trylock_retry(arch_spinlock_t *lp)
 }
 EXPORT_SYMBOL(arch_spin_trylock_retry);
 
-void _raw_read_lock_wait(arch_rwlock_t *rw)
+void arch_read_lock_wait(arch_rwlock_t *rw)
 {
-       int count = spin_retry;
-       int owner, old;
-
-#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
-       __RAW_LOCK(&rw->lock, -1, __RAW_OP_ADD);
-#endif
-       owner = 0;
-       while (1) {
-               if (count-- <= 0) {
-                       if (owner && arch_vcpu_is_preempted(~owner))
-                               smp_yield_cpu(~owner);
-                       count = spin_retry;
-               }
-               old = ACCESS_ONCE(rw->lock);
-               owner = ACCESS_ONCE(rw->owner);
-               if (old < 0)
-                       continue;
-               if (__atomic_cmpxchg_bool(&rw->lock, old, old + 1))
-                       return;
+       if (unlikely(in_interrupt())) {
+               while (READ_ONCE(rw->cnts) & 0x10000)
+                       barrier();
+               return;
        }
+
+       /* Remove this reader again to allow recursive read locking */
+       __atomic_add_const(-1, &rw->cnts);
+       /* Put the reader into the wait queue */
+       arch_spin_lock(&rw->wait);
+       /* Now add this reader to the count value again */
+       __atomic_add_const(1, &rw->cnts);
+       /* Loop until the writer is done */
+       while (READ_ONCE(rw->cnts) & 0x10000)
+               barrier();
+       arch_spin_unlock(&rw->wait);
 }
-EXPORT_SYMBOL(_raw_read_lock_wait);
+EXPORT_SYMBOL(arch_read_lock_wait);
 
-int _raw_read_trylock_retry(arch_rwlock_t *rw)
+void arch_write_lock_wait(arch_rwlock_t *rw)
 {
-       int count = spin_retry;
        int old;
 
-       while (count-- > 0) {
-               old = ACCESS_ONCE(rw->lock);
-               if (old < 0)
-                       continue;
-               if (__atomic_cmpxchg_bool(&rw->lock, old, old + 1))
-                       return 1;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(_raw_read_trylock_retry);
-
-#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
+       /* Add this CPU to the write waiters */
+       __atomic_add(0x20000, &rw->cnts);
 
-void _raw_write_lock_wait(arch_rwlock_t *rw, int prev)
-{
-       int count = spin_retry;
-       int owner, old;
+       /* Put the writer into the wait queue */
+       arch_spin_lock(&rw->wait);
 
-       owner = 0;
        while (1) {
-               if (count-- <= 0) {
-                       if (owner && arch_vcpu_is_preempted(~owner))
-                               smp_yield_cpu(~owner);
-                       count = spin_retry;
-               }
-               old = ACCESS_ONCE(rw->lock);
-               owner = ACCESS_ONCE(rw->owner);
-               smp_mb();
-               if (old >= 0) {
-                       prev = __RAW_LOCK(&rw->lock, 0x80000000, __RAW_OP_OR);
-                       old = prev;
-               }
-               if ((old & 0x7fffffff) == 0 && prev >= 0)
+               old = READ_ONCE(rw->cnts);
+               if ((old & 0x1ffff) == 0 &&
+                   __atomic_cmpxchg_bool(&rw->cnts, old, old | 0x10000))
+                       /* Got the lock */
                        break;
+               barrier();
        }
-}
-EXPORT_SYMBOL(_raw_write_lock_wait);
-
-#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
-
-void _raw_write_lock_wait(arch_rwlock_t *rw)
-{
-       int count = spin_retry;
-       int owner, old, prev;
 
-       prev = 0x80000000;
-       owner = 0;
-       while (1) {
-               if (count-- <= 0) {
-                       if (owner && arch_vcpu_is_preempted(~owner))
-                               smp_yield_cpu(~owner);
-                       count = spin_retry;
-               }
-               old = ACCESS_ONCE(rw->lock);
-               owner = ACCESS_ONCE(rw->owner);
-               if (old >= 0 &&
-                   __atomic_cmpxchg_bool(&rw->lock, old, old | 0x80000000))
-                       prev = old;
-               else
-                       smp_mb();
-               if ((old & 0x7fffffff) == 0 && prev >= 0)
-                       break;
-       }
+       arch_spin_unlock(&rw->wait);
 }
-EXPORT_SYMBOL(_raw_write_lock_wait);
-
-#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
+EXPORT_SYMBOL(arch_write_lock_wait);
 
-int _raw_write_trylock_retry(arch_rwlock_t *rw)
+void arch_spin_relax(arch_spinlock_t *lp)
 {
-       int count = spin_retry;
-       int old;
+       int cpu;
 
-       while (count-- > 0) {
-               old = ACCESS_ONCE(rw->lock);
-               if (old)
-                       continue;
-               if (__atomic_cmpxchg_bool(&rw->lock, 0, 0x80000000))
-                       return 1;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(_raw_write_trylock_retry);
-
-void arch_lock_relax(int cpu)
-{
+       cpu = READ_ONCE(lp->lock) & _Q_LOCK_CPU_MASK;
        if (!cpu)
                return;
-       if (MACHINE_IS_LPAR && !arch_vcpu_is_preempted(~cpu))
+       if (MACHINE_IS_LPAR && !arch_vcpu_is_preempted(cpu - 1))
                return;
-       smp_yield_cpu(~cpu);
+       smp_yield_cpu(cpu - 1);
 }
-EXPORT_SYMBOL(arch_lock_relax);
+EXPORT_SYMBOL(arch_spin_relax);
index dbf2fdad2724a991327a424bf273e9a4c8f11386..a10e11f7a5f79c3899d553757499627b6a93fcb9 100644 (file)
@@ -56,7 +56,7 @@ EXPORT_SYMBOL(strlen);
  *
  * returns the minimum of the length of @s and @n
  */
-size_t strnlen(const char * s, size_t n)
+size_t strnlen(const char *s, size_t n)
 {
        return __strnend(s, n) - s;
 }
@@ -195,14 +195,14 @@ EXPORT_SYMBOL(strncat);
 
 /**
  * strcmp - Compare two strings
- * @cs: One string
- * @ct: Another string
+ * @s1: One string
+ * @s2: Another string
  *
- * returns   0 if @cs and @ct are equal,
- *         < 0 if @cs is less than @ct
- *         > 0 if @cs is greater than @ct
+ * returns   0 if @s1 and @s2 are equal,
+ *        < 0 if @s1 is less than @s2
+ *        > 0 if @s1 is greater than @s2
  */
-int strcmp(const char *cs, const char *ct)
+int strcmp(const char *s1, const char *s2)
 {
        register int r0 asm("0") = 0;
        int ret = 0;
@@ -214,7 +214,7 @@ int strcmp(const char *cs, const char *ct)
                      "   ic   %1,0(%3)\n"
                      "   sr   %0,%1\n"
                      "1:"
-                     : "+d" (ret), "+d" (r0), "+a" (cs), "+a" (ct)
+                     : "+d" (ret), "+d" (r0), "+a" (s1), "+a" (s2)
                      : : "cc", "memory");
        return ret;
 }
@@ -225,7 +225,7 @@ EXPORT_SYMBOL(strcmp);
  * @s: The string to be searched
  * @c: The character to search for
  */
-char * strrchr(const char * s, int c)
+char *strrchr(const char *s, int c)
 {
        size_t len = __strend(s) - s;
 
@@ -261,7 +261,7 @@ static inline int clcle(const char *s1, unsigned long l1,
  * @s1: The string to be searched
  * @s2: The string to search for
  */
-char * strstr(const char * s1,const char * s2)
+char *strstr(const char *s1, const char *s2)
 {
        int l1, l2;
 
@@ -307,15 +307,15 @@ EXPORT_SYMBOL(memchr);
 
 /**
  * memcmp - Compare two areas of memory
- * @cs: One area of memory
- * @ct: Another area of memory
+ * @s1: One area of memory
+ * @s2: Another area of memory
  * @count: The size of the area.
  */
-int memcmp(const void *cs, const void *ct, size_t n)
+int memcmp(const void *s1, const void *s2, size_t n)
 {
        int ret;
 
-       ret = clcle(cs, n, ct, n);
+       ret = clcle(s1, n, s2, n);
        if (ret)
                ret = ret == 1 ? -1 : 1;
        return ret;
index 829c63dbc81af344d816bf2183d937d9f1cd4724..2dbdcd85b68f200762846ce0c59dc39438d0f9e0 100644 (file)
@@ -56,7 +56,7 @@ static DEFINE_SPINLOCK(cmm_lock);
 
 static struct task_struct *cmm_thread_ptr;
 static DECLARE_WAIT_QUEUE_HEAD(cmm_thread_wait);
-static DEFINE_TIMER(cmm_timer, NULL, 0, 0);
+static DEFINE_TIMER(cmm_timer, NULL);
 
 static void cmm_timer_fn(unsigned long);
 static void cmm_set_timer(void);
index 41ba9bd53e48aa42dc967cce60902f3a5c554b9b..817c9e16e83e5d3fe5e75b7e3b440cea5b23fe95 100644 (file)
@@ -145,8 +145,8 @@ void __init mem_init(void)
 
 void free_initmem(void)
 {
-       __set_memory((unsigned long) _sinittext,
-                    (_einittext - _sinittext) >> PAGE_SHIFT,
+       __set_memory((unsigned long)_sinittext,
+                    (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT,
                     SET_MEMORY_RW | SET_MEMORY_NX);
        free_initmem_default(POISON_FREE_INITMEM);
 }
index cc2faffa7d6ef49def16e2ba1204f23b98a52f8e..4ad4c4f77b4d9fa0362ed42a6e8474e443285e26 100644 (file)
@@ -159,13 +159,13 @@ static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits)
 struct page *page_table_alloc_pgste(struct mm_struct *mm)
 {
        struct page *page;
-       unsigned long *table;
+       u64 *table;
 
        page = alloc_page(GFP_KERNEL);
        if (page) {
-               table = (unsigned long *) page_to_phys(page);
-               clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
-               clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2);
+               table = (u64 *)page_to_phys(page);
+               memset64(table, _PAGE_INVALID, PTRS_PER_PTE);
+               memset64(table + PTRS_PER_PTE, 0, PTRS_PER_PTE);
        }
        return page;
 }
@@ -222,12 +222,12 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
        if (mm_alloc_pgste(mm)) {
                /* Return 4K page table with PGSTEs */
                atomic_set(&page->_mapcount, 3);
-               clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
-               clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2);
+               memset64((u64 *)table, _PAGE_INVALID, PTRS_PER_PTE);
+               memset64((u64 *)table + PTRS_PER_PTE, 0, PTRS_PER_PTE);
        } else {
                /* Return the first 2K fragment of the page */
                atomic_set(&page->_mapcount, 1);
-               clear_table(table, _PAGE_INVALID, PAGE_SIZE);
+               memset64((u64 *)table, _PAGE_INVALID, 2 * PTRS_PER_PTE);
                spin_lock_bh(&mm->context.lock);
                list_add(&page->lru, &mm->context.pgtable_list);
                spin_unlock_bh(&mm->context.lock);
index f2ada0bc08e6def45700a6cb0c8a5185aa8a536c..3316d463fc2917f984d985f395cd85541cbd9650 100644 (file)
@@ -60,7 +60,7 @@ pte_t __ref *vmem_pte_alloc(void)
                pte = (pte_t *) memblock_alloc(size, size);
        if (!pte)
                return NULL;
-       clear_table((unsigned long *) pte, _PAGE_INVALID, size);
+       memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE);
        return pte;
 }
 
@@ -403,17 +403,17 @@ void __init vmem_map_init(void)
 
        for_each_memblock(memory, reg)
                vmem_add_mem(reg->base, reg->size);
-       __set_memory((unsigned long) _stext,
-                    (_etext - _stext) >> PAGE_SHIFT,
+       __set_memory((unsigned long)_stext,
+                    (unsigned long)(_etext - _stext) >> PAGE_SHIFT,
                     SET_MEMORY_RO | SET_MEMORY_X);
-       __set_memory((unsigned long) _etext,
-                    (_eshared - _etext) >> PAGE_SHIFT,
+       __set_memory((unsigned long)_etext,
+                    (unsigned long)(__end_rodata - _etext) >> PAGE_SHIFT,
                     SET_MEMORY_RO);
-       __set_memory((unsigned long) _sinittext,
-                    (_einittext - _sinittext) >> PAGE_SHIFT,
+       __set_memory((unsigned long)_sinittext,
+                    (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT,
                     SET_MEMORY_RO | SET_MEMORY_X);
        pr_info("Write protected kernel read-only data: %luk\n",
-               (_eshared - _stext) >> 10);
+               (unsigned long)(__end_rodata - _stext) >> 10);
 }
 
 /*
index 7fa55ccffe480e55d35cd81b643409c5e6015fce..5e1e5133132de8f0964e3781dffd3d231ce610aa 100644 (file)
@@ -53,10 +53,13 @@ extern u8 sk_load_word[], sk_load_half[], sk_load_byte[];
  *
  * We get 160 bytes stack space from calling function, but only use
  * 12 * 8 byte for old backchain, r15..r6, and tail_call_cnt.
+ *
+ * The stack size used by the BPF program ("BPF stack" above) is passed
+ * via "aux->stack_depth".
  */
-#define STK_SPACE      (MAX_BPF_STACK + 8 + 8 + 4 + 4 + 160)
+#define STK_SPACE_ADD (8 + 8 + 4 + 4 + 160)
 #define STK_160_UNUSED (160 - 12 * 8)
-#define STK_OFF                (STK_SPACE - STK_160_UNUSED)
+#define STK_OFF                (STK_SPACE_ADD - STK_160_UNUSED)
 #define STK_OFF_TMP    160     /* Offset of tmp buffer on stack */
 #define STK_OFF_HLEN   168     /* Offset of SKB header length on stack */
 #define STK_OFF_SKBP   176     /* Offset of SKB pointer on stack */
index b15cd2f0320f81925a76bec3a2afe0fea094d2f9..e81c16838b90f1bc9a5418bc1b4e5365e9cb0aef 100644 (file)
@@ -320,12 +320,12 @@ static void save_regs(struct bpf_jit *jit, u32 rs, u32 re)
 /*
  * Restore registers from "rs" (register start) to "re" (register end) on stack
  */
-static void restore_regs(struct bpf_jit *jit, u32 rs, u32 re)
+static void restore_regs(struct bpf_jit *jit, u32 rs, u32 re, u32 stack_depth)
 {
        u32 off = STK_OFF_R6 + (rs - 6) * 8;
 
        if (jit->seen & SEEN_STACK)
-               off += STK_OFF;
+               off += STK_OFF + stack_depth;
 
        if (rs == re)
                /* lg %rs,off(%r15) */
@@ -369,7 +369,7 @@ static int get_end(struct bpf_jit *jit, int start)
  * Save and restore clobbered registers (6-15) on stack.
  * We save/restore registers in chunks with gap >= 2 registers.
  */
-static void save_restore_regs(struct bpf_jit *jit, int op)
+static void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth)
 {
 
        int re = 6, rs;
@@ -382,7 +382,7 @@ static void save_restore_regs(struct bpf_jit *jit, int op)
                if (op == REGS_SAVE)
                        save_regs(jit, rs, re);
                else
-                       restore_regs(jit, rs, re);
+                       restore_regs(jit, rs, re, stack_depth);
                re++;
        } while (re <= 15);
 }
@@ -414,7 +414,7 @@ static void emit_load_skb_data_hlen(struct bpf_jit *jit)
  * Save registers and create stack frame if necessary.
  * See stack frame layout desription in "bpf_jit.h"!
  */
-static void bpf_jit_prologue(struct bpf_jit *jit)
+static void bpf_jit_prologue(struct bpf_jit *jit, u32 stack_depth)
 {
        if (jit->seen & SEEN_TAIL_CALL) {
                /* xc STK_OFF_TCCNT(4,%r15),STK_OFF_TCCNT(%r15) */
@@ -427,7 +427,7 @@ static void bpf_jit_prologue(struct bpf_jit *jit)
        /* Tail calls have to skip above initialization */
        jit->tail_call_start = jit->prg;
        /* Save registers */
-       save_restore_regs(jit, REGS_SAVE);
+       save_restore_regs(jit, REGS_SAVE, stack_depth);
        /* Setup literal pool */
        if (jit->seen & SEEN_LITERAL) {
                /* basr %r13,0 */
@@ -442,7 +442,7 @@ static void bpf_jit_prologue(struct bpf_jit *jit)
                /* la %bfp,STK_160_UNUSED(%r15) (BPF frame pointer) */
                EMIT4_DISP(0x41000000, BPF_REG_FP, REG_15, STK_160_UNUSED);
                /* aghi %r15,-STK_OFF */
-               EMIT4_IMM(0xa70b0000, REG_15, -STK_OFF);
+               EMIT4_IMM(0xa70b0000, REG_15, -(STK_OFF + stack_depth));
                if (jit->seen & SEEN_FUNC)
                        /* stg %w1,152(%r15) (backchain) */
                        EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0,
@@ -459,7 +459,7 @@ static void bpf_jit_prologue(struct bpf_jit *jit)
 /*
  * Function epilogue
  */
-static void bpf_jit_epilogue(struct bpf_jit *jit)
+static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
 {
        /* Return 0 */
        if (jit->seen & SEEN_RET0) {
@@ -471,7 +471,7 @@ static void bpf_jit_epilogue(struct bpf_jit *jit)
        /* Load exit code: lgr %r2,%b0 */
        EMIT4(0xb9040000, REG_2, BPF_REG_0);
        /* Restore registers */
-       save_restore_regs(jit, REGS_RESTORE);
+       save_restore_regs(jit, REGS_RESTORE, stack_depth);
        /* br %r14 */
        _EMIT2(0x07fe);
 }
@@ -1019,7 +1019,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
                 */
 
                if (jit->seen & SEEN_STACK)
-                       off = STK_OFF_TCCNT + STK_OFF;
+                       off = STK_OFF_TCCNT + STK_OFF + fp->aux->stack_depth;
                else
                        off = STK_OFF_TCCNT;
                /* lhi %w0,1 */
@@ -1047,7 +1047,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
                /*
                 * Restore registers before calling function
                 */
-               save_restore_regs(jit, REGS_RESTORE);
+               save_restore_regs(jit, REGS_RESTORE, fp->aux->stack_depth);
 
                /*
                 * goto *(prog->bpf_func + tail_call_start);
@@ -1273,7 +1273,7 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp)
        jit->lit = jit->lit_start;
        jit->prg = 0;
 
-       bpf_jit_prologue(jit);
+       bpf_jit_prologue(jit, fp->aux->stack_depth);
        for (i = 0; i < fp->len; i += insn_count) {
                insn_count = bpf_jit_insn(jit, fp, i);
                if (insn_count < 0)
@@ -1281,7 +1281,7 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp)
                /* Next instruction address */
                jit->addrs[i + insn_count] = jit->prg;
        }
-       bpf_jit_epilogue(jit);
+       bpf_jit_epilogue(jit, fp->aux->stack_depth);
 
        jit->lit_start = jit->prg;
        jit->size = jit->lit;
index a25d95a6612dd90f9ff009764a1d318e087495b0..0fe649c0d5423a2ed51fcff4dc7d011204fdf4e9 100644 (file)
@@ -368,7 +368,8 @@ static void zpci_irq_handler(struct airq_struct *airq)
                                /* End of second scan with interrupts on. */
                                break;
                        /* First scan complete, reenable interrupts. */
-                       zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+                       if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC))
+                               break;
                        si = 0;
                        continue;
                }
@@ -956,7 +957,7 @@ static int __init pci_base_init(void)
        if (!s390_pci_probe)
                return 0;
 
-       if (!test_facility(69) || !test_facility(71) || !test_facility(72))
+       if (!test_facility(69) || !test_facility(71))
                return 0;
 
        rc = zpci_debug_init();
index ea34086c86744e0e19cd072f160592efa2d1c7fa..81b840bc6e4e733064d20f309bb57f24820f01cb 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/export.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <asm/facility.h>
 #include <asm/pci_insn.h>
 #include <asm/pci_debug.h>
 #include <asm/processor.h>
@@ -91,11 +92,14 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
 }
 
 /* Set Interruption Controls */
-void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
+int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
 {
+       if (!test_facility(72))
+               return -EIO;
        asm volatile (
                "       .insn   rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
                : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
+       return 0;
 }
 
 /* PCI Load */
index d54c149fbb6b821406c8dda170d814fd62f2d31c..2ebf2872cc16b6bc84990e30100501da87682ce5 100644 (file)
@@ -4,11 +4,21 @@
 #
 
 hostprogs-y                += gen_facilities
+hostprogs-y                += gen_opcode_table
+
 HOSTCFLAGS_gen_facilities.o += -Wall $(LINUXINCLUDE)
+HOSTCFLAGS_gen_opcode_table.o += -Wall $(LINUXINCLUDE)
 
 define filechk_facilities.h
        $(obj)/gen_facilities
 endef
 
+define filechk_dis.h
+       ( $(obj)/gen_opcode_table < $(srctree)/arch/$(ARCH)/tools/opcodes.txt )
+endef
+
 include/generated/facilities.h: $(obj)/gen_facilities FORCE
        $(call filechk,facilities.h)
+
+include/generated/dis.h: $(obj)/gen_opcode_table FORCE
+       $(call filechk,dis.h,__FUN)
diff --git a/arch/s390/tools/gen_opcode_table.c b/arch/s390/tools/gen_opcode_table.c
new file mode 100644 (file)
index 0000000..01d4c5a
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Generate opcode table initializers for the in-kernel disassembler.
+ *
+ *    Copyright IBM Corp. 2017
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#define STRING_SIZE_MAX 20
+
+struct insn_type {
+       unsigned char byte;
+       unsigned char mask;
+       char **format;
+};
+
+struct insn {
+       struct insn_type *type;
+       char opcode[STRING_SIZE_MAX];
+       char name[STRING_SIZE_MAX];
+       char upper[STRING_SIZE_MAX];
+       char format[STRING_SIZE_MAX];
+       unsigned int name_len;
+};
+
+struct insn_group {
+       struct insn_type *type;
+       int offset;
+       int count;
+       char opcode[2];
+};
+
+struct insn_format {
+       char *format;
+       int type;
+};
+
+struct gen_opcode {
+       struct insn *insn;
+       int nr;
+       struct insn_group *group;
+       int nr_groups;
+};
+
+/*
+ * Table of instruction format types. Each opcode is defined with at
+ * least one byte (two nibbles), three nibbles, or two bytes (four
+ * nibbles).
+ * The byte member of each instruction format type entry defines
+ * within which byte of an instruction the third (and fourth) nibble
+ * of an opcode can be found. The mask member is the and-mask that
+ * needs to be applied on this byte in order to get the third (and
+ * fourth) nibble of the opcode.
+ * The format array defines all instruction formats (as defined in the
+ * Principles of Operation) which have the same position of the opcode
+ * nibbles.
+ * A special case are instruction formats with 1-byte opcodes. In this
+ * case the byte member always is zero, so that the mask is applied on
+ * the (only) byte that contains the opcode.
+ */
+static struct insn_type insn_type_table[] = {
+       {
+               .byte = 0,
+               .mask = 0xff,
+               .format = (char *[]) {
+                       "MII",
+                       "RR",
+                       "RS",
+                       "RSI",
+                       "RX",
+                       "SI",
+                       "SMI",
+                       "SS",
+                       NULL,
+               },
+       },
+       {
+               .byte = 1,
+               .mask = 0x0f,
+               .format = (char *[]) {
+                       "RI",
+                       "RIL",
+                       "SSF",
+                       NULL,
+               },
+       },
+       {
+               .byte = 1,
+               .mask = 0xff,
+               .format = (char *[]) {
+                       "E",
+                       "IE",
+                       "RRE",
+                       "RRF",
+                       "RRR",
+                       "S",
+                       "SIL",
+                       "SSE",
+                       NULL,
+               },
+       },
+       {
+               .byte = 5,
+               .mask = 0xff,
+               .format = (char *[]) {
+                       "RIE",
+                       "RIS",
+                       "RRS",
+                       "RSE",
+                       "RSL",
+                       "RSY",
+                       "RXE",
+                       "RXF",
+                       "RXY",
+                       "SIY",
+                       "VRI",
+                       "VRR",
+                       "VRS",
+                       "VRV",
+                       "VRX",
+                       "VSI",
+                       NULL,
+               },
+       },
+};
+
+static struct insn_type *insn_format_to_type(char *format)
+{
+       char tmp[STRING_SIZE_MAX];
+       char *base_format, **ptr;
+       int i;
+
+       strcpy(tmp, format);
+       base_format = tmp;
+       base_format = strsep(&base_format, "_");
+       for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) {
+               ptr = insn_type_table[i].format;
+               while (*ptr) {
+                       if (!strcmp(base_format, *ptr))
+                               return &insn_type_table[i];
+                       ptr++;
+               }
+       }
+       exit(EXIT_FAILURE);
+}
+
+static void read_instructions(struct gen_opcode *desc)
+{
+       struct insn insn;
+       int rc, i;
+
+       while (1) {
+               rc = scanf("%s %s %s", insn.opcode, insn.name, insn.format);
+               if (rc == EOF)
+                       break;
+               if (rc != 3)
+                       exit(EXIT_FAILURE);
+               insn.type = insn_format_to_type(insn.format);
+               insn.name_len = strlen(insn.name);
+               for (i = 0; i <= insn.name_len; i++)
+                       insn.upper[i] = toupper((unsigned char)insn.name[i]);
+               desc->nr++;
+               desc->insn = realloc(desc->insn, desc->nr * sizeof(*desc->insn));
+               if (!desc->insn)
+                       exit(EXIT_FAILURE);
+               desc->insn[desc->nr - 1] = insn;
+       }
+}
+
+static int cmpformat(const void *a, const void *b)
+{
+       return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
+}
+
+static void print_formats(struct gen_opcode *desc)
+{
+       char *format;
+       int i, count;
+
+       qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpformat);
+       format = "";
+       count = 0;
+       printf("enum {\n");
+       for (i = 0; i < desc->nr; i++) {
+               if (!strcmp(format, desc->insn[i].format))
+                       continue;
+               count++;
+               format = desc->insn[i].format;
+               printf("\tINSTR_%s,\n", format);
+       }
+       printf("}; /* %d */\n\n", count);
+}
+
+static int cmp_long_insn(const void *a, const void *b)
+{
+       return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
+}
+
+static void print_long_insn(struct gen_opcode *desc)
+{
+       struct insn *insn;
+       int i, count;
+
+       qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn);
+       count = 0;
+       printf("enum {\n");
+       for (i = 0; i < desc->nr; i++) {
+               insn = &desc->insn[i];
+               if (insn->name_len < 6)
+                       continue;
+               printf("\tLONG_INSN_%s,\n", insn->upper);
+               count++;
+       }
+       printf("}; /* %d */\n\n", count);
+
+       printf("#define LONG_INSN_INITIALIZER { \\\n");
+       for (i = 0; i < desc->nr; i++) {
+               insn = &desc->insn[i];
+               if (insn->name_len < 6)
+                       continue;
+               printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn->upper, insn->name);
+       }
+       printf("}\n\n");
+}
+
+static void print_opcode(struct insn *insn, int nr)
+{
+       char *opcode;
+
+       opcode = insn->opcode;
+       if (insn->type->byte != 0)
+               opcode += 2;
+       printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr, opcode, insn->format);
+       if (insn->name_len < 6)
+               printf(".name = \"%s\" ", insn->name);
+       else
+               printf(".offset = LONG_INSN_%s ", insn->upper);
+       printf("}, \\\n");
+}
+
+static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset)
+{
+       struct insn_group *group;
+
+       group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL;
+       if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) {
+               group->count++;
+               return;
+       }
+       desc->nr_groups++;
+       desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group));
+       if (!desc->group)
+               exit(EXIT_FAILURE);
+       group = &desc->group[desc->nr_groups - 1];
+       strncpy(group->opcode, insn->opcode, 2);
+       group->type = insn->type;
+       group->offset = offset;
+       group->count = 1;
+}
+
+static int cmpopcode(const void *a, const void *b)
+{
+       return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
+}
+
+static void print_opcode_table(struct gen_opcode *desc)
+{
+       char opcode[2] = "";
+       struct insn *insn;
+       int i, offset;
+
+       qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode);
+       printf("#define OPCODE_TABLE_INITIALIZER { \\\n");
+       offset = 0;
+       for (i = 0; i < desc->nr; i++) {
+               insn = &desc->insn[i];
+               if (insn->type->byte == 0)
+                       continue;
+               add_to_group(desc, insn, offset);
+               if (strncmp(opcode, insn->opcode, 2)) {
+                       strncpy(opcode, insn->opcode, 2);
+                       printf("\t/* %.2s */ \\\n", opcode);
+               }
+               print_opcode(insn, offset);
+               offset++;
+       }
+       printf("\t/* 1-byte opcode instructions */ \\\n");
+       for (i = 0; i < desc->nr; i++) {
+               insn = &desc->insn[i];
+               if (insn->type->byte != 0)
+                       continue;
+               add_to_group(desc, insn, offset);
+               print_opcode(insn, offset);
+               offset++;
+       }
+       printf("}\n\n");
+}
+
+static void print_opcode_table_offsets(struct gen_opcode *desc)
+{
+       struct insn_group *group;
+       int i;
+
+       printf("#define OPCODE_OFFSET_INITIALIZER { \\\n");
+       for (i = 0; i < desc->nr_groups; i++) {
+               group = &desc->group[i];
+               printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n",
+                      group->opcode, group->type->mask, group->type->byte, group->offset, group->count);
+       }
+       printf("}\n\n");
+}
+
+int main(int argc, char **argv)
+{
+       struct gen_opcode _desc = { 0 };
+       struct gen_opcode *desc = &_desc;
+
+       read_instructions(desc);
+       printf("#ifndef __S390_GENERATED_DIS_H__\n");
+       printf("#define __S390_GENERATED_DIS_H__\n");
+       printf("/*\n");
+       printf(" * DO NOT MODIFY.\n");
+       printf(" *\n");
+       printf(" * This file was generated by %s\n", __FILE__);
+       printf(" */\n\n");
+       print_formats(desc);
+       print_long_insn(desc);
+       print_opcode_table(desc);
+       print_opcode_table_offsets(desc);
+       printf("#endif\n");
+       exit(EXIT_SUCCESS);
+}
diff --git a/arch/s390/tools/opcodes.txt b/arch/s390/tools/opcodes.txt
new file mode 100644 (file)
index 0000000..1cbed82
--- /dev/null
@@ -0,0 +1,1183 @@
+0101   pr      E
+0102   upt     E
+0104   ptff    E
+0107   sckpf   E
+010a   pfpo    E
+010b   tam     E
+010c   sam24   E
+010d   sam31   E
+010e   sam64   E
+01ff   trap2   E
+04     spm     RR_R0
+05     balr    RR_RR
+06     bctr    RR_RR
+07     bcr     RR_UR
+0a     svc     RR_U0
+0b     bsm     RR_RR
+0c     bassm   RR_RR
+0d     basr    RR_RR
+0e     mvcl    RR_RR
+0f     clcl    RR_RR
+10     lpr     RR_RR
+11     lnr     RR_RR
+12     ltr     RR_RR
+13     lcr     RR_RR
+14     nr      RR_RR
+15     clr     RR_RR
+16     or      RR_RR
+17     xr      RR_RR
+18     lr      RR_RR
+19     cr      RR_RR
+1a     ar      RR_RR
+1b     sr      RR_RR
+1c     mr      RR_RR
+1d     dr      RR_RR
+1e     alr     RR_RR
+1f     slr     RR_RR
+20     lpdr    RR_FF
+21     lndr    RR_FF
+22     ltdr    RR_FF
+23     lcdr    RR_FF
+24     hdr     RR_FF
+25     ldxr    RR_FF
+26     mxr     RR_FF
+27     mxdr    RR_FF
+28     ldr     RR_FF
+29     cdr     RR_FF
+2a     adr     RR_FF
+2b     sdr     RR_FF
+2c     mdr     RR_FF
+2d     ddr     RR_FF
+2e     awr     RR_FF
+2f     swr     RR_FF
+30     lper    RR_FF
+31     lner    RR_FF
+32     lter    RR_FF
+33     lcer    RR_FF
+34     her     RR_FF
+35     ledr    RR_FF
+36     axr     RR_FF
+37     sxr     RR_FF
+38     ler     RR_FF
+39     cer     RR_FF
+3a     aer     RR_FF
+3b     ser     RR_FF
+3c     mder    RR_FF
+3d     der     RR_FF
+3e     aur     RR_FF
+3f     sur     RR_FF
+40     sth     RX_RRRD
+41     la      RX_RRRD
+42     stc     RX_RRRD
+43     ic      RX_RRRD
+44     ex      RX_RRRD
+45     bal     RX_RRRD
+46     bct     RX_RRRD
+47     bc      RX_URRD
+48     lh      RX_RRRD
+49     ch      RX_RRRD
+4a     ah      RX_RRRD
+4b     sh      RX_RRRD
+4c     mh      RX_RRRD
+4d     bas     RX_RRRD
+4e     cvd     RX_RRRD
+4f     cvb     RX_RRRD
+50     st      RX_RRRD
+51     lae     RX_RRRD
+54     n       RX_RRRD
+55     cl      RX_RRRD
+56     o       RX_RRRD
+57     x       RX_RRRD
+58     l       RX_RRRD
+59     c       RX_RRRD
+5a     a       RX_RRRD
+5b     s       RX_RRRD
+5c     m       RX_RRRD
+5d     d       RX_RRRD
+5e     al      RX_RRRD
+5f     sl      RX_RRRD
+60     std     RX_FRRD
+67     mxd     RX_FRRD
+68     ld      RX_FRRD
+69     cd      RX_FRRD
+6a     ad      RX_FRRD
+6b     sd      RX_FRRD
+6c     md      RX_FRRD
+6d     dd      RX_FRRD
+6e     aw      RX_FRRD
+6f     sw      RX_FRRD
+70     ste     RX_FRRD
+71     ms      RX_RRRD
+78     le      RX_FRRD
+79     ce      RX_FRRD
+7a     ae      RX_FRRD
+7b     se      RX_FRRD
+7c     mde     RX_FRRD
+7d     de      RX_FRRD
+7e     au      RX_FRRD
+7f     su      RX_FRRD
+80     ssm     SI_RD
+82     lpsw    SI_RD
+83     diag    RS_RRRD
+84     brxh    RSI_RRP
+85     brxle   RSI_RRP
+86     bxh     RS_RRRD
+87     bxle    RS_RRRD
+88     srl     RS_R0RD
+89     sll     RS_R0RD
+8a     sra     RS_R0RD
+8b     sla     RS_R0RD
+8c     srdl    RS_R0RD
+8d     sldl    RS_R0RD
+8e     srda    RS_R0RD
+8f     slda    RS_R0RD
+90     stm     RS_RRRD
+91     tm      SI_URD
+92     mvi     SI_URD
+93     ts      SI_RD
+94     ni      SI_URD
+95     cli     SI_URD
+96     oi      SI_URD
+97     xi      SI_URD
+98     lm      RS_RRRD
+99     trace   RS_RRRD
+9a     lam     RS_AARD
+9b     stam    RS_AARD
+a50    iihh    RI_RU
+a51    iihl    RI_RU
+a52    iilh    RI_RU
+a53    iill    RI_RU
+a54    nihh    RI_RU
+a55    nihl    RI_RU
+a56    nilh    RI_RU
+a57    nill    RI_RU
+a58    oihh    RI_RU
+a59    oihl    RI_RU
+a5a    oilh    RI_RU
+a5b    oill    RI_RU
+a5c    llihh   RI_RU
+a5d    llihl   RI_RU
+a5e    llilh   RI_RU
+a5f    llill   RI_RU
+a70    tmlh    RI_RU
+a71    tmll    RI_RU
+a72    tmhh    RI_RU
+a73    tmhl    RI_RU
+a74    brc     RI_UP
+a75    bras    RI_RP
+a76    brct    RI_RP
+a77    brctg   RI_RP
+a78    lhi     RI_RI
+a79    lghi    RI_RI
+a7a    ahi     RI_RI
+a7b    aghi    RI_RI
+a7c    mhi     RI_RI
+a7d    mghi    RI_RI
+a7e    chi     RI_RI
+a7f    cghi    RI_RI
+a8     mvcle   RS_RRRD
+a9     clcle   RS_RRRD
+aa0    rinext  RI_RI
+aa1    rion    RI_RI
+aa2    tric    RI_RI
+aa3    rioff   RI_RI
+aa4    riemit  RI_RI
+ac     stnsm   SI_URD
+ad     stosm   SI_URD
+ae     sigp    RS_RRRD
+af     mc      SI_URD
+b1     lra     RX_RRRD
+b202   stidp   S_RD
+b204   sck     S_RD
+b205   stck    S_RD
+b206   sckc    S_RD
+b207   stckc   S_RD
+b208   spt     S_RD
+b209   stpt    S_RD
+b20a   spka    S_RD
+b20b   ipk     S_00
+b20d   ptlb    S_00
+b210   spx     S_RD
+b211   stpx    S_RD
+b212   stap    S_RD
+b214   sie     S_RD
+b218   pc      S_RD
+b219   sac     S_RD
+b21a   cfc     S_RD
+b220   servc   RRE_RR
+b221   ipte    RRF_RURR
+b222   ipm     RRE_R0
+b223   ivsk    RRE_RR
+b224   iac     RRE_R0
+b225   ssar    RRE_R0
+b226   epar    RRE_R0
+b227   esar    RRE_R0
+b228   pt      RRE_RR
+b229   iske    RRE_RR
+b22a   rrbe    RRE_RR
+b22b   sske    RRF_U0RR
+b22c   tb      RRE_RR
+b22d   dxr     RRE_FF
+b22e   pgin    RRE_RR
+b22f   pgout   RRE_RR
+b230   csch    S_00
+b231   hsch    S_00
+b232   msch    S_RD
+b233   ssch    S_RD
+b234   stsch   S_RD
+b235   tsch    S_RD
+b236   tpi     S_RD
+b237   sal     S_00
+b238   rsch    S_00
+b239   stcrw   S_RD
+b23a   stcps   S_RD
+b23b   rchp    S_00
+b23c   schm    S_00
+b240   bakr    RRE_RR
+b241   cksm    RRE_RR
+b244   sqdr    RRE_FF
+b245   sqer    RRE_FF
+b246   stura   RRE_RR
+b247   msta    RRE_R0
+b248   palb    RRE_00
+b249   ereg    RRE_RR
+b24a   esta    RRE_RR
+b24b   lura    RRE_RR
+b24c   tar     RRE_AR
+b24d   cpya    RRE_AA
+b24e   sar     RRE_AR
+b24f   ear     RRE_RA
+b250   csp     RRE_RR
+b252   msr     RRE_RR
+b254   mvpg    RRE_RR
+b255   mvst    RRE_RR
+b256   sthyi   RRE_RR
+b257   cuse    RRE_RR
+b258   bsg     RRE_RR
+b25a   bsa     RRE_RR
+b25d   clst    RRE_RR
+b25e   srst    RRE_RR
+b263   cmpsc   RRE_RR
+b274   siga    S_RD
+b276   xsch    S_00
+b277   rp      S_RD
+b278   stcke   S_RD
+b279   sacf    S_RD
+b27c   stckf   S_RD
+b27d   stsi    S_RD
+b280   lpp     S_RD
+b284   lcctl   S_RD
+b285   lpctl   S_RD
+b286   qsi     S_RD
+b287   lsctl   S_RD
+b28e   qctri   S_RD
+b299   srnm    S_RD
+b29c   stfpc   S_RD
+b29d   lfpc    S_RD
+b2a5   tre     RRE_RR
+b2a6   cu21    RRF_U0RR
+b2a7   cu12    RRF_U0RR
+b2b0   stfle   S_RD
+b2b1   stfl    S_RD
+b2b2   lpswe   S_RD
+b2b8   srnmb   S_RD
+b2b9   srnmt   S_RD
+b2bd   lfas    S_RD
+b2e0   scctr   RRE_RR
+b2e1   spctr   RRE_RR
+b2e4   ecctr   RRE_RR
+b2e5   epctr   RRE_RR
+b2e8   ppa     RRF_U0RR
+b2ec   etnd    RRE_R0
+b2ed   ecpga   RRE_RR
+b2f8   tend    S_00
+b2fa   niai    IE_UU
+b2fc   tabort  S_RD
+b2ff   trap4   S_RD
+b300   lpebr   RRE_FF
+b301   lnebr   RRE_FF
+b302   ltebr   RRE_FF
+b303   lcebr   RRE_FF
+b304   ldebr   RRE_FF
+b305   lxdbr   RRE_FF
+b306   lxebr   RRE_FF
+b307   mxdbr   RRE_FF
+b308   kebr    RRE_FF
+b309   cebr    RRE_FF
+b30a   aebr    RRE_FF
+b30b   sebr    RRE_FF
+b30c   mdebr   RRE_FF
+b30d   debr    RRE_FF
+b30e   maebr   RRF_F0FF
+b30f   msebr   RRF_F0FF
+b310   lpdbr   RRE_FF
+b311   lndbr   RRE_FF
+b312   ltdbr   RRE_FF
+b313   lcdbr   RRE_FF
+b314   sqebr   RRE_FF
+b315   sqdbr   RRE_FF
+b316   sqxbr   RRE_FF
+b317   meebr   RRE_FF
+b318   kdbr    RRE_FF
+b319   cdbr    RRE_FF
+b31a   adbr    RRE_FF
+b31b   sdbr    RRE_FF
+b31c   mdbr    RRE_FF
+b31d   ddbr    RRE_FF
+b31e   madbr   RRF_F0FF
+b31f   msdbr   RRF_F0FF
+b324   lder    RRE_FF
+b325   lxdr    RRE_FF
+b326   lxer    RRE_FF
+b32e   maer    RRF_F0FF
+b32f   mser    RRF_F0FF
+b336   sqxr    RRE_FF
+b337   meer    RRE_FF
+b338   maylr   RRF_F0FF
+b339   mylr    RRF_F0FF
+b33a   mayr    RRF_F0FF
+b33b   myr     RRF_F0FF
+b33c   mayhr   RRF_F0FF
+b33d   myhr    RRF_F0FF
+b33e   madr    RRF_F0FF
+b33f   msdr    RRF_F0FF
+b340   lpxbr   RRE_FF
+b341   lnxbr   RRE_FF
+b342   ltxbr   RRE_FF
+b343   lcxbr   RRE_FF
+b344   ledbra  RRF_UUFF
+b345   ldxbra  RRF_UUFF
+b346   lexbra  RRF_UUFF
+b347   fixbra  RRF_UUFF
+b348   kxbr    RRE_FF
+b349   cxbr    RRE_FF
+b34a   axbr    RRE_FF
+b34b   sxbr    RRE_FF
+b34c   mxbr    RRE_FF
+b34d   dxbr    RRE_FF
+b350   tbedr   RRF_U0FF
+b351   tbdr    RRF_U0FF
+b353   diebr   RRF_FUFF
+b357   fiebra  RRF_UUFF
+b358   thder   RRE_FF
+b359   thdr    RRE_FF
+b35b   didbr   RRF_FUFF
+b35f   fidbra  RRF_UUFF
+b360   lpxr    RRE_FF
+b361   lnxr    RRE_FF
+b362   ltxr    RRE_FF
+b363   lcxr    RRE_FF
+b365   lxr     RRE_FF
+b366   lexr    RRE_FF
+b367   fixr    RRE_FF
+b369   cxr     RRE_FF
+b370   lpdfr   RRE_FF
+b371   lndfr   RRE_FF
+b372   cpsdr   RRF_F0FF2
+b373   lcdfr   RRE_FF
+b374   lzer    RRE_F0
+b375   lzdr    RRE_F0
+b376   lzxr    RRE_F0
+b377   fier    RRE_FF
+b37f   fidr    RRE_FF
+b384   sfpc    RRE_RR
+b385   sfasr   RRE_R0
+b38c   efpc    RRE_RR
+b390   celfbr  RRF_UUFR
+b391   cdlfbr  RRF_UUFR
+b392   cxlfbr  RRF_UUFR
+b394   cefbra  RRF_UUFR
+b395   cdfbra  RRF_UUFR
+b396   cxfbra  RRF_UUFR
+b398   cfebra  RRF_UURF
+b399   cfdbra  RRF_UURF
+b39a   cfxbra  RRF_UURF
+b39c   clfebr  RRF_UURF
+b39d   clfdbr  RRF_UURF
+b39e   clfxbr  RRF_UURF
+b3a0   celgbr  RRF_UUFR
+b3a1   cdlgbr  RRF_UUFR
+b3a2   cxlgbr  RRF_UUFR
+b3a4   cegbra  RRF_UUFR
+b3a5   cdgbra  RRF_UUFR
+b3a6   cxgbra  RRF_UUFR
+b3a8   cgebra  RRF_UURF
+b3a9   cgdbra  RRF_UURF
+b3aa   cgxbra  RRF_UURF
+b3ac   clgebr  RRF_UURF
+b3ad   clgdbr  RRF_UURF
+b3ae   clgxbr  RRF_UURF
+b3b4   cefr    RRE_FR
+b3b5   cdfr    RRE_FR
+b3b6   cxfr    RRE_FR
+b3b8   cfer    RRF_U0RF
+b3b9   cfdr    RRF_U0RF
+b3ba   cfxr    RRF_U0RF
+b3c1   ldgr    RRE_FR
+b3c4   cegr    RRE_FR
+b3c5   cdgr    RRE_FR
+b3c6   cxgr    RRE_FR
+b3c8   cger    RRF_U0RF
+b3c9   cgdr    RRF_U0RF
+b3ca   cgxr    RRF_U0RF
+b3cd   lgdr    RRE_RF
+b3d0   mdtra   RRF_FUFF2
+b3d1   ddtra   RRF_FUFF2
+b3d2   adtra   RRF_FUFF2
+b3d3   sdtra   RRF_FUFF2
+b3d4   ldetr   RRF_0UFF
+b3d5   ledtr   RRF_UUFF
+b3d6   ltdtr   RRE_FF
+b3d7   fidtr   RRF_UUFF
+b3d8   mxtra   RRF_FUFF2
+b3d9   dxtra   RRF_FUFF2
+b3da   axtra   RRF_FUFF2
+b3db   sxtra   RRF_FUFF2
+b3dc   lxdtr   RRF_0UFF
+b3dd   ldxtr   RRF_UUFF
+b3de   ltxtr   RRE_FF
+b3df   fixtr   RRF_UUFF
+b3e0   kdtr    RRE_FF
+b3e1   cgdtra  RRF_UURF
+b3e2   cudtr   RRE_RF
+b3e3   csdtr   RRF_0URF
+b3e4   cdtr    RRE_FF
+b3e5   eedtr   RRE_RF
+b3e7   esdtr   RRE_RF
+b3e8   kxtr    RRE_FF
+b3e9   cgxtra  RRF_UURF
+b3ea   cuxtr   RRE_RF
+b3eb   csxtr   RRF_0URF
+b3ec   cxtr    RRE_FF
+b3ed   eextr   RRE_RF
+b3ef   esxtr   RRE_RF
+b3f1   cdgtra  RRF_UUFR
+b3f2   cdutr   RRE_FR
+b3f3   cdstr   RRE_FR
+b3f4   cedtr   RRE_FF
+b3f5   qadtr   RRF_FUFF
+b3f6   iedtr   RRF_F0FR
+b3f7   rrdtr   RRF_FFRU
+b3f9   cxgtra  RRF_UUFR
+b3fa   cxutr   RRE_FR
+b3fb   cxstr   RRE_FR
+b3fc   cextr   RRE_FF
+b3fd   qaxtr   RRF_FUFF
+b3fe   iextr   RRF_F0FR
+b3ff   rrxtr   RRF_FFRU
+b6     stctl   RS_CCRD
+b7     lctl    RS_CCRD
+b900   lpgr    RRE_RR
+b901   lngr    RRE_RR
+b902   ltgr    RRE_RR
+b903   lcgr    RRE_RR
+b904   lgr     RRE_RR
+b905   lurag   RRE_RR
+b906   lgbr    RRE_RR
+b907   lghr    RRE_RR
+b908   agr     RRE_RR
+b909   sgr     RRE_RR
+b90a   algr    RRE_RR
+b90b   slgr    RRE_RR
+b90c   msgr    RRE_RR
+b90d   dsgr    RRE_RR
+b90e   eregg   RRE_RR
+b90f   lrvgr   RRE_RR
+b910   lpgfr   RRE_RR
+b911   lngfr   RRE_RR
+b912   ltgfr   RRE_RR
+b913   lcgfr   RRE_RR
+b914   lgfr    RRE_RR
+b916   llgfr   RRE_RR
+b917   llgtr   RRE_RR
+b918   agfr    RRE_RR
+b919   sgfr    RRE_RR
+b91a   algfr   RRE_RR
+b91b   slgfr   RRE_RR
+b91c   msgfr   RRE_RR
+b91d   dsgfr   RRE_RR
+b91e   kmac    RRE_RR
+b91f   lrvr    RRE_RR
+b920   cgr     RRE_RR
+b921   clgr    RRE_RR
+b925   sturg   RRE_RR
+b926   lbr     RRE_RR
+b927   lhr     RRE_RR
+b928   pckmo   RRE_00
+b929   kma     RRF_R0RR
+b92a   kmf     RRE_RR
+b92b   kmo     RRE_RR
+b92c   pcc     RRE_00
+b92d   kmctr   RRF_R0RR
+b92e   km      RRE_RR
+b92f   kmc     RRE_RR
+b930   cgfr    RRE_RR
+b931   clgfr   RRE_RR
+b93c   ppno    RRE_RR
+b93e   kimd    RRE_RR
+b93f   klmd    RRE_RR
+b941   cfdtr   RRF_UURF
+b942   clgdtr  RRF_UURF
+b943   clfdtr  RRF_UURF
+b946   bctgr   RRE_RR
+b949   cfxtr   RRF_UURF
+b94a   clgxtr  RRF_UURF
+b94b   clfxtr  RRF_UURF
+b951   cdftr   RRF_UUFR
+b952   cdlgtr  RRF_UUFR
+b953   cdlftr  RRF_UUFR
+b959   cxftr   RRF_UUFR
+b95a   cxlgtr  RRF_UUFR
+b95b   cxlftr  RRF_UUFR
+b960   cgrt    RRF_U0RR
+b961   clgrt   RRF_U0RR
+b972   crt     RRF_U0RR
+b973   clrt    RRF_U0RR
+b980   ngr     RRE_RR
+b981   ogr     RRE_RR
+b982   xgr     RRE_RR
+b983   flogr   RRE_RR
+b984   llgcr   RRE_RR
+b985   llghr   RRE_RR
+b986   mlgr    RRE_RR
+b987   dlgr    RRE_RR
+b988   alcgr   RRE_RR
+b989   slbgr   RRE_RR
+b98a   cspg    RRE_RR
+b98d   epsw    RRE_RR
+b98e   idte    RRF_RURR2
+b98f   crdte   RRF_RURR2
+b990   trtt    RRF_U0RR
+b991   trto    RRF_U0RR
+b992   trot    RRF_U0RR
+b993   troo    RRF_U0RR
+b994   llcr    RRE_RR
+b995   llhr    RRE_RR
+b996   mlr     RRE_RR
+b997   dlr     RRE_RR
+b998   alcr    RRE_RR
+b999   slbr    RRE_RR
+b99a   epair   RRE_R0
+b99b   esair   RRE_R0
+b99d   esea    RRE_R0
+b99e   pti     RRE_RR
+b99f   ssair   RRE_R0
+b9a1   tpei    RRE_RR
+b9a2   ptf     RRE_R0
+b9aa   lptea   RRF_RURR2
+b9ac   irbm    RRE_RR
+b9ae   rrbm    RRE_RR
+b9af   pfmf    RRE_RR
+b9b0   cu14    RRF_U0RR
+b9b1   cu24    RRF_U0RR
+b9b2   cu41    RRE_RR
+b9b3   cu42    RRE_RR
+b9bd   trtre   RRF_U0RR
+b9be   srstu   RRE_RR
+b9bf   trte    RRF_U0RR
+b9c8   ahhhr   RRF_R0RR2
+b9c9   shhhr   RRF_R0RR2
+b9ca   alhhhr  RRF_R0RR2
+b9cb   slhhhr  RRF_R0RR2
+b9cd   chhr    RRE_RR
+b9cf   clhhr   RRE_RR
+b9d0   pcistg  RRE_RR
+b9d2   pcilg   RRE_RR
+b9d3   rpcit   RRE_RR
+b9d8   ahhlr   RRF_R0RR2
+b9d9   shhlr   RRF_R0RR2
+b9da   alhhlr  RRF_R0RR2
+b9db   slhhlr  RRF_R0RR2
+b9dd   chlr    RRE_RR
+b9df   clhlr   RRE_RR
+b9e0   locfhr  RRF_U0RR
+b9e1   popcnt  RRE_RR
+b9e2   locgr   RRF_U0RR
+b9e4   ngrk    RRF_R0RR2
+b9e6   ogrk    RRF_R0RR2
+b9e7   xgrk    RRF_R0RR2
+b9e8   agrk    RRF_R0RR2
+b9e9   sgrk    RRF_R0RR2
+b9ea   algrk   RRF_R0RR2
+b9eb   slgrk   RRF_R0RR2
+b9ec   mgrk    RRF_R0RR2
+b9ed   msgrkc  RRF_R0RR2
+b9f2   locr    RRF_U0RR
+b9f4   nrk     RRF_R0RR2
+b9f6   ork     RRF_R0RR2
+b9f7   xrk     RRF_R0RR2
+b9f8   ark     RRF_R0RR2
+b9f9   srk     RRF_R0RR2
+b9fa   alrk    RRF_R0RR2
+b9fb   slrk    RRF_R0RR2
+b9fd   msrkc   RRF_R0RR2
+ba     cs      RS_RRRD
+bb     cds     RS_RRRD
+bd     clm     RS_RURD
+be     stcm    RS_RURD
+bf     icm     RS_RURD
+c00    larl    RIL_RP
+c01    lgfi    RIL_RI
+c04    brcl    RIL_UP
+c05    brasl   RIL_RP
+c06    xihf    RIL_RU
+c07    xilf    RIL_RU
+c08    iihf    RIL_RU
+c09    iilf    RIL_RU
+c0a    nihf    RIL_RU
+c0b    nilf    RIL_RU
+c0c    oihf    RIL_RU
+c0d    oilf    RIL_RU
+c0e    llihf   RIL_RU
+c0f    llilf   RIL_RU
+c20    msgfi   RIL_RI
+c21    msfi    RIL_RI
+c24    slgfi   RIL_RU
+c25    slfi    RIL_RU
+c28    agfi    RIL_RI
+c29    afi     RIL_RI
+c2a    algfi   RIL_RU
+c2b    alfi    RIL_RU
+c2c    cgfi    RIL_RI
+c2d    cfi     RIL_RI
+c2e    clgfi   RIL_RU
+c2f    clfi    RIL_RU
+c42    llhrl   RIL_RP
+c44    lghrl   RIL_RP
+c45    lhrl    RIL_RP
+c46    llghrl  RIL_RP
+c47    sthrl   RIL_RP
+c48    lgrl    RIL_RP
+c4b    stgrl   RIL_RP
+c4c    lgfrl   RIL_RP
+c4d    lrl     RIL_RP
+c4e    llgfrl  RIL_RP
+c4f    strl    RIL_RP
+c5     bprp    MII_UPP
+c60    exrl    RIL_RP
+c62    pfdrl   RIL_UP
+c64    cghrl   RIL_RP
+c65    chrl    RIL_RP
+c66    clghrl  RIL_RP
+c67    clhrl   RIL_RP
+c68    cgrl    RIL_RP
+c6a    clgrl   RIL_RP
+c6c    cgfrl   RIL_RP
+c6d    crl     RIL_RP
+c6e    clgfrl  RIL_RP
+c6f    clrl    RIL_RP
+c7     bpp     SMI_U0RDP
+c80    mvcos   SSF_RRDRD
+c81    ectg    SSF_RRDRD
+c82    csst    SSF_RRDRD
+c84    lpd     SSF_RRDRD2
+c85    lpdg    SSF_RRDRD2
+cc6    brcth   RIL_RP
+cc8    aih     RIL_RI
+cca    alsih   RIL_RI
+ccb    alsihn  RIL_RI
+ccd    cih     RIL_RI
+ccf    clih    RIL_RU
+d0     trtr    SS_L0RDRD
+d1     mvn     SS_L0RDRD
+d2     mvc     SS_L0RDRD
+d3     mvz     SS_L0RDRD
+d4     nc      SS_L0RDRD
+d5     clc     SS_L0RDRD
+d6     oc      SS_L0RDRD
+d7     xc      SS_L0RDRD
+d9     mvck    SS_RRRDRD
+da     mvcp    SS_RRRDRD
+db     mvcs    SS_RRRDRD
+dc     tr      SS_L0RDRD
+dd     trt     SS_L0RDRD
+de     ed      SS_L0RDRD
+df     edmk    SS_L0RDRD
+e1     pku     SS_L2RDRD
+e2     unpku   SS_L0RDRD
+e302   ltg     RXY_RRRD
+e303   lrag    RXY_RRRD
+e304   lg      RXY_RRRD
+e306   cvby    RXY_RRRD
+e308   ag      RXY_RRRD
+e309   sg      RXY_RRRD
+e30a   alg     RXY_RRRD
+e30b   slg     RXY_RRRD
+e30c   msg     RXY_RRRD
+e30d   dsg     RXY_RRRD
+e30e   cvbg    RXY_RRRD
+e30f   lrvg    RXY_RRRD
+e312   lt      RXY_RRRD
+e313   lray    RXY_RRRD
+e314   lgf     RXY_RRRD
+e315   lgh     RXY_RRRD
+e316   llgf    RXY_RRRD
+e317   llgt    RXY_RRRD
+e318   agf     RXY_RRRD
+e319   sgf     RXY_RRRD
+e31a   algf    RXY_RRRD
+e31b   slgf    RXY_RRRD
+e31c   msgf    RXY_RRRD
+e31d   dsgf    RXY_RRRD
+e31e   lrv     RXY_RRRD
+e31f   lrvh    RXY_RRRD
+e320   cg      RXY_RRRD
+e321   clg     RXY_RRRD
+e324   stg     RXY_RRRD
+e325   ntstg   RXY_RRRD
+e326   cvdy    RXY_RRRD
+e32a   lzrg    RXY_RRRD
+e32e   cvdg    RXY_RRRD
+e32f   strvg   RXY_RRRD
+e330   cgf     RXY_RRRD
+e331   clgf    RXY_RRRD
+e332   ltgf    RXY_RRRD
+e334   cgh     RXY_RRRD
+e336   pfd     RXY_URRD
+e338   agh     RXY_RRRD
+e339   sgh     RXY_RRRD
+e33a   llzrgf  RXY_RRRD
+e33b   lzrf    RXY_RRRD
+e33c   mgh     RXY_RRRD
+e33e   strv    RXY_RRRD
+e33f   strvh   RXY_RRRD
+e346   bctg    RXY_RRRD
+e347   bic     RXY_URRD
+e348   llgfsg  RXY_RRRD
+e349   stgsc   RXY_RRRD
+e34c   lgg     RXY_RRRD
+e34d   lgsc    RXY_RRRD
+e350   sty     RXY_RRRD
+e351   msy     RXY_RRRD
+e353   msc     RXY_RRRD
+e354   ny      RXY_RRRD
+e355   cly     RXY_RRRD
+e356   oy      RXY_RRRD
+e357   xy      RXY_RRRD
+e358   ly      RXY_RRRD
+e359   cy      RXY_RRRD
+e35a   ay      RXY_RRRD
+e35b   sy      RXY_RRRD
+e35c   mfy     RXY_RRRD
+e35e   aly     RXY_RRRD
+e35f   sly     RXY_RRRD
+e370   sthy    RXY_RRRD
+e371   lay     RXY_RRRD
+e372   stcy    RXY_RRRD
+e373   icy     RXY_RRRD
+e375   laey    RXY_RRRD
+e376   lb      RXY_RRRD
+e377   lgb     RXY_RRRD
+e378   lhy     RXY_RRRD
+e379   chy     RXY_RRRD
+e37a   ahy     RXY_RRRD
+e37b   shy     RXY_RRRD
+e37c   mhy     RXY_RRRD
+e380   ng      RXY_RRRD
+e381   og      RXY_RRRD
+e382   xg      RXY_RRRD
+e383   msgc    RXY_RRRD
+e384   mg      RXY_RRRD
+e385   lgat    RXY_RRRD
+e386   mlg     RXY_RRRD
+e387   dlg     RXY_RRRD
+e388   alcg    RXY_RRRD
+e389   slbg    RXY_RRRD
+e38e   stpq    RXY_RRRD
+e38f   lpq     RXY_RRRD
+e390   llgc    RXY_RRRD
+e391   llgh    RXY_RRRD
+e394   llc     RXY_RRRD
+e395   llh     RXY_RRRD
+e396   ml      RXY_RRRD
+e397   dl      RXY_RRRD
+e398   alc     RXY_RRRD
+e399   slb     RXY_RRRD
+e39c   llgtat  RXY_RRRD
+e39d   llgfat  RXY_RRRD
+e39f   lat     RXY_RRRD
+e3c0   lbh     RXY_RRRD
+e3c2   llch    RXY_RRRD
+e3c3   stch    RXY_RRRD
+e3c4   lhh     RXY_RRRD
+e3c6   llhh    RXY_RRRD
+e3c7   sthh    RXY_RRRD
+e3c8   lfhat   RXY_RRRD
+e3ca   lfh     RXY_RRRD
+e3cb   stfh    RXY_RRRD
+e3cd   chf     RXY_RRRD
+e3cf   clhf    RXY_RRRD
+e3d0   mpcifc  RXY_RRRD
+e3d4   stpcifc RXY_RRRD
+e500   lasp    SSE_RDRD
+e501   tprot   SSE_RDRD
+e502   strag   SSE_RDRD
+e50e   mvcsk   SSE_RDRD
+e50f   mvcdk   SSE_RDRD
+e544   mvhhi   SIL_RDI
+e548   mvghi   SIL_RDI
+e54c   mvhi    SIL_RDI
+e554   chhsi   SIL_RDI
+e555   clhhsi  SIL_RDU
+e558   cghsi   SIL_RDI
+e559   clghsi  SIL_RDU
+e55c   chsi    SIL_RDI
+e55d   clfhsi  SIL_RDU
+e560   tbegin  SIL_RDU
+e561   tbeginc SIL_RDU
+e634   vpkz    VSI_URDV
+e635   vlrl    VSI_URDV
+e637   vlrlr   VRS_RRDV
+e63c   vupkz   VSI_URDV
+e63d   vstrl   VSI_URDV
+e63f   vstrlr  VRS_RRDV
+e649   vlip    VRI_V0UU2
+e650   vcvb    VRR_RV0U
+e652   vcvbg   VRR_RV0U
+e658   vcvd    VRI_VR0UU
+e659   vsrp    VRI_VVUUU2
+e65a   vcvdg   VRI_VR0UU
+e65b   vpsop   VRI_VVUUU2
+e65f   vtp     VRR_0V
+e671   vap     VRI_VVV0UU2
+e673   vsp     VRI_VVV0UU2
+e677   vcp     VRR_0VV0U
+e678   vmp     VRI_VVV0UU2
+e679   vmsp    VRI_VVV0UU2
+e67a   vdp     VRI_VVV0UU2
+e67b   vrp     VRI_VVV0UU2
+e67e   vsdp    VRI_VVV0UU2
+e700   vleb    VRX_VRRDU
+e701   vleh    VRX_VRRDU
+e702   vleg    VRX_VRRDU
+e703   vlef    VRX_VRRDU
+e704   vllez   VRX_VRRDU
+e705   vlrep   VRX_VRRDU
+e706   vl      VRX_VRRD
+e707   vlbb    VRX_VRRDU
+e708   vsteb   VRX_VRRDU
+e709   vsteh   VRX_VRRDU
+e70a   vsteg   VRX_VRRDU
+e70b   vstef   VRX_VRRDU
+e70e   vst     VRX_VRRD
+e712   vgeg    VRV_VVXRDU
+e713   vgef    VRV_VVXRDU
+e71a   vsceg   VRV_VVXRDU
+e71b   vscef   VRV_VVXRDU
+e721   vlgv    VRS_RVRDU
+e722   vlvg    VRS_VRRDU
+e727   lcbb    RXE_RRRDU
+e730   vesl    VRS_VVRDU
+e733   verll   VRS_VVRDU
+e736   vlm     VRS_VVRD
+e737   vll     VRS_VRRD
+e738   vesrl   VRS_VVRDU
+e73a   vesra   VRS_VVRDU
+e73e   vstm    VRS_VVRD
+e73f   vstl    VRS_VRRD
+e740   vleib   VRI_V0IU
+e741   vleih   VRI_V0IU
+e742   vleig   VRI_V0IU
+e743   vleif   VRI_V0IU
+e744   vgbm    VRI_V0U
+e745   vrepi   VRI_V0IU
+e746   vgm     VRI_V0UUU
+e74a   vftci   VRI_VVUUU
+e74d   vrep    VRI_VVUU
+e750   vpopct  VRR_VV0U
+e752   vctz    VRR_VV0U
+e753   vclz    VRR_VV0U
+e756   vlr     VRX_VV
+e75c   vistr   VRR_VV0U0U
+e75f   vseg    VRR_VV0U
+e760   vmrl    VRR_VVV0U
+e761   vmrh    VRR_VVV0U
+e762   vlvgp   VRR_VRR
+e764   vsum    VRR_VVV0U
+e765   vsumg   VRR_VVV0U
+e766   vcksm   VRR_VVV
+e767   vsumq   VRR_VVV0U
+e768   vn      VRR_VVV
+e769   vnc     VRR_VVV
+e76a   vo      VRR_VVV
+e76b   vno     VRR_VVV
+e76c   vnx     VRR_VVV
+e76d   vx      VRR_VVV
+e76e   vnn     VRR_VVV
+e76f   voc     VRR_VVV
+e770   veslv   VRR_VVV0U
+e772   verim   VRI_VVV0UU
+e773   verllv  VRR_VVV0U
+e774   vsl     VRR_VVV
+e775   vslb    VRR_VVV
+e777   vsldb   VRI_VVV0U
+e778   vesrlv  VRR_VVV0U
+e77a   vesrav  VRR_VVV0U
+e77c   vsrl    VRR_VVV
+e77d   vsrlb   VRR_VVV
+e77e   vsra    VRR_VVV
+e77f   vsrab   VRR_VVV
+e780   vfee    VRR_VVV0U0U
+e781   vfene   VRR_VVV0U0U
+e782   vfae    VRR_VVV0U0U
+e784   vpdi    VRR_VVV0U
+e785   vbperm  VRR_VVV
+e78a   vstrc   VRR_VVVUU0V
+e78c   vperm   VRR_VVV0V
+e78d   vsel    VRR_VVV0V
+e78e   vfms    VRR_VVVU0UV
+e78f   vfma    VRR_VVVU0UV
+e794   vpk     VRR_VVV0U
+e795   vpkls   VRR_VVV0U0U
+e797   vpks    VRR_VVV0U0U
+e79e   vfnms   VRR_VVVU0UV
+e79f   vfnma   VRR_VVVU0UV
+e7a1   vmlh    VRR_VVV0U
+e7a2   vml     VRR_VVV0U
+e7a3   vmh     VRR_VVV0U
+e7a4   vmle    VRR_VVV0U
+e7a5   vmlo    VRR_VVV0U
+e7a6   vme     VRR_VVV0U
+e7a7   vmo     VRR_VVV0U
+e7a9   vmalh   VRR_VVVU0V
+e7aa   vmal    VRR_VVVU0V
+e7ab   vmah    VRR_VVVU0V
+e7ac   vmale   VRR_VVVU0V
+e7ad   vmalo   VRR_VVVU0V
+e7ae   vmae    VRR_VVVU0V
+e7af   vmao    VRR_VVVU0V
+e7b4   vgfm    VRR_VVV0U
+e7b8   vmsl    VRR_VVVUU0V
+e7b9   vaccc   VRR_VVVU0V
+e7bb   vac     VRR_VVVU0V
+e7bc   vgfma   VRR_VVVU0V
+e7bd   vsbcbi  VRR_VVVU0V
+e7bf   vsbi    VRR_VVVU0V
+e7c0   vclgd   VRR_VV0UUU
+e7c1   vcdlg   VRR_VV0UUU
+e7c2   vcgd    VRR_VV0UUU
+e7c3   vcdg    VRR_VV0UUU
+e7c4   vlde    VRR_VV0UU2
+e7c5   vled    VRR_VV0UUU
+e7c7   vfi     VRR_VV0UUU
+e7ca   wfk     VRR_VV0UU2
+e7cb   wfc     VRR_VV0UU2
+e7cc   vfpso   VRR_VV0UUU
+e7ce   vfsq    VRR_VV0UU2
+e7d4   vupll   VRR_VV0U
+e7d5   vuplh   VRR_VV0U
+e7d6   vupl    VRR_VV0U
+e7d7   vuph    VRR_VV0U
+e7d8   vtm     VRR_VV
+e7d9   vecl    VRR_VV0U
+e7db   vec     VRR_VV0U
+e7de   vlc     VRR_VV0U
+e7df   vlp     VRR_VV0U
+e7e2   vfs     VRR_VVV0UU
+e7e3   vfa     VRR_VVV0UU
+e7e5   vfd     VRR_VVV0UU
+e7e7   vfm     VRR_VVV0UU
+e7e8   vfce    VRR_VVV0UUU
+e7ea   vfche   VRR_VVV0UUU
+e7eb   vfch    VRR_VVV0UUU
+e7ee   vfmin   VRR_VVV0UUU
+e7ef   vfmax   VRR_VVV0UUU
+e7f0   vavgl   VRR_VVV0U
+e7f1   vacc    VRR_VVV0U
+e7f2   vavg    VRR_VVV0U
+e7f3   va      VRR_VVV0U
+e7f5   vscbi   VRR_VVV0U
+e7f7   vs      VRR_VVV0U
+e7f8   vceq    VRR_VVV0U0U
+e7f9   vchl    VRR_VVV0U0U
+e7fb   vch     VRR_VVV0U0U
+e7fc   vmnl    VRR_VVV0U
+e7fd   vmxl    VRR_VVV0U
+e7fe   vmn     VRR_VVV0U
+e7ff   vmx     VRR_VVV0U
+e8     mvcin   SS_L0RDRD
+e9     pka     SS_L2RDRD
+ea     unpka   SS_L0RDRD
+eb04   lmg     RSY_RRRD
+eb0a   srag    RSY_RRRD
+eb0b   slag    RSY_RRRD
+eb0c   srlg    RSY_RRRD
+eb0d   sllg    RSY_RRRD
+eb0f   tracg   RSY_RRRD
+eb14   csy     RSY_RRRD
+eb17   stcctm  RSY_RURD
+eb1c   rllg    RSY_RRRD
+eb1d   rll     RSY_RRRD
+eb20   clmh    RSY_RURD
+eb21   clmy    RSY_RURD
+eb23   clt     RSY_RURD
+eb24   stmg    RSY_RRRD
+eb25   stctg   RSY_CCRD
+eb26   stmh    RSY_RRRD
+eb2b   clgt    RSY_RURD
+eb2c   stcmh   RSY_RURD
+eb2d   stcmy   RSY_RURD
+eb2f   lctlg   RSY_CCRD
+eb30   csg     RSY_RRRD
+eb31   cdsy    RSY_RRRD
+eb3e   cdsg    RSY_RRRD
+eb44   bxhg    RSY_RRRD
+eb45   bxleg   RSY_RRRD
+eb4c   ecag    RSY_RRRD
+eb51   tmy     SIY_URD
+eb52   mviy    SIY_URD
+eb54   niy     SIY_URD
+eb55   cliy    SIY_URD
+eb56   oiy     SIY_URD
+eb57   xiy     SIY_URD
+eb60   lric    RSY_RDRU
+eb61   stric   RSY_RDRU
+eb62   mric    RSY_RDRU
+eb6a   asi     SIY_IRD
+eb6e   alsi    SIY_IRD
+eb7a   agsi    SIY_IRD
+eb7e   algsi   SIY_IRD
+eb80   icmh    RSY_RURD
+eb81   icmy    RSY_RURD
+eb8e   mvclu   RSY_RRRD
+eb8f   clclu   RSY_RRRD
+eb90   stmy    RSY_RRRD
+eb96   lmh     RSY_RRRD
+eb98   lmy     RSY_RRRD
+eb9a   lamy    RSY_AARD
+eb9b   stamy   RSY_AARD
+ebc0   tp      RSL_R0RD
+ebd0   pcistb  RSY_RRRD
+ebd1   sic     RSY_RRRD
+ebdc   srak    RSY_RRRD
+ebdd   slak    RSY_RRRD
+ebde   srlk    RSY_RRRD
+ebdf   sllk    RSY_RRRD
+ebe0   locfh   RSY_RURD2
+ebe1   stocfh  RSY_RURD2
+ebe2   locg    RSY_RURD2
+ebe3   stocg   RSY_RURD2
+ebe4   lang    RSY_RRRD
+ebe6   laog    RSY_RRRD
+ebe7   laxg    RSY_RRRD
+ebe8   laag    RSY_RRRD
+ebea   laalg   RSY_RRRD
+ebf2   loc     RSY_RURD2
+ebf3   stoc    RSY_RURD2
+ebf4   lan     RSY_RRRD
+ebf6   lao     RSY_RRRD
+ebf7   lax     RSY_RRRD
+ebf8   laa     RSY_RRRD
+ebfa   laal    RSY_RRRD
+ec42   lochi   RIE_RUI0
+ec44   brxhg   RIE_RRP
+ec45   brxlg   RIE_RRP
+ec46   locghi  RIE_RUI0
+ec4e   lochhi  RIE_RUI0
+ec51   risblg  RIE_RRUUU
+ec54   rnsbg   RIE_RRUUU
+ec55   risbg   RIE_RRUUU
+ec56   rosbg   RIE_RRUUU
+ec57   rxsbg   RIE_RRUUU
+ec59   risbgn  RIE_RRUUU
+ec5d   risbhg  RIE_RRUUU
+ec64   cgrj    RIE_RRPU
+ec65   clgrj   RIE_RRPU
+ec70   cgit    RIE_R0IU
+ec71   clgit   RIE_R0UU
+ec72   cit     RIE_R0IU
+ec73   clfit   RIE_R0UU
+ec76   crj     RIE_RRPU
+ec77   clrj    RIE_RRPU
+ec7c   cgij    RIE_RUPI
+ec7d   clgij   RIE_RUPU
+ec7e   cij     RIE_RUPI
+ec7f   clij    RIE_RUPU
+ecd8   ahik    RIE_RRI0
+ecd9   aghik   RIE_RRI0
+ecda   alhsik  RIE_RRI0
+ecdb   alghsik RIE_RRI0
+ece4   cgrb    RRS_RRRDU
+ece5   clgrb   RRS_RRRDU
+ecf6   crb     RRS_RRRDU
+ecf7   clrb    RRS_RRRDU
+ecfc   cgib    RIS_RURDI
+ecfd   clgib   RIS_RURDU
+ecfe   cib     RIS_RURDI
+ecff   clib    RIS_RURDU
+ed04   ldeb    RXE_FRRD
+ed05   lxdb    RXE_FRRD
+ed06   lxeb    RXE_FRRD
+ed07   mxdb    RXE_FRRD
+ed08   keb     RXE_FRRD
+ed09   ceb     RXE_FRRD
+ed0a   aeb     RXE_FRRD
+ed0b   seb     RXE_FRRD
+ed0c   mdeb    RXE_FRRD
+ed0d   deb     RXE_FRRD
+ed0e   maeb    RXF_FRRDF
+ed0f   mseb    RXF_FRRDF
+ed10   tceb    RXE_FRRD
+ed11   tcdb    RXE_FRRD
+ed12   tcxb    RXE_FRRD
+ed14   sqeb    RXE_FRRD
+ed15   sqdb    RXE_FRRD
+ed17   meeb    RXE_FRRD
+ed18   kdb     RXE_FRRD
+ed19   cdb     RXE_FRRD
+ed1a   adb     RXE_FRRD
+ed1b   sdb     RXE_FRRD
+ed1c   mdb     RXE_FRRD
+ed1d   ddb     RXE_FRRD
+ed1e   madb    RXF_FRRDF
+ed1f   msdb    RXF_FRRDF
+ed24   lde     RXE_FRRD
+ed25   lxd     RXE_FRRD
+ed26   lxe     RXE_FRRD
+ed2e   mae     RXF_FRRDF
+ed2f   mse     RXF_FRRDF
+ed34   sqe     RXE_FRRD
+ed35   sqd     RXE_FRRD
+ed37   mee     RXE_FRRD
+ed38   mayl    RXF_FRRDF
+ed39   myl     RXF_FRRDF
+ed3a   may     RXF_FRRDF
+ed3b   my      RXF_FRRDF
+ed3c   mayh    RXF_FRRDF
+ed3d   myh     RXF_FRRDF
+ed3e   mad     RXF_FRRDF
+ed3f   msd     RXF_FRRDF
+ed40   sldt    RXF_FRRDF
+ed41   srdt    RXF_FRRDF
+ed48   slxt    RXF_FRRDF
+ed49   srxt    RXF_FRRDF
+ed50   tdcet   RXE_FRRD
+ed51   tdget   RXE_FRRD
+ed54   tdcdt   RXE_FRRD
+ed55   tdgdt   RXE_FRRD
+ed58   tdcxt   RXE_FRRD
+ed59   tdgxt   RXE_FRRD
+ed64   ley     RXY_FRRD
+ed65   ldy     RXY_FRRD
+ed66   stey    RXY_FRRD
+ed67   stdy    RXY_FRRD
+eda8   czdt    RSL_LRDFU
+eda9   czxt    RSL_LRDFU
+edaa   cdzt    RSL_LRDFU
+edab   cxzt    RSL_LRDFU
+edac   cpdt    RSL_LRDFU
+edad   cpxt    RSL_LRDFU
+edae   cdpt    RSL_LRDFU
+edaf   cxpt    RSL_LRDFU
+ee     plo     SS_RRRDRD2
+ef     lmd     SS_RRRDRD3
+f0     srp     SS_LIRDRD
+f1     mvo     SS_LLRDRD
+f2     pack    SS_LLRDRD
+f3     unpk    SS_LLRDRD
+f8     zap     SS_LLRDRD
+f9     cp      SS_LLRDRD
+fa     ap      SS_LLRDRD
+fb     sp      SS_LLRDRD
+fc     mp      SS_LLRDRD
+fd     dp      SS_LLRDRD
index 5ed7dbbd94ff5bce146bf9581297d9e1358373e7..270ee4d3e25b8acc9fd2231d2b93d061d18a9fc7 100644 (file)
@@ -27,7 +27,6 @@ static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new
  */
 
 #define arch_spin_is_locked(x)         ((x)->lock <= 0)
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
@@ -53,18 +52,6 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
  * read-locks.
  */
 
-/**
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_read_can_lock(x)  ((x)->lock > 0)
-
-/**
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
-
 static inline void arch_read_lock(arch_rwlock_t *rw)
 {
        unsigned old;
@@ -102,11 +89,4 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
        return __sl_cas(&rw->lock, RW_LOCK_BIAS, 0) == RW_LOCK_BIAS;
 }
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SH_SPINLOCK_CAS_H */
index f77263aae7607ff649ff167446c44879f2133345..715595de286a8348f05ac5470db369d130febcdd 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #define arch_spin_is_locked(x)         ((x)->lock <= 0)
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
@@ -89,18 +88,6 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
  * read-locks.
  */
 
-/**
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_read_can_lock(x)  ((x)->lock > 0)
-
-/**
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
-
 static inline void arch_read_lock(arch_rwlock_t *rw)
 {
        unsigned long tmp;
@@ -209,11 +196,4 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
        return (oldval > (RW_LOCK_BIAS - 1));
 }
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SH_SPINLOCK_LLSC_H */
index 0c3b3b4a99633e7d3500c19c07393cc1b4633cdc..d13ce517f4b9946382579a7a4d5e9bbccdb6332e 100644 (file)
@@ -32,7 +32,7 @@ void atomic_set(atomic_t *, int);
 
 #define atomic_set_release(v, i)       atomic_set((v), (i))
 
-#define atomic_read(v)          ACCESS_ONCE((v)->counter)
+#define atomic_read(v)          READ_ONCE((v)->counter)
 
 #define atomic_add(i, v)       ((void)atomic_add_return( (int)(i), (v)))
 #define atomic_sub(i, v)       ((void)atomic_add_return(-(int)(i), (v)))
index 6a339a78f4f42b442bfd40b8353356223ee831cb..71dd82b43cc57d84847a87bb315b6c2e19cda4e5 100644 (file)
@@ -7,6 +7,7 @@
 #if defined(__sparc__) && defined(__arch64__)
 #ifndef __ASSEMBLY__
 
+#include <linux/compiler.h>
 #include <linux/threads.h>
 #include <asm/switch_to.h>
 
index 26f00ac2b4700a41ba525cc2568367fb84813b23..bc5aa6f61676430890feec03b296725afe664893 100644 (file)
@@ -183,17 +183,6 @@ static inline int __arch_read_trylock(arch_rwlock_t *rw)
        res; \
 })
 
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-#define arch_read_lock_flags(rw, flags)   arch_read_lock(rw)
-#define arch_write_lock_flags(rw, flags)  arch_write_lock(rw)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
-#define arch_read_can_lock(rw) (!((rw)->lock & 0xff))
-#define arch_write_can_lock(rw) (!(rw)->lock)
-
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* __SPARC_SPINLOCK_H */
index 4822a7e94a30b839a09cf8a9bf4b2263611ff6fd..7fc82a233f4957c97bf8f0913a43bacd04a7eefc 100644 (file)
 #include <asm/qrwlock.h>
 #include <asm/qspinlock.h>
 
-#define arch_read_lock_flags(p, f) arch_read_lock(p)
-#define arch_write_lock_flags(p, f) arch_write_lock(p)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC64_SPINLOCK_H) */
index e278bf52963b58e834ca21015ac59c2a84fe6ec0..519f5ba7ed7e7e61609c3f4d2ed20d9fc56a23ba 100644 (file)
@@ -31,19 +31,20 @@ static inline void led_toggle(void)
 }
 
 static struct timer_list led_blink_timer;
+static unsigned long led_blink_timer_timeout;
 
-static void led_blink(unsigned long timeout)
+static void led_blink(struct timer_list *unused)
 {
+       unsigned long timeout = led_blink_timer_timeout;
+
        led_toggle();
 
        /* reschedule */
        if (!timeout) { /* blink according to load */
                led_blink_timer.expires = jiffies +
                        ((1 + (avenrun[0] >> FSHIFT)) * HZ);
-               led_blink_timer.data = 0;
        } else { /* blink at user specified interval */
                led_blink_timer.expires = jiffies + (timeout * HZ);
-               led_blink_timer.data = timeout;
        }
        add_timer(&led_blink_timer);
 }
@@ -88,9 +89,11 @@ static ssize_t led_proc_write(struct file *file, const char __user *buffer,
        } else if (!strcmp(buf, "toggle")) {
                led_toggle();
        } else if ((*buf > '0') && (*buf <= '9')) {
-               led_blink(simple_strtoul(buf, NULL, 10));
+               led_blink_timer_timeout = simple_strtoul(buf, NULL, 10);
+               led_blink(&led_blink_timer);
        } else if (!strcmp(buf, "load")) {
-               led_blink(0);
+               led_blink_timer_timeout = 0;
+               led_blink(&led_blink_timer);
        } else {
                auxio_set_led(AUXIO_LED_OFF);
        }
@@ -115,8 +118,7 @@ static struct proc_dir_entry *led;
 
 static int __init led_init(void)
 {
-       init_timer(&led_blink_timer);
-       led_blink_timer.function = led_blink;
+       timer_setup(&led_blink_timer, led_blink, 0);
 
        led = proc_create("led", 0, NULL, &led_proc_fops);
        if (!led)
index baa60357f8ba20b2e757f0aeebf01b37607d4be8..b7ba577d82ca36e82a44dd09e1c0fab47d6a0da7 100644 (file)
@@ -163,14 +163,14 @@ int __gxio_dma_queue_is_complete(__gxio_dma_queue_t *dma_queue,
                                 int64_t completion_slot, int update)
 {
        if (update) {
-               if (ACCESS_ONCE(dma_queue->hw_complete_count) >
+               if (READ_ONCE(dma_queue->hw_complete_count) >
                    completion_slot)
                        return 1;
 
                __gxio_dma_queue_update_credits(dma_queue);
        }
 
-       return ACCESS_ONCE(dma_queue->hw_complete_count) > completion_slot;
+       return READ_ONCE(dma_queue->hw_complete_count) > completion_slot;
 }
 
 EXPORT_SYMBOL_GPL(__gxio_dma_queue_is_complete);
index cba8ba9b8da6ab218cee2d4ca3cecaf6a2488d97..fb5313d773156a499cf224565404794c62ca2014 100644 (file)
@@ -51,9 +51,6 @@ static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 
 void arch_spin_lock(arch_spinlock_t *lock);
 
-/* We cannot take an interrupt after getting a ticket, so don't enable them. */
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
 int arch_spin_trylock(arch_spinlock_t *lock);
 
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
@@ -79,22 +76,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 #define _RD_COUNT_SHIFT 24
 #define _RD_COUNT_WIDTH 8
 
-/**
- * arch_read_can_lock() - would read_trylock() succeed?
- */
-static inline int arch_read_can_lock(arch_rwlock_t *rwlock)
-{
-       return (rwlock->lock << _RD_COUNT_WIDTH) == 0;
-}
-
-/**
- * arch_write_can_lock() - would write_trylock() succeed?
- */
-static inline int arch_write_can_lock(arch_rwlock_t *rwlock)
-{
-       return rwlock->lock == 0;
-}
-
 /**
  * arch_read_lock() - acquire a read lock.
  */
@@ -125,7 +106,4 @@ void arch_read_unlock(arch_rwlock_t *rwlock);
  */
 void arch_write_unlock(arch_rwlock_t *rwlock);
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
 #endif /* _ASM_TILE_SPINLOCK_32_H */
index 9a2c2d605752e6649c97286389013b1cce5f3e2f..5b616ef642a8b5cab238a9b310b3561b6f07f2a6 100644 (file)
@@ -75,9 +75,6 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
 /* Try to get the lock, and return whether we succeeded. */
 int arch_spin_trylock(arch_spinlock_t *lock);
 
-/* We cannot take an interrupt after getting a ticket, so don't enable them. */
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
@@ -93,24 +90,6 @@ static inline int arch_write_val_locked(int val)
        return val < 0;  /* Optimize "val & __WRITE_LOCK_BIT". */
 }
 
-/**
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-static inline int arch_read_can_lock(arch_rwlock_t *rw)
-{
-       return !arch_write_val_locked(rw->lock);
-}
-
-/**
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-static inline int arch_write_can_lock(arch_rwlock_t *rw)
-{
-       return rw->lock == 0;
-}
-
 extern void __read_lock_failed(arch_rwlock_t *rw);
 
 static inline void arch_read_lock(arch_rwlock_t *rw)
@@ -156,7 +135,4 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
        return 0;
 }
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
 #endif /* _ASM_TILE_SPINLOCK_64_H */
index b9e45e37649e324efe95df53695398cfe1d72958..c8fd47edba30f49910f35f0e5080ef27f353bf65 100644 (file)
@@ -121,7 +121,7 @@ static inline int64_t __gxio_dma_queue_reserve(__gxio_dma_queue_t *dma_queue,
                 * if the result is LESS than "hw_complete_count".
                 */
                uint64_t complete;
-               complete = ACCESS_ONCE(dma_queue->hw_complete_count);
+               complete = READ_ONCE(dma_queue->hw_complete_count);
                slot |= (complete & 0xffffffffff000000);
                if (slot < complete)
                        slot += 0x1000000;
index e1a078e6828e5915968de2adac4b306d870e421f..d516d61751c2250dbaa60bdb9c0b24dfe09e28e9 100644 (file)
@@ -255,7 +255,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 
 int do_syscall_trace_enter(struct pt_regs *regs)
 {
-       u32 work = ACCESS_ONCE(current_thread_info()->flags);
+       u32 work = READ_ONCE(current_thread_info()->flags);
 
        if ((work & _TIF_SYSCALL_TRACE) &&
            tracehook_report_syscall_entry(regs)) {
index 390572daa40de1605f3f3ff65f8881fa0bfe235b..b3f5865a92c911b8ad82ff8ce1d4ec143d175296 100644 (file)
@@ -41,7 +41,7 @@
 typedef int (*initcall_t)(void);
 typedef void (*exitcall_t)(void);
 
-#include <linux/compiler.h>
+#include <linux/compiler_types.h>
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
index 2fdb23313dd55fa2d08fee3e15c47bde6ef632ac..f08977d82ca0dd2cb49ee4798b45245fa1b5999c 100644 (file)
@@ -56,7 +56,7 @@ config X86
        select ARCH_HAS_KCOV                    if X86_64
        select ARCH_HAS_PMEM_API                if X86_64
        # Causing hangs/crashes, see the commit that added this change for details.
-       select ARCH_HAS_REFCOUNT                if BROKEN
+       select ARCH_HAS_REFCOUNT
        select ARCH_HAS_UACCESS_FLUSHCACHE      if X86_64
        select ARCH_HAS_SET_MEMORY
        select ARCH_HAS_SG_CHAIN
@@ -93,8 +93,10 @@ config X86
        select GENERIC_FIND_FIRST_BIT
        select GENERIC_IOMAP
        select GENERIC_IRQ_EFFECTIVE_AFF_MASK   if SMP
+       select GENERIC_IRQ_MATRIX_ALLOCATOR     if X86_LOCAL_APIC
        select GENERIC_IRQ_MIGRATION            if SMP
        select GENERIC_IRQ_PROBE
+       select GENERIC_IRQ_RESERVATION_MODE
        select GENERIC_IRQ_SHOW
        select GENERIC_PENDING_IRQ              if SMP
        select GENERIC_SMP_IDLE_THREAD
@@ -171,7 +173,7 @@ config X86
        select HAVE_PERF_USER_STACK_DUMP
        select HAVE_RCU_TABLE_FREE
        select HAVE_REGS_AND_STACK_ACCESS_API
-       select HAVE_RELIABLE_STACKTRACE         if X86_64 && FRAME_POINTER_UNWINDER && STACK_VALIDATION
+       select HAVE_RELIABLE_STACKTRACE         if X86_64 && UNWINDER_FRAME_POINTER && STACK_VALIDATION
        select HAVE_STACK_VALIDATION            if X86_64
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_UNSTABLE_SCHED_CLOCK
@@ -303,7 +305,6 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC
 config KASAN_SHADOW_OFFSET
        hex
        depends on KASAN
-       default 0xdff8000000000000 if X86_5LEVEL
        default 0xdffffc0000000000
 
 config HAVE_INTEL_TXT
@@ -1803,6 +1804,16 @@ config X86_SMAP
 
          If unsure, say Y.
 
+config X86_INTEL_UMIP
+       def_bool n
+       depends on CPU_SUP_INTEL
+       prompt "Intel User Mode Instruction Prevention" if EXPERT
+       ---help---
+         The User Mode Instruction Prevention (UMIP) is a security
+         feature in newer Intel processors. If enabled, a general
+         protection fault is issued if the instructions SGDT, SLDT,
+         SIDT, SMSW and STR are executed in user mode.
+
 config X86_INTEL_MPX
        prompt "Intel MPX (Memory Protection Extensions)"
        def_bool n
index 90b123056f4b389a40f51b1c0594493ad31af180..6293a8768a9123038eeced9e8dc2c4874feed275 100644 (file)
@@ -359,28 +359,14 @@ config PUNIT_ATOM_DEBUG
 
 choice
        prompt "Choose kernel unwinder"
-       default FRAME_POINTER_UNWINDER
+       default UNWINDER_ORC if X86_64
+       default UNWINDER_FRAME_POINTER if X86_32
        ---help---
          This determines which method will be used for unwinding kernel stack
          traces for panics, oopses, bugs, warnings, perf, /proc/<pid>/stack,
          livepatch, lockdep, and more.
 
-config FRAME_POINTER_UNWINDER
-       bool "Frame pointer unwinder"
-       select FRAME_POINTER
-       ---help---
-         This option enables the frame pointer unwinder for unwinding kernel
-         stack traces.
-
-         The unwinder itself is fast and it uses less RAM than the ORC
-         unwinder, but the kernel text size will grow by ~3% and the kernel's
-         overall performance will degrade by roughly 5-10%.
-
-         This option is recommended if you want to use the livepatch
-         consistency model, as this is currently the only way to get a
-         reliable stack trace (CONFIG_HAVE_RELIABLE_STACKTRACE).
-
-config ORC_UNWINDER
+config UNWINDER_ORC
        bool "ORC unwinder"
        depends on X86_64
        select STACK_VALIDATION
@@ -396,7 +382,22 @@ config ORC_UNWINDER
          Enabling this option will increase the kernel's runtime memory usage
          by roughly 2-4MB, depending on your kernel config.
 
-config GUESS_UNWINDER
+config UNWINDER_FRAME_POINTER
+       bool "Frame pointer unwinder"
+       select FRAME_POINTER
+       ---help---
+         This option enables the frame pointer unwinder for unwinding kernel
+         stack traces.
+
+         The unwinder itself is fast and it uses less RAM than the ORC
+         unwinder, but the kernel text size will grow by ~3% and the kernel's
+         overall performance will degrade by roughly 5-10%.
+
+         This option is recommended if you want to use the livepatch
+         consistency model, as this is currently the only way to get a
+         reliable stack trace (CONFIG_HAVE_RELIABLE_STACKTRACE).
+
+config UNWINDER_GUESS
        bool "Guess unwinder"
        depends on EXPERT
        ---help---
@@ -411,7 +412,7 @@ config GUESS_UNWINDER
 endchoice
 
 config FRAME_POINTER
-       depends on !ORC_UNWINDER && !GUESS_UNWINDER
+       depends on !UNWINDER_ORC && !UNWINDER_GUESS
        bool
 
 endmenu
index e3cf9f682be55e5d07617a7ba921bead05a218e1..09d25dd093075789440b1d7a8874cf461cd0c01e 100644 (file)
@@ -7,3 +7,6 @@ zoffset.h
 setup
 setup.bin
 setup.elf
+fdimage
+mtools.conf
+image.iso
index d88a2fddba8c7edb3eda2e21ea4a142ea25644a9..9b5adae9cc40cf59a5c8244bb3eb361a4772b626 100644 (file)
@@ -123,63 +123,26 @@ image_cmdline = default linux $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,)
 $(obj)/mtools.conf: $(src)/mtools.conf.in
        sed -e 's|@OBJ@|$(obj)|g' < $< > $@
 
+quiet_cmd_genimage = GENIMAGE $3
+cmd_genimage = sh $(srctree)/$(src)/genimage.sh $2 $3 $(obj)/bzImage \
+                       $(obj)/mtools.conf '$(image_cmdline)' $(FDINITRD)
+
 # This requires write access to /dev/fd0
 bzdisk: $(obj)/bzImage $(obj)/mtools.conf
-       MTOOLSRC=$(obj)/mtools.conf mformat a:                  ; sync
-       syslinux /dev/fd0                                       ; sync
-       echo '$(image_cmdline)' | \
-               MTOOLSRC=$(src)/mtools.conf mcopy - a:syslinux.cfg
-       if [ -f '$(FDINITRD)' ] ; then \
-               MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' a:initrd.img ; \
-       fi
-       MTOOLSRC=$(obj)/mtools.conf mcopy $(obj)/bzImage a:linux        ; sync
+       $(call cmd,genimage,bzdisk,/dev/fd0)
 
 # These require being root or having syslinux 2.02 or higher installed
 fdimage fdimage144: $(obj)/bzImage $(obj)/mtools.conf
-       dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440
-       MTOOLSRC=$(obj)/mtools.conf mformat v:                  ; sync
-       syslinux $(obj)/fdimage                                 ; sync
-       echo '$(image_cmdline)' | \
-               MTOOLSRC=$(obj)/mtools.conf mcopy - v:syslinux.cfg
-       if [ -f '$(FDINITRD)' ] ; then \
-               MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' v:initrd.img ; \
-       fi
-       MTOOLSRC=$(obj)/mtools.conf mcopy $(obj)/bzImage v:linux        ; sync
+       $(call cmd,genimage,fdimage144,$(obj)/fdimage)
+       @$(kecho) 'Kernel: $(obj)/fdimage is ready'
 
 fdimage288: $(obj)/bzImage $(obj)/mtools.conf
-       dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880
-       MTOOLSRC=$(obj)/mtools.conf mformat w:                  ; sync
-       syslinux $(obj)/fdimage                                 ; sync
-       echo '$(image_cmdline)' | \
-               MTOOLSRC=$(obj)/mtools.conf mcopy - w:syslinux.cfg
-       if [ -f '$(FDINITRD)' ] ; then \
-               MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' w:initrd.img ; \
-       fi
-       MTOOLSRC=$(obj)/mtools.conf mcopy $(obj)/bzImage w:linux        ; sync
+       $(call cmd,genimage,fdimage288,$(obj)/fdimage)
+       @$(kecho) 'Kernel: $(obj)/fdimage is ready'
 
 isoimage: $(obj)/bzImage
-       -rm -rf $(obj)/isoimage
-       mkdir $(obj)/isoimage
-       for i in lib lib64 share end ; do \
-               if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \
-                       cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \
-                       if [ -f /usr/$$i/syslinux/ldlinux.c32 ]; then \
-                               cp /usr/$$i/syslinux/ldlinux.c32 $(obj)/isoimage ; \
-                       fi ; \
-                       break ; \
-               fi ; \
-               if [ $$i = end ] ; then exit 1 ; fi ; \
-       done
-       cp $(obj)/bzImage $(obj)/isoimage/linux
-       echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
-       if [ -f '$(FDINITRD)' ] ; then \
-               cp '$(FDINITRD)' $(obj)/isoimage/initrd.img ; \
-       fi
-       mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
-               -no-emul-boot -boot-load-size 4 -boot-info-table \
-               $(obj)/isoimage
-       isohybrid $(obj)/image.iso 2>/dev/null || true
-       rm -rf $(obj)/isoimage
+       $(call cmd,genimage,isoimage,$(obj)/image.iso)
+       @$(kecho) 'Kernel: $(obj)/image.iso is ready'
 
 bzlilo: $(obj)/bzImage
        if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
index 4b7575b0056311097d3b2d1a1a1a0f37f6e58f7c..1e9c322e973af0e1024dc3751b99d16eb76574f7 100644 (file)
@@ -36,6 +36,7 @@ KBUILD_CFLAGS += -mno-mmx -mno-sse
 KBUILD_CFLAGS += $(call cc-option,-ffreestanding)
 KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
 KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
+KBUILD_CFLAGS += $(call cc-disable-warning, gnu)
 
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 GCOV_PROFILE := n
@@ -78,6 +79,7 @@ vmlinux-objs-$(CONFIG_EARLY_PRINTK) += $(obj)/early_serial_console.o
 vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/kaslr.o
 ifdef CONFIG_X86_64
        vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/pagetable.o
+       vmlinux-objs-y += $(obj)/mem_encrypt.o
 endif
 
 $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
index beb255b66447a8392f38f3ae3d0ff16e893f582e..20919b4f31330fbc36528e47cf7dd010e516c31c 100644 (file)
@@ -131,6 +131,19 @@ ENTRY(startup_32)
  /*
   * Build early 4G boot pagetable
   */
+       /*
+        * If SEV is active then set the encryption mask in the page tables.
+        * This will insure that when the kernel is copied and decompressed
+        * it will be done so encrypted.
+        */
+       call    get_sev_encryption_bit
+       xorl    %edx, %edx
+       testl   %eax, %eax
+       jz      1f
+       subl    $32, %eax       /* Encryption bit is always above bit 31 */
+       bts     %eax, %edx      /* Set encryption mask for page tables */
+1:
+
        /* Initialize Page tables to 0 */
        leal    pgtable(%ebx), %edi
        xorl    %eax, %eax
@@ -141,12 +154,14 @@ ENTRY(startup_32)
        leal    pgtable + 0(%ebx), %edi
        leal    0x1007 (%edi), %eax
        movl    %eax, 0(%edi)
+       addl    %edx, 4(%edi)
 
        /* Build Level 3 */
        leal    pgtable + 0x1000(%ebx), %edi
        leal    0x1007(%edi), %eax
        movl    $4, %ecx
 1:     movl    %eax, 0x00(%edi)
+       addl    %edx, 0x04(%edi)
        addl    $0x00001000, %eax
        addl    $8, %edi
        decl    %ecx
@@ -157,6 +172,7 @@ ENTRY(startup_32)
        movl    $0x00000183, %eax
        movl    $2048, %ecx
 1:     movl    %eax, 0(%edi)
+       addl    %edx, 4(%edi)
        addl    $0x00200000, %eax
        addl    $8, %edi
        decl    %ecx
diff --git a/arch/x86/boot/compressed/mem_encrypt.S b/arch/x86/boot/compressed/mem_encrypt.S
new file mode 100644 (file)
index 0000000..54f5f66
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * AMD Memory Encryption Support
+ *
+ * Copyright (C) 2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Tom Lendacky <thomas.lendacky@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/processor-flags.h>
+#include <asm/msr.h>
+#include <asm/asm-offsets.h>
+
+       .text
+       .code32
+ENTRY(get_sev_encryption_bit)
+       xor     %eax, %eax
+
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+       push    %ebx
+       push    %ecx
+       push    %edx
+       push    %edi
+
+       /*
+        * RIP-relative addressing is needed to access the encryption bit
+        * variable. Since we are running in 32-bit mode we need this call/pop
+        * sequence to get the proper relative addressing.
+        */
+       call    1f
+1:     popl    %edi
+       subl    $1b, %edi
+
+       movl    enc_bit(%edi), %eax
+       cmpl    $0, %eax
+       jge     .Lsev_exit
+
+       /* Check if running under a hypervisor */
+       movl    $1, %eax
+       cpuid
+       bt      $31, %ecx               /* Check the hypervisor bit */
+       jnc     .Lno_sev
+
+       movl    $0x80000000, %eax       /* CPUID to check the highest leaf */
+       cpuid
+       cmpl    $0x8000001f, %eax       /* See if 0x8000001f is available */
+       jb      .Lno_sev
+
+       /*
+        * Check for the SEV feature:
+        *   CPUID Fn8000_001F[EAX] - Bit 1
+        *   CPUID Fn8000_001F[EBX] - Bits 5:0
+        *     Pagetable bit position used to indicate encryption
+        */
+       movl    $0x8000001f, %eax
+       cpuid
+       bt      $1, %eax                /* Check if SEV is available */
+       jnc     .Lno_sev
+
+       movl    $MSR_AMD64_SEV, %ecx    /* Read the SEV MSR */
+       rdmsr
+       bt      $MSR_AMD64_SEV_ENABLED_BIT, %eax        /* Check if SEV is active */
+       jnc     .Lno_sev
+
+       movl    %ebx, %eax
+       andl    $0x3f, %eax             /* Return the encryption bit location */
+       movl    %eax, enc_bit(%edi)
+       jmp     .Lsev_exit
+
+.Lno_sev:
+       xor     %eax, %eax
+       movl    %eax, enc_bit(%edi)
+
+.Lsev_exit:
+       pop     %edi
+       pop     %edx
+       pop     %ecx
+       pop     %ebx
+
+#endif /* CONFIG_AMD_MEM_ENCRYPT */
+
+       ret
+ENDPROC(get_sev_encryption_bit)
+
+       .code64
+ENTRY(get_sev_encryption_mask)
+       xor     %rax, %rax
+
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+       push    %rbp
+       push    %rdx
+
+       movq    %rsp, %rbp              /* Save current stack pointer */
+
+       call    get_sev_encryption_bit  /* Get the encryption bit position */
+       testl   %eax, %eax
+       jz      .Lno_sev_mask
+
+       xor     %rdx, %rdx
+       bts     %rax, %rdx              /* Create the encryption mask */
+       mov     %rdx, %rax              /* ... and return it */
+
+.Lno_sev_mask:
+       movq    %rbp, %rsp              /* Restore original stack pointer */
+
+       pop     %rdx
+       pop     %rbp
+#endif
+
+       ret
+ENDPROC(get_sev_encryption_mask)
+
+       .data
+enc_bit:
+       .int    0xffffffff
index 32d4ec2e0243c30cc60e0d837e995eab550a4b52..9d323dc6b1594eac5d6215de29d9f46b312deece 100644 (file)
@@ -109,4 +109,6 @@ static inline void console_init(void)
 { }
 #endif
 
+unsigned long get_sev_encryption_mask(void);
+
 #endif
index 972319ff5b0193b9692ae69370426e3240ecbc5c..d5364ca2e3f9290d0ba36606b7e25369f872c144 100644 (file)
@@ -77,16 +77,18 @@ static unsigned long top_level_pgt;
  * Mapping information structure passed to kernel_ident_mapping_init().
  * Due to relocation, pointers must be assigned at run time not build time.
  */
-static struct x86_mapping_info mapping_info = {
-       .page_flag       = __PAGE_KERNEL_LARGE_EXEC,
-};
+static struct x86_mapping_info mapping_info;
 
 /* Locates and clears a region for a new top level page table. */
 void initialize_identity_maps(void)
 {
+       unsigned long sev_me_mask = get_sev_encryption_mask();
+
        /* Init mapping_info with run-time function/buffer pointers. */
        mapping_info.alloc_pgt_page = alloc_pgt_page;
        mapping_info.context = &pgt_data;
+       mapping_info.page_flag = __PAGE_KERNEL_LARGE_EXEC | sev_me_mask;
+       mapping_info.kernpg_flag = _KERNPG_TABLE | sev_me_mask;
 
        /*
         * It should be impossible for this not to already be true,
diff --git a/arch/x86/boot/genimage.sh b/arch/x86/boot/genimage.sh
new file mode 100644 (file)
index 0000000..49f4970
--- /dev/null
@@ -0,0 +1,124 @@
+#!/bin/sh
+#
+# 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) 2017 by Changbin Du <changbin.du@intel.com>
+#
+# Adapted from code in arch/x86/boot/Makefile by H. Peter Anvin and others
+#
+# "make fdimage/fdimage144/fdimage288/isoimage" script for x86 architecture
+#
+# Arguments:
+#   $1 - fdimage format
+#   $2 - target image file
+#   $3 - kernel bzImage file
+#   $4 - mtool configuration file
+#   $5 - kernel cmdline
+#   $6 - inird image file
+#
+
+# Use "make V=1" to debug this script
+case "${KBUILD_VERBOSE}" in
+*1*)
+        set -x
+        ;;
+esac
+
+verify () {
+       if [ ! -f "$1" ]; then
+               echo ""                                                   1>&2
+               echo " *** Missing file: $1"                              1>&2
+               echo ""                                                   1>&2
+               exit 1
+       fi
+}
+
+
+export MTOOLSRC=$4
+FIMAGE=$2
+FBZIMAGE=$3
+KCMDLINE=$5
+FDINITRD=$6
+
+# Make sure the files actually exist
+verify "$FBZIMAGE"
+verify "$MTOOLSRC"
+
+genbzdisk() {
+       mformat a:
+       syslinux $FIMAGE
+       echo "$KCMDLINE" | mcopy - a:syslinux.cfg
+       if [ -f "$FDINITRD" ] ; then
+               mcopy "$FDINITRD" a:initrd.img
+       fi
+       mcopy $FBZIMAGE a:linux
+}
+
+genfdimage144() {
+       dd if=/dev/zero of=$FIMAGE bs=1024 count=1440 2> /dev/null
+       mformat v:
+       syslinux $FIMAGE
+       echo "$KCMDLINE" | mcopy - v:syslinux.cfg
+       if [ -f "$FDINITRD" ] ; then
+               mcopy "$FDINITRD" v:initrd.img
+       fi
+       mcopy $FBZIMAGE v:linux
+}
+
+genfdimage288() {
+       dd if=/dev/zero of=$FIMAGE bs=1024 count=2880 2> /dev/null
+       mformat w:
+       syslinux $FIMAGE
+       echo "$KCMDLINE" | mcopy - W:syslinux.cfg
+       if [ -f "$FDINITRD" ] ; then
+               mcopy "$FDINITRD" w:initrd.img
+       fi
+       mcopy $FBZIMAGE w:linux
+}
+
+genisoimage() {
+       tmp_dir=`dirname $FIMAGE`/isoimage
+       rm -rf $tmp_dir
+       mkdir $tmp_dir
+       for i in lib lib64 share end ; do
+               for j in syslinux ISOLINUX ; do
+                       if [ -f /usr/$i/$j/isolinux.bin ] ; then
+                               isolinux=/usr/$i/$j/isolinux.bin
+                               cp $isolinux $tmp_dir
+                       fi
+               done
+               for j in syslinux syslinux/modules/bios ; do
+                       if [ -f /usr/$i/$j/ldlinux.c32 ]; then
+                               ldlinux=/usr/$i/$j/ldlinux.c32
+                               cp $ldlinux $tmp_dir
+                       fi
+               done
+               if [ -n "$isolinux" -a -n "$ldlinux" ] ; then
+                       break
+               fi
+               if [ $i = end -a -z "$isolinux" ] ; then
+                       echo 'Need an isolinux.bin file, please install syslinux/isolinux.'
+                       exit 1
+               fi
+       done
+       cp $FBZIMAGE $tmp_dir/linux
+       echo "$KCMDLINE" > $tmp_dir/isolinux.cfg
+       if [ -f "$FDINITRD" ] ; then
+               cp "$FDINITRD" $tmp_dir/initrd.img
+       fi
+       mkisofs -J -r -input-charset=utf-8 -quiet -o $FIMAGE -b isolinux.bin \
+               -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table \
+               $tmp_dir
+       isohybrid $FIMAGE 2>/dev/null || true
+       rm -rf $tmp_dir
+}
+
+case $1 in
+       bzdisk)     genbzdisk;;
+       fdimage144) genfdimage144;;
+       fdimage288) genfdimage288;;
+       isoimage)   genisoimage;;
+       *)          echo 'Unknown image format'; exit 1;
+esac
index 9c7ea597eee682115481b2ceaaf55da1261ce1fc..850b8762e889656c43da518520c5bae60e945e3d 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <asm/segment.h>
-#include <generated/utsrelease.h>
 #include <asm/boot.h>
 #include <asm/page_types.h>
 #include <asm/setup.h>
index 45bc9402aa497f7c7151a7ce3e0b419ab9454301..a14c5178d4ba9f9d13d0d06a1163885a08871f3a 100644 (file)
@@ -241,9 +241,9 @@ static int vga_probe(void)
                vga_modes,
        };
        static int mode_count[] = {
-               sizeof(cga_modes)/sizeof(struct mode_info),
-               sizeof(ega_modes)/sizeof(struct mode_info),
-               sizeof(vga_modes)/sizeof(struct mode_info),
+               ARRAY_SIZE(cga_modes),
+               ARRAY_SIZE(ega_modes),
+               ARRAY_SIZE(vga_modes),
        };
 
        struct biosregs ireg, oreg;
index 550cd5012b7354efd1d1eb3eaeebffd8cd7e30eb..66c9e2aab16cc31932c68ba08d484876ccf53ddc 100644 (file)
@@ -1,5 +1,5 @@
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
 # CONFIG_HIGHMEM64G is not set
-CONFIG_GUESS_UNWINDER=y
-# CONFIG_FRAME_POINTER_UNWINDER is not set
+CONFIG_UNWINDER_GUESS=y
+# CONFIG_UNWINDER_FRAME_POINTER is not set
index 4a4b16e56d354f3d48bcf8ba8a6ac21127f4cf13..e32fc1f274d854d48e1175a27210b87ccfaf509c 100644 (file)
@@ -299,6 +299,7 @@ CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_RODATA_TEST is not set
 CONFIG_DEBUG_BOOT_PARAMS=y
 CONFIG_OPTIMIZE_INLINING=y
+CONFIG_UNWINDER_ORC=y
 CONFIG_SECURITY=y
 CONFIG_SECURITY_NETWORK=y
 CONFIG_SECURITY_SELINUX=y
index 93b945597ecfb70b4f54758517d83530a3f042b6..7cfba738f104f52d27aa4f94a867f3e99e6c5f3f 100644 (file)
@@ -157,8 +157,8 @@ LABEL skip_ %I
 .endr
 
        # Find min length
-       vmovdqa _lens+0*16(state), %xmm0
-       vmovdqa _lens+1*16(state), %xmm1
+       vmovdqu _lens+0*16(state), %xmm0
+       vmovdqu _lens+1*16(state), %xmm1
 
        vpminud %xmm1, %xmm0, %xmm2     # xmm2 has {D,C,B,A}
        vpalignr $8, %xmm2, %xmm3, %xmm3   # xmm3 has {x,x,D,C}
@@ -178,8 +178,8 @@ LABEL skip_ %I
        vpsubd  %xmm2, %xmm0, %xmm0
        vpsubd  %xmm2, %xmm1, %xmm1
 
-       vmovdqa %xmm0, _lens+0*16(state)
-       vmovdqa %xmm1, _lens+1*16(state)
+       vmovdqu %xmm0, _lens+0*16(state)
+       vmovdqu %xmm1, _lens+1*16(state)
 
        # "state" and "args" are the same address, arg1
        # len is arg2
@@ -235,8 +235,8 @@ ENTRY(sha1_mb_mgr_get_comp_job_avx2)
        jc      .return_null
 
        # Find min length
-       vmovdqa _lens(state), %xmm0
-       vmovdqa _lens+1*16(state), %xmm1
+       vmovdqu _lens(state), %xmm0
+       vmovdqu _lens+1*16(state), %xmm1
 
        vpminud %xmm1, %xmm0, %xmm2        # xmm2 has {D,C,B,A}
        vpalignr $8, %xmm2, %xmm3, %xmm3   # xmm3 has {x,x,D,C}
index 8fe6338bcc845713338531694e3ed54fdf483662..16c4ccb1f154883017062c90d7ca0fc22dc67e29 100644 (file)
@@ -155,8 +155,8 @@ LABEL skip_ %I
 .endr
 
        # Find min length
-       vmovdqa _lens+0*16(state), %xmm0
-       vmovdqa _lens+1*16(state), %xmm1
+       vmovdqu _lens+0*16(state), %xmm0
+       vmovdqu _lens+1*16(state), %xmm1
 
        vpminud %xmm1, %xmm0, %xmm2             # xmm2 has {D,C,B,A}
        vpalignr $8, %xmm2, %xmm3, %xmm3        # xmm3 has {x,x,D,C}
@@ -176,8 +176,8 @@ LABEL skip_ %I
        vpsubd  %xmm2, %xmm0, %xmm0
        vpsubd  %xmm2, %xmm1, %xmm1
 
-       vmovdqa %xmm0, _lens+0*16(state)
-       vmovdqa %xmm1, _lens+1*16(state)
+       vmovdqu %xmm0, _lens+0*16(state)
+       vmovdqu %xmm1, _lens+1*16(state)
 
        # "state" and "args" are the same address, arg1
        # len is arg2
@@ -234,8 +234,8 @@ ENTRY(sha256_mb_mgr_get_comp_job_avx2)
        jc      .return_null
 
        # Find min length
-       vmovdqa _lens(state), %xmm0
-       vmovdqa _lens+1*16(state), %xmm1
+       vmovdqu _lens(state), %xmm0
+       vmovdqu _lens+1*16(state), %xmm1
 
        vpminud %xmm1, %xmm0, %xmm2             # xmm2 has {D,C,B,A}
        vpalignr $8, %xmm2, %xmm3, %xmm3        # xmm3 has {x,x,D,C}
index 6e160031cfea1d3afd65880f0b6477cc5ff8115e..3fd8bc560faece4cb6253e87a4c092965a73e7af 100644 (file)
@@ -142,56 +142,25 @@ For 32-bit we have the following conventions - kernel is built with
        UNWIND_HINT_REGS offset=\offset
        .endm
 
-       .macro RESTORE_EXTRA_REGS offset=0
-       movq 0*8+\offset(%rsp), %r15
-       movq 1*8+\offset(%rsp), %r14
-       movq 2*8+\offset(%rsp), %r13
-       movq 3*8+\offset(%rsp), %r12
-       movq 4*8+\offset(%rsp), %rbp
-       movq 5*8+\offset(%rsp), %rbx
-       UNWIND_HINT_REGS offset=\offset extra=0
-       .endm
-
-       .macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1
-       .if \rstor_r11
-       movq 6*8(%rsp), %r11
-       .endif
-       .if \rstor_r8910
-       movq 7*8(%rsp), %r10
-       movq 8*8(%rsp), %r9
-       movq 9*8(%rsp), %r8
-       .endif
-       .if \rstor_rax
-       movq 10*8(%rsp), %rax
-       .endif
-       .if \rstor_rcx
-       movq 11*8(%rsp), %rcx
-       .endif
-       .if \rstor_rdx
-       movq 12*8(%rsp), %rdx
-       .endif
-       movq 13*8(%rsp), %rsi
-       movq 14*8(%rsp), %rdi
-       UNWIND_HINT_IRET_REGS offset=16*8
-       .endm
-       .macro RESTORE_C_REGS
-       RESTORE_C_REGS_HELPER 1,1,1,1,1
-       .endm
-       .macro RESTORE_C_REGS_EXCEPT_RAX
-       RESTORE_C_REGS_HELPER 0,1,1,1,1
-       .endm
-       .macro RESTORE_C_REGS_EXCEPT_RCX
-       RESTORE_C_REGS_HELPER 1,0,1,1,1
-       .endm
-       .macro RESTORE_C_REGS_EXCEPT_R11
-       RESTORE_C_REGS_HELPER 1,1,0,1,1
-       .endm
-       .macro RESTORE_C_REGS_EXCEPT_RCX_R11
-       RESTORE_C_REGS_HELPER 1,0,0,1,1
-       .endm
-
-       .macro REMOVE_PT_GPREGS_FROM_STACK addskip=0
-       subq $-(15*8+\addskip), %rsp
+       .macro POP_EXTRA_REGS
+       popq %r15
+       popq %r14
+       popq %r13
+       popq %r12
+       popq %rbp
+       popq %rbx
+       .endm
+
+       .macro POP_C_REGS
+       popq %r11
+       popq %r10
+       popq %r9
+       popq %r8
+       popq %rax
+       popq %rcx
+       popq %rdx
+       popq %rsi
+       popq %rdi
        .endm
 
        .macro icebp
index 03505ffbe1b68d49982db71dfad0c83b04e45246..d7d3cc24baf4e5bf7c8f14e92aca44820eb8c463 100644 (file)
@@ -75,7 +75,7 @@ static long syscall_trace_enter(struct pt_regs *regs)
        if (IS_ENABLED(CONFIG_DEBUG_ENTRY))
                BUG_ON(regs != task_pt_regs(current));
 
-       work = ACCESS_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY;
+       work = READ_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY;
 
        if (unlikely(work & _TIF_SYSCALL_EMU))
                emulated = true;
@@ -186,9 +186,7 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
 
        addr_limit_user_check();
 
-       if (IS_ENABLED(CONFIG_PROVE_LOCKING) && WARN_ON(!irqs_disabled()))
-               local_irq_disable();
-
+       lockdep_assert_irqs_disabled();
        lockdep_sys_exit();
 
        cached_flags = READ_ONCE(ti->flags);
index bcfc5668dcb22f303b21c7a636273c46274835c5..a2b30ec69497277f39ef56e0dfad604170f78c19 100644 (file)
@@ -221,10 +221,9 @@ entry_SYSCALL_64_fastpath:
        TRACE_IRQS_ON           /* user mode is traced as IRQs on */
        movq    RIP(%rsp), %rcx
        movq    EFLAGS(%rsp), %r11
-       RESTORE_C_REGS_EXCEPT_RCX_R11
-       movq    RSP(%rsp), %rsp
+       addq    $6*8, %rsp      /* skip extra regs -- they were preserved */
        UNWIND_HINT_EMPTY
-       USERGS_SYSRET64
+       jmp     .Lpop_c_regs_except_rcx_r11_and_sysret
 
 1:
        /*
@@ -246,17 +245,18 @@ entry_SYSCALL64_slow_path:
        call    do_syscall_64           /* returns with IRQs disabled */
 
 return_from_SYSCALL_64:
-       RESTORE_EXTRA_REGS
        TRACE_IRQS_IRETQ                /* we're about to change IF */
 
        /*
         * Try to use SYSRET instead of IRET if we're returning to
-        * a completely clean 64-bit userspace context.
+        * a completely clean 64-bit userspace context.  If we're not,
+        * go to the slow exit path.
         */
        movq    RCX(%rsp), %rcx
        movq    RIP(%rsp), %r11
-       cmpq    %rcx, %r11                      /* RCX == RIP */
-       jne     opportunistic_sysret_failed
+
+       cmpq    %rcx, %r11      /* SYSRET requires RCX == RIP */
+       jne     swapgs_restore_regs_and_return_to_usermode
 
        /*
         * On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
@@ -274,14 +274,14 @@ return_from_SYSCALL_64:
 
        /* If this changed %rcx, it was not canonical */
        cmpq    %rcx, %r11
-       jne     opportunistic_sysret_failed
+       jne     swapgs_restore_regs_and_return_to_usermode
 
        cmpq    $__USER_CS, CS(%rsp)            /* CS must match SYSRET */
-       jne     opportunistic_sysret_failed
+       jne     swapgs_restore_regs_and_return_to_usermode
 
        movq    R11(%rsp), %r11
        cmpq    %r11, EFLAGS(%rsp)              /* R11 == RFLAGS */
-       jne     opportunistic_sysret_failed
+       jne     swapgs_restore_regs_and_return_to_usermode
 
        /*
         * SYSCALL clears RF when it saves RFLAGS in R11 and SYSRET cannot
@@ -302,12 +302,12 @@ return_from_SYSCALL_64:
         * would never get past 'stuck_here'.
         */
        testq   $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
-       jnz     opportunistic_sysret_failed
+       jnz     swapgs_restore_regs_and_return_to_usermode
 
        /* nothing to check for RSP */
 
        cmpq    $__USER_DS, SS(%rsp)            /* SS must match SYSRET */
-       jne     opportunistic_sysret_failed
+       jne     swapgs_restore_regs_and_return_to_usermode
 
        /*
         * We win! This label is here just for ease of understanding
@@ -315,14 +315,20 @@ return_from_SYSCALL_64:
         */
 syscall_return_via_sysret:
        /* rcx and r11 are already restored (see code above) */
-       RESTORE_C_REGS_EXCEPT_RCX_R11
-       movq    RSP(%rsp), %rsp
        UNWIND_HINT_EMPTY
+       POP_EXTRA_REGS
+.Lpop_c_regs_except_rcx_r11_and_sysret:
+       popq    %rsi    /* skip r11 */
+       popq    %r10
+       popq    %r9
+       popq    %r8
+       popq    %rax
+       popq    %rsi    /* skip rcx */
+       popq    %rdx
+       popq    %rsi
+       popq    %rdi
+       movq    RSP-ORIG_RAX(%rsp), %rsp
        USERGS_SYSRET64
-
-opportunistic_sysret_failed:
-       SWAPGS
-       jmp     restore_c_regs_and_iret
 END(entry_SYSCALL_64)
 
 ENTRY(stub_ptregs_64)
@@ -423,8 +429,7 @@ ENTRY(ret_from_fork)
        movq    %rsp, %rdi
        call    syscall_return_slowpath /* returns with IRQs disabled */
        TRACE_IRQS_ON                   /* user mode is traced as IRQS on */
-       SWAPGS
-       jmp     restore_regs_and_iret
+       jmp     swapgs_restore_regs_and_return_to_usermode
 
 1:
        /* kernel thread */
@@ -612,8 +617,21 @@ GLOBAL(retint_user)
        mov     %rsp,%rdi
        call    prepare_exit_to_usermode
        TRACE_IRQS_IRETQ
+
+GLOBAL(swapgs_restore_regs_and_return_to_usermode)
+#ifdef CONFIG_DEBUG_ENTRY
+       /* Assert that pt_regs indicates user mode. */
+       testb   $3, CS(%rsp)
+       jnz     1f
+       ud2
+1:
+#endif
        SWAPGS
-       jmp     restore_regs_and_iret
+       POP_EXTRA_REGS
+       POP_C_REGS
+       addq    $8, %rsp        /* skip regs->orig_ax */
+       INTERRUPT_RETURN
+
 
 /* Returning to kernel space */
 retint_kernel:
@@ -633,15 +651,17 @@ retint_kernel:
         */
        TRACE_IRQS_IRETQ
 
-/*
- * At this label, code paths which return to kernel and to user,
- * which come from interrupts/exception and from syscalls, merge.
- */
-GLOBAL(restore_regs_and_iret)
-       RESTORE_EXTRA_REGS
-restore_c_regs_and_iret:
-       RESTORE_C_REGS
-       REMOVE_PT_GPREGS_FROM_STACK 8
+GLOBAL(restore_regs_and_return_to_kernel)
+#ifdef CONFIG_DEBUG_ENTRY
+       /* Assert that pt_regs indicates kernel mode. */
+       testb   $3, CS(%rsp)
+       jz      1f
+       ud2
+1:
+#endif
+       POP_EXTRA_REGS
+       POP_C_REGS
+       addq    $8, %rsp        /* skip regs->orig_ax */
        INTERRUPT_RETURN
 
 ENTRY(native_iret)
@@ -818,7 +838,7 @@ ENTRY(\sym)
 
        ASM_CLAC
 
-       .ifeq \has_error_code
+       .if \has_error_code == 0
        pushq   $-1                             /* ORIG_RAX: no syscall to restart */
        .endif
 
@@ -1059,6 +1079,7 @@ idtentry int3                     do_int3                 has_error_code=0        paranoid=1 shift_ist=DEBUG_STACK
 idtentry stack_segment         do_stack_segment        has_error_code=1
 
 #ifdef CONFIG_XEN
+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
@@ -1112,17 +1133,14 @@ ENTRY(paranoid_exit)
        DISABLE_INTERRUPTS(CLBR_ANY)
        TRACE_IRQS_OFF_DEBUG
        testl   %ebx, %ebx                      /* swapgs needed? */
-       jnz     paranoid_exit_no_swapgs
+       jnz     .Lparanoid_exit_no_swapgs
        TRACE_IRQS_IRETQ
        SWAPGS_UNSAFE_STACK
-       jmp     paranoid_exit_restore
-paranoid_exit_no_swapgs:
+       jmp     .Lparanoid_exit_restore
+.Lparanoid_exit_no_swapgs:
        TRACE_IRQS_IRETQ_DEBUG
-paranoid_exit_restore:
-       RESTORE_EXTRA_REGS
-       RESTORE_C_REGS
-       REMOVE_PT_GPREGS_FROM_STACK 8
-       INTERRUPT_RETURN
+.Lparanoid_exit_restore:
+       jmp restore_regs_and_return_to_kernel
 END(paranoid_exit)
 
 /*
@@ -1223,10 +1241,13 @@ ENTRY(error_exit)
        jmp     retint_user
 END(error_exit)
 
-/* Runs on exception stack */
-/* XXX: broken on Xen PV */
+/*
+ * Runs on exception stack.  Xen PV does not go through this path at all,
+ * so we can use real assembly here.
+ */
 ENTRY(nmi)
        UNWIND_HINT_IRET_REGS
+
        /*
         * We allow breakpoints in NMIs. If a breakpoint occurs, then
         * the iretq it performs will take us out of NMI context.
@@ -1284,7 +1305,7 @@ ENTRY(nmi)
         * stacks lest we corrupt the "NMI executing" variable.
         */
 
-       SWAPGS_UNSAFE_STACK
+       swapgs
        cld
        movq    %rsp, %rdx
        movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp
@@ -1328,8 +1349,7 @@ ENTRY(nmi)
         * Return back to user mode.  We must *not* do the normal exit
         * work, because we don't want to enable interrupts.
         */
-       SWAPGS
-       jmp     restore_regs_and_iret
+       jmp     swapgs_restore_regs_and_return_to_usermode
 
 .Lnmi_from_kernel:
        /*
@@ -1450,7 +1470,7 @@ nested_nmi_out:
        popq    %rdx
 
        /* We are returning to kernel mode, so this cannot result in a fault. */
-       INTERRUPT_RETURN
+       iretq
 
 first_nmi:
        /* Restore rdx. */
@@ -1481,7 +1501,7 @@ first_nmi:
        pushfq                  /* RFLAGS */
        pushq   $__KERNEL_CS    /* CS */
        pushq   $1f             /* RIP */
-       INTERRUPT_RETURN        /* continues at repeat_nmi below */
+       iretq                   /* continues at repeat_nmi below */
        UNWIND_HINT_IRET_REGS
 1:
 #endif
@@ -1544,29 +1564,34 @@ end_repeat_nmi:
 nmi_swapgs:
        SWAPGS_UNSAFE_STACK
 nmi_restore:
-       RESTORE_EXTRA_REGS
-       RESTORE_C_REGS
+       POP_EXTRA_REGS
+       POP_C_REGS
 
-       /* Point RSP at the "iret" frame. */
-       REMOVE_PT_GPREGS_FROM_STACK 6*8
+       /*
+        * Skip orig_ax and the "outermost" frame to point RSP at the "iret"
+        * at the "iret" frame.
+        */
+       addq    $6*8, %rsp
 
        /*
         * Clear "NMI executing".  Set DF first so that we can easily
         * distinguish the remaining code between here and IRET from
-        * the SYSCALL entry and exit paths.  On a native kernel, we
-        * could just inspect RIP, but, on paravirt kernels,
-        * INTERRUPT_RETURN can translate into a jump into a
-        * hypercall page.
+        * the SYSCALL entry and exit paths.
+        *
+        * We arguably should just inspect RIP instead, but I (Andy) wrote
+        * this code when I had the misapprehension that Xen PV supported
+        * NMIs, and Xen PV would break that approach.
         */
        std
        movq    $0, 5*8(%rsp)           /* clear "NMI executing" */
 
        /*
-        * INTERRUPT_RETURN reads the "iret" frame and exits the NMI
-        * stack in a single instruction.  We are returning to kernel
-        * mode, so this cannot result in a fault.
+        * iretq reads the "iret" frame and exits the NMI stack in a
+        * single instruction.  We are returning to kernel mode, so this
+        * cannot result in a fault.  Similarly, we don't need to worry
+        * about espfix64 on the way back to kernel mode.
         */
-       INTERRUPT_RETURN
+       iretq
 END(nmi)
 
 ENTRY(ignore_sysret)
index b5c7a56ed256d4cb12d55a18bdaa045229b8093d..568e130d932cd2a7d44393e5fc52408cffe64f34 100644 (file)
@@ -337,8 +337,7 @@ ENTRY(entry_INT80_compat)
 
        /* Go back to user mode. */
        TRACE_IRQS_ON
-       SWAPGS
-       jmp     restore_regs_and_iret
+       jmp     swapgs_restore_regs_and_return_to_usermode
 END(entry_INT80_compat)
 
 ENTRY(stub32_clone)
index 331f1dca5085443987254d96fda3ec5477f5ecc7..6fb9b57ed5ba05dcc5247b26ee8b7b0575cf38e9 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
-out := $(obj)/../../include/generated/asm
-uapi := $(obj)/../../include/generated/uapi/asm
+out := arch/$(SRCARCH)/include/generated/asm
+uapi := arch/$(SRCARCH)/include/generated/uapi/asm
 
 # Create output directory if not already present
 _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') \
index fa8dbfcf7ed37f5677d9185d16e9addb114cf83f..11b13c4b43d55f8d6c8b239f478ecb302d4cfd07 100644 (file)
@@ -318,7 +318,7 @@ int gettimeofday(struct timeval *, struct timezone *)
 notrace time_t __vdso_time(time_t *t)
 {
        /* This is atomic on x86 so we don't need any locks. */
-       time_t result = ACCESS_ONCE(gtod->wall_time_sec);
+       time_t result = READ_ONCE(gtod->wall_time_sec);
 
        if (t)
                *t = result;
index 0780a443a53b5fbc8e5e202fd7eb585c445eef65..4674f58581a16cd6e1203141c590907d44cbc6a6 100644 (file)
@@ -65,6 +65,7 @@
 
 #include <linux/elf.h>
 #include <linux/types.h>
+#include <linux/kernel.h>
 
 const char *outfilename;
 
@@ -151,7 +152,7 @@ extern void bad_put_le(void);
        PLE(x, val, 64, PLE(x, val, 32, PLE(x, val, 16, LAST_PLE(x, val))))
 
 
-#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))
+#define NSYMS ARRAY_SIZE(required_syms)
 
 #define BITSFUNC3(name, bits, suffix) name##bits##suffix
 #define BITSFUNC2(name, bits, suffix) BITSFUNC3(name, bits, suffix)
index 1911310959f8b475cf42ef51a7c8d31780f7bc4b..d63053142b1685c9c150843cf9b2860617d1cfd8 100644 (file)
@@ -114,10 +114,11 @@ static int vvar_fault(const struct vm_special_mapping *sm,
                struct pvclock_vsyscall_time_info *pvti =
                        pvclock_pvti_cpu0_va();
                if (pvti && vclock_was_used(VCLOCK_PVCLOCK)) {
-                       ret = vm_insert_pfn(
+                       ret = vm_insert_pfn_prot(
                                vma,
                                vmf->address,
-                               __pa(pvti) >> PAGE_SHIFT);
+                               __pa(pvti) >> PAGE_SHIFT,
+                               pgprot_decrypted(vma->vm_page_prot));
                }
        } else if (sym_offset == image->sym_hvclock_page) {
                struct ms_hyperv_tsc_page *tsc_pg = hv_get_tsc_page();
index 3641e24fdac5801a32b2d23b89c1ce7775807e2f..38b5d41b0c37d6d4b76237060bee30b7de2ff049 100644 (file)
@@ -405,7 +405,7 @@ const struct attribute_group *amd_iommu_attr_groups[] = {
        NULL,
 };
 
-static struct pmu iommu_pmu = {
+static const struct pmu iommu_pmu __initconst = {
        .event_init     = perf_iommu_event_init,
        .add            = perf_iommu_add,
        .del            = perf_iommu_del,
index 80534d3c2480013caa8b170c09c0803b7fef55b9..140d33288e78e8ef72138a3ec247520f66b158a2 100644 (file)
@@ -2118,7 +2118,7 @@ static int x86_pmu_event_init(struct perf_event *event)
                        event->destroy(event);
        }
 
-       if (ACCESS_ONCE(x86_pmu.attr_rdpmc))
+       if (READ_ONCE(x86_pmu.attr_rdpmc))
                event->hw.flags |= PERF_X86_EVENT_RDPMC_ALLOWED;
 
        return err;
@@ -2371,7 +2371,7 @@ static unsigned long get_segment_base(unsigned int segment)
                struct ldt_struct *ldt;
 
                /* IRQs are off, so this synchronizes with smp_store_release */
-               ldt = lockless_dereference(current->active_mm->context.ldt);
+               ldt = READ_ONCE(current->active_mm->context.ldt);
                if (!ldt || idx >= ldt->nr_entries)
                        return 0;
 
index 9fb9a1f1e47bd0d0db3f9be9d4722f956d48dcfe..43445da30ceab12323772e81c95f0dfb3ba8cfa3 100644 (file)
@@ -2958,6 +2958,10 @@ static unsigned long intel_pmu_free_running_flags(struct perf_event *event)
 
        if (event->attr.use_clockid)
                flags &= ~PERF_SAMPLE_TIME;
+       if (!event->attr.exclude_kernel)
+               flags &= ~PERF_SAMPLE_REGS_USER;
+       if (event->attr.sample_regs_user & ~PEBS_REGS)
+               flags &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_REGS_INTR);
        return flags;
 }
 
index 4196f81ec0e1b0de71483cbc999837ec48b51f33..f7aaadf9331fb75587e74a42b041d78b2a014fc0 100644 (file)
@@ -85,13 +85,15 @@ struct amd_nb {
  * Flags PEBS can handle without an PMI.
  *
  * TID can only be handled by flushing at context switch.
+ * REGS_USER can be handled for events limited to ring 3.
  *
  */
 #define PEBS_FREERUNNING_FLAGS \
        (PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR | \
        PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID | \
        PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | \
-       PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR)
+       PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR | \
+       PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER)
 
 /*
  * A debug store configuration.
@@ -110,6 +112,26 @@ struct debug_store {
        u64     pebs_event_reset[MAX_PEBS_EVENTS];
 };
 
+#define PEBS_REGS \
+       (PERF_REG_X86_AX | \
+        PERF_REG_X86_BX | \
+        PERF_REG_X86_CX | \
+        PERF_REG_X86_DX | \
+        PERF_REG_X86_DI | \
+        PERF_REG_X86_SI | \
+        PERF_REG_X86_SP | \
+        PERF_REG_X86_BP | \
+        PERF_REG_X86_IP | \
+        PERF_REG_X86_FLAGS | \
+        PERF_REG_X86_R8 | \
+        PERF_REG_X86_R9 | \
+        PERF_REG_X86_R10 | \
+        PERF_REG_X86_R11 | \
+        PERF_REG_X86_R12 | \
+        PERF_REG_X86_R13 | \
+        PERF_REG_X86_R14 | \
+        PERF_REG_X86_R15)
+
 /*
  * Per register state.
  */
index a5db63f728a2f985bde0f1b98f87be4537913cdc..a0b86cf486e0adcf1e7d505bd003056a3e2a1b87 100644 (file)
@@ -113,7 +113,7 @@ void hyperv_init(void)
        u64 guest_id;
        union hv_x64_msr_hypercall_contents hypercall_msr;
 
-       if (x86_hyper != &x86_hyper_ms_hyperv)
+       if (x86_hyper_type != X86_HYPER_MS_HYPERV)
                return;
 
        /* Allocate percpu VP index */
index 5f01671c68f267ccc3b3aedd518134453162733a..a9e57f08bfa641d4cc9fb736bf2d1d4d22a6640c 100644 (file)
@@ -53,6 +53,15 @@ extern int local_apic_timer_c2_ok;
 extern int disable_apic;
 extern unsigned int lapic_timer_frequency;
 
+extern enum apic_intr_mode_id apic_intr_mode;
+enum apic_intr_mode_id {
+       APIC_PIC,
+       APIC_VIRTUAL_WIRE,
+       APIC_VIRTUAL_WIRE_NO_CONFIG,
+       APIC_SYMMETRIC_IO,
+       APIC_SYMMETRIC_IO_NO_ROUTING
+};
+
 #ifdef CONFIG_SMP
 extern void __inquire_remote_apic(int apicid);
 #else /* CONFIG_SMP */
@@ -127,14 +136,13 @@ extern void disconnect_bsp_APIC(int virt_wire_setup);
 extern void disable_local_APIC(void);
 extern void lapic_shutdown(void);
 extern void sync_Arb_IDs(void);
-extern void init_bsp_APIC(void);
+extern void apic_intr_mode_init(void);
 extern void setup_local_APIC(void);
 extern void init_apic_mappings(void);
 void register_lapic_address(unsigned long address);
 extern void setup_boot_APIC_clock(void);
 extern void setup_secondary_APIC_clock(void);
 extern void lapic_update_tsc_freq(void);
-extern int APIC_init_uniprocessor(void);
 
 #ifdef CONFIG_X86_64
 static inline int apic_force_enable(unsigned long addr)
@@ -145,7 +153,7 @@ static inline int apic_force_enable(unsigned long addr)
 extern int apic_force_enable(unsigned long addr);
 #endif
 
-extern int apic_bsp_setup(bool upmode);
+extern void apic_bsp_setup(bool upmode);
 extern void apic_ap_setup(void);
 
 /*
@@ -161,6 +169,10 @@ static inline int apic_is_clustered_box(void)
 #endif
 
 extern int setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask);
+extern void lapic_assign_system_vectors(void);
+extern void lapic_assign_legacy_vector(unsigned int isairq, bool replace);
+extern void lapic_online(void);
+extern void lapic_offline(void);
 
 #else /* !CONFIG_X86_LOCAL_APIC */
 static inline void lapic_shutdown(void) { }
@@ -170,6 +182,9 @@ static inline void disable_local_APIC(void) { }
 # define setup_boot_APIC_clock x86_init_noop
 # define setup_secondary_APIC_clock x86_init_noop
 static inline void lapic_update_tsc_freq(void) { }
+static inline void apic_intr_mode_init(void) { }
+static inline void lapic_assign_system_vectors(void) { }
+static inline void lapic_assign_legacy_vector(unsigned int i, bool r) { }
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_X2APIC
@@ -265,73 +280,63 @@ struct irq_data;
  * James Cleverdon.
  */
 struct apic {
-       char *name;
-
-       int (*probe)(void);
-       int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
-       int (*apic_id_valid)(int apicid);
-       int (*apic_id_registered)(void);
-
-       u32 irq_delivery_mode;
-       u32 irq_dest_mode;
-
-       const struct cpumask *(*target_cpus)(void);
-
-       int disable_esr;
-
-       int dest_logical;
-       unsigned long (*check_apicid_used)(physid_mask_t *map, int apicid);
-
-       void (*vector_allocation_domain)(int cpu, struct cpumask *retmask,
-                                        const struct cpumask *mask);
-       void (*init_apic_ldr)(void);
-
-       void (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
-
-       void (*setup_apic_routing)(void);
-       int (*cpu_present_to_apicid)(int mps_cpu);
-       void (*apicid_to_cpu_present)(int phys_apicid, physid_mask_t *retmap);
-       int (*check_phys_apicid_present)(int phys_apicid);
-       int (*phys_pkg_id)(int cpuid_apic, int index_msb);
-
-       unsigned int (*get_apic_id)(unsigned long x);
-       /* Can't be NULL on 64-bit */
-       unsigned long (*set_apic_id)(unsigned int id);
-
-       int (*cpu_mask_to_apicid)(const struct cpumask *cpumask,
-                                 struct irq_data *irqdata,
-                                 unsigned int *apicid);
-
-       /* ipi */
-       void (*send_IPI)(int cpu, int vector);
-       void (*send_IPI_mask)(const struct cpumask *mask, int vector);
-       void (*send_IPI_mask_allbutself)(const struct cpumask *mask,
-                                        int vector);
-       void (*send_IPI_allbutself)(int vector);
-       void (*send_IPI_all)(int vector);
-       void (*send_IPI_self)(int vector);
+       /* Hotpath functions first */
+       void    (*eoi_write)(u32 reg, u32 v);
+       void    (*native_eoi_write)(u32 reg, u32 v);
+       void    (*write)(u32 reg, u32 v);
+       u32     (*read)(u32 reg);
+
+       /* IPI related functions */
+       void    (*wait_icr_idle)(void);
+       u32     (*safe_wait_icr_idle)(void);
+
+       void    (*send_IPI)(int cpu, int vector);
+       void    (*send_IPI_mask)(const struct cpumask *mask, int vector);
+       void    (*send_IPI_mask_allbutself)(const struct cpumask *msk, int vec);
+       void    (*send_IPI_allbutself)(int vector);
+       void    (*send_IPI_all)(int vector);
+       void    (*send_IPI_self)(int vector);
+
+       /* dest_logical is used by the IPI functions */
+       u32     dest_logical;
+       u32     disable_esr;
+       u32     irq_delivery_mode;
+       u32     irq_dest_mode;
+
+       /* Functions and data related to vector allocation */
+       void    (*vector_allocation_domain)(int cpu, struct cpumask *retmask,
+                                           const struct cpumask *mask);
+       int     (*cpu_mask_to_apicid)(const struct cpumask *cpumask,
+                                     struct irq_data *irqdata,
+                                     unsigned int *apicid);
+       u32     (*calc_dest_apicid)(unsigned int cpu);
+
+       /* ICR related functions */
+       u64     (*icr_read)(void);
+       void    (*icr_write)(u32 low, u32 high);
+
+       /* Probe, setup and smpboot functions */
+       int     (*probe)(void);
+       int     (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
+       int     (*apic_id_valid)(int apicid);
+       int     (*apic_id_registered)(void);
+
+       bool    (*check_apicid_used)(physid_mask_t *map, int apicid);
+       void    (*init_apic_ldr)(void);
+       void    (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
+       void    (*setup_apic_routing)(void);
+       int     (*cpu_present_to_apicid)(int mps_cpu);
+       void    (*apicid_to_cpu_present)(int phys_apicid, physid_mask_t *retmap);
+       int     (*check_phys_apicid_present)(int phys_apicid);
+       int     (*phys_pkg_id)(int cpuid_apic, int index_msb);
+
+       u32     (*get_apic_id)(unsigned long x);
+       u32     (*set_apic_id)(unsigned int id);
 
        /* wakeup_secondary_cpu */
-       int (*wakeup_secondary_cpu)(int apicid, unsigned long start_eip);
+       int     (*wakeup_secondary_cpu)(int apicid, unsigned long start_eip);
 
-       void (*inquire_remote_apic)(int apicid);
-
-       /* apic ops */
-       u32 (*read)(u32 reg);
-       void (*write)(u32 reg, u32 v);
-       /*
-        * ->eoi_write() has the same signature as ->write().
-        *
-        * Drivers can support both ->eoi_write() and ->write() by passing the same
-        * callback value. Kernel can override ->eoi_write() and fall back
-        * on write for EOI.
-        */
-       void (*eoi_write)(u32 reg, u32 v);
-       void (*native_eoi_write)(u32 reg, u32 v);
-       u64 (*icr_read)(void);
-       void (*icr_write)(u32 low, u32 high);
-       void (*wait_icr_idle)(void);
-       u32 (*safe_wait_icr_idle)(void);
+       void    (*inquire_remote_apic)(int apicid);
 
 #ifdef CONFIG_X86_32
        /*
@@ -346,6 +351,7 @@ struct apic {
         */
        int (*x86_32_early_logical_apicid)(int cpu);
 #endif
+       char    *name;
 };
 
 /*
@@ -380,6 +386,7 @@ extern struct apic *__apicdrivers[], *__apicdrivers_end[];
  */
 #ifdef CONFIG_SMP
 extern int wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip);
+extern int lapic_can_unplug_cpu(void);
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -463,84 +470,33 @@ static inline unsigned default_get_apic_id(unsigned long x)
 extern void apic_send_IPI_self(int vector);
 
 DECLARE_PER_CPU(int, x2apic_extra_bits);
-
-extern int default_cpu_present_to_apicid(int mps_cpu);
-extern int default_check_phys_apicid_present(int phys_apicid);
 #endif
 
 extern void generic_bigsmp_probe(void);
 
-
 #ifdef CONFIG_X86_LOCAL_APIC
 
 #include <asm/smp.h>
 
 #define APIC_DFR_VALUE (APIC_DFR_FLAT)
 
-static inline const struct cpumask *default_target_cpus(void)
-{
-#ifdef CONFIG_SMP
-       return cpu_online_mask;
-#else
-       return cpumask_of(0);
-#endif
-}
-
-static inline const struct cpumask *online_target_cpus(void)
-{
-       return cpu_online_mask;
-}
-
 DECLARE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_bios_cpu_apicid);
 
+extern struct apic apic_noop;
 
 static inline unsigned int read_apic_id(void)
 {
-       unsigned int reg;
-
-       reg = apic_read(APIC_ID);
+       unsigned int reg = apic_read(APIC_ID);
 
        return apic->get_apic_id(reg);
 }
 
-static inline int default_apic_id_valid(int apicid)
-{
-       return (apicid < 255);
-}
-
+extern int default_apic_id_valid(int apicid);
 extern int default_acpi_madt_oem_check(char *, char *);
-
 extern void default_setup_apic_routing(void);
 
-extern struct apic apic_noop;
-
-#ifdef CONFIG_X86_32
-
-static inline int noop_x86_32_early_logical_apicid(int cpu)
-{
-       return BAD_APICID;
-}
-
-/*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LDR and TPR before enabling
- * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116).  So here it goes...
- */
-extern void default_init_apic_ldr(void);
-
-static inline int default_apic_id_registered(void)
-{
-       return physid_isset(read_apic_id(), phys_cpu_present_map);
-}
-
-static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
-{
-       return cpuid_apic >> index_msb;
-}
-
-#endif
+extern u32 apic_default_calc_apicid(unsigned int cpu);
+extern u32 apic_flat_calc_apicid(unsigned int cpu);
 
 extern int flat_cpu_mask_to_apicid(const struct cpumask *cpumask,
                                   struct irq_data *irqdata,
@@ -548,71 +504,17 @@ extern int flat_cpu_mask_to_apicid(const struct cpumask *cpumask,
 extern int default_cpu_mask_to_apicid(const struct cpumask *cpumask,
                                      struct irq_data *irqdata,
                                      unsigned int *apicid);
-
-static inline void
-flat_vector_allocation_domain(int cpu, struct cpumask *retmask,
-                             const struct cpumask *mask)
-{
-       /* Careful. Some cpus do not strictly honor the set of cpus
-        * specified in the interrupt destination when using lowest
-        * priority interrupt delivery mode.
-        *
-        * In particular there was a hyperthreading cpu observed to
-        * deliver interrupts to the wrong hyperthread when only one
-        * hyperthread was specified in the interrupt desitination.
-        */
-       cpumask_clear(retmask);
-       cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
-static inline void
-default_vector_allocation_domain(int cpu, struct cpumask *retmask,
-                                const struct cpumask *mask)
-{
-       cpumask_copy(retmask, cpumask_of(cpu));
-}
-
-static inline unsigned long default_check_apicid_used(physid_mask_t *map, int apicid)
-{
-       return physid_isset(apicid, *map);
-}
-
-static inline void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
-{
-       *retmap = *phys_map;
-}
-
-static inline int __default_cpu_present_to_apicid(int mps_cpu)
-{
-       if (mps_cpu < nr_cpu_ids && cpu_present(mps_cpu))
-               return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
-       else
-               return BAD_APICID;
-}
-
-static inline int
-__default_check_phys_apicid_present(int phys_apicid)
-{
-       return physid_isset(phys_apicid, phys_cpu_present_map);
-}
-
-#ifdef CONFIG_X86_32
-static inline int default_cpu_present_to_apicid(int mps_cpu)
-{
-       return __default_cpu_present_to_apicid(mps_cpu);
-}
-
-static inline int
-default_check_phys_apicid_present(int phys_apicid)
-{
-       return __default_check_phys_apicid_present(phys_apicid);
-}
-#else
+extern bool default_check_apicid_used(physid_mask_t *map, int apicid);
+extern void flat_vector_allocation_domain(int cpu, struct cpumask *retmask,
+                                  const struct cpumask *mask);
+extern void default_vector_allocation_domain(int cpu, struct cpumask *retmask,
+                                     const struct cpumask *mask);
+extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap);
 extern int default_cpu_present_to_apicid(int mps_cpu);
 extern int default_check_phys_apicid_present(int phys_apicid);
-#endif
 
 #endif /* CONFIG_X86_LOCAL_APIC */
+
 extern void irq_enter(void);
 extern void irq_exit(void);
 
index 5b0579abb39829ce3c6a1b4f00e73dd9295c26dc..3ac991d81e74d9c7293d66c19a0f66eb1ca7b436 100644 (file)
@@ -45,7 +45,7 @@ static inline bool rdrand_long(unsigned long *v)
        bool ok;
        unsigned int retry = RDRAND_RETRY_LOOPS;
        do {
-               asm volatile(RDRAND_LONG "\n\t"
+               asm volatile(RDRAND_LONG
                             CC_SET(c)
                             : CC_OUT(c) (ok), "=a" (*v));
                if (ok)
@@ -59,7 +59,7 @@ static inline bool rdrand_int(unsigned int *v)
        bool ok;
        unsigned int retry = RDRAND_RETRY_LOOPS;
        do {
-               asm volatile(RDRAND_INT "\n\t"
+               asm volatile(RDRAND_INT
                             CC_SET(c)
                             : CC_OUT(c) (ok), "=a" (*v));
                if (ok)
@@ -71,7 +71,7 @@ static inline bool rdrand_int(unsigned int *v)
 static inline bool rdseed_long(unsigned long *v)
 {
        bool ok;
-       asm volatile(RDSEED_LONG "\n\t"
+       asm volatile(RDSEED_LONG
                     CC_SET(c)
                     : CC_OUT(c) (ok), "=a" (*v));
        return ok;
@@ -80,7 +80,7 @@ static inline bool rdseed_long(unsigned long *v)
 static inline bool rdseed_int(unsigned int *v)
 {
        bool ok;
-       asm volatile(RDSEED_INT "\n\t"
+       asm volatile(RDSEED_INT
                     CC_SET(c)
                     : CC_OUT(c) (ok), "=a" (*v));
        return ok;
index 01727dbc294a3234c8c1be0035c01200c9504034..7fb336210e1b26b09371483bfb6a6fe0014f8f3c 100644 (file)
  */
 
 #ifdef CONFIG_X86_32
-#define mb() asm volatile(ALTERNATIVE("lock; addl $0,0(%%esp)", "mfence", \
+#define mb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "mfence", \
                                      X86_FEATURE_XMM2) ::: "memory", "cc")
-#define rmb() asm volatile(ALTERNATIVE("lock; addl $0,0(%%esp)", "lfence", \
+#define rmb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "lfence", \
                                       X86_FEATURE_XMM2) ::: "memory", "cc")
-#define wmb() asm volatile(ALTERNATIVE("lock; addl $0,0(%%esp)", "sfence", \
+#define wmb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "sfence", \
                                       X86_FEATURE_XMM2) ::: "memory", "cc")
 #else
 #define mb()   asm volatile("mfence":::"memory")
 #endif
 #define dma_wmb()      barrier()
 
-#define __smp_mb()     mb()
+#ifdef CONFIG_X86_32
+#define __smp_mb()     asm volatile("lock; addl $0,-4(%%esp)" ::: "memory", "cc")
+#else
+#define __smp_mb()     asm volatile("lock; addl $0,-4(%%rsp)" ::: "memory", "cc")
+#endif
 #define __smp_rmb()    dma_rmb()
 #define __smp_wmb()    barrier()
 #define __smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
index 2bcf4731495959e9da2db072d4397c925830483e..3fa039855b8f70aa2738468e33bef882b0a398cb 100644 (file)
@@ -143,7 +143,7 @@ static __always_inline void __clear_bit(long nr, volatile unsigned long *addr)
 static __always_inline bool clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr)
 {
        bool negative;
-       asm volatile(LOCK_PREFIX "andb %2,%1\n\t"
+       asm volatile(LOCK_PREFIX "andb %2,%1"
                CC_SET(s)
                : CC_OUT(s) (negative), ADDR
                : "ir" ((char) ~(1 << nr)) : "memory");
@@ -246,7 +246,7 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long *
 {
        bool oldbit;
 
-       asm("bts %2,%1\n\t"
+       asm("bts %2,%1"
            CC_SET(c)
            : CC_OUT(c) (oldbit), ADDR
            : "Ir" (nr));
@@ -286,7 +286,7 @@ static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long
 {
        bool oldbit;
 
-       asm volatile("btr %2,%1\n\t"
+       asm volatile("btr %2,%1"
                     CC_SET(c)
                     : CC_OUT(c) (oldbit), ADDR
                     : "Ir" (nr));
@@ -298,7 +298,7 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon
 {
        bool oldbit;
 
-       asm volatile("btc %2,%1\n\t"
+       asm volatile("btc %2,%1"
                     CC_SET(c)
                     : CC_OUT(c) (oldbit), ADDR
                     : "Ir" (nr) : "memory");
@@ -329,7 +329,7 @@ static __always_inline bool variable_test_bit(long nr, volatile const unsigned l
 {
        bool oldbit;
 
-       asm volatile("bt %2,%1\n\t"
+       asm volatile("bt %2,%1"
                     CC_SET(c)
                     : CC_OUT(c) (oldbit)
                     : "m" (*(unsigned long *)addr), "Ir" (nr));
index 9eef9cc64c6846d11dc5febae97109f2addc3648..a600a6cda9ecdf170c1a70ed151e5b0a5c01a1ba 100644 (file)
@@ -7,6 +7,7 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/sched/task_stack.h>
 #include <asm/processor.h>
 #include <asm/user32.h>
 #include <asm/unistd.h>
index 0dfa68438e80e70595deb0a20d237f8cb1b8d3f0..bf6a76202a779ee131b4df8c89449ab52abd0a79 100644 (file)
@@ -126,11 +126,10 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
 #define boot_cpu_has(bit)      cpu_has(&boot_cpu_data, bit)
 
 #define set_cpu_cap(c, bit)    set_bit(bit, (unsigned long *)((c)->x86_capability))
-#define clear_cpu_cap(c, bit)  clear_bit(bit, (unsigned long *)((c)->x86_capability))
-#define setup_clear_cpu_cap(bit) do { \
-       clear_cpu_cap(&boot_cpu_data, bit);     \
-       set_bit(bit, (unsigned long *)cpu_caps_cleared); \
-} while (0)
+
+extern void setup_clear_cpu_cap(unsigned int bit);
+extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
+
 #define setup_force_cpu_cap(bit) do { \
        set_cpu_cap(&boot_cpu_data, bit);       \
        set_bit(bit, (unsigned long *)cpu_caps_set);    \
index 793690fbda3625defd130262db1e94b57152c0bc..c0b0e9e8aa66eb645eba71784e80aa93b0f0df79 100644 (file)
 /*
  * Defines x86 CPU feature bits
  */
-#define NCAPINTS       18      /* N 32-bit words worth of info */
-#define NBUGINTS       1       /* N 32-bit bug flags */
+#define NCAPINTS                       18         /* N 32-bit words worth of info */
+#define NBUGINTS                       1          /* N 32-bit bug flags */
 
 /*
  * Note: If the comment begins with a quoted string, that string is used
  * in /proc/cpuinfo instead of the macro name.  If the string is "",
  * this feature bit is not displayed in /proc/cpuinfo at all.
+ *
+ * When adding new features here that depend on other features,
+ * please update the table in kernel/cpu/cpuid-deps.c as well.
  */
 
-/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
-#define X86_FEATURE_FPU                ( 0*32+ 0) /* Onboard FPU */
-#define X86_FEATURE_VME                ( 0*32+ 1) /* Virtual Mode Extensions */
-#define X86_FEATURE_DE         ( 0*32+ 2) /* Debugging Extensions */
-#define X86_FEATURE_PSE                ( 0*32+ 3) /* Page Size Extensions */
-#define X86_FEATURE_TSC                ( 0*32+ 4) /* Time Stamp Counter */
-#define X86_FEATURE_MSR                ( 0*32+ 5) /* Model-Specific Registers */
-#define X86_FEATURE_PAE                ( 0*32+ 6) /* Physical Address Extensions */
-#define X86_FEATURE_MCE                ( 0*32+ 7) /* Machine Check Exception */
-#define X86_FEATURE_CX8                ( 0*32+ 8) /* CMPXCHG8 instruction */
-#define X86_FEATURE_APIC       ( 0*32+ 9) /* Onboard APIC */
-#define X86_FEATURE_SEP                ( 0*32+11) /* SYSENTER/SYSEXIT */
-#define X86_FEATURE_MTRR       ( 0*32+12) /* Memory Type Range Registers */
-#define X86_FEATURE_PGE                ( 0*32+13) /* Page Global Enable */
-#define X86_FEATURE_MCA                ( 0*32+14) /* Machine Check Architecture */
-#define X86_FEATURE_CMOV       ( 0*32+15) /* CMOV instructions */
-                                         /* (plus FCMOVcc, FCOMI with FPU) */
-#define X86_FEATURE_PAT                ( 0*32+16) /* Page Attribute Table */
-#define X86_FEATURE_PSE36      ( 0*32+17) /* 36-bit PSEs */
-#define X86_FEATURE_PN         ( 0*32+18) /* Processor serial number */
-#define X86_FEATURE_CLFLUSH    ( 0*32+19) /* CLFLUSH instruction */
-#define X86_FEATURE_DS         ( 0*32+21) /* "dts" Debug Store */
-#define X86_FEATURE_ACPI       ( 0*32+22) /* ACPI via MSR */
-#define X86_FEATURE_MMX                ( 0*32+23) /* Multimedia Extensions */
-#define X86_FEATURE_FXSR       ( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */
-#define X86_FEATURE_XMM                ( 0*32+25) /* "sse" */
-#define X86_FEATURE_XMM2       ( 0*32+26) /* "sse2" */
-#define X86_FEATURE_SELFSNOOP  ( 0*32+27) /* "ss" CPU self snoop */
-#define X86_FEATURE_HT         ( 0*32+28) /* Hyper-Threading */
-#define X86_FEATURE_ACC                ( 0*32+29) /* "tm" Automatic clock control */
-#define X86_FEATURE_IA64       ( 0*32+30) /* IA-64 processor */
-#define X86_FEATURE_PBE                ( 0*32+31) /* Pending Break Enable */
+/* Intel-defined CPU features, CPUID level 0x00000001 (EDX), word 0 */
+#define X86_FEATURE_FPU                        ( 0*32+ 0) /* Onboard FPU */
+#define X86_FEATURE_VME                        ( 0*32+ 1) /* Virtual Mode Extensions */
+#define X86_FEATURE_DE                 ( 0*32+ 2) /* Debugging Extensions */
+#define X86_FEATURE_PSE                        ( 0*32+ 3) /* Page Size Extensions */
+#define X86_FEATURE_TSC                        ( 0*32+ 4) /* Time Stamp Counter */
+#define X86_FEATURE_MSR                        ( 0*32+ 5) /* Model-Specific Registers */
+#define X86_FEATURE_PAE                        ( 0*32+ 6) /* Physical Address Extensions */
+#define X86_FEATURE_MCE                        ( 0*32+ 7) /* Machine Check Exception */
+#define X86_FEATURE_CX8                        ( 0*32+ 8) /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC               ( 0*32+ 9) /* Onboard APIC */
+#define X86_FEATURE_SEP                        ( 0*32+11) /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR               ( 0*32+12) /* Memory Type Range Registers */
+#define X86_FEATURE_PGE                        ( 0*32+13) /* Page Global Enable */
+#define X86_FEATURE_MCA                        ( 0*32+14) /* Machine Check Architecture */
+#define X86_FEATURE_CMOV               ( 0*32+15) /* CMOV instructions (plus FCMOVcc, FCOMI with FPU) */
+#define X86_FEATURE_PAT                        ( 0*32+16) /* Page Attribute Table */
+#define X86_FEATURE_PSE36              ( 0*32+17) /* 36-bit PSEs */
+#define X86_FEATURE_PN                 ( 0*32+18) /* Processor serial number */
+#define X86_FEATURE_CLFLUSH            ( 0*32+19) /* CLFLUSH instruction */
+#define X86_FEATURE_DS                 ( 0*32+21) /* "dts" Debug Store */
+#define X86_FEATURE_ACPI               ( 0*32+22) /* ACPI via MSR */
+#define X86_FEATURE_MMX                        ( 0*32+23) /* Multimedia Extensions */
+#define X86_FEATURE_FXSR               ( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */
+#define X86_FEATURE_XMM                        ( 0*32+25) /* "sse" */
+#define X86_FEATURE_XMM2               ( 0*32+26) /* "sse2" */
+#define X86_FEATURE_SELFSNOOP          ( 0*32+27) /* "ss" CPU self snoop */
+#define X86_FEATURE_HT                 ( 0*32+28) /* Hyper-Threading */
+#define X86_FEATURE_ACC                        ( 0*32+29) /* "tm" Automatic clock control */
+#define X86_FEATURE_IA64               ( 0*32+30) /* IA-64 processor */
+#define X86_FEATURE_PBE                        ( 0*32+31) /* Pending Break Enable */
 
 /* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
 /* Don't duplicate feature flags which are redundant with Intel! */
-#define X86_FEATURE_SYSCALL    ( 1*32+11) /* SYSCALL/SYSRET */
-#define X86_FEATURE_MP         ( 1*32+19) /* MP Capable. */
-#define X86_FEATURE_NX         ( 1*32+20) /* Execute Disable */
-#define X86_FEATURE_MMXEXT     ( 1*32+22) /* AMD MMX extensions */
-#define X86_FEATURE_FXSR_OPT   ( 1*32+25) /* FXSAVE/FXRSTOR optimizations */
-#define X86_FEATURE_GBPAGES    ( 1*32+26) /* "pdpe1gb" GB pages */
-#define X86_FEATURE_RDTSCP     ( 1*32+27) /* RDTSCP */
-#define X86_FEATURE_LM         ( 1*32+29) /* Long Mode (x86-64) */
-#define X86_FEATURE_3DNOWEXT   ( 1*32+30) /* AMD 3DNow! extensions */
-#define X86_FEATURE_3DNOW      ( 1*32+31) /* 3DNow! */
+#define X86_FEATURE_SYSCALL            ( 1*32+11) /* SYSCALL/SYSRET */
+#define X86_FEATURE_MP                 ( 1*32+19) /* MP Capable */
+#define X86_FEATURE_NX                 ( 1*32+20) /* Execute Disable */
+#define X86_FEATURE_MMXEXT             ( 1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_FXSR_OPT           ( 1*32+25) /* FXSAVE/FXRSTOR optimizations */
+#define X86_FEATURE_GBPAGES            ( 1*32+26) /* "pdpe1gb" GB pages */
+#define X86_FEATURE_RDTSCP             ( 1*32+27) /* RDTSCP */
+#define X86_FEATURE_LM                 ( 1*32+29) /* Long Mode (x86-64, 64-bit support) */
+#define X86_FEATURE_3DNOWEXT           ( 1*32+30) /* AMD 3DNow extensions */
+#define X86_FEATURE_3DNOW              ( 1*32+31) /* 3DNow */
 
 /* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
-#define X86_FEATURE_RECOVERY   ( 2*32+ 0) /* CPU in recovery mode */
-#define X86_FEATURE_LONGRUN    ( 2*32+ 1) /* Longrun power control */
-#define X86_FEATURE_LRTI       ( 2*32+ 3) /* LongRun table interface */
+#define X86_FEATURE_RECOVERY           ( 2*32+ 0) /* CPU in recovery mode */
+#define X86_FEATURE_LONGRUN            ( 2*32+ 1) /* Longrun power control */
+#define X86_FEATURE_LRTI               ( 2*32+ 3) /* LongRun table interface */
 
 /* Other features, Linux-defined mapping, word 3 */
 /* This range is used for feature bits which conflict or are synthesized */
-#define X86_FEATURE_CXMMX      ( 3*32+ 0) /* Cyrix MMX extensions */
-#define X86_FEATURE_K6_MTRR    ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */
-#define X86_FEATURE_CYRIX_ARR  ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */
-#define X86_FEATURE_CENTAUR_MCR        ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */
-/* cpu types for specific tunings: */
-#define X86_FEATURE_K8         ( 3*32+ 4) /* "" Opteron, Athlon64 */
-#define X86_FEATURE_K7         ( 3*32+ 5) /* "" Athlon */
-#define X86_FEATURE_P3         ( 3*32+ 6) /* "" P3 */
-#define X86_FEATURE_P4         ( 3*32+ 7) /* "" P4 */
-#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */
-#define X86_FEATURE_UP         ( 3*32+ 9) /* smp kernel running on up */
-#define X86_FEATURE_ART                ( 3*32+10) /* Platform has always running timer (ART) */
-#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */
-#define X86_FEATURE_PEBS       ( 3*32+12) /* Precise-Event Based Sampling */
-#define X86_FEATURE_BTS                ( 3*32+13) /* Branch Trace Store */
-#define X86_FEATURE_SYSCALL32  ( 3*32+14) /* "" syscall in ia32 userspace */
-#define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in ia32 userspace */
-#define X86_FEATURE_REP_GOOD   ( 3*32+16) /* rep microcode works well */
-#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" Mfence synchronizes RDTSC */
-#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" Lfence synchronizes RDTSC */
-#define X86_FEATURE_ACC_POWER  ( 3*32+19) /* AMD Accumulated Power Mechanism */
-#define X86_FEATURE_NOPL       ( 3*32+20) /* The NOPL (0F 1F) instructions */
-#define X86_FEATURE_ALWAYS     ( 3*32+21) /* "" Always-present feature */
-#define X86_FEATURE_XTOPOLOGY  ( 3*32+22) /* cpu topology enum extensions */
-#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */
-#define X86_FEATURE_NONSTOP_TSC        ( 3*32+24) /* TSC does not stop in C states */
-#define X86_FEATURE_CPUID      ( 3*32+25) /* CPU has CPUID instruction itself */
-#define X86_FEATURE_EXTD_APICID        ( 3*32+26) /* has extended APICID (8 bits) */
-#define X86_FEATURE_AMD_DCM     ( 3*32+27) /* multi-node processor */
-#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
-#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
-#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* TSC has known frequency */
+#define X86_FEATURE_CXMMX              ( 3*32+ 0) /* Cyrix MMX extensions */
+#define X86_FEATURE_K6_MTRR            ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */
+#define X86_FEATURE_CYRIX_ARR          ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */
+#define X86_FEATURE_CENTAUR_MCR                ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */
+
+/* CPU types for specific tunings: */
+#define X86_FEATURE_K8                 ( 3*32+ 4) /* "" Opteron, Athlon64 */
+#define X86_FEATURE_K7                 ( 3*32+ 5) /* "" Athlon */
+#define X86_FEATURE_P3                 ( 3*32+ 6) /* "" P3 */
+#define X86_FEATURE_P4                 ( 3*32+ 7) /* "" P4 */
+#define X86_FEATURE_CONSTANT_TSC       ( 3*32+ 8) /* TSC ticks at a constant rate */
+#define X86_FEATURE_UP                 ( 3*32+ 9) /* SMP kernel running on UP */
+#define X86_FEATURE_ART                        ( 3*32+10) /* Always running timer (ART) */
+#define X86_FEATURE_ARCH_PERFMON       ( 3*32+11) /* Intel Architectural PerfMon */
+#define X86_FEATURE_PEBS               ( 3*32+12) /* Precise-Event Based Sampling */
+#define X86_FEATURE_BTS                        ( 3*32+13) /* Branch Trace Store */
+#define X86_FEATURE_SYSCALL32          ( 3*32+14) /* "" syscall in IA32 userspace */
+#define X86_FEATURE_SYSENTER32         ( 3*32+15) /* "" sysenter in IA32 userspace */
+#define X86_FEATURE_REP_GOOD           ( 3*32+16) /* REP microcode works well */
+#define X86_FEATURE_MFENCE_RDTSC       ( 3*32+17) /* "" MFENCE synchronizes RDTSC */
+#define X86_FEATURE_LFENCE_RDTSC       ( 3*32+18) /* "" LFENCE synchronizes RDTSC */
+#define X86_FEATURE_ACC_POWER          ( 3*32+19) /* AMD Accumulated Power Mechanism */
+#define X86_FEATURE_NOPL               ( 3*32+20) /* The NOPL (0F 1F) instructions */
+#define X86_FEATURE_ALWAYS             ( 3*32+21) /* "" Always-present feature */
+#define X86_FEATURE_XTOPOLOGY          ( 3*32+22) /* CPU topology enum extensions */
+#define X86_FEATURE_TSC_RELIABLE       ( 3*32+23) /* TSC is known to be reliable */
+#define X86_FEATURE_NONSTOP_TSC                ( 3*32+24) /* TSC does not stop in C states */
+#define X86_FEATURE_CPUID              ( 3*32+25) /* CPU has CPUID instruction itself */
+#define X86_FEATURE_EXTD_APICID                ( 3*32+26) /* Extended APICID (8 bits) */
+#define X86_FEATURE_AMD_DCM            ( 3*32+27) /* AMD multi-node processor */
+#define X86_FEATURE_APERFMPERF         ( 3*32+28) /* P-State hardware coordination feedback capability (APERF/MPERF MSRs) */
+#define X86_FEATURE_NONSTOP_TSC_S3     ( 3*32+30) /* TSC doesn't stop in S3 state */
+#define X86_FEATURE_TSC_KNOWN_FREQ     ( 3*32+31) /* TSC has known frequency */
 
-/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
-#define X86_FEATURE_XMM3       ( 4*32+ 0) /* "pni" SSE-3 */
-#define X86_FEATURE_PCLMULQDQ  ( 4*32+ 1) /* PCLMULQDQ instruction */
-#define X86_FEATURE_DTES64     ( 4*32+ 2) /* 64-bit Debug Store */
-#define X86_FEATURE_MWAIT      ( 4*32+ 3) /* "monitor" Monitor/Mwait support */
-#define X86_FEATURE_DSCPL      ( 4*32+ 4) /* "ds_cpl" CPL Qual. Debug Store */
-#define X86_FEATURE_VMX                ( 4*32+ 5) /* Hardware virtualization */
-#define X86_FEATURE_SMX                ( 4*32+ 6) /* Safer mode */
-#define X86_FEATURE_EST                ( 4*32+ 7) /* Enhanced SpeedStep */
-#define X86_FEATURE_TM2                ( 4*32+ 8) /* Thermal Monitor 2 */
-#define X86_FEATURE_SSSE3      ( 4*32+ 9) /* Supplemental SSE-3 */
-#define X86_FEATURE_CID                ( 4*32+10) /* Context ID */
-#define X86_FEATURE_SDBG       ( 4*32+11) /* Silicon Debug */
-#define X86_FEATURE_FMA                ( 4*32+12) /* Fused multiply-add */
-#define X86_FEATURE_CX16       ( 4*32+13) /* CMPXCHG16B */
-#define X86_FEATURE_XTPR       ( 4*32+14) /* Send Task Priority Messages */
-#define X86_FEATURE_PDCM       ( 4*32+15) /* Performance Capabilities */
-#define X86_FEATURE_PCID       ( 4*32+17) /* Process Context Identifiers */
-#define X86_FEATURE_DCA                ( 4*32+18) /* Direct Cache Access */
-#define X86_FEATURE_XMM4_1     ( 4*32+19) /* "sse4_1" SSE-4.1 */
-#define X86_FEATURE_XMM4_2     ( 4*32+20) /* "sse4_2" SSE-4.2 */
-#define X86_FEATURE_X2APIC     ( 4*32+21) /* x2APIC */
-#define X86_FEATURE_MOVBE      ( 4*32+22) /* MOVBE instruction */
-#define X86_FEATURE_POPCNT      ( 4*32+23) /* POPCNT instruction */
-#define X86_FEATURE_TSC_DEADLINE_TIMER ( 4*32+24) /* Tsc deadline timer */
-#define X86_FEATURE_AES                ( 4*32+25) /* AES instructions */
-#define X86_FEATURE_XSAVE      ( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
-#define X86_FEATURE_OSXSAVE    ( 4*32+27) /* "" XSAVE enabled in the OS */
-#define X86_FEATURE_AVX                ( 4*32+28) /* Advanced Vector Extensions */
-#define X86_FEATURE_F16C       ( 4*32+29) /* 16-bit fp conversions */
-#define X86_FEATURE_RDRAND     ( 4*32+30) /* The RDRAND instruction */
-#define X86_FEATURE_HYPERVISOR ( 4*32+31) /* Running on a hypervisor */
+/* Intel-defined CPU features, CPUID level 0x00000001 (ECX), word 4 */
+#define X86_FEATURE_XMM3               ( 4*32+ 0) /* "pni" SSE-3 */
+#define X86_FEATURE_PCLMULQDQ          ( 4*32+ 1) /* PCLMULQDQ instruction */
+#define X86_FEATURE_DTES64             ( 4*32+ 2) /* 64-bit Debug Store */
+#define X86_FEATURE_MWAIT              ( 4*32+ 3) /* "monitor" MONITOR/MWAIT support */
+#define X86_FEATURE_DSCPL              ( 4*32+ 4) /* "ds_cpl" CPL-qualified (filtered) Debug Store */
+#define X86_FEATURE_VMX                        ( 4*32+ 5) /* Hardware virtualization */
+#define X86_FEATURE_SMX                        ( 4*32+ 6) /* Safer Mode eXtensions */
+#define X86_FEATURE_EST                        ( 4*32+ 7) /* Enhanced SpeedStep */
+#define X86_FEATURE_TM2                        ( 4*32+ 8) /* Thermal Monitor 2 */
+#define X86_FEATURE_SSSE3              ( 4*32+ 9) /* Supplemental SSE-3 */
+#define X86_FEATURE_CID                        ( 4*32+10) /* Context ID */
+#define X86_FEATURE_SDBG               ( 4*32+11) /* Silicon Debug */
+#define X86_FEATURE_FMA                        ( 4*32+12) /* Fused multiply-add */
+#define X86_FEATURE_CX16               ( 4*32+13) /* CMPXCHG16B instruction */
+#define X86_FEATURE_XTPR               ( 4*32+14) /* Send Task Priority Messages */
+#define X86_FEATURE_PDCM               ( 4*32+15) /* Perf/Debug Capabilities MSR */
+#define X86_FEATURE_PCID               ( 4*32+17) /* Process Context Identifiers */
+#define X86_FEATURE_DCA                        ( 4*32+18) /* Direct Cache Access */
+#define X86_FEATURE_XMM4_1             ( 4*32+19) /* "sse4_1" SSE-4.1 */
+#define X86_FEATURE_XMM4_2             ( 4*32+20) /* "sse4_2" SSE-4.2 */
+#define X86_FEATURE_X2APIC             ( 4*32+21) /* X2APIC */
+#define X86_FEATURE_MOVBE              ( 4*32+22) /* MOVBE instruction */
+#define X86_FEATURE_POPCNT             ( 4*32+23) /* POPCNT instruction */
+#define X86_FEATURE_TSC_DEADLINE_TIMER ( 4*32+24) /* TSC deadline timer */
+#define X86_FEATURE_AES                        ( 4*32+25) /* AES instructions */
+#define X86_FEATURE_XSAVE              ( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV instructions */
+#define X86_FEATURE_OSXSAVE            ( 4*32+27) /* "" XSAVE instruction enabled in the OS */
+#define X86_FEATURE_AVX                        ( 4*32+28) /* Advanced Vector Extensions */
+#define X86_FEATURE_F16C               ( 4*32+29) /* 16-bit FP conversions */
+#define X86_FEATURE_RDRAND             ( 4*32+30) /* RDRAND instruction */
+#define X86_FEATURE_HYPERVISOR         ( 4*32+31) /* Running on a hypervisor */
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
-#define X86_FEATURE_XSTORE     ( 5*32+ 2) /* "rng" RNG present (xstore) */
-#define X86_FEATURE_XSTORE_EN  ( 5*32+ 3) /* "rng_en" RNG enabled */
-#define X86_FEATURE_XCRYPT     ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */
-#define X86_FEATURE_XCRYPT_EN  ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */
-#define X86_FEATURE_ACE2       ( 5*32+ 8) /* Advanced Cryptography Engine v2 */
-#define X86_FEATURE_ACE2_EN    ( 5*32+ 9) /* ACE v2 enabled */
-#define X86_FEATURE_PHE                ( 5*32+10) /* PadLock Hash Engine */
-#define X86_FEATURE_PHE_EN     ( 5*32+11) /* PHE enabled */
-#define X86_FEATURE_PMM                ( 5*32+12) /* PadLock Montgomery Multiplier */
-#define X86_FEATURE_PMM_EN     ( 5*32+13) /* PMM enabled */
+#define X86_FEATURE_XSTORE             ( 5*32+ 2) /* "rng" RNG present (xstore) */
+#define X86_FEATURE_XSTORE_EN          ( 5*32+ 3) /* "rng_en" RNG enabled */
+#define X86_FEATURE_XCRYPT             ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */
+#define X86_FEATURE_XCRYPT_EN          ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */
+#define X86_FEATURE_ACE2               ( 5*32+ 8) /* Advanced Cryptography Engine v2 */
+#define X86_FEATURE_ACE2_EN            ( 5*32+ 9) /* ACE v2 enabled */
+#define X86_FEATURE_PHE                        ( 5*32+10) /* PadLock Hash Engine */
+#define X86_FEATURE_PHE_EN             ( 5*32+11) /* PHE enabled */
+#define X86_FEATURE_PMM                        ( 5*32+12) /* PadLock Montgomery Multiplier */
+#define X86_FEATURE_PMM_EN             ( 5*32+13) /* PMM enabled */
 
-/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
-#define X86_FEATURE_LAHF_LM    ( 6*32+ 0) /* LAHF/SAHF in long mode */
-#define X86_FEATURE_CMP_LEGACY ( 6*32+ 1) /* If yes HyperThreading not valid */
-#define X86_FEATURE_SVM                ( 6*32+ 2) /* Secure virtual machine */
-#define X86_FEATURE_EXTAPIC    ( 6*32+ 3) /* Extended APIC space */
-#define X86_FEATURE_CR8_LEGACY ( 6*32+ 4) /* CR8 in 32-bit mode */
-#define X86_FEATURE_ABM                ( 6*32+ 5) /* Advanced bit manipulation */
-#define X86_FEATURE_SSE4A      ( 6*32+ 6) /* SSE-4A */
-#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* Misaligned SSE mode */
-#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* 3DNow prefetch instructions */
-#define X86_FEATURE_OSVW       ( 6*32+ 9) /* OS Visible Workaround */
-#define X86_FEATURE_IBS                ( 6*32+10) /* Instruction Based Sampling */
-#define X86_FEATURE_XOP                ( 6*32+11) /* extended AVX instructions */
-#define X86_FEATURE_SKINIT     ( 6*32+12) /* SKINIT/STGI instructions */
-#define X86_FEATURE_WDT                ( 6*32+13) /* Watchdog timer */
-#define X86_FEATURE_LWP                ( 6*32+15) /* Light Weight Profiling */
-#define X86_FEATURE_FMA4       ( 6*32+16) /* 4 operands MAC instructions */
-#define X86_FEATURE_TCE                ( 6*32+17) /* translation cache extension */
-#define X86_FEATURE_NODEID_MSR ( 6*32+19) /* NodeId MSR */
-#define X86_FEATURE_TBM                ( 6*32+21) /* trailing bit manipulations */
-#define X86_FEATURE_TOPOEXT    ( 6*32+22) /* topology extensions CPUID leafs */
-#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */
-#define X86_FEATURE_PERFCTR_NB  ( 6*32+24) /* NB performance counter extensions */
-#define X86_FEATURE_BPEXT      (6*32+26) /* data breakpoint extension */
-#define X86_FEATURE_PTSC       ( 6*32+27) /* performance time-stamp counter */
-#define X86_FEATURE_PERFCTR_LLC        ( 6*32+28) /* Last Level Cache performance counter extensions */
-#define X86_FEATURE_MWAITX     ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX) */
+/* More extended AMD flags: CPUID level 0x80000001, ECX, word 6 */
+#define X86_FEATURE_LAHF_LM            ( 6*32+ 0) /* LAHF/SAHF in long mode */
+#define X86_FEATURE_CMP_LEGACY         ( 6*32+ 1) /* If yes HyperThreading not valid */
+#define X86_FEATURE_SVM                        ( 6*32+ 2) /* Secure Virtual Machine */
+#define X86_FEATURE_EXTAPIC            ( 6*32+ 3) /* Extended APIC space */
+#define X86_FEATURE_CR8_LEGACY         ( 6*32+ 4) /* CR8 in 32-bit mode */
+#define X86_FEATURE_ABM                        ( 6*32+ 5) /* Advanced bit manipulation */
+#define X86_FEATURE_SSE4A              ( 6*32+ 6) /* SSE-4A */
+#define X86_FEATURE_MISALIGNSSE                ( 6*32+ 7) /* Misaligned SSE mode */
+#define X86_FEATURE_3DNOWPREFETCH      ( 6*32+ 8) /* 3DNow prefetch instructions */
+#define X86_FEATURE_OSVW               ( 6*32+ 9) /* OS Visible Workaround */
+#define X86_FEATURE_IBS                        ( 6*32+10) /* Instruction Based Sampling */
+#define X86_FEATURE_XOP                        ( 6*32+11) /* extended AVX instructions */
+#define X86_FEATURE_SKINIT             ( 6*32+12) /* SKINIT/STGI instructions */
+#define X86_FEATURE_WDT                        ( 6*32+13) /* Watchdog timer */
+#define X86_FEATURE_LWP                        ( 6*32+15) /* Light Weight Profiling */
+#define X86_FEATURE_FMA4               ( 6*32+16) /* 4 operands MAC instructions */
+#define X86_FEATURE_TCE                        ( 6*32+17) /* Translation Cache Extension */
+#define X86_FEATURE_NODEID_MSR         ( 6*32+19) /* NodeId MSR */
+#define X86_FEATURE_TBM                        ( 6*32+21) /* Trailing Bit Manipulations */
+#define X86_FEATURE_TOPOEXT            ( 6*32+22) /* Topology extensions CPUID leafs */
+#define X86_FEATURE_PERFCTR_CORE       ( 6*32+23) /* Core performance counter extensions */
+#define X86_FEATURE_PERFCTR_NB         ( 6*32+24) /* NB performance counter extensions */
+#define X86_FEATURE_BPEXT              ( 6*32+26) /* Data breakpoint extension */
+#define X86_FEATURE_PTSC               ( 6*32+27) /* Performance time-stamp counter */
+#define X86_FEATURE_PERFCTR_LLC                ( 6*32+28) /* Last Level Cache performance counter extensions */
+#define X86_FEATURE_MWAITX             ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX instructions) */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
  *
  * Reuse free bits when adding new feature flags!
  */
-#define X86_FEATURE_RING3MWAIT ( 7*32+ 0) /* Ring 3 MONITOR/MWAIT */
-#define X86_FEATURE_CPUID_FAULT ( 7*32+ 1) /* Intel CPUID faulting */
-#define X86_FEATURE_CPB                ( 7*32+ 2) /* AMD Core Performance Boost */
-#define X86_FEATURE_EPB                ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
-#define X86_FEATURE_CAT_L3     ( 7*32+ 4) /* Cache Allocation Technology L3 */
-#define X86_FEATURE_CAT_L2     ( 7*32+ 5) /* Cache Allocation Technology L2 */
-#define X86_FEATURE_CDP_L3     ( 7*32+ 6) /* Code and Data Prioritization L3 */
+#define X86_FEATURE_RING3MWAIT         ( 7*32+ 0) /* Ring 3 MONITOR/MWAIT instructions */
+#define X86_FEATURE_CPUID_FAULT                ( 7*32+ 1) /* Intel CPUID faulting */
+#define X86_FEATURE_CPB                        ( 7*32+ 2) /* AMD Core Performance Boost */
+#define X86_FEATURE_EPB                        ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
+#define X86_FEATURE_CAT_L3             ( 7*32+ 4) /* Cache Allocation Technology L3 */
+#define X86_FEATURE_CAT_L2             ( 7*32+ 5) /* Cache Allocation Technology L2 */
+#define X86_FEATURE_CDP_L3             ( 7*32+ 6) /* Code and Data Prioritization L3 */
 
-#define X86_FEATURE_HW_PSTATE  ( 7*32+ 8) /* AMD HW-PState */
-#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
-#define X86_FEATURE_SME                ( 7*32+10) /* AMD Secure Memory Encryption */
+#define X86_FEATURE_HW_PSTATE          ( 7*32+ 8) /* AMD HW-PState */
+#define X86_FEATURE_PROC_FEEDBACK      ( 7*32+ 9) /* AMD ProcFeedbackInterface */
+#define X86_FEATURE_SME                        ( 7*32+10) /* AMD Secure Memory Encryption */
 
-#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */
-#define X86_FEATURE_INTEL_PT   ( 7*32+15) /* Intel Processor Trace */
-#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */
-#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_INTEL_PPIN         ( 7*32+14) /* Intel Processor Inventory Number */
+#define X86_FEATURE_INTEL_PT           ( 7*32+15) /* Intel Processor Trace */
+#define X86_FEATURE_AVX512_4VNNIW      ( 7*32+16) /* AVX-512 Neural Network Instructions */
+#define X86_FEATURE_AVX512_4FMAPS      ( 7*32+17) /* AVX-512 Multiply Accumulation Single precision */
 
-#define X86_FEATURE_MBA         ( 7*32+18) /* Memory Bandwidth Allocation */
+#define X86_FEATURE_MBA                        ( 7*32+18) /* Memory Bandwidth Allocation */
 
 /* Virtualization flags: Linux defined, word 8 */
-#define X86_FEATURE_TPR_SHADOW  ( 8*32+ 0) /* Intel TPR Shadow */
-#define X86_FEATURE_VNMI        ( 8*32+ 1) /* Intel Virtual NMI */
-#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */
-#define X86_FEATURE_EPT         ( 8*32+ 3) /* Intel Extended Page Table */
-#define X86_FEATURE_VPID        ( 8*32+ 4) /* Intel Virtual Processor ID */
+#define X86_FEATURE_TPR_SHADOW         ( 8*32+ 0) /* Intel TPR Shadow */
+#define X86_FEATURE_VNMI               ( 8*32+ 1) /* Intel Virtual NMI */
+#define X86_FEATURE_FLEXPRIORITY       ( 8*32+ 2) /* Intel FlexPriority */
+#define X86_FEATURE_EPT                        ( 8*32+ 3) /* Intel Extended Page Table */
+#define X86_FEATURE_VPID               ( 8*32+ 4) /* Intel Virtual Processor ID */
 
-#define X86_FEATURE_VMMCALL     ( 8*32+15) /* Prefer vmmcall to vmcall */
-#define X86_FEATURE_XENPV       ( 8*32+16) /* "" Xen paravirtual guest */
+#define X86_FEATURE_VMMCALL            ( 8*32+15) /* Prefer VMMCALL to VMCALL */
+#define X86_FEATURE_XENPV              ( 8*32+16) /* "" Xen paravirtual guest */
 
 
-/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
-#define X86_FEATURE_FSGSBASE   ( 9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
-#define X86_FEATURE_TSC_ADJUST ( 9*32+ 1) /* TSC adjustment MSR 0x3b */
-#define X86_FEATURE_BMI1       ( 9*32+ 3) /* 1st group bit manipulation extensions */
-#define X86_FEATURE_HLE                ( 9*32+ 4) /* Hardware Lock Elision */
-#define X86_FEATURE_AVX2       ( 9*32+ 5) /* AVX2 instructions */
-#define X86_FEATURE_SMEP       ( 9*32+ 7) /* Supervisor Mode Execution Protection */
-#define X86_FEATURE_BMI2       ( 9*32+ 8) /* 2nd group bit manipulation extensions */
-#define X86_FEATURE_ERMS       ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB */
-#define X86_FEATURE_INVPCID    ( 9*32+10) /* Invalidate Processor Context ID */
-#define X86_FEATURE_RTM                ( 9*32+11) /* Restricted Transactional Memory */
-#define X86_FEATURE_CQM                ( 9*32+12) /* Cache QoS Monitoring */
-#define X86_FEATURE_MPX                ( 9*32+14) /* Memory Protection Extension */
-#define X86_FEATURE_RDT_A      ( 9*32+15) /* Resource Director Technology Allocation */
-#define X86_FEATURE_AVX512F    ( 9*32+16) /* AVX-512 Foundation */
-#define X86_FEATURE_AVX512DQ   ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */
-#define X86_FEATURE_RDSEED     ( 9*32+18) /* The RDSEED instruction */
-#define X86_FEATURE_ADX                ( 9*32+19) /* The ADCX and ADOX instructions */
-#define X86_FEATURE_SMAP       ( 9*32+20) /* Supervisor Mode Access Prevention */
-#define X86_FEATURE_AVX512IFMA  ( 9*32+21) /* AVX-512 Integer Fused Multiply-Add instructions */
-#define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */
-#define X86_FEATURE_CLWB       ( 9*32+24) /* CLWB instruction */
-#define X86_FEATURE_AVX512PF   ( 9*32+26) /* AVX-512 Prefetch */
-#define X86_FEATURE_AVX512ER   ( 9*32+27) /* AVX-512 Exponential and Reciprocal */
-#define X86_FEATURE_AVX512CD   ( 9*32+28) /* AVX-512 Conflict Detection */
-#define X86_FEATURE_SHA_NI     ( 9*32+29) /* SHA1/SHA256 Instruction Extensions */
-#define X86_FEATURE_AVX512BW   ( 9*32+30) /* AVX-512 BW (Byte/Word granular) Instructions */
-#define X86_FEATURE_AVX512VL   ( 9*32+31) /* AVX-512 VL (128/256 Vector Length) Extensions */
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
+#define X86_FEATURE_FSGSBASE           ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
+#define X86_FEATURE_TSC_ADJUST         ( 9*32+ 1) /* TSC adjustment MSR 0x3B */
+#define X86_FEATURE_BMI1               ( 9*32+ 3) /* 1st group bit manipulation extensions */
+#define X86_FEATURE_HLE                        ( 9*32+ 4) /* Hardware Lock Elision */
+#define X86_FEATURE_AVX2               ( 9*32+ 5) /* AVX2 instructions */
+#define X86_FEATURE_SMEP               ( 9*32+ 7) /* Supervisor Mode Execution Protection */
+#define X86_FEATURE_BMI2               ( 9*32+ 8) /* 2nd group bit manipulation extensions */
+#define X86_FEATURE_ERMS               ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB instructions */
+#define X86_FEATURE_INVPCID            ( 9*32+10) /* Invalidate Processor Context ID */
+#define X86_FEATURE_RTM                        ( 9*32+11) /* Restricted Transactional Memory */
+#define X86_FEATURE_CQM                        ( 9*32+12) /* Cache QoS Monitoring */
+#define X86_FEATURE_MPX                        ( 9*32+14) /* Memory Protection Extension */
+#define X86_FEATURE_RDT_A              ( 9*32+15) /* Resource Director Technology Allocation */
+#define X86_FEATURE_AVX512F            ( 9*32+16) /* AVX-512 Foundation */
+#define X86_FEATURE_AVX512DQ           ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */
+#define X86_FEATURE_RDSEED             ( 9*32+18) /* RDSEED instruction */
+#define X86_FEATURE_ADX                        ( 9*32+19) /* ADCX and ADOX instructions */
+#define X86_FEATURE_SMAP               ( 9*32+20) /* Supervisor Mode Access Prevention */
+#define X86_FEATURE_AVX512IFMA         ( 9*32+21) /* AVX-512 Integer Fused Multiply-Add instructions */
+#define X86_FEATURE_CLFLUSHOPT         ( 9*32+23) /* CLFLUSHOPT instruction */
+#define X86_FEATURE_CLWB               ( 9*32+24) /* CLWB instruction */
+#define X86_FEATURE_AVX512PF           ( 9*32+26) /* AVX-512 Prefetch */
+#define X86_FEATURE_AVX512ER           ( 9*32+27) /* AVX-512 Exponential and Reciprocal */
+#define X86_FEATURE_AVX512CD           ( 9*32+28) /* AVX-512 Conflict Detection */
+#define X86_FEATURE_SHA_NI             ( 9*32+29) /* SHA1/SHA256 Instruction Extensions */
+#define X86_FEATURE_AVX512BW           ( 9*32+30) /* AVX-512 BW (Byte/Word granular) Instructions */
+#define X86_FEATURE_AVX512VL           ( 9*32+31) /* AVX-512 VL (128/256 Vector Length) Extensions */
 
-/* Extended state features, CPUID level 0x0000000d:1 (eax), word 10 */
-#define X86_FEATURE_XSAVEOPT   (10*32+ 0) /* XSAVEOPT */
-#define X86_FEATURE_XSAVEC     (10*32+ 1) /* XSAVEC */
-#define X86_FEATURE_XGETBV1    (10*32+ 2) /* XGETBV with ECX = 1 */
-#define X86_FEATURE_XSAVES     (10*32+ 3) /* XSAVES/XRSTORS */
+/* Extended state features, CPUID level 0x0000000d:1 (EAX), word 10 */
+#define X86_FEATURE_XSAVEOPT           (10*32+ 0) /* XSAVEOPT instruction */
+#define X86_FEATURE_XSAVEC             (10*32+ 1) /* XSAVEC instruction */
+#define X86_FEATURE_XGETBV1            (10*32+ 2) /* XGETBV with ECX = 1 instruction */
+#define X86_FEATURE_XSAVES             (10*32+ 3) /* XSAVES/XRSTORS instructions */
 
-/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (edx), word 11 */
-#define X86_FEATURE_CQM_LLC    (11*32+ 1) /* LLC QoS if 1 */
+/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (EDX), word 11 */
+#define X86_FEATURE_CQM_LLC            (11*32+ 1) /* LLC QoS if 1 */
 
-/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (edx), word 12 */
-#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring if 1 */
-#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */
-#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */
+/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (EDX), word 12 */
+#define X86_FEATURE_CQM_OCCUP_LLC      (12*32+ 0) /* LLC occupancy monitoring */
+#define X86_FEATURE_CQM_MBM_TOTAL      (12*32+ 1) /* LLC Total MBM monitoring */
+#define X86_FEATURE_CQM_MBM_LOCAL      (12*32+ 2) /* LLC Local MBM monitoring */
 
-/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
-#define X86_FEATURE_CLZERO     (13*32+0) /* CLZERO instruction */
-#define X86_FEATURE_IRPERF     (13*32+1) /* Instructions Retired Count */
+/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
+#define X86_FEATURE_CLZERO             (13*32+ 0) /* CLZERO instruction */
+#define X86_FEATURE_IRPERF             (13*32+ 1) /* Instructions Retired Count */
 
-/* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */
-#define X86_FEATURE_DTHERM     (14*32+ 0) /* Digital Thermal Sensor */
-#define X86_FEATURE_IDA                (14*32+ 1) /* Intel Dynamic Acceleration */
-#define X86_FEATURE_ARAT       (14*32+ 2) /* Always Running APIC Timer */
-#define X86_FEATURE_PLN                (14*32+ 4) /* Intel Power Limit Notification */
-#define X86_FEATURE_PTS                (14*32+ 6) /* Intel Package Thermal Status */
-#define X86_FEATURE_HWP                (14*32+ 7) /* Intel Hardware P-states */
-#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */
-#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */
-#define X86_FEATURE_HWP_EPP    (14*32+10) /* HWP Energy Perf. Preference */
-#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */
+/* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
+#define X86_FEATURE_DTHERM             (14*32+ 0) /* Digital Thermal Sensor */
+#define X86_FEATURE_IDA                        (14*32+ 1) /* Intel Dynamic Acceleration */
+#define X86_FEATURE_ARAT               (14*32+ 2) /* Always Running APIC Timer */
+#define X86_FEATURE_PLN                        (14*32+ 4) /* Intel Power Limit Notification */
+#define X86_FEATURE_PTS                        (14*32+ 6) /* Intel Package Thermal Status */
+#define X86_FEATURE_HWP                        (14*32+ 7) /* Intel Hardware P-states */
+#define X86_FEATURE_HWP_NOTIFY         (14*32+ 8) /* HWP Notification */
+#define X86_FEATURE_HWP_ACT_WINDOW     (14*32+ 9) /* HWP Activity Window */
+#define X86_FEATURE_HWP_EPP            (14*32+10) /* HWP Energy Perf. Preference */
+#define X86_FEATURE_HWP_PKG_REQ                (14*32+11) /* HWP Package Level Request */
 
-/* AMD SVM Feature Identification, CPUID level 0x8000000a (edx), word 15 */
-#define X86_FEATURE_NPT                (15*32+ 0) /* Nested Page Table support */
-#define X86_FEATURE_LBRV       (15*32+ 1) /* LBR Virtualization support */
-#define X86_FEATURE_SVML       (15*32+ 2) /* "svm_lock" SVM locking MSR */
-#define X86_FEATURE_NRIPS      (15*32+ 3) /* "nrip_save" SVM next_rip save */
-#define X86_FEATURE_TSCRATEMSR  (15*32+ 4) /* "tsc_scale" TSC scaling support */
-#define X86_FEATURE_VMCBCLEAN   (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */
-#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */
-#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */
-#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */
-#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */
-#define X86_FEATURE_AVIC       (15*32+13) /* Virtual Interrupt Controller */
-#define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */
-#define X86_FEATURE_VGIF       (15*32+16) /* Virtual GIF */
+/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */
+#define X86_FEATURE_NPT                        (15*32+ 0) /* Nested Page Table support */
+#define X86_FEATURE_LBRV               (15*32+ 1) /* LBR Virtualization support */
+#define X86_FEATURE_SVML               (15*32+ 2) /* "svm_lock" SVM locking MSR */
+#define X86_FEATURE_NRIPS              (15*32+ 3) /* "nrip_save" SVM next_rip save */
+#define X86_FEATURE_TSCRATEMSR         (15*32+ 4) /* "tsc_scale" TSC scaling support */
+#define X86_FEATURE_VMCBCLEAN          (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */
+#define X86_FEATURE_FLUSHBYASID                (15*32+ 6) /* flush-by-ASID support */
+#define X86_FEATURE_DECODEASSISTS      (15*32+ 7) /* Decode Assists support */
+#define X86_FEATURE_PAUSEFILTER                (15*32+10) /* filtered pause intercept */
+#define X86_FEATURE_PFTHRESHOLD                (15*32+12) /* pause filter threshold */
+#define X86_FEATURE_AVIC               (15*32+13) /* Virtual Interrupt Controller */
+#define X86_FEATURE_V_VMSAVE_VMLOAD    (15*32+15) /* Virtual VMSAVE VMLOAD */
+#define X86_FEATURE_VGIF               (15*32+16) /* Virtual GIF */
 
-/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */
-#define X86_FEATURE_AVX512VBMI  (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/
-#define X86_FEATURE_PKU                (16*32+ 3) /* Protection Keys for Userspace */
-#define X86_FEATURE_OSPKE      (16*32+ 4) /* OS Protection Keys Enable */
-#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */
-#define X86_FEATURE_LA57       (16*32+16) /* 5-level page tables */
-#define X86_FEATURE_RDPID      (16*32+22) /* RDPID instruction */
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (ECX), word 16 */
+#define X86_FEATURE_AVX512VBMI         (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/
+#define X86_FEATURE_UMIP               (16*32+ 2) /* User Mode Instruction Protection */
+#define X86_FEATURE_PKU                        (16*32+ 3) /* Protection Keys for Userspace */
+#define X86_FEATURE_OSPKE              (16*32+ 4) /* OS Protection Keys Enable */
+#define X86_FEATURE_AVX512_VBMI2       (16*32+ 6) /* Additional AVX512 Vector Bit Manipulation Instructions */
+#define X86_FEATURE_GFNI               (16*32+ 8) /* Galois Field New Instructions */
+#define X86_FEATURE_VAES               (16*32+ 9) /* Vector AES */
+#define X86_FEATURE_VPCLMULQDQ         (16*32+10) /* Carry-Less Multiplication Double Quadword */
+#define X86_FEATURE_AVX512_VNNI                (16*32+11) /* Vector Neural Network Instructions */
+#define X86_FEATURE_AVX512_BITALG      (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */
+#define X86_FEATURE_AVX512_VPOPCNTDQ   (16*32+14) /* POPCNT for vectors of DW/QW */
+#define X86_FEATURE_LA57               (16*32+16) /* 5-level page tables */
+#define X86_FEATURE_RDPID              (16*32+22) /* RDPID instruction */
 
-/* AMD-defined CPU features, CPUID level 0x80000007 (ebx), word 17 */
-#define X86_FEATURE_OVERFLOW_RECOV (17*32+0) /* MCA overflow recovery support */
-#define X86_FEATURE_SUCCOR     (17*32+1) /* Uncorrectable error containment and recovery */
-#define X86_FEATURE_SMCA       (17*32+3) /* Scalable MCA */
+/* AMD-defined CPU features, CPUID level 0x80000007 (EBX), word 17 */
+#define X86_FEATURE_OVERFLOW_RECOV     (17*32+ 0) /* MCA overflow recovery support */
+#define X86_FEATURE_SUCCOR             (17*32+ 1) /* Uncorrectable error containment and recovery */
+#define X86_FEATURE_SMCA               (17*32+ 3) /* Scalable MCA */
 
 /*
  * BUG word(s)
  */
-#define X86_BUG(x)             (NCAPINTS*32 + (x))
+#define X86_BUG(x)                     (NCAPINTS*32 + (x))
 
-#define X86_BUG_F00F           X86_BUG(0) /* Intel F00F */
-#define X86_BUG_FDIV           X86_BUG(1) /* FPU FDIV */
-#define X86_BUG_COMA           X86_BUG(2) /* Cyrix 6x86 coma */
-#define X86_BUG_AMD_TLB_MMATCH X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */
-#define X86_BUG_AMD_APIC_C1E   X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */
-#define X86_BUG_11AP           X86_BUG(5) /* Bad local APIC aka 11AP */
-#define X86_BUG_FXSAVE_LEAK    X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */
-#define X86_BUG_CLFLUSH_MONITOR        X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */
-#define X86_BUG_SYSRET_SS_ATTRS        X86_BUG(8) /* SYSRET doesn't fix up SS attrs */
+#define X86_BUG_F00F                   X86_BUG(0) /* Intel F00F */
+#define X86_BUG_FDIV                   X86_BUG(1) /* FPU FDIV */
+#define X86_BUG_COMA                   X86_BUG(2) /* Cyrix 6x86 coma */
+#define X86_BUG_AMD_TLB_MMATCH         X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */
+#define X86_BUG_AMD_APIC_C1E           X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */
+#define X86_BUG_11AP                   X86_BUG(5) /* Bad local APIC aka 11AP */
+#define X86_BUG_FXSAVE_LEAK            X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */
+#define X86_BUG_CLFLUSH_MONITOR                X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */
+#define X86_BUG_SYSRET_SS_ATTRS                X86_BUG(8) /* SYSRET doesn't fix up SS attrs */
 #ifdef CONFIG_X86_32
 /*
  * 64-bit kernels don't use X86_BUG_ESPFIX.  Make the define conditional
  * to avoid confusion.
  */
-#define X86_BUG_ESPFIX         X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */
+#define X86_BUG_ESPFIX                 X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */
 #endif
-#define X86_BUG_NULL_SEG       X86_BUG(10) /* Nulling a selector preserves the base */
-#define X86_BUG_SWAPGS_FENCE   X86_BUG(11) /* SWAPGS without input dep on GS */
-#define X86_BUG_MONITOR                X86_BUG(12) /* IPI required to wake up remote CPU */
-#define X86_BUG_AMD_E400       X86_BUG(13) /* CPU is among the affected by Erratum 400 */
+#define X86_BUG_NULL_SEG               X86_BUG(10) /* Nulling a selector preserves the base */
+#define X86_BUG_SWAPGS_FENCE           X86_BUG(11) /* SWAPGS without input dep on GS */
+#define X86_BUG_MONITOR                        X86_BUG(12) /* IPI required to wake up remote CPU */
+#define X86_BUG_AMD_E400               X86_BUG(13) /* CPU is among the affected by Erratum 400 */
+
 #endif /* _ASM_X86_CPUFEATURES_H */
index 0a3e808b91230dbe498769fd18503a2d2960d3bc..4011cb03ef08e52db15f52779ce366c26359a34b 100644 (file)
@@ -393,7 +393,7 @@ static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit)
 void update_intr_gate(unsigned int n, const void *addr);
 void alloc_intr_gate(unsigned int n, const void *addr);
 
-extern unsigned long used_vectors[];
+extern unsigned long system_vectors[];
 
 #ifdef CONFIG_X86_64
 DECLARE_PER_CPU(u32, debug_idt_ctr);
index c10c9128f54e6b7296014a74e7a253a1eedaacd9..14d6d50073142b0f49b06850ccd0d394546479ee 100644 (file)
 # define DISABLE_MPX   (1<<(X86_FEATURE_MPX & 31))
 #endif
 
+#ifdef CONFIG_X86_INTEL_UMIP
+# define DISABLE_UMIP  0
+#else
+# define DISABLE_UMIP  (1<<(X86_FEATURE_UMIP & 31))
+#endif
+
 #ifdef CONFIG_X86_64
 # define DISABLE_VME           (1<<(X86_FEATURE_VME & 31))
 # define DISABLE_K6_MTRR       (1<<(X86_FEATURE_K6_MTRR & 31))
@@ -63,7 +69,7 @@
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
 #define DISABLED_MASK15        0
-#define DISABLED_MASK16        (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57)
+#define DISABLED_MASK16        (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57|DISABLE_UMIP)
 #define DISABLED_MASK17        0
 #define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
 
index c1a125e47ff3d08c9078ceda13c188404f965f96..3a091cea36c5a118d953fd25c897989270c6f0e4 100644 (file)
@@ -253,7 +253,7 @@ extern int force_personality32;
  * space open for things that want to use the area for 32-bit pointers.
  */
 #define ELF_ET_DYN_BASE                (mmap_is_ia32() ? 0x000400000UL : \
-                                                 (TASK_SIZE / 3 * 2))
+                                                 (DEFAULT_MAP_WINDOW / 3 * 2))
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports.  This could be done in user space,
index dcd9fb55e67991821d46602754a392c6f2ed0e06..b0c505fe9a958c701fef6d96f281bb8ab1a773de 100644 (file)
@@ -104,6 +104,12 @@ enum fixed_addresses {
        FIX_GDT_REMAP_BEGIN,
        FIX_GDT_REMAP_END = FIX_GDT_REMAP_BEGIN + NR_CPUS - 1,
 
+#ifdef CONFIG_ACPI_APEI_GHES
+       /* Used for GHES mapping from assorted contexts */
+       FIX_APEI_GHES_IRQ,
+       FIX_APEI_GHES_NMI,
+#endif
+
        __end_of_permanent_fixed_addresses,
 
        /*
index 8ec99a55e6b9d17df05bc02fcff637204c07ffa3..b80e46733909c981aa9125c055d7e1f9f22b2409 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <asm/irq_vectors.h>
 
+#define IRQ_MATRIX_BITS                NR_VECTORS
+
 #ifndef __ASSEMBLY__
 
 #include <linux/percpu.h>
@@ -123,15 +125,13 @@ struct irq_alloc_info {
 
 struct irq_cfg {
        unsigned int            dest_apicid;
-       u8                      vector;
-       u8                      old_vector;
+       unsigned int            vector;
 };
 
 extern struct irq_cfg *irq_cfg(unsigned int irq);
 extern struct irq_cfg *irqd_cfg(struct irq_data *irq_data);
 extern void lock_vector_lock(void);
 extern void unlock_vector_lock(void);
-extern void setup_vector_irq(int cpu);
 #ifdef CONFIG_SMP
 extern void send_cleanup_vector(struct irq_cfg *);
 extern void irq_complete_move(struct irq_cfg *cfg);
index 0ead9dbb91301d0f7f8923dcf33f25515bd182b8..1b0a5abcd8aeb6e700013c5434aaeb0bba7a152f 100644 (file)
 #ifdef CONFIG_HYPERVISOR_GUEST
 
 #include <asm/kvm_para.h>
+#include <asm/x86_init.h>
 #include <asm/xen/hypervisor.h>
 
 /*
  * x86 hypervisor information
  */
+
+enum x86_hypervisor_type {
+       X86_HYPER_NATIVE = 0,
+       X86_HYPER_VMWARE,
+       X86_HYPER_MS_HYPERV,
+       X86_HYPER_XEN_PV,
+       X86_HYPER_XEN_HVM,
+       X86_HYPER_KVM,
+};
+
 struct hypervisor_x86 {
        /* Hypervisor name */
        const char      *name;
@@ -35,40 +46,19 @@ struct hypervisor_x86 {
        /* Detection routine */
        uint32_t        (*detect)(void);
 
-       /* Platform setup (run once per boot) */
-       void            (*init_platform)(void);
-
-       /* X2APIC detection (run once per boot) */
-       bool            (*x2apic_available)(void);
+       /* Hypervisor type */
+       enum x86_hypervisor_type type;
 
-       /* pin current vcpu to specified physical cpu (run rarely) */
-       void            (*pin_vcpu)(int);
+       /* init time callbacks */
+       struct x86_hyper_init init;
 
-       /* called during init_mem_mapping() to setup early mappings. */
-       void            (*init_mem_mapping)(void);
+       /* runtime callbacks */
+       struct x86_hyper_runtime runtime;
 };
 
-extern const struct hypervisor_x86 *x86_hyper;
-
-/* Recognized hypervisors */
-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 enum x86_hypervisor_type x86_hyper_type;
 extern void init_hypervisor_platform(void);
-extern bool hypervisor_x2apic_available(void);
-extern void hypervisor_pin_vcpu(int cpu);
-
-static inline void hypervisor_init_mem_mapping(void)
-{
-       if (x86_hyper && x86_hyper->init_mem_mapping)
-               x86_hyper->init_mem_mapping();
-}
 #else
 static inline void init_hypervisor_platform(void) { }
-static inline bool hypervisor_x2apic_available(void) { return false; }
-static inline void hypervisor_init_mem_mapping(void) { }
 #endif /* CONFIG_HYPERVISOR_GUEST */
 #endif /* _ASM_X86_HYPERVISOR_H */
index 02aff08672115defd9511dd87f73c83c715c44ca..1c78580e58bea3e83b79076409aaaab2343aa47f 100644 (file)
 #define INAT_MAKE_GROUP(grp)   ((grp << INAT_GRP_OFFS) | INAT_MODRM)
 #define INAT_MAKE_IMM(imm)     (imm << INAT_IMM_OFFS)
 
+/* Identifiers for segment registers */
+#define INAT_SEG_REG_IGNORE    0
+#define INAT_SEG_REG_DEFAULT   1
+#define INAT_SEG_REG_CS                2
+#define INAT_SEG_REG_SS                3
+#define INAT_SEG_REG_DS                4
+#define INAT_SEG_REG_ES                5
+#define INAT_SEG_REG_FS                6
+#define INAT_SEG_REG_GS                7
+
 /* Attribute search APIs */
 extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
 extern int inat_get_last_prefix_id(insn_byte_t last_pfx);
diff --git a/arch/x86/include/asm/insn-eval.h b/arch/x86/include/asm/insn-eval.h
new file mode 100644 (file)
index 0000000..e1d3b4c
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _ASM_X86_INSN_EVAL_H
+#define _ASM_X86_INSN_EVAL_H
+/*
+ * A collection of utility functions for x86 instruction analysis to be
+ * used in a kernel context. Useful when, for instance, making sense
+ * of the registers indicated by operands.
+ */
+
+#include <linux/compiler.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <asm/ptrace.h>
+
+#define INSN_CODE_SEG_ADDR_SZ(params) ((params >> 4) & 0xf)
+#define INSN_CODE_SEG_OPND_SZ(params) (params & 0xf)
+#define INSN_CODE_SEG_PARAMS(oper_sz, addr_sz) (oper_sz | (addr_sz << 4))
+
+void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs);
+int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs);
+unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx);
+char insn_get_code_seg_params(struct pt_regs *regs);
+
+#endif /* _ASM_X86_INSN_EVAL_H */
index 11398d55aefaea3b03fe68bf65758e97c69513d2..93ae8aee178075da0110e026c546ab2db8674775 100644 (file)
@@ -266,6 +266,21 @@ static inline void slow_down_io(void)
 
 #endif
 
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+#include <linux/jump_label.h>
+
+extern struct static_key_false sev_enable_key;
+static inline bool sev_key_active(void)
+{
+       return static_branch_unlikely(&sev_enable_key);
+}
+
+#else /* !CONFIG_AMD_MEM_ENCRYPT */
+
+static inline bool sev_key_active(void) { return false; }
+
+#endif /* CONFIG_AMD_MEM_ENCRYPT */
+
 #define BUILDIO(bwl, bw, type)                                         \
 static inline void out##bwl(unsigned type value, int port)             \
 {                                                                      \
@@ -296,14 +311,34 @@ static inline unsigned type in##bwl##_p(int port)                 \
                                                                        \
 static inline void outs##bwl(int port, const void *addr, unsigned long count) \
 {                                                                      \
-       asm volatile("rep; outs" #bwl                                   \
-                    : "+S"(addr), "+c"(count) : "d"(port) : "memory"); \
+       if (sev_key_active()) {                                         \
+               unsigned type *value = (unsigned type *)addr;           \
+               while (count) {                                         \
+                       out##bwl(*value, port);                         \
+                       value++;                                        \
+                       count--;                                        \
+               }                                                       \
+       } else {                                                        \
+               asm volatile("rep; outs" #bwl                           \
+                            : "+S"(addr), "+c"(count)                  \
+                            : "d"(port) : "memory");                   \
+       }                                                               \
 }                                                                      \
                                                                        \
 static inline void ins##bwl(int port, void *addr, unsigned long count) \
 {                                                                      \
-       asm volatile("rep; ins" #bwl                                    \
-                    : "+D"(addr), "+c"(count) : "d"(port) : "memory"); \
+       if (sev_key_active()) {                                         \
+               unsigned type *value = (unsigned type *)addr;           \
+               while (count) {                                         \
+                       *value = in##bwl(port);                         \
+                       value++;                                        \
+                       count--;                                        \
+               }                                                       \
+       } else {                                                        \
+               asm volatile("rep; ins" #bwl                            \
+                            : "+D"(addr), "+c"(count)                  \
+                            : "d"(port) : "memory");                   \
+       }                                                               \
 }
 
 BUILDIO(b, b, char)
index 5c27e146a16696365754c8381722379f399f490e..a8834dd546cdb10ce148262a55cf18653876d7c7 100644 (file)
@@ -193,7 +193,6 @@ static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 extern void setup_IO_APIC(void);
 extern void enable_IO_APIC(void);
 extern void disable_IO_APIC(void);
-extern void setup_ioapic_dest(void);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin);
 extern void print_IO_APICs(void);
 #else  /* !CONFIG_X86_IO_APIC */
@@ -233,7 +232,6 @@ static inline void io_apic_init_mappings(void) { }
 
 static inline void setup_IO_APIC(void) { }
 static inline void enable_IO_APIC(void) { }
-static inline void setup_ioapic_dest(void) { }
 
 #endif
 
index d8632f8fa17d5a1fe52217ded64892c7c6bf72ff..2395bb794c7bb89211abb69a3f6deab2abf4d132 100644 (file)
@@ -26,11 +26,7 @@ extern void irq_ctx_init(int cpu);
 
 struct irq_desc;
 
-#ifdef CONFIG_HOTPLUG_CPU
-#include <linux/cpumask.h>
-extern int check_irq_vectors_for_cpu_disable(void);
 extern void fixup_irqs(void);
-#endif
 
 #ifdef CONFIG_HAVE_KVM
 extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void));
index c20ffca8fef1782ec8fdca8cad5e38b57b014120..67421f649cfa18d064a259bbbd78b30ebd44144a 100644 (file)
 #define POSTED_INTR_NESTED_VECTOR      0xf0
 #endif
 
-/*
- * Local APIC timer IRQ vector is on a different priority level,
- * to work around the 'lost local interrupt if more than 2 IRQ
- * sources per level' errata.
- */
-#define LOCAL_TIMER_VECTOR             0xef
+#define MANAGED_IRQ_SHUTDOWN_VECTOR    0xef
+#define LOCAL_TIMER_VECTOR             0xee
 
 #define NR_VECTORS                      256
 
index 423e112c1e8fe3f884e3c0e0f0001234104a305a..f695cc6b8e1f4476263d4477063aec247accde0d 100644 (file)
@@ -9,6 +9,7 @@
 enum {
        /* Allocate contiguous CPU vectors */
        X86_IRQ_ALLOC_CONTIGUOUS_VECTORS                = 0x1,
+       X86_IRQ_ALLOC_LEGACY                            = 0x2,
 };
 
 extern struct irq_domain *x86_vector_domain;
@@ -42,8 +43,8 @@ extern int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
                              unsigned int nr_irqs, void *arg);
 extern void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
                              unsigned int nr_irqs);
-extern void mp_irqdomain_activate(struct irq_domain *domain,
-                                 struct irq_data *irq_data);
+extern int mp_irqdomain_activate(struct irq_domain *domain,
+                                struct irq_data *irq_data, bool early);
 extern void mp_irqdomain_deactivate(struct irq_domain *domain,
                                    struct irq_data *irq_data);
 extern int mp_irqdomain_ioapic_idx(struct irq_domain *domain);
index 6cf65437b5e502194c9f4a354f755ee7b2a39102..9f2e3102e0bbea0f34baa5621703aa8ad01f1e39 100644 (file)
@@ -58,8 +58,8 @@ extern __visible kprobe_opcode_t optprobe_template_call[];
 extern __visible kprobe_opcode_t optprobe_template_end[];
 #define MAX_OPTIMIZED_LENGTH (MAX_INSN_SIZE + RELATIVE_ADDR_SIZE)
 #define MAX_OPTINSN_SIZE                               \
-       (((unsigned long)&optprobe_template_end -       \
-         (unsigned long)&optprobe_template_entry) +    \
+       (((unsigned long)optprobe_template_end -        \
+         (unsigned long)optprobe_template_entry) +     \
         MAX_OPTIMIZED_LENGTH + RELATIVEJUMP_SIZE)
 
 extern const int kretprobe_blacklist_size;
index c73e493adf0748108c31389ca62437267ea877e2..9d7d856b2d8965f605412d2716717e7069cefdb9 100644 (file)
@@ -1419,7 +1419,7 @@ static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
 static inline int kvm_cpu_get_apicid(int mps_cpu)
 {
 #ifdef CONFIG_X86_LOCAL_APIC
-       return __default_cpu_present_to_apicid(mps_cpu);
+       return default_cpu_present_to_apicid(mps_cpu);
 #else
        WARN_ON_ONCE(1);
        return BAD_APICID;
index c373e44049b10c0701d4ab83a003afcae6e692d2..7b407dda2bd713e00f1429a680528ad4e85973f7 100644 (file)
@@ -88,7 +88,6 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
 #ifdef CONFIG_KVM_GUEST
 bool kvm_para_available(void);
 unsigned int kvm_arch_para_features(void);
-void __init kvm_guest_init(void);
 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);
@@ -103,7 +102,6 @@ static inline void kvm_spinlock_init(void)
 #endif /* CONFIG_PARAVIRT_SPINLOCKS */
 
 #else /* CONFIG_KVM_GUEST */
-#define kvm_guest_init() do {} while (0)
 #define kvm_async_pf_task_wait(T, I) do {} while(0)
 #define kvm_async_pf_task_wake(T) do {} while(0)
 
index 6a77c63540f7585477229f27fc1797bc1bdd5719..c9459a4c3c680b754365cd8531b5c25f51b5fb54 100644 (file)
@@ -42,11 +42,17 @@ void __init sme_early_init(void);
 void __init sme_encrypt_kernel(void);
 void __init sme_enable(struct boot_params *bp);
 
+int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
+int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size);
+
 /* Architecture __weak replacement functions */
 void __init mem_encrypt_init(void);
 
 void swiotlb_set_mem_attributes(void *vaddr, unsigned long size);
 
+bool sme_active(void);
+bool sev_active(void);
+
 #else  /* !CONFIG_AMD_MEM_ENCRYPT */
 
 #define sme_me_mask    0ULL
@@ -64,6 +70,14 @@ static inline void __init sme_early_init(void) { }
 static inline void __init sme_encrypt_kernel(void) { }
 static inline void __init sme_enable(struct boot_params *bp) { }
 
+static inline bool sme_active(void) { return false; }
+static inline bool sev_active(void) { return false; }
+
+static inline int __init
+early_set_memory_decrypted(unsigned long vaddr, unsigned long size) { return 0; }
+static inline int __init
+early_set_memory_encrypted(unsigned long vaddr, unsigned long size) { return 0; }
+
 #endif /* CONFIG_AMD_MEM_ENCRYPT */
 
 /*
index 6699fc441644197608290d18659bc8d389b501c4..6d16d15d09a0daed96a1e3d670b6203d1779b98e 100644 (file)
@@ -73,8 +73,8 @@ static inline void load_mm_ldt(struct mm_struct *mm)
 #ifdef CONFIG_MODIFY_LDT_SYSCALL
        struct ldt_struct *ldt;
 
-       /* lockless_dereference synchronizes with smp_store_release */
-       ldt = lockless_dereference(mm->context.ldt);
+       /* READ_ONCE synchronizes with smp_store_release */
+       ldt = READ_ONCE(mm->context.ldt);
 
        /*
         * Any change to mm->context.ldt is followed by an IPI to all
index 8546fafa21a913054908e92cfa1f268df17135a5..7948a17febb4b55958daef70dd64dfe20010892a 100644 (file)
@@ -6,7 +6,7 @@
 #include <asm/orc_types.h>
 
 struct mod_arch_specific {
-#ifdef CONFIG_ORC_UNWINDER
+#ifdef CONFIG_UNWINDER_ORC
        unsigned int num_orcs;
        int *orc_unwind_ip;
        struct orc_entry *orc_unwind;
index 9492893aec529085ff9f03dccfb107ed169ec0ed..a6bec802848065f5d7a5288f70d6b856ea70acbd 100644 (file)
@@ -59,7 +59,7 @@ struct mpc_table {
 #define        MP_TRANSLATION          192
 
 #define CPU_ENABLED            1       /* Processor is available */
-#define CPU_BOOTPROCESSOR      2       /* Processor is the BP */
+#define CPU_BOOTPROCESSOR      2       /* Processor is the boot CPU */
 
 #define CPU_STEPPING_MASK      0x000F
 #define CPU_MODEL_MASK         0x00F0
index ab022618a50af902ee2a5cecfe546e990a29b318..34c4922bbc3fb5ed95cb0819d7ac6b9cd37a7f41 100644 (file)
 #define MSR_AMD64_IBSBRTARGET          0xc001103b
 #define MSR_AMD64_IBSOPDATA4           0xc001103d
 #define MSR_AMD64_IBS_REG_COUNT_MAX    8 /* includes MSR_AMD64_IBSBRTARGET */
+#define MSR_AMD64_SEV                  0xc0010131
+#define MSR_AMD64_SEV_ENABLED_BIT      0
+#define MSR_AMD64_SEV_ENABLED          BIT_ULL(MSR_AMD64_SEV_ENABLED_BIT)
 
 /* Fam 17h MSRs */
 #define MSR_F17H_IRPERF                        0xc00000e9
index fd81228e8037fe29fd27d805ed3fb7e617a45606..283efcaac8aff86f2c004bc23e4b8642cbf3d527 100644 (file)
 #include <linux/cpumask.h>
 #include <asm/frame.h>
 
-static inline void load_sp0(struct tss_struct *tss,
-                            struct thread_struct *thread)
+static inline void load_sp0(unsigned long sp0)
 {
-       PVOP_VCALL2(pv_cpu_ops.load_sp0, tss, thread);
+       PVOP_VCALL1(pv_cpu_ops.load_sp0, sp0);
 }
 
 /* The paravirtualized CPUID instruction. */
index 10cc3b9709fe0b5afa9d6c1d5e316bef5315d8db..6ec54d01972dcf7d79e75bcfbecc84a1f2da80ea 100644 (file)
@@ -134,7 +134,7 @@ struct pv_cpu_ops {
        void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries);
        void (*free_ldt)(struct desc_struct *ldt, unsigned entries);
 
-       void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
+       void (*load_sp0)(unsigned long sp0);
 
        void (*set_iopl_mask)(unsigned mask);
 
index 377f1ffd18be672d3ea21d8097fbdcaa9913c6c7..ba3c523aaf1618fdf6dfb35ade4c643799deec29 100644 (file)
@@ -526,7 +526,7 @@ static inline bool x86_this_cpu_variable_test_bit(int nr,
 {
        bool oldbit;
 
-       asm volatile("bt "__percpu_arg(2)",%1\n\t"
+       asm volatile("bt "__percpu_arg(2)",%1"
                        CC_SET(c)
                        : CC_OUT(c) (oldbit)
                        : "m" (*(unsigned long __percpu *)addr), "Ir" (nr));
index 59df7b47a4349e22ba977e6350c2504634fa34e9..9e9b05fc4860e7b48770f9c9687a60f7bd768450 100644 (file)
@@ -200,10 +200,9 @@ enum page_cache_mode {
 
 #define _PAGE_ENC      (_AT(pteval_t, sme_me_mask))
 
-#define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER |        \
-                        _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_ENC)
 #define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED |    \
                         _PAGE_DIRTY | _PAGE_ENC)
+#define _PAGE_TABLE    (_KERNPG_TABLE | _PAGE_USER)
 
 #define __PAGE_KERNEL_ENC      (__PAGE_KERNEL | _PAGE_ENC)
 #define __PAGE_KERNEL_ENC_WP   (__PAGE_KERNEL_WP | _PAGE_ENC)
index bdac19ab24888fe53045b334ae568a49cc7721d4..2db7cf720b04b2d067df4f3138f2914de0e5cc0f 100644 (file)
@@ -431,7 +431,9 @@ typedef struct {
 struct thread_struct {
        /* Cached TLS descriptors: */
        struct desc_struct      tls_array[GDT_ENTRY_TLS_ENTRIES];
+#ifdef CONFIG_X86_32
        unsigned long           sp0;
+#endif
        unsigned long           sp;
 #ifdef CONFIG_X86_32
        unsigned long           sysenter_cs;
@@ -518,16 +520,9 @@ static inline void native_set_iopl_mask(unsigned mask)
 }
 
 static inline void
-native_load_sp0(struct tss_struct *tss, struct thread_struct *thread)
+native_load_sp0(unsigned long sp0)
 {
-       tss->x86_tss.sp0 = thread->sp0;
-#ifdef CONFIG_X86_32
-       /* Only happens when SEP is enabled, no need to test "SEP"arately: */
-       if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) {
-               tss->x86_tss.ss1 = thread->sysenter_cs;
-               wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
-       }
-#endif
+       this_cpu_write(cpu_tss.x86_tss.sp0, sp0);
 }
 
 static inline void native_swapgs(void)
@@ -547,15 +542,20 @@ static inline unsigned long current_top_of_stack(void)
 #endif
 }
 
+static inline bool on_thread_stack(void)
+{
+       return (unsigned long)(current_top_of_stack() -
+                              current_stack_pointer) < THREAD_SIZE;
+}
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
 #define __cpuid                        native_cpuid
 
-static inline void load_sp0(struct tss_struct *tss,
-                           struct thread_struct *thread)
+static inline void load_sp0(unsigned long sp0)
 {
-       native_load_sp0(tss, thread);
+       native_load_sp0(sp0);
 }
 
 #define set_iopl_mask native_set_iopl_mask
@@ -804,6 +804,15 @@ static inline void spin_lock_prefetch(const void *x)
 #define TOP_OF_INIT_STACK ((unsigned long)&init_stack + sizeof(init_stack) - \
                           TOP_OF_KERNEL_STACK_PADDING)
 
+#define task_top_of_stack(task) ((unsigned long)(task_pt_regs(task) + 1))
+
+#define task_pt_regs(task) \
+({                                                                     \
+       unsigned long __ptr = (unsigned long)task_stack_page(task);     \
+       __ptr += THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING;             \
+       ((struct pt_regs *)__ptr) - 1;                                  \
+})
+
 #ifdef CONFIG_X86_32
 /*
  * User space process size: 3GB (default).
@@ -823,23 +832,6 @@ static inline void spin_lock_prefetch(const void *x)
        .addr_limit             = KERNEL_DS,                              \
 }
 
-/*
- * TOP_OF_KERNEL_STACK_PADDING reserves 8 bytes on top of the ring0 stack.
- * This is necessary to guarantee that the entire "struct pt_regs"
- * is accessible even if the CPU haven't stored the SS/ESP registers
- * on the stack (interrupt gate does not save these registers
- * when switching to the same priv ring).
- * Therefore beware: accessing the ss/esp fields of the
- * "struct pt_regs" is possible, but they may contain the
- * completely wrong values.
- */
-#define task_pt_regs(task) \
-({                                                                     \
-       unsigned long __ptr = (unsigned long)task_stack_page(task);     \
-       __ptr += THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING;             \
-       ((struct pt_regs *)__ptr) - 1;                                  \
-})
-
 #define KSTK_ESP(task)         (task_pt_regs(task)->sp)
 
 #else
@@ -873,11 +865,9 @@ static inline void spin_lock_prefetch(const void *x)
 #define STACK_TOP_MAX          TASK_SIZE_MAX
 
 #define INIT_THREAD  {                                         \
-       .sp0                    = TOP_OF_INIT_STACK,            \
        .addr_limit             = KERNEL_DS,                    \
 }
 
-#define task_pt_regs(tsk)      ((struct pt_regs *)(tsk)->thread.sp0 - 1)
 extern unsigned long KSTK_ESP(struct task_struct *task);
 
 #endif /* CONFIG_X86_64 */
index c0e3c45cf6aba2a0f06c0e07a4642b9519364f03..14131dd06b290af1bc1c83967512149578e55950 100644 (file)
@@ -136,9 +136,9 @@ static inline int v8086_mode(struct pt_regs *regs)
 #endif
 }
 
-#ifdef CONFIG_X86_64
 static inline bool user_64bit_mode(struct pt_regs *regs)
 {
+#ifdef CONFIG_X86_64
 #ifndef CONFIG_PARAVIRT
        /*
         * On non-paravirt systems, this is the only long mode CPL 3
@@ -149,8 +149,12 @@ static inline bool user_64bit_mode(struct pt_regs *regs)
        /* Headers are too twisted for this to go in paravirt.h. */
        return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs;
 #endif
+#else /* !CONFIG_X86_64 */
+       return false;
+#endif
 }
 
+#ifdef CONFIG_X86_64
 #define current_user_stack_pointer()   current_pt_regs()->sp
 #define compat_user_stack_pointer()    current_pt_regs()->sp
 #endif
index 9982dd96f093c3e924447c9750274d922381f2af..5e16b5d40d32b7667fb49f8c697f2b2443484151 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_QSPINLOCK_H
 #define _ASM_X86_QSPINLOCK_H
 
+#include <linux/jump_label.h>
 #include <asm/cpufeature.h>
 #include <asm-generic/qspinlock_types.h>
 #include <asm/paravirt.h>
@@ -47,10 +48,14 @@ static inline void queued_spin_unlock(struct qspinlock *lock)
 #endif
 
 #ifdef CONFIG_PARAVIRT
+DECLARE_STATIC_KEY_TRUE(virt_spin_lock_key);
+
+void native_pv_lock_init(void) __init;
+
 #define virt_spin_lock virt_spin_lock
 static inline bool virt_spin_lock(struct qspinlock *lock)
 {
-       if (!static_cpu_has(X86_FEATURE_HYPERVISOR))
+       if (!static_branch_likely(&virt_spin_lock_key))
                return false;
 
        /*
@@ -66,6 +71,10 @@ static inline bool virt_spin_lock(struct qspinlock *lock)
 
        return true;
 }
+#else
+static inline void native_pv_lock_init(void)
+{
+}
 #endif /* CONFIG_PARAVIRT */
 
 #include <asm-generic/qspinlock.h>
index ff871210b9f2f3f73ff030fe820d7c665de948b1..4e44250e7d0d75c6db385dbf151583b31d3e8c19 100644 (file)
@@ -15,7 +15,7 @@
  * back to the regular execution flow in .text.
  */
 #define _REFCOUNT_EXCEPTION                            \
-       ".pushsection .text.unlikely\n"                 \
+       ".pushsection .text..refcount\n"                \
        "111:\tlea %[counter], %%" _ASM_CX "\n"         \
        "112:\t" ASM_UD0 "\n"                           \
        ASM_UNREACHABLE                                 \
index d8f3a6ae9f6c98e4461a3d34a13e36531c82ac10..f91c365e57c36d2454806ff21a2d336dae5c6863 100644 (file)
@@ -29,7 +29,7 @@ cc_label:                                                             \
 #define __GEN_RMWcc(fullop, var, cc, clobbers, ...)                    \
 do {                                                                   \
        bool c;                                                         \
-       asm volatile (fullop ";" CC_SET(cc)                             \
+       asm volatile (fullop CC_SET(cc)                                 \
                        : [counter] "+m" (var), CC_OUT(cc) (c)          \
                        : __VA_ARGS__ : clobbers);                      \
        return c;                                                       \
index 4d38d85a16ada01ef65671cb47c220d268fa69a0..4c25cf6caefa1b64e732a6c1d5d7a6636ebd6a62 100644 (file)
 /*
  * lock for reading
  */
+#define ____down_read(sem, slow_path)                                  \
+({                                                                     \
+       struct rw_semaphore* ret;                                       \
+       asm volatile("# beginning down_read\n\t"                        \
+                    LOCK_PREFIX _ASM_INC "(%[sem])\n\t"                \
+                    /* adds 0x00000001 */                              \
+                    "  jns        1f\n"                                \
+                    "  call " slow_path "\n"                           \
+                    "1:\n\t"                                           \
+                    "# ending down_read\n\t"                           \
+                    : "+m" (sem->count), "=a" (ret),                   \
+                       ASM_CALL_CONSTRAINT                             \
+                    : [sem] "a" (sem)                                  \
+                    : "memory", "cc");                                 \
+       ret;                                                            \
+})
+
 static inline void __down_read(struct rw_semaphore *sem)
 {
-       asm volatile("# beginning down_read\n\t"
-                    LOCK_PREFIX _ASM_INC "(%1)\n\t"
-                    /* adds 0x00000001 */
-                    "  jns        1f\n"
-                    "  call call_rwsem_down_read_failed\n"
-                    "1:\n\t"
-                    "# ending down_read\n\t"
-                    : "+m" (sem->count)
-                    : "a" (sem)
-                    : "memory", "cc");
+       ____down_read(sem, "call_rwsem_down_read_failed");
+}
+
+static inline int __down_read_killable(struct rw_semaphore *sem)
+{
+       if (IS_ERR(____down_read(sem, "call_rwsem_down_read_failed_killable")))
+               return -EINTR;
+       return 0;
 }
 
 /*
@@ -82,17 +97,18 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
 {
        long result, tmp;
        asm volatile("# beginning __down_read_trylock\n\t"
-                    "  mov          %0,%1\n\t"
+                    "  mov          %[count],%[result]\n\t"
                     "1:\n\t"
-                    "  mov          %1,%2\n\t"
-                    "  add          %3,%2\n\t"
+                    "  mov          %[result],%[tmp]\n\t"
+                    "  add          %[inc],%[tmp]\n\t"
                     "  jle          2f\n\t"
-                    LOCK_PREFIX "  cmpxchg  %2,%0\n\t"
+                    LOCK_PREFIX "  cmpxchg  %[tmp],%[count]\n\t"
                     "  jnz          1b\n\t"
                     "2:\n\t"
                     "# ending __down_read_trylock\n\t"
-                    : "+m" (sem->count), "=&a" (result), "=&r" (tmp)
-                    : "i" (RWSEM_ACTIVE_READ_BIAS)
+                    : [count] "+m" (sem->count), [result] "=&a" (result),
+                      [tmp] "=&r" (tmp)
+                    : [inc] "i" (RWSEM_ACTIVE_READ_BIAS)
                     : "memory", "cc");
        return result >= 0;
 }
@@ -106,7 +122,7 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
        struct rw_semaphore* ret;                       \
                                                        \
        asm volatile("# beginning down_write\n\t"       \
-                    LOCK_PREFIX "  xadd      %1,(%4)\n\t"      \
+                    LOCK_PREFIX "  xadd      %[tmp],(%[sem])\n\t"      \
                     /* adds 0xffff0001, returns the old value */ \
                     "  test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
                     /* was the active mask 0 before? */\
@@ -114,9 +130,9 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
                     "  call " slow_path "\n"           \
                     "1:\n"                             \
                     "# ending down_write"              \
-                    : "+m" (sem->count), "=d" (tmp),   \
+                    : "+m" (sem->count), [tmp] "=d" (tmp),     \
                       "=a" (ret), ASM_CALL_CONSTRAINT  \
-                    : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
+                    : [sem] "a" (sem), "[tmp]" (RWSEM_ACTIVE_WRITE_BIAS) \
                     : "memory", "cc");                 \
        ret;                                            \
 })
@@ -142,21 +158,21 @@ static inline bool __down_write_trylock(struct rw_semaphore *sem)
        bool result;
        long tmp0, tmp1;
        asm volatile("# beginning __down_write_trylock\n\t"
-                    "  mov          %0,%1\n\t"
+                    "  mov          %[count],%[tmp0]\n\t"
                     "1:\n\t"
                     "  test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t"
                     /* was the active mask 0 before? */
                     "  jnz          2f\n\t"
-                    "  mov          %1,%2\n\t"
-                    "  add          %4,%2\n\t"
-                    LOCK_PREFIX "  cmpxchg  %2,%0\n\t"
+                    "  mov          %[tmp0],%[tmp1]\n\t"
+                    "  add          %[inc],%[tmp1]\n\t"
+                    LOCK_PREFIX "  cmpxchg  %[tmp1],%[count]\n\t"
                     "  jnz          1b\n\t"
                     "2:\n\t"
                     CC_SET(e)
                     "# ending __down_write_trylock\n\t"
-                    : "+m" (sem->count), "=&a" (tmp0), "=&r" (tmp1),
-                      CC_OUT(e) (result)
-                    : "er" (RWSEM_ACTIVE_WRITE_BIAS)
+                    : [count] "+m" (sem->count), [tmp0] "=&a" (tmp0),
+                      [tmp1] "=&r" (tmp1), CC_OUT(e) (result)
+                    : [inc] "er" (RWSEM_ACTIVE_WRITE_BIAS)
                     : "memory");
        return result;
 }
@@ -168,14 +184,14 @@ static inline void __up_read(struct rw_semaphore *sem)
 {
        long tmp;
        asm volatile("# beginning __up_read\n\t"
-                    LOCK_PREFIX "  xadd      %1,(%2)\n\t"
+                    LOCK_PREFIX "  xadd      %[tmp],(%[sem])\n\t"
                     /* subtracts 1, returns the old value */
                     "  jns        1f\n\t"
                     "  call call_rwsem_wake\n" /* expects old value in %edx */
                     "1:\n"
                     "# ending __up_read\n"
-                    : "+m" (sem->count), "=d" (tmp)
-                    : "a" (sem), "1" (-RWSEM_ACTIVE_READ_BIAS)
+                    : "+m" (sem->count), [tmp] "=d" (tmp)
+                    : [sem] "a" (sem), "[tmp]" (-RWSEM_ACTIVE_READ_BIAS)
                     : "memory", "cc");
 }
 
@@ -186,14 +202,14 @@ static inline void __up_write(struct rw_semaphore *sem)
 {
        long tmp;
        asm volatile("# beginning __up_write\n\t"
-                    LOCK_PREFIX "  xadd      %1,(%2)\n\t"
+                    LOCK_PREFIX "  xadd      %[tmp],(%[sem])\n\t"
                     /* subtracts 0xffff0001, returns the old value */
                     "  jns        1f\n\t"
                     "  call call_rwsem_wake\n" /* expects old value in %edx */
                     "1:\n\t"
                     "# ending __up_write\n"
-                    : "+m" (sem->count), "=d" (tmp)
-                    : "a" (sem), "1" (-RWSEM_ACTIVE_WRITE_BIAS)
+                    : "+m" (sem->count), [tmp] "=d" (tmp)
+                    : [sem] "a" (sem), "[tmp]" (-RWSEM_ACTIVE_WRITE_BIAS)
                     : "memory", "cc");
 }
 
@@ -203,7 +219,7 @@ static inline void __up_write(struct rw_semaphore *sem)
 static inline void __downgrade_write(struct rw_semaphore *sem)
 {
        asm volatile("# beginning __downgrade_write\n\t"
-                    LOCK_PREFIX _ASM_ADD "%2,(%1)\n\t"
+                    LOCK_PREFIX _ASM_ADD "%[inc],(%[sem])\n\t"
                     /*
                      * transitions 0xZZZZ0001 -> 0xYYYY0001 (i386)
                      *     0xZZZZZZZZ00000001 -> 0xYYYYYYYY00000001 (x86_64)
@@ -213,7 +229,7 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
                     "1:\n\t"
                     "# ending __downgrade_write\n"
                     : "+m" (sem->count)
-                    : "a" (sem), "er" (-RWSEM_WAITING_BIAS)
+                    : [sem] "a" (sem), [inc] "er" (-RWSEM_WAITING_BIAS)
                     : "memory", "cc");
 }
 
index b34625796eb2cf1f6d067a13e2a1f128e2fbb376..5b6bc7016c223e7496fc2645ae8b3434ef83b96b 100644 (file)
 
 #include <asm/qrwlock.h>
 
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* _ASM_X86_SPINLOCK_H */
index 899084b70412ebe1e11fbc0ebc0a80624caf520d..8c6bd6863db9d6b737cd0649324c154f9b9798a3 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_X86_SWITCH_TO_H
 #define _ASM_X86_SWITCH_TO_H
 
+#include <linux/sched/task_stack.h>
+
 struct task_struct; /* one of the stranger aspects of C forward declarations */
 
 struct task_struct *__switch_to_asm(struct task_struct *prev,
@@ -73,4 +75,26 @@ do {                                                                 \
        ((last) = __switch_to_asm((prev), (next)));                     \
 } while (0)
 
+#ifdef CONFIG_X86_32
+static inline void refresh_sysenter_cs(struct thread_struct *thread)
+{
+       /* Only happens when SEP is enabled, no need to test "SEP"arately: */
+       if (unlikely(this_cpu_read(cpu_tss.x86_tss.ss1) == thread->sysenter_cs))
+               return;
+
+       this_cpu_write(cpu_tss.x86_tss.ss1, thread->sysenter_cs);
+       wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
+}
+#endif
+
+/* This is used when switching tasks or entering/exiting vm86 mode. */
+static inline void update_sp0(struct task_struct *task)
+{
+#ifdef CONFIG_X86_32
+       load_sp0(task->thread.sp0);
+#else
+       load_sp0(task_top_of_stack(task));
+#endif
+}
+
 #endif /* _ASM_X86_SWITCH_TO_H */
index 91dfcafe27a662cba41d162bf374d9632961406e..bad25bb80679fe79cec042a0644d1205db5498fc 100644 (file)
@@ -21,7 +21,7 @@ asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
 asmlinkage long sys_iopl(unsigned int);
 
 /* kernel/ldt.c */
-asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
+asmlinkage long sys_modify_ldt(int, void __user *, unsigned long);
 
 /* kernel/signal.c */
 asmlinkage long sys_rt_sigreturn(void);
index 47457ab975fdb36bed1e5146eaddd2e4c83f6f49..7365dd4acffb654d4c2ab3f15a9f85ee3f0c35f0 100644 (file)
@@ -9,7 +9,7 @@
 #define TICK_SIZE (tick_nsec / 1000)
 
 unsigned long long native_sched_clock(void);
-extern int recalibrate_cpu_khz(void);
+extern void recalibrate_cpu_khz(void);
 
 extern int no_timer_check;
 
index fa60398bbc3acec91ed804d5d50d9fbcb1fa01be..069c04be15076075757522e24b27251e68d9be41 100644 (file)
@@ -34,11 +34,6 @@ DECLARE_EVENT_CLASS(x86_fpu,
        )
 );
 
-DEFINE_EVENT(x86_fpu, x86_fpu_state,
-       TP_PROTO(struct fpu *fpu),
-       TP_ARGS(fpu)
-);
-
 DEFINE_EVENT(x86_fpu, x86_fpu_before_save,
        TP_PROTO(struct fpu *fpu),
        TP_ARGS(fpu)
@@ -74,11 +69,6 @@ DEFINE_EVENT(x86_fpu, x86_fpu_activate_state,
        TP_ARGS(fpu)
 );
 
-DEFINE_EVENT(x86_fpu, x86_fpu_deactivate_state,
-       TP_PROTO(struct fpu *fpu),
-       TP_ARGS(fpu)
-);
-
 DEFINE_EVENT(x86_fpu, x86_fpu_init_state,
        TP_PROTO(struct fpu *fpu),
        TP_ARGS(fpu)
index 8eb139ed1a03bec70322b72502e518a2cc3ccf1e..84b9ec0c1bc0867795c3a2d327f3b8831bf4f8ba 100644 (file)
@@ -138,6 +138,254 @@ DEFINE_IRQ_VECTOR_EVENT(deferred_error_apic);
 DEFINE_IRQ_VECTOR_EVENT(thermal_apic);
 #endif
 
+TRACE_EVENT(vector_config,
+
+       TP_PROTO(unsigned int irq, unsigned int vector,
+                unsigned int cpu, unsigned int apicdest),
+
+       TP_ARGS(irq, vector, cpu, apicdest),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq             )
+               __field(        unsigned int,   vector          )
+               __field(        unsigned int,   cpu             )
+               __field(        unsigned int,   apicdest        )
+       ),
+
+       TP_fast_assign(
+               __entry->irq            = irq;
+               __entry->vector         = vector;
+               __entry->cpu            = cpu;
+               __entry->apicdest       = apicdest;
+       ),
+
+       TP_printk("irq=%u vector=%u cpu=%u apicdest=0x%08x",
+                 __entry->irq, __entry->vector, __entry->cpu,
+                 __entry->apicdest)
+);
+
+DECLARE_EVENT_CLASS(vector_mod,
+
+       TP_PROTO(unsigned int irq, unsigned int vector,
+                unsigned int cpu, unsigned int prev_vector,
+                unsigned int prev_cpu),
+
+       TP_ARGS(irq, vector, cpu, prev_vector, prev_cpu),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq             )
+               __field(        unsigned int,   vector          )
+               __field(        unsigned int,   cpu             )
+               __field(        unsigned int,   prev_vector     )
+               __field(        unsigned int,   prev_cpu        )
+       ),
+
+       TP_fast_assign(
+               __entry->irq            = irq;
+               __entry->vector         = vector;
+               __entry->cpu            = cpu;
+               __entry->prev_vector    = prev_vector;
+               __entry->prev_cpu       = prev_cpu;
+
+       ),
+
+       TP_printk("irq=%u vector=%u cpu=%u prev_vector=%u prev_cpu=%u",
+                 __entry->irq, __entry->vector, __entry->cpu,
+                 __entry->prev_vector, __entry->prev_cpu)
+);
+
+#define DEFINE_IRQ_VECTOR_MOD_EVENT(name)                              \
+DEFINE_EVENT_FN(vector_mod, name,                                      \
+       TP_PROTO(unsigned int irq, unsigned int vector,                 \
+                unsigned int cpu, unsigned int prev_vector,            \
+                unsigned int prev_cpu),                                \
+       TP_ARGS(irq, vector, cpu, prev_vector, prev_cpu), NULL, NULL);  \
+
+DEFINE_IRQ_VECTOR_MOD_EVENT(vector_update);
+DEFINE_IRQ_VECTOR_MOD_EVENT(vector_clear);
+
+DECLARE_EVENT_CLASS(vector_reserve,
+
+       TP_PROTO(unsigned int irq, int ret),
+
+       TP_ARGS(irq, ret),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq     )
+               __field(        int,            ret     )
+       ),
+
+       TP_fast_assign(
+               __entry->irq = irq;
+               __entry->ret = ret;
+       ),
+
+       TP_printk("irq=%u ret=%d", __entry->irq, __entry->ret)
+);
+
+#define DEFINE_IRQ_VECTOR_RESERVE_EVENT(name)  \
+DEFINE_EVENT_FN(vector_reserve, name,  \
+       TP_PROTO(unsigned int irq, int ret),    \
+       TP_ARGS(irq, ret), NULL, NULL);         \
+
+DEFINE_IRQ_VECTOR_RESERVE_EVENT(vector_reserve_managed);
+DEFINE_IRQ_VECTOR_RESERVE_EVENT(vector_reserve);
+
+TRACE_EVENT(vector_alloc,
+
+       TP_PROTO(unsigned int irq, unsigned int vector, bool reserved,
+                int ret),
+
+       TP_ARGS(irq, vector, ret, reserved),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq             )
+               __field(        unsigned int,   vector          )
+               __field(        bool,           reserved        )
+               __field(        int,            ret             )
+       ),
+
+       TP_fast_assign(
+               __entry->irq            = irq;
+               __entry->vector         = ret < 0 ? 0 : vector;
+               __entry->reserved       = reserved;
+               __entry->ret            = ret > 0 ? 0 : ret;
+       ),
+
+       TP_printk("irq=%u vector=%u reserved=%d ret=%d",
+                 __entry->irq, __entry->vector,
+                 __entry->reserved, __entry->ret)
+);
+
+TRACE_EVENT(vector_alloc_managed,
+
+       TP_PROTO(unsigned int irq, unsigned int vector,
+                int ret),
+
+       TP_ARGS(irq, vector, ret),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq             )
+               __field(        unsigned int,   vector          )
+               __field(        int,            ret             )
+       ),
+
+       TP_fast_assign(
+               __entry->irq            = irq;
+               __entry->vector         = ret < 0 ? 0 : vector;
+               __entry->ret            = ret > 0 ? 0 : ret;
+       ),
+
+       TP_printk("irq=%u vector=%u ret=%d",
+                 __entry->irq, __entry->vector, __entry->ret)
+);
+
+DECLARE_EVENT_CLASS(vector_activate,
+
+       TP_PROTO(unsigned int irq, bool is_managed, bool can_reserve,
+                bool early),
+
+       TP_ARGS(irq, is_managed, can_reserve, early),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq             )
+               __field(        bool,           is_managed      )
+               __field(        bool,           can_reserve     )
+               __field(        bool,           early           )
+       ),
+
+       TP_fast_assign(
+               __entry->irq            = irq;
+               __entry->is_managed     = is_managed;
+               __entry->can_reserve    = can_reserve;
+               __entry->early          = early;
+       ),
+
+       TP_printk("irq=%u is_managed=%d can_reserve=%d early=%d",
+                 __entry->irq, __entry->is_managed, __entry->can_reserve,
+                 __entry->early)
+);
+
+#define DEFINE_IRQ_VECTOR_ACTIVATE_EVENT(name)                         \
+DEFINE_EVENT_FN(vector_activate, name,                                 \
+       TP_PROTO(unsigned int irq, bool is_managed,                     \
+                bool can_reserve, bool early),                         \
+       TP_ARGS(irq, is_managed, can_reserve, early), NULL, NULL);      \
+
+DEFINE_IRQ_VECTOR_ACTIVATE_EVENT(vector_activate);
+DEFINE_IRQ_VECTOR_ACTIVATE_EVENT(vector_deactivate);
+
+TRACE_EVENT(vector_teardown,
+
+       TP_PROTO(unsigned int irq, bool is_managed, bool has_reserved),
+
+       TP_ARGS(irq, is_managed, has_reserved),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq             )
+               __field(        bool,           is_managed      )
+               __field(        bool,           has_reserved    )
+       ),
+
+       TP_fast_assign(
+               __entry->irq            = irq;
+               __entry->is_managed     = is_managed;
+               __entry->has_reserved   = has_reserved;
+       ),
+
+       TP_printk("irq=%u is_managed=%d has_reserved=%d",
+                 __entry->irq, __entry->is_managed, __entry->has_reserved)
+);
+
+TRACE_EVENT(vector_setup,
+
+       TP_PROTO(unsigned int irq, bool is_legacy, int ret),
+
+       TP_ARGS(irq, is_legacy, ret),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq             )
+               __field(        bool,           is_legacy       )
+               __field(        int,            ret             )
+       ),
+
+       TP_fast_assign(
+               __entry->irq            = irq;
+               __entry->is_legacy      = is_legacy;
+               __entry->ret            = ret;
+       ),
+
+       TP_printk("irq=%u is_legacy=%d ret=%d",
+                 __entry->irq, __entry->is_legacy, __entry->ret)
+);
+
+TRACE_EVENT(vector_free_moved,
+
+       TP_PROTO(unsigned int irq, unsigned int cpu, unsigned int vector,
+                bool is_managed),
+
+       TP_ARGS(irq, cpu, vector, is_managed),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   irq             )
+               __field(        unsigned int,   cpu             )
+               __field(        unsigned int,   vector          )
+               __field(        bool,           is_managed      )
+       ),
+
+       TP_fast_assign(
+               __entry->irq            = irq;
+               __entry->cpu            = cpu;
+               __entry->vector         = vector;
+               __entry->is_managed     = is_managed;
+       ),
+
+       TP_printk("irq=%u cpu=%u vector=%u is_managed=%d",
+                 __entry->irq, __entry->cpu, __entry->vector,
+                 __entry->is_managed)
+);
+
+
 #endif /* CONFIG_X86_LOCAL_APIC */
 
 #undef TRACE_INCLUDE_PATH
index b0cced97a6ce9b335cc17b41f7c60d0bfa9687ed..1fadd310ff680ece697fa65a8db410c380a8547e 100644 (file)
@@ -38,9 +38,9 @@ asmlinkage void simd_coprocessor_error(void);
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV)
 asmlinkage void xen_divide_error(void);
+asmlinkage void xen_xennmi(void);
 asmlinkage void xen_xendebug(void);
 asmlinkage void xen_xenint3(void);
-asmlinkage void xen_nmi(void);
 asmlinkage void xen_overflow(void);
 asmlinkage void xen_bounds(void);
 asmlinkage void xen_invalid_op(void);
@@ -145,4 +145,22 @@ enum {
        X86_TRAP_IRET = 32,     /* 32, IRET Exception */
 };
 
+/*
+ * Page fault error code bits:
+ *
+ *   bit 0 ==   0: no page found       1: protection fault
+ *   bit 1 ==   0: read access         1: write access
+ *   bit 2 ==   0: kernel-mode access  1: user-mode access
+ *   bit 3 ==                          1: use of reserved bit detected
+ *   bit 4 ==                          1: fault was an instruction fetch
+ *   bit 5 ==                          1: protection keys block access
+ */
+enum x86_pf_error_code {
+       X86_PF_PROT     =               1 << 0,
+       X86_PF_WRITE    =               1 << 1,
+       X86_PF_USER     =               1 << 2,
+       X86_PF_RSVD     =               1 << 3,
+       X86_PF_INSTR    =               1 << 4,
+       X86_PF_PK       =               1 << 5,
+};
 #endif /* _ASM_X86_TRAPS_H */
index 8da0efb13544dc0ed2149a8eba7720de6089a88a..cf5d53c3f9ea32434a5b0d614bad97a4ed4dd926 100644 (file)
@@ -32,15 +32,22 @@ static inline cycles_t get_cycles(void)
 
 extern struct system_counterval_t convert_art_to_tsc(u64 art);
 
+extern void tsc_early_delay_calibrate(void);
 extern void tsc_init(void);
 extern void mark_tsc_unstable(char *reason);
 extern int unsynchronized_tsc(void);
 extern int check_tsc_unstable(void);
+extern void mark_tsc_async_resets(char *reason);
 extern unsigned long native_calibrate_cpu(void);
 extern unsigned long native_calibrate_tsc(void);
 extern unsigned long long native_sched_clock_from_tsc(u64 tsc);
 
 extern int tsc_clocksource_reliable;
+#ifdef CONFIG_X86_TSC
+extern bool tsc_async_resets;
+#else
+# define tsc_async_resets      false
+#endif
 
 /*
  * Boot-time check whether the TSCs are synchronized across
diff --git a/arch/x86/include/asm/umip.h b/arch/x86/include/asm/umip.h
new file mode 100644 (file)
index 0000000..db43f2a
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _ASM_X86_UMIP_H
+#define _ASM_X86_UMIP_H
+
+#include <linux/types.h>
+#include <asm/ptrace.h>
+
+#ifdef CONFIG_X86_INTEL_UMIP
+bool fixup_umip_exception(struct pt_regs *regs);
+#else
+static inline bool fixup_umip_exception(struct pt_regs *regs) { return false; }
+#endif  /* CONFIG_X86_INTEL_UMIP */
+#endif  /* _ASM_X86_UMIP_H */
index 87adc0d38c4aa913b59820606e40a33b8edc9e8e..e9cc6fe1fc6f953c38ddcc61fcf06fd90d72ab04 100644 (file)
@@ -13,11 +13,11 @@ struct unwind_state {
        struct task_struct *task;
        int graph_idx;
        bool error;
-#if defined(CONFIG_ORC_UNWINDER)
+#if defined(CONFIG_UNWINDER_ORC)
        bool signal, full_regs;
        unsigned long sp, bp, ip;
        struct pt_regs *regs;
-#elif defined(CONFIG_FRAME_POINTER_UNWINDER)
+#elif defined(CONFIG_UNWINDER_FRAME_POINTER)
        bool got_irq;
        unsigned long *bp, *orig_sp, ip;
        struct pt_regs *regs;
@@ -51,7 +51,7 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
        __unwind_start(state, task, regs, first_frame);
 }
 
-#if defined(CONFIG_ORC_UNWINDER) || defined(CONFIG_FRAME_POINTER_UNWINDER)
+#if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
 static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
 {
        if (unwind_done(state))
@@ -66,7 +66,7 @@ static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
 }
 #endif
 
-#ifdef CONFIG_ORC_UNWINDER
+#ifdef CONFIG_UNWINDER_ORC
 void unwind_init(void);
 void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size,
                        void *orc, size_t orc_size);
index 9cffb44a3cf5dfedb122c7b31c2f690177e68604..036e26d63d9a020fbbfd775ac3248a4625fae276 100644 (file)
@@ -776,23 +776,36 @@ static inline int uv_num_possible_blades(void)
 extern void uv_nmi_setup(void);
 extern void uv_nmi_setup_hubless(void);
 
+/* BIOS/Kernel flags exchange MMR */
+#define UVH_BIOS_KERNEL_MMR            UVH_SCRATCH5
+#define UVH_BIOS_KERNEL_MMR_ALIAS      UVH_SCRATCH5_ALIAS
+#define UVH_BIOS_KERNEL_MMR_ALIAS_2    UVH_SCRATCH5_ALIAS_2
+
+/* TSC sync valid, set by BIOS */
+#define UVH_TSC_SYNC_MMR       UVH_BIOS_KERNEL_MMR
+#define UVH_TSC_SYNC_SHIFT     10
+#define UVH_TSC_SYNC_SHIFT_UV2K        16      /* UV2/3k have different bits */
+#define UVH_TSC_SYNC_MASK      3       /* 0011 */
+#define UVH_TSC_SYNC_VALID     3       /* 0011 */
+#define UVH_TSC_SYNC_INVALID   2       /* 0010 */
+
 /* BMC sets a bit this MMR non-zero before sending an NMI */
-#define UVH_NMI_MMR            UVH_SCRATCH5
-#define UVH_NMI_MMR_CLEAR      UVH_SCRATCH5_ALIAS
+#define UVH_NMI_MMR            UVH_BIOS_KERNEL_MMR
+#define UVH_NMI_MMR_CLEAR      UVH_BIOS_KERNEL_MMR_ALIAS
 #define UVH_NMI_MMR_SHIFT      63
-#define        UVH_NMI_MMR_TYPE        "SCRATCH5"
+#define UVH_NMI_MMR_TYPE       "SCRATCH5"
 
 /* Newer SMM NMI handler, not present in all systems */
 #define UVH_NMI_MMRX           UVH_EVENT_OCCURRED0
 #define UVH_NMI_MMRX_CLEAR     UVH_EVENT_OCCURRED0_ALIAS
 #define UVH_NMI_MMRX_SHIFT     UVH_EVENT_OCCURRED0_EXTIO_INT0_SHFT
-#define        UVH_NMI_MMRX_TYPE       "EXTIO_INT0"
+#define UVH_NMI_MMRX_TYPE      "EXTIO_INT0"
 
 /* Non-zero indicates newer SMM NMI handler present */
 #define UVH_NMI_MMRX_SUPPORTED UVH_EXTIO_INT0_BROADCAST
 
 /* Indicates to BIOS that we want to use the newer SMM NMI handler */
-#define UVH_NMI_MMRX_REQ       UVH_SCRATCH5_ALIAS_2
+#define UVH_NMI_MMRX_REQ       UVH_BIOS_KERNEL_MMR_ALIAS_2
 #define UVH_NMI_MMRX_REQ_SHIFT 62
 
 struct uv_hub_nmi_s {
index 52250681f68c7410b30f42d9e424553aaed4f313..fb856c9f04494b6633d9ea8fd3ebb9204cc2c620 100644 (file)
@@ -49,7 +49,7 @@ static inline unsigned gtod_read_begin(const struct vsyscall_gtod_data *s)
        unsigned ret;
 
 repeat:
-       ret = ACCESS_ONCE(s->seq);
+       ret = READ_ONCE(s->seq);
        if (unlikely(ret & 1)) {
                cpu_relax();
                goto repeat;
diff --git a/arch/x86/include/asm/x2apic.h b/arch/x86/include/asm/x2apic.h
deleted file mode 100644 (file)
index 78ccf28..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Common bits for X2APIC cluster/physical modes.
- */
-
-#ifndef _ASM_X86_X2APIC_H
-#define _ASM_X86_X2APIC_H
-
-#include <asm/apic.h>
-#include <asm/ipi.h>
-#include <linux/cpumask.h>
-
-static int x2apic_apic_id_valid(int apicid)
-{
-       return 1;
-}
-
-static int x2apic_apic_id_registered(void)
-{
-       return 1;
-}
-
-static void
-__x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest)
-{
-       unsigned long cfg = __prepare_ICR(0, vector, dest);
-       native_x2apic_icr_write(cfg, apicid);
-}
-
-static unsigned int x2apic_get_apic_id(unsigned long id)
-{
-       return id;
-}
-
-static unsigned long x2apic_set_apic_id(unsigned int id)
-{
-       return id;
-}
-
-static int x2apic_phys_pkg_id(int initial_apicid, int index_msb)
-{
-       return initial_apicid >> index_msb;
-}
-
-static void x2apic_send_IPI_self(int vector)
-{
-       apic_write(APIC_SELF_IPI, vector);
-}
-
-#endif /* _ASM_X86_X2APIC_H */
index 8a1ebf9540ddf0822c3f80c2fa09340c339860f7..aa4747569e23b63ea9cb83912bb6960caa8525cc 100644 (file)
@@ -51,11 +51,13 @@ struct x86_init_resources {
  *                             are set up.
  * @intr_init:                 interrupt init code
  * @trap_init:                 platform specific trap setup
+ * @intr_mode_init:            interrupt delivery mode setup
  */
 struct x86_init_irqs {
        void (*pre_vector_init)(void);
        void (*intr_init)(void);
        void (*trap_init)(void);
+       void (*intr_mode_init)(void);
 };
 
 /**
@@ -114,6 +116,20 @@ struct x86_init_pci {
        void (*fixup_irqs)(void);
 };
 
+/**
+ * struct x86_hyper_init - x86 hypervisor init functions
+ * @init_platform:             platform setup
+ * @guest_late_init:           guest late init
+ * @x2apic_available:          X2APIC detection
+ * @init_mem_mapping:          setup early mappings during init_mem_mapping()
+ */
+struct x86_hyper_init {
+       void (*init_platform)(void);
+       void (*guest_late_init)(void);
+       bool (*x2apic_available)(void);
+       void (*init_mem_mapping)(void);
+};
+
 /**
  * struct x86_init_ops - functions for platform specific setup
  *
@@ -127,6 +143,7 @@ struct x86_init_ops {
        struct x86_init_timers          timers;
        struct x86_init_iommu           iommu;
        struct x86_init_pci             pci;
+       struct x86_hyper_init           hyper;
 };
 
 /**
@@ -195,10 +212,20 @@ enum x86_legacy_i8042_state {
 struct x86_legacy_features {
        enum x86_legacy_i8042_state i8042;
        int rtc;
+       int no_vga;
        int reserve_bios_regions;
        struct x86_legacy_devices devices;
 };
 
+/**
+ * struct x86_hyper_runtime - x86 hypervisor specific runtime callbacks
+ *
+ * @pin_vcpu:          pin current vcpu to specified physical cpu (run rarely)
+ */
+struct x86_hyper_runtime {
+       void (*pin_vcpu)(int cpu);
+};
+
 /**
  * struct x86_platform_ops - platform specific runtime functions
  * @calibrate_cpu:             calibrate CPU
@@ -218,6 +245,7 @@ struct x86_legacy_features {
  *                             possible in x86_early_init_platform_quirks() by
  *                             only using the current x86_hardware_subarch
  *                             semantics.
+ * @hyper:                     x86 hypervisor specific runtime callbacks
  */
 struct x86_platform_ops {
        unsigned long (*calibrate_cpu)(void);
@@ -233,6 +261,7 @@ struct x86_platform_ops {
        void (*apic_post_init)(void);
        struct x86_legacy_features legacy;
        void (*set_legacy_features)(void);
+       struct x86_hyper_runtime hyper;
 };
 
 struct pci_dev;
index 554aa8f24f9167fe8ecc683384bce290fd4042dc..09cc06483bed426ba4e487067258d1016059aba4 100644 (file)
@@ -110,5 +110,4 @@ struct kvm_vcpu_pv_apf_data {
 #define KVM_PV_EOI_ENABLED KVM_PV_EOI_MASK
 #define KVM_PV_EOI_DISABLED 0x0
 
-
 #endif /* _UAPI_ASM_X86_KVM_PARA_H */
index 6f335539966500b11311d2a0a5c4dd5f3c315eab..7e1e730396ae08f5a267adaccf0c3ba46448f780 100644 (file)
 #define X86_CR4_OSFXSR         _BITUL(X86_CR4_OSFXSR_BIT)
 #define X86_CR4_OSXMMEXCPT_BIT 10 /* enable unmasked SSE exceptions */
 #define X86_CR4_OSXMMEXCPT     _BITUL(X86_CR4_OSXMMEXCPT_BIT)
+#define X86_CR4_UMIP_BIT       11 /* enable UMIP support */
+#define X86_CR4_UMIP           _BITUL(X86_CR4_UMIP_BIT)
 #define X86_CR4_LA57_BIT       12 /* enable 5-level page tables */
 #define X86_CR4_LA57           _BITUL(X86_CR4_LA57_BIT)
 #define X86_CR4_VMXE_BIT       13 /* enable VMX virtualization */
 #define CX86_ARR_BASE  0xc4
 #define CX86_RCR_BASE  0xdc
 
+#define CR0_STATE      (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
+                        X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
+                        X86_CR0_PG)
 
 #endif /* _UAPI_ASM_X86_PROCESSOR_FLAGS_H */
index 5f70044340ff1c6a379691c3d9ad6f5959c34bed..81bb565f449740c1d94e057c541db3c84df8bc46 100644 (file)
@@ -25,9 +25,9 @@ endif
 KASAN_SANITIZE_head$(BITS).o                           := n
 KASAN_SANITIZE_dumpstack.o                             := n
 KASAN_SANITIZE_dumpstack_$(BITS).o                     := n
-KASAN_SANITIZE_stacktrace.o := n
+KASAN_SANITIZE_stacktrace.o                            := n
+KASAN_SANITIZE_paravirt.o                              := n
 
-OBJECT_FILES_NON_STANDARD_head_$(BITS).o               := y
 OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o    := y
 OBJECT_FILES_NON_STANDARD_ftrace_$(BITS).o             := y
 OBJECT_FILES_NON_STANDARD_test_nx.o                    := y
@@ -127,10 +127,11 @@ obj-$(CONFIG_EFI)                 += sysfb_efi.o
 obj-$(CONFIG_PERF_EVENTS)              += perf_regs.o
 obj-$(CONFIG_TRACING)                  += tracepoint.o
 obj-$(CONFIG_SCHED_MC_PRIO)            += itmt.o
+obj-$(CONFIG_X86_INTEL_UMIP)           += umip.o
 
-obj-$(CONFIG_ORC_UNWINDER)             += unwind_orc.o
-obj-$(CONFIG_FRAME_POINTER_UNWINDER)   += unwind_frame.o
-obj-$(CONFIG_GUESS_UNWINDER)           += unwind_guess.o
+obj-$(CONFIG_UNWINDER_ORC)             += unwind_orc.o
+obj-$(CONFIG_UNWINDER_FRAME_POINTER)   += unwind_frame.o
+obj-$(CONFIG_UNWINDER_GUESS)           += unwind_guess.o
 
 ###
 # 64 bit specific files
index ea3046e0b0cf53c44417eed99ae8f76b6fec08d9..bb8d300fecbdd09c9469f796934a1d25caf19fb5 100644 (file)
@@ -52,8 +52,3 @@ void arch_apei_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
        apei_mce_report_mem_error(sev, mem_err);
 #endif
 }
-
-void arch_apei_flush_tlb_one(unsigned long addr)
-{
-       __flush_tlb_one(addr);
-}
index 079535e53e2a6435b3b4bd0fc3fa5c932cc2cd09..ef9e02e614d0691ac0c5cdba8fb2d878a59e416e 100644 (file)
@@ -961,6 +961,11 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
                x86_platform.legacy.rtc = 0;
        }
 
+       if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_VGA) {
+               pr_debug("ACPI: probing for VGA not safe\n");
+               x86_platform.legacy.no_vga = 1;
+       }
+
 #ifdef CONFIG_X86_PM_TIMER
        /* detect the location of the ACPI PM Timer */
        if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
index 3344d3382e91393fa7dd16ee336db3ca11a3a433..dbaf14d69ebd510b86a4a0e9e83bbd1862d99d14 100644 (file)
@@ -442,7 +442,6 @@ static void alternatives_smp_lock(const s32 *start, const s32 *end,
 {
        const s32 *poff;
 
-       mutex_lock(&text_mutex);
        for (poff = start; poff < end; poff++) {
                u8 *ptr = (u8 *)poff + *poff;
 
@@ -452,7 +451,6 @@ static void alternatives_smp_lock(const s32 *start, const s32 *end,
                if (*ptr == 0x3e)
                        text_poke(ptr, ((unsigned char []){0xf0}), 1);
        }
-       mutex_unlock(&text_mutex);
 }
 
 static void alternatives_smp_unlock(const s32 *start, const s32 *end,
@@ -460,7 +458,6 @@ static void alternatives_smp_unlock(const s32 *start, const s32 *end,
 {
        const s32 *poff;
 
-       mutex_lock(&text_mutex);
        for (poff = start; poff < end; poff++) {
                u8 *ptr = (u8 *)poff + *poff;
 
@@ -470,7 +467,6 @@ static void alternatives_smp_unlock(const s32 *start, const s32 *end,
                if (*ptr == 0xf0)
                        text_poke(ptr, ((unsigned char []){0x3E}), 1);
        }
-       mutex_unlock(&text_mutex);
 }
 
 struct smp_alt_module {
@@ -489,8 +485,7 @@ struct smp_alt_module {
        struct list_head next;
 };
 static LIST_HEAD(smp_alt_modules);
-static DEFINE_MUTEX(smp_alt);
-static bool uniproc_patched = false;   /* protected by smp_alt */
+static bool uniproc_patched = false;   /* protected by text_mutex */
 
 void __init_or_module alternatives_smp_module_add(struct module *mod,
                                                  char *name,
@@ -499,7 +494,7 @@ void __init_or_module alternatives_smp_module_add(struct module *mod,
 {
        struct smp_alt_module *smp;
 
-       mutex_lock(&smp_alt);
+       mutex_lock(&text_mutex);
        if (!uniproc_patched)
                goto unlock;
 
@@ -526,14 +521,14 @@ void __init_or_module alternatives_smp_module_add(struct module *mod,
 smp_unlock:
        alternatives_smp_unlock(locks, locks_end, text, text_end);
 unlock:
-       mutex_unlock(&smp_alt);
+       mutex_unlock(&text_mutex);
 }
 
 void __init_or_module alternatives_smp_module_del(struct module *mod)
 {
        struct smp_alt_module *item;
 
-       mutex_lock(&smp_alt);
+       mutex_lock(&text_mutex);
        list_for_each_entry(item, &smp_alt_modules, next) {
                if (mod != item->mod)
                        continue;
@@ -541,7 +536,7 @@ void __init_or_module alternatives_smp_module_del(struct module *mod)
                kfree(item);
                break;
        }
-       mutex_unlock(&smp_alt);
+       mutex_unlock(&text_mutex);
 }
 
 void alternatives_enable_smp(void)
@@ -551,7 +546,7 @@ void alternatives_enable_smp(void)
        /* Why bother if there are no other CPUs? */
        BUG_ON(num_possible_cpus() == 1);
 
-       mutex_lock(&smp_alt);
+       mutex_lock(&text_mutex);
 
        if (uniproc_patched) {
                pr_info("switching to SMP code\n");
@@ -563,10 +558,13 @@ void alternatives_enable_smp(void)
                                              mod->text, mod->text_end);
                uniproc_patched = false;
        }
-       mutex_unlock(&smp_alt);
+       mutex_unlock(&text_mutex);
 }
 
-/* Return 1 if the address range is reserved for smp-alternatives */
+/*
+ * Return 1 if the address range is reserved for SMP-alternatives.
+ * Must hold text_mutex.
+ */
 int alternatives_text_reserved(void *start, void *end)
 {
        struct smp_alt_module *mod;
@@ -574,6 +572,8 @@ int alternatives_text_reserved(void *start, void *end)
        u8 *text_start = start;
        u8 *text_end = end;
 
+       lockdep_assert_held(&text_mutex);
+
        list_for_each_entry(mod, &smp_alt_modules, next) {
                if (mod->text > text_end || mod->text_end < text_start)
                        continue;
index 2fb7309c6900635aa0891537875647cdbbf0da10..a9e08924927ef6da6f4620942b3ceba654d1578d 100644 (file)
@@ -7,7 +7,7 @@
 # In particualr, smp_apic_timer_interrupt() is called in random places.
 KCOV_INSTRUMENT                := n
 
-obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o apic_noop.o ipi.o vector.o
+obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o apic_common.o apic_noop.o ipi.o vector.o
 obj-y                          += hw_nmi.o
 
 obj-$(CONFIG_X86_IO_APIC)      += io_apic.o
index ff891772c9f86492d7ca2721b66619b2be61ed9d..6e272f3ea984a220975d1b7c144867840fb867a9 100644 (file)
@@ -211,11 +211,7 @@ static inline int lapic_get_version(void)
  */
 static inline int lapic_is_integrated(void)
 {
-#ifdef CONFIG_X86_64
-       return 1;
-#else
        return APIC_INTEGRATED(lapic_get_version());
-#endif
 }
 
 /*
@@ -298,14 +294,11 @@ int get_physical_broadcast(void)
  */
 int lapic_get_maxlvt(void)
 {
-       unsigned int v;
-
-       v = apic_read(APIC_LVR);
        /*
         * - we always have APIC integrated on 64bit mode
         * - 82489DXs do not report # of LVT entries
         */
-       return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
+       return lapic_is_integrated() ? GET_APIC_MAXLVT(apic_read(APIC_LVR)) : 2;
 }
 
 /*
@@ -1229,53 +1222,100 @@ void __init sync_Arb_IDs(void)
                        APIC_INT_LEVELTRIG | APIC_DM_INIT);
 }
 
-/*
- * An initial setup of the virtual wire mode.
- */
-void __init init_bsp_APIC(void)
+enum apic_intr_mode_id apic_intr_mode;
+
+static int __init apic_intr_mode_select(void)
 {
-       unsigned int value;
+       /* Check kernel option */
+       if (disable_apic) {
+               pr_info("APIC disabled via kernel command line\n");
+               return APIC_PIC;
+       }
 
-       /*
-        * Don't do the setup now if we have a SMP BIOS as the
-        * through-I/O-APIC virtual wire mode might be active.
-        */
-       if (smp_found_config || !boot_cpu_has(X86_FEATURE_APIC))
-               return;
+       /* Check BIOS */
+#ifdef CONFIG_X86_64
+       /* On 64-bit, the APIC must be integrated, Check local APIC only */
+       if (!boot_cpu_has(X86_FEATURE_APIC)) {
+               disable_apic = 1;
+               pr_info("APIC disabled by BIOS\n");
+               return APIC_PIC;
+       }
+#else
+       /* On 32-bit, the APIC may be integrated APIC or 82489DX */
 
-       /*
-        * Do not trust the local APIC being empty at bootup.
-        */
-       clear_local_APIC();
+       /* Neither 82489DX nor integrated APIC ? */
+       if (!boot_cpu_has(X86_FEATURE_APIC) && !smp_found_config) {
+               disable_apic = 1;
+               return APIC_PIC;
+       }
 
-       /*
-        * Enable APIC.
-        */
-       value = apic_read(APIC_SPIV);
-       value &= ~APIC_VECTOR_MASK;
-       value |= APIC_SPIV_APIC_ENABLED;
+       /* If the BIOS pretends there is an integrated APIC ? */
+       if (!boot_cpu_has(X86_FEATURE_APIC) &&
+               APIC_INTEGRATED(boot_cpu_apic_version)) {
+               disable_apic = 1;
+               pr_err(FW_BUG "Local APIC %d not detected, force emulation\n",
+                                      boot_cpu_physical_apicid);
+               return APIC_PIC;
+       }
+#endif
 
-#ifdef CONFIG_X86_32
-       /* This bit is reserved on P4/Xeon and should be cleared */
-       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
-           (boot_cpu_data.x86 == 15))
-               value &= ~APIC_SPIV_FOCUS_DISABLED;
-       else
+       /* Check MP table or ACPI MADT configuration */
+       if (!smp_found_config) {
+               disable_ioapic_support();
+               if (!acpi_lapic) {
+                       pr_info("APIC: ACPI MADT or MP tables are not detected\n");
+                       return APIC_VIRTUAL_WIRE_NO_CONFIG;
+               }
+               return APIC_VIRTUAL_WIRE;
+       }
+
+#ifdef CONFIG_SMP
+       /* If SMP should be disabled, then really disable it! */
+       if (!setup_max_cpus) {
+               pr_info("APIC: SMP mode deactivated\n");
+               return APIC_SYMMETRIC_IO_NO_ROUTING;
+       }
+
+       if (read_apic_id() != boot_cpu_physical_apicid) {
+               panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
+                    read_apic_id(), boot_cpu_physical_apicid);
+               /* Or can we switch back to PIC here? */
+       }
 #endif
-               value |= APIC_SPIV_FOCUS_DISABLED;
-       value |= SPURIOUS_APIC_VECTOR;
-       apic_write(APIC_SPIV, value);
 
-       /*
-        * Set up the virtual wire mode.
-        */
-       apic_write(APIC_LVT0, APIC_DM_EXTINT);
-       value = APIC_DM_NMI;
-       if (!lapic_is_integrated())             /* 82489DX */
-               value |= APIC_LVT_LEVEL_TRIGGER;
-       if (apic_extnmi == APIC_EXTNMI_NONE)
-               value |= APIC_LVT_MASKED;
-       apic_write(APIC_LVT1, value);
+       return APIC_SYMMETRIC_IO;
+}
+
+/* Init the interrupt delivery mode for the BSP */
+void __init apic_intr_mode_init(void)
+{
+       bool upmode = IS_ENABLED(CONFIG_UP_LATE_INIT);
+
+       apic_intr_mode = apic_intr_mode_select();
+
+       switch (apic_intr_mode) {
+       case APIC_PIC:
+               pr_info("APIC: Keep in PIC mode(8259)\n");
+               return;
+       case APIC_VIRTUAL_WIRE:
+               pr_info("APIC: Switch to virtual wire mode setup\n");
+               default_setup_apic_routing();
+               break;
+       case APIC_VIRTUAL_WIRE_NO_CONFIG:
+               pr_info("APIC: Switch to virtual wire mode setup with no configuration\n");
+               upmode = true;
+               default_setup_apic_routing();
+               break;
+       case APIC_SYMMETRIC_IO:
+               pr_info("APIC: Switch to symmetric I/O mode setup\n");
+               default_setup_apic_routing();
+               break;
+       case APIC_SYMMETRIC_IO_NO_ROUTING:
+               pr_info("APIC: Switch to symmetric I/O mode setup in no SMP routine\n");
+               break;
+       }
+
+       apic_bsp_setup(upmode);
 }
 
 static void lapic_setup_esr(void)
@@ -1473,7 +1513,7 @@ void setup_local_APIC(void)
        /*
         * Set up LVT0, LVT1:
         *
-        * set up through-local-APIC on the BP's LINT0. This is not
+        * set up through-local-APIC on the boot CPU's LINT0. This is not
         * strictly necessary in pure symmetric-IO mode, but sometimes
         * we delegate interrupts to the 8259A.
         */
@@ -1499,7 +1539,9 @@ void setup_local_APIC(void)
                value = APIC_DM_NMI;
        else
                value = APIC_DM_NMI | APIC_LVT_MASKED;
-       if (!lapic_is_integrated())             /* 82489DX */
+
+       /* Is 82489DX ? */
+       if (!lapic_is_integrated())
                value |= APIC_LVT_LEVEL_TRIGGER;
        apic_write(APIC_LVT1, value);
 
@@ -1645,7 +1687,7 @@ static __init void try_to_enable_x2apic(int remap_mode)
                 * under KVM
                 */
                if (max_physical_apicid > 255 ||
-                   !hypervisor_x2apic_available()) {
+                   !x86_init.hyper.x2apic_available()) {
                        pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n");
                        x2apic_disable();
                        return;
@@ -1885,8 +1927,8 @@ void __init init_apic_mappings(void)
                 * yeah -- we lie about apic_version
                 * in case if apic was disabled via boot option
                 * but it's not a problem for SMP compiled kernel
-                * since smp_sanity_check is prepared for such a case
-                * and disable smp mode
+                * since apic_intr_mode_select is prepared for such
+                * a case and disable smp mode
                 */
                boot_cpu_apic_version = GET_APIC_VERSION(apic_read(APIC_LVR));
        }
@@ -2242,44 +2284,6 @@ int hard_smp_processor_id(void)
        return read_apic_id();
 }
 
-void default_init_apic_ldr(void)
-{
-       unsigned long val;
-
-       apic_write(APIC_DFR, APIC_DFR_VALUE);
-       val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
-       val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
-       apic_write(APIC_LDR, val);
-}
-
-int default_cpu_mask_to_apicid(const struct cpumask *mask,
-                              struct irq_data *irqdata,
-                              unsigned int *apicid)
-{
-       unsigned int cpu = cpumask_first(mask);
-
-       if (cpu >= nr_cpu_ids)
-               return -EINVAL;
-       *apicid = per_cpu(x86_cpu_to_apicid, cpu);
-       irq_data_update_effective_affinity(irqdata, cpumask_of(cpu));
-       return 0;
-}
-
-int flat_cpu_mask_to_apicid(const struct cpumask *mask,
-                           struct irq_data *irqdata,
-                           unsigned int *apicid)
-
-{
-       struct cpumask *effmsk = irq_data_get_effective_affinity_mask(irqdata);
-       unsigned long cpu_mask = cpumask_bits(mask)[0] & APIC_ALL_CPUS;
-
-       if (!cpu_mask)
-               return -EINVAL;
-       *apicid = (unsigned int)cpu_mask;
-       cpumask_bits(effmsk)[0] = cpu_mask;
-       return 0;
-}
-
 /*
  * Override the generic EOI implementation with an optimized version.
  * Only called during early boot when only one CPU is active and with
@@ -2322,72 +2326,27 @@ static void __init apic_bsp_up_setup(void)
  * Returns:
  * apic_id of BSP APIC
  */
-int __init apic_bsp_setup(bool upmode)
+void __init apic_bsp_setup(bool upmode)
 {
-       int id;
-
        connect_bsp_APIC();
        if (upmode)
                apic_bsp_up_setup();
        setup_local_APIC();
 
-       if (x2apic_mode)
-               id = apic_read(APIC_LDR);
-       else
-               id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
-
        enable_IO_APIC();
        end_local_APIC_setup();
        irq_remap_enable_fault_handling();
        setup_IO_APIC();
-       /* Setup local timer */
-       x86_init.timers.setup_percpu_clockev();
-       return id;
-}
-
-/*
- * This initializes the IO-APIC and APIC hardware if this is
- * a UP kernel.
- */
-int __init APIC_init_uniprocessor(void)
-{
-       if (disable_apic) {
-               pr_info("Apic disabled\n");
-               return -1;
-       }
-#ifdef CONFIG_X86_64
-       if (!boot_cpu_has(X86_FEATURE_APIC)) {
-               disable_apic = 1;
-               pr_info("Apic disabled by BIOS\n");
-               return -1;
-       }
-#else
-       if (!smp_found_config && !boot_cpu_has(X86_FEATURE_APIC))
-               return -1;
-
-       /*
-        * Complain if the BIOS pretends there is one.
-        */
-       if (!boot_cpu_has(X86_FEATURE_APIC) &&
-           APIC_INTEGRATED(boot_cpu_apic_version)) {
-               pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
-                       boot_cpu_physical_apicid);
-               return -1;
-       }
-#endif
-
-       if (!smp_found_config)
-               disable_ioapic_support();
-
-       default_setup_apic_routing();
-       apic_bsp_setup(true);
-       return 0;
 }
 
 #ifdef CONFIG_UP_LATE_INIT
 void __init up_late_init(void)
 {
-       APIC_init_uniprocessor();
+       if (apic_intr_mode == APIC_PIC)
+               return;
+
+       /* Setup local timer */
+       x86_init.timers.setup_percpu_clockev();
 }
 #endif
 
diff --git a/arch/x86/kernel/apic/apic_common.c b/arch/x86/kernel/apic/apic_common.c
new file mode 100644 (file)
index 0000000..a360801
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Common functions shared between the various APIC flavours
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+#include <linux/irq.h>
+#include <asm/apic.h>
+
+u32 apic_default_calc_apicid(unsigned int cpu)
+{
+       return per_cpu(x86_cpu_to_apicid, cpu);
+}
+
+u32 apic_flat_calc_apicid(unsigned int cpu)
+{
+       return 1U << cpu;
+}
+
+bool default_check_apicid_used(physid_mask_t *map, int apicid)
+{
+       return physid_isset(apicid, *map);
+}
+
+void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
+{
+       *retmap = *phys_map;
+}
+
+int default_cpu_present_to_apicid(int mps_cpu)
+{
+       if (mps_cpu < nr_cpu_ids && cpu_present(mps_cpu))
+               return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
+       else
+               return BAD_APICID;
+}
+EXPORT_SYMBOL_GPL(default_cpu_present_to_apicid);
+
+int default_check_phys_apicid_present(int phys_apicid)
+{
+       return physid_isset(phys_apicid, phys_cpu_present_map);
+}
+
+int default_apic_id_valid(int apicid)
+{
+       return (apicid < 255);
+}
index dedd5a41ba48c8d72b513c033bcf1fffd03deb71..aa85690e9b6416b797db8129c8f1cbd7606bf687 100644 (file)
@@ -119,7 +119,7 @@ static unsigned int flat_get_apic_id(unsigned long x)
        return (x >> 24) & 0xFF;
 }
 
-static unsigned long set_apic_id(unsigned int id)
+static u32 set_apic_id(unsigned int id)
 {
        return (id & 0xFF) << 24;
 }
@@ -154,12 +154,10 @@ static struct apic apic_flat __ro_after_init = {
        .irq_delivery_mode              = dest_LowestPrio,
        .irq_dest_mode                  = 1, /* logical */
 
-       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = APIC_DEST_LOGICAL,
        .check_apicid_used              = NULL,
 
-       .vector_allocation_domain       = flat_vector_allocation_domain,
        .init_apic_ldr                  = flat_init_apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -172,7 +170,7 @@ static struct apic apic_flat __ro_after_init = {
        .get_apic_id                    = flat_get_apic_id,
        .set_apic_id                    = set_apic_id,
 
-       .cpu_mask_to_apicid             = flat_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_flat_calc_apicid,
 
        .send_IPI                       = default_send_IPI_single,
        .send_IPI_mask                  = flat_send_IPI_mask,
@@ -249,12 +247,10 @@ static struct apic apic_physflat __ro_after_init = {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* physical */
 
-       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = 0,
        .check_apicid_used              = NULL,
 
-       .vector_allocation_domain       = default_vector_allocation_domain,
        /* not needed, but shouldn't hurt: */
        .init_apic_ldr                  = flat_init_apic_ldr,
 
@@ -268,7 +264,7 @@ static struct apic apic_physflat __ro_after_init = {
        .get_apic_id                    = flat_get_apic_id,
        .set_apic_id                    = set_apic_id,
 
-       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_default_calc_apicid,
 
        .send_IPI                       = default_send_IPI_single_phys,
        .send_IPI_mask                  = default_send_IPI_mask_sequence_phys,
index c8d211277315e6b1a34172160578f8091def26a3..7b659c4480c91a680466cc961cee68754c633ada 100644 (file)
@@ -84,20 +84,6 @@ static int noop_apic_id_registered(void)
        return physid_isset(0, phys_cpu_present_map);
 }
 
-static const struct cpumask *noop_target_cpus(void)
-{
-       /* only BSP here */
-       return cpumask_of(0);
-}
-
-static void noop_vector_allocation_domain(int cpu, struct cpumask *retmask,
-                                         const struct cpumask *mask)
-{
-       if (cpu != 0)
-               pr_warning("APIC: Vector allocated for non-BSP cpu\n");
-       cpumask_copy(retmask, cpumask_of(cpu));
-}
-
 static u32 noop_apic_read(u32 reg)
 {
        WARN_ON_ONCE(boot_cpu_has(X86_FEATURE_APIC) && !disable_apic);
@@ -109,6 +95,13 @@ static void noop_apic_write(u32 reg, u32 v)
        WARN_ON_ONCE(boot_cpu_has(X86_FEATURE_APIC) && !disable_apic);
 }
 
+#ifdef CONFIG_X86_32
+static int noop_x86_32_early_logical_apicid(int cpu)
+{
+       return BAD_APICID;
+}
+#endif
+
 struct apic apic_noop __ro_after_init = {
        .name                           = "noop",
        .probe                          = noop_probe,
@@ -121,12 +114,10 @@ struct apic apic_noop __ro_after_init = {
        /* logical delivery broadcast to all CPUs: */
        .irq_dest_mode                  = 1,
 
-       .target_cpus                    = noop_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = APIC_DEST_LOGICAL,
        .check_apicid_used              = default_check_apicid_used,
 
-       .vector_allocation_domain       = noop_vector_allocation_domain,
        .init_apic_ldr                  = noop_init_apic_ldr,
 
        .ioapic_phys_id_map             = default_ioapic_phys_id_map,
@@ -142,7 +133,7 @@ struct apic apic_noop __ro_after_init = {
        .get_apic_id                    = noop_get_apic_id,
        .set_apic_id                    = NULL,
 
-       .cpu_mask_to_apicid             = flat_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_flat_calc_apicid,
 
        .send_IPI                       = noop_send_IPI,
        .send_IPI_mask                  = noop_send_IPI_mask,
index 2fda912219a6e97144c9f8c89bb191b8f5323d53..134e04506ab41419f41ddf1ee6edf767d95e0088 100644 (file)
@@ -38,7 +38,7 @@ static unsigned int numachip1_get_apic_id(unsigned long x)
        return id;
 }
 
-static unsigned long numachip1_set_apic_id(unsigned int id)
+static u32 numachip1_set_apic_id(unsigned int id)
 {
        return (id & 0xff) << 24;
 }
@@ -51,7 +51,7 @@ static unsigned int numachip2_get_apic_id(unsigned long x)
        return ((mcfg >> (28 - 8)) & 0xfff00) | (x >> 24);
 }
 
-static unsigned long numachip2_set_apic_id(unsigned int id)
+static u32 numachip2_set_apic_id(unsigned int id)
 {
        return id << 24;
 }
@@ -249,12 +249,10 @@ static const struct apic apic_numachip1 __refconst = {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* physical */
 
-       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = 0,
        .check_apicid_used              = NULL,
 
-       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = flat_init_apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -267,7 +265,7 @@ static const struct apic apic_numachip1 __refconst = {
        .get_apic_id                    = numachip1_get_apic_id,
        .set_apic_id                    = numachip1_set_apic_id,
 
-       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_default_calc_apicid,
 
        .send_IPI                       = numachip_send_IPI_one,
        .send_IPI_mask                  = numachip_send_IPI_mask,
@@ -300,12 +298,10 @@ static const struct apic apic_numachip2 __refconst = {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* physical */
 
-       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = 0,
        .check_apicid_used              = NULL,
 
-       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = flat_init_apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -318,7 +314,7 @@ static const struct apic apic_numachip2 __refconst = {
        .get_apic_id                    = numachip2_get_apic_id,
        .set_apic_id                    = numachip2_set_apic_id,
 
-       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_default_calc_apicid,
 
        .send_IPI                       = numachip_send_IPI_one,
        .send_IPI_mask                  = numachip_send_IPI_mask,
index e12fbcfc95715586c9b3dc8840321fe1142dde46..afee386ff711e95132dd5c01e79317ac22bd9a56 100644 (file)
@@ -27,9 +27,9 @@ static int bigsmp_apic_id_registered(void)
        return 1;
 }
 
-static unsigned long bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
+static bool bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
 {
-       return 0;
+       return false;
 }
 
 static int bigsmp_early_logical_apicid(int cpu)
@@ -155,12 +155,10 @@ static struct apic apic_bigsmp __ro_after_init = {
        /* phys delivery to target CPU: */
        .irq_dest_mode                  = 0,
 
-       .target_cpus                    = default_target_cpus,
        .disable_esr                    = 1,
        .dest_logical                   = 0,
        .check_apicid_used              = bigsmp_check_apicid_used,
 
-       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = bigsmp_init_apic_ldr,
 
        .ioapic_phys_id_map             = bigsmp_ioapic_phys_id_map,
@@ -173,7 +171,7 @@ static struct apic apic_bigsmp __ro_after_init = {
        .get_apic_id                    = bigsmp_get_apic_id,
        .set_apic_id                    = NULL,
 
-       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_default_calc_apicid,
 
        .send_IPI                       = default_send_IPI_single_phys,
        .send_IPI_mask                  = default_send_IPI_mask_sequence_phys,
index 56ccf9346b08ac4bf3e54e7994074b6c04fb02e8..b07075dce8b7faa931e3c0105c9c9396341a0d4a 100644 (file)
@@ -112,8 +112,8 @@ static void htirq_domain_free(struct irq_domain *domain, unsigned int virq,
        irq_domain_free_irqs_top(domain, virq, nr_irqs);
 }
 
-static void htirq_domain_activate(struct irq_domain *domain,
-                                 struct irq_data *irq_data)
+static int htirq_domain_activate(struct irq_domain *domain,
+                                struct irq_data *irq_data, bool early)
 {
        struct ht_irq_msg msg;
        struct irq_cfg *cfg = irqd_cfg(irq_data);
@@ -132,6 +132,7 @@ static void htirq_domain_activate(struct irq_domain *domain,
                        HT_IRQ_LOW_MT_ARBITRATED) |
                HT_IRQ_LOW_IRQ_MASKED;
        write_ht_irq_msg(irq_data->irq, &msg);
+       return 0;
 }
 
 static void htirq_domain_deactivate(struct irq_domain *domain,
index 3b89b27945fffc8f7c9d8dd28f9ed787158ad833..201579dc52428edb5c3989102a432c14799d1e1f 100644 (file)
@@ -1014,6 +1014,7 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
                                          info->ioapic_pin))
                        return -ENOMEM;
        } else {
+               info->flags |= X86_IRQ_ALLOC_LEGACY;
                irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true,
                                              NULL);
                if (irq >= 0) {
@@ -1586,6 +1587,43 @@ static int __init notimercheck(char *s)
 }
 __setup("no_timer_check", notimercheck);
 
+static void __init delay_with_tsc(void)
+{
+       unsigned long long start, now;
+       unsigned long end = jiffies + 4;
+
+       start = rdtsc();
+
+       /*
+        * We don't know the TSC frequency yet, but waiting for
+        * 40000000000/HZ TSC cycles is safe:
+        * 4 GHz == 10 jiffies
+        * 1 GHz == 40 jiffies
+        */
+       do {
+               rep_nop();
+               now = rdtsc();
+       } while ((now - start) < 40000000000UL / HZ &&
+               time_before_eq(jiffies, end));
+}
+
+static void __init delay_without_tsc(void)
+{
+       unsigned long end = jiffies + 4;
+       int band = 1;
+
+       /*
+        * We don't know any frequency yet, but waiting for
+        * 40940000000/HZ cycles is safe:
+        * 4 GHz == 10 jiffies
+        * 1 GHz == 40 jiffies
+        * 1 << 1 + 1 << 2 +...+ 1 << 11 = 4094
+        */
+       do {
+               __delay(((1U << band++) * 10000000UL) / HZ);
+       } while (band < 12 && time_before_eq(jiffies, end));
+}
+
 /*
  * There is a nasty bug in some older SMP boards, their mptable lies
  * about the timer IRQ. We do the following to work around the situation:
@@ -1604,8 +1642,12 @@ static int __init timer_irq_works(void)
 
        local_save_flags(flags);
        local_irq_enable();
-       /* Let ten ticks pass... */
-       mdelay((10 * 1000) / HZ);
+
+       if (boot_cpu_has(X86_FEATURE_TSC))
+               delay_with_tsc();
+       else
+               delay_without_tsc();
+
        local_irq_restore(flags);
 
        /*
@@ -1821,26 +1863,36 @@ static void ioapic_ir_ack_level(struct irq_data *irq_data)
        eoi_ioapic_pin(data->entry.vector, data);
 }
 
+static void ioapic_configure_entry(struct irq_data *irqd)
+{
+       struct mp_chip_data *mpd = irqd->chip_data;
+       struct irq_cfg *cfg = irqd_cfg(irqd);
+       struct irq_pin_list *entry;
+
+       /*
+        * Only update when the parent is the vector domain, don't touch it
+        * if the parent is the remapping domain. Check the installed
+        * ioapic chip to verify that.
+        */
+       if (irqd->chip == &ioapic_chip) {
+               mpd->entry.dest = cfg->dest_apicid;
+               mpd->entry.vector = cfg->vector;
+       }
+       for_each_irq_pin(entry, mpd->irq_2_pin)
+               __ioapic_write_entry(entry->apic, entry->pin, mpd->entry);
+}
+
 static int ioapic_set_affinity(struct irq_data *irq_data,
                               const struct cpumask *mask, bool force)
 {
        struct irq_data *parent = irq_data->parent_data;
-       struct mp_chip_data *data = irq_data->chip_data;
-       struct irq_pin_list *entry;
-       struct irq_cfg *cfg;
        unsigned long flags;
        int ret;
 
        ret = parent->chip->irq_set_affinity(parent, mask, force);
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
-               cfg = irqd_cfg(irq_data);
-               data->entry.dest = cfg->dest_apicid;
-               data->entry.vector = cfg->vector;
-               for_each_irq_pin(entry, data->irq_2_pin)
-                       __ioapic_write_entry(entry->apic, entry->pin,
-                                            data->entry);
-       }
+       if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE)
+               ioapic_configure_entry(irq_data);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
        return ret;
@@ -2097,7 +2149,7 @@ static inline void __init check_timer(void)
                                unmask_ioapic_irq(irq_get_irq_data(0));
                }
                irq_domain_deactivate_irq(irq_data);
-               irq_domain_activate_irq(irq_data);
+               irq_domain_activate_irq(irq_data, false);
                if (timer_irq_works()) {
                        if (disable_timer_pin_1 > 0)
                                clear_IO_APIC_pin(0, pin1);
@@ -2119,7 +2171,7 @@ static inline void __init check_timer(void)
                 */
                replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
                irq_domain_deactivate_irq(irq_data);
-               irq_domain_activate_irq(irq_data);
+               irq_domain_activate_irq(irq_data, false);
                legacy_pic->unmask(0);
                if (timer_irq_works()) {
                        apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
@@ -2513,52 +2565,9 @@ int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
 }
 
 /*
- * This function currently is only a helper for the i386 smp boot process where
- * we need to reprogram the ioredtbls to cater for the cpus which have come online
- * so mask in all cases should simply be apic->target_cpus()
+ * This function updates target affinity of IOAPIC interrupts to include
+ * the CPUs which came online during SMP bringup.
  */
-#ifdef CONFIG_SMP
-void __init setup_ioapic_dest(void)
-{
-       int pin, ioapic, irq, irq_entry;
-       const struct cpumask *mask;
-       struct irq_desc *desc;
-       struct irq_data *idata;
-       struct irq_chip *chip;
-
-       if (skip_ioapic_setup == 1)
-               return;
-
-       for_each_ioapic_pin(ioapic, pin) {
-               irq_entry = find_irq_entry(ioapic, pin, mp_INT);
-               if (irq_entry == -1)
-                       continue;
-
-               irq = pin_2_irq(irq_entry, ioapic, pin, 0);
-               if (irq < 0 || !mp_init_irq_at_boot(ioapic, irq))
-                       continue;
-
-               desc = irq_to_desc(irq);
-               raw_spin_lock_irq(&desc->lock);
-               idata = irq_desc_get_irq_data(desc);
-
-               /*
-                * Honour affinities which have been set in early boot
-                */
-               if (!irqd_can_balance(idata) || irqd_affinity_was_set(idata))
-                       mask = irq_data_get_affinity_mask(idata);
-               else
-                       mask = apic->target_cpus();
-
-               chip = irq_data_get_irq_chip(idata);
-               /* Might be lapic_chip for irq 0 */
-               if (chip->irq_set_affinity)
-                       chip->irq_set_affinity(idata, mask, false);
-               raw_spin_unlock_irq(&desc->lock);
-       }
-}
-#endif
-
 #define IOAPIC_RESOURCE_NAME_SIZE 11
 
 static struct resource *ioapic_resources;
@@ -2978,17 +2987,15 @@ void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
        irq_domain_free_irqs_top(domain, virq, nr_irqs);
 }
 
-void mp_irqdomain_activate(struct irq_domain *domain,
-                          struct irq_data *irq_data)
+int mp_irqdomain_activate(struct irq_domain *domain,
+                         struct irq_data *irq_data, bool early)
 {
        unsigned long flags;
-       struct irq_pin_list *entry;
-       struct mp_chip_data *data = irq_data->chip_data;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       for_each_irq_pin(entry, data->irq_2_pin)
-               __ioapic_write_entry(entry->apic, entry->pin, data->entry);
+       ioapic_configure_entry(irq_data);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+       return 0;
 }
 
 void mp_irqdomain_deactivate(struct irq_domain *domain,
index 63287659adb61acacdc127d4441f64e4fc45a4bb..fa22017de806504b79593ead951bffe4e5d5421b 100644 (file)
@@ -66,6 +66,31 @@ static void setup_apic_flat_routing(void)
 #endif
 }
 
+static int default_apic_id_registered(void)
+{
+       return physid_isset(read_apic_id(), phys_cpu_present_map);
+}
+
+/*
+ * Set up the logical destination ID.  Intel recommends to set DFR, LDR and
+ * TPR before enabling an APIC.  See e.g. "AP-388 82489DX User's Manual"
+ * (Intel document number 292116).
+ */
+static void default_init_apic_ldr(void)
+{
+       unsigned long val;
+
+       apic_write(APIC_DFR, APIC_DFR_VALUE);
+       val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
+       val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
+       apic_write(APIC_LDR, val);
+}
+
+static int default_phys_pkg_id(int cpuid_apic, int index_msb)
+{
+       return cpuid_apic >> index_msb;
+}
+
 /* should be called last. */
 static int probe_default(void)
 {
@@ -84,12 +109,10 @@ static struct apic apic_default __ro_after_init = {
        /* logical delivery broadcast to all CPUs: */
        .irq_dest_mode                  = 1,
 
-       .target_cpus                    = default_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = APIC_DEST_LOGICAL,
        .check_apicid_used              = default_check_apicid_used,
 
-       .vector_allocation_domain       = flat_vector_allocation_domain,
        .init_apic_ldr                  = default_init_apic_ldr,
 
        .ioapic_phys_id_map             = default_ioapic_phys_id_map,
@@ -102,7 +125,7 @@ static struct apic apic_default __ro_after_init = {
        .get_apic_id                    = default_get_apic_id,
        .set_apic_id                    = NULL,
 
-       .cpu_mask_to_apicid             = flat_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_flat_calc_apicid,
 
        .send_IPI                       = default_send_IPI_single,
        .send_IPI_mask                  = default_send_IPI_mask_logical,
index 88c214e75a6be0bd26a126e2f57ad67d46a444fe..05c85e693a5d4c9d9e17da19337f2318f29aa621 100644 (file)
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/interrupt.h>
+#include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/compiler.h>
 #include <linux/slab.h>
 #include <asm/desc.h>
 #include <asm/irq_remapping.h>
 
+#include <asm/trace/irq_vectors.h>
+
 struct apic_chip_data {
-       struct irq_cfg          cfg;
-       cpumask_var_t           domain;
-       cpumask_var_t           old_domain;
-       u8                      move_in_progress : 1;
+       struct irq_cfg          hw_irq_cfg;
+       unsigned int            vector;
+       unsigned int            prev_vector;
+       unsigned int            cpu;
+       unsigned int            prev_cpu;
+       unsigned int            irq;
+       struct hlist_node       clist;
+       unsigned int            move_in_progress        : 1,
+                               is_managed              : 1,
+                               can_reserve             : 1,
+                               has_reserved            : 1;
 };
 
 struct irq_domain *x86_vector_domain;
 EXPORT_SYMBOL_GPL(x86_vector_domain);
 static DEFINE_RAW_SPINLOCK(vector_lock);
-static cpumask_var_t vector_cpumask, vector_searchmask, searched_cpumask;
+static cpumask_var_t vector_searchmask;
 static struct irq_chip lapic_controller;
-#ifdef CONFIG_X86_IO_APIC
-static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
+static struct irq_matrix *vector_matrix;
+#ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct hlist_head, cleanup_list);
 #endif
 
 void lock_vector_lock(void)
@@ -50,22 +61,37 @@ void unlock_vector_lock(void)
        raw_spin_unlock(&vector_lock);
 }
 
-static struct apic_chip_data *apic_chip_data(struct irq_data *irq_data)
+void init_irq_alloc_info(struct irq_alloc_info *info,
+                        const struct cpumask *mask)
+{
+       memset(info, 0, sizeof(*info));
+       info->mask = mask;
+}
+
+void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src)
 {
-       if (!irq_data)
+       if (src)
+               *dst = *src;
+       else
+               memset(dst, 0, sizeof(*dst));
+}
+
+static struct apic_chip_data *apic_chip_data(struct irq_data *irqd)
+{
+       if (!irqd)
                return NULL;
 
-       while (irq_data->parent_data)
-               irq_data = irq_data->parent_data;
+       while (irqd->parent_data)
+               irqd = irqd->parent_data;
 
-       return irq_data->chip_data;
+       return irqd->chip_data;
 }
 
-struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
+struct irq_cfg *irqd_cfg(struct irq_data *irqd)
 {
-       struct apic_chip_data *data = apic_chip_data(irq_data);
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
 
-       return data ? &data->cfg : NULL;
+       return apicd ? &apicd->hw_irq_cfg : NULL;
 }
 EXPORT_SYMBOL_GPL(irqd_cfg);
 
@@ -76,270 +102,395 @@ struct irq_cfg *irq_cfg(unsigned int irq)
 
 static struct apic_chip_data *alloc_apic_chip_data(int node)
 {
-       struct apic_chip_data *data;
+       struct apic_chip_data *apicd;
 
-       data = kzalloc_node(sizeof(*data), GFP_KERNEL, node);
-       if (!data)
-               return NULL;
-       if (!zalloc_cpumask_var_node(&data->domain, GFP_KERNEL, node))
-               goto out_data;
-       if (!zalloc_cpumask_var_node(&data->old_domain, GFP_KERNEL, node))
-               goto out_domain;
-       return data;
-out_domain:
-       free_cpumask_var(data->domain);
-out_data:
-       kfree(data);
-       return NULL;
-}
-
-static void free_apic_chip_data(struct apic_chip_data *data)
-{
-       if (data) {
-               free_cpumask_var(data->domain);
-               free_cpumask_var(data->old_domain);
-               kfree(data);
+       apicd = kzalloc_node(sizeof(*apicd), GFP_KERNEL, node);
+       if (apicd)
+               INIT_HLIST_NODE(&apicd->clist);
+       return apicd;
+}
+
+static void free_apic_chip_data(struct apic_chip_data *apicd)
+{
+       kfree(apicd);
+}
+
+static void apic_update_irq_cfg(struct irq_data *irqd, unsigned int vector,
+                               unsigned int cpu)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+
+       lockdep_assert_held(&vector_lock);
+
+       apicd->hw_irq_cfg.vector = vector;
+       apicd->hw_irq_cfg.dest_apicid = apic->calc_dest_apicid(cpu);
+       irq_data_update_effective_affinity(irqd, cpumask_of(cpu));
+       trace_vector_config(irqd->irq, vector, cpu,
+                           apicd->hw_irq_cfg.dest_apicid);
+}
+
+static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
+                              unsigned int newcpu)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       struct irq_desc *desc = irq_data_to_desc(irqd);
+
+       lockdep_assert_held(&vector_lock);
+
+       trace_vector_update(irqd->irq, newvec, newcpu, apicd->vector,
+                           apicd->cpu);
+
+       /* Setup the vector move, if required  */
+       if (apicd->vector && cpu_online(apicd->cpu)) {
+               apicd->move_in_progress = true;
+               apicd->prev_vector = apicd->vector;
+               apicd->prev_cpu = apicd->cpu;
+       } else {
+               apicd->prev_vector = 0;
        }
+
+       apicd->vector = newvec;
+       apicd->cpu = newcpu;
+       BUG_ON(!IS_ERR_OR_NULL(per_cpu(vector_irq, newcpu)[newvec]));
+       per_cpu(vector_irq, newcpu)[newvec] = desc;
 }
 
-static int __assign_irq_vector(int irq, struct apic_chip_data *d,
-                              const struct cpumask *mask,
-                              struct irq_data *irqdata)
+static void vector_assign_managed_shutdown(struct irq_data *irqd)
 {
-       /*
-        * NOTE! The local APIC isn't very good at handling
-        * multiple interrupts at the same interrupt level.
-        * As the interrupt level is determined by taking the
-        * vector number and shifting that right by 4, we
-        * want to spread these out a bit so that they don't
-        * all fall in the same interrupt level.
-        *
-        * Also, we've got to be careful not to trash gate
-        * 0x80, because int 0x80 is hm, kind of importantish. ;)
-        */
-       static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
-       static int current_offset = VECTOR_OFFSET_START % 16;
-       int cpu, vector;
+       unsigned int cpu = cpumask_first(cpu_online_mask);
 
-       /*
-        * If there is still a move in progress or the previous move has not
-        * been cleaned up completely, tell the caller to come back later.
-        */
-       if (d->move_in_progress ||
-           cpumask_intersects(d->old_domain, cpu_online_mask))
-               return -EBUSY;
+       apic_update_irq_cfg(irqd, MANAGED_IRQ_SHUTDOWN_VECTOR, cpu);
+}
 
-       /* Only try and allocate irqs on cpus that are present */
-       cpumask_clear(d->old_domain);
-       cpumask_clear(searched_cpumask);
-       cpu = cpumask_first_and(mask, cpu_online_mask);
-       while (cpu < nr_cpu_ids) {
-               int new_cpu, offset;
+static int reserve_managed_vector(struct irq_data *irqd)
+{
+       const struct cpumask *affmsk = irq_data_get_affinity_mask(irqd);
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       unsigned long flags;
+       int ret;
 
-               /* Get the possible target cpus for @mask/@cpu from the apic */
-               apic->vector_allocation_domain(cpu, vector_cpumask, mask);
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       apicd->is_managed = true;
+       ret = irq_matrix_reserve_managed(vector_matrix, affmsk);
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+       trace_vector_reserve_managed(irqd->irq, ret);
+       return ret;
+}
 
-               /*
-                * Clear the offline cpus from @vector_cpumask for searching
-                * and verify whether the result overlaps with @mask. If true,
-                * then the call to apic->cpu_mask_to_apicid() will
-                * succeed as well. If not, no point in trying to find a
-                * vector in this mask.
-                */
-               cpumask_and(vector_searchmask, vector_cpumask, cpu_online_mask);
-               if (!cpumask_intersects(vector_searchmask, mask))
-                       goto next_cpu;
-
-               if (cpumask_subset(vector_cpumask, d->domain)) {
-                       if (cpumask_equal(vector_cpumask, d->domain))
-                               goto success;
-                       /*
-                        * Mark the cpus which are not longer in the mask for
-                        * cleanup.
-                        */
-                       cpumask_andnot(d->old_domain, d->domain, vector_cpumask);
-                       vector = d->cfg.vector;
-                       goto update;
-               }
+static void reserve_irq_vector_locked(struct irq_data *irqd)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
 
-               vector = current_vector;
-               offset = current_offset;
-next:
-               vector += 16;
-               if (vector >= FIRST_SYSTEM_VECTOR) {
-                       offset = (offset + 1) % 16;
-                       vector = FIRST_EXTERNAL_VECTOR + offset;
-               }
+       irq_matrix_reserve(vector_matrix);
+       apicd->can_reserve = true;
+       apicd->has_reserved = true;
+       trace_vector_reserve(irqd->irq, 0);
+       vector_assign_managed_shutdown(irqd);
+}
 
-               /* If the search wrapped around, try the next cpu */
-               if (unlikely(current_vector == vector))
-                       goto next_cpu;
+static int reserve_irq_vector(struct irq_data *irqd)
+{
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       reserve_irq_vector_locked(irqd);
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+       return 0;
+}
 
-               if (test_bit(vector, used_vectors))
-                       goto next;
+static int allocate_vector(struct irq_data *irqd, const struct cpumask *dest)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       bool resvd = apicd->has_reserved;
+       unsigned int cpu = apicd->cpu;
+       int vector = apicd->vector;
 
-               for_each_cpu(new_cpu, vector_searchmask) {
-                       if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector]))
-                               goto next;
-               }
-               /* Found one! */
-               current_vector = vector;
-               current_offset = offset;
-               /* Schedule the old vector for cleanup on all cpus */
-               if (d->cfg.vector)
-                       cpumask_copy(d->old_domain, d->domain);
-               for_each_cpu(new_cpu, vector_searchmask)
-                       per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq);
-               goto update;
-
-next_cpu:
-               /*
-                * We exclude the current @vector_cpumask from the requested
-                * @mask and try again with the next online cpu in the
-                * result. We cannot modify @mask, so we use @vector_cpumask
-                * as a temporary buffer here as it will be reassigned when
-                * calling apic->vector_allocation_domain() above.
-                */
-               cpumask_or(searched_cpumask, searched_cpumask, vector_cpumask);
-               cpumask_andnot(vector_cpumask, mask, searched_cpumask);
-               cpu = cpumask_first_and(vector_cpumask, cpu_online_mask);
-               continue;
-       }
-       return -ENOSPC;
+       lockdep_assert_held(&vector_lock);
 
-update:
        /*
-        * Exclude offline cpus from the cleanup mask and set the
-        * move_in_progress flag when the result is not empty.
+        * If the current target CPU is online and in the new requested
+        * affinity mask, there is no point in moving the interrupt from
+        * one CPU to another.
         */
-       cpumask_and(d->old_domain, d->old_domain, cpu_online_mask);
-       d->move_in_progress = !cpumask_empty(d->old_domain);
-       d->cfg.old_vector = d->move_in_progress ? d->cfg.vector : 0;
-       d->cfg.vector = vector;
-       cpumask_copy(d->domain, vector_cpumask);
-success:
-       /*
-        * Cache destination APIC IDs into cfg->dest_apicid. This cannot fail
-        * as we already established, that mask & d->domain & cpu_online_mask
-        * is not empty.
-        *
-        * vector_searchmask is a subset of d->domain and has the offline
-        * cpus masked out.
-        */
-       cpumask_and(vector_searchmask, vector_searchmask, mask);
-       BUG_ON(apic->cpu_mask_to_apicid(vector_searchmask, irqdata,
-                                       &d->cfg.dest_apicid));
+       if (vector && cpu_online(cpu) && cpumask_test_cpu(cpu, dest))
+               return 0;
+
+       vector = irq_matrix_alloc(vector_matrix, dest, resvd, &cpu);
+       if (vector > 0)
+               apic_update_vector(irqd, vector, cpu);
+       trace_vector_alloc(irqd->irq, vector, resvd, vector);
+       return vector;
+}
+
+static int assign_vector_locked(struct irq_data *irqd,
+                               const struct cpumask *dest)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       int vector = allocate_vector(irqd, dest);
+
+       if (vector < 0)
+               return vector;
+
+       apic_update_irq_cfg(irqd, apicd->vector, apicd->cpu);
        return 0;
 }
 
-static int assign_irq_vector(int irq, struct apic_chip_data *data,
-                            const struct cpumask *mask,
-                            struct irq_data *irqdata)
+static int assign_irq_vector(struct irq_data *irqd, const struct cpumask *dest)
 {
-       int err;
        unsigned long flags;
+       int ret;
 
        raw_spin_lock_irqsave(&vector_lock, flags);
-       err = __assign_irq_vector(irq, data, mask, irqdata);
+       cpumask_and(vector_searchmask, dest, cpu_online_mask);
+       ret = assign_vector_locked(irqd, vector_searchmask);
        raw_spin_unlock_irqrestore(&vector_lock, flags);
-       return err;
+       return ret;
 }
 
-static int assign_irq_vector_policy(int irq, int node,
-                                   struct apic_chip_data *data,
-                                   struct irq_alloc_info *info,
-                                   struct irq_data *irqdata)
+static int assign_irq_vector_any_locked(struct irq_data *irqd)
 {
-       if (info && info->mask)
-               return assign_irq_vector(irq, data, info->mask, irqdata);
-       if (node != NUMA_NO_NODE &&
-           assign_irq_vector(irq, data, cpumask_of_node(node), irqdata) == 0)
+       /* Get the affinity mask - either irq_default_affinity or (user) set */
+       const struct cpumask *affmsk = irq_data_get_affinity_mask(irqd);
+       int node = irq_data_get_node(irqd);
+
+       if (node == NUMA_NO_NODE)
+               goto all;
+       /* Try the intersection of @affmsk and node mask */
+       cpumask_and(vector_searchmask, cpumask_of_node(node), affmsk);
+       if (!assign_vector_locked(irqd, vector_searchmask))
+               return 0;
+       /* Try the node mask */
+       if (!assign_vector_locked(irqd, cpumask_of_node(node)))
                return 0;
-       return assign_irq_vector(irq, data, apic->target_cpus(), irqdata);
+all:
+       /* Try the full affinity mask */
+       cpumask_and(vector_searchmask, affmsk, cpu_online_mask);
+       if (!assign_vector_locked(irqd, vector_searchmask))
+               return 0;
+       /* Try the full online mask */
+       return assign_vector_locked(irqd, cpu_online_mask);
+}
+
+static int
+assign_irq_vector_policy(struct irq_data *irqd, struct irq_alloc_info *info)
+{
+       if (irqd_affinity_is_managed(irqd))
+               return reserve_managed_vector(irqd);
+       if (info->mask)
+               return assign_irq_vector(irqd, info->mask);
+       /*
+        * Make only a global reservation with no guarantee. A real vector
+        * is associated at activation time.
+        */
+       return reserve_irq_vector(irqd);
 }
 
-static void clear_irq_vector(int irq, struct apic_chip_data *data)
+static int
+assign_managed_vector(struct irq_data *irqd, const struct cpumask *dest)
 {
-       struct irq_desc *desc;
-       int cpu, vector;
+       const struct cpumask *affmsk = irq_data_get_affinity_mask(irqd);
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       int vector, cpu;
 
-       if (!data->cfg.vector)
+       cpumask_and(vector_searchmask, vector_searchmask, affmsk);
+       cpu = cpumask_first(vector_searchmask);
+       if (cpu >= nr_cpu_ids)
+               return -EINVAL;
+       /* set_affinity might call here for nothing */
+       if (apicd->vector && cpumask_test_cpu(apicd->cpu, vector_searchmask))
+               return 0;
+       vector = irq_matrix_alloc_managed(vector_matrix, cpu);
+       trace_vector_alloc_managed(irqd->irq, vector, vector);
+       if (vector < 0)
+               return vector;
+       apic_update_vector(irqd, vector, cpu);
+       apic_update_irq_cfg(irqd, vector, cpu);
+       return 0;
+}
+
+static void clear_irq_vector(struct irq_data *irqd)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       bool managed = irqd_affinity_is_managed(irqd);
+       unsigned int vector = apicd->vector;
+
+       lockdep_assert_held(&vector_lock);
+
+       if (!vector)
                return;
 
-       vector = data->cfg.vector;
-       for_each_cpu_and(cpu, data->domain, cpu_online_mask)
-               per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
+       trace_vector_clear(irqd->irq, vector, apicd->cpu, apicd->prev_vector,
+                          apicd->prev_cpu);
 
-       data->cfg.vector = 0;
-       cpumask_clear(data->domain);
+       per_cpu(vector_irq, apicd->cpu)[vector] = VECTOR_UNUSED;
+       irq_matrix_free(vector_matrix, apicd->cpu, vector, managed);
+       apicd->vector = 0;
 
-       /*
-        * If move is in progress or the old_domain mask is not empty,
-        * i.e. the cleanup IPI has not been processed yet, we need to remove
-        * the old references to desc from all cpus vector tables.
-        */
-       if (!data->move_in_progress && cpumask_empty(data->old_domain))
+       /* Clean up move in progress */
+       vector = apicd->prev_vector;
+       if (!vector)
                return;
 
-       desc = irq_to_desc(irq);
-       for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
-               for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
-                    vector++) {
-                       if (per_cpu(vector_irq, cpu)[vector] != desc)
-                               continue;
-                       per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
-                       break;
-               }
+       per_cpu(vector_irq, apicd->prev_cpu)[vector] = VECTOR_UNUSED;
+       irq_matrix_free(vector_matrix, apicd->prev_cpu, vector, managed);
+       apicd->prev_vector = 0;
+       apicd->move_in_progress = 0;
+       hlist_del_init(&apicd->clist);
+}
+
+static void x86_vector_deactivate(struct irq_domain *dom, struct irq_data *irqd)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       unsigned long flags;
+
+       trace_vector_deactivate(irqd->irq, apicd->is_managed,
+                               apicd->can_reserve, false);
+
+       /* Regular fixed assigned interrupt */
+       if (!apicd->is_managed && !apicd->can_reserve)
+               return;
+       /* If the interrupt has a global reservation, nothing to do */
+       if (apicd->has_reserved)
+               return;
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       clear_irq_vector(irqd);
+       if (apicd->can_reserve)
+               reserve_irq_vector_locked(irqd);
+       else
+               vector_assign_managed_shutdown(irqd);
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+static int activate_reserved(struct irq_data *irqd)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       int ret;
+
+       ret = assign_irq_vector_any_locked(irqd);
+       if (!ret)
+               apicd->has_reserved = false;
+       return ret;
+}
+
+static int activate_managed(struct irq_data *irqd)
+{
+       const struct cpumask *dest = irq_data_get_affinity_mask(irqd);
+       int ret;
+
+       cpumask_and(vector_searchmask, dest, cpu_online_mask);
+       if (WARN_ON_ONCE(cpumask_empty(vector_searchmask))) {
+               /* Something in the core code broke! Survive gracefully */
+               pr_err("Managed startup for irq %u, but no CPU\n", irqd->irq);
+               return EINVAL;
+       }
+
+       ret = assign_managed_vector(irqd, vector_searchmask);
+       /*
+        * This should not happen. The vector reservation got buggered.  Handle
+        * it gracefully.
+        */
+       if (WARN_ON_ONCE(ret < 0)) {
+               pr_err("Managed startup irq %u, no vector available\n",
+                      irqd->irq);
        }
-       data->move_in_progress = 0;
+       return ret;
 }
 
-void init_irq_alloc_info(struct irq_alloc_info *info,
-                        const struct cpumask *mask)
+static int x86_vector_activate(struct irq_domain *dom, struct irq_data *irqd,
+                              bool early)
 {
-       memset(info, 0, sizeof(*info));
-       info->mask = mask;
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       unsigned long flags;
+       int ret = 0;
+
+       trace_vector_activate(irqd->irq, apicd->is_managed,
+                             apicd->can_reserve, early);
+
+       /* Nothing to do for fixed assigned vectors */
+       if (!apicd->can_reserve && !apicd->is_managed)
+               return 0;
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       if (early || irqd_is_managed_and_shutdown(irqd))
+               vector_assign_managed_shutdown(irqd);
+       else if (apicd->is_managed)
+               ret = activate_managed(irqd);
+       else if (apicd->has_reserved)
+               ret = activate_reserved(irqd);
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+       return ret;
 }
 
-void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src)
+static void vector_free_reserved_and_managed(struct irq_data *irqd)
 {
-       if (src)
-               *dst = *src;
-       else
-               memset(dst, 0, sizeof(*dst));
+       const struct cpumask *dest = irq_data_get_affinity_mask(irqd);
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+
+       trace_vector_teardown(irqd->irq, apicd->is_managed,
+                             apicd->has_reserved);
+
+       if (apicd->has_reserved)
+               irq_matrix_remove_reserved(vector_matrix);
+       if (apicd->is_managed)
+               irq_matrix_remove_managed(vector_matrix, dest);
 }
 
 static void x86_vector_free_irqs(struct irq_domain *domain,
                                 unsigned int virq, unsigned int nr_irqs)
 {
-       struct apic_chip_data *apic_data;
-       struct irq_data *irq_data;
+       struct apic_chip_data *apicd;
+       struct irq_data *irqd;
        unsigned long flags;
        int i;
 
        for (i = 0; i < nr_irqs; i++) {
-               irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i);
-               if (irq_data && irq_data->chip_data) {
+               irqd = irq_domain_get_irq_data(x86_vector_domain, virq + i);
+               if (irqd && irqd->chip_data) {
                        raw_spin_lock_irqsave(&vector_lock, flags);
-                       clear_irq_vector(virq + i, irq_data->chip_data);
-                       apic_data = irq_data->chip_data;
-                       irq_domain_reset_irq_data(irq_data);
+                       clear_irq_vector(irqd);
+                       vector_free_reserved_and_managed(irqd);
+                       apicd = irqd->chip_data;
+                       irq_domain_reset_irq_data(irqd);
                        raw_spin_unlock_irqrestore(&vector_lock, flags);
-                       free_apic_chip_data(apic_data);
-#ifdef CONFIG_X86_IO_APIC
-                       if (virq + i < nr_legacy_irqs())
-                               legacy_irq_data[virq + i] = NULL;
-#endif
+                       free_apic_chip_data(apicd);
                }
        }
 }
 
+static bool vector_configure_legacy(unsigned int virq, struct irq_data *irqd,
+                                   struct apic_chip_data *apicd)
+{
+       unsigned long flags;
+       bool realloc = false;
+
+       apicd->vector = ISA_IRQ_VECTOR(virq);
+       apicd->cpu = 0;
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       /*
+        * If the interrupt is activated, then it must stay at this vector
+        * position. That's usually the timer interrupt (0).
+        */
+       if (irqd_is_activated(irqd)) {
+               trace_vector_setup(virq, true, 0);
+               apic_update_irq_cfg(irqd, apicd->vector, apicd->cpu);
+       } else {
+               /* Release the vector */
+               apicd->can_reserve = true;
+               clear_irq_vector(irqd);
+               realloc = true;
+       }
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+       return realloc;
+}
+
 static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
                                 unsigned int nr_irqs, void *arg)
 {
        struct irq_alloc_info *info = arg;
-       struct apic_chip_data *data;
-       struct irq_data *irq_data;
+       struct apic_chip_data *apicd;
+       struct irq_data *irqd;
        int i, err, node;
 
        if (disable_apic)
@@ -350,34 +501,37 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
                return -ENOSYS;
 
        for (i = 0; i < nr_irqs; i++) {
-               irq_data = irq_domain_get_irq_data(domain, virq + i);
-               BUG_ON(!irq_data);
-               node = irq_data_get_node(irq_data);
-#ifdef CONFIG_X86_IO_APIC
-               if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i])
-                       data = legacy_irq_data[virq + i];
-               else
-#endif
-                       data = alloc_apic_chip_data(node);
-               if (!data) {
+               irqd = irq_domain_get_irq_data(domain, virq + i);
+               BUG_ON(!irqd);
+               node = irq_data_get_node(irqd);
+               WARN_ON_ONCE(irqd->chip_data);
+               apicd = alloc_apic_chip_data(node);
+               if (!apicd) {
                        err = -ENOMEM;
                        goto error;
                }
 
-               irq_data->chip = &lapic_controller;
-               irq_data->chip_data = data;
-               irq_data->hwirq = virq + i;
-               err = assign_irq_vector_policy(virq + i, node, data, info,
-                                              irq_data);
-               if (err)
-                       goto error;
+               apicd->irq = virq + i;
+               irqd->chip = &lapic_controller;
+               irqd->chip_data = apicd;
+               irqd->hwirq = virq + i;
+               irqd_set_single_target(irqd);
                /*
-                * If the apic destination mode is physical, then the
-                * effective affinity is restricted to a single target
-                * CPU. Mark the interrupt accordingly.
+                * Legacy vectors are already assigned when the IOAPIC
+                * takes them over. They stay on the same vector. This is
+                * required for check_timer() to work correctly as it might
+                * switch back to legacy mode. Only update the hardware
+                * config.
                 */
-               if (!apic->irq_dest_mode)
-                       irqd_set_single_target(irq_data);
+               if (info->flags & X86_IRQ_ALLOC_LEGACY) {
+                       if (!vector_configure_legacy(virq + i, irqd, apicd))
+                               continue;
+               }
+
+               err = assign_irq_vector_policy(irqd, info);
+               trace_vector_setup(virq + i, false, err);
+               if (err)
+                       goto error;
        }
 
        return 0;
@@ -387,9 +541,56 @@ error:
        return err;
 }
 
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+void x86_vector_debug_show(struct seq_file *m, struct irq_domain *d,
+                          struct irq_data *irqd, int ind)
+{
+       unsigned int cpu, vector, prev_cpu, prev_vector;
+       struct apic_chip_data *apicd;
+       unsigned long flags;
+       int irq;
+
+       if (!irqd) {
+               irq_matrix_debug_show(m, vector_matrix, ind);
+               return;
+       }
+
+       irq = irqd->irq;
+       if (irq < nr_legacy_irqs() && !test_bit(irq, &io_apic_irqs)) {
+               seq_printf(m, "%*sVector: %5d\n", ind, "", ISA_IRQ_VECTOR(irq));
+               seq_printf(m, "%*sTarget: Legacy PIC all CPUs\n", ind, "");
+               return;
+       }
+
+       apicd = irqd->chip_data;
+       if (!apicd) {
+               seq_printf(m, "%*sVector: Not assigned\n", ind, "");
+               return;
+       }
+
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       cpu = apicd->cpu;
+       vector = apicd->vector;
+       prev_cpu = apicd->prev_cpu;
+       prev_vector = apicd->prev_vector;
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+       seq_printf(m, "%*sVector: %5u\n", ind, "", vector);
+       seq_printf(m, "%*sTarget: %5u\n", ind, "", cpu);
+       if (prev_vector) {
+               seq_printf(m, "%*sPrevious vector: %5u\n", ind, "", prev_vector);
+               seq_printf(m, "%*sPrevious target: %5u\n", ind, "", prev_cpu);
+       }
+}
+#endif
+
 static const struct irq_domain_ops x86_vector_domain_ops = {
-       .alloc  = x86_vector_alloc_irqs,
-       .free   = x86_vector_free_irqs,
+       .alloc          = x86_vector_alloc_irqs,
+       .free           = x86_vector_free_irqs,
+       .activate       = x86_vector_activate,
+       .deactivate     = x86_vector_deactivate,
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+       .debug_show     = x86_vector_debug_show,
+#endif
 };
 
 int __init arch_probe_nr_irqs(void)
@@ -419,35 +620,40 @@ int __init arch_probe_nr_irqs(void)
        return legacy_pic->probe();
 }
 
-#ifdef CONFIG_X86_IO_APIC
-static void __init init_legacy_irqs(void)
+void lapic_assign_legacy_vector(unsigned int irq, bool replace)
 {
-       int i, node = cpu_to_node(0);
-       struct apic_chip_data *data;
-
        /*
-        * For legacy IRQ's, start with assigning irq0 to irq15 to
-        * ISA_IRQ_VECTOR(i) for all cpu's.
+        * Use assign system here so it wont get accounted as allocated
+        * and moveable in the cpu hotplug check and it prevents managed
+        * irq reservation from touching it.
         */
-       for (i = 0; i < nr_legacy_irqs(); i++) {
-               data = legacy_irq_data[i] = alloc_apic_chip_data(node);
-               BUG_ON(!data);
+       irq_matrix_assign_system(vector_matrix, ISA_IRQ_VECTOR(irq), replace);
+}
+
+void __init lapic_assign_system_vectors(void)
+{
+       unsigned int i, vector = 0;
 
-               data->cfg.vector = ISA_IRQ_VECTOR(i);
-               cpumask_setall(data->domain);
-               irq_set_chip_data(i, data);
+       for_each_set_bit_from(vector, system_vectors, NR_VECTORS)
+               irq_matrix_assign_system(vector_matrix, vector, false);
+
+       if (nr_legacy_irqs() > 1)
+               lapic_assign_legacy_vector(PIC_CASCADE_IR, false);
+
+       /* System vectors are reserved, online it */
+       irq_matrix_online(vector_matrix);
+
+       /* Mark the preallocated legacy interrupts */
+       for (i = 0; i < nr_legacy_irqs(); i++) {
+               if (i != PIC_CASCADE_IR)
+                       irq_matrix_assign(vector_matrix, ISA_IRQ_VECTOR(i));
        }
 }
-#else
-static inline void init_legacy_irqs(void) { }
-#endif
 
 int __init arch_early_irq_init(void)
 {
        struct fwnode_handle *fn;
 
-       init_legacy_irqs();
-
        fn = irq_domain_alloc_named_fwnode("VECTOR");
        BUG_ON(!fn);
        x86_vector_domain = irq_domain_create_tree(fn, &x86_vector_domain_ops,
@@ -459,100 +665,115 @@ int __init arch_early_irq_init(void)
        arch_init_msi_domain(x86_vector_domain);
        arch_init_htirq_domain(x86_vector_domain);
 
-       BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL));
        BUG_ON(!alloc_cpumask_var(&vector_searchmask, GFP_KERNEL));
-       BUG_ON(!alloc_cpumask_var(&searched_cpumask, GFP_KERNEL));
+
+       /*
+        * Allocate the vector matrix allocator data structure and limit the
+        * search area.
+        */
+       vector_matrix = irq_alloc_matrix(NR_VECTORS, FIRST_EXTERNAL_VECTOR,
+                                        FIRST_SYSTEM_VECTOR);
+       BUG_ON(!vector_matrix);
 
        return arch_early_ioapic_init();
 }
 
-/* Initialize vector_irq on a new cpu */
-static void __setup_vector_irq(int cpu)
+#ifdef CONFIG_SMP
+
+static struct irq_desc *__setup_vector_irq(int vector)
 {
-       struct apic_chip_data *data;
-       struct irq_desc *desc;
-       int irq, vector;
+       int isairq = vector - ISA_IRQ_VECTOR(0);
+
+       /* Check whether the irq is in the legacy space */
+       if (isairq < 0 || isairq >= nr_legacy_irqs())
+               return VECTOR_UNUSED;
+       /* Check whether the irq is handled by the IOAPIC */
+       if (test_bit(isairq, &io_apic_irqs))
+               return VECTOR_UNUSED;
+       return irq_to_desc(isairq);
+}
 
-       /* Mark the inuse vectors */
-       for_each_irq_desc(irq, desc) {
-               struct irq_data *idata = irq_desc_get_irq_data(desc);
+/* Online the local APIC infrastructure and initialize the vectors */
+void lapic_online(void)
+{
+       unsigned int vector;
 
-               data = apic_chip_data(idata);
-               if (!data || !cpumask_test_cpu(cpu, data->domain))
-                       continue;
-               vector = data->cfg.vector;
-               per_cpu(vector_irq, cpu)[vector] = desc;
-       }
-       /* Mark the free vectors */
-       for (vector = 0; vector < NR_VECTORS; ++vector) {
-               desc = per_cpu(vector_irq, cpu)[vector];
-               if (IS_ERR_OR_NULL(desc))
-                       continue;
+       lockdep_assert_held(&vector_lock);
 
-               data = apic_chip_data(irq_desc_get_irq_data(desc));
-               if (!cpumask_test_cpu(cpu, data->domain))
-                       per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
-       }
+       /* Online the vector matrix array for this CPU */
+       irq_matrix_online(vector_matrix);
+
+       /*
+        * The interrupt affinity logic never targets interrupts to offline
+        * CPUs. The exception are the legacy PIC interrupts. In general
+        * they are only targeted to CPU0, but depending on the platform
+        * they can be distributed to any online CPU in hardware. The
+        * kernel has no influence on that. So all active legacy vectors
+        * must be installed on all CPUs. All non legacy interrupts can be
+        * cleared.
+        */
+       for (vector = 0; vector < NR_VECTORS; vector++)
+               this_cpu_write(vector_irq[vector], __setup_vector_irq(vector));
 }
 
-/*
- * Setup the vector to irq mappings. Must be called with vector_lock held.
- */
-void setup_vector_irq(int cpu)
+void lapic_offline(void)
 {
-       int irq;
+       lock_vector_lock();
+       irq_matrix_offline(vector_matrix);
+       unlock_vector_lock();
+}
+
+static int apic_set_affinity(struct irq_data *irqd,
+                            const struct cpumask *dest, bool force)
+{
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
+       int err;
 
-       lockdep_assert_held(&vector_lock);
        /*
-        * On most of the platforms, legacy PIC delivers the interrupts on the
-        * boot cpu. But there are certain platforms where PIC interrupts are
-        * delivered to multiple cpu's. If the legacy IRQ is handled by the
-        * legacy PIC, for the new cpu that is coming online, setup the static
-        * legacy vector to irq mapping:
+        * Core code can call here for inactive interrupts. For inactive
+        * interrupts which use managed or reservation mode there is no
+        * point in going through the vector assignment right now as the
+        * activation will assign a vector which fits the destination
+        * cpumask. Let the core code store the destination mask and be
+        * done with it.
         */
-       for (irq = 0; irq < nr_legacy_irqs(); irq++)
-               per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq_to_desc(irq);
+       if (!irqd_is_activated(irqd) &&
+           (apicd->is_managed || apicd->can_reserve))
+               return IRQ_SET_MASK_OK;
 
-       __setup_vector_irq(cpu);
+       raw_spin_lock(&vector_lock);
+       cpumask_and(vector_searchmask, dest, cpu_online_mask);
+       if (irqd_affinity_is_managed(irqd))
+               err = assign_managed_vector(irqd, vector_searchmask);
+       else
+               err = assign_vector_locked(irqd, vector_searchmask);
+       raw_spin_unlock(&vector_lock);
+       return err ? err : IRQ_SET_MASK_OK;
 }
 
-static int apic_retrigger_irq(struct irq_data *irq_data)
+#else
+# define apic_set_affinity     NULL
+#endif
+
+static int apic_retrigger_irq(struct irq_data *irqd)
 {
-       struct apic_chip_data *data = apic_chip_data(irq_data);
+       struct apic_chip_data *apicd = apic_chip_data(irqd);
        unsigned long flags;
-       int cpu;
 
        raw_spin_lock_irqsave(&vector_lock, flags);
-       cpu = cpumask_first_and(data->domain, cpu_online_mask);
-       apic->send_IPI_mask(cpumask_of(cpu), data->cfg.vector);
+       apic->send_IPI(apicd->cpu, apicd->vector);
        raw_spin_unlock_irqrestore(&vector_lock, flags);
 
        return 1;
 }
 
-void apic_ack_edge(struct irq_data *data)
+void apic_ack_edge(struct irq_data *irqd)
 {
-       irq_complete_move(irqd_cfg(data));
-       irq_move_irq(data);
+       irq_complete_move(irqd_cfg(irqd));
+       irq_move_irq(irqd);
        ack_APIC_irq();
 }
 
-static int apic_set_affinity(struct irq_data *irq_data,
-                            const struct cpumask *dest, bool force)
-{
-       struct apic_chip_data *data = irq_data->chip_data;
-       int err, irq = irq_data->irq;
-
-       if (!IS_ENABLED(CONFIG_SMP))
-               return -EPERM;
-
-       if (!cpumask_intersects(dest, cpu_online_mask))
-               return -EINVAL;
-
-       err = assign_irq_vector(irq, data, dest, irq_data);
-       return err ? err : IRQ_SET_MASK_OK;
-}
-
 static struct irq_chip lapic_controller = {
        .name                   = "APIC",
        .irq_ack                = apic_ack_edge,
@@ -561,115 +782,98 @@ static struct irq_chip lapic_controller = {
 };
 
 #ifdef CONFIG_SMP
-static void __send_cleanup_vector(struct apic_chip_data *data)
-{
-       raw_spin_lock(&vector_lock);
-       cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
-       data->move_in_progress = 0;
-       if (!cpumask_empty(data->old_domain))
-               apic->send_IPI_mask(data->old_domain, IRQ_MOVE_CLEANUP_VECTOR);
-       raw_spin_unlock(&vector_lock);
-}
 
-void send_cleanup_vector(struct irq_cfg *cfg)
+static void free_moved_vector(struct apic_chip_data *apicd)
 {
-       struct apic_chip_data *data;
+       unsigned int vector = apicd->prev_vector;
+       unsigned int cpu = apicd->prev_cpu;
+       bool managed = apicd->is_managed;
 
-       data = container_of(cfg, struct apic_chip_data, cfg);
-       if (data->move_in_progress)
-               __send_cleanup_vector(data);
+       /*
+        * This should never happen. Managed interrupts are not
+        * migrated except on CPU down, which does not involve the
+        * cleanup vector. But try to keep the accounting correct
+        * nevertheless.
+        */
+       WARN_ON_ONCE(managed);
+
+       trace_vector_free_moved(apicd->irq, cpu, vector, managed);
+       irq_matrix_free(vector_matrix, cpu, vector, managed);
+       per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
+       hlist_del_init(&apicd->clist);
+       apicd->prev_vector = 0;
+       apicd->move_in_progress = 0;
 }
 
 asmlinkage __visible void __irq_entry smp_irq_move_cleanup_interrupt(void)
 {
-       unsigned vector, me;
+       struct hlist_head *clhead = this_cpu_ptr(&cleanup_list);
+       struct apic_chip_data *apicd;
+       struct hlist_node *tmp;
 
        entering_ack_irq();
-
        /* Prevent vectors vanishing under us */
        raw_spin_lock(&vector_lock);
 
-       me = smp_processor_id();
-       for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
-               struct apic_chip_data *data;
-               struct irq_desc *desc;
-               unsigned int irr;
-
-       retry:
-               desc = __this_cpu_read(vector_irq[vector]);
-               if (IS_ERR_OR_NULL(desc))
-                       continue;
-
-               if (!raw_spin_trylock(&desc->lock)) {
-                       raw_spin_unlock(&vector_lock);
-                       cpu_relax();
-                       raw_spin_lock(&vector_lock);
-                       goto retry;
-               }
-
-               data = apic_chip_data(irq_desc_get_irq_data(desc));
-               if (!data)
-                       goto unlock;
+       hlist_for_each_entry_safe(apicd, tmp, clhead, clist) {
+               unsigned int irr, vector = apicd->prev_vector;
 
                /*
-                * Nothing to cleanup if irq migration is in progress
-                * or this cpu is not set in the cleanup mask.
-                */
-               if (data->move_in_progress ||
-                   !cpumask_test_cpu(me, data->old_domain))
-                       goto unlock;
-
-               /*
-                * We have two cases to handle here:
-                * 1) vector is unchanged but the target mask got reduced
-                * 2) vector and the target mask has changed
-                *
-                * #1 is obvious, but in #2 we have two vectors with the same
-                * irq descriptor: the old and the new vector. So we need to
-                * make sure that we only cleanup the old vector. The new
-                * vector has the current @vector number in the config and
-                * this cpu is part of the target mask. We better leave that
-                * one alone.
-                */
-               if (vector == data->cfg.vector &&
-                   cpumask_test_cpu(me, data->domain))
-                       goto unlock;
-
-               irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
-               /*
-                * Check if the vector that needs to be cleanedup is
-                * registered at the cpu's IRR. If so, then this is not
-                * the best time to clean it up. Lets clean it up in the
+                * Paranoia: Check if the vector that needs to be cleaned
+                * up is registered at the APICs IRR. If so, then this is
+                * not the best time to clean it up. Clean it up in the
                 * next attempt by sending another IRQ_MOVE_CLEANUP_VECTOR
-                * to myself.
+                * to this CPU. IRQ_MOVE_CLEANUP_VECTOR is the lowest
+                * priority external vector, so on return from this
+                * interrupt the device interrupt will happen first.
                 */
-               if (irr  & (1 << (vector % 32))) {
+               irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
+               if (irr & (1U << (vector % 32))) {
                        apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
-                       goto unlock;
+                       continue;
                }
-               __this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
-               cpumask_clear_cpu(me, data->old_domain);
-unlock:
-               raw_spin_unlock(&desc->lock);
+               free_moved_vector(apicd);
        }
 
        raw_spin_unlock(&vector_lock);
-
        exiting_irq();
 }
 
+static void __send_cleanup_vector(struct apic_chip_data *apicd)
+{
+       unsigned int cpu;
+
+       raw_spin_lock(&vector_lock);
+       apicd->move_in_progress = 0;
+       cpu = apicd->prev_cpu;
+       if (cpu_online(cpu)) {
+               hlist_add_head(&apicd->clist, per_cpu_ptr(&cleanup_list, cpu));
+               apic->send_IPI(cpu, IRQ_MOVE_CLEANUP_VECTOR);
+       } else {
+               apicd->prev_vector = 0;
+       }
+       raw_spin_unlock(&vector_lock);
+}
+
+void send_cleanup_vector(struct irq_cfg *cfg)
+{
+       struct apic_chip_data *apicd;
+
+       apicd = container_of(cfg, struct apic_chip_data, hw_irq_cfg);
+       if (apicd->move_in_progress)
+               __send_cleanup_vector(apicd);
+}
+
 static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
 {
-       unsigned me;
-       struct apic_chip_data *data;
+       struct apic_chip_data *apicd;
 
-       data = container_of(cfg, struct apic_chip_data, cfg);
-       if (likely(!data->move_in_progress))
+       apicd = container_of(cfg, struct apic_chip_data, hw_irq_cfg);
+       if (likely(!apicd->move_in_progress))
                return;
 
-       me = smp_processor_id();
-       if (vector == data->cfg.vector && cpumask_test_cpu(me, data->domain))
-               __send_cleanup_vector(data);
+       if (vector == apicd->vector && apicd->cpu == smp_processor_id())
+               __send_cleanup_vector(apicd);
 }
 
 void irq_complete_move(struct irq_cfg *cfg)
@@ -682,10 +886,9 @@ void irq_complete_move(struct irq_cfg *cfg)
  */
 void irq_force_complete_move(struct irq_desc *desc)
 {
-       struct irq_data *irqdata;
-       struct apic_chip_data *data;
-       struct irq_cfg *cfg;
-       unsigned int cpu;
+       struct apic_chip_data *apicd;
+       struct irq_data *irqd;
+       unsigned int vector;
 
        /*
         * The function is called for all descriptors regardless of which
@@ -696,43 +899,31 @@ void irq_force_complete_move(struct irq_desc *desc)
         * Check first that the chip_data is what we expect
         * (apic_chip_data) before touching it any further.
         */
-       irqdata = irq_domain_get_irq_data(x86_vector_domain,
-                                         irq_desc_get_irq(desc));
-       if (!irqdata)
+       irqd = irq_domain_get_irq_data(x86_vector_domain,
+                                      irq_desc_get_irq(desc));
+       if (!irqd)
                return;
 
-       data = apic_chip_data(irqdata);
-       cfg = data ? &data->cfg : NULL;
+       raw_spin_lock(&vector_lock);
+       apicd = apic_chip_data(irqd);
+       if (!apicd)
+               goto unlock;
 
-       if (!cfg)
-               return;
+       /*
+        * If prev_vector is empty, no action required.
+        */
+       vector = apicd->prev_vector;
+       if (!vector)
+               goto unlock;
 
        /*
-        * This is tricky. If the cleanup of @data->old_domain has not been
+        * This is tricky. If the cleanup of the old vector has not been
         * done yet, then the following setaffinity call will fail with
         * -EBUSY. This can leave the interrupt in a stale state.
         *
         * All CPUs are stuck in stop machine with interrupts disabled so
         * calling __irq_complete_move() would be completely pointless.
-        */
-       raw_spin_lock(&vector_lock);
-       /*
-        * Clean out all offline cpus (including the outgoing one) from the
-        * old_domain mask.
-        */
-       cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
-
-       /*
-        * If move_in_progress is cleared and the old_domain mask is empty,
-        * then there is nothing to cleanup. fixup_irqs() will take care of
-        * the stale vectors on the outgoing cpu.
-        */
-       if (!data->move_in_progress && cpumask_empty(data->old_domain)) {
-               raw_spin_unlock(&vector_lock);
-               return;
-       }
-
-       /*
+        *
         * 1) The interrupt is in move_in_progress state. That means that we
         *    have not seen an interrupt since the io_apic was reprogrammed to
         *    the new vector.
@@ -740,7 +931,7 @@ void irq_force_complete_move(struct irq_desc *desc)
         * 2) The interrupt has fired on the new vector, but the cleanup IPIs
         *    have not been processed yet.
         */
-       if (data->move_in_progress) {
+       if (apicd->move_in_progress) {
                /*
                 * In theory there is a race:
                 *
@@ -774,21 +965,43 @@ void irq_force_complete_move(struct irq_desc *desc)
                 * area arises.
                 */
                pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n",
-                       irqdata->irq, cfg->old_vector);
+                       irqd->irq, vector);
        }
-       /*
-        * If old_domain is not empty, then other cpus still have the irq
-        * descriptor set in their vector array. Clean it up.
-        */
-       for_each_cpu(cpu, data->old_domain)
-               per_cpu(vector_irq, cpu)[cfg->old_vector] = VECTOR_UNUSED;
+       free_moved_vector(apicd);
+unlock:
+       raw_spin_unlock(&vector_lock);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Note, this is not accurate accounting, but at least good enough to
+ * prevent that the actual interrupt move will run out of vectors.
+ */
+int lapic_can_unplug_cpu(void)
+{
+       unsigned int rsvd, avl, tomove, cpu = smp_processor_id();
+       int ret = 0;
 
-       /* Cleanup the left overs of the (half finished) move */
-       cpumask_clear(data->old_domain);
-       data->move_in_progress = 0;
+       raw_spin_lock(&vector_lock);
+       tomove = irq_matrix_allocated(vector_matrix);
+       avl = irq_matrix_available(vector_matrix, true);
+       if (avl < tomove) {
+               pr_warn("CPU %u has %u vectors, %u available. Cannot disable CPU\n",
+                       cpu, tomove, avl);
+               ret = -ENOSPC;
+               goto out;
+       }
+       rsvd = irq_matrix_reserved(vector_matrix);
+       if (avl < rsvd) {
+               pr_warn("Reserved vectors %u > available %u. IRQ request may fail\n",
+                       rsvd, avl);
+       }
+out:
        raw_spin_unlock(&vector_lock);
+       return ret;
 }
-#endif
+#endif /* HOTPLUG_CPU */
+#endif /* SMP */
 
 static void __init print_APIC_field(int base)
 {
diff --git a/arch/x86/kernel/apic/x2apic.h b/arch/x86/kernel/apic/x2apic.h
new file mode 100644 (file)
index 0000000..b107de3
--- /dev/null
@@ -0,0 +1,9 @@
+/* Common bits for X2APIC cluster/physical modes. */
+
+int x2apic_apic_id_valid(int apicid);
+int x2apic_apic_id_registered(void);
+void __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest);
+unsigned int x2apic_get_apic_id(unsigned long id);
+u32 x2apic_set_apic_id(unsigned int id);
+int x2apic_phys_pkg_id(int initial_apicid, int index_msb);
+void x2apic_send_IPI_self(int vector);
index e216cf3d64d2e8432589c6b2fdfaca1b33765bf8..622f13ca8a943c270e70df6100561ce4c56d7db2 100644 (file)
@@ -9,22 +9,24 @@
 #include <linux/cpu.h>
 
 #include <asm/smp.h>
-#include <asm/x2apic.h>
+#include "x2apic.h"
+
+struct cluster_mask {
+       unsigned int    clusterid;
+       int             node;
+       struct cpumask  mask;
+};
 
 static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
-static DEFINE_PER_CPU(cpumask_var_t, cpus_in_cluster);
 static DEFINE_PER_CPU(cpumask_var_t, ipi_mask);
+static DEFINE_PER_CPU(struct cluster_mask *, cluster_masks);
+static struct cluster_mask *cluster_hotplug_mask;
 
 static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
        return x2apic_enabled();
 }
 
-static inline u32 x2apic_cluster(int cpu)
-{
-       return per_cpu(x86_cpu_to_logical_apicid, cpu) >> 16;
-}
-
 static void x2apic_send_IPI(int cpu, int vector)
 {
        u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
@@ -36,49 +38,34 @@ static void x2apic_send_IPI(int cpu, int vector)
 static void
 __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
 {
-       struct cpumask *cpus_in_cluster_ptr;
-       struct cpumask *ipi_mask_ptr;
-       unsigned int cpu, this_cpu;
+       unsigned int cpu, clustercpu;
+       struct cpumask *tmpmsk;
        unsigned long flags;
        u32 dest;
 
        x2apic_wrmsr_fence();
-
        local_irq_save(flags);
 
-       this_cpu = smp_processor_id();
+       tmpmsk = this_cpu_cpumask_var_ptr(ipi_mask);
+       cpumask_copy(tmpmsk, mask);
+       /* If IPI should not be sent to self, clear current CPU */
+       if (apic_dest != APIC_DEST_ALLINC)
+               cpumask_clear_cpu(smp_processor_id(), tmpmsk);
 
-       /*
-        * We are to modify mask, so we need an own copy
-        * and be sure it's manipulated with irq off.
-        */
-       ipi_mask_ptr = this_cpu_cpumask_var_ptr(ipi_mask);
-       cpumask_copy(ipi_mask_ptr, mask);
-
-       /*
-        * The idea is to send one IPI per cluster.
-        */
-       for_each_cpu(cpu, ipi_mask_ptr) {
-               unsigned long i;
+       /* Collapse cpus in a cluster so a single IPI per cluster is sent */
+       for_each_cpu(cpu, tmpmsk) {
+               struct cluster_mask *cmsk = per_cpu(cluster_masks, cpu);
 
-               cpus_in_cluster_ptr = per_cpu(cpus_in_cluster, cpu);
                dest = 0;
-
-               /* Collect cpus in cluster. */
-               for_each_cpu_and(i, ipi_mask_ptr, cpus_in_cluster_ptr) {
-                       if (apic_dest == APIC_DEST_ALLINC || i != this_cpu)
-                               dest |= per_cpu(x86_cpu_to_logical_apicid, i);
-               }
+               for_each_cpu_and(clustercpu, tmpmsk, &cmsk->mask)
+                       dest |= per_cpu(x86_cpu_to_logical_apicid, clustercpu);
 
                if (!dest)
                        continue;
 
                __x2apic_send_IPI_dest(dest, vector, apic->dest_logical);
-               /*
-                * Cluster sibling cpus should be discared now so
-                * we would not send IPI them second time.
-                */
-               cpumask_andnot(ipi_mask_ptr, ipi_mask_ptr, cpus_in_cluster_ptr);
+               /* Remove cluster CPUs from tmpmask */
+               cpumask_andnot(tmpmsk, tmpmsk, &cmsk->mask);
        }
 
        local_irq_restore(flags);
@@ -105,125 +92,90 @@ static void x2apic_send_IPI_all(int vector)
        __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
 }
 
-static int
-x2apic_cpu_mask_to_apicid(const struct cpumask *mask, struct irq_data *irqdata,
-                         unsigned int *apicid)
+static u32 x2apic_calc_apicid(unsigned int cpu)
 {
-       struct cpumask *effmsk = irq_data_get_effective_affinity_mask(irqdata);
-       unsigned int cpu;
-       u32 dest = 0;
-       u16 cluster;
-
-       cpu = cpumask_first(mask);
-       if (cpu >= nr_cpu_ids)
-               return -EINVAL;
-
-       dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
-       cluster = x2apic_cluster(cpu);
-
-       cpumask_clear(effmsk);
-       for_each_cpu(cpu, mask) {
-               if (cluster != x2apic_cluster(cpu))
-                       continue;
-               dest |= per_cpu(x86_cpu_to_logical_apicid, cpu);
-               cpumask_set_cpu(cpu, effmsk);
-       }
-
-       *apicid = dest;
-       return 0;
+       return per_cpu(x86_cpu_to_logical_apicid, cpu);
 }
 
 static void init_x2apic_ldr(void)
 {
-       unsigned int this_cpu = smp_processor_id();
+       struct cluster_mask *cmsk = this_cpu_read(cluster_masks);
+       u32 cluster, apicid = apic_read(APIC_LDR);
        unsigned int cpu;
 
-       per_cpu(x86_cpu_to_logical_apicid, this_cpu) = apic_read(APIC_LDR);
+       this_cpu_write(x86_cpu_to_logical_apicid, apicid);
+
+       if (cmsk)
+               goto update;
 
-       cpumask_set_cpu(this_cpu, per_cpu(cpus_in_cluster, this_cpu));
+       cluster = apicid >> 16;
        for_each_online_cpu(cpu) {
-               if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
-                       continue;
-               cpumask_set_cpu(this_cpu, per_cpu(cpus_in_cluster, cpu));
-               cpumask_set_cpu(cpu, per_cpu(cpus_in_cluster, this_cpu));
+               cmsk = per_cpu(cluster_masks, cpu);
+               /* Matching cluster found. Link and update it. */
+               if (cmsk && cmsk->clusterid == cluster)
+                       goto update;
        }
+       cmsk = cluster_hotplug_mask;
+       cluster_hotplug_mask = NULL;
+update:
+       this_cpu_write(cluster_masks, cmsk);
+       cpumask_set_cpu(smp_processor_id(), &cmsk->mask);
 }
 
-/*
- * At CPU state changes, update the x2apic cluster sibling info.
- */
-static int x2apic_prepare_cpu(unsigned int cpu)
+static int alloc_clustermask(unsigned int cpu, int node)
 {
-       if (!zalloc_cpumask_var(&per_cpu(cpus_in_cluster, cpu), GFP_KERNEL))
-               return -ENOMEM;
+       if (per_cpu(cluster_masks, cpu))
+               return 0;
+       /*
+        * If a hotplug spare mask exists, check whether it's on the right
+        * node. If not, free it and allocate a new one.
+        */
+       if (cluster_hotplug_mask) {
+               if (cluster_hotplug_mask->node == node)
+                       return 0;
+               kfree(cluster_hotplug_mask);
+       }
 
-       if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL)) {
-               free_cpumask_var(per_cpu(cpus_in_cluster, cpu));
+       cluster_hotplug_mask = kzalloc_node(sizeof(*cluster_hotplug_mask),
+                                           GFP_KERNEL, node);
+       if (!cluster_hotplug_mask)
                return -ENOMEM;
-       }
+       cluster_hotplug_mask->node = node;
+       return 0;
+}
 
+static int x2apic_prepare_cpu(unsigned int cpu)
+{
+       if (alloc_clustermask(cpu, cpu_to_node(cpu)) < 0)
+               return -ENOMEM;
+       if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL))
+               return -ENOMEM;
        return 0;
 }
 
-static int x2apic_dead_cpu(unsigned int this_cpu)
+static int x2apic_dead_cpu(unsigned int dead_cpu)
 {
-       int cpu;
+       struct cluster_mask *cmsk = per_cpu(cluster_masks, dead_cpu);
 
-       for_each_online_cpu(cpu) {
-               if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
-                       continue;
-               cpumask_clear_cpu(this_cpu, per_cpu(cpus_in_cluster, cpu));
-               cpumask_clear_cpu(cpu, per_cpu(cpus_in_cluster, this_cpu));
-       }
-       free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
-       free_cpumask_var(per_cpu(ipi_mask, this_cpu));
+       cpumask_clear_cpu(dead_cpu, &cmsk->mask);
+       free_cpumask_var(per_cpu(ipi_mask, dead_cpu));
        return 0;
 }
 
 static int x2apic_cluster_probe(void)
 {
-       int cpu = smp_processor_id();
-       int ret;
-
        if (!x2apic_mode)
                return 0;
 
-       ret = cpuhp_setup_state(CPUHP_X2APIC_PREPARE, "x86/x2apic:prepare",
-                               x2apic_prepare_cpu, x2apic_dead_cpu);
-       if (ret < 0) {
+       if (cpuhp_setup_state(CPUHP_X2APIC_PREPARE, "x86/x2apic:prepare",
+                             x2apic_prepare_cpu, x2apic_dead_cpu) < 0) {
                pr_err("Failed to register X2APIC_PREPARE\n");
                return 0;
        }
-       cpumask_set_cpu(cpu, per_cpu(cpus_in_cluster, cpu));
+       init_x2apic_ldr();
        return 1;
 }
 
-static const struct cpumask *x2apic_cluster_target_cpus(void)
-{
-       return cpu_all_mask;
-}
-
-/*
- * Each x2apic cluster is an allocation domain.
- */
-static void cluster_vector_allocation_domain(int cpu, struct cpumask *retmask,
-                                            const struct cpumask *mask)
-{
-       /*
-        * To minimize vector pressure, default case of boot, device bringup
-        * etc will use a single cpu for the interrupt destination.
-        *
-        * On explicit migration requests coming from irqbalance etc,
-        * interrupts will be routed to the x2apic cluster (cluster-id
-        * derived from the first cpu in the mask) members specified
-        * in the mask.
-        */
-       if (mask == x2apic_cluster_target_cpus())
-               cpumask_copy(retmask, cpumask_of(cpu));
-       else
-               cpumask_and(retmask, mask, per_cpu(cpus_in_cluster, cpu));
-}
-
 static struct apic apic_x2apic_cluster __ro_after_init = {
 
        .name                           = "cluster x2apic",
@@ -235,12 +187,10 @@ static struct apic apic_x2apic_cluster __ro_after_init = {
        .irq_delivery_mode              = dest_LowestPrio,
        .irq_dest_mode                  = 1, /* logical */
 
-       .target_cpus                    = x2apic_cluster_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = APIC_DEST_LOGICAL,
        .check_apicid_used              = NULL,
 
-       .vector_allocation_domain       = cluster_vector_allocation_domain,
        .init_apic_ldr                  = init_x2apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -253,7 +203,7 @@ static struct apic apic_x2apic_cluster __ro_after_init = {
        .get_apic_id                    = x2apic_get_apic_id,
        .set_apic_id                    = x2apic_set_apic_id,
 
-       .cpu_mask_to_apicid             = x2apic_cpu_mask_to_apicid,
+       .calc_dest_apicid               = x2apic_calc_apicid,
 
        .send_IPI                       = x2apic_send_IPI,
        .send_IPI_mask                  = x2apic_send_IPI_mask,
index b94d35320f85e7bcc5d20c4461b43bc848e191b4..f8d9d69994e619f3abb90dbcb135a130cbe257f5 100644 (file)
@@ -7,7 +7,8 @@
 #include <linux/dmar.h>
 
 #include <asm/smp.h>
-#include <asm/x2apic.h>
+#include <asm/ipi.h>
+#include "x2apic.h"
 
 int x2apic_phys;
 
@@ -99,6 +100,43 @@ static int x2apic_phys_probe(void)
        return apic == &apic_x2apic_phys;
 }
 
+/* Common x2apic functions, also used by x2apic_cluster */
+int x2apic_apic_id_valid(int apicid)
+{
+       return 1;
+}
+
+int x2apic_apic_id_registered(void)
+{
+       return 1;
+}
+
+void __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest)
+{
+       unsigned long cfg = __prepare_ICR(0, vector, dest);
+       native_x2apic_icr_write(cfg, apicid);
+}
+
+unsigned int x2apic_get_apic_id(unsigned long id)
+{
+       return id;
+}
+
+u32 x2apic_set_apic_id(unsigned int id)
+{
+       return id;
+}
+
+int x2apic_phys_pkg_id(int initial_apicid, int index_msb)
+{
+       return initial_apicid >> index_msb;
+}
+
+void x2apic_send_IPI_self(int vector)
+{
+       apic_write(APIC_SELF_IPI, vector);
+}
+
 static struct apic apic_x2apic_phys __ro_after_init = {
 
        .name                           = "physical x2apic",
@@ -110,12 +148,10 @@ static struct apic apic_x2apic_phys __ro_after_init = {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* physical */
 
-       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = 0,
        .check_apicid_used              = NULL,
 
-       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = init_x2apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -128,7 +164,7 @@ static struct apic apic_x2apic_phys __ro_after_init = {
        .get_apic_id                    = x2apic_get_apic_id,
        .set_apic_id                    = x2apic_set_apic_id,
 
-       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_default_calc_apicid,
 
        .send_IPI                       = x2apic_send_IPI,
        .send_IPI_mask                  = x2apic_send_IPI_mask,
index 0d57bb9079c998173f31bc2f4b73032caf23331b..e1b8e8bf6b3c2572b30f0de39957c602abc2434d 100644 (file)
@@ -154,6 +154,48 @@ static int __init early_get_pnodeid(void)
        return pnode;
 }
 
+static void __init uv_tsc_check_sync(void)
+{
+       u64 mmr;
+       int sync_state;
+       int mmr_shift;
+       char *state;
+       bool valid;
+
+       /* Accommodate different UV arch BIOSes */
+       mmr = uv_early_read_mmr(UVH_TSC_SYNC_MMR);
+       mmr_shift =
+               is_uv1_hub() ? 0 :
+               is_uv2_hub() ? UVH_TSC_SYNC_SHIFT_UV2K : UVH_TSC_SYNC_SHIFT;
+       if (mmr_shift)
+               sync_state = (mmr >> mmr_shift) & UVH_TSC_SYNC_MASK;
+       else
+               sync_state = 0;
+
+       switch (sync_state) {
+       case UVH_TSC_SYNC_VALID:
+               state = "in sync";
+               valid = true;
+               break;
+
+       case UVH_TSC_SYNC_INVALID:
+               state = "unstable";
+               valid = false;
+               break;
+       default:
+               state = "unknown: assuming valid";
+               valid = true;
+               break;
+       }
+       pr_info("UV: TSC sync state from BIOS:0%d(%s)\n", sync_state, state);
+
+       /* Mark flag that says TSC != 0 is valid for socket 0 */
+       if (valid)
+               mark_tsc_async_resets("UV BIOS");
+       else
+               mark_tsc_unstable("UV BIOS");
+}
+
 /* [Copied from arch/x86/kernel/cpu/topology.c:detect_extended_topology()] */
 
 #define SMT_LEVEL                      0       /* Leaf 0xb SMT level */
@@ -288,6 +330,7 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
        }
 
        pr_info("UV: OEM IDs %s/%s, System/HUB Types %d/%d, uv_apic %d\n", oem_id, oem_table_id, uv_system_type, uv_min_hub_revision_id, uv_apic);
+       uv_tsc_check_sync();
 
        return uv_apic;
 
@@ -525,16 +568,9 @@ static void uv_init_apic_ldr(void)
 {
 }
 
-static int
-uv_cpu_mask_to_apicid(const struct cpumask *mask, struct irq_data *irqdata,
-                     unsigned int *apicid)
+static u32 apic_uv_calc_apicid(unsigned int cpu)
 {
-       int ret = default_cpu_mask_to_apicid(mask, irqdata, apicid);
-
-       if (!ret)
-               *apicid |= uv_apicid_hibits;
-
-       return ret;
+       return apic_default_calc_apicid(cpu) | uv_apicid_hibits;
 }
 
 static unsigned int x2apic_get_apic_id(unsigned long x)
@@ -547,7 +583,7 @@ static unsigned int x2apic_get_apic_id(unsigned long x)
        return id;
 }
 
-static unsigned long set_apic_id(unsigned int id)
+static u32 set_apic_id(unsigned int id)
 {
        /* CHECKME: Do we need to mask out the xapic extra bits? */
        return id;
@@ -584,12 +620,10 @@ static struct apic apic_x2apic_uv_x __ro_after_init = {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* Physical */
 
-       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = APIC_DEST_LOGICAL,
        .check_apicid_used              = NULL,
 
-       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = uv_init_apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -602,7 +636,7 @@ static struct apic apic_x2apic_uv_x __ro_after_init = {
        .get_apic_id                    = x2apic_get_apic_id,
        .set_apic_id                    = set_apic_id,
 
-       .cpu_mask_to_apicid             = uv_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_uv_calc_apicid,
 
        .send_IPI                       = uv_send_IPI_one,
        .send_IPI_mask                  = uv_send_IPI_mask,
@@ -920,9 +954,8 @@ static __init void uv_rtc_init(void)
 /*
  * percpu heartbeat timer
  */
-static void uv_heartbeat(unsigned long ignored)
+static void uv_heartbeat(struct timer_list *timer)
 {
-       struct timer_list *timer = &uv_scir_info->timer;
        unsigned char bits = uv_scir_info->state;
 
        /* Flip heartbeat bit: */
@@ -947,7 +980,7 @@ static int uv_heartbeat_enable(unsigned int cpu)
                struct timer_list *timer = &uv_cpu_scir_info(cpu)->timer;
 
                uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY);
-               setup_pinned_timer(timer, uv_heartbeat, cpu);
+               timer_setup(timer, uv_heartbeat, TIMER_PINNED);
                timer->expires = jiffies + SCIR_CPU_HB_INTERVAL;
                add_timer_on(timer, cpu);
                uv_cpu_scir_info(cpu)->enabled = 1;
index 236999c54edce69820fcf372a918db9899a5eef5..90cb82dbba577cc3bd7dd1e9cf63ef9b89c89daa 100644 (file)
@@ -22,7 +22,8 @@ obj-y                 += common.o
 obj-y                  += rdrand.o
 obj-y                  += match.o
 obj-y                  += bugs.o
-obj-y                  += aperfmperf.o
+obj-$(CONFIG_CPU_FREQ) += aperfmperf.o
+obj-y                  += cpuid-deps.o
 
 obj-$(CONFIG_PROC_FS)  += proc.o
 obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
index c9176bae7fd8cdb0e85f6d60766a809b9b36aa42..13ae9e5eec2f5c8e40f89f2ecd077fc852d8d32c 100644 (file)
@@ -329,6 +329,28 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c)
        }
 }
 
+static __always_inline void setup_umip(struct cpuinfo_x86 *c)
+{
+       /* Check the boot processor, plus build option for UMIP. */
+       if (!cpu_feature_enabled(X86_FEATURE_UMIP))
+               goto out;
+
+       /* Check the current processor's cpuid bits. */
+       if (!cpu_has(c, X86_FEATURE_UMIP))
+               goto out;
+
+       cr4_set_bits(X86_CR4_UMIP);
+
+       return;
+
+out:
+       /*
+        * Make sure UMIP is disabled in case it was enabled in a
+        * previous boot (e.g., via kexec).
+        */
+       cr4_clear_bits(X86_CR4_UMIP);
+}
+
 /*
  * Protection Keys are not available in 32-bit mode.
  */
@@ -863,8 +885,8 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
  * cache alignment.
  * The others are not touched to avoid unwanted side effects.
  *
- * WARNING: this function is only called on the BP.  Don't add code here
- * that is supposed to run on all CPUs.
+ * WARNING: this function is only called on the boot CPU.  Don't add code
+ * here that is supposed to run on all CPUs.
  */
 static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
@@ -1147,9 +1169,10 @@ static void identify_cpu(struct cpuinfo_x86 *c)
        /* Disable the PN if appropriate */
        squash_the_stupid_serial_number(c);
 
-       /* Set up SMEP/SMAP */
+       /* Set up SMEP/SMAP/UMIP */
        setup_smep(c);
        setup_smap(c);
+       setup_umip(c);
 
        /*
         * The vendor-specific functions might have changed features.
@@ -1301,18 +1324,16 @@ void print_cpu_info(struct cpuinfo_x86 *c)
                pr_cont(")\n");
 }
 
-static __init int setup_disablecpuid(char *arg)
+/*
+ * clearcpuid= was already parsed in fpu__init_parse_early_param.
+ * But we need to keep a dummy __setup around otherwise it would
+ * show up as an environment variable for init.
+ */
+static __init int setup_clearcpuid(char *arg)
 {
-       int bit;
-
-       if (get_option(&arg, &bit) && bit >= 0 && bit < NCAPINTS * 32)
-               setup_clear_cpu_cap(bit);
-       else
-               return 0;
-
        return 1;
 }
-__setup("clearcpuid=", setup_disablecpuid);
+__setup("clearcpuid=", setup_clearcpuid);
 
 #ifdef CONFIG_X86_64
 DEFINE_PER_CPU_FIRST(union irq_stack_union,
@@ -1572,9 +1593,13 @@ void cpu_init(void)
        initialize_tlbstate_and_flush();
        enter_lazy_tlb(&init_mm, me);
 
-       load_sp0(t, &current->thread);
+       /*
+        * Initialize the TSS.  Don't bother initializing sp0, as the initial
+        * task never enters user mode.
+        */
        set_tss_desc(cpu, t);
        load_TR_desc();
+
        load_mm_ldt(&init_mm);
 
        clear_all_debug_regs();
@@ -1596,7 +1621,6 @@ void cpu_init(void)
        int cpu = smp_processor_id();
        struct task_struct *curr = current;
        struct tss_struct *t = &per_cpu(cpu_tss, cpu);
-       struct thread_struct *thread = &curr->thread;
 
        wait_for_master_cpu(cpu);
 
@@ -1627,9 +1651,13 @@ void cpu_init(void)
        initialize_tlbstate_and_flush();
        enter_lazy_tlb(&init_mm, curr);
 
-       load_sp0(t, thread);
+       /*
+        * Initialize the TSS.  Don't bother initializing sp0, as the initial
+        * task never enters user mode.
+        */
        set_tss_desc(cpu, t);
        load_TR_desc();
+
        load_mm_ldt(&init_mm);
 
        t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
new file mode 100644 (file)
index 0000000..904b0a3
--- /dev/null
@@ -0,0 +1,121 @@
+/* Declare dependencies between CPUIDs */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/cpufeature.h>
+
+struct cpuid_dep {
+       unsigned int    feature;
+       unsigned int    depends;
+};
+
+/*
+ * Table of CPUID features that depend on others.
+ *
+ * This only includes dependencies that can be usefully disabled, not
+ * features part of the base set (like FPU).
+ *
+ * Note this all is not __init / __initdata because it can be
+ * called from cpu hotplug. It shouldn't do anything in this case,
+ * but it's difficult to tell that to the init reference checker.
+ */
+const static struct cpuid_dep cpuid_deps[] = {
+       { X86_FEATURE_XSAVEOPT,         X86_FEATURE_XSAVE     },
+       { X86_FEATURE_XSAVEC,           X86_FEATURE_XSAVE     },
+       { X86_FEATURE_XSAVES,           X86_FEATURE_XSAVE     },
+       { X86_FEATURE_AVX,              X86_FEATURE_XSAVE     },
+       { X86_FEATURE_PKU,              X86_FEATURE_XSAVE     },
+       { X86_FEATURE_MPX,              X86_FEATURE_XSAVE     },
+       { X86_FEATURE_XGETBV1,          X86_FEATURE_XSAVE     },
+       { X86_FEATURE_FXSR_OPT,         X86_FEATURE_FXSR      },
+       { X86_FEATURE_XMM,              X86_FEATURE_FXSR      },
+       { X86_FEATURE_XMM2,             X86_FEATURE_XMM       },
+       { X86_FEATURE_XMM3,             X86_FEATURE_XMM2      },
+       { X86_FEATURE_XMM4_1,           X86_FEATURE_XMM2      },
+       { X86_FEATURE_XMM4_2,           X86_FEATURE_XMM2      },
+       { X86_FEATURE_XMM3,             X86_FEATURE_XMM2      },
+       { X86_FEATURE_PCLMULQDQ,        X86_FEATURE_XMM2      },
+       { X86_FEATURE_SSSE3,            X86_FEATURE_XMM2,     },
+       { X86_FEATURE_F16C,             X86_FEATURE_XMM2,     },
+       { X86_FEATURE_AES,              X86_FEATURE_XMM2      },
+       { X86_FEATURE_SHA_NI,           X86_FEATURE_XMM2      },
+       { X86_FEATURE_FMA,              X86_FEATURE_AVX       },
+       { X86_FEATURE_AVX2,             X86_FEATURE_AVX,      },
+       { X86_FEATURE_AVX512F,          X86_FEATURE_AVX,      },
+       { X86_FEATURE_AVX512IFMA,       X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512PF,         X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512ER,         X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512CD,         X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512DQ,         X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512BW,         X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512VL,         X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512VBMI,       X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512_VBMI2,     X86_FEATURE_AVX512VL  },
+       { X86_FEATURE_GFNI,             X86_FEATURE_AVX512VL  },
+       { X86_FEATURE_VAES,             X86_FEATURE_AVX512VL  },
+       { X86_FEATURE_VPCLMULQDQ,       X86_FEATURE_AVX512VL  },
+       { X86_FEATURE_AVX512_VNNI,      X86_FEATURE_AVX512VL  },
+       { X86_FEATURE_AVX512_BITALG,    X86_FEATURE_AVX512VL  },
+       { X86_FEATURE_AVX512_4VNNIW,    X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512_4FMAPS,    X86_FEATURE_AVX512F   },
+       { X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F   },
+       {}
+};
+
+static inline void clear_feature(struct cpuinfo_x86 *c, unsigned int feature)
+{
+       /*
+        * Note: This could use the non atomic __*_bit() variants, but the
+        * rest of the cpufeature code uses atomics as well, so keep it for
+        * consistency. Cleanup all of it separately.
+        */
+       if (!c) {
+               clear_cpu_cap(&boot_cpu_data, feature);
+               set_bit(feature, (unsigned long *)cpu_caps_cleared);
+       } else {
+               clear_bit(feature, (unsigned long *)c->x86_capability);
+       }
+}
+
+/* Take the capabilities and the BUG bits into account */
+#define MAX_FEATURE_BITS ((NCAPINTS + NBUGINTS) * sizeof(u32) * 8)
+
+static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
+{
+       DECLARE_BITMAP(disable, MAX_FEATURE_BITS);
+       const struct cpuid_dep *d;
+       bool changed;
+
+       if (WARN_ON(feature >= MAX_FEATURE_BITS))
+               return;
+
+       clear_feature(c, feature);
+
+       /* Collect all features to disable, handling dependencies */
+       memset(disable, 0, sizeof(disable));
+       __set_bit(feature, disable);
+
+       /* Loop until we get a stable state. */
+       do {
+               changed = false;
+               for (d = cpuid_deps; d->feature; d++) {
+                       if (!test_bit(d->depends, disable))
+                               continue;
+                       if (__test_and_set_bit(d->feature, disable))
+                               continue;
+
+                       changed = true;
+                       clear_feature(c, d->feature);
+               }
+       } while (changed);
+}
+
+void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
+{
+       do_clear_cpu_cap(c, feature);
+}
+
+void setup_clear_cpu_cap(unsigned int feature)
+{
+       do_clear_cpu_cap(NULL, feature);
+}
index 4fa90006ac68cbeade534020a689c4a07b4f0e60..bea8d3e24f508704ca80210e6b864bd07e51bfc5 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;
+
 static const __initconst struct hypervisor_x86 * const hypervisors[] =
 {
 #ifdef CONFIG_XEN_PV
@@ -41,54 +47,52 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] =
 #endif
 };
 
-const struct hypervisor_x86 *x86_hyper;
-EXPORT_SYMBOL(x86_hyper);
+enum x86_hypervisor_type x86_hyper_type;
+EXPORT_SYMBOL(x86_hyper_type);
 
-static inline void __init
+static inline const struct hypervisor_x86 * __init
 detect_hypervisor_vendor(void)
 {
-       const struct hypervisor_x86 *h, * const *p;
+       const struct hypervisor_x86 *h = NULL, * const *p;
        uint32_t pri, max_pri = 0;
 
        for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
-               h = *p;
-               pri = h->detect();
-               if (pri != 0 && pri > max_pri) {
+               pri = (*p)->detect();
+               if (pri > max_pri) {
                        max_pri = pri;
-                       x86_hyper = h;
+                       h = *p;
                }
        }
 
-       if (max_pri)
-               pr_info("Hypervisor detected: %s\n", x86_hyper->name);
+       if (h)
+               pr_info("Hypervisor detected: %s\n", h->name);
+
+       return h;
 }
 
-void __init init_hypervisor_platform(void)
+static void __init copy_array(const void *src, void *target, unsigned int size)
 {
+       unsigned int i, n = size / sizeof(void *);
+       const void * const *from = (const void * const *)src;
+       const void **to = (const void **)target;
 
-       detect_hypervisor_vendor();
-
-       if (!x86_hyper)
-               return;
-
-       if (x86_hyper->init_platform)
-               x86_hyper->init_platform();
+       for (i = 0; i < n; i++)
+               if (from[i])
+                       to[i] = from[i];
 }
 
-bool __init hypervisor_x2apic_available(void)
+void __init init_hypervisor_platform(void)
 {
-       return x86_hyper                   &&
-              x86_hyper->x2apic_available &&
-              x86_hyper->x2apic_available();
-}
+       const struct hypervisor_x86 *h;
 
-void hypervisor_pin_vcpu(int cpu)
-{
-       if (!x86_hyper)
+       h = detect_hypervisor_vendor();
+
+       if (!h)
                return;
 
-       if (x86_hyper->pin_vcpu)
-               x86_hyper->pin_vcpu(cpu);
-       else
-               WARN_ONCE(1, "vcpu pinning requested but not supported!\n");
+       copy_array(&h->init, &x86_init.hyper, sizeof(h->init));
+       copy_array(&h->runtime, &x86_platform.hyper, sizeof(h->runtime));
+
+       x86_hyper_type = h->type;
+       x86_init.hyper.init_platform();
 }
index cd5fc61ba45020f66bb8e619b4c033eb6b786a63..88dcf8479013569e93a58c278badaf690c29a27b 100644 (file)
@@ -267,6 +267,7 @@ static void rdt_get_cdp_l3_config(int type)
        r->num_closid = r_l3->num_closid / 2;
        r->cache.cbm_len = r_l3->cache.cbm_len;
        r->default_ctrl = r_l3->default_ctrl;
+       r->cache.shareable_bits = r_l3->cache.shareable_bits;
        r->data_width = (r->cache.cbm_len + 3) / 4;
        r->alloc_capable = true;
        /*
index a43a72d8e88e45ef76a2dee5e5a4abbd0ecab308..3397244984f559ec405ab82b242b82ad5ee49c7f 100644 (file)
@@ -127,12 +127,15 @@ struct rdtgroup {
 #define RFTYPE_BASE                    BIT(1)
 #define RF_CTRLSHIFT                   4
 #define RF_MONSHIFT                    5
+#define RF_TOPSHIFT                    6
 #define RFTYPE_CTRL                    BIT(RF_CTRLSHIFT)
 #define RFTYPE_MON                     BIT(RF_MONSHIFT)
+#define RFTYPE_TOP                     BIT(RF_TOPSHIFT)
 #define RFTYPE_RES_CACHE               BIT(8)
 #define RFTYPE_RES_MB                  BIT(9)
 #define RF_CTRL_INFO                   (RFTYPE_INFO | RFTYPE_CTRL)
 #define RF_MON_INFO                    (RFTYPE_INFO | RFTYPE_MON)
+#define RF_TOP_INFO                    (RFTYPE_INFO | RFTYPE_TOP)
 #define RF_CTRL_BASE                   (RFTYPE_BASE | RFTYPE_CTRL)
 
 /* List of all resource groups */
@@ -409,6 +412,10 @@ union cpuid_0x10_x_edx {
        unsigned int full;
 };
 
+void rdt_last_cmd_clear(void);
+void rdt_last_cmd_puts(const char *s);
+void rdt_last_cmd_printf(const char *fmt, ...);
+
 void rdt_ctrl_update(void *arg);
 struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn);
 void rdtgroup_kn_unlock(struct kernfs_node *kn);
index f6ea94f8954a7d5e862b4f25a98b963d664007ec..23e1d5c249c60bca179e2ede61a98366e426beec 100644 (file)
@@ -42,15 +42,22 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
        /*
         * Only linear delay values is supported for current Intel SKUs.
         */
-       if (!r->membw.delay_linear)
+       if (!r->membw.delay_linear) {
+               rdt_last_cmd_puts("No support for non-linear MB domains\n");
                return false;
+       }
 
        ret = kstrtoul(buf, 10, &bw);
-       if (ret)
+       if (ret) {
+               rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf);
                return false;
+       }
 
-       if (bw < r->membw.min_bw || bw > r->default_ctrl)
+       if (bw < r->membw.min_bw || bw > r->default_ctrl) {
+               rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", bw,
+                                   r->membw.min_bw, r->default_ctrl);
                return false;
+       }
 
        *data = roundup(bw, (unsigned long)r->membw.bw_gran);
        return true;
@@ -60,8 +67,10 @@ int parse_bw(char *buf, struct rdt_resource *r, struct rdt_domain *d)
 {
        unsigned long data;
 
-       if (d->have_new_ctrl)
+       if (d->have_new_ctrl) {
+               rdt_last_cmd_printf("duplicate domain %d\n", d->id);
                return -EINVAL;
+       }
 
        if (!bw_validate(buf, &data, r))
                return -EINVAL;
@@ -84,20 +93,29 @@ static bool cbm_validate(char *buf, unsigned long *data, struct rdt_resource *r)
        int ret;
 
        ret = kstrtoul(buf, 16, &val);
-       if (ret)
+       if (ret) {
+               rdt_last_cmd_printf("non-hex character in mask %s\n", buf);
                return false;
+       }
 
-       if (val == 0 || val > r->default_ctrl)
+       if (val == 0 || val > r->default_ctrl) {
+               rdt_last_cmd_puts("mask out of range\n");
                return false;
+       }
 
        first_bit = find_first_bit(&val, cbm_len);
        zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
 
-       if (find_next_bit(&val, cbm_len, zero_bit) < cbm_len)
+       if (find_next_bit(&val, cbm_len, zero_bit) < cbm_len) {
+               rdt_last_cmd_printf("mask %lx has non-consecutive 1-bits\n", val);
                return false;
+       }
 
-       if ((zero_bit - first_bit) < r->cache.min_cbm_bits)
+       if ((zero_bit - first_bit) < r->cache.min_cbm_bits) {
+               rdt_last_cmd_printf("Need at least %d bits in mask\n",
+                                   r->cache.min_cbm_bits);
                return false;
+       }
 
        *data = val;
        return true;
@@ -111,8 +129,10 @@ int parse_cbm(char *buf, struct rdt_resource *r, struct rdt_domain *d)
 {
        unsigned long data;
 
-       if (d->have_new_ctrl)
+       if (d->have_new_ctrl) {
+               rdt_last_cmd_printf("duplicate domain %d\n", d->id);
                return -EINVAL;
+       }
 
        if(!cbm_validate(buf, &data, r))
                return -EINVAL;
@@ -139,8 +159,10 @@ next:
                return 0;
        dom = strsep(&line, ";");
        id = strsep(&dom, "=");
-       if (!dom || kstrtoul(id, 10, &dom_id))
+       if (!dom || kstrtoul(id, 10, &dom_id)) {
+               rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
                return -EINVAL;
+       }
        dom = strim(dom);
        list_for_each_entry(d, &r->domains, list) {
                if (d->id == dom_id) {
@@ -196,6 +218,7 @@ static int rdtgroup_parse_resource(char *resname, char *tok, int closid)
                if (!strcmp(resname, r->name) && closid < r->num_closid)
                        return parse_line(tok, r);
        }
+       rdt_last_cmd_printf("unknown/unsupported resource name '%s'\n", resname);
        return -EINVAL;
 }
 
@@ -218,6 +241,7 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
                rdtgroup_kn_unlock(of->kn);
                return -ENOENT;
        }
+       rdt_last_cmd_clear();
 
        closid = rdtgrp->closid;
 
@@ -229,6 +253,12 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
        while ((tok = strsep(&buf, "\n")) != NULL) {
                resname = strim(strsep(&tok, ":"));
                if (!tok) {
+                       rdt_last_cmd_puts("Missing ':'\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (tok[0] == '\0') {
+                       rdt_last_cmd_printf("Missing '%s' value\n", resname);
                        ret = -EINVAL;
                        goto out;
                }
index 30827510094befb37aec9be1b356201a3644dd5e..681450eee428b8b07f9fb3a3b1fd5551a5c18cec 100644 (file)
@@ -51,7 +51,7 @@ static LIST_HEAD(rmid_free_lru);
  *     may have a occupancy value > intel_cqm_threshold. User can change
  *     the threshold occupancy value.
  */
-unsigned int rmid_limbo_count;
+static unsigned int rmid_limbo_count;
 
 /**
  * @rmid_entry - The entry in the limbo and free lists.
index a869d4a073c5ced61e19977eccaa94cf8891e208..64c5ff97ee0d76c98e2e76869ddc30475a602599 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fs.h>
 #include <linux/sysfs.h>
 #include <linux/kernfs.h>
+#include <linux/seq_buf.h>
 #include <linux/seq_file.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/task.h>
@@ -51,6 +52,31 @@ static struct kernfs_node *kn_mongrp;
 /* Kernel fs node for "mon_data" directory under root */
 static struct kernfs_node *kn_mondata;
 
+static struct seq_buf last_cmd_status;
+static char last_cmd_status_buf[512];
+
+void rdt_last_cmd_clear(void)
+{
+       lockdep_assert_held(&rdtgroup_mutex);
+       seq_buf_clear(&last_cmd_status);
+}
+
+void rdt_last_cmd_puts(const char *s)
+{
+       lockdep_assert_held(&rdtgroup_mutex);
+       seq_buf_puts(&last_cmd_status, s);
+}
+
+void rdt_last_cmd_printf(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       lockdep_assert_held(&rdtgroup_mutex);
+       seq_buf_vprintf(&last_cmd_status, fmt, ap);
+       va_end(ap);
+}
+
 /*
  * Trivial allocator for CLOSIDs. Since h/w only supports a small number,
  * we can keep a bitmap of free CLOSIDs in a single integer.
@@ -238,8 +264,10 @@ static int cpus_mon_write(struct rdtgroup *rdtgrp, cpumask_var_t newmask,
 
        /* Check whether cpus belong to parent ctrl group */
        cpumask_andnot(tmpmask, newmask, &prgrp->cpu_mask);
-       if (cpumask_weight(tmpmask))
+       if (cpumask_weight(tmpmask)) {
+               rdt_last_cmd_puts("can only add CPUs to mongroup that belong to parent\n");
                return -EINVAL;
+       }
 
        /* Check whether cpus are dropped from this group */
        cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
@@ -291,8 +319,10 @@ static int cpus_ctrl_write(struct rdtgroup *rdtgrp, cpumask_var_t newmask,
        cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
        if (cpumask_weight(tmpmask)) {
                /* Can't drop from default group */
-               if (rdtgrp == &rdtgroup_default)
+               if (rdtgrp == &rdtgroup_default) {
+                       rdt_last_cmd_puts("Can't drop CPUs from default group\n");
                        return -EINVAL;
+               }
 
                /* Give any dropped cpus to rdtgroup_default */
                cpumask_or(&rdtgroup_default.cpu_mask,
@@ -357,8 +387,10 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
        }
 
        rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       rdt_last_cmd_clear();
        if (!rdtgrp) {
                ret = -ENOENT;
+               rdt_last_cmd_puts("directory was removed\n");
                goto unlock;
        }
 
@@ -367,13 +399,16 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
        else
                ret = cpumask_parse(buf, newmask);
 
-       if (ret)
+       if (ret) {
+               rdt_last_cmd_puts("bad cpu list/mask\n");
                goto unlock;
+       }
 
        /* check that user didn't specify any offline cpus */
        cpumask_andnot(tmpmask, newmask, cpu_online_mask);
        if (cpumask_weight(tmpmask)) {
                ret = -EINVAL;
+               rdt_last_cmd_puts("can only assign online cpus\n");
                goto unlock;
        }
 
@@ -452,6 +487,7 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
                 */
                atomic_dec(&rdtgrp->waitcount);
                kfree(callback);
+               rdt_last_cmd_puts("task exited\n");
        } else {
                /*
                 * For ctrl_mon groups move both closid and rmid.
@@ -462,10 +498,12 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
                        tsk->closid = rdtgrp->closid;
                        tsk->rmid = rdtgrp->mon.rmid;
                } else if (rdtgrp->type == RDTMON_GROUP) {
-                       if (rdtgrp->mon.parent->closid == tsk->closid)
+                       if (rdtgrp->mon.parent->closid == tsk->closid) {
                                tsk->rmid = rdtgrp->mon.rmid;
-                       else
+                       } else {
+                               rdt_last_cmd_puts("Can't move task to different control group\n");
                                ret = -EINVAL;
+                       }
                }
        }
        return ret;
@@ -484,8 +522,10 @@ static int rdtgroup_task_write_permission(struct task_struct *task,
         */
        if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
            !uid_eq(cred->euid, tcred->uid) &&
-           !uid_eq(cred->euid, tcred->suid))
+           !uid_eq(cred->euid, tcred->suid)) {
+               rdt_last_cmd_printf("No permission to move task %d\n", task->pid);
                ret = -EPERM;
+       }
 
        put_cred(tcred);
        return ret;
@@ -502,6 +542,7 @@ static int rdtgroup_move_task(pid_t pid, struct rdtgroup *rdtgrp,
                tsk = find_task_by_vpid(pid);
                if (!tsk) {
                        rcu_read_unlock();
+                       rdt_last_cmd_printf("No task %d\n", pid);
                        return -ESRCH;
                }
        } else {
@@ -529,6 +570,7 @@ static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
        if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)
                return -EINVAL;
        rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       rdt_last_cmd_clear();
 
        if (rdtgrp)
                ret = rdtgroup_move_task(pid, rdtgrp, of);
@@ -569,6 +611,21 @@ static int rdtgroup_tasks_show(struct kernfs_open_file *of,
        return ret;
 }
 
+static int rdt_last_cmd_status_show(struct kernfs_open_file *of,
+                                   struct seq_file *seq, void *v)
+{
+       int len;
+
+       mutex_lock(&rdtgroup_mutex);
+       len = seq_buf_used(&last_cmd_status);
+       if (len)
+               seq_printf(seq, "%.*s", len, last_cmd_status_buf);
+       else
+               seq_puts(seq, "ok\n");
+       mutex_unlock(&rdtgroup_mutex);
+       return 0;
+}
+
 static int rdt_num_closids_show(struct kernfs_open_file *of,
                                struct seq_file *seq, void *v)
 {
@@ -685,6 +742,13 @@ static ssize_t max_threshold_occ_write(struct kernfs_open_file *of,
 
 /* rdtgroup information files for one cache resource. */
 static struct rftype res_common_files[] = {
+       {
+               .name           = "last_cmd_status",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_last_cmd_status_show,
+               .fflags         = RF_TOP_INFO,
+       },
        {
                .name           = "num_closids",
                .mode           = 0444,
@@ -855,6 +919,10 @@ static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn)
                return PTR_ERR(kn_info);
        kernfs_get(kn_info);
 
+       ret = rdtgroup_add_files(kn_info, RF_TOP_INFO);
+       if (ret)
+               goto out_destroy;
+
        for_each_alloc_enabled_rdt_resource(r) {
                fflags =  r->fflags | RF_CTRL_INFO;
                ret = rdtgroup_mkdir_info_resdir(r, r->name, fflags);
@@ -1081,6 +1149,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
        struct dentry *dentry;
        int ret;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
        /*
         * resctrl file system can only be mounted once.
@@ -1130,12 +1199,12 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
                goto out_mondata;
 
        if (rdt_alloc_capable)
-               static_branch_enable(&rdt_alloc_enable_key);
+               static_branch_enable_cpuslocked(&rdt_alloc_enable_key);
        if (rdt_mon_capable)
-               static_branch_enable(&rdt_mon_enable_key);
+               static_branch_enable_cpuslocked(&rdt_mon_enable_key);
 
        if (rdt_alloc_capable || rdt_mon_capable)
-               static_branch_enable(&rdt_enable_key);
+               static_branch_enable_cpuslocked(&rdt_enable_key);
 
        if (is_mbm_enabled()) {
                r = &rdt_resources_all[RDT_RESOURCE_L3];
@@ -1156,7 +1225,9 @@ out_info:
 out_cdp:
        cdp_disable();
 out:
+       rdt_last_cmd_clear();
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 
        return dentry;
 }
@@ -1295,9 +1366,7 @@ static void rmdir_all_sub(void)
                kfree(rdtgrp);
        }
        /* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */
-       get_online_cpus();
        update_closid_rmid(cpu_online_mask, &rdtgroup_default);
-       put_online_cpus();
 
        kernfs_remove(kn_info);
        kernfs_remove(kn_mongrp);
@@ -1308,6 +1377,7 @@ static void rdt_kill_sb(struct super_block *sb)
 {
        struct rdt_resource *r;
 
+       cpus_read_lock();
        mutex_lock(&rdtgroup_mutex);
 
        /*Put everything back to default values. */
@@ -1315,11 +1385,12 @@ static void rdt_kill_sb(struct super_block *sb)
                reset_all_ctrls(r);
        cdp_disable();
        rmdir_all_sub();
-       static_branch_disable(&rdt_alloc_enable_key);
-       static_branch_disable(&rdt_mon_enable_key);
-       static_branch_disable(&rdt_enable_key);
+       static_branch_disable_cpuslocked(&rdt_alloc_enable_key);
+       static_branch_disable_cpuslocked(&rdt_mon_enable_key);
+       static_branch_disable_cpuslocked(&rdt_enable_key);
        kernfs_kill_sb(sb);
        mutex_unlock(&rdtgroup_mutex);
+       cpus_read_unlock();
 }
 
 static struct file_system_type rdt_fs_type = {
@@ -1524,8 +1595,10 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
        int ret;
 
        prdtgrp = rdtgroup_kn_lock_live(prgrp_kn);
+       rdt_last_cmd_clear();
        if (!prdtgrp) {
                ret = -ENODEV;
+               rdt_last_cmd_puts("directory was removed\n");
                goto out_unlock;
        }
 
@@ -1533,6 +1606,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
        rdtgrp = kzalloc(sizeof(*rdtgrp), GFP_KERNEL);
        if (!rdtgrp) {
                ret = -ENOSPC;
+               rdt_last_cmd_puts("kernel out of memory\n");
                goto out_unlock;
        }
        *r = rdtgrp;
@@ -1544,6 +1618,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
        kn = kernfs_create_dir(parent_kn, name, mode, rdtgrp);
        if (IS_ERR(kn)) {
                ret = PTR_ERR(kn);
+               rdt_last_cmd_puts("kernfs create error\n");
                goto out_free_rgrp;
        }
        rdtgrp->kn = kn;
@@ -1557,24 +1632,31 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
        kernfs_get(kn);
 
        ret = rdtgroup_kn_set_ugid(kn);
-       if (ret)
+       if (ret) {
+               rdt_last_cmd_puts("kernfs perm error\n");
                goto out_destroy;
+       }
 
-       files = RFTYPE_BASE | RFTYPE_CTRL;
        files = RFTYPE_BASE | BIT(RF_CTRLSHIFT + rtype);
        ret = rdtgroup_add_files(kn, files);
-       if (ret)
+       if (ret) {
+               rdt_last_cmd_puts("kernfs fill error\n");
                goto out_destroy;
+       }
 
        if (rdt_mon_capable) {
                ret = alloc_rmid();
-               if (ret < 0)
+               if (ret < 0) {
+                       rdt_last_cmd_puts("out of RMIDs\n");
                        goto out_destroy;
+               }
                rdtgrp->mon.rmid = ret;
 
                ret = mkdir_mondata_all(kn, rdtgrp, &rdtgrp->mon.mon_data_kn);
-               if (ret)
+               if (ret) {
+                       rdt_last_cmd_puts("kernfs subdir error\n");
                        goto out_idfree;
+               }
        }
        kernfs_activate(kn);
 
@@ -1652,8 +1734,10 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
 
        kn = rdtgrp->kn;
        ret = closid_alloc();
-       if (ret < 0)
+       if (ret < 0) {
+               rdt_last_cmd_puts("out of CLOSIDs\n");
                goto out_common_fail;
+       }
        closid = ret;
 
        rdtgrp->closid = closid;
@@ -1665,8 +1749,10 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
                 * of tasks and cpus to monitor.
                 */
                ret = mongroup_create_dir(kn, NULL, "mon_groups", NULL);
-               if (ret)
+               if (ret) {
+                       rdt_last_cmd_puts("kernfs subdir error\n");
                        goto out_id_free;
+               }
        }
 
        goto out_unlock;
@@ -1902,6 +1988,9 @@ int __init rdtgroup_init(void)
 {
        int ret = 0;
 
+       seq_buf_init(&last_cmd_status, last_cmd_status_buf,
+                    sizeof(last_cmd_status_buf));
+
        ret = rdtgroup_setup_root();
        if (ret)
                return ret;
index 87cc9ab7a13cdeb731cd1782a8ea8863aed432a1..4ca632a06e0b25143c84207d91d00dc1072af0a8 100644 (file)
@@ -204,7 +204,7 @@ static int error_context(struct mce *m)
        return IN_KERNEL;
 }
 
-static int mce_severity_amd_smca(struct mce *m, int err_ctx)
+static int mce_severity_amd_smca(struct mce *m, enum context err_ctx)
 {
        u32 addr = MSR_AMD64_SMCA_MCx_CONFIG(m->bank);
        u32 low, high;
@@ -245,6 +245,9 @@ static int mce_severity_amd(struct mce *m, int tolerant, char **msg, bool is_exc
 
        if (m->status & MCI_STATUS_UC) {
 
+               if (ctx == IN_KERNEL)
+                       return MCE_PANIC_SEVERITY;
+
                /*
                 * On older systems where overflow_recov flag is not present, we
                 * should simply panic if an error overflow occurs. If
@@ -255,10 +258,6 @@ static int mce_severity_amd(struct mce *m, int tolerant, char **msg, bool is_exc
                        if (mce_flags.smca)
                                return mce_severity_amd_smca(m, ctx);
 
-                       /* software can try to contain */
-                       if (!(m->mcgstatus & MCG_STATUS_RIPV) && (ctx == IN_KERNEL))
-                               return MCE_PANIC_SEVERITY;
-
                        /* kill current process */
                        return MCE_AR_SEVERITY;
                } else {
index 3b413065c61308104794db2efe6ab939b39411a1..b1d616d08eee11d058d1046a6642c83f3cf67b05 100644 (file)
@@ -1367,13 +1367,12 @@ static void __start_timer(struct timer_list *t, unsigned long interval)
        local_irq_restore(flags);
 }
 
-static void mce_timer_fn(unsigned long data)
+static void mce_timer_fn(struct timer_list *t)
 {
-       struct timer_list *t = this_cpu_ptr(&mce_timer);
-       int cpu = smp_processor_id();
+       struct timer_list *cpu_t = this_cpu_ptr(&mce_timer);
        unsigned long iv;
 
-       WARN_ON(cpu != data);
+       WARN_ON(cpu_t != t);
 
        iv = __this_cpu_read(mce_next_interval);
 
@@ -1763,17 +1762,15 @@ static void mce_start_timer(struct timer_list *t)
 static void __mcheck_cpu_setup_timer(void)
 {
        struct timer_list *t = this_cpu_ptr(&mce_timer);
-       unsigned int cpu = smp_processor_id();
 
-       setup_pinned_timer(t, mce_timer_fn, cpu);
+       timer_setup(t, mce_timer_fn, TIMER_PINNED);
 }
 
 static void __mcheck_cpu_init_timer(void)
 {
        struct timer_list *t = this_cpu_ptr(&mce_timer);
-       unsigned int cpu = smp_processor_id();
 
-       setup_pinned_timer(t, mce_timer_fn, cpu);
+       timer_setup(t, mce_timer_fn, TIMER_PINNED);
        mce_start_timer(t);
 }
 
index 236324e83a3ae0755c4de2a087983759793c0add..85eb5fc180c8194f473529182237897386dd927a 100644 (file)
@@ -254,9 +254,9 @@ static void __init ms_hyperv_init_platform(void)
 #endif
 }
 
-const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
+const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
        .name                   = "Microsoft Hyper-V",
        .detect                 = ms_hyperv_platform,
-       .init_platform          = ms_hyperv_init_platform,
+       .type                   = X86_HYPER_MS_HYPERV,
+       .init.init_platform     = ms_hyperv_init_platform,
 };
-EXPORT_SYMBOL(x86_hyper_ms_hyperv);
index 4378a729b933508e806d28045401d99781587c84..6b7e17bf0b71dd63394b0ec5a83bea508c7ebfe9 100644 (file)
@@ -78,10 +78,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                seq_printf(m, "microcode\t: 0x%x\n", c->microcode);
 
        if (cpu_has(c, X86_FEATURE_TSC)) {
-               unsigned int freq = arch_freq_get_on_cpu(cpu);
+               unsigned int freq = cpufreq_quick_get(cpu);
 
-               if (!freq)
-                       freq = cpufreq_quick_get(cpu);
                if (!freq)
                        freq = cpu_khz;
                seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
index 40ed26852ebd9a7fb61b6bc24b06426c4faf9f62..8e005329648b6b49d9afe671062368fe25db38e9 100644 (file)
@@ -205,10 +205,10 @@ static bool __init vmware_legacy_x2apic_available(void)
               (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0;
 }
 
-const __refconst struct hypervisor_x86 x86_hyper_vmware = {
+const __initconst struct hypervisor_x86 x86_hyper_vmware = {
        .name                   = "VMware",
        .detect                 = vmware_platform,
-       .init_platform          = vmware_platform_setup,
-       .x2apic_available       = vmware_legacy_x2apic_available,
+       .type                   = X86_HYPER_VMWARE,
+       .init.init_platform     = vmware_platform_setup,
+       .init.x2apic_available  = vmware_legacy_x2apic_available,
 };
-EXPORT_SYMBOL(x86_hyper_vmware);
index 44404e2307bbebaa9c1edd17db0cd4a07099462a..10e74d4778a1c48925e8d9a72f185d925c9eae3a 100644 (file)
@@ -209,7 +209,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
 }
 
 #ifdef CONFIG_KEXEC_FILE
-static int get_nr_ram_ranges_callback(u64 start, u64 end, void *arg)
+static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
 {
        unsigned int *nr_ranges = arg;
 
@@ -342,7 +342,7 @@ static int elf_header_exclude_ranges(struct crash_elf_data *ced,
        return ret;
 }
 
-static int prepare_elf64_ram_headers_callback(u64 start, u64 end, void *arg)
+static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 {
        struct crash_elf_data *ced = arg;
        Elf64_Ehdr *ehdr;
@@ -355,7 +355,7 @@ static int prepare_elf64_ram_headers_callback(u64 start, u64 end, void *arg)
        ehdr = ced->ehdr;
 
        /* Exclude unwanted mem ranges */
-       ret = elf_header_exclude_ranges(ced, start, end);
+       ret = elf_header_exclude_ranges(ced, res->start, res->end);
        if (ret)
                return ret;
 
@@ -518,14 +518,14 @@ static int add_e820_entry(struct boot_params *params, struct e820_entry *entry)
        return 0;
 }
 
-static int memmap_entry_callback(u64 start, u64 end, void *arg)
+static int memmap_entry_callback(struct resource *res, void *arg)
 {
        struct crash_memmap_data *cmd = arg;
        struct boot_params *params = cmd->params;
        struct e820_entry ei;
 
-       ei.addr = start;
-       ei.size = end - start + 1;
+       ei.addr = res->start;
+       ei.size = resource_size(res);
        ei.type = cmd->type;
        add_e820_entry(params, &ei);
 
@@ -619,12 +619,12 @@ out:
        return ret;
 }
 
-static int determine_backup_region(u64 start, u64 end, void *arg)
+static int determine_backup_region(struct resource *res, void *arg)
 {
        struct kimage *image = arg;
 
-       image->arch.backup_src_start = start;
-       image->arch.backup_src_sz = end - start + 1;
+       image->arch.backup_src_start = res->start;
+       image->arch.backup_src_sz = resource_size(res);
 
        /* Expecting only one range for backup region */
        return 1;
index 9c4e7ba6870c142921cfbbd07b8bbf45285e5c07..7d7715dde901539c3358e90bd0f449b04fe20700 100644 (file)
@@ -155,14 +155,14 @@ void init_espfix_ap(int cpu)
        page = cpu/ESPFIX_STACKS_PER_PAGE;
 
        /* Did another CPU already set this up? */
-       stack_page = ACCESS_ONCE(espfix_pages[page]);
+       stack_page = READ_ONCE(espfix_pages[page]);
        if (likely(stack_page))
                goto done;
 
        mutex_lock(&espfix_init_mutex);
 
        /* Did we race on the lock? */
-       stack_page = ACCESS_ONCE(espfix_pages[page]);
+       stack_page = READ_ONCE(espfix_pages[page]);
        if (stack_page)
                goto unlock_done;
 
@@ -200,7 +200,7 @@ void init_espfix_ap(int cpu)
                set_pte(&pte_p[n*PTE_STRIDE], pte);
 
        /* Job is done for this CPU and any CPU which shares this page */
-       ACCESS_ONCE(espfix_pages[page]) = stack_page;
+       WRITE_ONCE(espfix_pages[page], stack_page);
 
 unlock_done:
        mutex_unlock(&espfix_init_mutex);
index 7affb7e3d9a5b94326b51528119787f4f956640b..6abd83572b01633c4f67ad6112e6adcb0557bf8c 100644 (file)
@@ -249,6 +249,10 @@ static void __init fpu__init_system_ctx_switch(void)
  */
 static void __init fpu__init_parse_early_param(void)
 {
+       char arg[32];
+       char *argptr = arg;
+       int bit;
+
        if (cmdline_find_option_bool(boot_command_line, "no387"))
                setup_clear_cpu_cap(X86_FEATURE_FPU);
 
@@ -266,6 +270,13 @@ static void __init fpu__init_parse_early_param(void)
 
        if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
                setup_clear_cpu_cap(X86_FEATURE_XSAVES);
+
+       if (cmdline_find_option(boot_command_line, "clearcpuid", arg,
+                               sizeof(arg)) &&
+           get_option(&argptr, &bit) &&
+           bit >= 0 &&
+           bit < NCAPINTS * 32)
+               setup_clear_cpu_cap(bit);
 }
 
 /*
index f1d5476c902209eebeae83d3cd30fe5b6226921c..87a57b7642d3673420b272fec0f442b9baf76414 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/fpu/xstate.h>
 
 #include <asm/tlbflush.h>
+#include <asm/cpufeature.h>
 
 /*
  * Although we spell it out in here, the Processor Trace
@@ -36,6 +37,19 @@ static const char *xfeature_names[] =
        "unknown xstate feature"        ,
 };
 
+static short xsave_cpuid_features[] __initdata = {
+       X86_FEATURE_FPU,
+       X86_FEATURE_XMM,
+       X86_FEATURE_AVX,
+       X86_FEATURE_MPX,
+       X86_FEATURE_MPX,
+       X86_FEATURE_AVX512F,
+       X86_FEATURE_AVX512F,
+       X86_FEATURE_AVX512F,
+       X86_FEATURE_INTEL_PT,
+       X86_FEATURE_PKU,
+};
+
 /*
  * Mask of xstate features supported by the CPU and the kernel:
  */
@@ -59,26 +73,6 @@ unsigned int fpu_user_xstate_size;
 void fpu__xstate_clear_all_cpu_caps(void)
 {
        setup_clear_cpu_cap(X86_FEATURE_XSAVE);
-       setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
-       setup_clear_cpu_cap(X86_FEATURE_XSAVEC);
-       setup_clear_cpu_cap(X86_FEATURE_XSAVES);
-       setup_clear_cpu_cap(X86_FEATURE_AVX);
-       setup_clear_cpu_cap(X86_FEATURE_AVX2);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512F);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512IFMA);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512PF);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512ER);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512CD);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512DQ);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512BW);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512VL);
-       setup_clear_cpu_cap(X86_FEATURE_MPX);
-       setup_clear_cpu_cap(X86_FEATURE_XGETBV1);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512VBMI);
-       setup_clear_cpu_cap(X86_FEATURE_PKU);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512_4VNNIW);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512_4FMAPS);
-       setup_clear_cpu_cap(X86_FEATURE_AVX512_VPOPCNTDQ);
 }
 
 /*
@@ -726,6 +720,7 @@ void __init fpu__init_system_xstate(void)
        unsigned int eax, ebx, ecx, edx;
        static int on_boot_cpu __initdata = 1;
        int err;
+       int i;
 
        WARN_ON_FPU(!on_boot_cpu);
        on_boot_cpu = 0;
@@ -759,6 +754,14 @@ void __init fpu__init_system_xstate(void)
                goto out_disable;
        }
 
+       /*
+        * Clear XSAVE features that are disabled in the normal CPUID.
+        */
+       for (i = 0; i < ARRAY_SIZE(xsave_cpuid_features); i++) {
+               if (!boot_cpu_has(xsave_cpuid_features[i]))
+                       xfeatures_mask &= ~BIT(i);
+       }
+
        xfeatures_mask &= fpu__get_supported_xfeatures_mask();
 
        /* Enable xstate instructions to be able to continue with initialization: */
index f1d528bb66a6ceb54d3b506f3df09ac92f3e8a82..c29020907886a32d1ca40e9beb858c32dfdefd0f 100644 (file)
@@ -212,9 +212,6 @@ ENTRY(startup_32_smp)
 #endif
 
 .Ldefault_entry:
-#define CR0_STATE      (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
-                        X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
-                        X86_CR0_PG)
        movl $(CR0_STATE & ~X86_CR0_PG),%eax
        movl %eax,%cr0
 
@@ -402,7 +399,7 @@ ENTRY(early_idt_handler_array)
        # 24(%rsp) error code
        i = 0
        .rept NUM_EXCEPTION_VECTORS
-       .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1
+       .if ((EXCEPTION_ERRCODE_MASK >> i) & 1) == 0
        pushl $0                # Dummy error code, to make stack frame uniform
        .endif
        pushl $i                # 20(%esp) Vector number
index 6dde3f3fc1f8e7cc213ded1d9098a17649d0e54d..7dca675fe78db60c5d79bc450bbd14bfee35cfc2 100644 (file)
  *
  */
 
-#define p4d_index(x)   (((x) >> P4D_SHIFT) & (PTRS_PER_P4D-1))
 #define pud_index(x)   (((x) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
 
+#if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH)
 PGD_PAGE_OFFSET = pgd_index(__PAGE_OFFSET_BASE)
 PGD_START_KERNEL = pgd_index(__START_KERNEL_map)
+#endif
 L3_START_KERNEL = pud_index(__START_KERNEL_map)
 
        .text
@@ -50,6 +51,7 @@ L3_START_KERNEL = pud_index(__START_KERNEL_map)
        .code64
        .globl startup_64
 startup_64:
+       UNWIND_HINT_EMPTY
        /*
         * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0,
         * and someone has loaded an identity mapped page table
@@ -89,6 +91,7 @@ startup_64:
        addq    $(early_top_pgt - __START_KERNEL_map), %rax
        jmp 1f
 ENTRY(secondary_startup_64)
+       UNWIND_HINT_EMPTY
        /*
         * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0,
         * and someone has loaded a mapped page table.
@@ -133,6 +136,7 @@ ENTRY(secondary_startup_64)
        movq    $1f, %rax
        jmp     *%rax
 1:
+       UNWIND_HINT_EMPTY
 
        /* Check if nx is implemented */
        movl    $0x80000001, %eax
@@ -150,9 +154,6 @@ ENTRY(secondary_startup_64)
 1:     wrmsr                           /* Make changes effective */
 
        /* Setup cr0 */
-#define CR0_STATE      (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
-                        X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
-                        X86_CR0_PG)
        movl    $CR0_STATE, %eax
        /* Make changes effective */
        movq    %rax, %cr0
@@ -235,7 +236,7 @@ ENTRY(secondary_startup_64)
        pushq   %rax            # target address in negative space
        lretq
 .Lafter_lret:
-ENDPROC(secondary_startup_64)
+END(secondary_startup_64)
 
 #include "verify_cpu.S"
 
@@ -247,6 +248,7 @@ ENDPROC(secondary_startup_64)
  */
 ENTRY(start_cpu0)
        movq    initial_stack(%rip), %rsp
+       UNWIND_HINT_EMPTY
        jmp     .Ljump_to_C_code
 ENDPROC(start_cpu0)
 #endif
@@ -266,26 +268,24 @@ ENDPROC(start_cpu0)
        .quad  init_thread_union + THREAD_SIZE - SIZEOF_PTREGS
        __FINITDATA
 
-bad_address:
-       jmp bad_address
-
        __INIT
 ENTRY(early_idt_handler_array)
-       # 104(%rsp) %rflags
-       #  96(%rsp) %cs
-       #  88(%rsp) %rip
-       #  80(%rsp) error code
        i = 0
        .rept NUM_EXCEPTION_VECTORS
-       .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1
-       pushq $0                # Dummy error code, to make stack frame uniform
+       .if ((EXCEPTION_ERRCODE_MASK >> i) & 1) == 0
+               UNWIND_HINT_IRET_REGS
+               pushq $0        # Dummy error code, to make stack frame uniform
+       .else
+               UNWIND_HINT_IRET_REGS offset=8
        .endif
        pushq $i                # 72(%rsp) Vector number
        jmp early_idt_handler_common
+       UNWIND_HINT_IRET_REGS
        i = i + 1
        .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc
        .endr
-ENDPROC(early_idt_handler_array)
+       UNWIND_HINT_IRET_REGS offset=16
+END(early_idt_handler_array)
 
 early_idt_handler_common:
        /*
@@ -313,6 +313,7 @@ early_idt_handler_common:
        pushq %r13                              /* pt_regs->r13 */
        pushq %r14                              /* pt_regs->r14 */
        pushq %r15                              /* pt_regs->r15 */
+       UNWIND_HINT_REGS
 
        cmpq $14,%rsi           /* Page fault? */
        jnz 10f
@@ -327,8 +328,8 @@ early_idt_handler_common:
 
 20:
        decl early_recursion_flag(%rip)
-       jmp restore_regs_and_iret
-ENDPROC(early_idt_handler_common)
+       jmp restore_regs_and_return_to_kernel
+END(early_idt_handler_common)
 
        __INITDATA
 
@@ -362,10 +363,7 @@ NEXT_PAGE(early_dynamic_pgts)
 
        .data
 
-#ifndef CONFIG_XEN
-NEXT_PAGE(init_top_pgt)
-       .fill   512,8,0
-#else
+#if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH)
 NEXT_PAGE(init_top_pgt)
        .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
        .org    init_top_pgt + PGD_PAGE_OFFSET*8, 0
@@ -382,6 +380,9 @@ NEXT_PAGE(level2_ident_pgt)
         * Don't set NX because code runs from these pages.
         */
        PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
+#else
+NEXT_PAGE(init_top_pgt)
+       .fill   512,8,0
 #endif
 
 #ifdef CONFIG_X86_5LEVEL
@@ -435,7 +436,7 @@ ENTRY(phys_base)
 EXPORT_SYMBOL(phys_base)
 
 #include "../../x86/xen/xen-head.S"
-       
+
        __PAGE_ALIGNED_BSS
 NEXT_PAGE(empty_zero_page)
        .skip PAGE_SIZE
index 8f5cb2c7060cfc29b46ec24669ec418dfdf0c0df..86c4439f9d74963b7d9317e6a487ed0d7c085765 100644 (file)
@@ -114,6 +114,7 @@ static void make_8259A_irq(unsigned int irq)
        io_apic_irqs &= ~(1<<irq);
        irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
        enable_irq(irq);
+       lapic_assign_legacy_vector(irq, true);
 }
 
 /*
index 6107ee1cb8d56762ab76b0e076b52c3f838b1698..d985cef3984ff030e3a83d50eaa9dc45f0a64a82 100644 (file)
@@ -92,8 +92,6 @@ static const __initdata struct idt_data def_idts[] = {
        INTG(X86_TRAP_DF,               double_fault),
 #endif
        INTG(X86_TRAP_DB,               debug),
-       INTG(X86_TRAP_NMI,              nmi),
-       INTG(X86_TRAP_BP,               int3),
 
 #ifdef CONFIG_X86_MCE
        INTG(X86_TRAP_MC,               &machine_check),
@@ -225,7 +223,7 @@ idt_setup_from_table(gate_desc *idt, const struct idt_data *t, int size, bool sy
                idt_init_desc(&desc, t);
                write_idt_entry(idt, t->vector, &desc);
                if (sys)
-                       set_bit(t->vector, used_vectors);
+                       set_bit(t->vector, system_vectors);
        }
 }
 
@@ -313,14 +311,14 @@ void __init idt_setup_apic_and_irq_gates(void)
 
        idt_setup_from_table(idt_table, apic_idts, ARRAY_SIZE(apic_idts), true);
 
-       for_each_clear_bit_from(i, used_vectors, FIRST_SYSTEM_VECTOR) {
+       for_each_clear_bit_from(i, system_vectors, FIRST_SYSTEM_VECTOR) {
                entry = irq_entries_start + 8 * (i - FIRST_EXTERNAL_VECTOR);
                set_intr_gate(i, entry);
        }
 
-       for_each_clear_bit_from(i, used_vectors, NR_VECTORS) {
+       for_each_clear_bit_from(i, system_vectors, NR_VECTORS) {
 #ifdef CONFIG_X86_LOCAL_APIC
-               set_bit(i, used_vectors);
+               set_bit(i, system_vectors);
                set_intr_gate(i, spurious_interrupt);
 #else
                entry = irq_entries_start + 8 * (i - FIRST_EXTERNAL_VECTOR);
@@ -358,7 +356,7 @@ void idt_invalidate(void *addr)
 
 void __init update_intr_gate(unsigned int n, const void *addr)
 {
-       if (WARN_ON_ONCE(!test_bit(n, used_vectors)))
+       if (WARN_ON_ONCE(!test_bit(n, system_vectors)))
                return;
        set_intr_gate(n, addr);
 }
@@ -366,6 +364,6 @@ void __init update_intr_gate(unsigned int n, const void *addr)
 void alloc_intr_gate(unsigned int n, const void *addr)
 {
        BUG_ON(n < FIRST_SYSTEM_VECTOR);
-       if (!test_and_set_bit(n, used_vectors))
+       if (!test_and_set_bit(n, system_vectors))
                set_intr_gate(n, addr);
 }
index 52089c043160b5b54b667f6054bdb4c53f269d43..49cfd9fe7589fa5ef2bef5d4a5d6431b7007836f 100644 (file)
@@ -134,7 +134,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
        seq_puts(p, "  Machine check polls\n");
 #endif
 #if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
-       if (test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors)) {
+       if (test_bit(HYPERVISOR_CALLBACK_VECTOR, system_vectors)) {
                seq_printf(p, "%*s: ", prec, "HYP");
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ",
@@ -333,105 +333,6 @@ __visible void smp_kvm_posted_intr_nested_ipi(struct pt_regs *regs)
 
 
 #ifdef CONFIG_HOTPLUG_CPU
-
-/* These two declarations are only used in check_irq_vectors_for_cpu_disable()
- * below, which is protected by stop_machine().  Putting them on the stack
- * results in a stack frame overflow.  Dynamically allocating could result in a
- * failure so declare these two cpumasks as global.
- */
-static struct cpumask affinity_new, online_new;
-
-/*
- * This cpu is going to be removed and its vectors migrated to the remaining
- * online cpus.  Check to see if there are enough vectors in the remaining cpus.
- * This function is protected by stop_machine().
- */
-int check_irq_vectors_for_cpu_disable(void)
-{
-       unsigned int this_cpu, vector, this_count, count;
-       struct irq_desc *desc;
-       struct irq_data *data;
-       int cpu;
-
-       this_cpu = smp_processor_id();
-       cpumask_copy(&online_new, cpu_online_mask);
-       cpumask_clear_cpu(this_cpu, &online_new);
-
-       this_count = 0;
-       for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
-               desc = __this_cpu_read(vector_irq[vector]);
-               if (IS_ERR_OR_NULL(desc))
-                       continue;
-               /*
-                * Protect against concurrent action removal, affinity
-                * changes etc.
-                */
-               raw_spin_lock(&desc->lock);
-               data = irq_desc_get_irq_data(desc);
-               cpumask_copy(&affinity_new,
-                            irq_data_get_affinity_mask(data));
-               cpumask_clear_cpu(this_cpu, &affinity_new);
-
-               /* Do not count inactive or per-cpu irqs. */
-               if (!irq_desc_has_action(desc) || irqd_is_per_cpu(data)) {
-                       raw_spin_unlock(&desc->lock);
-                       continue;
-               }
-
-               raw_spin_unlock(&desc->lock);
-               /*
-                * A single irq may be mapped to multiple cpu's
-                * vector_irq[] (for example IOAPIC cluster mode).  In
-                * this case we have two possibilities:
-                *
-                * 1) the resulting affinity mask is empty; that is
-                * this the down'd cpu is the last cpu in the irq's
-                * affinity mask, or
-                *
-                * 2) the resulting affinity mask is no longer a
-                * subset of the online cpus but the affinity mask is
-                * not zero; that is the down'd cpu is the last online
-                * cpu in a user set affinity mask.
-                */
-               if (cpumask_empty(&affinity_new) ||
-                   !cpumask_subset(&affinity_new, &online_new))
-                       this_count++;
-       }
-       /* No need to check any further. */
-       if (!this_count)
-               return 0;
-
-       count = 0;
-       for_each_online_cpu(cpu) {
-               if (cpu == this_cpu)
-                       continue;
-               /*
-                * We scan from FIRST_EXTERNAL_VECTOR to first system
-                * vector. If the vector is marked in the used vectors
-                * bitmap or an irq is assigned to it, we don't count
-                * it as available.
-                *
-                * As this is an inaccurate snapshot anyway, we can do
-                * this w/o holding vector_lock.
-                */
-               for (vector = FIRST_EXTERNAL_VECTOR;
-                    vector < FIRST_SYSTEM_VECTOR; vector++) {
-                       if (!test_bit(vector, used_vectors) &&
-                           IS_ERR_OR_NULL(per_cpu(vector_irq, cpu)[vector])) {
-                               if (++count == this_count)
-                                       return 0;
-                       }
-               }
-       }
-
-       if (count < this_count) {
-               pr_warn("CPU %d disable failed: CPU has %u vectors assigned and there are only %u available.\n",
-                       this_cpu, this_count, count);
-               return -ERANGE;
-       }
-       return 0;
-}
-
 /* A cpu has been removed from cpu_online_mask.  Reset irq affinities. */
 void fixup_irqs(void)
 {
index 1e4094eba15e95e6f9b3c6f19de6d748bb894dd1..8da3e909e967dd1cd2c55955f7e5445574a07a24 100644 (file)
@@ -61,9 +61,6 @@ void __init init_ISA_irqs(void)
        struct irq_chip *chip = legacy_pic->chip;
        int i;
 
-#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
-       init_bsp_APIC();
-#endif
        legacy_pic->init(0);
 
        for (i = 0; i < nr_legacy_irqs(); i++)
@@ -94,6 +91,7 @@ void __init native_init_IRQ(void)
        x86_init.irqs.pre_vector_init();
 
        idt_setup_apic_and_irq_gates();
+       lapic_assign_system_vectors();
 
        if (!acpi_ioapic && !of_ioapic && nr_legacy_irqs())
                setup_irq(2, &irq2);
index 615105cf7d58073f9ec03e041b3dd3749f1bfd60..ae38dccf0c8f2cb76fc959999438c6051d3d87de 100644 (file)
@@ -85,11 +85,11 @@ extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf,
  * Copy an instruction and adjust the displacement if the instruction
  * uses the %rip-relative addressing mode.
  */
-extern int __copy_instruction(u8 *dest, u8 *src, struct insn *insn);
+extern int __copy_instruction(u8 *dest, u8 *src, u8 *real, struct insn *insn);
 
 /* Generate a relative-jump/call instruction */
-extern void synthesize_reljump(void *from, void *to);
-extern void synthesize_relcall(void *from, void *to);
+extern void synthesize_reljump(void *dest, void *from, void *to);
+extern void synthesize_relcall(void *dest, void *from, void *to);
 
 #ifdef CONFIG_OPTPROBES
 extern int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter);
index 0742491cbb734d29e1be790d890aeb5271ea6eb4..bd36f3c33cd0f96f47b61034b02c205301fe87d1 100644 (file)
@@ -119,29 +119,29 @@ struct kretprobe_blackpoint kretprobe_blacklist[] = {
 const int kretprobe_blacklist_size = ARRAY_SIZE(kretprobe_blacklist);
 
 static nokprobe_inline void
-__synthesize_relative_insn(void *from, void *to, u8 op)
+__synthesize_relative_insn(void *dest, void *from, void *to, u8 op)
 {
        struct __arch_relative_insn {
                u8 op;
                s32 raddr;
        } __packed *insn;
 
-       insn = (struct __arch_relative_insn *)from;
+       insn = (struct __arch_relative_insn *)dest;
        insn->raddr = (s32)((long)(to) - ((long)(from) + 5));
        insn->op = op;
 }
 
 /* Insert a jump instruction at address 'from', which jumps to address 'to'.*/
-void synthesize_reljump(void *from, void *to)
+void synthesize_reljump(void *dest, void *from, void *to)
 {
-       __synthesize_relative_insn(from, to, RELATIVEJUMP_OPCODE);
+       __synthesize_relative_insn(dest, from, to, RELATIVEJUMP_OPCODE);
 }
 NOKPROBE_SYMBOL(synthesize_reljump);
 
 /* Insert a call instruction at address 'from', which calls address 'to'.*/
-void synthesize_relcall(void *from, void *to)
+void synthesize_relcall(void *dest, void *from, void *to)
 {
-       __synthesize_relative_insn(from, to, RELATIVECALL_OPCODE);
+       __synthesize_relative_insn(dest, from, to, RELATIVECALL_OPCODE);
 }
 NOKPROBE_SYMBOL(synthesize_relcall);
 
@@ -346,10 +346,11 @@ static int is_IF_modifier(kprobe_opcode_t *insn)
 /*
  * Copy an instruction with recovering modified instruction by kprobes
  * and adjust the displacement if the instruction uses the %rip-relative
- * addressing mode.
+ * addressing mode. Note that since @real will be the final place of copied
+ * instruction, displacement must be adjust by @real, not @dest.
  * This returns the length of copied instruction, or 0 if it has an error.
  */
-int __copy_instruction(u8 *dest, u8 *src, struct insn *insn)
+int __copy_instruction(u8 *dest, u8 *src, u8 *real, struct insn *insn)
 {
        kprobe_opcode_t buf[MAX_INSN_SIZE];
        unsigned long recovered_insn =
@@ -387,11 +388,11 @@ int __copy_instruction(u8 *dest, u8 *src, struct insn *insn)
                 * have given.
                 */
                newdisp = (u8 *) src + (s64) insn->displacement.value
-                         - (u8 *) dest;
+                         - (u8 *) real;
                if ((s64) (s32) newdisp != newdisp) {
                        pr_err("Kprobes error: new displacement does not fit into s32 (%llx)\n", newdisp);
                        pr_err("\tSrc: %p, Dest: %p, old disp: %x\n",
-                               src, dest, insn->displacement.value);
+                               src, real, insn->displacement.value);
                        return 0;
                }
                disp = (u8 *) dest + insn_offset_displacement(insn);
@@ -402,20 +403,38 @@ int __copy_instruction(u8 *dest, u8 *src, struct insn *insn)
 }
 
 /* Prepare reljump right after instruction to boost */
-static void prepare_boost(struct kprobe *p, struct insn *insn)
+static int prepare_boost(kprobe_opcode_t *buf, struct kprobe *p,
+                         struct insn *insn)
 {
+       int len = insn->length;
+
        if (can_boost(insn, p->addr) &&
-           MAX_INSN_SIZE - insn->length >= RELATIVEJUMP_SIZE) {
+           MAX_INSN_SIZE - len >= RELATIVEJUMP_SIZE) {
                /*
                 * These instructions can be executed directly if it
                 * jumps back to correct address.
                 */
-               synthesize_reljump(p->ainsn.insn + insn->length,
+               synthesize_reljump(buf + len, p->ainsn.insn + len,
                                   p->addr + insn->length);
+               len += RELATIVEJUMP_SIZE;
                p->ainsn.boostable = true;
        } else {
                p->ainsn.boostable = false;
        }
+
+       return len;
+}
+
+/* Make page to RO mode when allocate it */
+void *alloc_insn_page(void)
+{
+       void *page;
+
+       page = module_alloc(PAGE_SIZE);
+       if (page)
+               set_memory_ro((unsigned long)page & PAGE_MASK, 1);
+
+       return page;
 }
 
 /* Recover page to RW mode before releasing it */
@@ -429,12 +448,11 @@ void free_insn_page(void *page)
 static int arch_copy_kprobe(struct kprobe *p)
 {
        struct insn insn;
+       kprobe_opcode_t buf[MAX_INSN_SIZE];
        int len;
 
-       set_memory_rw((unsigned long)p->ainsn.insn & PAGE_MASK, 1);
-
        /* Copy an instruction with recovering if other optprobe modifies it.*/
-       len = __copy_instruction(p->ainsn.insn, p->addr, &insn);
+       len = __copy_instruction(buf, p->addr, p->ainsn.insn, &insn);
        if (!len)
                return -EINVAL;
 
@@ -442,15 +460,16 @@ static int arch_copy_kprobe(struct kprobe *p)
         * __copy_instruction can modify the displacement of the instruction,
         * but it doesn't affect boostable check.
         */
-       prepare_boost(p, &insn);
-
-       set_memory_ro((unsigned long)p->ainsn.insn & PAGE_MASK, 1);
+       len = prepare_boost(buf, p, &insn);
 
        /* Check whether the instruction modifies Interrupt Flag or not */
-       p->ainsn.if_modifier = is_IF_modifier(p->ainsn.insn);
+       p->ainsn.if_modifier = is_IF_modifier(buf);
 
        /* Also, displacement change doesn't affect the first byte */
-       p->opcode = p->ainsn.insn[0];
+       p->opcode = buf[0];
+
+       /* OK, write back the instruction(s) into ROX insn buffer */
+       text_poke(p->ainsn.insn, buf, len);
 
        return 0;
 }
index 041f7b6dfa0fe00f9c6e6611451889d41dc006b9..8dc0161cec8f470f365220097f9b0f97a252c803 100644 (file)
@@ -26,7 +26,7 @@
 #include "common.h"
 
 static nokprobe_inline
-int __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+void __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
                      struct kprobe_ctlblk *kcb, unsigned long orig_ip)
 {
        /*
@@ -41,33 +41,31 @@ int __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
        __this_cpu_write(current_kprobe, NULL);
        if (orig_ip)
                regs->ip = orig_ip;
-       return 1;
 }
 
 int skip_singlestep(struct kprobe *p, struct pt_regs *regs,
                    struct kprobe_ctlblk *kcb)
 {
-       if (kprobe_ftrace(p))
-               return __skip_singlestep(p, regs, kcb, 0);
-       else
-               return 0;
+       if (kprobe_ftrace(p)) {
+               __skip_singlestep(p, regs, kcb, 0);
+               preempt_enable_no_resched();
+               return 1;
+       }
+       return 0;
 }
 NOKPROBE_SYMBOL(skip_singlestep);
 
-/* Ftrace callback handler for kprobes */
+/* Ftrace callback handler for kprobes -- called under preepmt disabed */
 void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                           struct ftrace_ops *ops, struct pt_regs *regs)
 {
        struct kprobe *p;
        struct kprobe_ctlblk *kcb;
-       unsigned long flags;
-
-       /* Disable irq for emulating a breakpoint and avoiding preempt */
-       local_irq_save(flags);
 
+       /* Preempt is disabled by ftrace */
        p = get_kprobe((kprobe_opcode_t *)ip);
        if (unlikely(!p) || kprobe_disabled(p))
-               goto end;
+               return;
 
        kcb = get_kprobe_ctlblk();
        if (kprobe_running()) {
@@ -77,17 +75,19 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
                regs->ip = ip + sizeof(kprobe_opcode_t);
 
+               /* To emulate trap based kprobes, preempt_disable here */
+               preempt_disable();
                __this_cpu_write(current_kprobe, p);
                kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-               if (!p->pre_handler || !p->pre_handler(p, regs))
+               if (!p->pre_handler || !p->pre_handler(p, regs)) {
                        __skip_singlestep(p, regs, kcb, orig_ip);
+                       preempt_enable_no_resched();
+               }
                /*
                 * If pre_handler returns !0, it sets regs->ip and
-                * resets current kprobe.
+                * resets current kprobe, and keep preempt count +1.
                 */
        }
-end:
-       local_irq_restore(flags);
 }
 NOKPROBE_SYMBOL(kprobe_ftrace_handler);
 
index 4f98aad382378a5987306842ea4fc9cde56972d4..e941136e24d834b20b4c15670f0d7a9fd6def1a1 100644 (file)
@@ -142,11 +142,11 @@ void optprobe_template_func(void);
 STACK_FRAME_NON_STANDARD(optprobe_template_func);
 
 #define TMPL_MOVE_IDX \
-       ((long)&optprobe_template_val - (long)&optprobe_template_entry)
+       ((long)optprobe_template_val - (long)optprobe_template_entry)
 #define TMPL_CALL_IDX \
-       ((long)&optprobe_template_call - (long)&optprobe_template_entry)
+       ((long)optprobe_template_call - (long)optprobe_template_entry)
 #define TMPL_END_IDX \
-       ((long)&optprobe_template_end - (long)&optprobe_template_entry)
+       ((long)optprobe_template_end - (long)optprobe_template_entry)
 
 #define INT3_SIZE sizeof(kprobe_opcode_t)
 
@@ -154,17 +154,15 @@ STACK_FRAME_NON_STANDARD(optprobe_template_func);
 static void
 optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
 {
-       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
-       unsigned long flags;
-
        /* This is possible if op is under delayed unoptimizing */
        if (kprobe_disabled(&op->kp))
                return;
 
-       local_irq_save(flags);
+       preempt_disable();
        if (kprobe_running()) {
                kprobes_inc_nmissed_count(&op->kp);
        } else {
+               struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
                /* Save skipped registers */
 #ifdef CONFIG_X86_64
                regs->cs = __KERNEL_CS;
@@ -180,17 +178,17 @@ optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
                opt_pre_handler(&op->kp, regs);
                __this_cpu_write(current_kprobe, NULL);
        }
-       local_irq_restore(flags);
+       preempt_enable_no_resched();
 }
 NOKPROBE_SYMBOL(optimized_callback);
 
-static int copy_optimized_instructions(u8 *dest, u8 *src)
+static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real)
 {
        struct insn insn;
        int len = 0, ret;
 
        while (len < RELATIVEJUMP_SIZE) {
-               ret = __copy_instruction(dest + len, src + len, &insn);
+               ret = __copy_instruction(dest + len, src + len, real, &insn);
                if (!ret || !can_boost(&insn, src + len))
                        return -EINVAL;
                len += ret;
@@ -343,57 +341,66 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
 int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
                                  struct kprobe *__unused)
 {
-       u8 *buf;
-       int ret;
+       u8 *buf = NULL, *slot;
+       int ret, len;
        long rel;
 
        if (!can_optimize((unsigned long)op->kp.addr))
                return -EILSEQ;
 
-       op->optinsn.insn = get_optinsn_slot();
-       if (!op->optinsn.insn)
+       buf = kzalloc(MAX_OPTINSN_SIZE, GFP_KERNEL);
+       if (!buf)
                return -ENOMEM;
 
+       op->optinsn.insn = slot = get_optinsn_slot();
+       if (!slot) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
        /*
         * Verify if the address gap is in 2GB range, because this uses
         * a relative jump.
         */
-       rel = (long)op->optinsn.insn - (long)op->kp.addr + RELATIVEJUMP_SIZE;
+       rel = (long)slot - (long)op->kp.addr + RELATIVEJUMP_SIZE;
        if (abs(rel) > 0x7fffffff) {
-               __arch_remove_optimized_kprobe(op, 0);
-               return -ERANGE;
+               ret = -ERANGE;
+               goto err;
        }
 
-       buf = (u8 *)op->optinsn.insn;
-       set_memory_rw((unsigned long)buf & PAGE_MASK, 1);
+       /* Copy arch-dep-instance from template */
+       memcpy(buf, optprobe_template_entry, TMPL_END_IDX);
 
        /* Copy instructions into the out-of-line buffer */
-       ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr);
-       if (ret < 0) {
-               __arch_remove_optimized_kprobe(op, 0);
-               return ret;
-       }
+       ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr,
+                                         slot + TMPL_END_IDX);
+       if (ret < 0)
+               goto err;
        op->optinsn.size = ret;
-
-       /* Copy arch-dep-instance from template */
-       memcpy(buf, &optprobe_template_entry, TMPL_END_IDX);
+       len = TMPL_END_IDX + op->optinsn.size;
 
        /* Set probe information */
        synthesize_set_arg1(buf + TMPL_MOVE_IDX, (unsigned long)op);
 
        /* Set probe function call */
-       synthesize_relcall(buf + TMPL_CALL_IDX, optimized_callback);
+       synthesize_relcall(buf + TMPL_CALL_IDX,
+                          slot + TMPL_CALL_IDX, optimized_callback);
 
        /* Set returning jmp instruction at the tail of out-of-line buffer */
-       synthesize_reljump(buf + TMPL_END_IDX + op->optinsn.size,
+       synthesize_reljump(buf + len, slot + len,
                           (u8 *)op->kp.addr + op->optinsn.size);
-
-       set_memory_ro((unsigned long)buf & PAGE_MASK, 1);
-
-       flush_icache_range((unsigned long) buf,
-                          (unsigned long) buf + TMPL_END_IDX +
-                          op->optinsn.size + RELATIVEJUMP_SIZE);
-       return 0;
+       len += RELATIVEJUMP_SIZE;
+
+       /* We have to use text_poke for instuction buffer because it is RO */
+       text_poke(slot, buf, len);
+       ret = 0;
+out:
+       kfree(buf);
+       return ret;
+
+err:
+       __arch_remove_optimized_kprobe(op, 0);
+       goto out;
 }
 
 /*
index 8bb9594d076166ee0f6bd4f70350fe3ecf8c3d8b..b40ffbf156c181f69601ed82a09a2292783c524d 100644 (file)
@@ -75,8 +75,8 @@ static int parse_no_kvmclock_vsyscall(char *arg)
 
 early_param("no-kvmclock-vsyscall", parse_no_kvmclock_vsyscall);
 
-static DEFINE_PER_CPU(struct kvm_vcpu_pv_apf_data, apf_reason) __aligned(64);
-static DEFINE_PER_CPU(struct kvm_steal_time, steal_time) __aligned(64);
+static DEFINE_PER_CPU_DECRYPTED(struct kvm_vcpu_pv_apf_data, apf_reason) __aligned(64);
+static DEFINE_PER_CPU_DECRYPTED(struct kvm_steal_time, steal_time) __aligned(64);
 static int has_steal_clock = 0;
 
 /*
@@ -312,7 +312,7 @@ static void kvm_register_steal_time(void)
                cpu, (unsigned long long) slow_virt_to_phys(st));
 }
 
-static DEFINE_PER_CPU(unsigned long, kvm_apic_eoi) = KVM_PV_EOI_DISABLED;
+static DEFINE_PER_CPU_DECRYPTED(unsigned long, kvm_apic_eoi) = KVM_PV_EOI_DISABLED;
 
 static notrace void kvm_guest_apic_eoi_write(u32 reg, u32 val)
 {
@@ -426,9 +426,42 @@ void kvm_disable_steal_time(void)
        wrmsr(MSR_KVM_STEAL_TIME, 0, 0);
 }
 
+static inline void __set_percpu_decrypted(void *ptr, unsigned long size)
+{
+       early_set_memory_decrypted((unsigned long) ptr, size);
+}
+
+/*
+ * Iterate through all possible CPUs and map the memory region pointed
+ * by apf_reason, steal_time and kvm_apic_eoi as decrypted at once.
+ *
+ * Note: we iterate through all possible CPUs to ensure that CPUs
+ * hotplugged will have their per-cpu variable already mapped as
+ * decrypted.
+ */
+static void __init sev_map_percpu_data(void)
+{
+       int cpu;
+
+       if (!sev_active())
+               return;
+
+       for_each_possible_cpu(cpu) {
+               __set_percpu_decrypted(&per_cpu(apf_reason, cpu), sizeof(apf_reason));
+               __set_percpu_decrypted(&per_cpu(steal_time, cpu), sizeof(steal_time));
+               __set_percpu_decrypted(&per_cpu(kvm_apic_eoi, cpu), sizeof(kvm_apic_eoi));
+       }
+}
+
 #ifdef CONFIG_SMP
 static void __init kvm_smp_prepare_boot_cpu(void)
 {
+       /*
+        * Map the per-cpu variables as decrypted before kvm_guest_cpu_init()
+        * shares the guest physical address with the hypervisor.
+        */
+       sev_map_percpu_data();
+
        kvm_guest_cpu_init();
        native_smp_prepare_boot_cpu();
        kvm_spinlock_init();
@@ -465,7 +498,7 @@ static void __init kvm_apf_trap_init(void)
        update_intr_gate(X86_TRAP_PF, async_page_fault);
 }
 
-void __init kvm_guest_init(void)
+static void __init kvm_guest_init(void)
 {
        int i;
 
@@ -496,6 +529,7 @@ void __init kvm_guest_init(void)
                                      kvm_cpu_online, kvm_cpu_down_prepare) < 0)
                pr_err("kvm_guest: Failed to install cpu hotplug callbacks\n");
 #else
+       sev_map_percpu_data();
        kvm_guest_cpu_init();
 #endif
 
@@ -544,12 +578,13 @@ static uint32_t __init kvm_detect(void)
        return kvm_cpuid_base();
 }
 
-const struct hypervisor_x86 x86_hyper_kvm __refconst = {
+const __initconst struct hypervisor_x86 x86_hyper_kvm = {
        .name                   = "KVM",
        .detect                 = kvm_detect,
-       .x2apic_available       = kvm_para_available,
+       .type                   = X86_HYPER_KVM,
+       .init.guest_late_init   = kvm_guest_init,
+       .init.x2apic_available  = kvm_para_available,
 };
-EXPORT_SYMBOL_GPL(x86_hyper_kvm);
 
 static __init int activate_jump_labels(void)
 {
index 5b609e28ce3f40514be95ac47cddd5a0c4d77ab0..77b492c2d6584ffb0f86ab1e600e8b9c1d2eae10 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/sched/clock.h>
 
+#include <asm/mem_encrypt.h>
 #include <asm/x86_init.h>
 #include <asm/reboot.h>
 #include <asm/kvmclock.h>
@@ -45,7 +46,7 @@ early_param("no-kvmclock", parse_no_kvmclock);
 
 /* The hypervisor will put information about time periodically here */
 static struct pvclock_vsyscall_time_info *hv_clock;
-static struct pvclock_wall_clock wall_clock;
+static struct pvclock_wall_clock *wall_clock;
 
 struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
 {
@@ -64,15 +65,15 @@ static void kvm_get_wallclock(struct timespec *now)
        int low, high;
        int cpu;
 
-       low = (int)__pa_symbol(&wall_clock);
-       high = ((u64)__pa_symbol(&wall_clock) >> 32);
+       low = (int)slow_virt_to_phys(wall_clock);
+       high = ((u64)slow_virt_to_phys(wall_clock) >> 32);
 
        native_write_msr(msr_kvm_wall_clock, low, high);
 
        cpu = get_cpu();
 
        vcpu_time = &hv_clock[cpu].pvti;
-       pvclock_read_wallclock(&wall_clock, vcpu_time, now);
+       pvclock_read_wallclock(wall_clock, vcpu_time, now);
 
        put_cpu();
 }
@@ -249,11 +250,39 @@ static void kvm_shutdown(void)
        native_machine_shutdown();
 }
 
+static phys_addr_t __init kvm_memblock_alloc(phys_addr_t size,
+                                            phys_addr_t align)
+{
+       phys_addr_t mem;
+
+       mem = memblock_alloc(size, align);
+       if (!mem)
+               return 0;
+
+       if (sev_active()) {
+               if (early_set_memory_decrypted((unsigned long)__va(mem), size))
+                       goto e_free;
+       }
+
+       return mem;
+e_free:
+       memblock_free(mem, size);
+       return 0;
+}
+
+static void __init kvm_memblock_free(phys_addr_t addr, phys_addr_t size)
+{
+       if (sev_active())
+               early_set_memory_encrypted((unsigned long)__va(addr), size);
+
+       memblock_free(addr, size);
+}
+
 void __init kvmclock_init(void)
 {
        struct pvclock_vcpu_time_info *vcpu_time;
-       unsigned long mem;
-       int size, cpu;
+       unsigned long mem, mem_wall_clock;
+       int size, cpu, wall_clock_size;
        u8 flags;
 
        size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS);
@@ -267,21 +296,35 @@ void __init kvmclock_init(void)
        } else if (!(kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)))
                return;
 
-       printk(KERN_INFO "kvm-clock: Using msrs %x and %x",
-               msr_kvm_system_time, msr_kvm_wall_clock);
+       wall_clock_size = PAGE_ALIGN(sizeof(struct pvclock_wall_clock));
+       mem_wall_clock = kvm_memblock_alloc(wall_clock_size, PAGE_SIZE);
+       if (!mem_wall_clock)
+               return;
 
-       mem = memblock_alloc(size, PAGE_SIZE);
-       if (!mem)
+       wall_clock = __va(mem_wall_clock);
+       memset(wall_clock, 0, wall_clock_size);
+
+       mem = kvm_memblock_alloc(size, PAGE_SIZE);
+       if (!mem) {
+               kvm_memblock_free(mem_wall_clock, wall_clock_size);
+               wall_clock = NULL;
                return;
+       }
+
        hv_clock = __va(mem);
        memset(hv_clock, 0, size);
 
        if (kvm_register_clock("primary cpu clock")) {
                hv_clock = NULL;
-               memblock_free(mem, size);
+               kvm_memblock_free(mem, size);
+               kvm_memblock_free(mem_wall_clock, wall_clock_size);
+               wall_clock = NULL;
                return;
        }
 
+       printk(KERN_INFO "kvm-clock: Using msrs %x and %x",
+               msr_kvm_system_time, msr_kvm_wall_clock);
+
        if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
                pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
 
index 4d17bacf40308cbc9e0414b1b60d038f7a340f0a..1c1eae9613406b14c3154065e1fd036f985a384c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/syscalls.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
@@ -102,7 +103,7 @@ static void finalize_ldt_struct(struct ldt_struct *ldt)
 static void install_ldt(struct mm_struct *current_mm,
                        struct ldt_struct *ldt)
 {
-       /* Synchronizes with lockless_dereference in load_mm_ldt. */
+       /* Synchronizes with READ_ONCE in load_mm_ldt. */
        smp_store_release(&current_mm->context.ldt, ldt);
 
        /* Activate the LDT for all CPUs using current_mm. */
@@ -295,8 +296,8 @@ out:
        return error;
 }
 
-asmlinkage int sys_modify_ldt(int func, void __user *ptr,
-                             unsigned long bytecount)
+SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr ,
+               unsigned long , bytecount)
 {
        int ret = -ENOSYS;
 
@@ -314,5 +315,14 @@ asmlinkage int sys_modify_ldt(int func, void __user *ptr,
                ret = write_ldt(ptr, bytecount, 0);
                break;
        }
-       return ret;
+       /*
+        * The SYSCALL_DEFINE() macros give us an 'unsigned long'
+        * return type, but tht ABI for sys_modify_ldt() expects
+        * 'int'.  This cast gives us an int-sized value in %rax
+        * for the return code.  The 'unsigned' is necessary so
+        * the compiler does not try to sign-extend the negative
+        * return codes into the high half of the register when
+        * taking the value from int->long.
+        */
+       return (unsigned int)ret;
 }
index 35aafc95e4b8a505491d7079a06e8e1b8e16c968..18bc9b51ac9b99ffaf51e85daf490b0ba108bcc9 100644 (file)
@@ -105,7 +105,7 @@ static void nmi_max_handler(struct irq_work *w)
 {
        struct nmiaction *a = container_of(w, struct nmiaction, irq_work);
        int remainder_ns, decimal_msecs;
-       u64 whole_msecs = ACCESS_ONCE(a->max_duration);
+       u64 whole_msecs = READ_ONCE(a->max_duration);
 
        remainder_ns = do_div(whole_msecs, (1000 * 1000));
        decimal_msecs = remainder_ns / 1000;
index 19a3e8f961c772af6572f80a860e1c892ad31a32..041096bdef860d356d58873e3e0483384ee98301 100644 (file)
@@ -115,8 +115,18 @@ unsigned paravirt_patch_jmp(void *insnbuf, const void *target,
        return 5;
 }
 
-/* Neat trick to map patch type back to the call within the
- * corresponding structure. */
+DEFINE_STATIC_KEY_TRUE(virt_spin_lock_key);
+
+void __init native_pv_lock_init(void)
+{
+       if (!static_cpu_has(X86_FEATURE_HYPERVISOR))
+               static_branch_disable(&virt_spin_lock_key);
+}
+
+/*
+ * Neat trick to map patch type back to the call within the
+ * corresponding structure.
+ */
 static void *get_call_destination(u8 type)
 {
        struct paravirt_patch_template tmpl = {
index 5286a4a92cf78dced0613577828a2d7cef17fee5..35c461f218153019b49825898379582718b099b6 100644 (file)
@@ -898,10 +898,9 @@ static void calioc2_dump_error_regs(struct iommu_table *tbl)
               PHB_ROOT_COMPLEX_STATUS);
 }
 
-static void calgary_watchdog(unsigned long data)
+static void calgary_watchdog(struct timer_list *t)
 {
-       struct pci_dev *dev = (struct pci_dev *)data;
-       struct iommu_table *tbl = pci_iommu(dev->bus);
+       struct iommu_table *tbl = from_timer(tbl, t, watchdog_timer);
        void __iomem *bbar = tbl->bbar;
        u32 val32;
        void __iomem *target;
@@ -1016,8 +1015,7 @@ static void __init calgary_enable_translation(struct pci_dev *dev)
        writel(cpu_to_be32(val32), target);
        readl(target); /* flush */
 
-       setup_timer(&tbl->watchdog_timer, &calgary_watchdog,
-                   (unsigned long)dev);
+       timer_setup(&tbl->watchdog_timer, calgary_watchdog, 0);
        mod_timer(&tbl->watchdog_timer, jiffies);
 }
 
index 3fe6900678026e2cee5eb721dbba3eaae84bbb81..6b07faaa157980915e42dc71bdc392a7c5a704e0 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 
-static int found(u64 start, u64 end, void *data)
+static int found(struct resource *res, void *data)
 {
        return 1;
 }
index c67685337c5ac33a5d5ddcec9a07a7949ae2922e..97fb3e5737f5d0b5d50f8d9232726923c2692e65 100644 (file)
  */
 __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = {
        .x86_tss = {
-               .sp0 = TOP_OF_INIT_STACK,
+               /*
+                * .sp0 is only used when entering ring 0 from a lower
+                * privilege level.  Since the init task never runs anything
+                * but ring 0 code, there is no need for a valid value here.
+                * Poison it.
+                */
+               .sp0 = (1UL << (BITS_PER_LONG-1)) + 1,
 #ifdef CONFIG_X86_32
                .ss0 = __KERNEL_DS,
                .ss1 = __KERNEL_CS,
index 11966251cd4259b871203636953e4897e8bd67ab..45bf0c5f93e15103060d67d5245756ab72ce8fe5 100644 (file)
@@ -284,9 +284,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 
        /*
         * Reload esp0 and cpu_current_top_of_stack.  This changes
-        * current_thread_info().
+        * current_thread_info().  Refresh the SYSENTER configuration in
+        * case prev or next is vm86.
         */
-       load_sp0(tss, next);
+       update_sp0(next_p);
+       refresh_sysenter_cs(next);
        this_cpu_write(cpu_current_top_of_stack,
                       (unsigned long)task_stack_page(next_p) +
                       THREAD_SIZE);
index 302e7b2572d1883d7f79d90956446fff1ef8c8ab..eeeb34f85c250e8c01188b6d32cf5a62bd1af8a0 100644 (file)
@@ -274,7 +274,6 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
        struct inactive_task_frame *frame;
        struct task_struct *me = current;
 
-       p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE;
        childregs = task_pt_regs(p);
        fork_frame = container_of(childregs, struct fork_frame, regs);
        frame = &fork_frame->frame;
@@ -464,8 +463,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         */
        this_cpu_write(current_task, next_p);
 
-       /* Reload esp0 and ss1.  This changes current_thread_info(). */
-       load_sp0(tss, next);
+       /* Reload sp0. */
+       update_sp0(next_p);
 
        /*
         * Now maybe reload the debug registers and handle I/O bitmaps
index 0957dd73d127554803f35d5be45dcddb845ca741..8af2e8d0c0a1d2d0290ff2026afeab056cdc59b6 100644 (file)
@@ -136,18 +136,6 @@ RESERVE_BRK(dmi_alloc, 65536);
 static __initdata unsigned long _brk_start = (unsigned long)__brk_base;
 unsigned long _brk_end = (unsigned long)__brk_base;
 
-#ifdef CONFIG_X86_64
-int default_cpu_present_to_apicid(int mps_cpu)
-{
-       return __default_cpu_present_to_apicid(mps_cpu);
-}
-
-int default_check_phys_apicid_present(int phys_apicid)
-{
-       return __default_check_phys_apicid_present(phys_apicid);
-}
-#endif
-
 struct boot_params boot_params;
 
 /*
@@ -380,9 +368,11 @@ static void __init reserve_initrd(void)
         * If SME is active, this memory will be marked encrypted by the
         * kernel when it is accessed (including relocation). However, the
         * ramdisk image was loaded decrypted by the bootloader, so make
-        * sure that it is encrypted before accessing it.
+        * sure that it is encrypted before accessing it. For SEV the
+        * ramdisk will already be encrypted, so only do this for SME.
         */
-       sme_early_encrypt(ramdisk_image, ramdisk_end - ramdisk_image);
+       if (sme_active())
+               sme_early_encrypt(ramdisk_image, ramdisk_end - ramdisk_image);
 
        initrd_start = 0;
 
@@ -822,26 +812,6 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
        return 0;
 }
 
-static void __init simple_udelay_calibration(void)
-{
-       unsigned int tsc_khz, cpu_khz;
-       unsigned long lpj;
-
-       if (!boot_cpu_has(X86_FEATURE_TSC))
-               return;
-
-       cpu_khz = x86_platform.calibrate_cpu();
-       tsc_khz = x86_platform.calibrate_tsc();
-
-       tsc_khz = tsc_khz ? : cpu_khz;
-       if (!tsc_khz)
-               return;
-
-       lpj = tsc_khz * 1000;
-       do_div(lpj, HZ);
-       loops_per_jiffy = lpj;
-}
-
 /*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
@@ -1045,12 +1015,10 @@ void __init setup_arch(char **cmdline_p)
 
        /*
         * VMware detection requires dmi to be available, so this
-        * needs to be done after dmi_scan_machine, for the BP.
+        * needs to be done after dmi_scan_machine(), for the boot CPU.
         */
        init_hypervisor_platform();
 
-       simple_udelay_calibration();
-
        x86_init.resources.probe_roms();
 
        /* after parse_early_param, so could debug it */
@@ -1135,9 +1103,6 @@ void __init setup_arch(char **cmdline_p)
        memblock_set_current_limit(ISA_END_ADDRESS);
        e820__memblock_setup();
 
-       if (!early_xdbc_setup_hardware())
-               early_xdbc_register_console();
-
        reserve_bios_regions();
 
        if (efi_enabled(EFI_MEMMAP)) {
@@ -1243,6 +1208,10 @@ void __init setup_arch(char **cmdline_p)
        kvmclock_init();
 #endif
 
+       tsc_early_delay_calibrate();
+       if (!early_xdbc_setup_hardware())
+               early_xdbc_register_console();
+
        x86_init.paging.pagetable_init();
 
        kasan_init();
@@ -1294,7 +1263,7 @@ void __init setup_arch(char **cmdline_p)
 
        io_apic_init_mappings();
 
-       kvm_guest_init();
+       x86_init.hyper.guest_late_init();
 
        e820__reserve_resources();
        e820__register_nosave_regions(max_low_pfn);
index ad59edd84de70cfb978b8c0bc2ac38b892418b71..5f59e6bee123ffb324ec12a02d1921a7029ddc96 100644 (file)
@@ -77,6 +77,7 @@
 #include <asm/i8259.h>
 #include <asm/realmode.h>
 #include <asm/misc.h>
+#include <asm/qspinlock.h>
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
@@ -193,6 +194,12 @@ static void smp_callin(void)
         */
        smp_store_cpu_info(cpuid);
 
+       /*
+        * The topology information must be up to date before
+        * calibrate_delay() and notify_cpu_starting().
+        */
+       set_cpu_sibling_map(raw_smp_processor_id());
+
        /*
         * Get our bogomips.
         * Update loops_per_jiffy in cpu_data. Previous call to
@@ -203,11 +210,6 @@ static void smp_callin(void)
        cpu_data(cpuid).loops_per_jiffy = loops_per_jiffy;
        pr_debug("Stack at about %p\n", &cpuid);
 
-       /*
-        * This must be done before setting cpu_online_mask
-        * or calling notify_cpu_starting.
-        */
-       set_cpu_sibling_map(raw_smp_processor_id());
        wmb();
 
        notify_cpu_starting(cpuid);
@@ -249,19 +251,19 @@ static void notrace start_secondary(void *unused)
        /* otherwise gcc will move up smp_processor_id before the cpu_init */
        barrier();
        /*
-        * Check TSC synchronization with the BP:
+        * Check TSC synchronization with the boot CPU:
         */
        check_tsc_sync_target();
 
        /*
-        * Lock vector_lock and initialize the vectors on this cpu
-        * before setting the cpu online. We must set it online with
-        * vector_lock held to prevent a concurrent setup/teardown
-        * from seeing a half valid vector space.
+        * Lock vector_lock, set CPU online and bring the vector
+        * allocator online. Online must be set with vector_lock held
+        * to prevent a concurrent irq setup/teardown from seeing a
+        * half valid vector space.
         */
        lock_vector_lock();
-       setup_vector_irq(smp_processor_id());
        set_cpu_online(smp_processor_id(), true);
+       lapic_online();
        unlock_vector_lock();
        cpu_set_state_online(smp_processor_id());
        x86_platform.nmi_init();
@@ -961,8 +963,7 @@ void common_cpu_up(unsigned int cpu, struct task_struct *idle)
 #ifdef CONFIG_X86_32
        /* Stack for startup_32 can be just as for start_secondary onwards */
        irq_ctx_init(cpu);
-       per_cpu(cpu_current_top_of_stack, cpu) =
-               (unsigned long)task_stack_page(idle) + THREAD_SIZE;
+       per_cpu(cpu_current_top_of_stack, cpu) = task_top_of_stack(idle);
 #else
        initial_gs = per_cpu_offset(cpu);
 #endif
@@ -1094,7 +1095,7 @@ int native_cpu_up(unsigned int cpu, struct task_struct *tidle)
        unsigned long flags;
        int err, ret = 0;
 
-       WARN_ON(irqs_disabled());
+       lockdep_assert_irqs_enabled();
 
        pr_debug("++++++++++++++++++++=_---CPU UP  %u\n", cpu);
 
@@ -1190,17 +1191,10 @@ static __init void disable_smp(void)
        cpumask_set_cpu(0, topology_core_cpumask(0));
 }
 
-enum {
-       SMP_OK,
-       SMP_NO_CONFIG,
-       SMP_NO_APIC,
-       SMP_FORCE_UP,
-};
-
 /*
  * Various sanity checks.
  */
-static int __init smp_sanity_check(unsigned max_cpus)
+static void __init smp_sanity_check(void)
 {
        preempt_disable();
 
@@ -1237,16 +1231,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
                physid_set(hard_smp_processor_id(), phys_cpu_present_map);
        }
 
-       /*
-        * If we couldn't find an SMP configuration at boot time,
-        * get out of here now!
-        */
-       if (!smp_found_config && !acpi_lapic) {
-               preempt_enable();
-               pr_notice("SMP motherboard not detected\n");
-               return SMP_NO_CONFIG;
-       }
-
        /*
         * Should not be necessary because the MP table should list the boot
         * CPU too, but we do it for the sake of robustness anyway.
@@ -1257,29 +1241,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
                physid_set(hard_smp_processor_id(), phys_cpu_present_map);
        }
        preempt_enable();
-
-       /*
-        * If we couldn't find a local APIC, then get out of here now!
-        */
-       if (APIC_INTEGRATED(boot_cpu_apic_version) &&
-           !boot_cpu_has(X86_FEATURE_APIC)) {
-               if (!disable_apic) {
-                       pr_err("BIOS bug, local APIC #%d not detected!...\n",
-                               boot_cpu_physical_apicid);
-                       pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n");
-               }
-               return SMP_NO_APIC;
-       }
-
-       /*
-        * If SMP should be disabled, then really disable it!
-        */
-       if (!max_cpus) {
-               pr_info("SMP mode deactivated\n");
-               return SMP_FORCE_UP;
-       }
-
-       return SMP_OK;
 }
 
 static void __init smp_cpu_index_default(void)
@@ -1294,9 +1255,18 @@ static void __init smp_cpu_index_default(void)
        }
 }
 
+static void __init smp_get_logical_apicid(void)
+{
+       if (x2apic_mode)
+               cpu0_logical_apicid = apic_read(APIC_LDR);
+       else
+               cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
+}
+
 /*
- * Prepare for SMP bootup.  The MP table or ACPI has been read
- * earlier.  Just do some sanity checking here and enable APIC mode.
+ * Prepare for SMP bootup.
+ * @max_cpus: configured maximum number of CPUs, It is a legacy parameter
+ *            for common interface support.
  */
 void __init native_smp_prepare_cpus(unsigned int max_cpus)
 {
@@ -1328,35 +1298,33 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 
        set_cpu_sibling_map(0);
 
-       switch (smp_sanity_check(max_cpus)) {
-       case SMP_NO_CONFIG:
-               disable_smp();
-               if (APIC_init_uniprocessor())
-                       pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
-               return;
-       case SMP_NO_APIC:
+       smp_sanity_check();
+
+       switch (apic_intr_mode) {
+       case APIC_PIC:
+       case APIC_VIRTUAL_WIRE_NO_CONFIG:
                disable_smp();
                return;
-       case SMP_FORCE_UP:
+       case APIC_SYMMETRIC_IO_NO_ROUTING:
                disable_smp();
-               apic_bsp_setup(false);
+               /* Setup local timer */
+               x86_init.timers.setup_percpu_clockev();
                return;
-       case SMP_OK:
+       case APIC_VIRTUAL_WIRE:
+       case APIC_SYMMETRIC_IO:
                break;
        }
 
-       if (read_apic_id() != boot_cpu_physical_apicid) {
-               panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
-                    read_apic_id(), boot_cpu_physical_apicid);
-               /* Or can we switch back to PIC here? */
-       }
+       /* Setup local timer */
+       x86_init.timers.setup_percpu_clockev();
 
-       default_setup_apic_routing();
-       cpu0_logical_apicid = apic_bsp_setup(false);
+       smp_get_logical_apicid();
 
        pr_info("CPU0: ");
        print_cpu_info(&cpu_data(0));
 
+       native_pv_lock_init();
+
        uv_system_init();
 
        set_mtrr_aps_delayed_init();
@@ -1395,7 +1363,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
 
        nmi_selftest();
        impress_friends();
-       setup_ioapic_dest();
        mtrr_aps_init();
 }
 
@@ -1554,13 +1521,14 @@ void cpu_disable_common(void)
        remove_cpu_from_maps(cpu);
        unlock_vector_lock();
        fixup_irqs();
+       lapic_offline();
 }
 
 int native_cpu_disable(void)
 {
        int ret;
 
-       ret = check_irq_vectors_for_cpu_disable();
+       ret = lapic_can_unplug_cpu();
        if (ret)
                return ret;
 
index 8dabd7bf16730918f1a8c91fcd5df503d73b056a..77835bc021c766744dd1976b4429141e3fb645fa 100644 (file)
@@ -30,7 +30,7 @@ static int save_stack_address(struct stack_trace *trace, unsigned long addr,
        return 0;
 }
 
-static void __save_stack_trace(struct stack_trace *trace,
+static void noinline __save_stack_trace(struct stack_trace *trace,
                               struct task_struct *task, struct pt_regs *regs,
                               bool nosched)
 {
@@ -56,6 +56,7 @@ static void __save_stack_trace(struct stack_trace *trace,
  */
 void save_stack_trace(struct stack_trace *trace)
 {
+       trace->skip++;
        __save_stack_trace(trace, current, NULL, false);
 }
 EXPORT_SYMBOL_GPL(save_stack_trace);
@@ -70,6 +71,8 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
        if (!try_get_task_stack(tsk))
                return;
 
+       if (tsk == current)
+               trace->skip++;
        __save_stack_trace(trace, tsk, NULL, true);
 
        put_task_stack(tsk);
@@ -88,8 +91,9 @@ EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
        }                                                       \
 })
 
-static int __save_stack_trace_reliable(struct stack_trace *trace,
-                                      struct task_struct *task)
+static int __always_inline
+__save_stack_trace_reliable(struct stack_trace *trace,
+                           struct task_struct *task)
 {
        struct unwind_state state;
        struct pt_regs *regs;
index 879af864d99afd6c8645f0d74fe71bf6a2bade07..749d189f8cd4675de3267310e38217a8082c0485 100644 (file)
@@ -85,6 +85,11 @@ void __init hpet_time_init(void)
 static __init void x86_late_time_init(void)
 {
        x86_init.timers.timer_init();
+       /*
+        * After PIT/HPET timers init, select and setup
+        * the final interrupt mode for delivering IRQs.
+        */
+       x86_init.irqs.intr_mode_init();
        tsc_init();
 }
 
index 67db4f43309ecadc86f4d7e95c6a0db0650a0d18..b7b0f74a215024ddd5881bce823083355ad1e3d0 100644 (file)
@@ -60,6 +60,7 @@
 #include <asm/trace/mpx.h>
 #include <asm/mpx.h>
 #include <asm/vm86.h>
+#include <asm/umip.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/x86_init.h>
@@ -71,7 +72,7 @@
 #include <asm/proto.h>
 #endif
 
-DECLARE_BITMAP(used_vectors, NR_VECTORS);
+DECLARE_BITMAP(system_vectors, NR_VECTORS);
 
 static inline void cond_local_irq_enable(struct pt_regs *regs)
 {
@@ -141,8 +142,7 @@ void ist_begin_non_atomic(struct pt_regs *regs)
         * will catch asm bugs and any attempt to use ist_preempt_enable
         * from double_fault.
         */
-       BUG_ON((unsigned long)(current_top_of_stack() -
-                              current_stack_pointer) >= THREAD_SIZE);
+       BUG_ON(!on_thread_stack());
 
        preempt_enable_no_resched();
 }
@@ -209,9 +209,6 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
                if (fixup_exception(regs, trapnr))
                        return 0;
 
-               if (fixup_bug(regs, trapnr))
-                       return 0;
-
                tsk->thread.error_code = error_code;
                tsk->thread.trap_nr = trapnr;
                die(str, regs, error_code);
@@ -292,6 +289,13 @@ static void do_error_trap(struct pt_regs *regs, long error_code, char *str,
 
        RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
 
+       /*
+        * WARN*()s end up here; fix them up before we call the
+        * notifier chain.
+        */
+       if (!user_mode(regs) && fixup_bug(regs, trapnr))
+               return;
+
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) !=
                        NOTIFY_STOP) {
                cond_local_irq_enable(regs);
@@ -514,6 +518,11 @@ do_general_protection(struct pt_regs *regs, long error_code)
        RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
        cond_local_irq_enable(regs);
 
+       if (static_cpu_has(X86_FEATURE_UMIP)) {
+               if (user_mode(regs) && fixup_umip_exception(regs))
+                       return;
+       }
+
        if (v8086_mode(regs)) {
                local_irq_enable();
                handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
index 796d96bb0821874a3b567d1b95f802b85f1222dc..8ea117f8142e192ac0a143f225e505803c82106a 100644 (file)
@@ -112,7 +112,7 @@ static void cyc2ns_data_init(struct cyc2ns_data *data)
        data->cyc2ns_offset = 0;
 }
 
-static void cyc2ns_init(int cpu)
+static void __init cyc2ns_init(int cpu)
 {
        struct cyc2ns *c2n = &per_cpu(cyc2ns, cpu);
 
@@ -812,13 +812,13 @@ unsigned long native_calibrate_cpu(void)
        return tsc_pit_min;
 }
 
-int recalibrate_cpu_khz(void)
+void recalibrate_cpu_khz(void)
 {
 #ifndef CONFIG_SMP
        unsigned long cpu_khz_old = cpu_khz;
 
        if (!boot_cpu_has(X86_FEATURE_TSC))
-               return -ENODEV;
+               return;
 
        cpu_khz = x86_platform.calibrate_cpu();
        tsc_khz = x86_platform.calibrate_tsc();
@@ -828,10 +828,6 @@ int recalibrate_cpu_khz(void)
                cpu_khz = tsc_khz;
        cpu_data(0).loops_per_jiffy = cpufreq_scale(cpu_data(0).loops_per_jiffy,
                                                    cpu_khz_old, cpu_khz);
-
-       return 0;
-#else
-       return -ENODEV;
 #endif
 }
 
@@ -959,17 +955,21 @@ core_initcall(cpufreq_register_tsc_scaling);
 /*
  * If ART is present detect the numerator:denominator to convert to TSC
  */
-static void detect_art(void)
+static void __init detect_art(void)
 {
        unsigned int unused[2];
 
        if (boot_cpu_data.cpuid_level < ART_CPUID_LEAF)
                return;
 
-       /* Don't enable ART in a VM, non-stop TSC and TSC_ADJUST required */
+       /*
+        * Don't enable ART in a VM, non-stop TSC and TSC_ADJUST required,
+        * and the TSC counter resets must not occur asynchronously.
+        */
        if (boot_cpu_has(X86_FEATURE_HYPERVISOR) ||
            !boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ||
-           !boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+           !boot_cpu_has(X86_FEATURE_TSC_ADJUST) ||
+           tsc_async_resets)
                return;
 
        cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
@@ -1263,6 +1263,25 @@ static int __init init_tsc_clocksource(void)
  */
 device_initcall(init_tsc_clocksource);
 
+void __init tsc_early_delay_calibrate(void)
+{
+       unsigned long lpj;
+
+       if (!boot_cpu_has(X86_FEATURE_TSC))
+               return;
+
+       cpu_khz = x86_platform.calibrate_cpu();
+       tsc_khz = x86_platform.calibrate_tsc();
+
+       tsc_khz = tsc_khz ? : cpu_khz;
+       if (!tsc_khz)
+               return;
+
+       lpj = tsc_khz * 1000;
+       do_div(lpj, HZ);
+       loops_per_jiffy = lpj;
+}
+
 void __init tsc_init(void)
 {
        u64 lpj, cyc;
@@ -1346,12 +1365,10 @@ void __init tsc_init(void)
 unsigned long calibrate_delay_is_known(void)
 {
        int sibling, cpu = smp_processor_id();
-       struct cpumask *mask = topology_core_cpumask(cpu);
-
-       if (!tsc_disabled && !cpu_has(&cpu_data(cpu), X86_FEATURE_CONSTANT_TSC))
-               return 0;
+       int constant_tsc = cpu_has(&cpu_data(cpu), X86_FEATURE_CONSTANT_TSC);
+       const struct cpumask *mask = topology_core_cpumask(cpu);
 
-       if (!mask)
+       if (tsc_disabled || !constant_tsc || !mask)
                return 0;
 
        sibling = cpumask_any_but(mask, cpu);
index e76a9881306b34fc800b4e290e1eb7d38baaad6b..ec534f978867db90e662e7ee1d82e366796d1340 100644 (file)
@@ -31,6 +31,20 @@ struct tsc_adjust {
 
 static DEFINE_PER_CPU(struct tsc_adjust, tsc_adjust);
 
+/*
+ * TSC's on different sockets may be reset asynchronously.
+ * This may cause the TSC ADJUST value on socket 0 to be NOT 0.
+ */
+bool __read_mostly tsc_async_resets;
+
+void mark_tsc_async_resets(char *reason)
+{
+       if (tsc_async_resets)
+               return;
+       tsc_async_resets = true;
+       pr_info("tsc: Marking TSC async resets true due to %s\n", reason);
+}
+
 void tsc_verify_tsc_adjust(bool resume)
 {
        struct tsc_adjust *adj = this_cpu_ptr(&tsc_adjust);
@@ -39,6 +53,10 @@ void tsc_verify_tsc_adjust(bool resume)
        if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
                return;
 
+       /* Skip unnecessary error messages if TSC already unstable */
+       if (check_tsc_unstable())
+               return;
+
        /* Rate limit the MSR check */
        if (!resume && time_before(jiffies, adj->nextcheck))
                return;
@@ -72,12 +90,22 @@ static void tsc_sanitize_first_cpu(struct tsc_adjust *cur, s64 bootval,
         * non zero. We don't do that on non boot cpus because physical
         * hotplug should have set the ADJUST register to a value > 0 so
         * the TSC is in sync with the already running cpus.
+        *
+        * Also don't force the ADJUST value to zero if that is a valid value
+        * for socket 0 as determined by the system arch.  This is required
+        * when multiple sockets are reset asynchronously with each other
+        * and socket 0 may not have an TSC ADJUST value of 0.
         */
        if (bootcpu && bootval != 0) {
-               pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n", cpu,
-                       bootval);
-               wrmsrl(MSR_IA32_TSC_ADJUST, 0);
-               bootval = 0;
+               if (likely(!tsc_async_resets)) {
+                       pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n",
+                               cpu, bootval);
+                       wrmsrl(MSR_IA32_TSC_ADJUST, 0);
+                       bootval = 0;
+               } else {
+                       pr_info("TSC ADJUST: CPU%u: %lld NOT forced to 0\n",
+                               cpu, bootval);
+               }
        }
        cur->adjusted = bootval;
 }
@@ -91,6 +119,10 @@ bool __init tsc_store_and_check_tsc_adjust(bool bootcpu)
        if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
                return false;
 
+       /* Skip unnecessary error messages if TSC already unstable */
+       if (check_tsc_unstable())
+               return false;
+
        rdmsrl(MSR_IA32_TSC_ADJUST, bootval);
        cur->bootval = bootval;
        cur->nextcheck = jiffies + HZ;
@@ -118,6 +150,13 @@ bool tsc_store_and_check_tsc_adjust(bool bootcpu)
        cur->nextcheck = jiffies + HZ;
        cur->warned = false;
 
+       /*
+        * If a non-zero TSC value for socket 0 may be valid then the default
+        * adjusted value cannot assumed to be zero either.
+        */
+       if (tsc_async_resets)
+               cur->adjusted = bootval;
+
        /*
         * Check whether this CPU is the first in a package to come up. In
         * this case do not check the boot value against another package
@@ -139,10 +178,9 @@ bool tsc_store_and_check_tsc_adjust(bool bootcpu)
         * Compare the boot value and complain if it differs in the
         * package.
         */
-       if (bootval != ref->bootval) {
-               pr_warn(FW_BUG "TSC ADJUST differs: Reference CPU%u: %lld CPU%u: %lld\n",
-                       refcpu, ref->bootval, cpu, bootval);
-       }
+       if (bootval != ref->bootval)
+               printk_once(FW_BUG "TSC ADJUST differs within socket(s), fixing all errors\n");
+
        /*
         * The TSC_ADJUST values in a package must be the same. If the boot
         * value on this newly upcoming CPU differs from the adjustment
@@ -150,8 +188,6 @@ bool tsc_store_and_check_tsc_adjust(bool bootcpu)
         * adjusted value.
         */
        if (bootval != ref->adjusted) {
-               pr_warn("TSC ADJUST synchronize: Reference CPU%u: %lld CPU%u: %lld\n",
-                       refcpu, ref->adjusted, cpu, bootval);
                cur->adjusted = ref->adjusted;
                wrmsrl(MSR_IA32_TSC_ADJUST, ref->adjusted);
        }
diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c
new file mode 100644 (file)
index 0000000..6ba82be
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * umip.c Emulation for instruction protected by the Intel User-Mode
+ * Instruction Prevention feature
+ *
+ * Copyright (c) 2017, Intel Corporation.
+ * Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
+ */
+
+#include <linux/uaccess.h>
+#include <asm/umip.h>
+#include <asm/traps.h>
+#include <asm/insn.h>
+#include <asm/insn-eval.h>
+#include <linux/ratelimit.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "umip: " fmt
+
+/** DOC: Emulation for User-Mode Instruction Prevention (UMIP)
+ *
+ * The feature User-Mode Instruction Prevention present in recent Intel
+ * processor prevents a group of instructions (sgdt, sidt, sldt, smsw, and str)
+ * from being executed with CPL > 0. Otherwise, a general protection fault is
+ * issued.
+ *
+ * Rather than relaying to the user space the general protection fault caused by
+ * the UMIP-protected instructions (in the form of a SIGSEGV signal), it can be
+ * trapped and emulate the result of such instructions to provide dummy values.
+ * This allows to both conserve the current kernel behavior and not reveal the
+ * system resources that UMIP intends to protect (i.e., the locations of the
+ * global descriptor and interrupt descriptor tables, the segment selectors of
+ * the local descriptor table, the value of the task state register and the
+ * contents of the CR0 register).
+ *
+ * This emulation is needed because certain applications (e.g., WineHQ and
+ * DOSEMU2) rely on this subset of instructions to function.
+ *
+ * The instructions protected by UMIP can be split in two groups. Those which
+ * return a kernel memory address (sgdt and sidt) and those which return a
+ * value (sldt, str and smsw).
+ *
+ * For the instructions that return a kernel memory address, applications
+ * such as WineHQ rely on the result being located in the kernel memory space,
+ * not the actual location of the table. The result is emulated as a hard-coded
+ * value that, lies close to the top of the kernel memory. The limit for the GDT
+ * and the IDT are set to zero.
+ *
+ * Given that sldt and str are not commonly used in programs that run on WineHQ
+ * or DOSEMU2, they are not emulated.
+ *
+ * The instruction smsw is emulated to return the value that the register CR0
+ * has at boot time as set in the head_32.
+ *
+ * Also, emulation is provided only for 32-bit processes; 64-bit processes
+ * that attempt to use the instructions that UMIP protects will receive the
+ * SIGSEGV signal issued as a consequence of the general protection fault.
+ *
+ * Care is taken to appropriately emulate the results when segmentation is
+ * used. That is, rather than relying on USER_DS and USER_CS, the function
+ * insn_get_addr_ref() inspects the segment descriptor pointed by the
+ * registers in pt_regs. This ensures that we correctly obtain the segment
+ * base address and the address and operand sizes even if the user space
+ * application uses a local descriptor table.
+ */
+
+#define UMIP_DUMMY_GDT_BASE 0xfffe0000
+#define UMIP_DUMMY_IDT_BASE 0xffff0000
+
+/*
+ * The SGDT and SIDT instructions store the contents of the global descriptor
+ * table and interrupt table registers, respectively. The destination is a
+ * memory operand of X+2 bytes. X bytes are used to store the base address of
+ * the table and 2 bytes are used to store the limit. In 32-bit processes, the
+ * only processes for which emulation is provided, X has a value of 4.
+ */
+#define UMIP_GDT_IDT_BASE_SIZE 4
+#define UMIP_GDT_IDT_LIMIT_SIZE 2
+
+#define        UMIP_INST_SGDT  0       /* 0F 01 /0 */
+#define        UMIP_INST_SIDT  1       /* 0F 01 /1 */
+#define        UMIP_INST_SMSW  3       /* 0F 01 /4 */
+
+/**
+ * identify_insn() - Identify a UMIP-protected instruction
+ * @insn:      Instruction structure with opcode and ModRM byte.
+ *
+ * From the opcode and ModRM.reg in @insn identify, if any, a UMIP-protected
+ * instruction that can be emulated.
+ *
+ * Returns:
+ *
+ * On success, a constant identifying a specific UMIP-protected instruction that
+ * can be emulated.
+ *
+ * -EINVAL on error or when not an UMIP-protected instruction that can be
+ * emulated.
+ */
+static int identify_insn(struct insn *insn)
+{
+       /* By getting modrm we also get the opcode. */
+       insn_get_modrm(insn);
+
+       if (!insn->modrm.nbytes)
+               return -EINVAL;
+
+       /* All the instructions of interest start with 0x0f. */
+       if (insn->opcode.bytes[0] != 0xf)
+               return -EINVAL;
+
+       if (insn->opcode.bytes[1] == 0x1) {
+               switch (X86_MODRM_REG(insn->modrm.value)) {
+               case 0:
+                       return UMIP_INST_SGDT;
+               case 1:
+                       return UMIP_INST_SIDT;
+               case 4:
+                       return UMIP_INST_SMSW;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       /* SLDT AND STR are not emulated */
+       return -EINVAL;
+}
+
+/**
+ * emulate_umip_insn() - Emulate UMIP instructions and return dummy values
+ * @insn:      Instruction structure with operands
+ * @umip_inst: A constant indicating the instruction to emulate
+ * @data:      Buffer into which the dummy result is stored
+ * @data_size: Size of the emulated result
+ *
+ * Emulate an instruction protected by UMIP and provide a dummy result. The
+ * result of the emulation is saved in @data. The size of the results depends
+ * on both the instruction and type of operand (register vs memory address).
+ * The size of the result is updated in @data_size. Caller is responsible
+ * of providing a @data buffer of at least UMIP_GDT_IDT_BASE_SIZE +
+ * UMIP_GDT_IDT_LIMIT_SIZE bytes.
+ *
+ * Returns:
+ *
+ * 0 on success, -EINVAL on error while emulating.
+ */
+static int emulate_umip_insn(struct insn *insn, int umip_inst,
+                            unsigned char *data, int *data_size)
+{
+       unsigned long dummy_base_addr, dummy_value;
+       unsigned short dummy_limit = 0;
+
+       if (!data || !data_size || !insn)
+               return -EINVAL;
+       /*
+        * These two instructions return the base address and limit of the
+        * global and interrupt descriptor table, respectively. According to the
+        * Intel Software Development manual, the base address can be 24-bit,
+        * 32-bit or 64-bit. Limit is always 16-bit. If the operand size is
+        * 16-bit, the returned value of the base address is supposed to be a
+        * zero-extended 24-byte number. However, it seems that a 32-byte number
+        * is always returned irrespective of the operand size.
+        */
+       if (umip_inst == UMIP_INST_SGDT || umip_inst == UMIP_INST_SIDT) {
+               /* SGDT and SIDT do not use registers operands. */
+               if (X86_MODRM_MOD(insn->modrm.value) == 3)
+                       return -EINVAL;
+
+               if (umip_inst == UMIP_INST_SGDT)
+                       dummy_base_addr = UMIP_DUMMY_GDT_BASE;
+               else
+                       dummy_base_addr = UMIP_DUMMY_IDT_BASE;
+
+               *data_size = UMIP_GDT_IDT_LIMIT_SIZE + UMIP_GDT_IDT_BASE_SIZE;
+
+               memcpy(data + 2, &dummy_base_addr, UMIP_GDT_IDT_BASE_SIZE);
+               memcpy(data, &dummy_limit, UMIP_GDT_IDT_LIMIT_SIZE);
+
+       } else if (umip_inst == UMIP_INST_SMSW) {
+               dummy_value = CR0_STATE;
+
+               /*
+                * Even though the CR0 register has 4 bytes, the number
+                * of bytes to be copied in the result buffer is determined
+                * by whether the operand is a register or a memory location.
+                * If operand is a register, return as many bytes as the operand
+                * size. If operand is memory, return only the two least
+                * siginificant bytes of CR0.
+                */
+               if (X86_MODRM_MOD(insn->modrm.value) == 3)
+                       *data_size = insn->opnd_bytes;
+               else
+                       *data_size = 2;
+
+               memcpy(data, &dummy_value, *data_size);
+       /* STR and SLDT  are not emulated */
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * force_sig_info_umip_fault() - Force a SIGSEGV with SEGV_MAPERR
+ * @addr:      Address that caused the signal
+ * @regs:      Register set containing the instruction pointer
+ *
+ * Force a SIGSEGV signal with SEGV_MAPERR as the error code. This function is
+ * intended to be used to provide a segmentation fault when the result of the
+ * UMIP emulation could not be copied to the user space memory.
+ *
+ * Returns: none
+ */
+static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs)
+{
+       siginfo_t info;
+       struct task_struct *tsk = current;
+
+       tsk->thread.cr2         = (unsigned long)addr;
+       tsk->thread.error_code  = X86_PF_USER | X86_PF_WRITE;
+       tsk->thread.trap_nr     = X86_TRAP_PF;
+
+       info.si_signo   = SIGSEGV;
+       info.si_errno   = 0;
+       info.si_code    = SEGV_MAPERR;
+       info.si_addr    = addr;
+       force_sig_info(SIGSEGV, &info, tsk);
+
+       if (!(show_unhandled_signals && unhandled_signal(tsk, SIGSEGV)))
+               return;
+
+       pr_err_ratelimited("%s[%d] umip emulation segfault ip:%lx sp:%lx error:%x in %lx\n",
+                          tsk->comm, task_pid_nr(tsk), regs->ip,
+                          regs->sp, X86_PF_USER | X86_PF_WRITE,
+                          regs->ip);
+}
+
+/**
+ * fixup_umip_exception() - Fixup a general protection fault caused by UMIP
+ * @regs:      Registers as saved when entering the #GP handler
+ *
+ * The instructions sgdt, sidt, str, smsw, sldt cause a general protection
+ * fault if executed with CPL > 0 (i.e., from user space). If the offending
+ * user-space process is not in long mode, this function fixes the exception
+ * up and provides dummy results for sgdt, sidt and smsw; str and sldt are not
+ * fixed up. Also long mode user-space processes are not fixed up.
+ *
+ * If operands are memory addresses, results are copied to user-space memory as
+ * indicated by the instruction pointed by eIP using the registers indicated in
+ * the instruction operands. If operands are registers, results are copied into
+ * the context that was saved when entering kernel mode.
+ *
+ * Returns:
+ *
+ * True if emulation was successful; false if not.
+ */
+bool fixup_umip_exception(struct pt_regs *regs)
+{
+       int not_copied, nr_copied, reg_offset, dummy_data_size, umip_inst;
+       unsigned long seg_base = 0, *reg_addr;
+       /* 10 bytes is the maximum size of the result of UMIP instructions */
+       unsigned char dummy_data[10] = { 0 };
+       unsigned char buf[MAX_INSN_SIZE];
+       void __user *uaddr;
+       struct insn insn;
+       char seg_defs;
+
+       if (!regs)
+               return false;
+
+       /* Do not emulate 64-bit processes. */
+       if (user_64bit_mode(regs))
+               return false;
+
+       /*
+        * If not in user-space long mode, a custom code segment could be in
+        * use. This is true in protected mode (if the process defined a local
+        * descriptor table), or virtual-8086 mode. In most of the cases
+        * seg_base will be zero as in USER_CS.
+        */
+       if (!user_64bit_mode(regs))
+               seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS);
+
+       if (seg_base == -1L)
+               return false;
+
+       not_copied = copy_from_user(buf, (void __user *)(seg_base + regs->ip),
+                                   sizeof(buf));
+       nr_copied = sizeof(buf) - not_copied;
+
+       /*
+        * The copy_from_user above could have failed if user code is protected
+        * by a memory protection key. Give up on emulation in such a case.
+        * Should we issue a page fault?
+        */
+       if (!nr_copied)
+               return false;
+
+       insn_init(&insn, buf, nr_copied, user_64bit_mode(regs));
+
+       /*
+        * Override the default operand and address sizes with what is specified
+        * in the code segment descriptor. The instruction decoder only sets
+        * the address size it to either 4 or 8 address bytes and does nothing
+        * for the operand bytes. This OK for most of the cases, but we could
+        * have special cases where, for instance, a 16-bit code segment
+        * descriptor is used.
+        * If there is an address override prefix, the instruction decoder
+        * correctly updates these values, even for 16-bit defaults.
+        */
+       seg_defs = insn_get_code_seg_params(regs);
+       if (seg_defs == -EINVAL)
+               return false;
+
+       insn.addr_bytes = INSN_CODE_SEG_ADDR_SZ(seg_defs);
+       insn.opnd_bytes = INSN_CODE_SEG_OPND_SZ(seg_defs);
+
+       insn_get_length(&insn);
+       if (nr_copied < insn.length)
+               return false;
+
+       umip_inst = identify_insn(&insn);
+       if (umip_inst < 0)
+               return false;
+
+       if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size))
+               return false;
+
+       /*
+        * If operand is a register, write result to the copy of the register
+        * value that was pushed to the stack when entering into kernel mode.
+        * Upon exit, the value we write will be restored to the actual hardware
+        * register.
+        */
+       if (X86_MODRM_MOD(insn.modrm.value) == 3) {
+               reg_offset = insn_get_modrm_rm_off(&insn, regs);
+
+               /*
+                * Negative values are usually errors. In memory addressing,
+                * the exception is -EDOM. Since we expect a register operand,
+                * all negative values are errors.
+                */
+               if (reg_offset < 0)
+                       return false;
+
+               reg_addr = (unsigned long *)((unsigned long)regs + reg_offset);
+               memcpy(reg_addr, dummy_data, dummy_data_size);
+       } else {
+               uaddr = insn_get_addr_ref(&insn, regs);
+               if ((unsigned long)uaddr == -1L)
+                       return false;
+
+               nr_copied = copy_to_user(uaddr, dummy_data, dummy_data_size);
+               if (nr_copied  > 0) {
+                       /*
+                        * If copy fails, send a signal and tell caller that
+                        * fault was fixed up.
+                        */
+                       force_sig_info_umip_fault(uaddr, regs);
+                       return true;
+               }
+       }
+
+       /* increase IP to let the program keep going */
+       regs->ip += insn.length;
+       return true;
+}
index b95007e7c1b305e24ee63e728e003d53ff7a5c31..a3f973b2c97a03b121fe0173dbdc9298216721e6 100644 (file)
@@ -279,7 +279,7 @@ static bool deref_stack_reg(struct unwind_state *state, unsigned long addr,
        if (!stack_access_ok(state, addr, sizeof(long)))
                return false;
 
-       *val = READ_ONCE_TASK_STACK(state->task, *(unsigned long *)addr);
+       *val = READ_ONCE_NOCHECK(*(unsigned long *)addr);
        return true;
 }
 
index 495c776de4b470f8eb53236a0ddeb2ca8f043b6b..a3755d293a48ca038844ed92e15ea071efdd6449 100644 (file)
@@ -271,12 +271,15 @@ static bool is_prefix_bad(struct insn *insn)
        int i;
 
        for (i = 0; i < insn->prefixes.nbytes; i++) {
-               switch (insn->prefixes.bytes[i]) {
-               case 0x26:      /* INAT_PFX_ES   */
-               case 0x2E:      /* INAT_PFX_CS   */
-               case 0x36:      /* INAT_PFX_DS   */
-               case 0x3E:      /* INAT_PFX_SS   */
-               case 0xF0:      /* INAT_PFX_LOCK */
+               insn_attr_t attr;
+
+               attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
+               switch (attr) {
+               case INAT_MAKE_PREFIX(INAT_PFX_ES):
+               case INAT_MAKE_PREFIX(INAT_PFX_CS):
+               case INAT_MAKE_PREFIX(INAT_PFX_DS):
+               case INAT_MAKE_PREFIX(INAT_PFX_SS):
+               case INAT_MAKE_PREFIX(INAT_PFX_LOCK):
                        return true;
                }
        }
index 014ea59aa153e4f37725dd8771cdb37d88371e34..3d3c2f71f61719b8d504031e03171430c48d9dab 100644 (file)
@@ -33,7 +33,7 @@
 #include <asm/cpufeatures.h>
 #include <asm/msr-index.h>
 
-verify_cpu:
+ENTRY(verify_cpu)
        pushf                           # Save caller passed flags
        push    $0                      # Kill any dangerous flags
        popf
@@ -139,3 +139,4 @@ verify_cpu:
        popf                            # Restore caller passed flags
        xorl %eax, %eax
        ret
+ENDPROC(verify_cpu)
index 68244742ecb0bc376232bbab4b94164251e434dd..5edb27f1a2c407ff8173161fb87cbd9130b76e8e 100644 (file)
@@ -55,6 +55,7 @@
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/vm86.h>
+#include <asm/switch_to.h>
 
 /*
  * Known problems:
@@ -94,7 +95,6 @@
 
 void save_v86_state(struct kernel_vm86_regs *regs, int retval)
 {
-       struct tss_struct *tss;
        struct task_struct *tsk = current;
        struct vm86plus_struct __user *user;
        struct vm86 *vm86 = current->thread.vm86;
@@ -146,12 +146,13 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
                do_exit(SIGSEGV);
        }
 
-       tss = &per_cpu(cpu_tss, get_cpu());
+       preempt_disable();
        tsk->thread.sp0 = vm86->saved_sp0;
        tsk->thread.sysenter_cs = __KERNEL_CS;
-       load_sp0(tss, &tsk->thread);
+       update_sp0(tsk);
+       refresh_sysenter_cs(&tsk->thread);
        vm86->saved_sp0 = 0;
-       put_cpu();
+       preempt_enable();
 
        memcpy(&regs->pt, &vm86->regs32, sizeof(struct pt_regs));
 
@@ -237,7 +238,6 @@ SYSCALL_DEFINE2(vm86, unsigned long, cmd, unsigned long, arg)
 
 static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
 {
-       struct tss_struct *tss;
        struct task_struct *tsk = current;
        struct vm86 *vm86 = tsk->thread.vm86;
        struct kernel_vm86_regs vm86regs;
@@ -365,15 +365,17 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
        vm86->saved_sp0 = tsk->thread.sp0;
        lazy_save_gs(vm86->regs32.gs);
 
-       tss = &per_cpu(cpu_tss, get_cpu());
        /* make room for real-mode segments */
+       preempt_disable();
        tsk->thread.sp0 += 16;
 
-       if (static_cpu_has(X86_FEATURE_SEP))
+       if (static_cpu_has(X86_FEATURE_SEP)) {
                tsk->thread.sysenter_cs = 0;
+               refresh_sysenter_cs(&tsk->thread);
+       }
 
-       load_sp0(tss, &tsk->thread);
-       put_cpu();
+       update_sp0(tsk);
+       preempt_enable();
 
        if (vm86->flags & VM86_SCREEN_BITMAP)
                mark_screen_rdonly(tsk->mm);
index b034b1b14b9c66ab77b24d9757ce10de7f0f318e..44685fb2a192f7969ed6453fb56c16ff5a33ca40 100644 (file)
@@ -26,9 +26,6 @@
 
 #define TOPOLOGY_REGISTER_OFFSET 0x10
 
-/* Flag below is initialized once during vSMP PCI initialization. */
-static int irq_routing_comply = 1;
-
 #if defined CONFIG_PCI && defined CONFIG_PARAVIRT
 /*
  * Interrupt control on vSMPowered systems:
@@ -105,9 +102,6 @@ static void __init set_vsmp_pv_ops(void)
        if (cap & ctl & BIT(8)) {
                ctl &= ~BIT(8);
 
-               /* Interrupt routing set to ignore */
-               irq_routing_comply = 0;
-
 #ifdef CONFIG_PROC_FS
                /* Don't let users change irq affinity via procfs */
                no_irq_affinity = 1;
@@ -211,23 +205,10 @@ static int apicid_phys_pkg_id(int initial_apic_id, int index_msb)
        return hard_smp_processor_id() >> index_msb;
 }
 
-/*
- * In vSMP, all cpus should be capable of handling interrupts, regardless of
- * the APIC used.
- */
-static void fill_vector_allocation_domain(int cpu, struct cpumask *retmask,
-                                         const struct cpumask *mask)
-{
-       cpumask_setall(retmask);
-}
-
 static void vsmp_apic_post_init(void)
 {
        /* need to update phys_pkg_id */
        apic->phys_pkg_id = apicid_phys_pkg_id;
-
-       if (!irq_routing_comply)
-               apic->vector_allocation_domain = fill_vector_allocation_domain;
 }
 
 void __init vsmp_init(void)
index a088b2c47f7396dbfa9bd070ebc8f3c544a33d07..1151ccd72ce9752a8144baa40b4d24807d68a4f8 100644 (file)
@@ -28,6 +28,8 @@ void x86_init_noop(void) { }
 void __init x86_init_uint_noop(unsigned int unused) { }
 int __init iommu_init_noop(void) { return 0; }
 void iommu_shutdown_noop(void) { }
+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
@@ -55,6 +57,7 @@ struct x86_init_ops x86_init __initdata = {
                .pre_vector_init        = init_ISA_irqs,
                .intr_init              = native_init_IRQ,
                .trap_init              = x86_init_noop,
+               .intr_mode_init         = apic_intr_mode_init
        },
 
        .oem = {
@@ -81,6 +84,13 @@ struct x86_init_ops x86_init __initdata = {
                .init_irq               = x86_default_pci_init_irq,
                .fixup_irqs             = x86_default_pci_fixup_irqs,
        },
+
+       .hyper = {
+               .init_platform          = x86_init_noop,
+               .guest_late_init        = x86_init_noop,
+               .x2apic_available       = bool_x86_init_noop,
+               .init_mem_mapping       = x86_init_noop,
+       },
 };
 
 struct x86_cpuinit_ops x86_cpuinit = {
@@ -101,6 +111,7 @@ struct x86_platform_ops x86_platform __ro_after_init = {
        .get_nmi_reason                 = default_get_nmi_reason,
        .save_sched_clock_state         = tsc_save_sched_clock_state,
        .restore_sched_clock_state      = tsc_restore_sched_clock_state,
+       .hyper.pin_vcpu                 = x86_op_int_noop,
 };
 
 EXPORT_SYMBOL_GPL(x86_platform);
index 7a69cf053711197df9a0f2ec284ef5a436c42514..a119b361b8b7a9c916e4df7ecd9e69622e64c1b3 100644 (file)
@@ -443,7 +443,7 @@ static u64 __update_clear_spte_slow(u64 *sptep, u64 spte)
 
 static u64 __get_spte_lockless(u64 *sptep)
 {
-       return ACCESS_ONCE(*sptep);
+       return READ_ONCE(*sptep);
 }
 #else
 union split_spte {
@@ -4819,7 +4819,7 @@ static void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
         * If we don't have indirect shadow pages, it means no page is
         * write-protected, so we can exit simply.
         */
-       if (!ACCESS_ONCE(vcpu->kvm->arch.indirect_shadow_pages))
+       if (!READ_ONCE(vcpu->kvm->arch.indirect_shadow_pages))
                return;
 
        remote_flush = local_flush = false;
index ea67dc876316487f4fff2bf2e6a5193510086aee..01c1371f39f8cd91912d9f4027587bfe6479dc29 100644 (file)
@@ -157,7 +157,7 @@ bool kvm_page_track_is_active(struct kvm_vcpu *vcpu, gfn_t gfn,
                return false;
 
        index = gfn_to_index(gfn, slot->base_gfn, PT_PAGE_TABLE_LEVEL);
-       return !!ACCESS_ONCE(slot->arch.gfn_track[mode][index]);
+       return !!READ_ONCE(slot->arch.gfn_track[mode][index]);
 }
 
 void kvm_page_track_cleanup(struct kvm *kvm)
index 457f681ef37921be836c0e50bf659b07cc534fc5..7b181b61170e769fc41a062a3eddbb62c4e53793 100644 (file)
@@ -24,7 +24,7 @@ lib-y := delay.o misc.o cmdline.o cpu.o
 lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
-lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
+lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o
 lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
 
 obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
new file mode 100644 (file)
index 0000000..35625d2
--- /dev/null
@@ -0,0 +1,1364 @@
+/*
+ * Utility functions for x86 operand and address decoding
+ *
+ * Copyright (C) Intel Corporation 2017
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ratelimit.h>
+#include <linux/mmu_context.h>
+#include <asm/desc_defs.h>
+#include <asm/desc.h>
+#include <asm/inat.h>
+#include <asm/insn.h>
+#include <asm/insn-eval.h>
+#include <asm/ldt.h>
+#include <asm/vm86.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "insn: " fmt
+
+enum reg_type {
+       REG_TYPE_RM = 0,
+       REG_TYPE_INDEX,
+       REG_TYPE_BASE,
+};
+
+/**
+ * is_string_insn() - Determine if instruction is a string instruction
+ * @insn:      Instruction containing the opcode to inspect
+ *
+ * Returns:
+ *
+ * true if the instruction, determined by the opcode, is any of the
+ * string instructions as defined in the Intel Software Development manual.
+ * False otherwise.
+ */
+static bool is_string_insn(struct insn *insn)
+{
+       insn_get_opcode(insn);
+
+       /* All string instructions have a 1-byte opcode. */
+       if (insn->opcode.nbytes != 1)
+               return false;
+
+       switch (insn->opcode.bytes[0]) {
+       case 0x6c ... 0x6f:     /* INS, OUTS */
+       case 0xa4 ... 0xa7:     /* MOVS, CMPS */
+       case 0xaa ... 0xaf:     /* STOS, LODS, SCAS */
+               return true;
+       default:
+               return false;
+       }
+}
+
+/**
+ * get_seg_reg_override_idx() - obtain segment register override index
+ * @insn:      Valid instruction with segment override prefixes
+ *
+ * Inspect the instruction prefixes in @insn and find segment overrides, if any.
+ *
+ * Returns:
+ *
+ * A constant identifying the segment register to use, among CS, SS, DS,
+ * ES, FS, or GS. INAT_SEG_REG_DEFAULT is returned if no segment override
+ * prefixes were found.
+ *
+ * -EINVAL in case of error.
+ */
+static int get_seg_reg_override_idx(struct insn *insn)
+{
+       int idx = INAT_SEG_REG_DEFAULT;
+       int num_overrides = 0, i;
+
+       insn_get_prefixes(insn);
+
+       /* Look for any segment override prefixes. */
+       for (i = 0; i < insn->prefixes.nbytes; i++) {
+               insn_attr_t attr;
+
+               attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
+               switch (attr) {
+               case INAT_MAKE_PREFIX(INAT_PFX_CS):
+                       idx = INAT_SEG_REG_CS;
+                       num_overrides++;
+                       break;
+               case INAT_MAKE_PREFIX(INAT_PFX_SS):
+                       idx = INAT_SEG_REG_SS;
+                       num_overrides++;
+                       break;
+               case INAT_MAKE_PREFIX(INAT_PFX_DS):
+                       idx = INAT_SEG_REG_DS;
+                       num_overrides++;
+                       break;
+               case INAT_MAKE_PREFIX(INAT_PFX_ES):
+                       idx = INAT_SEG_REG_ES;
+                       num_overrides++;
+                       break;
+               case INAT_MAKE_PREFIX(INAT_PFX_FS):
+                       idx = INAT_SEG_REG_FS;
+                       num_overrides++;
+                       break;
+               case INAT_MAKE_PREFIX(INAT_PFX_GS):
+                       idx = INAT_SEG_REG_GS;
+                       num_overrides++;
+                       break;
+               /* No default action needed. */
+               }
+       }
+
+       /* More than one segment override prefix leads to undefined behavior. */
+       if (num_overrides > 1)
+               return -EINVAL;
+
+       return idx;
+}
+
+/**
+ * check_seg_overrides() - check if segment override prefixes are allowed
+ * @insn:      Valid instruction with segment override prefixes
+ * @regoff:    Operand offset, in pt_regs, for which the check is performed
+ *
+ * For a particular register used in register-indirect addressing, determine if
+ * segment override prefixes can be used. Specifically, no overrides are allowed
+ * for rDI if used with a string instruction.
+ *
+ * Returns:
+ *
+ * True if segment override prefixes can be used with the register indicated
+ * in @regoff. False if otherwise.
+ */
+static bool check_seg_overrides(struct insn *insn, int regoff)
+{
+       if (regoff == offsetof(struct pt_regs, di) && is_string_insn(insn))
+               return false;
+
+       return true;
+}
+
+/**
+ * resolve_default_seg() - resolve default segment register index for an operand
+ * @insn:      Instruction with opcode and address size. Must be valid.
+ * @regs:      Register values as seen when entering kernel mode
+ * @off:       Operand offset, in pt_regs, for which resolution is needed
+ *
+ * Resolve the default segment register index associated with the instruction
+ * operand register indicated by @off. Such index is resolved based on defaults
+ * described in the Intel Software Development Manual.
+ *
+ * Returns:
+ *
+ * If in protected mode, a constant identifying the segment register to use,
+ * among CS, SS, ES or DS. If in long mode, INAT_SEG_REG_IGNORE.
+ *
+ * -EINVAL in case of error.
+ */
+static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off)
+{
+       if (user_64bit_mode(regs))
+               return INAT_SEG_REG_IGNORE;
+       /*
+        * Resolve the default segment register as described in Section 3.7.4
+        * of the Intel Software Development Manual Vol. 1:
+        *
+        *  + DS for all references involving r[ABCD]X, and rSI.
+        *  + If used in a string instruction, ES for rDI. Otherwise, DS.
+        *  + AX, CX and DX are not valid register operands in 16-bit address
+        *    encodings but are valid for 32-bit and 64-bit encodings.
+        *  + -EDOM is reserved to identify for cases in which no register
+        *    is used (i.e., displacement-only addressing). Use DS.
+        *  + SS for rSP or rBP.
+        *  + CS for rIP.
+        */
+
+       switch (off) {
+       case offsetof(struct pt_regs, ax):
+       case offsetof(struct pt_regs, cx):
+       case offsetof(struct pt_regs, dx):
+               /* Need insn to verify address size. */
+               if (insn->addr_bytes == 2)
+                       return -EINVAL;
+
+       case -EDOM:
+       case offsetof(struct pt_regs, bx):
+       case offsetof(struct pt_regs, si):
+               return INAT_SEG_REG_DS;
+
+       case offsetof(struct pt_regs, di):
+               if (is_string_insn(insn))
+                       return INAT_SEG_REG_ES;
+               return INAT_SEG_REG_DS;
+
+       case offsetof(struct pt_regs, bp):
+       case offsetof(struct pt_regs, sp):
+               return INAT_SEG_REG_SS;
+
+       case offsetof(struct pt_regs, ip):
+               return INAT_SEG_REG_CS;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+/**
+ * resolve_seg_reg() - obtain segment register index
+ * @insn:      Instruction with operands
+ * @regs:      Register values as seen when entering kernel mode
+ * @regoff:    Operand offset, in pt_regs, used to deterimine segment register
+ *
+ * Determine the segment register associated with the operands and, if
+ * applicable, prefixes and the instruction pointed by @insn.
+ *
+ * The segment register associated to an operand used in register-indirect
+ * addressing depends on:
+ *
+ * a) Whether running in long mode (in such a case segments are ignored, except
+ * if FS or GS are used).
+ *
+ * b) Whether segment override prefixes can be used. Certain instructions and
+ *    registers do not allow override prefixes.
+ *
+ * c) Whether segment overrides prefixes are found in the instruction prefixes.
+ *
+ * d) If there are not segment override prefixes or they cannot be used, the
+ *    default segment register associated with the operand register is used.
+ *
+ * The function checks first if segment override prefixes can be used with the
+ * operand indicated by @regoff. If allowed, obtain such overridden segment
+ * register index. Lastly, if not prefixes were found or cannot be used, resolve
+ * the segment register index to use based on the defaults described in the
+ * Intel documentation. In long mode, all segment register indexes will be
+ * ignored, except if overrides were found for FS or GS. All these operations
+ * are done using helper functions.
+ *
+ * The operand register, @regoff, is represented as the offset from the base of
+ * pt_regs.
+ *
+ * As stated, the main use of this function is to determine the segment register
+ * index based on the instruction, its operands and prefixes. Hence, @insn
+ * must be valid. However, if @regoff indicates rIP, we don't need to inspect
+ * @insn at all as in this case CS is used in all cases. This case is checked
+ * before proceeding further.
+ *
+ * Please note that this function does not return the value in the segment
+ * register (i.e., the segment selector) but our defined index. The segment
+ * selector needs to be obtained using get_segment_selector() and passing the
+ * segment register index resolved by this function.
+ *
+ * Returns:
+ *
+ * An index identifying the segment register to use, among CS, SS, DS,
+ * ES, FS, or GS. INAT_SEG_REG_IGNORE is returned if running in long mode.
+ *
+ * -EINVAL in case of error.
+ */
+static int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff)
+{
+       int idx;
+
+       /*
+        * In the unlikely event of having to resolve the segment register
+        * index for rIP, do it first. Segment override prefixes should not
+        * be used. Hence, it is not necessary to inspect the instruction,
+        * which may be invalid at this point.
+        */
+       if (regoff == offsetof(struct pt_regs, ip)) {
+               if (user_64bit_mode(regs))
+                       return INAT_SEG_REG_IGNORE;
+               else
+                       return INAT_SEG_REG_CS;
+       }
+
+       if (!insn)
+               return -EINVAL;
+
+       if (!check_seg_overrides(insn, regoff))
+               return resolve_default_seg(insn, regs, regoff);
+
+       idx = get_seg_reg_override_idx(insn);
+       if (idx < 0)
+               return idx;
+
+       if (idx == INAT_SEG_REG_DEFAULT)
+               return resolve_default_seg(insn, regs, regoff);
+
+       /*
+        * In long mode, segment override prefixes are ignored, except for
+        * overrides for FS and GS.
+        */
+       if (user_64bit_mode(regs)) {
+               if (idx != INAT_SEG_REG_FS &&
+                   idx != INAT_SEG_REG_GS)
+                       idx = INAT_SEG_REG_IGNORE;
+       }
+
+       return idx;
+}
+
+/**
+ * get_segment_selector() - obtain segment selector
+ * @regs:              Register values as seen when entering kernel mode
+ * @seg_reg_idx:       Segment register index to use
+ *
+ * Obtain the segment selector from any of the CS, SS, DS, ES, FS, GS segment
+ * registers. In CONFIG_X86_32, the segment is obtained from either pt_regs or
+ * kernel_vm86_regs as applicable. In CONFIG_X86_64, CS and SS are obtained
+ * from pt_regs. DS, ES, FS and GS are obtained by reading the actual CPU
+ * registers. This done for only for completeness as in CONFIG_X86_64 segment
+ * registers are ignored.
+ *
+ * Returns:
+ *
+ * Value of the segment selector, including null when running in
+ * long mode.
+ *
+ * -EINVAL on error.
+ */
+static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx)
+{
+#ifdef CONFIG_X86_64
+       unsigned short sel;
+
+       switch (seg_reg_idx) {
+       case INAT_SEG_REG_IGNORE:
+               return 0;
+       case INAT_SEG_REG_CS:
+               return (unsigned short)(regs->cs & 0xffff);
+       case INAT_SEG_REG_SS:
+               return (unsigned short)(regs->ss & 0xffff);
+       case INAT_SEG_REG_DS:
+               savesegment(ds, sel);
+               return sel;
+       case INAT_SEG_REG_ES:
+               savesegment(es, sel);
+               return sel;
+       case INAT_SEG_REG_FS:
+               savesegment(fs, sel);
+               return sel;
+       case INAT_SEG_REG_GS:
+               savesegment(gs, sel);
+               return sel;
+       default:
+               return -EINVAL;
+       }
+#else /* CONFIG_X86_32 */
+       struct kernel_vm86_regs *vm86regs = (struct kernel_vm86_regs *)regs;
+
+       if (v8086_mode(regs)) {
+               switch (seg_reg_idx) {
+               case INAT_SEG_REG_CS:
+                       return (unsigned short)(regs->cs & 0xffff);
+               case INAT_SEG_REG_SS:
+                       return (unsigned short)(regs->ss & 0xffff);
+               case INAT_SEG_REG_DS:
+                       return vm86regs->ds;
+               case INAT_SEG_REG_ES:
+                       return vm86regs->es;
+               case INAT_SEG_REG_FS:
+                       return vm86regs->fs;
+               case INAT_SEG_REG_GS:
+                       return vm86regs->gs;
+               case INAT_SEG_REG_IGNORE:
+                       /* fall through */
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       switch (seg_reg_idx) {
+       case INAT_SEG_REG_CS:
+               return (unsigned short)(regs->cs & 0xffff);
+       case INAT_SEG_REG_SS:
+               return (unsigned short)(regs->ss & 0xffff);
+       case INAT_SEG_REG_DS:
+               return (unsigned short)(regs->ds & 0xffff);
+       case INAT_SEG_REG_ES:
+               return (unsigned short)(regs->es & 0xffff);
+       case INAT_SEG_REG_FS:
+               return (unsigned short)(regs->fs & 0xffff);
+       case INAT_SEG_REG_GS:
+               /*
+                * GS may or may not be in regs as per CONFIG_X86_32_LAZY_GS.
+                * The macro below takes care of both cases.
+                */
+               return get_user_gs(regs);
+       case INAT_SEG_REG_IGNORE:
+               /* fall through */
+       default:
+               return -EINVAL;
+       }
+#endif /* CONFIG_X86_64 */
+}
+
+static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
+                         enum reg_type type)
+{
+       int regno = 0;
+
+       static const int regoff[] = {
+               offsetof(struct pt_regs, ax),
+               offsetof(struct pt_regs, cx),
+               offsetof(struct pt_regs, dx),
+               offsetof(struct pt_regs, bx),
+               offsetof(struct pt_regs, sp),
+               offsetof(struct pt_regs, bp),
+               offsetof(struct pt_regs, si),
+               offsetof(struct pt_regs, di),
+#ifdef CONFIG_X86_64
+               offsetof(struct pt_regs, r8),
+               offsetof(struct pt_regs, r9),
+               offsetof(struct pt_regs, r10),
+               offsetof(struct pt_regs, r11),
+               offsetof(struct pt_regs, r12),
+               offsetof(struct pt_regs, r13),
+               offsetof(struct pt_regs, r14),
+               offsetof(struct pt_regs, r15),
+#endif
+       };
+       int nr_registers = ARRAY_SIZE(regoff);
+       /*
+        * Don't possibly decode a 32-bit instructions as
+        * reading a 64-bit-only register.
+        */
+       if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64)
+               nr_registers -= 8;
+
+       switch (type) {
+       case REG_TYPE_RM:
+               regno = X86_MODRM_RM(insn->modrm.value);
+
+               /*
+                * ModRM.mod == 0 and ModRM.rm == 5 means a 32-bit displacement
+                * follows the ModRM byte.
+                */
+               if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5)
+                       return -EDOM;
+
+               if (X86_REX_B(insn->rex_prefix.value))
+                       regno += 8;
+               break;
+
+       case REG_TYPE_INDEX:
+               regno = X86_SIB_INDEX(insn->sib.value);
+               if (X86_REX_X(insn->rex_prefix.value))
+                       regno += 8;
+
+               /*
+                * If ModRM.mod != 3 and SIB.index = 4 the scale*index
+                * portion of the address computation is null. This is
+                * true only if REX.X is 0. In such a case, the SIB index
+                * is used in the address computation.
+                */
+               if (X86_MODRM_MOD(insn->modrm.value) != 3 && regno == 4)
+                       return -EDOM;
+               break;
+
+       case REG_TYPE_BASE:
+               regno = X86_SIB_BASE(insn->sib.value);
+               /*
+                * If ModRM.mod is 0 and SIB.base == 5, the base of the
+                * register-indirect addressing is 0. In this case, a
+                * 32-bit displacement follows the SIB byte.
+                */
+               if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5)
+                       return -EDOM;
+
+               if (X86_REX_B(insn->rex_prefix.value))
+                       regno += 8;
+               break;
+
+       default:
+               pr_err_ratelimited("invalid register type: %d\n", type);
+               return -EINVAL;
+       }
+
+       if (regno >= nr_registers) {
+               WARN_ONCE(1, "decoded an instruction with an invalid register");
+               return -EINVAL;
+       }
+       return regoff[regno];
+}
+
+/**
+ * get_reg_offset_16() - Obtain offset of register indicated by instruction
+ * @insn:      Instruction containing ModRM byte
+ * @regs:      Register values as seen when entering kernel mode
+ * @offs1:     Offset of the first operand register
+ * @offs2:     Offset of the second opeand register, if applicable
+ *
+ * Obtain the offset, in pt_regs, of the registers indicated by the ModRM byte
+ * in @insn. This function is to be used with 16-bit address encodings. The
+ * @offs1 and @offs2 will be written with the offset of the two registers
+ * indicated by the instruction. In cases where any of the registers is not
+ * referenced by the instruction, the value will be set to -EDOM.
+ *
+ * Returns:
+ *
+ * 0 on success, -EINVAL on error.
+ */
+static int get_reg_offset_16(struct insn *insn, struct pt_regs *regs,
+                            int *offs1, int *offs2)
+{
+       /*
+        * 16-bit addressing can use one or two registers. Specifics of
+        * encodings are given in Table 2-1. "16-Bit Addressing Forms with the
+        * ModR/M Byte" of the Intel Software Development Manual.
+        */
+       static const int regoff1[] = {
+               offsetof(struct pt_regs, bx),
+               offsetof(struct pt_regs, bx),
+               offsetof(struct pt_regs, bp),
+               offsetof(struct pt_regs, bp),
+               offsetof(struct pt_regs, si),
+               offsetof(struct pt_regs, di),
+               offsetof(struct pt_regs, bp),
+               offsetof(struct pt_regs, bx),
+       };
+
+       static const int regoff2[] = {
+               offsetof(struct pt_regs, si),
+               offsetof(struct pt_regs, di),
+               offsetof(struct pt_regs, si),
+               offsetof(struct pt_regs, di),
+               -EDOM,
+               -EDOM,
+               -EDOM,
+               -EDOM,
+       };
+
+       if (!offs1 || !offs2)
+               return -EINVAL;
+
+       /* Operand is a register, use the generic function. */
+       if (X86_MODRM_MOD(insn->modrm.value) == 3) {
+               *offs1 = insn_get_modrm_rm_off(insn, regs);
+               *offs2 = -EDOM;
+               return 0;
+       }
+
+       *offs1 = regoff1[X86_MODRM_RM(insn->modrm.value)];
+       *offs2 = regoff2[X86_MODRM_RM(insn->modrm.value)];
+
+       /*
+        * If ModRM.mod is 0 and ModRM.rm is 110b, then we use displacement-
+        * only addressing. This means that no registers are involved in
+        * computing the effective address. Thus, ensure that the first
+        * register offset is invalild. The second register offset is already
+        * invalid under the aforementioned conditions.
+        */
+       if ((X86_MODRM_MOD(insn->modrm.value) == 0) &&
+           (X86_MODRM_RM(insn->modrm.value) == 6))
+               *offs1 = -EDOM;
+
+       return 0;
+}
+
+/**
+ * get_desc() - Obtain pointer to a segment descriptor
+ * @sel:       Segment selector
+ *
+ * Given a segment selector, obtain a pointer to the segment descriptor.
+ * Both global and local descriptor tables are supported.
+ *
+ * Returns:
+ *
+ * Pointer to segment descriptor on success.
+ *
+ * NULL on error.
+ */
+static struct desc_struct *get_desc(unsigned short sel)
+{
+       struct desc_ptr gdt_desc = {0, 0};
+       unsigned long desc_base;
+
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+       if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) {
+               struct desc_struct *desc = NULL;
+               struct ldt_struct *ldt;
+
+               /* Bits [15:3] contain the index of the desired entry. */
+               sel >>= 3;
+
+               mutex_lock(&current->active_mm->context.lock);
+               ldt = current->active_mm->context.ldt;
+               if (ldt && sel < ldt->nr_entries)
+                       desc = &ldt->entries[sel];
+
+               mutex_unlock(&current->active_mm->context.lock);
+
+               return desc;
+       }
+#endif
+       native_store_gdt(&gdt_desc);
+
+       /*
+        * Segment descriptors have a size of 8 bytes. Thus, the index is
+        * multiplied by 8 to obtain the memory offset of the desired descriptor
+        * from the base of the GDT. As bits [15:3] of the segment selector
+        * contain the index, it can be regarded as multiplied by 8 already.
+        * All that remains is to clear bits [2:0].
+        */
+       desc_base = sel & ~(SEGMENT_RPL_MASK | SEGMENT_TI_MASK);
+
+       if (desc_base > gdt_desc.size)
+               return NULL;
+
+       return (struct desc_struct *)(gdt_desc.address + desc_base);
+}
+
+/**
+ * insn_get_seg_base() - Obtain base address of segment descriptor.
+ * @regs:              Register values as seen when entering kernel mode
+ * @seg_reg_idx:       Index of the segment register pointing to seg descriptor
+ *
+ * Obtain the base address of the segment as indicated by the segment descriptor
+ * pointed by the segment selector. The segment selector is obtained from the
+ * input segment register index @seg_reg_idx.
+ *
+ * Returns:
+ *
+ * In protected mode, base address of the segment. Zero in long mode,
+ * except when FS or GS are used. In virtual-8086 mode, the segment
+ * selector shifted 4 bits to the right.
+ *
+ * -1L in case of error.
+ */
+unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx)
+{
+       struct desc_struct *desc;
+       short sel;
+
+       sel = get_segment_selector(regs, seg_reg_idx);
+       if (sel < 0)
+               return -1L;
+
+       if (v8086_mode(regs))
+               /*
+                * Base is simply the segment selector shifted 4
+                * bits to the right.
+                */
+               return (unsigned long)(sel << 4);
+
+       if (user_64bit_mode(regs)) {
+               /*
+                * Only FS or GS will have a base address, the rest of
+                * the segments' bases are forced to 0.
+                */
+               unsigned long base;
+
+               if (seg_reg_idx == INAT_SEG_REG_FS)
+                       rdmsrl(MSR_FS_BASE, base);
+               else if (seg_reg_idx == INAT_SEG_REG_GS)
+                       /*
+                        * swapgs was called at the kernel entry point. Thus,
+                        * MSR_KERNEL_GS_BASE will have the user-space GS base.
+                        */
+                       rdmsrl(MSR_KERNEL_GS_BASE, base);
+               else
+                       base = 0;
+               return base;
+       }
+
+       /* In protected mode the segment selector cannot be null. */
+       if (!sel)
+               return -1L;
+
+       desc = get_desc(sel);
+       if (!desc)
+               return -1L;
+
+       return get_desc_base(desc);
+}
+
+/**
+ * get_seg_limit() - Obtain the limit of a segment descriptor
+ * @regs:              Register values as seen when entering kernel mode
+ * @seg_reg_idx:       Index of the segment register pointing to seg descriptor
+ *
+ * Obtain the limit of the segment as indicated by the segment descriptor
+ * pointed by the segment selector. The segment selector is obtained from the
+ * input segment register index @seg_reg_idx.
+ *
+ * Returns:
+ *
+ * In protected mode, the limit of the segment descriptor in bytes.
+ * In long mode and virtual-8086 mode, segment limits are not enforced. Thus,
+ * limit is returned as -1L to imply a limit-less segment.
+ *
+ * Zero is returned on error.
+ */
+static unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx)
+{
+       struct desc_struct *desc;
+       unsigned long limit;
+       short sel;
+
+       sel = get_segment_selector(regs, seg_reg_idx);
+       if (sel < 0)
+               return 0;
+
+       if (user_64bit_mode(regs) || v8086_mode(regs))
+               return -1L;
+
+       if (!sel)
+               return 0;
+
+       desc = get_desc(sel);
+       if (!desc)
+               return 0;
+
+       /*
+        * If the granularity bit is set, the limit is given in multiples
+        * of 4096. This also means that the 12 least significant bits are
+        * not tested when checking the segment limits. In practice,
+        * this means that the segment ends in (limit << 12) + 0xfff.
+        */
+       limit = get_desc_limit(desc);
+       if (desc->g)
+               limit = (limit << 12) + 0xfff;
+
+       return limit;
+}
+
+/**
+ * insn_get_code_seg_params() - Obtain code segment parameters
+ * @regs:      Structure with register values as seen when entering kernel mode
+ *
+ * Obtain address and operand sizes of the code segment. It is obtained from the
+ * selector contained in the CS register in regs. In protected mode, the default
+ * address is determined by inspecting the L and D bits of the segment
+ * descriptor. In virtual-8086 mode, the default is always two bytes for both
+ * address and operand sizes.
+ *
+ * Returns:
+ *
+ * A signed 8-bit value containing the default parameters on success.
+ *
+ * -EINVAL on error.
+ */
+char insn_get_code_seg_params(struct pt_regs *regs)
+{
+       struct desc_struct *desc;
+       short sel;
+
+       if (v8086_mode(regs))
+               /* Address and operand size are both 16-bit. */
+               return INSN_CODE_SEG_PARAMS(2, 2);
+
+       sel = get_segment_selector(regs, INAT_SEG_REG_CS);
+       if (sel < 0)
+               return sel;
+
+       desc = get_desc(sel);
+       if (!desc)
+               return -EINVAL;
+
+       /*
+        * The most significant byte of the Type field of the segment descriptor
+        * determines whether a segment contains data or code. If this is a data
+        * segment, return error.
+        */
+       if (!(desc->type & BIT(3)))
+               return -EINVAL;
+
+       switch ((desc->l << 1) | desc->d) {
+       case 0: /*
+                * Legacy mode. CS.L=0, CS.D=0. Address and operand size are
+                * both 16-bit.
+                */
+               return INSN_CODE_SEG_PARAMS(2, 2);
+       case 1: /*
+                * Legacy mode. CS.L=0, CS.D=1. Address and operand size are
+                * both 32-bit.
+                */
+               return INSN_CODE_SEG_PARAMS(4, 4);
+       case 2: /*
+                * IA-32e 64-bit mode. CS.L=1, CS.D=0. Address size is 64-bit;
+                * operand size is 32-bit.
+                */
+               return INSN_CODE_SEG_PARAMS(4, 8);
+       case 3: /* Invalid setting. CS.L=1, CS.D=1 */
+               /* fall through */
+       default:
+               return -EINVAL;
+       }
+}
+
+/**
+ * insn_get_modrm_rm_off() - Obtain register in r/m part of the ModRM byte
+ * @insn:      Instruction containing the ModRM byte
+ * @regs:      Register values as seen when entering kernel mode
+ *
+ * Returns:
+ *
+ * The register indicated by the r/m part of the ModRM byte. The
+ * register is obtained as an offset from the base of pt_regs. In specific
+ * cases, the returned value can be -EDOM to indicate that the particular value
+ * of ModRM does not refer to a register and shall be ignored.
+ */
+int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs)
+{
+       return get_reg_offset(insn, regs, REG_TYPE_RM);
+}
+
+/**
+ * get_seg_base_limit() - obtain base address and limit of a segment
+ * @insn:      Instruction. Must be valid.
+ * @regs:      Register values as seen when entering kernel mode
+ * @regoff:    Operand offset, in pt_regs, used to resolve segment descriptor
+ * @base:      Obtained segment base
+ * @limit:     Obtained segment limit
+ *
+ * Obtain the base address and limit of the segment associated with the operand
+ * @regoff and, if any or allowed, override prefixes in @insn. This function is
+ * different from insn_get_seg_base() as the latter does not resolve the segment
+ * associated with the instruction operand. If a limit is not needed (e.g.,
+ * when running in long mode), @limit can be NULL.
+ *
+ * Returns:
+ *
+ * 0 on success. @base and @limit will contain the base address and of the
+ * resolved segment, respectively.
+ *
+ * -EINVAL on error.
+ */
+static int get_seg_base_limit(struct insn *insn, struct pt_regs *regs,
+                             int regoff, unsigned long *base,
+                             unsigned long *limit)
+{
+       int seg_reg_idx;
+
+       if (!base)
+               return -EINVAL;
+
+       seg_reg_idx = resolve_seg_reg(insn, regs, regoff);
+       if (seg_reg_idx < 0)
+               return seg_reg_idx;
+
+       *base = insn_get_seg_base(regs, seg_reg_idx);
+       if (*base == -1L)
+               return -EINVAL;
+
+       if (!limit)
+               return 0;
+
+       *limit = get_seg_limit(regs, seg_reg_idx);
+       if (!(*limit))
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * get_eff_addr_reg() - Obtain effective address from register operand
+ * @insn:      Instruction. Must be valid.
+ * @regs:      Register values as seen when entering kernel mode
+ * @regoff:    Obtained operand offset, in pt_regs, with the effective address
+ * @eff_addr:  Obtained effective address
+ *
+ * Obtain the effective address stored in the register operand as indicated by
+ * the ModRM byte. This function is to be used only with register addressing
+ * (i.e.,  ModRM.mod is 3). The effective address is saved in @eff_addr. The
+ * register operand, as an offset from the base of pt_regs, is saved in @regoff;
+ * such offset can then be used to resolve the segment associated with the
+ * operand. This function can be used with any of the supported address sizes
+ * in x86.
+ *
+ * Returns:
+ *
+ * 0 on success. @eff_addr will have the effective address stored in the
+ * operand indicated by ModRM. @regoff will have such operand as an offset from
+ * the base of pt_regs.
+ *
+ * -EINVAL on error.
+ */
+static int get_eff_addr_reg(struct insn *insn, struct pt_regs *regs,
+                           int *regoff, long *eff_addr)
+{
+       insn_get_modrm(insn);
+
+       if (!insn->modrm.nbytes)
+               return -EINVAL;
+
+       if (X86_MODRM_MOD(insn->modrm.value) != 3)
+               return -EINVAL;
+
+       *regoff = get_reg_offset(insn, regs, REG_TYPE_RM);
+       if (*regoff < 0)
+               return -EINVAL;
+
+       /* Ignore bytes that are outside the address size. */
+       if (insn->addr_bytes == 2)
+               *eff_addr = regs_get_register(regs, *regoff) & 0xffff;
+       else if (insn->addr_bytes == 4)
+               *eff_addr = regs_get_register(regs, *regoff) & 0xffffffff;
+       else /* 64-bit address */
+               *eff_addr = regs_get_register(regs, *regoff);
+
+       return 0;
+}
+
+/**
+ * get_eff_addr_modrm() - Obtain referenced effective address via ModRM
+ * @insn:      Instruction. Must be valid.
+ * @regs:      Register values as seen when entering kernel mode
+ * @regoff:    Obtained operand offset, in pt_regs, associated with segment
+ * @eff_addr:  Obtained effective address
+ *
+ * Obtain the effective address referenced by the ModRM byte of @insn. After
+ * identifying the registers involved in the register-indirect memory reference,
+ * its value is obtained from the operands in @regs. The computed address is
+ * stored @eff_addr. Also, the register operand that indicates the associated
+ * segment is stored in @regoff, this parameter can later be used to determine
+ * such segment.
+ *
+ * Returns:
+ *
+ * 0 on success. @eff_addr will have the referenced effective address. @regoff
+ * will have a register, as an offset from the base of pt_regs, that can be used
+ * to resolve the associated segment.
+ *
+ * -EINVAL on error.
+ */
+static int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs,
+                             int *regoff, long *eff_addr)
+{
+       long tmp;
+
+       if (insn->addr_bytes != 8 && insn->addr_bytes != 4)
+               return -EINVAL;
+
+       insn_get_modrm(insn);
+
+       if (!insn->modrm.nbytes)
+               return -EINVAL;
+
+       if (X86_MODRM_MOD(insn->modrm.value) > 2)
+               return -EINVAL;
+
+       *regoff = get_reg_offset(insn, regs, REG_TYPE_RM);
+
+       /*
+        * -EDOM means that we must ignore the address_offset. In such a case,
+        * in 64-bit mode the effective address relative to the rIP of the
+        * following instruction.
+        */
+       if (*regoff == -EDOM) {
+               if (user_64bit_mode(regs))
+                       tmp = regs->ip + insn->length;
+               else
+                       tmp = 0;
+       } else if (*regoff < 0) {
+               return -EINVAL;
+       } else {
+               tmp = regs_get_register(regs, *regoff);
+       }
+
+       if (insn->addr_bytes == 4) {
+               int addr32 = (int)(tmp & 0xffffffff) + insn->displacement.value;
+
+               *eff_addr = addr32 & 0xffffffff;
+       } else {
+               *eff_addr = tmp + insn->displacement.value;
+       }
+
+       return 0;
+}
+
+/**
+ * get_eff_addr_modrm_16() - Obtain referenced effective address via ModRM
+ * @insn:      Instruction. Must be valid.
+ * @regs:      Register values as seen when entering kernel mode
+ * @regoff:    Obtained operand offset, in pt_regs, associated with segment
+ * @eff_addr:  Obtained effective address
+ *
+ * Obtain the 16-bit effective address referenced by the ModRM byte of @insn.
+ * After identifying the registers involved in the register-indirect memory
+ * reference, its value is obtained from the operands in @regs. The computed
+ * address is stored @eff_addr. Also, the register operand that indicates
+ * the associated segment is stored in @regoff, this parameter can later be used
+ * to determine such segment.
+ *
+ * Returns:
+ *
+ * 0 on success. @eff_addr will have the referenced effective address. @regoff
+ * will have a register, as an offset from the base of pt_regs, that can be used
+ * to resolve the associated segment.
+ *
+ * -EINVAL on error.
+ */
+static int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs,
+                                int *regoff, short *eff_addr)
+{
+       int addr_offset1, addr_offset2, ret;
+       short addr1 = 0, addr2 = 0, displacement;
+
+       if (insn->addr_bytes != 2)
+               return -EINVAL;
+
+       insn_get_modrm(insn);
+
+       if (!insn->modrm.nbytes)
+               return -EINVAL;
+
+       if (X86_MODRM_MOD(insn->modrm.value) > 2)
+               return -EINVAL;
+
+       ret = get_reg_offset_16(insn, regs, &addr_offset1, &addr_offset2);
+       if (ret < 0)
+               return -EINVAL;
+
+       /*
+        * Don't fail on invalid offset values. They might be invalid because
+        * they cannot be used for this particular value of ModRM. Instead, use
+        * them in the computation only if they contain a valid value.
+        */
+       if (addr_offset1 != -EDOM)
+               addr1 = regs_get_register(regs, addr_offset1) & 0xffff;
+
+       if (addr_offset2 != -EDOM)
+               addr2 = regs_get_register(regs, addr_offset2) & 0xffff;
+
+       displacement = insn->displacement.value & 0xffff;
+       *eff_addr = addr1 + addr2 + displacement;
+
+       /*
+        * The first operand register could indicate to use of either SS or DS
+        * registers to obtain the segment selector.  The second operand
+        * register can only indicate the use of DS. Thus, the first operand
+        * will be used to obtain the segment selector.
+        */
+       *regoff = addr_offset1;
+
+       return 0;
+}
+
+/**
+ * get_eff_addr_sib() - Obtain referenced effective address via SIB
+ * @insn:      Instruction. Must be valid.
+ * @regs:      Register values as seen when entering kernel mode
+ * @regoff:    Obtained operand offset, in pt_regs, associated with segment
+ * @eff_addr:  Obtained effective address
+ *
+ * Obtain the effective address referenced by the SIB byte of @insn. After
+ * identifying the registers involved in the indexed, register-indirect memory
+ * reference, its value is obtained from the operands in @regs. The computed
+ * address is stored @eff_addr. Also, the register operand that indicates the
+ * associated segment is stored in @regoff, this parameter can later be used to
+ * determine such segment.
+ *
+ * Returns:
+ *
+ * 0 on success. @eff_addr will have the referenced effective address.
+ * @base_offset will have a register, as an offset from the base of pt_regs,
+ * that can be used to resolve the associated segment.
+ *
+ * -EINVAL on error.
+ */
+static int get_eff_addr_sib(struct insn *insn, struct pt_regs *regs,
+                           int *base_offset, long *eff_addr)
+{
+       long base, indx;
+       int indx_offset;
+
+       if (insn->addr_bytes != 8 && insn->addr_bytes != 4)
+               return -EINVAL;
+
+       insn_get_modrm(insn);
+
+       if (!insn->modrm.nbytes)
+               return -EINVAL;
+
+       if (X86_MODRM_MOD(insn->modrm.value) > 2)
+               return -EINVAL;
+
+       insn_get_sib(insn);
+
+       if (!insn->sib.nbytes)
+               return -EINVAL;
+
+       *base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
+       indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
+
+       /*
+        * Negative values in the base and index offset means an error when
+        * decoding the SIB byte. Except -EDOM, which means that the registers
+        * should not be used in the address computation.
+        */
+       if (*base_offset == -EDOM)
+               base = 0;
+       else if (*base_offset < 0)
+               return -EINVAL;
+       else
+               base = regs_get_register(regs, *base_offset);
+
+       if (indx_offset == -EDOM)
+               indx = 0;
+       else if (indx_offset < 0)
+               return -EINVAL;
+       else
+               indx = regs_get_register(regs, indx_offset);
+
+       if (insn->addr_bytes == 4) {
+               int addr32, base32, idx32;
+
+               base32 = base & 0xffffffff;
+               idx32 = indx & 0xffffffff;
+
+               addr32 = base32 + idx32 * (1 << X86_SIB_SCALE(insn->sib.value));
+               addr32 += insn->displacement.value;
+
+               *eff_addr = addr32 & 0xffffffff;
+       } else {
+               *eff_addr = base + indx * (1 << X86_SIB_SCALE(insn->sib.value));
+               *eff_addr += insn->displacement.value;
+       }
+
+       return 0;
+}
+
+/**
+ * get_addr_ref_16() - Obtain the 16-bit address referred by instruction
+ * @insn:      Instruction containing ModRM byte and displacement
+ * @regs:      Register values as seen when entering kernel mode
+ *
+ * This function is to be used with 16-bit address encodings. Obtain the memory
+ * address referred by the instruction's ModRM and displacement bytes. Also, the
+ * segment used as base is determined by either any segment override prefixes in
+ * @insn or the default segment of the registers involved in the address
+ * computation. In protected mode, segment limits are enforced.
+ *
+ * Returns:
+ *
+ * Linear address referenced by the instruction operands on success.
+ *
+ * -1L on error.
+ */
+static void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs)
+{
+       unsigned long linear_addr = -1L, seg_base, seg_limit;
+       int ret, regoff;
+       short eff_addr;
+       long tmp;
+
+       insn_get_modrm(insn);
+       insn_get_displacement(insn);
+
+       if (insn->addr_bytes != 2)
+               goto out;
+
+       if (X86_MODRM_MOD(insn->modrm.value) == 3) {
+               ret = get_eff_addr_reg(insn, regs, &regoff, &tmp);
+               if (ret)
+                       goto out;
+
+               eff_addr = tmp;
+       } else {
+               ret = get_eff_addr_modrm_16(insn, regs, &regoff, &eff_addr);
+               if (ret)
+                       goto out;
+       }
+
+       ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit);
+       if (ret)
+               goto out;
+
+       /*
+        * Before computing the linear address, make sure the effective address
+        * is within the limits of the segment. In virtual-8086 mode, segment
+        * limits are not enforced. In such a case, the segment limit is -1L to
+        * reflect this fact.
+        */
+       if ((unsigned long)(eff_addr & 0xffff) > seg_limit)
+               goto out;
+
+       linear_addr = (unsigned long)(eff_addr & 0xffff) + seg_base;
+
+       /* Limit linear address to 20 bits */
+       if (v8086_mode(regs))
+               linear_addr &= 0xfffff;
+
+out:
+       return (void __user *)linear_addr;
+}
+
+/**
+ * get_addr_ref_32() - Obtain a 32-bit linear address
+ * @insn:      Instruction with ModRM, SIB bytes and displacement
+ * @regs:      Register values as seen when entering kernel mode
+ *
+ * This function is to be used with 32-bit address encodings to obtain the
+ * linear memory address referred by the instruction's ModRM, SIB,
+ * displacement bytes and segment base address, as applicable. If in protected
+ * mode, segment limits are enforced.
+ *
+ * Returns:
+ *
+ * Linear address referenced by instruction and registers on success.
+ *
+ * -1L on error.
+ */
+static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs)
+{
+       unsigned long linear_addr = -1L, seg_base, seg_limit;
+       int eff_addr, regoff;
+       long tmp;
+       int ret;
+
+       if (insn->addr_bytes != 4)
+               goto out;
+
+       if (X86_MODRM_MOD(insn->modrm.value) == 3) {
+               ret = get_eff_addr_reg(insn, regs, &regoff, &tmp);
+               if (ret)
+                       goto out;
+
+               eff_addr = tmp;
+
+       } else {
+               if (insn->sib.nbytes) {
+                       ret = get_eff_addr_sib(insn, regs, &regoff, &tmp);
+                       if (ret)
+                               goto out;
+
+                       eff_addr = tmp;
+               } else {
+                       ret = get_eff_addr_modrm(insn, regs, &regoff, &tmp);
+                       if (ret)
+                               goto out;
+
+                       eff_addr = tmp;
+               }
+       }
+
+       ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit);
+       if (ret)
+               goto out;
+
+       /*
+        * In protected mode, before computing the linear address, make sure
+        * the effective address is within the limits of the segment.
+        * 32-bit addresses can be used in long and virtual-8086 modes if an
+        * address override prefix is used. In such cases, segment limits are
+        * not enforced. When in virtual-8086 mode, the segment limit is -1L
+        * to reflect this situation.
+        *
+        * After computed, the effective address is treated as an unsigned
+        * quantity.
+        */
+       if (!user_64bit_mode(regs) && ((unsigned int)eff_addr > seg_limit))
+               goto out;
+
+       /*
+        * Even though 32-bit address encodings are allowed in virtual-8086
+        * mode, the address range is still limited to [0x-0xffff].
+        */
+       if (v8086_mode(regs) && (eff_addr & ~0xffff))
+               goto out;
+
+       /*
+        * Data type long could be 64 bits in size. Ensure that our 32-bit
+        * effective address is not sign-extended when computing the linear
+        * address.
+        */
+       linear_addr = (unsigned long)(eff_addr & 0xffffffff) + seg_base;
+
+       /* Limit linear address to 20 bits */
+       if (v8086_mode(regs))
+               linear_addr &= 0xfffff;
+
+out:
+       return (void __user *)linear_addr;
+}
+
+/**
+ * get_addr_ref_64() - Obtain a 64-bit linear address
+ * @insn:      Instruction struct with ModRM and SIB bytes and displacement
+ * @regs:      Structure with register values as seen when entering kernel mode
+ *
+ * This function is to be used with 64-bit address encodings to obtain the
+ * linear memory address referred by the instruction's ModRM, SIB,
+ * displacement bytes and segment base address, as applicable.
+ *
+ * Returns:
+ *
+ * Linear address referenced by instruction and registers on success.
+ *
+ * -1L on error.
+ */
+#ifndef CONFIG_X86_64
+static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs)
+{
+       return (void __user *)-1L;
+}
+#else
+static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs)
+{
+       unsigned long linear_addr = -1L, seg_base;
+       int regoff, ret;
+       long eff_addr;
+
+       if (insn->addr_bytes != 8)
+               goto out;
+
+       if (X86_MODRM_MOD(insn->modrm.value) == 3) {
+               ret = get_eff_addr_reg(insn, regs, &regoff, &eff_addr);
+               if (ret)
+                       goto out;
+
+       } else {
+               if (insn->sib.nbytes) {
+                       ret = get_eff_addr_sib(insn, regs, &regoff, &eff_addr);
+                       if (ret)
+                               goto out;
+               } else {
+                       ret = get_eff_addr_modrm(insn, regs, &regoff, &eff_addr);
+                       if (ret)
+                               goto out;
+               }
+
+       }
+
+       ret = get_seg_base_limit(insn, regs, regoff, &seg_base, NULL);
+       if (ret)
+               goto out;
+
+       linear_addr = (unsigned long)eff_addr + seg_base;
+
+out:
+       return (void __user *)linear_addr;
+}
+#endif /* CONFIG_X86_64 */
+
+/**
+ * insn_get_addr_ref() - Obtain the linear address referred by instruction
+ * @insn:      Instruction structure containing ModRM byte and displacement
+ * @regs:      Structure with register values as seen when entering kernel mode
+ *
+ * Obtain the linear address referred by the instruction's ModRM, SIB and
+ * displacement bytes, and segment base, as applicable. In protected mode,
+ * segment limits are enforced.
+ *
+ * Returns:
+ *
+ * Linear address referenced by instruction and registers on success.
+ *
+ * -1L on error.
+ */
+void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
+{
+       if (!insn || !regs)
+               return (void __user *)-1L;
+
+       switch (insn->addr_bytes) {
+       case 2:
+               return get_addr_ref_16(insn, regs);
+       case 4:
+               return get_addr_ref_32(insn, regs);
+       case 8:
+               return get_addr_ref_64(insn, regs);
+       default:
+               return (void __user *)-1L;
+       }
+}
index bf2c6074efd2fb97886d974dea2668f8da59c49c..dc2ab6ea676864a7c8f219856a20242f4da57195 100644 (file)
@@ -98,6 +98,18 @@ ENTRY(call_rwsem_down_read_failed)
        ret
 ENDPROC(call_rwsem_down_read_failed)
 
+ENTRY(call_rwsem_down_read_failed_killable)
+       FRAME_BEGIN
+       save_common_regs
+       __ASM_SIZE(push,) %__ASM_REG(dx)
+       movq %rax,%rdi
+       call rwsem_down_read_failed_killable
+       __ASM_SIZE(pop,) %__ASM_REG(dx)
+       restore_common_regs
+       FRAME_END
+       ret
+ENDPROC(call_rwsem_down_read_failed_killable)
+
 ENTRY(call_rwsem_down_write_failed)
        FRAME_BEGIN
        save_common_regs
index c3521e2be39610c3d932c34126fadd5203f28958..3321b446b66cdb99f16fe145bf9bad50f9d1fd01 100644 (file)
@@ -67,12 +67,17 @@ bool ex_handler_refcount(const struct exception_table_entry *fixup,
         * wrapped around) will be set. Additionally, seeing the refcount
         * reach 0 will set ZF (Zero Flag: result was zero). In each of
         * these cases we want a report, since it's a boundary condition.
-        *
+        * The SF case is not reported since it indicates post-boundary
+        * manipulations below zero or above INT_MAX. And if none of the
+        * flags are set, something has gone very wrong, so report it.
         */
        if (regs->flags & (X86_EFLAGS_OF | X86_EFLAGS_ZF)) {
                bool zero = regs->flags & X86_EFLAGS_ZF;
 
                refcount_error_report(regs, zero ? "hit zero" : "overflow");
+       } else if ((regs->flags & X86_EFLAGS_SF) == 0) {
+               /* Report if none of OF, ZF, nor SF are set. */
+               refcount_error_report(regs, "unexpected saturation");
        }
 
        return true;
index b0ff378650a9c7ef988d2fa6c984ceae9c19df54..3109ba6c6edeedb3f22e1ef81fd37b5e4757b4dc 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <asm/trace/exceptions.h>
 
-/*
- * Page fault error code bits:
- *
- *   bit 0 ==   0: no page found       1: protection fault
- *   bit 1 ==   0: read access         1: write access
- *   bit 2 ==   0: kernel-mode access  1: user-mode access
- *   bit 3 ==                          1: use of reserved bit detected
- *   bit 4 ==                          1: fault was an instruction fetch
- *   bit 5 ==                          1: protection keys block access
- */
-enum x86_pf_error_code {
-
-       PF_PROT         =               1 << 0,
-       PF_WRITE        =               1 << 1,
-       PF_USER         =               1 << 2,
-       PF_RSVD         =               1 << 3,
-       PF_INSTR        =               1 << 4,
-       PF_PK           =               1 << 5,
-};
-
 /*
  * Returns 0 if mmiotrace is disabled, or if the fault is not
  * handled by mmiotrace:
@@ -150,7 +130,7 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
         * If it was a exec (instruction fetch) fault on NX page, then
         * do not ignore the fault:
         */
-       if (error_code & PF_INSTR)
+       if (error_code & X86_PF_INSTR)
                return 0;
 
        instr = (void *)convert_ip_to_linear(current, regs);
@@ -180,7 +160,7 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
  * siginfo so userspace can discover which protection key was set
  * on the PTE.
  *
- * If we get here, we know that the hardware signaled a PF_PK
+ * If we get here, we know that the hardware signaled a X86_PF_PK
  * fault and that there was a VMA once we got in the fault
  * handler.  It does *not* guarantee that the VMA we find here
  * was the one that we faulted on.
@@ -205,7 +185,7 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey)
        /*
         * force_sig_info_fault() is called from a number of
         * contexts, some of which have a VMA and some of which
-        * do not.  The PF_PK handing happens after we have a
+        * do not.  The X86_PF_PK handing happens after we have a
         * valid VMA, so we should never reach this without a
         * valid VMA.
         */
@@ -698,7 +678,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
        if (!oops_may_print())
                return;
 
-       if (error_code & PF_INSTR) {
+       if (error_code & X86_PF_INSTR) {
                unsigned int level;
                pgd_t *pgd;
                pte_t *pte;
@@ -780,7 +760,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
                 */
                if (current->thread.sig_on_uaccess_err && signal) {
                        tsk->thread.trap_nr = X86_TRAP_PF;
-                       tsk->thread.error_code = error_code | PF_USER;
+                       tsk->thread.error_code = error_code | X86_PF_USER;
                        tsk->thread.cr2 = address;
 
                        /* XXX: hwpoison faults will set the wrong code. */
@@ -898,7 +878,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
        struct task_struct *tsk = current;
 
        /* User mode accesses just cause a SIGSEGV */
-       if (error_code & PF_USER) {
+       if (error_code & X86_PF_USER) {
                /*
                 * It's possible to have interrupts off here:
                 */
@@ -919,7 +899,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
                 * Instruction fetch faults in the vsyscall page might need
                 * emulation.
                 */
-               if (unlikely((error_code & PF_INSTR) &&
+               if (unlikely((error_code & X86_PF_INSTR) &&
                             ((address & ~0xfff) == VSYSCALL_ADDR))) {
                        if (emulate_vsyscall(regs, address))
                                return;
@@ -932,7 +912,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
                 * are always protection faults.
                 */
                if (address >= TASK_SIZE_MAX)
-                       error_code |= PF_PROT;
+                       error_code |= X86_PF_PROT;
 
                if (likely(show_unhandled_signals))
                        show_signal_msg(regs, error_code, address, tsk);
@@ -993,11 +973,11 @@ static inline bool bad_area_access_from_pkeys(unsigned long error_code,
 
        if (!boot_cpu_has(X86_FEATURE_OSPKE))
                return false;
-       if (error_code & PF_PK)
+       if (error_code & X86_PF_PK)
                return true;
        /* this checks permission keys on the VMA: */
-       if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE),
-                               (error_code & PF_INSTR), foreign))
+       if (!arch_vma_access_permitted(vma, (error_code & X86_PF_WRITE),
+                                      (error_code & X86_PF_INSTR), foreign))
                return true;
        return false;
 }
@@ -1025,7 +1005,7 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
        int code = BUS_ADRERR;
 
        /* Kernel mode? Handle exceptions or die: */
-       if (!(error_code & PF_USER)) {
+       if (!(error_code & X86_PF_USER)) {
                no_context(regs, error_code, address, SIGBUS, BUS_ADRERR);
                return;
        }
@@ -1053,14 +1033,14 @@ static noinline void
 mm_fault_error(struct pt_regs *regs, unsigned long error_code,
               unsigned long address, u32 *pkey, unsigned int fault)
 {
-       if (fatal_signal_pending(current) && !(error_code & PF_USER)) {
+       if (fatal_signal_pending(current) && !(error_code & X86_PF_USER)) {
                no_context(regs, error_code, address, 0, 0);
                return;
        }
 
        if (fault & VM_FAULT_OOM) {
                /* Kernel mode? Handle exceptions or die: */
-               if (!(error_code & PF_USER)) {
+               if (!(error_code & X86_PF_USER)) {
                        no_context(regs, error_code, address,
                                   SIGSEGV, SEGV_MAPERR);
                        return;
@@ -1085,16 +1065,16 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
 
 static int spurious_fault_check(unsigned long error_code, pte_t *pte)
 {
-       if ((error_code & PF_WRITE) && !pte_write(*pte))
+       if ((error_code & X86_PF_WRITE) && !pte_write(*pte))
                return 0;
 
-       if ((error_code & PF_INSTR) && !pte_exec(*pte))
+       if ((error_code & X86_PF_INSTR) && !pte_exec(*pte))
                return 0;
        /*
         * Note: We do not do lazy flushing on protection key
-        * changes, so no spurious fault will ever set PF_PK.
+        * changes, so no spurious fault will ever set X86_PF_PK.
         */
-       if ((error_code & PF_PK))
+       if ((error_code & X86_PF_PK))
                return 1;
 
        return 1;
@@ -1140,8 +1120,8 @@ spurious_fault(unsigned long error_code, unsigned long address)
         * change, so user accesses are not expected to cause spurious
         * faults.
         */
-       if (error_code != (PF_WRITE | PF_PROT)
-           && error_code != (PF_INSTR | PF_PROT))
+       if (error_code != (X86_PF_WRITE | X86_PF_PROT) &&
+           error_code != (X86_PF_INSTR | X86_PF_PROT))
                return 0;
 
        pgd = init_mm.pgd + pgd_index(address);
@@ -1201,19 +1181,19 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)
         * always an unconditional error and can never result in
         * a follow-up action to resolve the fault, like a COW.
         */
-       if (error_code & PF_PK)
+       if (error_code & X86_PF_PK)
                return 1;
 
        /*
         * Make sure to check the VMA so that we do not perform
-        * faults just to hit a PF_PK as soon as we fill in a
+        * faults just to hit a X86_PF_PK as soon as we fill in a
         * page.
         */
-       if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE),
-                               (error_code & PF_INSTR), foreign))
+       if (!arch_vma_access_permitted(vma, (error_code & X86_PF_WRITE),
+                                      (error_code & X86_PF_INSTR), foreign))
                return 1;
 
-       if (error_code & PF_WRITE) {
+       if (error_code & X86_PF_WRITE) {
                /* write, present and write, not present: */
                if (unlikely(!(vma->vm_flags & VM_WRITE)))
                        return 1;
@@ -1221,7 +1201,7 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)
        }
 
        /* read, present: */
-       if (unlikely(error_code & PF_PROT))
+       if (unlikely(error_code & X86_PF_PROT))
                return 1;
 
        /* read, not present: */
@@ -1244,7 +1224,7 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
        if (!static_cpu_has(X86_FEATURE_SMAP))
                return false;
 
-       if (error_code & PF_USER)
+       if (error_code & X86_PF_USER)
                return false;
 
        if (!user_mode(regs) && (regs->flags & X86_EFLAGS_AC))
@@ -1297,7 +1277,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
         * protection error (error_code & 9) == 0.
         */
        if (unlikely(fault_in_kernel_space(address))) {
-               if (!(error_code & (PF_RSVD | PF_USER | PF_PROT))) {
+               if (!(error_code & (X86_PF_RSVD | X86_PF_USER | X86_PF_PROT))) {
                        if (vmalloc_fault(address) >= 0)
                                return;
 
@@ -1325,7 +1305,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
        if (unlikely(kprobes_fault(regs)))
                return;
 
-       if (unlikely(error_code & PF_RSVD))
+       if (unlikely(error_code & X86_PF_RSVD))
                pgtable_bad(regs, error_code, address);
 
        if (unlikely(smap_violation(error_code, regs))) {
@@ -1351,7 +1331,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
         */
        if (user_mode(regs)) {
                local_irq_enable();
-               error_code |= PF_USER;
+               error_code |= X86_PF_USER;
                flags |= FAULT_FLAG_USER;
        } else {
                if (regs->flags & X86_EFLAGS_IF)
@@ -1360,9 +1340,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
 
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
-       if (error_code & PF_WRITE)
+       if (error_code & X86_PF_WRITE)
                flags |= FAULT_FLAG_WRITE;
-       if (error_code & PF_INSTR)
+       if (error_code & X86_PF_INSTR)
                flags |= FAULT_FLAG_INSTRUCTION;
 
        /*
@@ -1382,7 +1362,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
         * space check, thus avoiding the deadlock:
         */
        if (unlikely(!down_read_trylock(&mm->mmap_sem))) {
-               if ((error_code & PF_USER) == 0 &&
+               if (!(error_code & X86_PF_USER) &&
                    !search_exception_tables(regs->ip)) {
                        bad_area_nosemaphore(regs, error_code, address, NULL);
                        return;
@@ -1409,7 +1389,7 @@ retry:
                bad_area(regs, error_code, address);
                return;
        }
-       if (error_code & PF_USER) {
+       if (error_code & X86_PF_USER) {
                /*
                 * Accessing the stack below %sp is always a bug.
                 * The large cushion allows instructions like enter
index af5c1ed21d43ac651ecbe02e7a58dc7baa884168..a22c2b95e5133919e839d3c7a7a33b82b17e629c 100644 (file)
@@ -671,7 +671,7 @@ void __init init_mem_mapping(void)
        load_cr3(swapper_pg_dir);
        __flush_tlb_all();
 
-       hypervisor_init_mem_mapping();
+       x86_init.hyper.init_mem_mapping();
 
        early_memtest(0, max_pfn_mapped << PAGE_SHIFT);
 }
index 048fbe8fc274017cb6584e6b38fed174c457fc99..adcea90a2046e91aee1d4693e9c505dbcab1771c 100644 (file)
@@ -1426,16 +1426,16 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
 
 #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HAVE_BOOTMEM_INFO_NODE)
 void register_page_bootmem_memmap(unsigned long section_nr,
-                                 struct page *start_page, unsigned long size)
+                                 struct page *start_page, unsigned long nr_pages)
 {
        unsigned long addr = (unsigned long)start_page;
-       unsigned long end = (unsigned long)(start_page + size);
+       unsigned long end = (unsigned long)(start_page + nr_pages);
        unsigned long next;
        pgd_t *pgd;
        p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
-       unsigned int nr_pages;
+       unsigned int nr_pmd_pages;
        struct page *page;
 
        for (; addr < end; addr = next) {
@@ -1482,9 +1482,9 @@ void register_page_bootmem_memmap(unsigned long section_nr,
                        if (pmd_none(*pmd))
                                continue;
 
-                       nr_pages = 1 << (get_order(PMD_SIZE));
+                       nr_pmd_pages = 1 << get_order(PMD_SIZE);
                        page = pmd_page(*pmd);
-                       while (nr_pages--)
+                       while (nr_pmd_pages--)
                                get_page_bootmem(section_nr, page++,
                                                 SECTION_INFO);
                }
index 34f0e1847dd64bc82a10679b9896c3d8886aa330..6e4573b1da341bd41095b11a692afcba51e4b850 100644 (file)
 
 #include "physaddr.h"
 
+struct ioremap_mem_flags {
+       bool system_ram;
+       bool desc_other;
+};
+
 /*
  * Fix up the linear direct mapping of the kernel to avoid cache attribute
  * conflicts.
@@ -56,17 +61,59 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
        return err;
 }
 
-static int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages,
-                              void *arg)
+static bool __ioremap_check_ram(struct resource *res)
 {
+       unsigned long start_pfn, stop_pfn;
        unsigned long i;
 
-       for (i = 0; i < nr_pages; ++i)
-               if (pfn_valid(start_pfn + i) &&
-                   !PageReserved(pfn_to_page(start_pfn + i)))
-                       return 1;
+       if ((res->flags & IORESOURCE_SYSTEM_RAM) != IORESOURCE_SYSTEM_RAM)
+               return false;
 
-       return 0;
+       start_pfn = (res->start + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       stop_pfn = (res->end + 1) >> PAGE_SHIFT;
+       if (stop_pfn > start_pfn) {
+               for (i = 0; i < (stop_pfn - start_pfn); ++i)
+                       if (pfn_valid(start_pfn + i) &&
+                           !PageReserved(pfn_to_page(start_pfn + i)))
+                               return true;
+       }
+
+       return false;
+}
+
+static int __ioremap_check_desc_other(struct resource *res)
+{
+       return (res->desc != IORES_DESC_NONE);
+}
+
+static int __ioremap_res_check(struct resource *res, void *arg)
+{
+       struct ioremap_mem_flags *flags = arg;
+
+       if (!flags->system_ram)
+               flags->system_ram = __ioremap_check_ram(res);
+
+       if (!flags->desc_other)
+               flags->desc_other = __ioremap_check_desc_other(res);
+
+       return flags->system_ram && flags->desc_other;
+}
+
+/*
+ * To avoid multiple resource walks, this function walks resources marked as
+ * IORESOURCE_MEM and IORESOURCE_BUSY and looking for system RAM and/or a
+ * resource described not as IORES_DESC_NONE (e.g. IORES_DESC_ACPI_TABLES).
+ */
+static void __ioremap_check_mem(resource_size_t addr, unsigned long size,
+                               struct ioremap_mem_flags *flags)
+{
+       u64 start, end;
+
+       start = (u64)addr;
+       end = start + size - 1;
+       memset(flags, 0, sizeof(*flags));
+
+       walk_mem_res(start, end, flags, __ioremap_res_check);
 }
 
 /*
@@ -87,9 +134,10 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
                unsigned long size, enum page_cache_mode pcm, void *caller)
 {
        unsigned long offset, vaddr;
-       resource_size_t pfn, last_pfn, last_addr;
+       resource_size_t last_addr;
        const resource_size_t unaligned_phys_addr = phys_addr;
        const unsigned long unaligned_size = size;
+       struct ioremap_mem_flags mem_flags;
        struct vm_struct *area;
        enum page_cache_mode new_pcm;
        pgprot_t prot;
@@ -108,13 +156,12 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
                return NULL;
        }
 
+       __ioremap_check_mem(phys_addr, size, &mem_flags);
+
        /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
-       pfn      = phys_addr >> PAGE_SHIFT;
-       last_pfn = last_addr >> PAGE_SHIFT;
-       if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
-                                         __ioremap_check_ram) == 1) {
+       if (mem_flags.system_ram) {
                WARN_ONCE(1, "ioremap on RAM at %pa - %pa\n",
                          &phys_addr, &last_addr);
                return NULL;
@@ -146,7 +193,15 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
                pcm = new_pcm;
        }
 
+       /*
+        * If the page being mapped is in memory and SEV is active then
+        * make sure the memory encryption attribute is enabled in the
+        * resulting mapping.
+        */
        prot = PAGE_KERNEL_IO;
+       if (sev_active() && mem_flags.desc_other)
+               prot = pgprot_encrypted(prot);
+
        switch (pcm) {
        case _PAGE_CACHE_MODE_UC:
        default:
@@ -422,6 +477,9 @@ void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
  * areas should be mapped decrypted. And since the encryption key can
  * change across reboots, persistent memory should also be mapped
  * decrypted.
+ *
+ * If SEV is active, that implies that BIOS/UEFI also ran encrypted so
+ * only persistent memory should be mapped decrypted.
  */
 static bool memremap_should_map_decrypted(resource_size_t phys_addr,
                                          unsigned long size)
@@ -458,6 +516,11 @@ static bool memremap_should_map_decrypted(resource_size_t phys_addr,
        case E820_TYPE_ACPI:
        case E820_TYPE_NVS:
        case E820_TYPE_UNUSABLE:
+               /* For SEV, these areas are encrypted */
+               if (sev_active())
+                       break;
+               /* Fallthrough */
+
        case E820_TYPE_PRAM:
                return true;
        default:
@@ -581,7 +644,7 @@ static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
 bool arch_memremap_can_ram_remap(resource_size_t phys_addr, unsigned long size,
                                 unsigned long flags)
 {
-       if (!sme_active())
+       if (!mem_encrypt_active())
                return true;
 
        if (flags & MEMREMAP_ENC)
@@ -590,12 +653,13 @@ bool arch_memremap_can_ram_remap(resource_size_t phys_addr, unsigned long size,
        if (flags & MEMREMAP_DEC)
                return false;
 
-       if (memremap_is_setup_data(phys_addr, size) ||
-           memremap_is_efi_data(phys_addr, size) ||
-           memremap_should_map_decrypted(phys_addr, size))
-               return false;
+       if (sme_active()) {
+               if (memremap_is_setup_data(phys_addr, size) ||
+                   memremap_is_efi_data(phys_addr, size))
+                       return false;
+       }
 
-       return true;
+       return !memremap_should_map_decrypted(phys_addr, size);
 }
 
 /*
@@ -608,17 +672,24 @@ pgprot_t __init early_memremap_pgprot_adjust(resource_size_t phys_addr,
                                             unsigned long size,
                                             pgprot_t prot)
 {
-       if (!sme_active())
+       bool encrypted_prot;
+
+       if (!mem_encrypt_active())
                return prot;
 
-       if (early_memremap_is_setup_data(phys_addr, size) ||
-           memremap_is_efi_data(phys_addr, size) ||
-           memremap_should_map_decrypted(phys_addr, size))
-               prot = pgprot_decrypted(prot);
-       else
-               prot = pgprot_encrypted(prot);
+       encrypted_prot = true;
+
+       if (sme_active()) {
+               if (early_memremap_is_setup_data(phys_addr, size) ||
+                   memremap_is_efi_data(phys_addr, size))
+                       encrypted_prot = false;
+       }
+
+       if (encrypted_prot && memremap_should_map_decrypted(phys_addr, size))
+               encrypted_prot = false;
 
-       return prot;
+       return encrypted_prot ? pgprot_encrypted(prot)
+                             : pgprot_decrypted(prot);
 }
 
 bool phys_mem_access_encrypted(unsigned long phys_addr, unsigned long size)
index 8f5be3eb40ddb37c9faa9be57803438563bd982a..2b60dc6e64b1daa857ee68d75683b1b2850899d5 100644 (file)
@@ -16,6 +16,8 @@
 
 extern struct range pfn_mapped[E820_MAX_ENTRIES];
 
+static p4d_t tmp_p4d_table[PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE);
+
 static int __init map_range(struct range *range)
 {
        unsigned long start;
@@ -31,8 +33,10 @@ static void __init clear_pgds(unsigned long start,
                        unsigned long end)
 {
        pgd_t *pgd;
+       /* See comment in kasan_init() */
+       unsigned long pgd_end = end & PGDIR_MASK;
 
-       for (; start < end; start += PGDIR_SIZE) {
+       for (; start < pgd_end; start += PGDIR_SIZE) {
                pgd = pgd_offset_k(start);
                /*
                 * With folded p4d, pgd_clear() is nop, use p4d_clear()
@@ -43,29 +47,61 @@ static void __init clear_pgds(unsigned long start,
                else
                        pgd_clear(pgd);
        }
+
+       pgd = pgd_offset_k(start);
+       for (; start < end; start += P4D_SIZE)
+               p4d_clear(p4d_offset(pgd, start));
+}
+
+static inline p4d_t *early_p4d_offset(pgd_t *pgd, unsigned long addr)
+{
+       unsigned long p4d;
+
+       if (!IS_ENABLED(CONFIG_X86_5LEVEL))
+               return (p4d_t *)pgd;
+
+       p4d = __pa_nodebug(pgd_val(*pgd)) & PTE_PFN_MASK;
+       p4d += __START_KERNEL_map - phys_base;
+       return (p4d_t *)p4d + p4d_index(addr);
+}
+
+static void __init kasan_early_p4d_populate(pgd_t *pgd,
+               unsigned long addr,
+               unsigned long end)
+{
+       pgd_t pgd_entry;
+       p4d_t *p4d, p4d_entry;
+       unsigned long next;
+
+       if (pgd_none(*pgd)) {
+               pgd_entry = __pgd(_KERNPG_TABLE | __pa_nodebug(kasan_zero_p4d));
+               set_pgd(pgd, pgd_entry);
+       }
+
+       p4d = early_p4d_offset(pgd, addr);
+       do {
+               next = p4d_addr_end(addr, end);
+
+               if (!p4d_none(*p4d))
+                       continue;
+
+               p4d_entry = __p4d(_KERNPG_TABLE | __pa_nodebug(kasan_zero_pud));
+               set_p4d(p4d, p4d_entry);
+       } while (p4d++, addr = next, addr != end && p4d_none(*p4d));
 }
 
 static void __init kasan_map_early_shadow(pgd_t *pgd)
 {
-       int i;
-       unsigned long start = KASAN_SHADOW_START;
+       /* See comment in kasan_init() */
+       unsigned long addr = KASAN_SHADOW_START & PGDIR_MASK;
        unsigned long end = KASAN_SHADOW_END;
+       unsigned long next;
 
-       for (i = pgd_index(start); start < end; i++) {
-               switch (CONFIG_PGTABLE_LEVELS) {
-               case 4:
-                       pgd[i] = __pgd(__pa_nodebug(kasan_zero_pud) |
-                                       _KERNPG_TABLE);
-                       break;
-               case 5:
-                       pgd[i] = __pgd(__pa_nodebug(kasan_zero_p4d) |
-                                       _KERNPG_TABLE);
-                       break;
-               default:
-                       BUILD_BUG();
-               }
-               start += PGDIR_SIZE;
-       }
+       pgd += pgd_index(addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               kasan_early_p4d_populate(pgd, addr, next);
+       } while (pgd++, addr = next, addr != end);
 }
 
 #ifdef CONFIG_KASAN_INLINE
@@ -102,7 +138,7 @@ void __init kasan_early_init(void)
        for (i = 0; i < PTRS_PER_PUD; i++)
                kasan_zero_pud[i] = __pud(pud_val);
 
-       for (i = 0; CONFIG_PGTABLE_LEVELS >= 5 && i < PTRS_PER_P4D; i++)
+       for (i = 0; IS_ENABLED(CONFIG_X86_5LEVEL) && i < PTRS_PER_P4D; i++)
                kasan_zero_p4d[i] = __p4d(p4d_val);
 
        kasan_map_early_shadow(early_top_pgt);
@@ -118,12 +154,35 @@ void __init kasan_init(void)
 #endif
 
        memcpy(early_top_pgt, init_top_pgt, sizeof(early_top_pgt));
+
+       /*
+        * We use the same shadow offset for 4- and 5-level paging to
+        * facilitate boot-time switching between paging modes.
+        * As result in 5-level paging mode KASAN_SHADOW_START and
+        * KASAN_SHADOW_END are not aligned to PGD boundary.
+        *
+        * KASAN_SHADOW_START doesn't share PGD with anything else.
+        * We claim whole PGD entry to make things easier.
+        *
+        * KASAN_SHADOW_END lands in the last PGD entry and it collides with
+        * bunch of things like kernel code, modules, EFI mapping, etc.
+        * We need to take extra steps to not overwrite them.
+        */
+       if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+               void *ptr;
+
+               ptr = (void *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END));
+               memcpy(tmp_p4d_table, (void *)ptr, sizeof(tmp_p4d_table));
+               set_pgd(&early_top_pgt[pgd_index(KASAN_SHADOW_END)],
+                               __pgd(__pa(tmp_p4d_table) | _KERNPG_TABLE));
+       }
+
        load_cr3(early_top_pgt);
        __flush_tlb_all();
 
-       clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
+       clear_pgds(KASAN_SHADOW_START & PGDIR_MASK, KASAN_SHADOW_END);
 
-       kasan_populate_zero_shadow((void *)KASAN_SHADOW_START,
+       kasan_populate_zero_shadow((void *)(KASAN_SHADOW_START & PGDIR_MASK),
                        kasan_mem_to_shadow((void *)PAGE_OFFSET));
 
        for (i = 0; i < E820_MAX_ENTRIES; i++) {
index 16c5f37933a2ae2d120402f1871af93872aebb07..d9a9e9fc75dd7b511050adc6bd4c914b0c4fcdaa 100644 (file)
@@ -30,6 +30,8 @@
 #include <asm/msr.h>
 #include <asm/cmdline.h>
 
+#include "mm_internal.h"
+
 static char sme_cmdline_arg[] __initdata = "mem_encrypt";
 static char sme_cmdline_on[]  __initdata = "on";
 static char sme_cmdline_off[] __initdata = "off";
@@ -40,7 +42,11 @@ static char sme_cmdline_off[] __initdata = "off";
  * section is later cleared.
  */
 u64 sme_me_mask __section(.data) = 0;
-EXPORT_SYMBOL_GPL(sme_me_mask);
+EXPORT_SYMBOL(sme_me_mask);
+DEFINE_STATIC_KEY_FALSE(sev_enable_key);
+EXPORT_SYMBOL_GPL(sev_enable_key);
+
+static 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);
@@ -63,7 +69,6 @@ static void __init __sme_early_enc_dec(resource_size_t paddr,
        if (!sme_me_mask)
                return;
 
-       local_flush_tlb();
        wbinvd();
 
        /*
@@ -190,8 +195,238 @@ void __init sme_early_init(void)
        /* Update the protection map with memory encryption mask */
        for (i = 0; i < ARRAY_SIZE(protection_map); i++)
                protection_map[i] = pgprot_encrypted(protection_map[i]);
+
+       if (sev_active())
+               swiotlb_force = SWIOTLB_FORCE;
+}
+
+static void *sev_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
+                      gfp_t gfp, unsigned long attrs)
+{
+       unsigned long dma_mask;
+       unsigned int order;
+       struct page *page;
+       void *vaddr = NULL;
+
+       dma_mask = dma_alloc_coherent_mask(dev, gfp);
+       order = get_order(size);
+
+       /*
+        * Memory will be memset to zero after marking decrypted, so don't
+        * bother clearing it before.
+        */
+       gfp &= ~__GFP_ZERO;
+
+       page = alloc_pages_node(dev_to_node(dev), gfp, order);
+       if (page) {
+               dma_addr_t addr;
+
+               /*
+                * Since we will be clearing the encryption bit, check the
+                * mask with it already cleared.
+                */
+               addr = __sme_clr(phys_to_dma(dev, page_to_phys(page)));
+               if ((addr + size) > dma_mask) {
+                       __free_pages(page, get_order(size));
+               } else {
+                       vaddr = page_address(page);
+                       *dma_handle = addr;
+               }
+       }
+
+       if (!vaddr)
+               vaddr = swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
+
+       if (!vaddr)
+               return NULL;
+
+       /* Clear the SME encryption bit for DMA use if not swiotlb area */
+       if (!is_swiotlb_buffer(dma_to_phys(dev, *dma_handle))) {
+               set_memory_decrypted((unsigned long)vaddr, 1 << order);
+               memset(vaddr, 0, PAGE_SIZE << order);
+               *dma_handle = __sme_clr(*dma_handle);
+       }
+
+       return vaddr;
 }
 
+static void sev_free(struct device *dev, size_t size, void *vaddr,
+                    dma_addr_t dma_handle, unsigned long attrs)
+{
+       /* Set the SME encryption bit for re-use if not swiotlb area */
+       if (!is_swiotlb_buffer(dma_to_phys(dev, dma_handle)))
+               set_memory_encrypted((unsigned long)vaddr,
+                                    1 << get_order(size));
+
+       swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+}
+
+static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc)
+{
+       pgprot_t old_prot, new_prot;
+       unsigned long pfn, pa, size;
+       pte_t new_pte;
+
+       switch (level) {
+       case PG_LEVEL_4K:
+               pfn = pte_pfn(*kpte);
+               old_prot = pte_pgprot(*kpte);
+               break;
+       case PG_LEVEL_2M:
+               pfn = pmd_pfn(*(pmd_t *)kpte);
+               old_prot = pmd_pgprot(*(pmd_t *)kpte);
+               break;
+       case PG_LEVEL_1G:
+               pfn = pud_pfn(*(pud_t *)kpte);
+               old_prot = pud_pgprot(*(pud_t *)kpte);
+               break;
+       default:
+               return;
+       }
+
+       new_prot = old_prot;
+       if (enc)
+               pgprot_val(new_prot) |= _PAGE_ENC;
+       else
+               pgprot_val(new_prot) &= ~_PAGE_ENC;
+
+       /* If prot is same then do nothing. */
+       if (pgprot_val(old_prot) == pgprot_val(new_prot))
+               return;
+
+       pa = pfn << page_level_shift(level);
+       size = page_level_size(level);
+
+       /*
+        * We are going to perform in-place en-/decryption and change the
+        * physical page attribute from C=1 to C=0 or vice versa. Flush the
+        * caches to ensure that data gets accessed with the correct C-bit.
+        */
+       clflush_cache_range(__va(pa), size);
+
+       /* Encrypt/decrypt the contents in-place */
+       if (enc)
+               sme_early_encrypt(pa, size);
+       else
+               sme_early_decrypt(pa, size);
+
+       /* Change the page encryption mask. */
+       new_pte = pfn_pte(pfn, new_prot);
+       set_pte_atomic(kpte, new_pte);
+}
+
+static int __init early_set_memory_enc_dec(unsigned long vaddr,
+                                          unsigned long size, bool enc)
+{
+       unsigned long vaddr_end, vaddr_next;
+       unsigned long psize, pmask;
+       int split_page_size_mask;
+       int level, ret;
+       pte_t *kpte;
+
+       vaddr_next = vaddr;
+       vaddr_end = vaddr + size;
+
+       for (; vaddr < vaddr_end; vaddr = vaddr_next) {
+               kpte = lookup_address(vaddr, &level);
+               if (!kpte || pte_none(*kpte)) {
+                       ret = 1;
+                       goto out;
+               }
+
+               if (level == PG_LEVEL_4K) {
+                       __set_clr_pte_enc(kpte, level, enc);
+                       vaddr_next = (vaddr & PAGE_MASK) + PAGE_SIZE;
+                       continue;
+               }
+
+               psize = page_level_size(level);
+               pmask = page_level_mask(level);
+
+               /*
+                * Check whether we can change the large page in one go.
+                * We request a split when the address is not aligned and
+                * the number of pages to set/clear encryption bit is smaller
+                * than the number of pages in the large page.
+                */
+               if (vaddr == (vaddr & pmask) &&
+                   ((vaddr_end - vaddr) >= psize)) {
+                       __set_clr_pte_enc(kpte, level, enc);
+                       vaddr_next = (vaddr & pmask) + psize;
+                       continue;
+               }
+
+               /*
+                * The virtual address is part of a larger page, create the next
+                * level page table mapping (4K or 2M). If it is part of a 2M
+                * page then we request a split of the large page into 4K
+                * chunks. A 1GB large page is split into 2M pages, resp.
+                */
+               if (level == PG_LEVEL_2M)
+                       split_page_size_mask = 0;
+               else
+                       split_page_size_mask = 1 << PG_LEVEL_2M;
+
+               kernel_physical_mapping_init(__pa(vaddr & pmask),
+                                            __pa((vaddr_end & pmask) + psize),
+                                            split_page_size_mask);
+       }
+
+       ret = 0;
+
+out:
+       __flush_tlb_all();
+       return ret;
+}
+
+int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size)
+{
+       return early_set_memory_enc_dec(vaddr, size, false);
+}
+
+int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size)
+{
+       return early_set_memory_enc_dec(vaddr, size, true);
+}
+
+/*
+ * SME and SEV are very similar but they are not the same, so there are
+ * times that the kernel will need to distinguish between SME and SEV. The
+ * sme_active() and sev_active() functions are used for this.  When a
+ * distinction isn't needed, the mem_encrypt_active() function can be used.
+ *
+ * The trampoline code is a good example for this requirement.  Before
+ * paging is activated, SME will access all memory as decrypted, but SEV
+ * will access all memory as encrypted.  So, when APs are being brought
+ * up under SME the trampoline area cannot be encrypted, whereas under SEV
+ * the trampoline area must be encrypted.
+ */
+bool sme_active(void)
+{
+       return sme_me_mask && !sev_enabled;
+}
+EXPORT_SYMBOL_GPL(sme_active);
+
+bool sev_active(void)
+{
+       return sme_me_mask && sev_enabled;
+}
+EXPORT_SYMBOL_GPL(sev_active);
+
+static const struct dma_map_ops sev_dma_ops = {
+       .alloc                  = sev_alloc,
+       .free                   = sev_free,
+       .map_page               = swiotlb_map_page,
+       .unmap_page             = swiotlb_unmap_page,
+       .map_sg                 = swiotlb_map_sg_attrs,
+       .unmap_sg               = swiotlb_unmap_sg_attrs,
+       .sync_single_for_cpu    = swiotlb_sync_single_for_cpu,
+       .sync_single_for_device = swiotlb_sync_single_for_device,
+       .sync_sg_for_cpu        = swiotlb_sync_sg_for_cpu,
+       .sync_sg_for_device     = swiotlb_sync_sg_for_device,
+       .mapping_error          = swiotlb_dma_mapping_error,
+};
+
 /* Architecture __weak replacement functions */
 void __init mem_encrypt_init(void)
 {
@@ -201,7 +436,23 @@ void __init mem_encrypt_init(void)
        /* Call into SWIOTLB to update the SWIOTLB DMA buffers */
        swiotlb_update_mem_attributes();
 
-       pr_info("AMD Secure Memory Encryption (SME) active\n");
+       /*
+        * With SEV, DMA operations cannot use encryption. New DMA ops
+        * are required in order to mark the DMA areas as decrypted or
+        * to use bounce buffers.
+        */
+       if (sev_active())
+               dma_ops = &sev_dma_ops;
+
+       /*
+        * With SEV, we need to unroll the rep string I/O instructions.
+        */
+       if (sev_active())
+               static_branch_enable(&sev_enable_key);
+
+       pr_info("AMD %s active\n",
+               sev_active() ? "Secure Encrypted Virtualization (SEV)"
+                            : "Secure Memory Encryption (SME)");
 }
 
 void swiotlb_set_mem_attributes(void *vaddr, unsigned long size)
@@ -529,37 +780,63 @@ void __init __nostackprotector sme_enable(struct boot_params *bp)
 {
        const char *cmdline_ptr, *cmdline_arg, *cmdline_on, *cmdline_off;
        unsigned int eax, ebx, ecx, edx;
+       unsigned long feature_mask;
        bool active_by_default;
        unsigned long me_mask;
        char buffer[16];
        u64 msr;
 
-       /* Check for the SME support leaf */
+       /* Check for the SME/SEV support leaf */
        eax = 0x80000000;
        ecx = 0;
        native_cpuid(&eax, &ebx, &ecx, &edx);
        if (eax < 0x8000001f)
                return;
 
+#define AMD_SME_BIT    BIT(0)
+#define AMD_SEV_BIT    BIT(1)
        /*
-        * Check for the SME feature:
-        *   CPUID Fn8000_001F[EAX] - Bit 0
-        *     Secure Memory Encryption support
-        *   CPUID Fn8000_001F[EBX] - Bits 5:0
-        *     Pagetable bit position used to indicate encryption
+        * Set the feature mask (SME or SEV) based on whether we are
+        * running under a hypervisor.
+        */
+       eax = 1;
+       ecx = 0;
+       native_cpuid(&eax, &ebx, &ecx, &edx);
+       feature_mask = (ecx & BIT(31)) ? AMD_SEV_BIT : AMD_SME_BIT;
+
+       /*
+        * Check for the SME/SEV feature:
+        *   CPUID Fn8000_001F[EAX]
+        *   - Bit 0 - Secure Memory Encryption support
+        *   - Bit 1 - Secure Encrypted Virtualization support
+        *   CPUID Fn8000_001F[EBX]
+        *   - Bits 5:0 - Pagetable bit position used to indicate encryption
         */
        eax = 0x8000001f;
        ecx = 0;
        native_cpuid(&eax, &ebx, &ecx, &edx);
-       if (!(eax & 1))
+       if (!(eax & feature_mask))
                return;
 
        me_mask = 1UL << (ebx & 0x3f);
 
-       /* Check if SME is enabled */
-       msr = __rdmsr(MSR_K8_SYSCFG);
-       if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT))
+       /* Check if memory encryption is enabled */
+       if (feature_mask == AMD_SME_BIT) {
+               /* For SME, check the SYSCFG MSR */
+               msr = __rdmsr(MSR_K8_SYSCFG);
+               if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT))
+                       return;
+       } else {
+               /* For SEV, check the SEV MSR */
+               msr = __rdmsr(MSR_AMD64_SEV);
+               if (!(msr & MSR_AMD64_SEV_ENABLED))
+                       return;
+
+               /* SEV state cannot be controlled by a command line option */
+               sme_me_mask = me_mask;
+               sev_enabled = true;
                return;
+       }
 
        /*
         * Fixups have not been applied to phys_base yet and we're running
index 7eb06701a93593118ee444ed4abe122055ca9d41..e500949bae24534ce7fea11d73bddb2810affa99 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sched/sysctl.h>
 
 #include <asm/insn.h>
+#include <asm/insn-eval.h>
 #include <asm/mman.h>
 #include <asm/mmu_context.h>
 #include <asm/mpx.h>
@@ -61,123 +62,6 @@ static unsigned long mpx_mmap(unsigned long len)
        return addr;
 }
 
-enum reg_type {
-       REG_TYPE_RM = 0,
-       REG_TYPE_INDEX,
-       REG_TYPE_BASE,
-};
-
-static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
-                         enum reg_type type)
-{
-       int regno = 0;
-
-       static const int regoff[] = {
-               offsetof(struct pt_regs, ax),
-               offsetof(struct pt_regs, cx),
-               offsetof(struct pt_regs, dx),
-               offsetof(struct pt_regs, bx),
-               offsetof(struct pt_regs, sp),
-               offsetof(struct pt_regs, bp),
-               offsetof(struct pt_regs, si),
-               offsetof(struct pt_regs, di),
-#ifdef CONFIG_X86_64
-               offsetof(struct pt_regs, r8),
-               offsetof(struct pt_regs, r9),
-               offsetof(struct pt_regs, r10),
-               offsetof(struct pt_regs, r11),
-               offsetof(struct pt_regs, r12),
-               offsetof(struct pt_regs, r13),
-               offsetof(struct pt_regs, r14),
-               offsetof(struct pt_regs, r15),
-#endif
-       };
-       int nr_registers = ARRAY_SIZE(regoff);
-       /*
-        * Don't possibly decode a 32-bit instructions as
-        * reading a 64-bit-only register.
-        */
-       if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64)
-               nr_registers -= 8;
-
-       switch (type) {
-       case REG_TYPE_RM:
-               regno = X86_MODRM_RM(insn->modrm.value);
-               if (X86_REX_B(insn->rex_prefix.value))
-                       regno += 8;
-               break;
-
-       case REG_TYPE_INDEX:
-               regno = X86_SIB_INDEX(insn->sib.value);
-               if (X86_REX_X(insn->rex_prefix.value))
-                       regno += 8;
-               break;
-
-       case REG_TYPE_BASE:
-               regno = X86_SIB_BASE(insn->sib.value);
-               if (X86_REX_B(insn->rex_prefix.value))
-                       regno += 8;
-               break;
-
-       default:
-               pr_err("invalid register type");
-               BUG();
-               break;
-       }
-
-       if (regno >= nr_registers) {
-               WARN_ONCE(1, "decoded an instruction with an invalid register");
-               return -EINVAL;
-       }
-       return regoff[regno];
-}
-
-/*
- * return the address being referenced be instruction
- * for rm=3 returning the content of the rm reg
- * for rm!=3 calculates the address using SIB and Disp
- */
-static void __user *mpx_get_addr_ref(struct insn *insn, struct pt_regs *regs)
-{
-       unsigned long addr, base, indx;
-       int addr_offset, base_offset, indx_offset;
-       insn_byte_t sib;
-
-       insn_get_modrm(insn);
-       insn_get_sib(insn);
-       sib = insn->sib.value;
-
-       if (X86_MODRM_MOD(insn->modrm.value) == 3) {
-               addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
-               if (addr_offset < 0)
-                       goto out_err;
-               addr = regs_get_register(regs, addr_offset);
-       } else {
-               if (insn->sib.nbytes) {
-                       base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
-                       if (base_offset < 0)
-                               goto out_err;
-
-                       indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
-                       if (indx_offset < 0)
-                               goto out_err;
-
-                       base = regs_get_register(regs, base_offset);
-                       indx = regs_get_register(regs, indx_offset);
-                       addr = base + indx * (1 << X86_SIB_SCALE(sib));
-               } else {
-                       addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
-                       if (addr_offset < 0)
-                               goto out_err;
-                       addr = regs_get_register(regs, addr_offset);
-               }
-               addr += insn->displacement.value;
-       }
-       return (void __user *)addr;
-out_err:
-       return (void __user *)-1;
-}
-
 static int mpx_insn_decode(struct insn *insn,
                           struct pt_regs *regs)
 {
@@ -290,7 +174,7 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
        info->si_signo = SIGSEGV;
        info->si_errno = 0;
        info->si_code = SEGV_BNDERR;
-       info->si_addr = mpx_get_addr_ref(&insn, regs);
+       info->si_addr = insn_get_addr_ref(&insn, regs);
        /*
         * We were not able to extract an address from the instruction,
         * probably because there was something invalid in it.
index dfb7d657cf4322b0dedcd0bb63c1058bd090b4ea..3fe68483463ca55fb2445dcdfad20c291884eebf 100644 (file)
@@ -1781,8 +1781,8 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
        unsigned long start;
        int ret;
 
-       /* Nothing to do if the SME is not active */
-       if (!sme_active())
+       /* Nothing to do if memory encryption is not active */
+       if (!mem_encrypt_active())
                return 0;
 
        /* Should not be working on unaligned addresses */
index 350f7096baac82893bc076fd6db4d04a685d7104..7913b692195901384087073a3f9f5a2d542802a6 100644 (file)
@@ -212,8 +212,8 @@ static void arch_perfmon_setup_counters(void)
        eax.full = cpuid_eax(0xa);
 
        /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
-       if (eax.split.version_id == 0 && __this_cpu_read(cpu_info.x86) == 6 &&
-               __this_cpu_read(cpu_info.x86_model) == 15) {
+       if (eax.split.version_id == 0 && boot_cpu_data.x86 == 6 &&
+           boot_cpu_data.x86_model == 15) {
                eax.split.version_id = 2;
                eax.split.num_counters = 2;
                eax.split.bit_width = 40;
index 20fb31579b6942ccbcb4c8ebea350d72a81e860f..9e4ee5b04b2d40067196c21b03ef7de84884d653 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/ucs2_string.h>
+#include <linux/mem_encrypt.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -370,7 +371,11 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
         * as trim_bios_range() will reserve the first page and isolate it away
         * from memory allocators anyway.
         */
-       if (kernel_map_pages_in_pgd(pgd, 0x0, 0x0, 1, _PAGE_RW)) {
+       pf = _PAGE_RW;
+       if (sev_active())
+               pf |= _PAGE_ENC;
+
+       if (kernel_map_pages_in_pgd(pgd, 0x0, 0x0, 1, pf)) {
                pr_err("Failed to create 1:1 mapping for the first page!\n");
                return 1;
        }
@@ -413,6 +418,9 @@ static void __init __map_region(efi_memory_desc_t *md, u64 va)
        if (!(md->attribute & EFI_MEMORY_WB))
                flags |= _PAGE_PCD;
 
+       if (sev_active())
+               flags |= _PAGE_ENC;
+
        pfn = md->phys_addr >> PAGE_SHIFT;
        if (kernel_map_pages_in_pgd(pgd, pfn, va, md->num_pages, flags))
                pr_warn("Error mapping PA 0x%llx -> VA 0x%llx!\n",
@@ -539,6 +547,9 @@ static int __init efi_update_mem_attr(struct mm_struct *mm, efi_memory_desc_t *m
        if (!(md->attribute & EFI_MEMORY_RO))
                pf |= _PAGE_RW;
 
+       if (sev_active())
+               pf |= _PAGE_ENC;
+
        return efi_update_mappings(md, pf);
 }
 
@@ -590,6 +601,9 @@ void __init efi_runtime_update_mappings(void)
                        (md->type != EFI_RUNTIME_SERVICES_CODE))
                        pf |= _PAGE_RW;
 
+               if (sev_active())
+                       pf |= _PAGE_ENC;
+
                efi_update_mappings(md, pf);
        }
 }
index 74283875c7e83925b8bd7c9f5951cd4a0b4430d0..e639e3116acfe2a1009d9e319cc1c58e0f23e260 100644 (file)
@@ -62,10 +62,9 @@ static struct platform_device pb_device = {
 static int __init pb_keys_init(void)
 {
        struct gpio_keys_button *gb = gpio_button;
-       int i, num, good = 0;
+       int i, good = 0;
 
-       num = sizeof(gpio_button) / sizeof(struct gpio_keys_button);
-       for (i = 0; i < num; i++) {
+       for (i = 0; i < ARRAY_SIZE(gpio_button); i++) {
                gb[i].gpio = get_gpio_by_name(gb[i].desc);
                pr_debug("info[%2d]: name = %s, gpio = %d\n", i, gb[i].desc,
                                        gb[i].gpio);
index 03fc397335b7482e9302f7d7f6b85d9c0f553df5..5f6fd860820a3c5175609a5a3468262aac937604 100644 (file)
@@ -127,10 +127,11 @@ static void uv_domain_free(struct irq_domain *domain, unsigned int virq,
  * Re-target the irq to the specified CPU and enable the specified MMR located
  * on the specified blade to allow the sending of MSIs to the specified CPU.
  */
-static void uv_domain_activate(struct irq_domain *domain,
-                              struct irq_data *irq_data)
+static int uv_domain_activate(struct irq_domain *domain,
+                             struct irq_data *irq_data, bool early)
 {
        uv_program_mmr(irqd_cfg(irq_data), irq_data->chip_data);
+       return 0;
 }
 
 /*
index ed84d3917a5916fe003188c2603b81317cce7732..d10105825d57a7faee5f3221d04f0e77b9807e45 100644 (file)
@@ -64,9 +64,10 @@ static void __init setup_real_mode(void)
        /*
         * If SME is active, the trampoline area will need to be in
         * decrypted memory in order to bring up other processors
-        * successfully.
+        * successfully. This is not needed for SEV.
         */
-       set_memory_decrypted((unsigned long)base, size >> PAGE_SHIFT);
+       if (sme_active())
+               set_memory_decrypted((unsigned long)base, size >> PAGE_SHIFT);
 
        memcpy(base, real_mode_blob, size);
 
index 836a1eb5df436bdad88fe3b4ae59b512f9573b19..3ee234b6234dd6eaf0a3e61b8d4d99677a5a7078 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/syscalls.h>
 #include <linux/uaccess.h>
 #include <asm/unistd.h>
 #include <os.h>
@@ -369,7 +370,9 @@ void free_ldt(struct mm_context *mm)
        mm->arch.ldt.entry_count = 0;
 }
 
-int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
+SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr ,
+               unsigned long , bytecount)
 {
-       return do_modify_ldt_skas(func, ptr, bytecount);
+       /* See non-um modify_ldt() for why we do this cast */
+       return (unsigned int)do_modify_ldt_skas(func, ptr, bytecount);
 }
index 30434b8708f206d62888b1b9bd46466a25af7861..6b830d4cb4c8e8e78c44dd87a12f642234533b4e 100644 (file)
@@ -31,7 +31,7 @@ static unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
        return 0xfd;
 }
 
-static unsigned long xen_set_apic_id(unsigned int x)
+static u32 xen_set_apic_id(unsigned int x)
 {
        WARN_ON(1);
        return x;
@@ -161,12 +161,10 @@ static struct apic xen_pv_apic = {
        /* .irq_delivery_mode - used in native_compose_msi_msg only */
        /* .irq_dest_mode     - used in native_compose_msi_msg only */
 
-       .target_cpus                    = default_target_cpus,
        .disable_esr                    = 0,
        /* .dest_logical      -  default_send_IPI_ use it but we use our own. */
        .check_apicid_used              = default_check_apicid_used, /* Used on 32-bit */
 
-       .vector_allocation_domain       = flat_vector_allocation_domain,
        .init_apic_ldr                  = xen_noop, /* setup_local_APIC calls it */
 
        .ioapic_phys_id_map             = default_ioapic_phys_id_map, /* Used on 32-bit */
@@ -179,7 +177,7 @@ static struct apic xen_pv_apic = {
        .get_apic_id                    = xen_get_apic_id,
        .set_apic_id                    = xen_set_apic_id, /* Can be NULL on 32-bit. */
 
-       .cpu_mask_to_apicid             = flat_cpu_mask_to_apicid,
+       .calc_dest_apicid               = apic_flat_calc_apicid,
 
 #ifdef CONFIG_SMP
        .send_IPI_mask                  = xen_send_IPI_mask,
index de503c225ae1f194b10c71b44528ad2a2a7a4c0d..8268987010458489b386da80c09ed5164fff8b77 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/acpi.h>
 #include <linux/cpu.h>
 #include <linux/kexec.h>
 #include <linux/memblock.h>
@@ -188,8 +189,6 @@ static void __init xen_hvm_guest_init(void)
        xen_hvm_init_time_ops();
        xen_hvm_init_mmu_ops();
 
-       if (xen_pvh_domain())
-               machine_ops.emergency_restart = xen_emergency_restart;
 #ifdef CONFIG_KEXEC_CORE
        machine_ops.shutdown = xen_hvm_shutdown;
        machine_ops.crash_shutdown = xen_hvm_crash_shutdown;
@@ -226,12 +225,33 @@ static uint32_t __init xen_platform_hvm(void)
        return xen_cpuid_base();
 }
 
-const struct hypervisor_x86 x86_hyper_xen_hvm = {
+static __init void xen_hvm_guest_late_init(void)
+{
+#ifdef CONFIG_XEN_PVH
+       /* Test for PVH domain (PVH boot path taken overrides ACPI flags). */
+       if (!xen_pvh &&
+           (x86_platform.legacy.rtc || !x86_platform.legacy.no_vga))
+               return;
+
+       /* PVH detected. */
+       xen_pvh = true;
+
+       /* 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;
+
+       machine_ops.emergency_restart = xen_emergency_restart;
+       pv_info.name = "Xen PVH";
+#endif
+}
+
+const __initconst struct hypervisor_x86 x86_hyper_xen_hvm = {
        .name                   = "Xen HVM",
        .detect                 = xen_platform_hvm,
-       .init_platform          = xen_hvm_guest_init,
-       .pin_vcpu               = xen_pin_vcpu,
-       .x2apic_available       = xen_x2apic_para_available,
-       .init_mem_mapping       = xen_hvm_init_mem_mapping,
+       .type                   = X86_HYPER_XEN_HVM,
+       .init.init_platform     = xen_hvm_guest_init,
+       .init.x2apic_available  = xen_x2apic_para_available,
+       .init.init_mem_mapping  = xen_hvm_init_mem_mapping,
+       .init.guest_late_init   = xen_hvm_guest_late_init,
+       .runtime.pin_vcpu       = xen_pin_vcpu,
 };
-EXPORT_SYMBOL(x86_hyper_xen_hvm);
index d4396e27b1fb755994fc839a08b86e45e625db42..5b2b3f3f653112fbe00484f5dcae0de02543df3c 100644 (file)
@@ -601,7 +601,7 @@ static struct trap_array_entry trap_array[] = {
 #ifdef CONFIG_X86_MCE
        { machine_check,               xen_machine_check,               true },
 #endif
-       { nmi,                         xen_nmi,                         true },
+       { nmi,                         xen_xennmi,                      true },
        { overflow,                    xen_overflow,                    false },
 #ifdef CONFIG_IA32_EMULATION
        { entry_INT80_compat,          xen_entry_INT80_compat,          false },
@@ -811,15 +811,14 @@ static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry,
        }
 }
 
-static void xen_load_sp0(struct tss_struct *tss,
-                        struct thread_struct *thread)
+static void xen_load_sp0(unsigned long sp0)
 {
        struct multicall_space mcs;
 
        mcs = xen_mc_entry(0);
-       MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0);
+       MULTI_stack_switch(mcs.mc, __KERNEL_DS, sp0);
        xen_mc_issue(PARAVIRT_LAZY_CPU);
-       tss->x86_tss.sp0 = thread->sp0;
+       this_cpu_write(cpu_tss.x86_tss.sp0, sp0);
 }
 
 void xen_set_iopl_mask(unsigned mask)
@@ -1231,6 +1230,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
        x86_platform.get_nmi_reason = xen_get_nmi_reason;
 
        x86_init.resources.memory_setup = xen_memory_setup;
+       x86_init.irqs.intr_mode_init    = x86_init_noop;
        x86_init.oem.arch_setup = xen_arch_setup;
        x86_init.oem.banner = xen_banner;
 
@@ -1460,9 +1460,9 @@ static uint32_t __init xen_platform_pv(void)
        return 0;
 }
 
-const struct hypervisor_x86 x86_hyper_xen_pv = {
+const __initconst struct hypervisor_x86 x86_hyper_xen_pv = {
        .name                   = "Xen PV",
        .detect                 = xen_platform_pv,
-       .pin_vcpu               = xen_pin_vcpu,
+       .type                   = X86_HYPER_XEN_PV,
+       .runtime.pin_vcpu       = xen_pin_vcpu,
 };
-EXPORT_SYMBOL(x86_hyper_xen_pv);
index 7bd3ee08393e60620bc744ac1768221267652a3f..436c4f003e17fc398cb23ed4aa5928ac3b6c8bc1 100644 (file)
@@ -25,13 +25,6 @@ struct boot_params pvh_bootparams __attribute__((section(".data")));
 struct hvm_start_info pvh_start_info;
 unsigned int pvh_start_info_sz = sizeof(pvh_start_info);
 
-static void xen_pvh_arch_setup(void)
-{
-       /* Make sure we don't fall back to (default) ACPI_IRQ_MODEL_PIC. */
-       if (nr_ioapics == 0)
-               acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
-}
-
 static void __init init_pvh_bootparams(void)
 {
        struct xen_memory_map memmap;
@@ -102,6 +95,4 @@ void __init xen_prepare_pvh(void)
        wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
 
        init_pvh_bootparams();
-
-       x86_init.oem.arch_setup = xen_pvh_arch_setup;
 }
index 71495f1a86d72f7df1464ce3ffe805d880948bbd..2ccdaba31a0778d975af96298d9e65443fa7debd 100644 (file)
@@ -449,7 +449,7 @@ __visible pmd_t xen_make_pmd(pmdval_t pmd)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pmd);
 
-#if CONFIG_PGTABLE_LEVELS == 4
+#ifdef CONFIG_X86_64
 __visible pudval_t xen_pud_val(pud_t pud)
 {
        return pte_mfn_to_pfn(pud.pud);
@@ -538,7 +538,7 @@ static void xen_set_p4d(p4d_t *ptr, p4d_t val)
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
-#endif /* CONFIG_PGTABLE_LEVELS == 4 */
+#endif /* CONFIG_X86_64 */
 
 static int xen_pmd_walk(struct mm_struct *mm, pmd_t *pmd,
                int (*func)(struct mm_struct *mm, struct page *, enum pt_level),
@@ -580,21 +580,17 @@ static int xen_p4d_walk(struct mm_struct *mm, p4d_t *p4d,
                int (*func)(struct mm_struct *mm, struct page *, enum pt_level),
                bool last, unsigned long limit)
 {
-       int i, nr, flush = 0;
+       int flush = 0;
+       pud_t *pud;
 
-       nr = last ? p4d_index(limit) + 1 : PTRS_PER_P4D;
-       for (i = 0; i < nr; i++) {
-               pud_t *pud;
 
-               if (p4d_none(p4d[i]))
-                       continue;
+       if (p4d_none(*p4d))
+               return flush;
 
-               pud = pud_offset(&p4d[i], 0);
-               if (PTRS_PER_PUD > 1)
-                       flush |= (*func)(mm, virt_to_page(pud), PT_PUD);
-               flush |= xen_pud_walk(mm, pud, func,
-                               last && i == nr - 1, limit);
-       }
+       pud = pud_offset(p4d, 0);
+       if (PTRS_PER_PUD > 1)
+               flush |= (*func)(mm, virt_to_page(pud), PT_PUD);
+       flush |= xen_pud_walk(mm, pud, func, last, limit);
        return flush;
 }
 
@@ -644,8 +640,6 @@ static int __xen_pgd_walk(struct mm_struct *mm, pgd_t *pgd,
                        continue;
 
                p4d = p4d_offset(&pgd[i], 0);
-               if (PTRS_PER_P4D > 1)
-                       flush |= (*func)(mm, virt_to_page(p4d), PT_P4D);
                flush |= xen_p4d_walk(mm, p4d, func, i == nr - 1, limit);
        }
 
@@ -1176,22 +1170,14 @@ static void __init xen_cleanmfnmap(unsigned long vaddr)
 {
        pgd_t *pgd;
        p4d_t *p4d;
-       unsigned int i;
        bool unpin;
 
        unpin = (vaddr == 2 * PGDIR_SIZE);
        vaddr &= PMD_MASK;
        pgd = pgd_offset_k(vaddr);
        p4d = p4d_offset(pgd, 0);
-       for (i = 0; i < PTRS_PER_P4D; i++) {
-               if (p4d_none(p4d[i]))
-                       continue;
-               xen_cleanmfnmap_p4d(p4d + i, unpin);
-       }
-       if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
-               set_pgd(pgd, __pgd(0));
-               xen_cleanmfnmap_free_pgtbl(p4d, unpin);
-       }
+       if (!p4d_none(*p4d))
+               xen_cleanmfnmap_p4d(p4d, unpin);
 }
 
 static void __init xen_pagetable_p2m_free(void)
@@ -1692,7 +1678,7 @@ static void xen_release_pmd(unsigned long pfn)
        xen_release_ptpage(pfn, PT_PMD);
 }
 
-#if CONFIG_PGTABLE_LEVELS >= 4
+#ifdef CONFIG_X86_64
 static void xen_alloc_pud(struct mm_struct *mm, unsigned long pfn)
 {
        xen_alloc_ptpage(mm, pfn, PT_PUD);
@@ -2029,13 +2015,12 @@ static phys_addr_t __init xen_early_virt_to_phys(unsigned long vaddr)
  */
 void __init xen_relocate_p2m(void)
 {
-       phys_addr_t size, new_area, pt_phys, pmd_phys, pud_phys, p4d_phys;
+       phys_addr_t size, new_area, pt_phys, pmd_phys, pud_phys;
        unsigned long p2m_pfn, p2m_pfn_end, n_frames, pfn, pfn_end;
-       int n_pte, n_pt, n_pmd, n_pud, n_p4d, idx_pte, idx_pt, idx_pmd, idx_pud, idx_p4d;
+       int n_pte, n_pt, n_pmd, n_pud, idx_pte, idx_pt, idx_pmd, idx_pud;
        pte_t *pt;
        pmd_t *pmd;
        pud_t *pud;
-       p4d_t *p4d = NULL;
        pgd_t *pgd;
        unsigned long *new_p2m;
        int save_pud;
@@ -2045,11 +2030,7 @@ void __init xen_relocate_p2m(void)
        n_pt = roundup(size, PMD_SIZE) >> PMD_SHIFT;
        n_pmd = roundup(size, PUD_SIZE) >> PUD_SHIFT;
        n_pud = roundup(size, P4D_SIZE) >> P4D_SHIFT;
-       if (PTRS_PER_P4D > 1)
-               n_p4d = roundup(size, PGDIR_SIZE) >> PGDIR_SHIFT;
-       else
-               n_p4d = 0;
-       n_frames = n_pte + n_pt + n_pmd + n_pud + n_p4d;
+       n_frames = n_pte + n_pt + n_pmd + n_pud;
 
        new_area = xen_find_free_area(PFN_PHYS(n_frames));
        if (!new_area) {
@@ -2065,76 +2046,56 @@ void __init xen_relocate_p2m(void)
         * To avoid any possible virtual address collision, just use
         * 2 * PUD_SIZE for the new area.
         */
-       p4d_phys = new_area;
-       pud_phys = p4d_phys + PFN_PHYS(n_p4d);
+       pud_phys = new_area;
        pmd_phys = pud_phys + PFN_PHYS(n_pud);
        pt_phys = pmd_phys + PFN_PHYS(n_pmd);
        p2m_pfn = PFN_DOWN(pt_phys) + n_pt;
 
        pgd = __va(read_cr3_pa());
        new_p2m = (unsigned long *)(2 * PGDIR_SIZE);
-       idx_p4d = 0;
        save_pud = n_pud;
-       do {
-               if (n_p4d > 0) {
-                       p4d = early_memremap(p4d_phys, PAGE_SIZE);
-                       clear_page(p4d);
-                       n_pud = min(save_pud, PTRS_PER_P4D);
-               }
-               for (idx_pud = 0; idx_pud < n_pud; idx_pud++) {
-                       pud = early_memremap(pud_phys, PAGE_SIZE);
-                       clear_page(pud);
-                       for (idx_pmd = 0; idx_pmd < min(n_pmd, PTRS_PER_PUD);
-                                idx_pmd++) {
-                               pmd = early_memremap(pmd_phys, PAGE_SIZE);
-                               clear_page(pmd);
-                               for (idx_pt = 0; idx_pt < min(n_pt, PTRS_PER_PMD);
-                                        idx_pt++) {
-                                       pt = early_memremap(pt_phys, PAGE_SIZE);
-                                       clear_page(pt);
-                                       for (idx_pte = 0;
-                                                idx_pte < min(n_pte, PTRS_PER_PTE);
-                                                idx_pte++) {
-                                               set_pte(pt + idx_pte,
-                                                               pfn_pte(p2m_pfn, PAGE_KERNEL));
-                                               p2m_pfn++;
-                                       }
-                                       n_pte -= PTRS_PER_PTE;
-                                       early_memunmap(pt, PAGE_SIZE);
-                                       make_lowmem_page_readonly(__va(pt_phys));
-                                       pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE,
-                                                       PFN_DOWN(pt_phys));
-                                       set_pmd(pmd + idx_pt,
-                                                       __pmd(_PAGE_TABLE | pt_phys));
-                                       pt_phys += PAGE_SIZE;
+       for (idx_pud = 0; idx_pud < n_pud; idx_pud++) {
+               pud = early_memremap(pud_phys, PAGE_SIZE);
+               clear_page(pud);
+               for (idx_pmd = 0; idx_pmd < min(n_pmd, PTRS_PER_PUD);
+                               idx_pmd++) {
+                       pmd = early_memremap(pmd_phys, PAGE_SIZE);
+                       clear_page(pmd);
+                       for (idx_pt = 0; idx_pt < min(n_pt, PTRS_PER_PMD);
+                                       idx_pt++) {
+                               pt = early_memremap(pt_phys, PAGE_SIZE);
+                               clear_page(pt);
+                               for (idx_pte = 0;
+                                               idx_pte < min(n_pte, PTRS_PER_PTE);
+                                               idx_pte++) {
+                                       set_pte(pt + idx_pte,
+                                                       pfn_pte(p2m_pfn, PAGE_KERNEL));
+                                       p2m_pfn++;
                                }
-                               n_pt -= PTRS_PER_PMD;
-                               early_memunmap(pmd, PAGE_SIZE);
-                               make_lowmem_page_readonly(__va(pmd_phys));
-                               pin_pagetable_pfn(MMUEXT_PIN_L2_TABLE,
-                                               PFN_DOWN(pmd_phys));
-                               set_pud(pud + idx_pmd, __pud(_PAGE_TABLE | pmd_phys));
-                               pmd_phys += PAGE_SIZE;
+                               n_pte -= PTRS_PER_PTE;
+                               early_memunmap(pt, PAGE_SIZE);
+                               make_lowmem_page_readonly(__va(pt_phys));
+                               pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE,
+                                               PFN_DOWN(pt_phys));
+                               set_pmd(pmd + idx_pt,
+                                               __pmd(_PAGE_TABLE | pt_phys));
+                               pt_phys += PAGE_SIZE;
                        }
-                       n_pmd -= PTRS_PER_PUD;
-                       early_memunmap(pud, PAGE_SIZE);
-                       make_lowmem_page_readonly(__va(pud_phys));
-                       pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(pud_phys));
-                       if (n_p4d > 0)
-                               set_p4d(p4d + idx_pud, __p4d(_PAGE_TABLE | pud_phys));
-                       else
-                               set_pgd(pgd + 2 + idx_pud, __pgd(_PAGE_TABLE | pud_phys));
-                       pud_phys += PAGE_SIZE;
-               }
-               if (n_p4d > 0) {
-                       save_pud -= PTRS_PER_P4D;
-                       early_memunmap(p4d, PAGE_SIZE);
-                       make_lowmem_page_readonly(__va(p4d_phys));
-                       pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE, PFN_DOWN(p4d_phys));
-                       set_pgd(pgd + 2 + idx_p4d, __pgd(_PAGE_TABLE | p4d_phys));
-                       p4d_phys += PAGE_SIZE;
+                       n_pt -= PTRS_PER_PMD;
+                       early_memunmap(pmd, PAGE_SIZE);
+                       make_lowmem_page_readonly(__va(pmd_phys));
+                       pin_pagetable_pfn(MMUEXT_PIN_L2_TABLE,
+                                       PFN_DOWN(pmd_phys));
+                       set_pud(pud + idx_pmd, __pud(_PAGE_TABLE | pmd_phys));
+                       pmd_phys += PAGE_SIZE;
                }
-       } while (++idx_p4d < n_p4d);
+               n_pmd -= PTRS_PER_PUD;
+               early_memunmap(pud, PAGE_SIZE);
+               make_lowmem_page_readonly(__va(pud_phys));
+               pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(pud_phys));
+               set_pgd(pgd + 2 + idx_pud, __pgd(_PAGE_TABLE | pud_phys));
+               pud_phys += PAGE_SIZE;
+       }
 
        /* Now copy the old p2m info to the new area. */
        memcpy(new_p2m, xen_p2m_addr, size);
@@ -2361,7 +2322,7 @@ static void __init xen_post_allocator_init(void)
        pv_mmu_ops.set_pte = xen_set_pte;
        pv_mmu_ops.set_pmd = xen_set_pmd;
        pv_mmu_ops.set_pud = xen_set_pud;
-#if CONFIG_PGTABLE_LEVELS >= 4
+#ifdef CONFIG_X86_64
        pv_mmu_ops.set_p4d = xen_set_p4d;
 #endif
 
@@ -2371,7 +2332,7 @@ static void __init xen_post_allocator_init(void)
        pv_mmu_ops.alloc_pmd = xen_alloc_pmd;
        pv_mmu_ops.release_pte = xen_release_pte;
        pv_mmu_ops.release_pmd = xen_release_pmd;
-#if CONFIG_PGTABLE_LEVELS >= 4
+#ifdef CONFIG_X86_64
        pv_mmu_ops.alloc_pud = xen_alloc_pud;
        pv_mmu_ops.release_pud = xen_release_pud;
 #endif
@@ -2435,14 +2396,14 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
        .make_pmd = PV_CALLEE_SAVE(xen_make_pmd),
        .pmd_val = PV_CALLEE_SAVE(xen_pmd_val),
 
-#if CONFIG_PGTABLE_LEVELS >= 4
+#ifdef CONFIG_X86_64
        .pud_val = PV_CALLEE_SAVE(xen_pud_val),
        .make_pud = PV_CALLEE_SAVE(xen_make_pud),
        .set_p4d = xen_set_p4d_hyper,
 
        .alloc_pud = xen_alloc_pmd_init,
        .release_pud = xen_release_pmd_init,
-#endif /* CONFIG_PGTABLE_LEVELS == 4 */
+#endif /* CONFIG_X86_64 */
 
        .activate_mm = xen_activate_mm,
        .dup_mmap = xen_dup_mmap,
index 6083ba462f350d99c5f7b7caa0c47283823ac2e7..13b4f19b9131353f8617706ccb42b60082649fbc 100644 (file)
@@ -547,7 +547,7 @@ int xen_alloc_p2m_entry(unsigned long pfn)
        if (p2m_top_mfn && pfn < MAX_P2M_PFN) {
                topidx = p2m_top_index(pfn);
                top_mfn_p = &p2m_top_mfn[topidx];
-               mid_mfn = ACCESS_ONCE(p2m_top_mfn_p[topidx]);
+               mid_mfn = READ_ONCE(p2m_top_mfn_p[topidx]);
 
                BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p);
 
index 05f91ce9b55eea1519a900dd57a48a29f6c08da1..c0c756c76afebf08d282fb35c2fc49b641120bb4 100644 (file)
@@ -14,6 +14,7 @@
  * single-threaded.
  */
 #include <linux/sched.h>
+#include <linux/sched/task_stack.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
@@ -294,12 +295,19 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
 #endif
        memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
 
+       /*
+        * Bring up the CPU in cpu_bringup_and_idle() with the stack
+        * pointing just below where pt_regs would be if it were a normal
+        * kernel entry.
+        */
        ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
        ctxt->flags = VGCF_IN_KERNEL;
        ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
        ctxt->user_regs.ds = __USER_DS;
        ctxt->user_regs.es = __USER_DS;
        ctxt->user_regs.ss = __KERNEL_DS;
+       ctxt->user_regs.cs = __KERNEL_CS;
+       ctxt->user_regs.esp = (unsigned long)task_pt_regs(idle);
 
        xen_copy_trap_info(ctxt->trap_ctxt);
 
@@ -314,8 +322,13 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
        ctxt->gdt_frames[0] = gdt_mfn;
        ctxt->gdt_ents      = GDT_ENTRIES;
 
+       /*
+        * Set SS:SP that Xen will use when entering guest kernel mode
+        * from guest user mode.  Subsequent calls to load_sp0() can
+        * change this value.
+        */
        ctxt->kernel_ss = __KERNEL_DS;
-       ctxt->kernel_sp = idle->thread.sp0;
+       ctxt->kernel_sp = task_top_of_stack(idle);
 
 #ifdef CONFIG_X86_32
        ctxt->event_callback_cs     = __KERNEL_CS;
@@ -327,10 +340,8 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
                (unsigned long)xen_hypervisor_callback;
        ctxt->failsafe_callback_eip =
                (unsigned long)xen_failsafe_callback;
-       ctxt->user_regs.cs = __KERNEL_CS;
        per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
 
-       ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs);
        ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_gfn(swapper_pg_dir));
        if (HYPERVISOR_vcpu_op(VCPUOP_initialise, xen_vcpu_nr(cpu), ctxt))
                BUG();
index 08324c64005dba48d79ee8914a198562e582e0d8..02f3445a2b5f60b5cf8fd1e296bba3a55fe37068 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 
 #include <asm/paravirt.h>
+#include <asm/qspinlock.h>
 
 #include <xen/interface/xen.h>
 #include <xen/events.h>
@@ -81,8 +82,11 @@ void xen_init_lock_cpu(int cpu)
        int irq;
        char *name;
 
-       if (!xen_pvspin)
+       if (!xen_pvspin) {
+               if (cpu == 0)
+                       static_branch_disable(&virt_spin_lock_key);
                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));
index c98a48c861fd33ec4958dccc462ecbccf6856f3b..8a10c9a9e2b50651b2c8dd322956298402e79e7d 100644 (file)
@@ -30,7 +30,7 @@ xen_pv_trap debug
 xen_pv_trap xendebug
 xen_pv_trap int3
 xen_pv_trap xenint3
-xen_pv_trap nmi
+xen_pv_trap xennmi
 xen_pv_trap overflow
 xen_pv_trap bounds
 xen_pv_trap invalid_op
index b5b8d7f4355744d24b00404ac9eb35360d5e9e82..497cc55a0c16cccbe64f0a17e2518a6337e7d4e8 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/boot.h>
 #include <asm/asm.h>
 #include <asm/page_types.h>
+#include <asm/unwind_hints.h>
 
 #include <xen/interface/elfnote.h>
 #include <xen/interface/features.h>
@@ -20,6 +21,7 @@
 #ifdef CONFIG_XEN_PV
        __INIT
 ENTRY(startup_xen)
+       UNWIND_HINT_EMPTY
        cld
 
        /* Clear .bss */
@@ -34,21 +36,24 @@ ENTRY(startup_xen)
        mov $init_thread_union+THREAD_SIZE, %_ASM_SP
 
        jmp xen_start_kernel
-
+END(startup_xen)
        __FINIT
 #endif
 
 .pushsection .text
        .balign PAGE_SIZE
 ENTRY(hypercall_page)
-       .skip PAGE_SIZE
+       .rept (PAGE_SIZE / 32)
+               UNWIND_HINT_EMPTY
+               .skip 32
+       .endr
 
 #define HYPERCALL(n) \
        .equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
        .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
 #include <asm/xen-hypercalls.h>
 #undef HYPERCALL
-
+END(hypercall_page)
 .popsection
 
        ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
index 3bb49681ee242803e13c1ef1eae81011a33a98b4..c6e1290dcbb7cbb8034437bc47e95d653b968bfb 100644 (file)
@@ -33,8 +33,6 @@
 
 #define arch_spin_is_locked(x) ((x)->slock != 0)
 
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
        unsigned long tmp;
@@ -97,8 +95,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
  *  0x80000000  one writer owns the rwlock, no other writers, no readers
  */
 
-#define arch_write_can_lock(x)  ((x)->lock == 0)
-
 static inline void arch_write_lock(arch_rwlock_t *rw)
 {
        unsigned long tmp;
@@ -200,7 +196,4 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
                        : "memory");
 }
 
-#define arch_read_lock_flags(lock, flags)      arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags)     arch_write_lock(lock)
-
 #endif /* _XTENSA_SPINLOCK_H */
index 0140a22551c84155e083abaeed8ee15f39ebc3d3..464c2684c4f15fd04bd84760a3c14642a87373f6 100644 (file)
@@ -47,15 +47,14 @@ static char *serial_name = "ISS serial driver";
  * initialization for the tty structure.
  */
 
-static void rs_poll(unsigned long);
+static void rs_poll(struct timer_list *);
 
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
        tty->port = &serial_port;
        spin_lock_bh(&timer_lock);
        if (tty->count == 1) {
-               setup_timer(&serial_timer, rs_poll,
-                               (unsigned long)&serial_port);
+               timer_setup(&serial_timer, rs_poll, 0);
                mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
        }
        spin_unlock_bh(&timer_lock);
@@ -92,9 +91,9 @@ static int rs_write(struct tty_struct * tty,
        return count;
 }
 
-static void rs_poll(unsigned long priv)
+static void rs_poll(struct timer_list *unused)
 {
-       struct tty_port *port = (struct tty_port *)priv;
+       struct tty_port *port = &serial_port;
        int i = 0;
        int rd = 1;
        unsigned char c;
index 66a5d15a9e0e27b613a0fa4694b46f96aaadf9d1..6363b18e5b8c457fbe2f95932ed4d16f722da905 100644 (file)
@@ -349,9 +349,9 @@ static int iss_net_poll(void)
 }
 
 
-static void iss_net_timer(unsigned long priv)
+static void iss_net_timer(struct timer_list *t)
 {
-       struct iss_net_private *lp = (struct iss_net_private *)priv;
+       struct iss_net_private *lp = from_timer(lp, t, timer);
 
        iss_net_poll();
        spin_lock(&lp->lock);
@@ -386,10 +386,8 @@ static int iss_net_open(struct net_device *dev)
        spin_unlock_bh(&opened_lock);
        spin_lock_bh(&lp->lock);
 
-       init_timer(&lp->timer);
+       timer_setup(&lp->timer, iss_net_timer, 0);
        lp->timer_val = ISS_NET_TIMER_VALUE;
-       lp->timer.data = (unsigned long) lp;
-       lp->timer.function = iss_net_timer;
        mod_timer(&lp->timer, jiffies + lp->timer_val);
 
 out:
@@ -482,7 +480,7 @@ static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
        return -EINVAL;
 }
 
-void iss_net_user_timer_expire(unsigned long _conn)
+void iss_net_user_timer_expire(struct timer_list *unused)
 {
 }
 
@@ -582,8 +580,7 @@ static int iss_net_configure(int index, char *init)
                return 1;
        }
 
-       init_timer(&lp->tl);
-       lp->tl.function = iss_net_user_timer_expire;
+       timer_setup(&lp->tl, iss_net_user_timer_expire, 0);
 
        return 0;
 
index 4dc0c1b43f4bfd917a65fc04b225a790d0fdfeaa..2f7eb66c23ec9b340d1a1ff03c6e5255842eb8f0 100644 (file)
 static void lcd_put_byte(u8 *addr, u8 data)
 {
 #ifdef CONFIG_XTFPGA_LCD_8BIT_ACCESS
-       ACCESS_ONCE(*addr) = data;
+       WRITE_ONCE(*addr, data);
 #else
-       ACCESS_ONCE(*addr) = data & 0xf0;
-       ACCESS_ONCE(*addr) = (data << 4) & 0xf0;
+       WRITE_ONCE(*addr, data & 0xf0);
+       WRITE_ONCE(*addr, (data << 4) & 0xf0);
 #endif
 }
 
 static int __init lcd_init(void)
 {
-       ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
+       WRITE_ONCE(*LCD_INSTR_ADDR, LCD_DISPLAY_MODE8BIT);
        mdelay(5);
-       ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
+       WRITE_ONCE(*LCD_INSTR_ADDR, LCD_DISPLAY_MODE8BIT);
        udelay(200);
-       ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
+       WRITE_ONCE(*LCD_INSTR_ADDR, LCD_DISPLAY_MODE8BIT);
        udelay(50);
 #ifndef CONFIG_XTFPGA_LCD_8BIT_ACCESS
-       ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE4BIT;
+       WRITE_ONCE(*LCD_INSTR_ADDR, LCD_DISPLAY_MODE4BIT);
        udelay(50);
        lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_MODE4BIT);
        udelay(50);
index 101c2a9b548150cd3f7bb5b28a460ef82c9e4a75..cc60213e56d8695d121cec7e7402341175e24f46 100644 (file)
@@ -917,17 +917,9 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
 }
 EXPORT_SYMBOL_GPL(bio_iov_iter_get_pages);
 
-struct submit_bio_ret {
-       struct completion event;
-       int error;
-};
-
 static void submit_bio_wait_endio(struct bio *bio)
 {
-       struct submit_bio_ret *ret = bio->bi_private;
-
-       ret->error = blk_status_to_errno(bio->bi_status);
-       complete(&ret->event);
+       complete(bio->bi_private);
 }
 
 /**
@@ -943,16 +935,15 @@ static void submit_bio_wait_endio(struct bio *bio)
  */
 int submit_bio_wait(struct bio *bio)
 {
-       struct submit_bio_ret ret;
+       DECLARE_COMPLETION_ONSTACK_MAP(done, bio->bi_disk->lockdep_map);
 
-       init_completion(&ret.event);
-       bio->bi_private = &ret;
+       bio->bi_private = &done;
        bio->bi_end_io = submit_bio_wait_endio;
        bio->bi_opf |= REQ_SYNC;
        submit_bio(bio);
-       wait_for_completion_io(&ret.event);
+       wait_for_completion_io(&done);
 
-       return ret.error;
+       return blk_status_to_errno(bio->bi_status);
 }
 EXPORT_SYMBOL(submit_bio_wait);
 
index 6a9a0f03a67bd9ac9839ba667fb407a03694a304..d822530e6aeade81a7c9b2b3d9c6a6cccc0bb351 100644 (file)
@@ -261,7 +261,7 @@ static inline bool stat_sample_valid(struct blk_rq_stat *stat)
 
 static u64 rwb_sync_issue_lat(struct rq_wb *rwb)
 {
-       u64 now, issue = ACCESS_ONCE(rwb->sync_issue);
+       u64 now, issue = READ_ONCE(rwb->sync_issue);
 
        if (!issue || !rwb->sync_cookie)
                return 0;
index dd305c65ffb05d5016f1c602e65849a2fbf8e418..630c0da6cfcf2633bf8340616b6ba1d013f5f408 100644 (file)
@@ -1354,13 +1354,7 @@ dev_t blk_lookup_devt(const char *name, int partno)
 }
 EXPORT_SYMBOL(blk_lookup_devt);
 
-struct gendisk *alloc_disk(int minors)
-{
-       return alloc_disk_node(minors, NUMA_NO_NODE);
-}
-EXPORT_SYMBOL(alloc_disk);
-
-struct gendisk *alloc_disk_node(int minors, int node_id)
+struct gendisk *__alloc_disk_node(int minors, int node_id)
 {
        struct gendisk *disk;
        struct disk_part_tbl *ptbl;
@@ -1411,7 +1405,7 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
        }
        return disk;
 }
-EXPORT_SYMBOL(alloc_disk_node);
+EXPORT_SYMBOL(__alloc_disk_node);
 
 struct kobject *get_disk(struct gendisk *disk)
 {
index 1ce37ae0ce565a130962f50244f331117fe965d8..0a083342ec8cf3b17c4da15c515c8c3d7a519a0f 100644 (file)
@@ -363,7 +363,7 @@ static int crypto_ccm_decrypt(struct aead_request *req)
        unsigned int cryptlen = req->cryptlen;
        u8 *authtag = pctx->auth_tag;
        u8 *odata = pctx->odata;
-       u8 *iv = req->iv;
+       u8 *iv = pctx->idata;
        int err;
 
        cryptlen -= authsize;
@@ -379,6 +379,8 @@ static int crypto_ccm_decrypt(struct aead_request *req)
        if (req->src != req->dst)
                dst = pctx->dst;
 
+       memcpy(iv, req->iv, 16);
+
        skcipher_request_set_tfm(skreq, ctx->ctr);
        skcipher_request_set_callback(skreq, pctx->flags,
                                      crypto_ccm_decrypt_done, req);
index 1d7af3c2ff27c770218272115a287cb35d02ec0b..152744c5ef0f394afe1c32971053fd796b9fc6aa 100644 (file)
@@ -209,4 +209,6 @@ source "drivers/tee/Kconfig"
 
 source "drivers/mux/Kconfig"
 
+source "drivers/opp/Kconfig"
+
 endmenu
index d242d3514d30589e79d1ac61e905827f7b53f8aa..1d034b6804310a1d740b4e8aa40c649922748d77 100644 (file)
@@ -126,6 +126,7 @@ obj-$(CONFIG_ACCESSIBILITY) += accessibility/
 obj-$(CONFIG_ISDN)             += isdn/
 obj-$(CONFIG_EDAC)             += edac/
 obj-$(CONFIG_EISA)             += eisa/
+obj-$(CONFIG_PM_OPP)           += opp/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_CPU_IDLE)         += cpuidle/
 obj-y                          += mmc/
index 5b1938f4b626196c68689d3606c9a4bf5f646f59..91477d5ab422c4795b56abffe1075f3c35e40b76 100644 (file)
@@ -81,6 +81,11 @@ endif
 config ACPI_SPCR_TABLE
        bool
 
+config ACPI_LPIT
+       bool
+       depends on X86_64
+       default y
+
 config ACPI_SLEEP
        bool
        depends on SUSPEND || HIBERNATION
@@ -536,4 +541,20 @@ if ARM64
 source "drivers/acpi/arm64/Kconfig"
 endif
 
+config TPS68470_PMIC_OPREGION
+       bool "ACPI operation region support for TPS68470 PMIC"
+       depends on MFD_TPS68470
+       help
+         This config adds ACPI operation region support for TI TPS68470 PMIC.
+         TPS68470 device is an advanced power management unit that powers
+         a Compact Camera Module (CCM), generates clocks for image sensors,
+         drives a dual LED for flash and incorporates two LED drivers for
+         general purpose indicators.
+         This driver enables ACPI operation region support control voltage
+         regulators and clocks.
+
+         This option is a bool as it provides an ACPI operation
+         region, which must be available before any of the devices
+         using this, are probed.
+
 endif  # ACPI
index cd1abc9bc325c5dbd966089e8fe61344d4eaf5ea..31c15d84a8d03811358cc4f0b9a40509694c10bc 100644 (file)
@@ -57,6 +57,7 @@ acpi-$(CONFIG_DEBUG_FS)               += debugfs.o
 acpi-$(CONFIG_ACPI_NUMA)       += numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y                         += acpi_lpat.o
+acpi-$(CONFIG_ACPI_LPIT)       += acpi_lpit.o
 acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
 acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
 
@@ -108,6 +109,8 @@ obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o
 
 obj-$(CONFIG_ACPI_CONFIGFS)    += acpi_configfs.o
 
+obj-$(CONFIG_TPS68470_PMIC_OPREGION)   += pmic/tps68470_pmic.o
+
 video-objs                     += acpi_video.o video_detect.o
 obj-y                          += dptf/
 
index 8f52483219ba109625792c24cc29e490068ea209..47a7ed557bd645924a6cfe112e8f712dfc18a6b9 100644 (file)
@@ -265,6 +265,7 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Unsupported event [0x%x]\n", event));
+       /* fall through */
        case ACPI_AC_NOTIFY_STATUS:
        case ACPI_NOTIFY_BUS_CHECK:
        case ACPI_NOTIFY_DEVICE_CHECK:
diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c
new file mode 100644 (file)
index 0000000..e94e478
--- /dev/null
@@ -0,0 +1,162 @@
+
+/*
+ * acpi_lpit.c - LPIT table processing functions
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/cpu.h>
+#include <linux/acpi.h>
+#include <asm/msr.h>
+#include <asm/tsc.h>
+
+struct lpit_residency_info {
+       struct acpi_generic_address gaddr;
+       u64 frequency;
+       void __iomem *iomem_addr;
+};
+
+/* Storage for an memory mapped and FFH based entries */
+static struct lpit_residency_info residency_info_mem;
+static struct lpit_residency_info residency_info_ffh;
+
+static int lpit_read_residency_counter_us(u64 *counter, bool io_mem)
+{
+       int err;
+
+       if (io_mem) {
+               u64 count = 0;
+               int error;
+
+               error = acpi_os_read_iomem(residency_info_mem.iomem_addr, &count,
+                                          residency_info_mem.gaddr.bit_width);
+               if (error)
+                       return error;
+
+               *counter = div64_u64(count * 1000000ULL, residency_info_mem.frequency);
+               return 0;
+       }
+
+       err = rdmsrl_safe(residency_info_ffh.gaddr.address, counter);
+       if (!err) {
+               u64 mask = GENMASK_ULL(residency_info_ffh.gaddr.bit_offset +
+                                      residency_info_ffh.gaddr. bit_width - 1,
+                                      residency_info_ffh.gaddr.bit_offset);
+
+               *counter &= mask;
+               *counter >>= residency_info_ffh.gaddr.bit_offset;
+               *counter = div64_u64(*counter * 1000000ULL, residency_info_ffh.frequency);
+               return 0;
+       }
+
+       return -ENODATA;
+}
+
+static ssize_t low_power_idle_system_residency_us_show(struct device *dev,
+                                                      struct device_attribute *attr,
+                                                      char *buf)
+{
+       u64 counter;
+       int ret;
+
+       ret = lpit_read_residency_counter_us(&counter, true);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%llu\n", counter);
+}
+static DEVICE_ATTR_RO(low_power_idle_system_residency_us);
+
+static ssize_t low_power_idle_cpu_residency_us_show(struct device *dev,
+                                                   struct device_attribute *attr,
+                                                   char *buf)
+{
+       u64 counter;
+       int ret;
+
+       ret = lpit_read_residency_counter_us(&counter, false);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%llu\n", counter);
+}
+static DEVICE_ATTR_RO(low_power_idle_cpu_residency_us);
+
+int lpit_read_residency_count_address(u64 *address)
+{
+       if (!residency_info_mem.gaddr.address)
+               return -EINVAL;
+
+       *address = residency_info_mem.gaddr.address;
+
+       return 0;
+}
+
+static void lpit_update_residency(struct lpit_residency_info *info,
+                                struct acpi_lpit_native *lpit_native)
+{
+       info->frequency = lpit_native->counter_frequency ?
+                               lpit_native->counter_frequency : tsc_khz * 1000;
+       if (!info->frequency)
+               info->frequency = 1;
+
+       info->gaddr = lpit_native->residency_counter;
+       if (info->gaddr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+               info->iomem_addr = ioremap_nocache(info->gaddr.address,
+                                                  info->gaddr.bit_width / 8);
+               if (!info->iomem_addr)
+                       return;
+
+               /* Silently fail, if cpuidle attribute group is not present */
+               sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj,
+                                       &dev_attr_low_power_idle_system_residency_us.attr,
+                                       "cpuidle");
+       } else if (info->gaddr.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
+               /* Silently fail, if cpuidle attribute group is not present */
+               sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj,
+                                       &dev_attr_low_power_idle_cpu_residency_us.attr,
+                                       "cpuidle");
+       }
+}
+
+static void lpit_process(u64 begin, u64 end)
+{
+       while (begin + sizeof(struct acpi_lpit_native) < end) {
+               struct acpi_lpit_native *lpit_native = (struct acpi_lpit_native *)begin;
+
+               if (!lpit_native->header.type && !lpit_native->header.flags) {
+                       if (lpit_native->residency_counter.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY &&
+                           !residency_info_mem.gaddr.address) {
+                               lpit_update_residency(&residency_info_mem, lpit_native);
+                       } else if (lpit_native->residency_counter.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE &&
+                                  !residency_info_ffh.gaddr.address) {
+                               lpit_update_residency(&residency_info_ffh, lpit_native);
+                       }
+               }
+               begin += lpit_native->header.length;
+       }
+}
+
+void acpi_init_lpit(void)
+{
+       acpi_status status;
+       u64 lpit_begin;
+       struct acpi_table_lpit *lpit;
+
+       status = acpi_get_table(ACPI_SIG_LPIT, 0, (struct acpi_table_header **)&lpit);
+
+       if (ACPI_FAILURE(status))
+               return;
+
+       lpit_begin = (u64)lpit + sizeof(*lpit);
+       lpit_process(lpit_begin, lpit_begin + lpit->header.length);
+}
index 032ae44710e5d877770ce746f2412393f2171189..7f2b02cc8ea148c6091b56006889babfeb09e309 100644 (file)
@@ -362,7 +362,7 @@ static int register_device_clock(struct acpi_device *adev,
 {
        const struct lpss_device_desc *dev_desc = pdata->dev_desc;
        const char *devname = dev_name(&adev->dev);
-       struct clk *clk = ERR_PTR(-ENODEV);
+       struct clk *clk;
        struct lpss_clk_data *clk_data;
        const char *parent, *clk_name;
        void __iomem *prv_base;
@@ -693,7 +693,7 @@ static int acpi_lpss_activate(struct device *dev)
        struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
        int ret;
 
-       ret = acpi_dev_runtime_resume(dev);
+       ret = acpi_dev_resume(dev);
        if (ret)
                return ret;
 
@@ -713,42 +713,8 @@ static int acpi_lpss_activate(struct device *dev)
 
 static void acpi_lpss_dismiss(struct device *dev)
 {
-       acpi_dev_runtime_suspend(dev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int acpi_lpss_suspend_late(struct device *dev)
-{
-       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
-       int ret;
-
-       ret = pm_generic_suspend_late(dev);
-       if (ret)
-               return ret;
-
-       if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
-               acpi_lpss_save_ctx(dev, pdata);
-
-       return acpi_dev_suspend_late(dev);
-}
-
-static int acpi_lpss_resume_early(struct device *dev)
-{
-       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
-       int ret;
-
-       ret = acpi_dev_resume_early(dev);
-       if (ret)
-               return ret;
-
-       acpi_lpss_d3_to_d0_delay(pdata);
-
-       if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
-               acpi_lpss_restore_ctx(dev, pdata);
-
-       return pm_generic_resume_early(dev);
+       acpi_dev_suspend(dev, false);
 }
-#endif /* CONFIG_PM_SLEEP */
 
 /* IOSF SB for LPSS island */
 #define LPSS_IOSF_UNIT_LPIOEP          0xA0
@@ -835,19 +801,15 @@ static void lpss_iosf_exit_d3_state(void)
        mutex_unlock(&lpss_iosf_mutex);
 }
 
-static int acpi_lpss_runtime_suspend(struct device *dev)
+static int acpi_lpss_suspend(struct device *dev, bool wakeup)
 {
        struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
        int ret;
 
-       ret = pm_generic_runtime_suspend(dev);
-       if (ret)
-               return ret;
-
        if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
                acpi_lpss_save_ctx(dev, pdata);
 
-       ret = acpi_dev_runtime_suspend(dev);
+       ret = acpi_dev_suspend(dev, wakeup);
 
        /*
         * This call must be last in the sequence, otherwise PMC will return
@@ -860,7 +822,7 @@ static int acpi_lpss_runtime_suspend(struct device *dev)
        return ret;
 }
 
-static int acpi_lpss_runtime_resume(struct device *dev)
+static int acpi_lpss_resume(struct device *dev)
 {
        struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
        int ret;
@@ -872,7 +834,7 @@ static int acpi_lpss_runtime_resume(struct device *dev)
        if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available())
                lpss_iosf_exit_d3_state();
 
-       ret = acpi_dev_runtime_resume(dev);
+       ret = acpi_dev_resume(dev);
        if (ret)
                return ret;
 
@@ -881,7 +843,41 @@ static int acpi_lpss_runtime_resume(struct device *dev)
        if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
                acpi_lpss_restore_ctx(dev, pdata);
 
-       return pm_generic_runtime_resume(dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int acpi_lpss_suspend_late(struct device *dev)
+{
+       int ret;
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       ret = pm_generic_suspend_late(dev);
+       return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
+}
+
+static int acpi_lpss_resume_early(struct device *dev)
+{
+       int ret = acpi_lpss_resume(dev);
+
+       return ret ? ret : pm_generic_resume_early(dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int acpi_lpss_runtime_suspend(struct device *dev)
+{
+       int ret = pm_generic_runtime_suspend(dev);
+
+       return ret ? ret : acpi_lpss_suspend(dev, true);
+}
+
+static int acpi_lpss_runtime_resume(struct device *dev)
+{
+       int ret = acpi_lpss_resume(dev);
+
+       return ret ? ret : pm_generic_runtime_resume(dev);
 }
 #endif /* CONFIG_PM */
 
@@ -894,13 +890,20 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM_SLEEP
                .prepare = acpi_subsys_prepare,
-               .complete = pm_complete_with_resume_check,
+               .complete = acpi_subsys_complete,
                .suspend = acpi_subsys_suspend,
                .suspend_late = acpi_lpss_suspend_late,
+               .suspend_noirq = acpi_subsys_suspend_noirq,
+               .resume_noirq = acpi_subsys_resume_noirq,
                .resume_early = acpi_lpss_resume_early,
                .freeze = acpi_subsys_freeze,
+               .freeze_late = acpi_subsys_freeze_late,
+               .freeze_noirq = acpi_subsys_freeze_noirq,
+               .thaw_noirq = acpi_subsys_thaw_noirq,
                .poweroff = acpi_subsys_suspend,
                .poweroff_late = acpi_lpss_suspend_late,
+               .poweroff_noirq = acpi_subsys_suspend_noirq,
+               .restore_noirq = acpi_subsys_resume_noirq,
                .restore_early = acpi_lpss_resume_early,
 #endif
                .runtime_suspend = acpi_lpss_runtime_suspend,
index 86c10599d9f83e86517aa436d6d93f78839e0f5f..449d86d39965e6090a518eab4f9c18aa9f2f6852 100644 (file)
@@ -82,6 +82,7 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
                 * PIIX4 models.
                 */
                errata.piix4.throttle = 1;
+               /* fall through*/
 
        case 2:         /* PIIX4E */
        case 3:         /* PIIX4M */
index e05232da05888a69660082fcd7751652ec9e81d4..71f6f2624debca2c3909307c30ec17fc04409ea4 100644 (file)
@@ -178,6 +178,7 @@ acpi-y +=           \
        utresrc.o       \
        utstate.o       \
        utstring.o      \
+       utstrsuppt.o    \
        utstrtoul64.o   \
        utxface.o       \
        utxfinit.o      \
index fd4f3cacb356aa005d49f90572f32194894c6f75..cd722d8edacbb462c9977372b758b9de1a2518cb 100644 (file)
@@ -66,9 +66,9 @@ acpi_status
 acpi_hw_validate_register(struct acpi_generic_address *reg,
                          u8 max_bit_width, u64 *address);
 
-acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg);
+acpi_status acpi_hw_read(u64 *value, struct acpi_generic_address *reg);
 
-acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg);
+acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg);
 
 struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id);
 
index 29a863c8531835e7d17a82c649fca240f770d751..29555c8789a31e5e6d80ccf1fb7d5acd29899daf 100644 (file)
@@ -101,7 +101,8 @@ typedef const struct acpi_exdump_info {
  */
 acpi_status
 acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
-                          union acpi_operand_object **result_desc, u32 flags);
+                          union acpi_operand_object **result_desc,
+                          u32 implicit_conversion);
 
 acpi_status
 acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
@@ -424,9 +425,6 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
                             struct acpi_walk_state *walk_state,
                             u8 implicit_conversion);
 
-#define ACPI_IMPLICIT_CONVERSION        TRUE
-#define ACPI_NO_IMPLICIT_CONVERSION     FALSE
-
 /*
  * exstoren - resolve/store object
  */
index 745134ade35fd72972efd708d0cb66c550a46037..83b75e9db7efc88003ffa6de681439e6bfa61b2d 100644 (file)
@@ -141,6 +141,11 @@ extern const char *acpi_gbl_ptyp_decode[];
 #define ACPI_MSG_SUFFIX \
        acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
 
+/* Flags to indicate implicit or explicit string-to-integer conversion */
+
+#define ACPI_IMPLICIT_CONVERSION        TRUE
+#define ACPI_NO_IMPLICIT_CONVERSION     FALSE
+
 /* Types for Resource descriptor entries */
 
 #define ACPI_INVALID_RESOURCE           0
@@ -197,15 +202,31 @@ void acpi_ut_strlwr(char *src_string);
 
 int acpi_ut_stricmp(char *string1, char *string2);
 
-acpi_status acpi_ut_strtoul64(char *string, u32 flags, u64 *ret_integer);
+/*
+ * utstrsuppt - string-to-integer conversion support functions
+ */
+acpi_status acpi_ut_convert_octal_string(char *string, u64 *return_value);
+
+acpi_status acpi_ut_convert_decimal_string(char *string, u64 *return_value_ptr);
+
+acpi_status acpi_ut_convert_hex_string(char *string, u64 *return_value_ptr);
+
+char acpi_ut_remove_whitespace(char **string);
+
+char acpi_ut_remove_leading_zeros(char **string);
+
+u8 acpi_ut_detect_hex_prefix(char **string);
+
+u8 acpi_ut_detect_octal_prefix(char **string);
 
 /*
- * Values for Flags above
- * Note: LIMIT values correspond to acpi_gbl_integer_byte_width values (4/8)
+ * utstrtoul64 - string-to-integer conversion functions
  */
-#define ACPI_STRTOUL_32BIT          0x04       /* 4 bytes */
-#define ACPI_STRTOUL_64BIT          0x08       /* 8 bytes */
-#define ACPI_STRTOUL_BASE16         0x10       /* Default: Base10/16 */
+acpi_status acpi_ut_strtoul64(char *string, u64 *ret_integer);
+
+u64 acpi_ut_explicit_strtoul64(char *string);
+
+u64 acpi_ut_implicit_strtoul64(char *string);
 
 /*
  * utglobal - Global data structures and procedures
index 857dbc43a9b133cec8f4f9b27ca91434806fe7f1..32d546f0db2f567b8747d73fc6ffec18baa22036 100644 (file)
@@ -277,10 +277,7 @@ acpi_db_convert_to_object(acpi_object_type type,
        default:
 
                object->type = ACPI_TYPE_INTEGER;
-               status = acpi_ut_strtoul64(string,
-                                          (acpi_gbl_integer_byte_width |
-                                           ACPI_STRTOUL_BASE16),
-                                          &object->integer.value);
+               status = acpi_ut_strtoul64(string, &object->integer.value);
                break;
        }
 
index 20d7744b06ae7c77fb9acaaf088c28b4f9652b17..22f45d090733244e008607be4b4ad2e42df9f0de 100644 (file)
@@ -134,7 +134,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
         * object. Implicitly convert the argument if necessary.
         */
        status = acpi_ex_convert_to_integer(obj_desc, &local_obj_desc,
-                                           ACPI_STRTOUL_BASE16);
+                                           ACPI_IMPLICIT_CONVERSION);
        if (ACPI_FAILURE(status)) {
                goto cleanup;
        }
index 229382035550bc4473d13272f76753fcc6e6e8e4..263d8fc4a9e2f848080cd3e16550082de819d9cc 100644 (file)
@@ -390,8 +390,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
        struct acpi_gpe_handler_info *gpe_handler_info;
        u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
        u8 enabled_status_byte;
-       u32 status_reg;
-       u32 enable_reg;
+       u64 status_reg;
+       u64 enable_reg;
        acpi_cpu_flags flags;
        u32 i;
        u32 j;
@@ -472,7 +472,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
                                          gpe_register_info->base_gpe_number,
                                          gpe_register_info->base_gpe_number +
                                          (ACPI_GPE_REGISTER_WIDTH - 1),
-                                         status_reg, enable_reg,
+                                         (u32)status_reg, (u32)enable_reg,
                                          gpe_register_info->enable_for_run,
                                          gpe_register_info->enable_for_wake));
 
index 76bfb7dcae2f083f1fb7f1a5231a2e973a65c673..59b8de2f07d3915a3e857980eac934d1d1c8ca10 100644 (file)
@@ -156,7 +156,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
 
                status =
                    acpi_ex_convert_to_integer(local_operand1, &temp_operand1,
-                                              ACPI_STRTOUL_BASE16);
+                                              ACPI_IMPLICIT_CONVERSION);
                break;
 
        case ACPI_TYPE_BUFFER:
index f71028e334eefe6fcdf65b0ab832031c19d6263e..23ebadb06a95b248830105d4c8b02bcc0cfb0044 100644 (file)
@@ -57,10 +57,10 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length);
  *
  * FUNCTION:    acpi_ex_convert_to_integer
  *
- * PARAMETERS:  obj_desc        - Object to be converted. Must be an
- *                                Integer, Buffer, or String
- *              result_desc     - Where the new Integer object is returned
- *              flags           - Used for string conversion
+ * PARAMETERS:  obj_desc            - Object to be converted. Must be an
+ *                                    Integer, Buffer, or String
+ *              result_desc         - Where the new Integer object is returned
+ *              implicit_conversion - Used for string conversion
  *
  * RETURN:      Status
  *
@@ -70,14 +70,14 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length);
 
 acpi_status
 acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
-                          union acpi_operand_object **result_desc, u32 flags)
+                          union acpi_operand_object **result_desc,
+                          u32 implicit_conversion)
 {
        union acpi_operand_object *return_desc;
        u8 *pointer;
        u64 result;
        u32 i;
        u32 count;
-       acpi_status status;
 
        ACPI_FUNCTION_TRACE_PTR(ex_convert_to_integer, obj_desc);
 
@@ -123,12 +123,18 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
                 * hexadecimal as per the ACPI specification. The only exception (as
                 * of ACPI 3.0) is that the to_integer() operator allows both decimal
                 * and hexadecimal strings (hex prefixed with "0x").
+                *
+                * Explicit conversion is used only by to_integer.
+                * All other string-to-integer conversions are implicit conversions.
                 */
-               status = acpi_ut_strtoul64(ACPI_CAST_PTR(char, pointer),
-                                          (acpi_gbl_integer_byte_width |
-                                           flags), &result);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
+               if (implicit_conversion) {
+                       result =
+                           acpi_ut_implicit_strtoul64(ACPI_CAST_PTR
+                                                      (char, pointer));
+               } else {
+                       result =
+                           acpi_ut_explicit_strtoul64(ACPI_CAST_PTR
+                                                      (char, pointer));
                }
                break;
 
@@ -631,7 +637,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
                         */
                        status =
                            acpi_ex_convert_to_integer(source_desc, result_desc,
-                                                      ACPI_STRTOUL_BASE16);
+                                                      ACPI_IMPLICIT_CONVERSION);
                        break;
 
                case ACPI_TYPE_STRING:
index 1e7649ce0a7b1b324862d69c9421f49eae49ca47..dbad3ebd7df504f362a97dc365b5475a8037cb29 100644 (file)
@@ -330,7 +330,7 @@ acpi_ex_do_logical_op(u16 opcode,
        case ACPI_TYPE_INTEGER:
 
                status = acpi_ex_convert_to_integer(operand1, &local_operand1,
-                                                   ACPI_STRTOUL_BASE16);
+                                                   ACPI_IMPLICIT_CONVERSION);
                break;
 
        case ACPI_TYPE_STRING:
index c4852429e2fff62a561e7e495da1502983e5518c..1c7c9962b0de7f6180bc8561c9343703e9944cde 100644 (file)
@@ -415,7 +415,7 @@ acpi_ex_resolve_operands(u16 opcode,
                         * Known as "Implicit Source Operand Conversion"
                         */
                        status = acpi_ex_convert_to_integer(obj_desc, stack_ptr,
-                                                           ACPI_STRTOUL_BASE16);
+                                                           ACPI_IMPLICIT_CONVERSION);
                        if (ACPI_FAILURE(status)) {
                                if (status == AE_TYPE) {
                                        ACPI_ERROR((AE_INFO,
index 5eb11b30a79e6c685118e660a5d294c93d02e527..09b6822aa5cc2554e1043ef158c1e45f38c29b77 100644 (file)
@@ -99,7 +99,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
 {
        struct acpi_gpe_register_info *gpe_register_info;
        acpi_status status = AE_OK;
-       u32 enable_mask;
+       u64 enable_mask;
        u32 register_bit;
 
        ACPI_FUNCTION_ENTRY();
@@ -214,7 +214,7 @@ acpi_status
 acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
                       acpi_event_status *event_status)
 {
-       u32 in_byte;
+       u64 in_byte;
        u32 register_bit;
        struct acpi_gpe_register_info *gpe_register_info;
        acpi_event_status local_event_status = 0;
index acb417b58bbb388f1f53325e154ade65cde131b9..aa6e000819155024631d1e0922d69abe297095a6 100644 (file)
@@ -220,16 +220,15 @@ acpi_hw_validate_register(struct acpi_generic_address *reg,
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
- *              version of acpi_read, used internally since the overhead of
- *              64-bit values is not needed.
+ * DESCRIPTION: Read from either memory or IO space. This is a 64-bit max
+ *              version of acpi_read.
  *
  * LIMITATIONS: <These limitations also apply to acpi_hw_write>
  *      space_ID must be system_memory or system_IO.
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
+acpi_status acpi_hw_read(u64 *value, struct acpi_generic_address *reg)
 {
        u64 address;
        u8 access_width;
@@ -244,17 +243,17 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
 
        /* Validate contents of the GAS register */
 
-       status = acpi_hw_validate_register(reg, 32, &address);
+       status = acpi_hw_validate_register(reg, 64, &address);
        if (ACPI_FAILURE(status)) {
                return (status);
        }
 
        /*
-        * Initialize entire 32-bit return value to zero, convert access_width
+        * Initialize entire 64-bit return value to zero, convert access_width
         * into number of bits based
         */
        *value = 0;
-       access_width = acpi_hw_get_access_bit_width(address, reg, 32);
+       access_width = acpi_hw_get_access_bit_width(address, reg, 64);
        bit_width = reg->bit_offset + reg->bit_width;
        bit_offset = reg->bit_offset;
 
@@ -265,7 +264,7 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
        index = 0;
        while (bit_width) {
                if (bit_offset >= access_width) {
-                       value32 = 0;
+                       value64 = 0;
                        bit_offset -= access_width;
                } else {
                        if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
@@ -276,7 +275,6 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
                                                        ACPI_DIV_8
                                                        (access_width),
                                                        &value64, access_width);
-                               value32 = (u32)value64;
                        } else {        /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
 
                                status = acpi_hw_read_port((acpi_io_address)
@@ -286,15 +284,16 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
                                                           (access_width),
                                                           &value32,
                                                           access_width);
+                               value64 = (u64)value32;
                        }
                }
 
                /*
                 * Use offset style bit writes because "Index * AccessWidth" is
-                * ensured to be less than 32-bits by acpi_hw_validate_register().
+                * ensured to be less than 64-bits by acpi_hw_validate_register().
                 */
                ACPI_SET_BITS(value, index * access_width,
-                             ACPI_MASK_BITS_ABOVE_32(access_width), value32);
+                             ACPI_MASK_BITS_ABOVE_64(access_width), value64);
 
                bit_width -=
                    bit_width > access_width ? access_width : bit_width;
@@ -302,8 +301,9 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO,
-                         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
-                         *value, access_width, ACPI_FORMAT_UINT64(address),
+                         "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
+                         ACPI_FORMAT_UINT64(*value), access_width,
+                         ACPI_FORMAT_UINT64(address),
                          acpi_ut_get_region_name(reg->space_id)));
 
        return (status);
@@ -318,20 +318,18 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
- *              version of acpi_write, used internally since the overhead of
- *              64-bit values is not needed.
+ * DESCRIPTION: Write to either memory or IO space. This is a 64-bit max
+ *              version of acpi_write.
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
+acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg)
 {
        u64 address;
        u8 access_width;
        u32 bit_width;
        u8 bit_offset;
        u64 value64;
-       u32 value32;
        u8 index;
        acpi_status status;
 
@@ -339,14 +337,14 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
 
        /* Validate contents of the GAS register */
 
-       status = acpi_hw_validate_register(reg, 32, &address);
+       status = acpi_hw_validate_register(reg, 64, &address);
        if (ACPI_FAILURE(status)) {
                return (status);
        }
 
        /* Convert access_width into number of bits based */
 
-       access_width = acpi_hw_get_access_bit_width(address, reg, 32);
+       access_width = acpi_hw_get_access_bit_width(address, reg, 64);
        bit_width = reg->bit_offset + reg->bit_width;
        bit_offset = reg->bit_offset;
 
@@ -358,16 +356,15 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
        while (bit_width) {
                /*
                 * Use offset style bit reads because "Index * AccessWidth" is
-                * ensured to be less than 32-bits by acpi_hw_validate_register().
+                * ensured to be less than 64-bits by acpi_hw_validate_register().
                 */
-               value32 = ACPI_GET_BITS(&value, index * access_width,
-                                       ACPI_MASK_BITS_ABOVE_32(access_width));
+               value64 = ACPI_GET_BITS(&value, index * access_width,
+                                       ACPI_MASK_BITS_ABOVE_64(access_width));
 
                if (bit_offset >= access_width) {
                        bit_offset -= access_width;
                } else {
                        if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-                               value64 = (u64)value32;
                                status =
                                    acpi_os_write_memory((acpi_physical_address)
                                                         address +
@@ -382,7 +379,7 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
                                                            index *
                                                            ACPI_DIV_8
                                                            (access_width),
-                                                           value32,
+                                                           (u32)value64,
                                                            access_width);
                        }
                }
@@ -397,8 +394,9 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO,
-                         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
-                         value, access_width, ACPI_FORMAT_UINT64(address),
+                         "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
+                         ACPI_FORMAT_UINT64(value), access_width,
+                         ACPI_FORMAT_UINT64(address),
                          acpi_ut_get_region_name(reg->space_id)));
 
        return (status);
@@ -526,6 +524,7 @@ acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
 acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
 {
        u32 value = 0;
+       u64 value64;
        acpi_status status;
 
        ACPI_FUNCTION_TRACE(hw_register_read);
@@ -564,12 +563,14 @@ acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
        case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
 
                status =
-                   acpi_hw_read(&value, &acpi_gbl_FADT.xpm2_control_block);
+                   acpi_hw_read(&value64, &acpi_gbl_FADT.xpm2_control_block);
+               value = (u32)value64;
                break;
 
        case ACPI_REGISTER_PM_TIMER:    /* 32-bit access */
 
-               status = acpi_hw_read(&value, &acpi_gbl_FADT.xpm_timer_block);
+               status = acpi_hw_read(&value64, &acpi_gbl_FADT.xpm_timer_block);
+               value = (u32)value64;
                break;
 
        case ACPI_REGISTER_SMI_COMMAND_BLOCK:   /* 8-bit access */
@@ -586,7 +587,7 @@ acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
        }
 
        if (ACPI_SUCCESS(status)) {
-               *return_value = value;
+               *return_value = (u32)value;
        }
 
        return_ACPI_STATUS(status);
@@ -622,6 +623,7 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
 {
        acpi_status status;
        u32 read_value;
+       u64 read_value64;
 
        ACPI_FUNCTION_TRACE(hw_register_write);
 
@@ -685,11 +687,12 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
                 * as per the ACPI spec.
                 */
                status =
-                   acpi_hw_read(&read_value,
+                   acpi_hw_read(&read_value64,
                                 &acpi_gbl_FADT.xpm2_control_block);
                if (ACPI_FAILURE(status)) {
                        goto exit;
                }
+               read_value = (u32)read_value64;
 
                /* Insert the bits to be preserved */
 
@@ -745,22 +748,25 @@ acpi_hw_read_multiple(u32 *value,
 {
        u32 value_a = 0;
        u32 value_b = 0;
+       u64 value64;
        acpi_status status;
 
        /* The first register is always required */
 
-       status = acpi_hw_read(&value_a, register_a);
+       status = acpi_hw_read(&value64, register_a);
        if (ACPI_FAILURE(status)) {
                return (status);
        }
+       value_a = (u32)value64;
 
        /* Second register is optional */
 
        if (register_b->address) {
-               status = acpi_hw_read(&value_b, register_b);
+               status = acpi_hw_read(&value64, register_b);
                if (ACPI_FAILURE(status)) {
                        return (status);
                }
+               value_b = (u32)value64;
        }
 
        /*
index b3c5d8c754bb864a0ddf18ac4759bbb301a1e93f..a2f4e25d45b18e5c241a02890d3302256b68c0d0 100644 (file)
@@ -94,6 +94,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_timer_resolution)
 acpi_status acpi_get_timer(u32 * ticks)
 {
        acpi_status status;
+       u64 timer_value;
 
        ACPI_FUNCTION_TRACE(acpi_get_timer);
 
@@ -107,7 +108,14 @@ acpi_status acpi_get_timer(u32 * ticks)
                return_ACPI_STATUS(AE_SUPPORT);
        }
 
-       status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block);
+       status = acpi_hw_read(&timer_value, &acpi_gbl_FADT.xpm_timer_block);
+       if (ACPI_SUCCESS(status)) {
+
+               /* ACPI PM Timer is defined to be 32 bits (PM_TMR_LEN) */
+
+               *ticks = (u32)timer_value;
+       }
+
        return_ACPI_STATUS(status);
 }
 
index 34684ae899810889738fee7bbe3c2d2f806d4d01..b3c6e439933c56e428ff6d58485c594ca959b4cd 100644 (file)
@@ -125,76 +125,12 @@ ACPI_EXPORT_SYMBOL(acpi_reset)
  ******************************************************************************/
 acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg)
 {
-       u32 value_lo;
-       u32 value_hi;
-       u32 width;
-       u64 address;
        acpi_status status;
 
        ACPI_FUNCTION_NAME(acpi_read);
 
-       if (!return_value) {
-               return (AE_BAD_PARAMETER);
-       }
-
-       /* Validate contents of the GAS register. Allow 64-bit transfers */
-
-       status = acpi_hw_validate_register(reg, 64, &address);
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
-
-       /*
-        * Two address spaces supported: Memory or I/O. PCI_Config is
-        * not supported here because the GAS structure is insufficient
-        */
-       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-               status = acpi_os_read_memory((acpi_physical_address)
-                                            address, return_value,
-                                            reg->bit_width);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-       } else {                /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
-
-               value_lo = 0;
-               value_hi = 0;
-
-               width = reg->bit_width;
-               if (width == 64) {
-                       width = 32;     /* Break into two 32-bit transfers */
-               }
-
-               status = acpi_hw_read_port((acpi_io_address)
-                                          address, &value_lo, width);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-
-               if (reg->bit_width == 64) {
-
-                       /* Read the top 32 bits */
-
-                       status = acpi_hw_read_port((acpi_io_address)
-                                                  (address + 4), &value_hi,
-                                                  32);
-                       if (ACPI_FAILURE(status)) {
-                               return (status);
-                       }
-               }
-
-               /* Set the return value only if status is AE_OK */
-
-               *return_value = (value_lo | ((u64)value_hi << 32));
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_IO,
-                         "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
-                         ACPI_FORMAT_UINT64(*return_value), reg->bit_width,
-                         ACPI_FORMAT_UINT64(address),
-                         acpi_ut_get_region_name(reg->space_id)));
-
-       return (AE_OK);
+       status = acpi_hw_read(return_value, reg);
+       return (status);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_read)
@@ -213,59 +149,11 @@ ACPI_EXPORT_SYMBOL(acpi_read)
  ******************************************************************************/
 acpi_status acpi_write(u64 value, struct acpi_generic_address *reg)
 {
-       u32 width;
-       u64 address;
        acpi_status status;
 
        ACPI_FUNCTION_NAME(acpi_write);
 
-       /* Validate contents of the GAS register. Allow 64-bit transfers */
-
-       status = acpi_hw_validate_register(reg, 64, &address);
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
-
-       /*
-        * Two address spaces supported: Memory or IO. PCI_Config is
-        * not supported here because the GAS structure is insufficient
-        */
-       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-               status = acpi_os_write_memory((acpi_physical_address)
-                                             address, value, reg->bit_width);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-       } else {                /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
-
-               width = reg->bit_width;
-               if (width == 64) {
-                       width = 32;     /* Break into two 32-bit transfers */
-               }
-
-               status = acpi_hw_write_port((acpi_io_address)
-                                           address, ACPI_LODWORD(value),
-                                           width);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-
-               if (reg->bit_width == 64) {
-                       status = acpi_hw_write_port((acpi_io_address)
-                                                   (address + 4),
-                                                   ACPI_HIDWORD(value), 32);
-                       if (ACPI_FAILURE(status)) {
-                               return (status);
-                       }
-               }
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_IO,
-                         "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
-                         ACPI_FORMAT_UINT64(value), reg->bit_width,
-                         ACPI_FORMAT_UINT64(address),
-                         acpi_ut_get_region_name(reg->space_id)));
-
+       status = acpi_hw_write(value, reg);
        return (status);
 }
 
index e4a7da8a11f0ac014cee2a8b3013f5d8e3bc9024..539d775bbc92344ae719e0e1da38dbed9580419a 100644 (file)
@@ -78,8 +78,8 @@ acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
 
                /* String-to-Integer conversion */
 
-               status = acpi_ut_strtoul64(original_object->string.pointer,
-                                          acpi_gbl_integer_byte_width, &value);
+               status =
+                   acpi_ut_strtoul64(original_object->string.pointer, &value);
                if (ACPI_FAILURE(status)) {
                        return (status);
                }
index 26ad596c973e9309d8fb961c26100eae2d650d1b..5ecb8d2e683479e3f0fe249f724818ee319991c5 100644 (file)
@@ -173,10 +173,13 @@ acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void)
        ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
 
        /*
-        * Only reallocate the root table if the host provided a static buffer
-        * for the table array in the call to acpi_initialize_tables.
+        * If there are tables unverified, it is required to reallocate the
+        * root table list to clean up invalid table entries. Otherwise only
+        * reallocate the root table list if the host provided a static buffer
+        * for the table array in the call to acpi_initialize_tables().
         */
-       if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+       if ((acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) &&
+           acpi_gbl_enable_table_validation) {
                return_ACPI_STATUS(AE_SUPPORT);
        }
 
diff --git a/drivers/acpi/acpica/utstrsuppt.c b/drivers/acpi/acpica/utstrsuppt.c
new file mode 100644 (file)
index 0000000..965fb5c
--- /dev/null
@@ -0,0 +1,438 @@
+/*******************************************************************************
+ *
+ * Module Name: utstrsuppt - Support functions for string-to-integer conversion
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2017, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utstrsuppt")
+
+/* Local prototypes */
+static acpi_status
+acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit);
+
+static acpi_status
+acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product);
+
+static acpi_status
+acpi_ut_strtoul_add64(u64 addend1, u64 addend2, u64 *out_sum);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_convert_octal_string
+ *
+ * PARAMETERS:  string                  - Null terminated input string
+ *              return_value_ptr        - Where the converted value is returned
+ *
+ * RETURN:      Status and 64-bit converted integer
+ *
+ * DESCRIPTION: Performs a base 8 conversion of the input string to an
+ *              integer value, either 32 or 64 bits.
+ *
+ * NOTE:        Maximum 64-bit unsigned octal value is 01777777777777777777777
+ *              Maximum 32-bit unsigned octal value is 037777777777
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_convert_octal_string(char *string, u64 *return_value_ptr)
+{
+       u64 accumulated_value = 0;
+       acpi_status status = AE_OK;
+
+       /* Convert each ASCII byte in the input string */
+
+       while (*string) {
+
+               /* Character must be ASCII 0-7, otherwise terminate with no error */
+
+               if (!(ACPI_IS_OCTAL_DIGIT(*string))) {
+                       break;
+               }
+
+               /* Convert and insert this octal digit into the accumulator */
+
+               status = acpi_ut_insert_digit(&accumulated_value, 8, *string);
+               if (ACPI_FAILURE(status)) {
+                       status = AE_OCTAL_OVERFLOW;
+                       break;
+               }
+
+               string++;
+       }
+
+       /* Always return the value that has been accumulated */
+
+       *return_value_ptr = accumulated_value;
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_convert_decimal_string
+ *
+ * PARAMETERS:  string                  - Null terminated input string
+ *              return_value_ptr        - Where the converted value is returned
+ *
+ * RETURN:      Status and 64-bit converted integer
+ *
+ * DESCRIPTION: Performs a base 10 conversion of the input string to an
+ *              integer value, either 32 or 64 bits.
+ *
+ * NOTE:        Maximum 64-bit unsigned decimal value is 18446744073709551615
+ *              Maximum 32-bit unsigned decimal value is 4294967295
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_convert_decimal_string(char *string, u64 *return_value_ptr)
+{
+       u64 accumulated_value = 0;
+       acpi_status status = AE_OK;
+
+       /* Convert each ASCII byte in the input string */
+
+       while (*string) {
+
+               /* Character must be ASCII 0-9, otherwise terminate with no error */
+
+               if (!isdigit(*string)) {
+                       break;
+               }
+
+               /* Convert and insert this decimal digit into the accumulator */
+
+               status = acpi_ut_insert_digit(&accumulated_value, 10, *string);
+               if (ACPI_FAILURE(status)) {
+                       status = AE_DECIMAL_OVERFLOW;
+                       break;
+               }
+
+               string++;
+       }
+
+       /* Always return the value that has been accumulated */
+
+       *return_value_ptr = accumulated_value;
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_convert_hex_string
+ *
+ * PARAMETERS:  string                  - Null terminated input string
+ *              return_value_ptr        - Where the converted value is returned
+ *
+ * RETURN:      Status and 64-bit converted integer
+ *
+ * DESCRIPTION: Performs a base 16 conversion of the input string to an
+ *              integer value, either 32 or 64 bits.
+ *
+ * NOTE:        Maximum 64-bit unsigned hex value is 0xFFFFFFFFFFFFFFFF
+ *              Maximum 32-bit unsigned hex value is 0xFFFFFFFF
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_convert_hex_string(char *string, u64 *return_value_ptr)
+{
+       u64 accumulated_value = 0;
+       acpi_status status = AE_OK;
+
+       /* Convert each ASCII byte in the input string */
+
+       while (*string) {
+
+               /* Must be ASCII A-F, a-f, or 0-9, otherwise terminate with no error */
+
+               if (!isxdigit(*string)) {
+                       break;
+               }
+
+               /* Convert and insert this hex digit into the accumulator */
+
+               status = acpi_ut_insert_digit(&accumulated_value, 16, *string);
+               if (ACPI_FAILURE(status)) {
+                       status = AE_HEX_OVERFLOW;
+                       break;
+               }
+
+               string++;
+       }
+
+       /* Always return the value that has been accumulated */
+
+       *return_value_ptr = accumulated_value;
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_remove_leading_zeros
+ *
+ * PARAMETERS:  string                  - Pointer to input ASCII string
+ *
+ * RETURN:      Next character after any leading zeros. This character may be
+ *              used by the caller to detect end-of-string.
+ *
+ * DESCRIPTION: Remove any leading zeros in the input string. Return the
+ *              next character after the final ASCII zero to enable the caller
+ *              to check for the end of the string (NULL terminator).
+ *
+ ******************************************************************************/
+
+char acpi_ut_remove_leading_zeros(char **string)
+{
+
+       while (**string == ACPI_ASCII_ZERO) {
+               *string += 1;
+       }
+
+       return (**string);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_remove_whitespace
+ *
+ * PARAMETERS:  string                  - Pointer to input ASCII string
+ *
+ * RETURN:      Next character after any whitespace. This character may be
+ *              used by the caller to detect end-of-string.
+ *
+ * DESCRIPTION: Remove any leading whitespace in the input string. Return the
+ *              next character after the final ASCII zero to enable the caller
+ *              to check for the end of the string (NULL terminator).
+ *
+ ******************************************************************************/
+
+char acpi_ut_remove_whitespace(char **string)
+{
+
+       while (isspace((u8)**string)) {
+               *string += 1;
+       }
+
+       return (**string);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_detect_hex_prefix
+ *
+ * PARAMETERS:  string                  - Pointer to input ASCII string
+ *
+ * RETURN:      TRUE if a "0x" prefix was found at the start of the string
+ *
+ * DESCRIPTION: Detect and remove a hex "0x" prefix
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_detect_hex_prefix(char **string)
+{
+
+       if ((**string == ACPI_ASCII_ZERO) &&
+           (tolower((int)*(*string + 1)) == 'x')) {
+               *string += 2;   /* Go past the leading 0x */
+               return (TRUE);
+       }
+
+       return (FALSE);         /* Not a hex string */
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_detect_octal_prefix
+ *
+ * PARAMETERS:  string                  - Pointer to input ASCII string
+ *
+ * RETURN:      True if an octal "0" prefix was found at the start of the
+ *              string
+ *
+ * DESCRIPTION: Detect and remove an octal prefix (zero)
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_detect_octal_prefix(char **string)
+{
+
+       if (**string == ACPI_ASCII_ZERO) {
+               *string += 1;   /* Go past the leading 0 */
+               return (TRUE);
+       }
+
+       return (FALSE);         /* Not an octal string */
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_insert_digit
+ *
+ * PARAMETERS:  accumulated_value       - Current value of the integer value
+ *                                        accumulator. The new value is
+ *                                        returned here.
+ *              base                    - Radix, either 8/10/16
+ *              ascii_digit             - ASCII single digit to be inserted
+ *
+ * RETURN:      Status and result of the convert/insert operation. The only
+ *              possible returned exception code is numeric overflow of
+ *              either the multiply or add conversion operations.
+ *
+ * DESCRIPTION: Generic conversion and insertion function for all bases:
+ *
+ *              1) Multiply the current accumulated/converted value by the
+ *              base in order to make room for the new character.
+ *
+ *              2) Convert the new character to binary and add it to the
+ *              current accumulated value.
+ *
+ *              Note: The only possible exception indicates an integer
+ *              overflow (AE_NUMERIC_OVERFLOW)
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit)
+{
+       acpi_status status;
+       u64 product;
+
+       /* Make room in the accumulated value for the incoming digit */
+
+       status = acpi_ut_strtoul_multiply64(*accumulated_value, base, &product);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Add in the new digit, and store the sum to the accumulated value */
+
+       status =
+           acpi_ut_strtoul_add64(product,
+                                 acpi_ut_ascii_char_to_hex(ascii_digit),
+                                 accumulated_value);
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_strtoul_multiply64
+ *
+ * PARAMETERS:  multiplicand            - Current accumulated converted integer
+ *              multiplier              - Base/Radix
+ *              out_product             - Where the product is returned
+ *
+ * RETURN:      Status and 64-bit product
+ *
+ * DESCRIPTION: Multiply two 64-bit values, with checking for 64-bit overflow as
+ *              well as 32-bit overflow if necessary (if the current global
+ *              integer width is 32).
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product)
+{
+       u64 val;
+
+       /* Exit if either operand is zero */
+
+       *out_product = 0;
+       if (!multiplicand || !multiplier) {
+               return (AE_OK);
+       }
+
+       /* Check for 64-bit overflow before the actual multiplication */
+
+       acpi_ut_short_divide(ACPI_UINT64_MAX, (u32)multiplier, &val, NULL);
+       if (multiplicand > val) {
+               return (AE_NUMERIC_OVERFLOW);
+       }
+
+       val = multiplicand * multiplier;
+
+       /* Check for 32-bit overflow if necessary */
+
+       if ((acpi_gbl_integer_bit_width == 32) && (val > ACPI_UINT32_MAX)) {
+               return (AE_NUMERIC_OVERFLOW);
+       }
+
+       *out_product = val;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_strtoul_add64
+ *
+ * PARAMETERS:  addend1                 - Current accumulated converted integer
+ *              addend2                 - New hex value/char
+ *              out_sum                 - Where sum is returned (Accumulator)
+ *
+ * RETURN:      Status and 64-bit sum
+ *
+ * DESCRIPTION: Add two 64-bit values, with checking for 64-bit overflow as
+ *              well as 32-bit overflow if necessary (if the current global
+ *              integer width is 32).
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ut_strtoul_add64(u64 addend1, u64 addend2, u64 *out_sum)
+{
+       u64 sum;
+
+       /* Check for 64-bit overflow before the actual addition */
+
+       if ((addend1 > 0) && (addend2 > (ACPI_UINT64_MAX - addend1))) {
+               return (AE_NUMERIC_OVERFLOW);
+       }
+
+       sum = addend1 + addend2;
+
+       /* Check for 32-bit overflow if necessary */
+
+       if ((acpi_gbl_integer_bit_width == 32) && (sum > ACPI_UINT32_MAX)) {
+               return (AE_NUMERIC_OVERFLOW);
+       }
+
+       *out_sum = sum;
+       return (AE_OK);
+}
index 9633ee142855b879feea438f62b6c80ad32b18c1..e2067dcb93893cde975502c952991fca76115266 100644 (file)
@@ -1,6 +1,7 @@
 /*******************************************************************************
  *
- * Module Name: utstrtoul64 - string to 64-bit integer support
+ * Module Name: utstrtoul64 - String-to-integer conversion support for both
+ *                            64-bit and 32-bit integers
  *
  ******************************************************************************/
 
 #include <acpi/acpi.h>
 #include "accommon.h"
 
-/*******************************************************************************
- *
- * The functions in this module satisfy the need for 64-bit string-to-integer
- * conversions on both 32-bit and 64-bit platforms.
- *
- ******************************************************************************/
-
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utstrtoul64")
 
-/* Local prototypes */
-static u64 acpi_ut_strtoul_base10(char *string, u32 flags);
-
-static u64 acpi_ut_strtoul_base16(char *string, u32 flags);
-
 /*******************************************************************************
  *
- * String conversion rules as written in the ACPI specification. The error
- * conditions and behavior are different depending on the type of conversion.
- *
- *
- * Implicit data type conversion: string-to-integer
- * --------------------------------------------------
- *
- * Base is always 16. This is the ACPI_STRTOUL_BASE16 case.
- *
- * Example:
- *      Add ("BA98", Arg0, Local0)
- *
- * The integer is initialized to the value zero.
- * The ASCII string is interpreted as a hexadecimal constant.
+ * This module contains the top-level string to 64/32-bit unsigned integer
+ * conversion functions:
  *
- *  1)  A "0x" prefix is not allowed. However, ACPICA allows this for
- *      compatibility with previous ACPICA. (NO ERROR)
+ *  1) A standard strtoul() function that supports 64-bit integers, base
+ *     8/10/16, with integer overflow support. This is used mainly by the
+ *     iASL compiler, which implements tighter constraints on integer
+ *     constants than the runtime (interpreter) integer-to-string conversions.
+ *  2) Runtime "Explicit conversion" as defined in the ACPI specification.
+ *  3) Runtime "Implicit conversion" as defined in the ACPI specification.
  *
- *  2)  Terminates when the size of an integer is reached (32 or 64 bits).
- *      (NO ERROR)
+ * Current users of this module:
  *
- *  3)  The first non-hex character terminates the conversion without error.
- *      (NO ERROR)
- *
- *  4)  Conversion of a null (zero-length) string to an integer is not
- *      allowed. However, ACPICA allows this for compatibility with previous
- *      ACPICA. This conversion returns the value 0. (NO ERROR)
- *
- *
- * Explicit data type conversion:  to_integer() with string operand
- * ---------------------------------------------------------------
- *
- * Base is either 10 (default) or 16 (with 0x prefix)
- *
- * Examples:
- *      to_integer ("1000")
- *      to_integer ("0xABCD")
- *
- *  1)  Can be (must be) either a decimal or hexadecimal numeric string.
- *      A hex value must be prefixed by "0x" or it is interpreted as a decimal.
+ *  iASL        - Preprocessor (constants and math expressions)
+ *  iASL        - Main parser, conversion of constants to integers
+ *  iASL        - Data Table Compiler parser (constants and math expressions)
+ *  interpreter - Implicit and explicit conversions, GPE method names
+ *  interpreter - Repair code for return values from predefined names
+ *  debugger    - Command line input string conversion
+ *  acpi_dump   - ACPI table physical addresses
+ *  acpi_exec   - Support for namespace overrides
  *
- *  2)  The value must not exceed the maximum of an integer value. ACPI spec
- *      states the behavior is "unpredictable", so ACPICA matches the behavior
- *      of the implicit conversion case.(NO ERROR)
+ * Notes concerning users of these interfaces:
  *
- *  3)  Behavior on the first non-hex character is not specified by the ACPI
- *      spec, so ACPICA matches the behavior of the implicit conversion case
- *      and terminates. (NO ERROR)
+ * acpi_gbl_integer_byte_width is used to set the 32/64 bit limit for explicit
+ * and implicit conversions. This global must be set to the proper width.
+ * For the core ACPICA code, the width depends on the DSDT version. For the
+ * acpi_ut_strtoul64 interface, all conversions are 64 bits. This interface is
+ * used primarily for iASL, where the default width is 64 bits for all parsers,
+ * but error checking is performed later to flag cases where a 64-bit constant
+ * is wrongly defined in a 32-bit DSDT/SSDT.
  *
- *  4)  A null (zero-length) string is illegal.
- *      However, ACPICA allows this for compatibility with previous ACPICA.
- *      This conversion returns the value 0. (NO ERROR)
+ * In ACPI, the only place where octal numbers are supported is within
+ * the ASL language itself. This is implemented via the main acpi_ut_strtoul64
+ * interface. According the ACPI specification, there is no ACPI runtime
+ * support (explicit/implicit) for octal string conversions.
  *
  ******************************************************************************/
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_strtoul64
  *
- * PARAMETERS:  string                  - Null terminated input string
- *              flags                   - Conversion info, see below
+ * PARAMETERS:  string                  - Null terminated input string,
+ *                                        must be a valid pointer
  *              return_value            - Where the converted integer is
- *                                        returned
- *
- * RETURN:      Status and Converted value
+ *                                        returned. Must be a valid pointer
  *
- * DESCRIPTION: Convert a string into an unsigned value. Performs either a
- *              32-bit or 64-bit conversion, depending on the input integer
- *              size in Flags (often the current mode of the interpreter).
+ * RETURN:      Status and converted integer. Returns an exception on a
+ *              64-bit numeric overflow
  *
- * Values for Flags:
- *      ACPI_STRTOUL_32BIT      - Max integer value is 32 bits
- *      ACPI_STRTOUL_64BIT      - Max integer value is 64 bits
- *      ACPI_STRTOUL_BASE16     - Input string is hexadecimal. Default
- *                                is 10/16 based on string prefix (0x).
+ * DESCRIPTION: Convert a string into an unsigned integer. Always performs a
+ *              full 64-bit conversion, regardless of the current global
+ *              integer width. Supports Decimal, Hex, and Octal strings.
  *
- * NOTES:
- *   Negative numbers are not supported, as they are not supported by ACPI.
+ * Current users of this function:
  *
- *   Supports only base 16 or base 10 strings/values. Does not
- *   support Octal strings, as these are not supported by ACPI.
- *
- * Current users of this support:
- *
- *  interpreter - Implicit and explicit conversions, GPE method names
- *  debugger    - Command line input string conversion
- *  iASL        - Main parser, conversion of constants to integers
- *  iASL        - Data Table Compiler parser (constant math expressions)
- *  iASL        - Preprocessor (constant math expressions)
- *  acpi_dump   - Input table addresses
- *  acpi_exec   - Testing of the acpi_ut_strtoul64 function
- *
- * Note concerning callers:
- *   acpi_gbl_integer_byte_width can be used to set the 32/64 limit. If used,
- *   this global should be set to the proper width. For the core ACPICA code,
- *   this width depends on the DSDT version. For iASL, the default byte
- *   width is always 8 for the parser, but error checking is performed later
- *   to flag cases where a 64-bit constant is defined in a 32-bit DSDT/SSDT.
+ *  iASL        - Preprocessor (constants and math expressions)
+ *  iASL        - Main ASL parser, conversion of ASL constants to integers
+ *  iASL        - Data Table Compiler parser (constants and math expressions)
+ *  interpreter - Repair code for return values from predefined names
+ *  acpi_dump   - ACPI table physical addresses
+ *  acpi_exec   - Support for namespace overrides
  *
  ******************************************************************************/
-
-acpi_status acpi_ut_strtoul64(char *string, u32 flags, u64 *return_value)
+acpi_status acpi_ut_strtoul64(char *string, u64 *return_value)
 {
        acpi_status status = AE_OK;
-       u32 base;
+       u8 original_bit_width;
+       u32 base = 10;          /* Default is decimal */
 
        ACPI_FUNCTION_TRACE_STR(ut_strtoul64, string);
 
-       /* Parameter validation */
-
-       if (!string || !return_value) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
        *return_value = 0;
 
-       /* Check for zero-length string, returns 0 */
+       /* A NULL return string returns a value of zero */
 
        if (*string == 0) {
                return_ACPI_STATUS(AE_OK);
        }
 
-       /* Skip over any white space at start of string */
-
-       while (isspace((int)*string)) {
-               string++;
-       }
-
-       /* End of string? return 0 */
-
-       if (*string == 0) {
+       if (!acpi_ut_remove_whitespace(&string)) {
                return_ACPI_STATUS(AE_OK);
        }
 
        /*
-        * 1) The "0x" prefix indicates base 16. Per the ACPI specification,
-        * the "0x" prefix is only allowed for implicit (non-strict) conversions.
-        * However, we always allow it for compatibility with older ACPICA.
+        * 1) Check for a hex constant. A "0x" prefix indicates base 16.
         */
-       if ((*string == ACPI_ASCII_ZERO) &&
-           (tolower((int)*(string + 1)) == 'x')) {
-               string += 2;    /* Go past the 0x */
-               if (*string == 0) {
-                       return_ACPI_STATUS(AE_OK);      /* Return value 0 */
-               }
-
+       if (acpi_ut_detect_hex_prefix(&string)) {
                base = 16;
        }
 
-       /* 2) Force to base 16 (implicit conversion case) */
-
-       else if (flags & ACPI_STRTOUL_BASE16) {
-               base = 16;
+       /*
+        * 2) Check for an octal constant, defined to be a leading zero
+        * followed by sequence of octal digits (0-7)
+        */
+       else if (acpi_ut_detect_octal_prefix(&string)) {
+               base = 8;
        }
 
-       /* 3) Default fallback is to Base 10 */
-
-       else {
-               base = 10;
+       if (!acpi_ut_remove_leading_zeros(&string)) {
+               return_ACPI_STATUS(AE_OK);      /* Return value 0 */
        }
 
-       /* Skip all leading zeros */
+       /*
+        * Force a full 64-bit conversion. The caller (usually iASL) must
+        * check for a 32-bit overflow later as necessary (If current mode
+        * is 32-bit, meaning a 32-bit DSDT).
+        */
+       original_bit_width = acpi_gbl_integer_bit_width;
+       acpi_gbl_integer_bit_width = 64;
 
-       while (*string == ACPI_ASCII_ZERO) {
-               string++;
-               if (*string == 0) {
-                       return_ACPI_STATUS(AE_OK);      /* Return value 0 */
-               }
+       /*
+        * Perform the base 8, 10, or 16 conversion. A 64-bit numeric overflow
+        * will return an exception (to allow iASL to flag the statement).
+        */
+       switch (base) {
+       case 8:
+               status = acpi_ut_convert_octal_string(string, return_value);
+               break;
+
+       case 10:
+               status = acpi_ut_convert_decimal_string(string, return_value);
+               break;
+
+       case 16:
+       default:
+               status = acpi_ut_convert_hex_string(string, return_value);
+               break;
        }
 
-       /* Perform the base 16 or 10 conversion */
-
-       if (base == 16) {
-               *return_value = acpi_ut_strtoul_base16(string, flags);
-       } else {
-               *return_value = acpi_ut_strtoul_base10(string, flags);
-       }
+       /* Only possible exception from above is a 64-bit overflow */
 
+       acpi_gbl_integer_bit_width = original_bit_width;
        return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ut_strtoul_base10
+ * FUNCTION:    acpi_ut_implicit_strtoul64
+ *
+ * PARAMETERS:  string                  - Null terminated input string,
+ *                                        must be a valid pointer
+ *
+ * RETURN:      Converted integer
+ *
+ * DESCRIPTION: Perform a 64-bit conversion with restrictions placed upon
+ *              an "implicit conversion" by the ACPI specification. Used by
+ *              many ASL operators that require an integer operand, and support
+ *              an automatic (implicit) conversion from a string operand
+ *              to the final integer operand. The major restriction is that
+ *              only hex strings are supported.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Base is always 16, either with or without the 0x prefix. Decimal and
+ * Octal strings are not supported, as per the ACPI specification.
+ *
+ * Examples (both are hex values):
+ *      Add ("BA98", Arg0, Local0)
+ *      Subtract ("0x12345678", Arg1, Local1)
+ *
+ * Conversion rules as extracted from the ACPI specification:
+ *
+ *  The converted integer is initialized to the value zero.
+ *  The ASCII string is always interpreted as a hexadecimal constant.
+ *
+ *  1)  According to the ACPI specification, a "0x" prefix is not allowed.
+ *      However, ACPICA allows this as an ACPI extension on general
+ *      principle. (NO ERROR)
+ *
+ *  2)  The conversion terminates when the size of an integer is reached
+ *      (32 or 64 bits). There are no numeric overflow conditions. (NO ERROR)
+ *
+ *  3)  The first non-hex character terminates the conversion and returns
+ *      the current accumulated value of the converted integer (NO ERROR).
  *
- * PARAMETERS:  string                  - Null terminated input string
- *              flags                   - Conversion info
+ *  4)  Conversion of a null (zero-length) string to an integer is
+ *      technically not allowed. However, ACPICA allows this as an ACPI
+ *      extension. The conversion returns the value 0. (NO ERROR)
  *
- * RETURN:      64-bit converted integer
+ * NOTE: There are no error conditions returned by this function. At
+ * the minimum, a value of zero is returned.
  *
- * DESCRIPTION: Performs a base 10 conversion of the input string to an
- *              integer value, either 32 or 64 bits.
- *              Note: String must be valid and non-null.
+ * Current users of this function:
+ *
+ *  interpreter - All runtime implicit conversions, as per ACPI specification
+ *  iASL        - Data Table Compiler parser (constants and math expressions)
  *
  ******************************************************************************/
 
-static u64 acpi_ut_strtoul_base10(char *string, u32 flags)
+u64 acpi_ut_implicit_strtoul64(char *string)
 {
-       int ascii_digit;
-       u64 next_value;
-       u64 return_value = 0;
-
-       /* Main loop: convert each ASCII byte in the input string */
-
-       while (*string) {
-               ascii_digit = *string;
-               if (!isdigit(ascii_digit)) {
-
-                       /* Not ASCII 0-9, terminate */
-
-                       goto exit;
-               }
-
-               /* Convert and insert (add) the decimal digit */
+       u64 converted_integer = 0;
 
-               acpi_ut_short_multiply(return_value, 10, &next_value);
-               next_value += (ascii_digit - ACPI_ASCII_ZERO);
+       ACPI_FUNCTION_TRACE_STR(ut_implicit_strtoul64, string);
 
-               /* Check for overflow (32 or 64 bit) - return current converted value */
+       if (!acpi_ut_remove_whitespace(&string)) {
+               return_VALUE(0);
+       }
 
-               if (((flags & ACPI_STRTOUL_32BIT) && (next_value > ACPI_UINT32_MAX)) || (next_value < return_value)) {  /* 64-bit overflow case */
-                       goto exit;
-               }
+       /*
+        * Per the ACPI specification, only hexadecimal is supported for
+        * implicit conversions, and the "0x" prefix is "not allowed".
+        * However, allow a "0x" prefix as an ACPI extension.
+        */
+       acpi_ut_detect_hex_prefix(&string);
 
-               return_value = next_value;
-               string++;
+       if (!acpi_ut_remove_leading_zeros(&string)) {
+               return_VALUE(0);
        }
 
-exit:
-       return (return_value);
+       /*
+        * Ignore overflow as per the ACPI specification. This is implemented by
+        * ignoring the return status from the conversion function called below.
+        * On overflow, the input string is simply truncated.
+        */
+       acpi_ut_convert_hex_string(string, &converted_integer);
+       return_VALUE(converted_integer);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ut_strtoul_base16
+ * FUNCTION:    acpi_ut_explicit_strtoul64
+ *
+ * PARAMETERS:  string                  - Null terminated input string,
+ *                                        must be a valid pointer
  *
- * PARAMETERS:  string                  - Null terminated input string
- *              flags                   - conversion info
+ * RETURN:      Converted integer
  *
- * RETURN:      64-bit converted integer
+ * DESCRIPTION: Perform a 64-bit conversion with the restrictions placed upon
+ *              an "explicit conversion" by the ACPI specification. The
+ *              main restriction is that only hex and decimal are supported.
  *
- * DESCRIPTION: Performs a base 16 conversion of the input string to an
- *              integer value, either 32 or 64 bits.
- *              Note: String must be valid and non-null.
+ * -----------------------------------------------------------------------------
+ *
+ * Base is either 10 (default) or 16 (with 0x prefix). Octal (base 8) strings
+ * are not supported, as per the ACPI specification.
+ *
+ * Examples:
+ *      to_integer ("1000")     Decimal
+ *      to_integer ("0xABCD")   Hex
+ *
+ * Conversion rules as extracted from the ACPI specification:
+ *
+ *  1)  The input string is either a decimal or hexadecimal numeric string.
+ *      A hex value must be prefixed by "0x" or it is interpreted as decimal.
+ *
+ *  2)  The value must not exceed the maximum of an integer value
+ *      (32 or 64 bits). The ACPI specification states the behavior is
+ *      "unpredictable", so ACPICA matches the behavior of the implicit
+ *      conversion case. There are no numeric overflow conditions. (NO ERROR)
+ *
+ *  3)  Behavior on the first non-hex character is not defined by the ACPI
+ *      specification (for the to_integer operator), so ACPICA matches the
+ *      behavior of the implicit conversion case. It terminates the
+ *      conversion and returns the current accumulated value of the converted
+ *      integer. (NO ERROR)
+ *
+ *  4)  Conversion of a null (zero-length) string to an integer is
+ *      technically not allowed. However, ACPICA allows this as an ACPI
+ *      extension. The conversion returns the value 0. (NO ERROR)
+ *
+ * NOTE: There are no error conditions returned by this function. At the
+ * minimum, a value of zero is returned.
+ *
+ * Current users of this function:
+ *
+ *  interpreter - Runtime ASL to_integer operator, as per the ACPI specification
  *
  ******************************************************************************/
 
-static u64 acpi_ut_strtoul_base16(char *string, u32 flags)
+u64 acpi_ut_explicit_strtoul64(char *string)
 {
-       int ascii_digit;
-       u32 valid_digits = 1;
-       u64 return_value = 0;
-
-       /* Main loop: convert each ASCII byte in the input string */
+       u64 converted_integer = 0;
+       u32 base = 10;          /* Default is decimal */
 
-       while (*string) {
+       ACPI_FUNCTION_TRACE_STR(ut_explicit_strtoul64, string);
 
-               /* Check for overflow (32 or 64 bit) - return current converted value */
-
-               if ((valid_digits > 16) ||
-                   ((valid_digits > 8) && (flags & ACPI_STRTOUL_32BIT))) {
-                       goto exit;
-               }
-
-               ascii_digit = *string;
-               if (!isxdigit(ascii_digit)) {
-
-                       /* Not Hex ASCII A-F, a-f, or 0-9, terminate */
-
-                       goto exit;
-               }
+       if (!acpi_ut_remove_whitespace(&string)) {
+               return_VALUE(0);
+       }
 
-               /* Convert and insert the hex digit */
+       /*
+        * Only Hex and Decimal are supported, as per the ACPI specification.
+        * A "0x" prefix indicates hex; otherwise decimal is assumed.
+        */
+       if (acpi_ut_detect_hex_prefix(&string)) {
+               base = 16;
+       }
 
-               acpi_ut_short_shift_left(return_value, 4, &return_value);
-               return_value |= acpi_ut_ascii_char_to_hex(ascii_digit);
+       if (!acpi_ut_remove_leading_zeros(&string)) {
+               return_VALUE(0);
+       }
 
-               string++;
-               valid_digits++;
+       /*
+        * Ignore overflow as per the ACPI specification. This is implemented by
+        * ignoring the return status from the conversion functions called below.
+        * On overflow, the input string is simply truncated.
+        */
+       switch (base) {
+       case 10:
+       default:
+               acpi_ut_convert_decimal_string(string, &converted_integer);
+               break;
+
+       case 16:
+               acpi_ut_convert_hex_string(string, &converted_integer);
+               break;
        }
 
-exit:
-       return (return_value);
+       return_VALUE(converted_integer);
 }
index 2c462beee5513ec40448f6faf0179e621644558f..6742f6c68034c5e833505d294902dd97c274c1b0 100644 (file)
@@ -1061,7 +1061,7 @@ static int erst_writer(struct pstore_record *record)
        rcd->hdr.error_severity = CPER_SEV_FATAL;
        /* timestamp valid. platform_id, partition_id are invalid */
        rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP;
-       rcd->hdr.timestamp = get_seconds();
+       rcd->hdr.timestamp = ktime_get_real_seconds();
        rcd->hdr.record_length = sizeof(*rcd) + record->size;
        rcd->hdr.creator_id = CPER_CREATOR_PSTORE;
        rcd->hdr.notification_type = CPER_NOTIFY_MCE;
index 3c3a37b8503bd43db4200230309ddeff96eb4e00..6402f7fad3bb3bf1cfb28384a4d843f0bd0b5bc8 100644 (file)
@@ -51,6 +51,7 @@
 #include <acpi/actbl1.h>
 #include <acpi/ghes.h>
 #include <acpi/apei.h>
+#include <asm/fixmap.h>
 #include <asm/tlbflush.h>
 #include <ras/ras_event.h>
 
@@ -112,22 +113,10 @@ static DEFINE_MUTEX(ghes_list_mutex);
  * Because the memory area used to transfer hardware error information
  * from BIOS to Linux can be determined only in NMI, IRQ or timer
  * handler, but general ioremap can not be used in atomic context, so
- * a special version of atomic ioremap is implemented for that.
- */
-
-/*
- * Two virtual pages are used, one for IRQ/PROCESS context, the other for
- * NMI context (optionally).
- */
-#define GHES_IOREMAP_PAGES           2
-#define GHES_IOREMAP_IRQ_PAGE(base)    (base)
-#define GHES_IOREMAP_NMI_PAGE(base)    ((base) + PAGE_SIZE)
-
-/* virtual memory area for atomic ioremap */
-static struct vm_struct *ghes_ioremap_area;
-/*
- * These 2 spinlock is used to prevent atomic ioremap virtual memory
- * area from being mapped simultaneously.
+ * the fixmap is used instead.
+ *
+ * These 2 spinlocks are used to prevent the fixmap entries from being used
+ * simultaneously.
  */
 static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
 static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
@@ -140,71 +129,38 @@ static atomic_t ghes_estatus_cache_alloced;
 
 static int ghes_panic_timeout __read_mostly = 30;
 
-static int ghes_ioremap_init(void)
-{
-       ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
-               VM_IOREMAP, VMALLOC_START, VMALLOC_END);
-       if (!ghes_ioremap_area) {
-               pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void ghes_ioremap_exit(void)
-{
-       free_vm_area(ghes_ioremap_area);
-}
-
 static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
 {
-       unsigned long vaddr;
        phys_addr_t paddr;
        pgprot_t prot;
 
-       vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
-
        paddr = pfn << PAGE_SHIFT;
        prot = arch_apei_get_mem_attribute(paddr);
-       ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
+       __set_fixmap(FIX_APEI_GHES_NMI, paddr, prot);
 
-       return (void __iomem *)vaddr;
+       return (void __iomem *) fix_to_virt(FIX_APEI_GHES_NMI);
 }
 
 static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
 {
-       unsigned long vaddr, paddr;
+       phys_addr_t paddr;
        pgprot_t prot;
 
-       vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
-
        paddr = pfn << PAGE_SHIFT;
        prot = arch_apei_get_mem_attribute(paddr);
+       __set_fixmap(FIX_APEI_GHES_IRQ, paddr, prot);
 
-       ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
-
-       return (void __iomem *)vaddr;
+       return (void __iomem *) fix_to_virt(FIX_APEI_GHES_IRQ);
 }
 
-static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
+static void ghes_iounmap_nmi(void)
 {
-       unsigned long vaddr = (unsigned long __force)vaddr_ptr;
-       void *base = ghes_ioremap_area->addr;
-
-       BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
-       unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
-       arch_apei_flush_tlb_one(vaddr);
+       clear_fixmap(FIX_APEI_GHES_NMI);
 }
 
-static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
+static void ghes_iounmap_irq(void)
 {
-       unsigned long vaddr = (unsigned long __force)vaddr_ptr;
-       void *base = ghes_ioremap_area->addr;
-
-       BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
-       unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
-       arch_apei_flush_tlb_one(vaddr);
+       clear_fixmap(FIX_APEI_GHES_IRQ);
 }
 
 static int ghes_estatus_pool_init(void)
@@ -360,10 +316,10 @@ static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
                paddr += trunk;
                buffer += trunk;
                if (in_nmi) {
-                       ghes_iounmap_nmi(vaddr);
+                       ghes_iounmap_nmi();
                        raw_spin_unlock(&ghes_ioremap_lock_nmi);
                } else {
-                       ghes_iounmap_irq(vaddr);
+                       ghes_iounmap_irq();
                        spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
                }
        }
@@ -774,9 +730,9 @@ static void ghes_add_timer(struct ghes *ghes)
        add_timer(&ghes->timer);
 }
 
-static void ghes_poll_func(unsigned long data)
+static void ghes_poll_func(struct timer_list *t)
 {
-       struct ghes *ghes = (void *)data;
+       struct ghes *ghes = from_timer(ghes, t, timer);
 
        ghes_proc(ghes);
        if (!(ghes->flags & GHES_EXITING))
@@ -851,17 +807,8 @@ static void ghes_sea_remove(struct ghes *ghes)
        synchronize_rcu();
 }
 #else /* CONFIG_ACPI_APEI_SEA */
-static inline void ghes_sea_add(struct ghes *ghes)
-{
-       pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n",
-              ghes->generic->header.source_id);
-}
-
-static inline void ghes_sea_remove(struct ghes *ghes)
-{
-       pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n",
-              ghes->generic->header.source_id);
-}
+static inline void ghes_sea_add(struct ghes *ghes) { }
+static inline void ghes_sea_remove(struct ghes *ghes) { }
 #endif /* CONFIG_ACPI_APEI_SEA */
 
 #ifdef CONFIG_HAVE_ACPI_APEI_NMI
@@ -1063,23 +1010,9 @@ static void ghes_nmi_init_cxt(void)
        init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq);
 }
 #else /* CONFIG_HAVE_ACPI_APEI_NMI */
-static inline void ghes_nmi_add(struct ghes *ghes)
-{
-       pr_err(GHES_PFX "ID: %d, trying to add NMI notification which is not supported!\n",
-              ghes->generic->header.source_id);
-       BUG();
-}
-
-static inline void ghes_nmi_remove(struct ghes *ghes)
-{
-       pr_err(GHES_PFX "ID: %d, trying to remove NMI notification which is not supported!\n",
-              ghes->generic->header.source_id);
-       BUG();
-}
-
-static inline void ghes_nmi_init_cxt(void)
-{
-}
+static inline void ghes_nmi_add(struct ghes *ghes) { }
+static inline void ghes_nmi_remove(struct ghes *ghes) { }
+static inline void ghes_nmi_init_cxt(void) { }
 #endif /* CONFIG_HAVE_ACPI_APEI_NMI */
 
 static int ghes_probe(struct platform_device *ghes_dev)
@@ -1147,8 +1080,7 @@ static int ghes_probe(struct platform_device *ghes_dev)
 
        switch (generic->notify.type) {
        case ACPI_HEST_NOTIFY_POLLED:
-               setup_deferrable_timer(&ghes->timer, ghes_poll_func,
-                                      (unsigned long)ghes);
+               timer_setup(&ghes->timer, ghes_poll_func, TIMER_DEFERRABLE);
                ghes_add_timer(ghes);
                break;
        case ACPI_HEST_NOTIFY_EXTERNAL:
@@ -1285,13 +1217,9 @@ static int __init ghes_init(void)
 
        ghes_nmi_init_cxt();
 
-       rc = ghes_ioremap_init();
-       if (rc)
-               goto err;
-
        rc = ghes_estatus_pool_init();
        if (rc)
-               goto err_ioremap_exit;
+               goto err;
 
        rc = ghes_estatus_pool_expand(GHES_ESTATUS_CACHE_AVG_SIZE *
                                      GHES_ESTATUS_CACHE_ALLOCED_MAX);
@@ -1315,8 +1243,6 @@ static int __init ghes_init(void)
        return 0;
 err_pool_exit:
        ghes_estatus_pool_exit();
-err_ioremap_exit:
-       ghes_ioremap_exit();
 err:
        return rc;
 }
index ef1856b15488be10cf81f8abfa20c630f461768d..c391898b483c84067aadc35f8f36fd932d674fb9 100644 (file)
@@ -390,6 +390,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
 {
        struct acpi_button *button = acpi_driver_data(device);
        struct input_dev *input;
+       int users;
 
        switch (event) {
        case ACPI_FIXED_HARDWARE_EVENT:
@@ -398,7 +399,11 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
        case ACPI_BUTTON_NOTIFY_STATUS:
                input = button->input;
                if (button->type == ACPI_BUTTON_TYPE_LID) {
-                       acpi_lid_update_state(device);
+                       mutex_lock(&button->input->mutex);
+                       users = button->input->users;
+                       mutex_unlock(&button->input->mutex);
+                       if (users)
+                               acpi_lid_update_state(device);
                } else {
                        int keycode;
 
@@ -442,12 +447,24 @@ static int acpi_button_resume(struct device *dev)
        struct acpi_button *button = acpi_driver_data(device);
 
        button->suspended = false;
-       if (button->type == ACPI_BUTTON_TYPE_LID)
+       if (button->type == ACPI_BUTTON_TYPE_LID && button->input->users)
                acpi_lid_initialize_state(device);
        return 0;
 }
 #endif
 
+static int acpi_lid_input_open(struct input_dev *input)
+{
+       struct acpi_device *device = input_get_drvdata(input);
+       struct acpi_button *button = acpi_driver_data(device);
+
+       button->last_state = !!acpi_lid_evaluate_state(device);
+       button->last_time = ktime_get();
+       acpi_lid_initialize_state(device);
+
+       return 0;
+}
+
 static int acpi_button_add(struct acpi_device *device)
 {
        struct acpi_button *button;
@@ -488,8 +505,7 @@ static int acpi_button_add(struct acpi_device *device)
                strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
                sprintf(class, "%s/%s",
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
-               button->last_state = !!acpi_lid_evaluate_state(device);
-               button->last_time = ktime_get();
+               input->open = acpi_lid_input_open;
        } else {
                printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
                error = -ENODEV;
@@ -522,11 +538,11 @@ static int acpi_button_add(struct acpi_device *device)
                break;
        }
 
+       input_set_drvdata(input, device);
        error = input_register_device(input);
        if (error)
                goto err_remove_fs;
        if (button->type == ACPI_BUTTON_TYPE_LID) {
-               acpi_lid_initialize_state(device);
                /*
                 * This assumes there's only one lid device, or if there are
                 * more we only care about the last one...
index e5b47f032d9af552a04dc9aee301a8160f942997..21c28433c590a4aec323bdcea19a0e1426c751e4 100644 (file)
@@ -48,7 +48,6 @@
 struct cppc_pcc_data {
        struct mbox_chan *pcc_channel;
        void __iomem *pcc_comm_addr;
-       int pcc_subspace_idx;
        bool pcc_channel_acquired;
        ktime_t deadline;
        unsigned int pcc_mpar, pcc_mrtt, pcc_nominal;
@@ -75,13 +74,16 @@ struct cppc_pcc_data {
 
        /* Wait queue for CPUs whose requests were batched */
        wait_queue_head_t pcc_write_wait_q;
+       ktime_t last_cmd_cmpl_time;
+       ktime_t last_mpar_reset;
+       int mpar_count;
+       int refcount;
 };
 
-/* Structure to represent the single PCC channel */
-static struct cppc_pcc_data pcc_data = {
-       .pcc_subspace_idx = -1,
-       .platform_owns_pcc = true,
-};
+/* Array  to represent the PCC channel per subspace id */
+static struct cppc_pcc_data *pcc_data[MAX_PCC_SUBSPACES];
+/* The cpu_pcc_subspace_idx containsper CPU subspace id */
+static DEFINE_PER_CPU(int, cpu_pcc_subspace_idx);
 
 /*
  * The cpc_desc structure contains the ACPI register details
@@ -93,7 +95,8 @@ static struct cppc_pcc_data pcc_data = {
 static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
 
 /* pcc mapped address + header size + offset within PCC subspace */
-#define GET_PCC_VADDR(offs) (pcc_data.pcc_comm_addr + 0x8 + (offs))
+#define GET_PCC_VADDR(offs, pcc_ss_id) (pcc_data[pcc_ss_id]->pcc_comm_addr + \
+                                               0x8 + (offs))
 
 /* Check if a CPC register is in PCC */
 #define CPC_IN_PCC(cpc) ((cpc)->type == ACPI_TYPE_BUFFER &&            \
@@ -188,13 +191,16 @@ static struct kobj_type cppc_ktype = {
        .default_attrs = cppc_attrs,
 };
 
-static int check_pcc_chan(bool chk_err_bit)
+static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit)
 {
        int ret = -EIO, status = 0;
-       struct acpi_pcct_shared_memory __iomem *generic_comm_base = pcc_data.pcc_comm_addr;
-       ktime_t next_deadline = ktime_add(ktime_get(), pcc_data.deadline);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
+       struct acpi_pcct_shared_memory __iomem *generic_comm_base =
+               pcc_ss_data->pcc_comm_addr;
+       ktime_t next_deadline = ktime_add(ktime_get(),
+                                         pcc_ss_data->deadline);
 
-       if (!pcc_data.platform_owns_pcc)
+       if (!pcc_ss_data->platform_owns_pcc)
                return 0;
 
        /* Retry in case the remote processor was too slow to catch up. */
@@ -219,7 +225,7 @@ static int check_pcc_chan(bool chk_err_bit)
        }
 
        if (likely(!ret))
-               pcc_data.platform_owns_pcc = false;
+               pcc_ss_data->platform_owns_pcc = false;
        else
                pr_err("PCC check channel failed. Status=%x\n", status);
 
@@ -230,13 +236,12 @@ static int check_pcc_chan(bool chk_err_bit)
  * This function transfers the ownership of the PCC to the platform
  * So it must be called while holding write_lock(pcc_lock)
  */
-static int send_pcc_cmd(u16 cmd)
+static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
 {
        int ret = -EIO, i;
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
        struct acpi_pcct_shared_memory *generic_comm_base =
-               (struct acpi_pcct_shared_memory *) pcc_data.pcc_comm_addr;
-       static ktime_t last_cmd_cmpl_time, last_mpar_reset;
-       static int mpar_count;
+               (struct acpi_pcct_shared_memory *)pcc_ss_data->pcc_comm_addr;
        unsigned int time_delta;
 
        /*
@@ -249,24 +254,25 @@ static int send_pcc_cmd(u16 cmd)
                 * before write completion, so first send a WRITE command to
                 * platform
                 */
-               if (pcc_data.pending_pcc_write_cmd)
-                       send_pcc_cmd(CMD_WRITE);
+               if (pcc_ss_data->pending_pcc_write_cmd)
+                       send_pcc_cmd(pcc_ss_id, CMD_WRITE);
 
-               ret = check_pcc_chan(false);
+               ret = check_pcc_chan(pcc_ss_id, false);
                if (ret)
                        goto end;
        } else /* CMD_WRITE */
-               pcc_data.pending_pcc_write_cmd = FALSE;
+               pcc_ss_data->pending_pcc_write_cmd = FALSE;
 
        /*
         * Handle the Minimum Request Turnaround Time(MRTT)
         * "The minimum amount of time that OSPM must wait after the completion
         * of a command before issuing the next command, in microseconds"
         */
-       if (pcc_data.pcc_mrtt) {
-               time_delta = ktime_us_delta(ktime_get(), last_cmd_cmpl_time);
-               if (pcc_data.pcc_mrtt > time_delta)
-                       udelay(pcc_data.pcc_mrtt - time_delta);
+       if (pcc_ss_data->pcc_mrtt) {
+               time_delta = ktime_us_delta(ktime_get(),
+                                           pcc_ss_data->last_cmd_cmpl_time);
+               if (pcc_ss_data->pcc_mrtt > time_delta)
+                       udelay(pcc_ss_data->pcc_mrtt - time_delta);
        }
 
        /*
@@ -280,18 +286,19 @@ static int send_pcc_cmd(u16 cmd)
         * not send the request to the platform after hitting the MPAR limit in
         * any 60s window
         */
-       if (pcc_data.pcc_mpar) {
-               if (mpar_count == 0) {
-                       time_delta = ktime_ms_delta(ktime_get(), last_mpar_reset);
-                       if (time_delta < 60 * MSEC_PER_SEC) {
+       if (pcc_ss_data->pcc_mpar) {
+               if (pcc_ss_data->mpar_count == 0) {
+                       time_delta = ktime_ms_delta(ktime_get(),
+                                                   pcc_ss_data->last_mpar_reset);
+                       if ((time_delta < 60 * MSEC_PER_SEC) && pcc_ss_data->last_mpar_reset) {
                                pr_debug("PCC cmd not sent due to MPAR limit");
                                ret = -EIO;
                                goto end;
                        }
-                       last_mpar_reset = ktime_get();
-                       mpar_count = pcc_data.pcc_mpar;
+                       pcc_ss_data->last_mpar_reset = ktime_get();
+                       pcc_ss_data->mpar_count = pcc_ss_data->pcc_mpar;
                }
-               mpar_count--;
+               pcc_ss_data->mpar_count--;
        }
 
        /* Write to the shared comm region. */
@@ -300,10 +307,10 @@ static int send_pcc_cmd(u16 cmd)
        /* Flip CMD COMPLETE bit */
        writew_relaxed(0, &generic_comm_base->status);
 
-       pcc_data.platform_owns_pcc = true;
+       pcc_ss_data->platform_owns_pcc = true;
 
        /* Ring doorbell */
-       ret = mbox_send_message(pcc_data.pcc_channel, &cmd);
+       ret = mbox_send_message(pcc_ss_data->pcc_channel, &cmd);
        if (ret < 0) {
                pr_err("Err sending PCC mbox message. cmd:%d, ret:%d\n",
                                cmd, ret);
@@ -311,15 +318,15 @@ static int send_pcc_cmd(u16 cmd)
        }
 
        /* wait for completion and check for PCC errro bit */
-       ret = check_pcc_chan(true);
+       ret = check_pcc_chan(pcc_ss_id, true);
 
-       if (pcc_data.pcc_mrtt)
-               last_cmd_cmpl_time = ktime_get();
+       if (pcc_ss_data->pcc_mrtt)
+               pcc_ss_data->last_cmd_cmpl_time = ktime_get();
 
-       if (pcc_data.pcc_channel->mbox->txdone_irq)
-               mbox_chan_txdone(pcc_data.pcc_channel, ret);
+       if (pcc_ss_data->pcc_channel->mbox->txdone_irq)
+               mbox_chan_txdone(pcc_ss_data->pcc_channel, ret);
        else
-               mbox_client_txdone(pcc_data.pcc_channel, ret);
+               mbox_client_txdone(pcc_ss_data->pcc_channel, ret);
 
 end:
        if (cmd == CMD_WRITE) {
@@ -329,12 +336,12 @@ end:
                                if (!desc)
                                        continue;
 
-                               if (desc->write_cmd_id == pcc_data.pcc_write_cnt)
+                               if (desc->write_cmd_id == pcc_ss_data->pcc_write_cnt)
                                        desc->write_cmd_status = ret;
                        }
                }
-               pcc_data.pcc_write_cnt++;
-               wake_up_all(&pcc_data.pcc_write_wait_q);
+               pcc_ss_data->pcc_write_cnt++;
+               wake_up_all(&pcc_ss_data->pcc_write_wait_q);
        }
 
        return ret;
@@ -536,16 +543,16 @@ err_ret:
 }
 EXPORT_SYMBOL_GPL(acpi_get_psd_map);
 
-static int register_pcc_channel(int pcc_subspace_idx)
+static int register_pcc_channel(int pcc_ss_idx)
 {
        struct acpi_pcct_hw_reduced *cppc_ss;
        u64 usecs_lat;
 
-       if (pcc_subspace_idx >= 0) {
-               pcc_data.pcc_channel = pcc_mbox_request_channel(&cppc_mbox_cl,
-                               pcc_subspace_idx);
+       if (pcc_ss_idx >= 0) {
+               pcc_data[pcc_ss_idx]->pcc_channel =
+                       pcc_mbox_request_channel(&cppc_mbox_cl, pcc_ss_idx);
 
-               if (IS_ERR(pcc_data.pcc_channel)) {
+               if (IS_ERR(pcc_data[pcc_ss_idx]->pcc_channel)) {
                        pr_err("Failed to find PCC communication channel\n");
                        return -ENODEV;
                }
@@ -556,7 +563,7 @@ static int register_pcc_channel(int pcc_subspace_idx)
                 * PCC channels) and stored pointers to the
                 * subspace communication region in con_priv.
                 */
-               cppc_ss = (pcc_data.pcc_channel)->con_priv;
+               cppc_ss = (pcc_data[pcc_ss_idx]->pcc_channel)->con_priv;
 
                if (!cppc_ss) {
                        pr_err("No PCC subspace found for CPPC\n");
@@ -569,19 +576,20 @@ static int register_pcc_channel(int pcc_subspace_idx)
                 * So add an arbitrary amount of wait on top of Nominal.
                 */
                usecs_lat = NUM_RETRIES * cppc_ss->latency;
-               pcc_data.deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC);
-               pcc_data.pcc_mrtt = cppc_ss->min_turnaround_time;
-               pcc_data.pcc_mpar = cppc_ss->max_access_rate;
-               pcc_data.pcc_nominal = cppc_ss->latency;
-
-               pcc_data.pcc_comm_addr = acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length);
-               if (!pcc_data.pcc_comm_addr) {
+               pcc_data[pcc_ss_idx]->deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC);
+               pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time;
+               pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate;
+               pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency;
+
+               pcc_data[pcc_ss_idx]->pcc_comm_addr =
+                       acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length);
+               if (!pcc_data[pcc_ss_idx]->pcc_comm_addr) {
                        pr_err("Failed to ioremap PCC comm region mem\n");
                        return -ENOMEM;
                }
 
                /* Set flag so that we dont come here for each CPU. */
-               pcc_data.pcc_channel_acquired = true;
+               pcc_data[pcc_ss_idx]->pcc_channel_acquired = true;
        }
 
        return 0;
@@ -600,6 +608,34 @@ bool __weak cpc_ffh_supported(void)
        return false;
 }
 
+
+/**
+ * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace
+ *
+ * Check and allocate the cppc_pcc_data memory.
+ * In some processor configurations it is possible that same subspace
+ * is shared between multiple CPU's. This is seen especially in CPU's
+ * with hardware multi-threading support.
+ *
+ * Return: 0 for success, errno for failure
+ */
+int pcc_data_alloc(int pcc_ss_id)
+{
+       if (pcc_ss_id < 0 || pcc_ss_id >= MAX_PCC_SUBSPACES)
+               return -EINVAL;
+
+       if (pcc_data[pcc_ss_id]) {
+               pcc_data[pcc_ss_id]->refcount++;
+       } else {
+               pcc_data[pcc_ss_id] = kzalloc(sizeof(struct cppc_pcc_data),
+                                             GFP_KERNEL);
+               if (!pcc_data[pcc_ss_id])
+                       return -ENOMEM;
+               pcc_data[pcc_ss_id]->refcount++;
+       }
+
+       return 0;
+}
 /*
  * An example CPC table looks like the following.
  *
@@ -661,6 +697,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        struct device *cpu_dev;
        acpi_handle handle = pr->handle;
        unsigned int num_ent, i, cpc_rev;
+       int pcc_subspace_id = -1;
        acpi_status status;
        int ret = -EFAULT;
 
@@ -733,9 +770,11 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                         * so extract it only once.
                         */
                        if (gas_t->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
-                               if (pcc_data.pcc_subspace_idx < 0)
-                                       pcc_data.pcc_subspace_idx = gas_t->access_width;
-                               else if (pcc_data.pcc_subspace_idx != gas_t->access_width) {
+                               if (pcc_subspace_id < 0) {
+                                       pcc_subspace_id = gas_t->access_width;
+                                       if (pcc_data_alloc(pcc_subspace_id))
+                                               goto out_free;
+                               } else if (pcc_subspace_id != gas_t->access_width) {
                                        pr_debug("Mismatched PCC ids.\n");
                                        goto out_free;
                                }
@@ -763,6 +802,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                        goto out_free;
                }
        }
+       per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id;
        /* Store CPU Logical ID */
        cpc_ptr->cpu_id = pr->id;
 
@@ -771,14 +811,14 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        if (ret)
                goto out_free;
 
-       /* Register PCC channel once for all CPUs. */
-       if (!pcc_data.pcc_channel_acquired) {
-               ret = register_pcc_channel(pcc_data.pcc_subspace_idx);
+       /* Register PCC channel once for all PCC subspace id. */
+       if (pcc_subspace_id >= 0 && !pcc_data[pcc_subspace_id]->pcc_channel_acquired) {
+               ret = register_pcc_channel(pcc_subspace_id);
                if (ret)
                        goto out_free;
 
-               init_rwsem(&pcc_data.pcc_lock);
-               init_waitqueue_head(&pcc_data.pcc_write_wait_q);
+               init_rwsem(&pcc_data[pcc_subspace_id]->pcc_lock);
+               init_waitqueue_head(&pcc_data[pcc_subspace_id]->pcc_write_wait_q);
        }
 
        /* Everything looks okay */
@@ -831,6 +871,18 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
        struct cpc_desc *cpc_ptr;
        unsigned int i;
        void __iomem *addr;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, pr->id);
+
+       if (pcc_ss_id >=0 && pcc_data[pcc_ss_id]) {
+               if (pcc_data[pcc_ss_id]->pcc_channel_acquired) {
+                       pcc_data[pcc_ss_id]->refcount--;
+                       if (!pcc_data[pcc_ss_id]->refcount) {
+                               pcc_mbox_free_channel(pcc_data[pcc_ss_id]->pcc_channel);
+                               pcc_data[pcc_ss_id]->pcc_channel_acquired = 0;
+                               kfree(pcc_data[pcc_ss_id]);
+                       }
+               }
+       }
 
        cpc_ptr = per_cpu(cpc_desc_ptr, pr->id);
        if (!cpc_ptr)
@@ -888,6 +940,7 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
 {
        int ret_val = 0;
        void __iomem *vaddr = 0;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
        struct cpc_reg *reg = &reg_res->cpc_entry.reg;
 
        if (reg_res->type == ACPI_TYPE_INTEGER) {
@@ -897,7 +950,7 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
 
        *val = 0;
        if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
-               vaddr = GET_PCC_VADDR(reg->address);
+               vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
        else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
                vaddr = reg_res->sys_mem_vaddr;
        else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
@@ -932,10 +985,11 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
 {
        int ret_val = 0;
        void __iomem *vaddr = 0;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
        struct cpc_reg *reg = &reg_res->cpc_entry.reg;
 
        if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
-               vaddr = GET_PCC_VADDR(reg->address);
+               vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
        else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
                vaddr = reg_res->sys_mem_vaddr;
        else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
@@ -980,6 +1034,8 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
        struct cpc_register_resource *highest_reg, *lowest_reg,
                *lowest_non_linear_reg, *nominal_reg;
        u64 high, low, nom, min_nonlinear;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
        int ret = 0, regs_in_pcc = 0;
 
        if (!cpc_desc) {
@@ -996,9 +1052,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
        if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) ||
                CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg)) {
                regs_in_pcc = 1;
-               down_write(&pcc_data.pcc_lock);
+               down_write(&pcc_ss_data->pcc_lock);
                /* Ring doorbell once to update PCC subspace */
-               if (send_pcc_cmd(CMD_READ) < 0) {
+               if (send_pcc_cmd(pcc_ss_id, CMD_READ) < 0) {
                        ret = -EIO;
                        goto out_err;
                }
@@ -1021,7 +1077,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
 
 out_err:
        if (regs_in_pcc)
-               up_write(&pcc_data.pcc_lock);
+               up_write(&pcc_ss_data->pcc_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
@@ -1038,6 +1094,8 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
        struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
        struct cpc_register_resource *delivered_reg, *reference_reg,
                *ref_perf_reg, *ctr_wrap_reg;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
        u64 delivered, reference, ref_perf, ctr_wrap_time;
        int ret = 0, regs_in_pcc = 0;
 
@@ -1061,10 +1119,10 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
        /* Are any of the regs PCC ?*/
        if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) ||
                CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) {
-               down_write(&pcc_data.pcc_lock);
+               down_write(&pcc_ss_data->pcc_lock);
                regs_in_pcc = 1;
                /* Ring doorbell once to update PCC subspace */
-               if (send_pcc_cmd(CMD_READ) < 0) {
+               if (send_pcc_cmd(pcc_ss_id, CMD_READ) < 0) {
                        ret = -EIO;
                        goto out_err;
                }
@@ -1094,7 +1152,7 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
        perf_fb_ctrs->wraparound_time = ctr_wrap_time;
 out_err:
        if (regs_in_pcc)
-               up_write(&pcc_data.pcc_lock);
+               up_write(&pcc_ss_data->pcc_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(cppc_get_perf_ctrs);
@@ -1110,6 +1168,8 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 {
        struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
        struct cpc_register_resource *desired_reg;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
        int ret = 0;
 
        if (!cpc_desc) {
@@ -1127,11 +1187,11 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
         * achieve that goal here
         */
        if (CPC_IN_PCC(desired_reg)) {
-               down_read(&pcc_data.pcc_lock);  /* BEGIN Phase-I */
-               if (pcc_data.platform_owns_pcc) {
-                       ret = check_pcc_chan(false);
+               down_read(&pcc_ss_data->pcc_lock); /* BEGIN Phase-I */
+               if (pcc_ss_data->platform_owns_pcc) {
+                       ret = check_pcc_chan(pcc_ss_id, false);
                        if (ret) {
-                               up_read(&pcc_data.pcc_lock);
+                               up_read(&pcc_ss_data->pcc_lock);
                                return ret;
                        }
                }
@@ -1139,8 +1199,8 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
                 * Update the pending_write to make sure a PCC CMD_READ will not
                 * arrive and steal the channel during the switch to write lock
                 */
-               pcc_data.pending_pcc_write_cmd = true;
-               cpc_desc->write_cmd_id = pcc_data.pcc_write_cnt;
+               pcc_ss_data->pending_pcc_write_cmd = true;
+               cpc_desc->write_cmd_id = pcc_ss_data->pcc_write_cnt;
                cpc_desc->write_cmd_status = 0;
        }
 
@@ -1151,7 +1211,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
        cpc_write(cpu, desired_reg, perf_ctrls->desired_perf);
 
        if (CPC_IN_PCC(desired_reg))
-               up_read(&pcc_data.pcc_lock);    /* END Phase-I */
+               up_read(&pcc_ss_data->pcc_lock);        /* END Phase-I */
        /*
         * This is Phase-II where we transfer the ownership of PCC to Platform
         *
@@ -1199,15 +1259,15 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
         * the write command before servicing the read command
         */
        if (CPC_IN_PCC(desired_reg)) {
-               if (down_write_trylock(&pcc_data.pcc_lock)) {   /* BEGIN Phase-II */
+               if (down_write_trylock(&pcc_ss_data->pcc_lock)) {/* BEGIN Phase-II */
                        /* Update only if there are pending write commands */
-                       if (pcc_data.pending_pcc_write_cmd)
-                               send_pcc_cmd(CMD_WRITE);
-                       up_write(&pcc_data.pcc_lock);           /* END Phase-II */
+                       if (pcc_ss_data->pending_pcc_write_cmd)
+                               send_pcc_cmd(pcc_ss_id, CMD_WRITE);
+                       up_write(&pcc_ss_data->pcc_lock);       /* END Phase-II */
                } else
                        /* Wait until pcc_write_cnt is updated by send_pcc_cmd */
-                       wait_event(pcc_data.pcc_write_wait_q,
-                               cpc_desc->write_cmd_id != pcc_data.pcc_write_cnt);
+                       wait_event(pcc_ss_data->pcc_write_wait_q,
+                                  cpc_desc->write_cmd_id != pcc_ss_data->pcc_write_cnt);
 
                /* send_pcc_cmd updates the status in case of failure */
                ret = cpc_desc->write_cmd_status;
@@ -1240,6 +1300,8 @@ unsigned int cppc_get_transition_latency(int cpu_num)
        unsigned int latency_ns = 0;
        struct cpc_desc *cpc_desc;
        struct cpc_register_resource *desired_reg;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu_num);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
 
        cpc_desc = per_cpu(cpc_desc_ptr, cpu_num);
        if (!cpc_desc)
@@ -1249,11 +1311,11 @@ unsigned int cppc_get_transition_latency(int cpu_num)
        if (!CPC_IN_PCC(desired_reg))
                return CPUFREQ_ETERNAL;
 
-       if (pcc_data.pcc_mpar)
-               latency_ns = 60 * (1000 * 1000 * 1000 / pcc_data.pcc_mpar);
+       if (pcc_ss_data->pcc_mpar)
+               latency_ns = 60 * (1000 * 1000 * 1000 / pcc_ss_data->pcc_mpar);
 
-       latency_ns = max(latency_ns, pcc_data.pcc_nominal * 1000);
-       latency_ns = max(latency_ns, pcc_data.pcc_mrtt * 1000);
+       latency_ns = max(latency_ns, pcc_ss_data->pcc_nominal * 1000);
+       latency_ns = max(latency_ns, pcc_ss_data->pcc_mrtt * 1000);
 
        return latency_ns;
 }
index fbcc73f7a0990993557e51205d451623f515c15c..e4ffaeec9ec204110f7e50c5cff49172a486f081 100644 (file)
@@ -387,6 +387,7 @@ EXPORT_SYMBOL(acpi_bus_power_manageable);
 
 #ifdef CONFIG_PM
 static DEFINE_MUTEX(acpi_pm_notifier_lock);
+static DEFINE_MUTEX(acpi_pm_notifier_install_lock);
 
 void acpi_pm_wakeup_event(struct device *dev)
 {
@@ -443,24 +444,25 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
        if (!dev && !func)
                return AE_BAD_PARAMETER;
 
-       mutex_lock(&acpi_pm_notifier_lock);
+       mutex_lock(&acpi_pm_notifier_install_lock);
 
        if (adev->wakeup.flags.notifier_present)
                goto out;
 
-       adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev));
-       adev->wakeup.context.dev = dev;
-       adev->wakeup.context.func = func;
-
        status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY,
                                             acpi_pm_notify_handler, NULL);
        if (ACPI_FAILURE(status))
                goto out;
 
+       mutex_lock(&acpi_pm_notifier_lock);
+       adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev));
+       adev->wakeup.context.dev = dev;
+       adev->wakeup.context.func = func;
        adev->wakeup.flags.notifier_present = true;
+       mutex_unlock(&acpi_pm_notifier_lock);
 
  out:
-       mutex_unlock(&acpi_pm_notifier_lock);
+       mutex_unlock(&acpi_pm_notifier_install_lock);
        return status;
 }
 
@@ -472,7 +474,7 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
 {
        acpi_status status = AE_BAD_PARAMETER;
 
-       mutex_lock(&acpi_pm_notifier_lock);
+       mutex_lock(&acpi_pm_notifier_install_lock);
 
        if (!adev->wakeup.flags.notifier_present)
                goto out;
@@ -483,14 +485,15 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
        if (ACPI_FAILURE(status))
                goto out;
 
+       mutex_lock(&acpi_pm_notifier_lock);
        adev->wakeup.context.func = NULL;
        adev->wakeup.context.dev = NULL;
        wakeup_source_unregister(adev->wakeup.ws);
-
        adev->wakeup.flags.notifier_present = false;
+       mutex_unlock(&acpi_pm_notifier_lock);
 
  out:
-       mutex_unlock(&acpi_pm_notifier_lock);
+       mutex_unlock(&acpi_pm_notifier_install_lock);
        return status;
 }
 
@@ -581,8 +584,7 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
                d_min = ret;
                wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid
                        && adev->wakeup.sleep_state >= target_state;
-       } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) !=
-                       PM_QOS_FLAGS_NONE) {
+       } else {
                wakeup = adev->wakeup.flags.valid;
        }
 
@@ -848,48 +850,48 @@ static int acpi_dev_pm_full_power(struct acpi_device *adev)
 }
 
 /**
- * acpi_dev_runtime_suspend - Put device into a low-power state using ACPI.
+ * acpi_dev_suspend - Put device into a low-power state using ACPI.
  * @dev: Device to put into a low-power state.
+ * @wakeup: Whether or not to enable wakeup for the device.
  *
- * Put the given device into a runtime low-power state using the standard ACPI
+ * Put the given device into a low-power state using the standard ACPI
  * mechanism.  Set up remote wakeup if desired, choose the state to put the
  * device into (this checks if remote wakeup is expected to work too), and set
  * the power state of the device.
  */
-int acpi_dev_runtime_suspend(struct device *dev)
+int acpi_dev_suspend(struct device *dev, bool wakeup)
 {
        struct acpi_device *adev = ACPI_COMPANION(dev);
-       bool remote_wakeup;
+       u32 target_state = acpi_target_system_state();
        int error;
 
        if (!adev)
                return 0;
 
-       remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
-                               PM_QOS_FLAGS_NONE;
-       if (remote_wakeup) {
-               error = acpi_device_wakeup_enable(adev, ACPI_STATE_S0);
+       if (wakeup && acpi_device_can_wakeup(adev)) {
+               error = acpi_device_wakeup_enable(adev, target_state);
                if (error)
                        return -EAGAIN;
+       } else {
+               wakeup = false;
        }
 
-       error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
-       if (error && remote_wakeup)
+       error = acpi_dev_pm_low_power(dev, adev, target_state);
+       if (error && wakeup)
                acpi_device_wakeup_disable(adev);
 
        return error;
 }
-EXPORT_SYMBOL_GPL(acpi_dev_runtime_suspend);
+EXPORT_SYMBOL_GPL(acpi_dev_suspend);
 
 /**
- * acpi_dev_runtime_resume - Put device into the full-power state using ACPI.
+ * acpi_dev_resume - Put device into the full-power state using ACPI.
  * @dev: Device to put into the full-power state.
  *
  * Put the given device into the full-power state using the standard ACPI
- * mechanism at run time.  Set the power state of the device to ACPI D0 and
- * disable remote wakeup.
+ * mechanism.  Set the power state of the device to ACPI D0 and disable wakeup.
  */
-int acpi_dev_runtime_resume(struct device *dev)
+int acpi_dev_resume(struct device *dev)
 {
        struct acpi_device *adev = ACPI_COMPANION(dev);
        int error;
@@ -901,7 +903,7 @@ int acpi_dev_runtime_resume(struct device *dev)
        acpi_device_wakeup_disable(adev);
        return error;
 }
-EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
+EXPORT_SYMBOL_GPL(acpi_dev_resume);
 
 /**
  * acpi_subsys_runtime_suspend - Suspend device using ACPI.
@@ -913,7 +915,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
 int acpi_subsys_runtime_suspend(struct device *dev)
 {
        int ret = pm_generic_runtime_suspend(dev);
-       return ret ? ret : acpi_dev_runtime_suspend(dev);
+       return ret ? ret : acpi_dev_suspend(dev, true);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend);
 
@@ -926,68 +928,33 @@ EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend);
  */
 int acpi_subsys_runtime_resume(struct device *dev)
 {
-       int ret = acpi_dev_runtime_resume(dev);
+       int ret = acpi_dev_resume(dev);
        return ret ? ret : pm_generic_runtime_resume(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume);
 
 #ifdef CONFIG_PM_SLEEP
-/**
- * acpi_dev_suspend_late - Put device into a low-power state using ACPI.
- * @dev: Device to put into a low-power state.
- *
- * Put the given device into a low-power state during system transition to a
- * sleep state using the standard ACPI mechanism.  Set up system wakeup if
- * desired, choose the state to put the device into (this checks if system
- * wakeup is expected to work too), and set the power state of the device.
- */
-int acpi_dev_suspend_late(struct device *dev)
+static bool acpi_dev_needs_resume(struct device *dev, struct acpi_device *adev)
 {
-       struct acpi_device *adev = ACPI_COMPANION(dev);
-       u32 target_state;
-       bool wakeup;
-       int error;
-
-       if (!adev)
-               return 0;
-
-       target_state = acpi_target_system_state();
-       wakeup = device_may_wakeup(dev) && acpi_device_can_wakeup(adev);
-       if (wakeup) {
-               error = acpi_device_wakeup_enable(adev, target_state);
-               if (error)
-                       return error;
-       }
+       u32 sys_target = acpi_target_system_state();
+       int ret, state;
 
-       error = acpi_dev_pm_low_power(dev, adev, target_state);
-       if (error && wakeup)
-               acpi_device_wakeup_disable(adev);
+       if (!pm_runtime_suspended(dev) || !adev ||
+           device_may_wakeup(dev) != !!adev->wakeup.prepare_count)
+               return true;
 
-       return error;
-}
-EXPORT_SYMBOL_GPL(acpi_dev_suspend_late);
+       if (sys_target == ACPI_STATE_S0)
+               return false;
 
-/**
- * acpi_dev_resume_early - Put device into the full-power state using ACPI.
- * @dev: Device to put into the full-power state.
- *
- * Put the given device into the full-power state using the standard ACPI
- * mechanism during system transition to the working state.  Set the power
- * state of the device to ACPI D0 and disable remote wakeup.
- */
-int acpi_dev_resume_early(struct device *dev)
-{
-       struct acpi_device *adev = ACPI_COMPANION(dev);
-       int error;
+       if (adev->power.flags.dsw_present)
+               return true;
 
-       if (!adev)
-               return 0;
+       ret = acpi_dev_pm_get_state(dev, adev, sys_target, NULL, &state);
+       if (ret)
+               return true;
 
-       error = acpi_dev_pm_full_power(adev);
-       acpi_device_wakeup_disable(adev);
-       return error;
+       return state != adev->power.state;
 }
-EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
 
 /**
  * acpi_subsys_prepare - Prepare device for system transition to a sleep state.
@@ -996,39 +963,53 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
 int acpi_subsys_prepare(struct device *dev)
 {
        struct acpi_device *adev = ACPI_COMPANION(dev);
-       u32 sys_target;
-       int ret, state;
 
-       ret = pm_generic_prepare(dev);
-       if (ret < 0)
-               return ret;
-
-       if (!adev || !pm_runtime_suspended(dev)
-           || device_may_wakeup(dev) != !!adev->wakeup.prepare_count)
-               return 0;
+       if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) {
+               int ret = dev->driver->pm->prepare(dev);
 
-       sys_target = acpi_target_system_state();
-       if (sys_target == ACPI_STATE_S0)
-               return 1;
+               if (ret < 0)
+                       return ret;
 
-       if (adev->power.flags.dsw_present)
-               return 0;
+               if (!ret && dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_PREPARE))
+                       return 0;
+       }
 
-       ret = acpi_dev_pm_get_state(dev, adev, sys_target, NULL, &state);
-       return !ret && state == adev->power.state;
+       return !acpi_dev_needs_resume(dev, adev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
 
+/**
+ * acpi_subsys_complete - Finalize device's resume during system resume.
+ * @dev: Device to handle.
+ */
+void acpi_subsys_complete(struct device *dev)
+{
+       pm_generic_complete(dev);
+       /*
+        * If the device had been runtime-suspended before the system went into
+        * the sleep state it is going out of and it has never been resumed till
+        * now, resume it in case the firmware powered it up.
+        */
+       if (dev->power.direct_complete && pm_resume_via_firmware())
+               pm_request_resume(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_complete);
+
 /**
  * acpi_subsys_suspend - Run the device driver's suspend callback.
  * @dev: Device to handle.
  *
- * Follow PCI and resume devices suspended at run time before running their
- * system suspend callbacks.
+ * Follow PCI and resume devices from runtime suspend before running their
+ * system suspend callbacks, unless the driver can cope with runtime-suspended
+ * devices during system suspend and there are no ACPI-specific reasons for
+ * resuming them.
  */
 int acpi_subsys_suspend(struct device *dev)
 {
-       pm_runtime_resume(dev);
+       if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
+           acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
+               pm_runtime_resume(dev);
+
        return pm_generic_suspend(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
@@ -1042,11 +1023,47 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
  */
 int acpi_subsys_suspend_late(struct device *dev)
 {
-       int ret = pm_generic_suspend_late(dev);
-       return ret ? ret : acpi_dev_suspend_late(dev);
+       int ret;
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       ret = pm_generic_suspend_late(dev);
+       return ret ? ret : acpi_dev_suspend(dev, device_may_wakeup(dev));
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late);
 
+/**
+ * acpi_subsys_suspend_noirq - Run the device driver's "noirq" suspend callback.
+ * @dev: Device to suspend.
+ */
+int acpi_subsys_suspend_noirq(struct device *dev)
+{
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       return pm_generic_suspend_noirq(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq);
+
+/**
+ * acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_resume_noirq(struct device *dev)
+{
+       /*
+        * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend
+        * during system suspend, so update their runtime PM status to "active"
+        * as they will be put into D0 going forward.
+        */
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               pm_runtime_set_active(dev);
+
+       return pm_generic_resume_noirq(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq);
+
 /**
  * acpi_subsys_resume_early - Resume device using ACPI.
  * @dev: Device to Resume.
@@ -1057,7 +1074,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late);
  */
 int acpi_subsys_resume_early(struct device *dev)
 {
-       int ret = acpi_dev_resume_early(dev);
+       int ret = acpi_dev_resume(dev);
        return ret ? ret : pm_generic_resume_early(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
@@ -1074,11 +1091,60 @@ int acpi_subsys_freeze(struct device *dev)
         * runtime-suspended devices should not be touched during freeze/thaw
         * transitions.
         */
-       pm_runtime_resume(dev);
+       if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
+               pm_runtime_resume(dev);
+
        return pm_generic_freeze(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
 
+/**
+ * acpi_subsys_freeze_late - Run the device driver's "late" freeze callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_freeze_late(struct device *dev)
+{
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       return pm_generic_freeze_late(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_freeze_late);
+
+/**
+ * acpi_subsys_freeze_noirq - Run the device driver's "noirq" freeze callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_freeze_noirq(struct device *dev)
+{
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       return pm_generic_freeze_noirq(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_freeze_noirq);
+
+/**
+ * acpi_subsys_thaw_noirq - Run the device driver's "noirq" thaw callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_thaw_noirq(struct device *dev)
+{
+       /*
+        * If the device is in runtime suspend, the "thaw" code may not work
+        * correctly with it, so skip the driver callback and make the PM core
+        * skip all of the subsequent "thaw" callbacks for the device.
+        */
+       if (dev_pm_smart_suspend_and_suspended(dev)) {
+               dev->power.direct_complete = true;
+               return 0;
+       }
+
+       return pm_generic_thaw_noirq(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_thaw_noirq);
 #endif /* CONFIG_PM_SLEEP */
 
 static struct dev_pm_domain acpi_general_pm_domain = {
@@ -1087,13 +1153,20 @@ static struct dev_pm_domain acpi_general_pm_domain = {
                .runtime_resume = acpi_subsys_runtime_resume,
 #ifdef CONFIG_PM_SLEEP
                .prepare = acpi_subsys_prepare,
-               .complete = pm_complete_with_resume_check,
+               .complete = acpi_subsys_complete,
                .suspend = acpi_subsys_suspend,
                .suspend_late = acpi_subsys_suspend_late,
+               .suspend_noirq = acpi_subsys_suspend_noirq,
+               .resume_noirq = acpi_subsys_resume_noirq,
                .resume_early = acpi_subsys_resume_early,
                .freeze = acpi_subsys_freeze,
+               .freeze_late = acpi_subsys_freeze_late,
+               .freeze_noirq = acpi_subsys_freeze_noirq,
+               .thaw_noirq = acpi_subsys_thaw_noirq,
                .poweroff = acpi_subsys_suspend,
                .poweroff_late = acpi_subsys_suspend_late,
+               .poweroff_noirq = acpi_subsys_suspend_noirq,
+               .restore_noirq = acpi_subsys_resume_noirq,
                .restore_early = acpi_subsys_resume_early,
 #endif
        },
index 2305e1ab978ea0e09f6a7eb8cdb4e3dc78b0533e..e3fc1f045e1cd96cf67dec8d069f7d21c3a6c30d 100644 (file)
@@ -482,6 +482,7 @@ int dock_notify(struct acpi_device *adev, u32 event)
                surprise_removal = 1;
                event = ACPI_NOTIFY_EJECT_REQUEST;
                /* Fall back */
+               /* fall through */
        case ACPI_NOTIFY_EJECT_REQUEST:
                begin_undock(ds);
                if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
index 236b14324780a1c1c416c852957cfa732144b8fc..82b3ce5e937e8b980acd1a02e6a1f21c408a5ee0 100644 (file)
@@ -486,8 +486,11 @@ static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
 {
        if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
                ec_log_drv("event unblocked");
-       if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
-               advance_transaction(ec);
+       /*
+        * Unconditionally invoke this once after enabling the event
+        * handling mechanism to detect the pending events.
+        */
+       advance_transaction(ec);
 }
 
 static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
@@ -1456,11 +1459,10 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
                        if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
                            ec->reference_count >= 1)
                                acpi_ec_enable_gpe(ec, true);
-
-                       /* EC is fully operational, allow queries */
-                       acpi_ec_enable_event(ec);
                }
        }
+       /* EC is fully operational, allow queries */
+       acpi_ec_enable_event(ec);
 
        return 0;
 }
index 4361c4415b4f4cce9b96a6c0f7aaec42c1f09b52..fc8c43e767074c177c56c1c97adc6a3a077d5336 100644 (file)
@@ -248,4 +248,10 @@ void acpi_watchdog_init(void);
 static inline void acpi_watchdog_init(void) {}
 #endif
 
+#ifdef CONFIG_ACPI_LPIT
+void acpi_init_lpit(void);
+#else
+static inline void acpi_init_lpit(void) { }
+#endif
+
 #endif /* _ACPI_INTERNAL_H_ */
index db78d353bab1f94b4d88c8b767b105a1da486d0b..3bb46cb24a9966ac86b950d53c817e523fe7cd40 100644 (file)
@@ -663,6 +663,29 @@ acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
 
 EXPORT_SYMBOL(acpi_os_write_port);
 
+int acpi_os_read_iomem(void __iomem *virt_addr, u64 *value, u32 width)
+{
+
+       switch (width) {
+       case 8:
+               *(u8 *) value = readb(virt_addr);
+               break;
+       case 16:
+               *(u16 *) value = readw(virt_addr);
+               break;
+       case 32:
+               *(u32 *) value = readl(virt_addr);
+               break;
+       case 64:
+               *(u64 *) value = readq(virt_addr);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 acpi_status
 acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width)
 {
@@ -670,6 +693,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width)
        unsigned int size = width / 8;
        bool unmap = false;
        u64 dummy;
+       int error;
 
        rcu_read_lock();
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
@@ -684,22 +708,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width)
        if (!value)
                value = &dummy;
 
-       switch (width) {
-       case 8:
-               *(u8 *) value = readb(virt_addr);
-               break;
-       case 16:
-               *(u16 *) value = readw(virt_addr);
-               break;
-       case 32:
-               *(u32 *) value = readl(virt_addr);
-               break;
-       case 64:
-               *(u64 *) value = readq(virt_addr);
-               break;
-       default:
-               BUG();
-       }
+       error = acpi_os_read_iomem(virt_addr, value, width);
+       BUG_ON(error);
 
        if (unmap)
                iounmap(virt_addr);
diff --git a/drivers/acpi/pmic/tps68470_pmic.c b/drivers/acpi/pmic/tps68470_pmic.c
new file mode 100644 (file)
index 0000000..7f3c567
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * TI TPS68470 PMIC operation region driver
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ * Author: Rajmohan Mani <rajmohan.mani@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Based on drivers/acpi/pmic/intel_pmic* drivers
+ */
+
+#include <linux/acpi.h>
+#include <linux/mfd/tps68470.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+struct tps68470_pmic_table {
+       u32 address;            /* operation region address */
+       u32 reg;                /* corresponding register */
+       u32 bitmask;            /* bit mask for power, clock */
+};
+
+#define TI_PMIC_POWER_OPREGION_ID              0xB0
+#define TI_PMIC_VR_VAL_OPREGION_ID             0xB1
+#define TI_PMIC_CLOCK_OPREGION_ID              0xB2
+#define TI_PMIC_CLKFREQ_OPREGION_ID            0xB3
+
+struct tps68470_pmic_opregion {
+       struct mutex lock;
+       struct regmap *regmap;
+};
+
+#define S_IO_I2C_EN    (BIT(0) | BIT(1))
+
+static const struct tps68470_pmic_table power_table[] = {
+       {
+               .address = 0x00,
+               .reg = TPS68470_REG_S_I2C_CTL,
+               .bitmask = S_IO_I2C_EN,
+               /* S_I2C_CTL */
+       },
+       {
+               .address = 0x04,
+               .reg = TPS68470_REG_VCMCTL,
+               .bitmask = BIT(0),
+               /* VCMCTL */
+       },
+       {
+               .address = 0x08,
+               .reg = TPS68470_REG_VAUX1CTL,
+               .bitmask = BIT(0),
+               /* VAUX1_CTL */
+       },
+       {
+               .address = 0x0C,
+               .reg = TPS68470_REG_VAUX2CTL,
+               .bitmask = BIT(0),
+               /* VAUX2CTL */
+       },
+       {
+               .address = 0x10,
+               .reg = TPS68470_REG_VACTL,
+               .bitmask = BIT(0),
+               /* VACTL */
+       },
+       {
+               .address = 0x14,
+               .reg = TPS68470_REG_VDCTL,
+               .bitmask = BIT(0),
+               /* VDCTL */
+       },
+};
+
+/* Table to set voltage regulator value */
+static const struct tps68470_pmic_table vr_val_table[] = {
+       {
+               .address = 0x00,
+               .reg = TPS68470_REG_VSIOVAL,
+               .bitmask = TPS68470_VSIOVAL_IOVOLT_MASK,
+               /* TPS68470_REG_VSIOVAL */
+       },
+       {
+               .address = 0x04,
+               .reg = TPS68470_REG_VIOVAL,
+               .bitmask = TPS68470_VIOVAL_IOVOLT_MASK,
+               /* TPS68470_REG_VIOVAL */
+       },
+       {
+               .address = 0x08,
+               .reg = TPS68470_REG_VCMVAL,
+               .bitmask = TPS68470_VCMVAL_VCVOLT_MASK,
+               /* TPS68470_REG_VCMVAL */
+       },
+       {
+               .address = 0x0C,
+               .reg = TPS68470_REG_VAUX1VAL,
+               .bitmask = TPS68470_VAUX1VAL_AUX1VOLT_MASK,
+               /* TPS68470_REG_VAUX1VAL */
+       },
+       {
+               .address = 0x10,
+               .reg = TPS68470_REG_VAUX2VAL,
+               .bitmask = TPS68470_VAUX2VAL_AUX2VOLT_MASK,
+               /* TPS68470_REG_VAUX2VAL */
+       },
+       {
+               .address = 0x14,
+               .reg = TPS68470_REG_VAVAL,
+               .bitmask = TPS68470_VAVAL_AVOLT_MASK,
+               /* TPS68470_REG_VAVAL */
+       },
+       {
+               .address = 0x18,
+               .reg = TPS68470_REG_VDVAL,
+               .bitmask = TPS68470_VDVAL_DVOLT_MASK,
+               /* TPS68470_REG_VDVAL */
+       },
+};
+
+/* Table to configure clock frequency */
+static const struct tps68470_pmic_table clk_freq_table[] = {
+       {
+               .address = 0x00,
+               .reg = TPS68470_REG_POSTDIV2,
+               .bitmask = BIT(0) | BIT(1),
+               /* TPS68470_REG_POSTDIV2 */
+       },
+       {
+               .address = 0x04,
+               .reg = TPS68470_REG_BOOSTDIV,
+               .bitmask = 0x1F,
+               /* TPS68470_REG_BOOSTDIV */
+       },
+       {
+               .address = 0x08,
+               .reg = TPS68470_REG_BUCKDIV,
+               .bitmask = 0x0F,
+               /* TPS68470_REG_BUCKDIV */
+       },
+       {
+               .address = 0x0C,
+               .reg = TPS68470_REG_PLLSWR,
+               .bitmask = 0x13,
+               /* TPS68470_REG_PLLSWR */
+       },
+       {
+               .address = 0x10,
+               .reg = TPS68470_REG_XTALDIV,
+               .bitmask = 0xFF,
+               /* TPS68470_REG_XTALDIV */
+       },
+       {
+               .address = 0x14,
+               .reg = TPS68470_REG_PLLDIV,
+               .bitmask = 0xFF,
+               /* TPS68470_REG_PLLDIV */
+       },
+       {
+               .address = 0x18,
+               .reg = TPS68470_REG_POSTDIV,
+               .bitmask = 0x83,
+               /* TPS68470_REG_POSTDIV */
+       },
+};
+
+/* Table to configure and enable clocks */
+static const struct tps68470_pmic_table clk_table[] = {
+       {
+               .address = 0x00,
+               .reg = TPS68470_REG_PLLCTL,
+               .bitmask = 0xF5,
+               /* TPS68470_REG_PLLCTL */
+       },
+       {
+               .address = 0x04,
+               .reg = TPS68470_REG_PLLCTL2,
+               .bitmask = BIT(0),
+               /* TPS68470_REG_PLLCTL2 */
+       },
+       {
+               .address = 0x08,
+               .reg = TPS68470_REG_CLKCFG1,
+               .bitmask = TPS68470_CLKCFG1_MODE_A_MASK |
+                       TPS68470_CLKCFG1_MODE_B_MASK,
+               /* TPS68470_REG_CLKCFG1 */
+       },
+       {
+               .address = 0x0C,
+               .reg = TPS68470_REG_CLKCFG2,
+               .bitmask = TPS68470_CLKCFG1_MODE_A_MASK |
+                       TPS68470_CLKCFG1_MODE_B_MASK,
+               /* TPS68470_REG_CLKCFG2 */
+       },
+};
+
+static int pmic_get_reg_bit(u64 address,
+                           const struct tps68470_pmic_table *table,
+                           const unsigned int table_size, int *reg,
+                           int *bitmask)
+{
+       u64 i;
+
+       i = address / 4;
+       if (i >= table_size)
+               return -ENOENT;
+
+       if (!reg || !bitmask)
+               return -EINVAL;
+
+       *reg = table[i].reg;
+       *bitmask = table[i].bitmask;
+
+       return 0;
+}
+
+static int tps68470_pmic_get_power(struct regmap *regmap, int reg,
+                                      int bitmask, u64 *value)
+{
+       unsigned int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = (data & bitmask) ? 1 : 0;
+       return 0;
+}
+
+static int tps68470_pmic_get_vr_val(struct regmap *regmap, int reg,
+                                      int bitmask, u64 *value)
+{
+       unsigned int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = data & bitmask;
+       return 0;
+}
+
+static int tps68470_pmic_get_clk(struct regmap *regmap, int reg,
+                                      int bitmask, u64 *value)
+{
+       unsigned int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = (data & bitmask) ? 1 : 0;
+       return 0;
+}
+
+static int tps68470_pmic_get_clk_freq(struct regmap *regmap, int reg,
+                                      int bitmask, u64 *value)
+{
+       unsigned int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = data & bitmask;
+       return 0;
+}
+
+static int ti_tps68470_regmap_update_bits(struct regmap *regmap, int reg,
+                                       int bitmask, u64 value)
+{
+       return regmap_update_bits(regmap, reg, bitmask, value);
+}
+
+static acpi_status tps68470_pmic_common_handler(u32 function,
+                                         acpi_physical_address address,
+                                         u32 bits, u64 *value,
+                                         void *region_context,
+                                         int (*get)(struct regmap *,
+                                                    int, int, u64 *),
+                                         int (*update)(struct regmap *,
+                                                       int, int, u64),
+                                         const struct tps68470_pmic_table *tbl,
+                                         unsigned int tbl_size)
+{
+       struct tps68470_pmic_opregion *opregion = region_context;
+       struct regmap *regmap = opregion->regmap;
+       int reg, ret, bitmask;
+
+       if (bits != 32)
+               return AE_BAD_PARAMETER;
+
+       ret = pmic_get_reg_bit(address, tbl, tbl_size, &reg, &bitmask);
+       if (ret < 0)
+               return AE_BAD_PARAMETER;
+
+       if (function == ACPI_WRITE && *value > bitmask)
+               return AE_BAD_PARAMETER;
+
+       mutex_lock(&opregion->lock);
+
+       ret = (function == ACPI_READ) ?
+               get(regmap, reg, bitmask, value) :
+               update(regmap, reg, bitmask, *value);
+
+       mutex_unlock(&opregion->lock);
+
+       return ret ? AE_ERROR : AE_OK;
+}
+
+static acpi_status tps68470_pmic_cfreq_handler(u32 function,
+                                           acpi_physical_address address,
+                                           u32 bits, u64 *value,
+                                           void *handler_context,
+                                           void *region_context)
+{
+       return tps68470_pmic_common_handler(function, address, bits, value,
+                               region_context,
+                               tps68470_pmic_get_clk_freq,
+                               ti_tps68470_regmap_update_bits,
+                               clk_freq_table,
+                               ARRAY_SIZE(clk_freq_table));
+}
+
+static acpi_status tps68470_pmic_clk_handler(u32 function,
+                                      acpi_physical_address address, u32 bits,
+                                      u64 *value, void *handler_context,
+                                      void *region_context)
+{
+       return tps68470_pmic_common_handler(function, address, bits, value,
+                               region_context,
+                               tps68470_pmic_get_clk,
+                               ti_tps68470_regmap_update_bits,
+                               clk_table,
+                               ARRAY_SIZE(clk_table));
+}
+
+static acpi_status tps68470_pmic_vrval_handler(u32 function,
+                                         acpi_physical_address address,
+                                         u32 bits, u64 *value,
+                                         void *handler_context,
+                                         void *region_context)
+{
+       return tps68470_pmic_common_handler(function, address, bits, value,
+                               region_context,
+                               tps68470_pmic_get_vr_val,
+                               ti_tps68470_regmap_update_bits,
+                               vr_val_table,
+                               ARRAY_SIZE(vr_val_table));
+}
+
+static acpi_status tps68470_pmic_pwr_handler(u32 function,
+                                        acpi_physical_address address,
+                                        u32 bits, u64 *value,
+                                        void *handler_context,
+                                        void *region_context)
+{
+       if (bits != 32)
+               return AE_BAD_PARAMETER;
+
+       /* set/clear for bit 0, bits 0 and 1 together */
+       if (function == ACPI_WRITE &&
+           !(*value == 0 || *value == 1 || *value == 3)) {
+               return AE_BAD_PARAMETER;
+       }
+
+       return tps68470_pmic_common_handler(function, address, bits, value,
+                               region_context,
+                               tps68470_pmic_get_power,
+                               ti_tps68470_regmap_update_bits,
+                               power_table,
+                               ARRAY_SIZE(power_table));
+}
+
+static int tps68470_pmic_opregion_probe(struct platform_device *pdev)
+{
+       struct regmap *tps68470_regmap = dev_get_drvdata(pdev->dev.parent);
+       acpi_handle handle = ACPI_HANDLE(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct tps68470_pmic_opregion *opregion;
+       acpi_status status;
+
+       if (!dev || !tps68470_regmap) {
+               dev_warn(dev, "dev or regmap is NULL\n");
+               return -EINVAL;
+       }
+
+       if (!handle) {
+               dev_warn(dev, "acpi handle is NULL\n");
+               return -ENODEV;
+       }
+
+       opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
+       if (!opregion)
+               return -ENOMEM;
+
+       mutex_init(&opregion->lock);
+       opregion->regmap = tps68470_regmap;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   TI_PMIC_POWER_OPREGION_ID,
+                                                   tps68470_pmic_pwr_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               goto out_mutex_destroy;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   TI_PMIC_VR_VAL_OPREGION_ID,
+                                                   tps68470_pmic_vrval_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               goto out_remove_power_handler;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   TI_PMIC_CLOCK_OPREGION_ID,
+                                                   tps68470_pmic_clk_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               goto out_remove_vr_val_handler;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   TI_PMIC_CLKFREQ_OPREGION_ID,
+                                                   tps68470_pmic_cfreq_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               goto out_remove_clk_handler;
+
+       return 0;
+
+out_remove_clk_handler:
+       acpi_remove_address_space_handler(handle, TI_PMIC_CLOCK_OPREGION_ID,
+                                         tps68470_pmic_clk_handler);
+out_remove_vr_val_handler:
+       acpi_remove_address_space_handler(handle, TI_PMIC_VR_VAL_OPREGION_ID,
+                                         tps68470_pmic_vrval_handler);
+out_remove_power_handler:
+       acpi_remove_address_space_handler(handle, TI_PMIC_POWER_OPREGION_ID,
+                                         tps68470_pmic_pwr_handler);
+out_mutex_destroy:
+       mutex_destroy(&opregion->lock);
+       return -ENODEV;
+}
+
+static struct platform_driver tps68470_pmic_opregion_driver = {
+       .probe = tps68470_pmic_opregion_probe,
+       .driver = {
+               .name = "tps68470_pmic_opregion",
+       },
+};
+
+builtin_platform_driver(tps68470_pmic_opregion_driver)
index d85e010ee2cced7b840ebe59fc41a4830bef74e4..316a0fc785e3629a4bdd6dadd031cbe6691cec70 100644 (file)
@@ -381,6 +381,7 @@ unsigned int acpi_dev_get_irq_type(int triggering, int polarity)
        case ACPI_ACTIVE_BOTH:
                if (triggering == ACPI_EDGE_SENSITIVE)
                        return IRQ_TYPE_EDGE_BOTH;
+               /* fall through */
        default:
                return IRQ_TYPE_NONE;
        }
index 602f8ff212f2c699f1d897a54d7c6a90cbdfe9f3..81367edc8a1052f8d361318a32a4e1f95ff5aded 100644 (file)
@@ -2122,6 +2122,7 @@ int __init acpi_scan_init(void)
        acpi_int340x_thermal_init();
        acpi_amba_init();
        acpi_watchdog_init();
+       acpi_init_lpit();
 
        acpi_scan_add_handler(&generic_device_handler);
 
index 6804ddab3052962d28e5e4954ab0c4e830675de4..8082871b409a6d631a80b5d2327e9fcb6a1509d4 100644 (file)
@@ -160,6 +160,14 @@ static int __init init_nvs_nosave(const struct dmi_system_id *d)
        return 0;
 }
 
+static bool acpi_sleep_no_lps0;
+
+static int __init init_no_lps0(const struct dmi_system_id *d)
+{
+       acpi_sleep_no_lps0 = true;
+       return 0;
+}
+
 static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
        {
        .callback = init_old_suspend_ordering,
@@ -343,6 +351,19 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
                DMI_MATCH(DMI_PRODUCT_NAME, "80E3"),
                },
        },
+       /*
+        * https://bugzilla.kernel.org/show_bug.cgi?id=196907
+        * Some Dell XPS13 9360 cannot do suspend-to-idle using the Low Power
+        * S0 Idle firmware interface.
+        */
+       {
+       .callback = init_no_lps0,
+       .ident = "Dell XPS13 9360",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9360"),
+               },
+       },
        {},
 };
 
@@ -485,6 +506,7 @@ static void acpi_pm_end(void)
 }
 #else /* !CONFIG_ACPI_SLEEP */
 #define acpi_target_sleep_state        ACPI_STATE_S0
+#define acpi_sleep_no_lps0     (false)
 static inline void acpi_sleep_dmi_check(void) {}
 #endif /* CONFIG_ACPI_SLEEP */
 
@@ -863,6 +885,12 @@ static int lps0_device_attach(struct acpi_device *adev,
        if (lps0_device_handle)
                return 0;
 
+       if (acpi_sleep_no_lps0) {
+               acpi_handle_info(adev->handle,
+                                "Low Power S0 Idle interface disabled\n");
+               return 0;
+       }
+
        if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
                return 0;
 
index 0fd57bf33524a46938396210eabfad57226100f6..bc303df60d5dcebf336d6a7822df02fa2b8cc68a 100644 (file)
@@ -169,7 +169,8 @@ module_param_cb(debug_level, &param_ops_debug_level, &acpi_dbg_level, 0644);
 
 static char trace_method_name[1024];
 
-int param_set_trace_method_name(const char *val, const struct kernel_param *kp)
+static int param_set_trace_method_name(const char *val,
+                                      const struct kernel_param *kp)
 {
        u32 saved_flags = 0;
        bool is_abs_path = true;
index b4fbb99294828cf06900ddd7c4c908c6f28c83cb..ec5b0f190231c8b6ce6a98d99ae33347ad51054a 100644 (file)
@@ -71,18 +71,34 @@ static const struct always_present_id always_present_ids[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"),
              }),
        /*
-        * The GPD win BIOS dated 20170320 has disabled the accelerometer, the
+        * The GPD win BIOS dated 20170221 has disabled the accelerometer, the
         * drivers sometimes cause crashes under Windows and this is how the
         * manufacturer has solved this :| Note that the the DMI data is less
         * generic then it seems, a board_vendor of "AMI Corporation" is quite
         * rare and a board_name of "Default String" also is rare.
+        *
+        * Unfortunately the GPD pocket also uses these strings and its BIOS
+        * was copy-pasted from the GPD win, so it has a disabled KIOX000A
+        * node which we should not enable, thus we also check the BIOS date.
         */
+       ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+               DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+               DMI_MATCH(DMI_BOARD_NAME, "Default string"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+               DMI_MATCH(DMI_BIOS_DATE, "02/21/2017")
+             }),
        ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
                DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
                DMI_MATCH(DMI_BOARD_NAME, "Default string"),
                DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
                DMI_MATCH(DMI_BIOS_DATE, "03/20/2017")
              }),
+       ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+               DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+               DMI_MATCH(DMI_BOARD_NAME, "Default string"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+               DMI_MATCH(DMI_BIOS_DATE, "05/25/2017")
+             }),
 };
 
 bool acpi_device_always_present(struct acpi_device *adev)
index 8b61123d2c3c1cd55489feb389b68735077219d5..749fd94441b034104bc9ac87738785c43337c876 100644 (file)
@@ -303,6 +303,7 @@ struct ahci_em_priv {
        unsigned long saved_activity;
        unsigned long activity;
        unsigned long led_state;
+       struct ata_link *link;
 };
 
 struct ahci_port_priv {
index 3e286d86ab42acbc54c84488e74ffc37f13dff65..a0de7a38430c954b31c7b4e6e01a790ee98e85c2 100644 (file)
@@ -968,12 +968,12 @@ static void ahci_sw_activity(struct ata_link *link)
                mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
 }
 
-static void ahci_sw_activity_blink(unsigned long arg)
+static void ahci_sw_activity_blink(struct timer_list *t)
 {
-       struct ata_link *link = (struct ata_link *)arg;
+       struct ahci_em_priv *emp = from_timer(emp, t, timer);
+       struct ata_link *link = emp->link;
        struct ata_port *ap = link->ap;
-       struct ahci_port_priv *pp = ap->private_data;
-       struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
+
        unsigned long led_message = emp->led_state;
        u32 activity_led_state;
        unsigned long flags;
@@ -1020,7 +1020,8 @@ static void ahci_init_sw_activity(struct ata_link *link)
 
        /* init activity stats, setup timer */
        emp->saved_activity = emp->activity = 0;
-       setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
+       emp->link = link;
+       timer_setup(&emp->timer, ahci_sw_activity_blink, 0);
 
        /* check our blink policy and set flag for link if it's enabled */
        if (emp->blink_policy)
index ee4c1ec9dca0ef9e51f4abf56924aab2112d9f77..b8ac4902d3122d138e050511648e6c7a81b7c938 100644 (file)
@@ -5979,9 +5979,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        INIT_LIST_HEAD(&ap->eh_done_q);
        init_waitqueue_head(&ap->eh_wait_q);
        init_completion(&ap->park_req_pending);
-       setup_deferrable_timer(&ap->fastdrain_timer,
-                              ata_eh_fastdrain_timerfn,
-                              (unsigned long)ap);
+       timer_setup(&ap->fastdrain_timer, ata_eh_fastdrain_timerfn,
+                   TIMER_DEFERRABLE);
 
        ap->cbl = ATA_CBL_NONE;
 
index e4effef0c83f2bcea57bf5dda123b1c8ce4ed939..ece6fd91a947674f6f9c8cb46e46f5c4c22a1a86 100644 (file)
@@ -879,9 +879,9 @@ static int ata_eh_nr_in_flight(struct ata_port *ap)
        return nr;
 }
 
-void ata_eh_fastdrain_timerfn(unsigned long arg)
+void ata_eh_fastdrain_timerfn(struct timer_list *t)
 {
-       struct ata_port *ap = (void *)arg;
+       struct ata_port *ap = from_timer(ap, t, fastdrain_timer);
        unsigned long flags;
        int cnt;
 
index 839d487394b7be5ed8966c25571f75fe5b16a8b5..08a245b76417b14aec139f1b2f94833d7443002e 100644 (file)
@@ -154,7 +154,7 @@ extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
 extern void ata_eh_acquire(struct ata_port *ap);
 extern void ata_eh_release(struct ata_port *ap);
 extern void ata_scsi_error(struct Scsi_Host *host);
-extern void ata_eh_fastdrain_timerfn(unsigned long arg);
+extern void ata_eh_fastdrain_timerfn(struct timer_list *t);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
 extern void ata_dev_disable(struct ata_device *dev);
 extern void ata_eh_detach_dev(struct ata_device *dev);
index 082aa02abc5742fa68d3073b361d6afbf13ab5da..57af9fd198e4e756b4646e5153f3f51b6b741626 100644 (file)
@@ -49,8 +49,8 @@ static void idt77105_stats_timer_func(unsigned long);
 static void idt77105_restart_timer_func(unsigned long);
 
 
-static DEFINE_TIMER(stats_timer, idt77105_stats_timer_func, 0, 0);
-static DEFINE_TIMER(restart_timer, idt77105_restart_timer_func, 0, 0);
+static DEFINE_TIMER(stats_timer, idt77105_stats_timer_func);
+static DEFINE_TIMER(restart_timer, idt77105_restart_timer_func);
 static int start_timer = 1;
 static struct idt77105_priv *idt77105_all = NULL;
 
index fc72b763fdd78684f156956a5960e5abccab0090..ad6b582c268e1c2dbc6f20051eb49170b18dd8be 100644 (file)
@@ -76,7 +76,7 @@ static IADEV *ia_dev[8];
 static struct atm_dev *_ia_dev[8];
 static int iadev_count;
 static void ia_led_timer(unsigned long arg);
-static DEFINE_TIMER(ia_timer, ia_led_timer, 0, 0);
+static DEFINE_TIMER(ia_timer, ia_led_timer);
 static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ;
 static int IA_RX_BUF = DFL_RX_BUFFERS, IA_RX_BUF_SZ = DFL_RX_BUF_SZ;
 static uint IADebugFlag = /* IF_IADBG_ERR | IF_IADBG_CBR| IF_IADBG_INIT_ADAPTER
index a9020f82eea7139dbc0e3961c20c4e32f40dbb3a..db040b37822448fb75d1598d8d3a2657e9835644 100644 (file)
@@ -229,9 +229,9 @@ MODULE_DEVICE_TABLE(of, img_ascii_lcd_matches);
  * Scroll the current message along the LCD by one character, rearming the
  * timer if required.
  */
-static void img_ascii_lcd_scroll(unsigned long arg)
+static void img_ascii_lcd_scroll(struct timer_list *t)
 {
-       struct img_ascii_lcd_ctx *ctx = (struct img_ascii_lcd_ctx *)arg;
+       struct img_ascii_lcd_ctx *ctx = from_timer(ctx, t, timer);
        unsigned int i, ch = ctx->scroll_pos;
        unsigned int num_chars = ctx->cfg->num_chars;
 
@@ -299,7 +299,7 @@ static int img_ascii_lcd_display(struct img_ascii_lcd_ctx *ctx,
        ctx->scroll_pos = 0;
 
        /* update the LCD */
-       img_ascii_lcd_scroll((unsigned long)ctx);
+       img_ascii_lcd_scroll(&ctx->timer);
 
        return 0;
 }
@@ -395,9 +395,7 @@ static int img_ascii_lcd_probe(struct platform_device *pdev)
        ctx->scroll_rate = HZ / 2;
 
        /* initialise a timer for scrolling the message */
-       init_timer(&ctx->timer);
-       ctx->timer.function = img_ascii_lcd_scroll;
-       ctx->timer.data = (unsigned long)ctx;
+       timer_setup(&ctx->timer, img_ascii_lcd_scroll, 0);
 
        platform_set_drvdata(pdev, ctx);
 
index 6911acd896d935946b3c805d07c88bc03bf41918..ea7869c0d7f9f638ffb33f61d7b2b7437cd3bf41 100644 (file)
@@ -1396,7 +1396,7 @@ static void panel_process_inputs(void)
        }
 }
 
-static void panel_scan_timer(void)
+static void panel_scan_timer(struct timer_list *unused)
 {
        if (keypad.enabled && keypad_initialized) {
                if (spin_trylock_irq(&pprt_lock)) {
@@ -1421,7 +1421,7 @@ static void init_scan_timer(void)
        if (scan_timer.function)
                return;         /* already started */
 
-       setup_timer(&scan_timer, (void *)&panel_scan_timer, 0);
+       timer_setup(&scan_timer, panel_scan_timer, 0);
        scan_timer.expires = jiffies + INPUT_POLL_TIME;
        add_timer(&scan_timer);
 }
index 6df7d6676a48104267b5e739c6e58b85a00724e1..0739c5b953bf8ab1b1f48d8df9a14cc9fcb76731 100644 (file)
 #include <linux/string.h>
 #include <linux/sched/topology.h>
 
-static DEFINE_MUTEX(cpu_scale_mutex);
-static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
+DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
 
-unsigned long topology_get_cpu_scale(struct sched_domain *sd, int cpu)
+void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
+                        unsigned long max_freq)
 {
-       return per_cpu(cpu_scale, cpu);
+       unsigned long scale;
+       int i;
+
+       scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq;
+
+       for_each_cpu(i, cpus)
+               per_cpu(freq_scale, i) = scale;
 }
 
+static DEFINE_MUTEX(cpu_scale_mutex);
+DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
+
 void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity)
 {
        per_cpu(cpu_scale, cpu) = capacity;
@@ -212,6 +221,8 @@ static struct notifier_block init_cpu_capacity_notifier __initdata = {
 
 static int __init register_cpufreq_notifier(void)
 {
+       int ret;
+
        /*
         * on ACPI-based systems we need to use the default cpu capacity
         * until we have the necessary code to parse the cpu capacity, so
@@ -227,8 +238,13 @@ static int __init register_cpufreq_notifier(void)
 
        cpumask_copy(cpus_to_visit, cpu_possible_mask);
 
-       return cpufreq_register_notifier(&init_cpu_capacity_notifier,
-                                        CPUFREQ_POLICY_NOTIFIER);
+       ret = cpufreq_register_notifier(&init_cpu_capacity_notifier,
+                                       CPUFREQ_POLICY_NOTIFIER);
+
+       if (ret)
+               free_cpumask_var(cpus_to_visit);
+
+       return ret;
 }
 core_initcall(register_cpufreq_notifier);
 
@@ -236,6 +252,7 @@ static void __init parsing_done_workfn(struct work_struct *work)
 {
        cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
                                         CPUFREQ_POLICY_NOTIFIER);
+       free_cpumask_var(cpus_to_visit);
 }
 
 #else
index 12ebd055724cd6cdc01edff013583f38979fe92a..4b8ba2a75a4d1d026903616f508df41db10d3869 100644 (file)
@@ -668,7 +668,7 @@ const char *dev_driver_string(const struct device *dev)
         * so be careful about accessing it.  dev->bus and dev->class should
         * never change once they are set, so they don't need special care.
         */
-       drv = ACCESS_ONCE(dev->driver);
+       drv = READ_ONCE(dev->driver);
        return drv ? drv->name :
                        (dev->bus ? dev->bus->name :
                        (dev->class ? dev->class->name : ""));
index 321cd7b4d817fd6ffd9323362041c7d4cb29b7e9..58a9b608d8216a67f13d6c514d92290dc0a27de3 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/cpufeature.h>
 #include <linux/tick.h>
 #include <linux/pm_qos.h>
+#include <linux/sched/isolation.h>
 
 #include "base.h"
 
@@ -271,8 +272,16 @@ static ssize_t print_cpus_isolated(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
        int n = 0, len = PAGE_SIZE-2;
+       cpumask_var_t isolated;
 
-       n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(cpu_isolated_map));
+       if (!alloc_cpumask_var(&isolated, GFP_KERNEL))
+               return -ENOMEM;
+
+       cpumask_andnot(isolated, cpu_possible_mask,
+                      housekeeping_cpumask(HK_FLAG_DOMAIN));
+       n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(isolated));
+
+       free_cpumask_var(isolated);
 
        return n;
 }
@@ -377,7 +386,8 @@ int register_cpu(struct cpu *cpu, int num)
 
        per_cpu(cpu_sys_devices, num) = &cpu->dev;
        register_cpu_under_node(num, cpu_to_node(num));
-       dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
+       dev_pm_qos_expose_latency_limit(&cpu->dev,
+                                       PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
 
        return 0;
 }
index ad44b40fe2847d219e50a5d51d799f2541b5d6d0..45575e134696280b4b2de4635b9631f1737b0f58 100644 (file)
@@ -464,6 +464,7 @@ pinctrl_bind_failed:
        if (dev->pm_domain && dev->pm_domain->dismiss)
                dev->pm_domain->dismiss(dev);
        pm_runtime_reinit(dev);
+       dev_pm_set_driver_flags(dev, 0);
 
        switch (ret) {
        case -EPROBE_DEFER:
@@ -869,6 +870,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
                if (dev->pm_domain && dev->pm_domain->dismiss)
                        dev->pm_domain->dismiss(dev);
                pm_runtime_reinit(dev);
+               dev_pm_set_driver_flags(dev, 0);
 
                klist_remove(&dev->p->knode_driver);
                device_pm_check_callbacks(dev);
index 29cd71d8b360c17e310d672b1127d9793eaf248a..e1bb691cf8f14632ed40cf8d570578bf42616d91 100644 (file)
@@ -2,7 +2,6 @@
 obj-$(CONFIG_PM)       += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o
 obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
 obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
-obj-$(CONFIG_PM_OPP)   += opp/
 obj-$(CONFIG_PM_GENERIC_DOMAINS)       +=  domain.o domain_governor.o
 obj-$(CONFIG_HAVE_CLK) += clock_ops.o
 
index e8ca5e2cf1e51e5ad17b08274a26e3251fdb0f93..0c80bea05bcb92be79b90e3210fbfdbbb65d0bac 100644 (file)
@@ -124,6 +124,7 @@ static const struct genpd_lock_ops genpd_spin_ops = {
 #define genpd_status_on(genpd)         (genpd->status == GPD_STATE_ACTIVE)
 #define genpd_is_irq_safe(genpd)       (genpd->flags & GENPD_FLAG_IRQ_SAFE)
 #define genpd_is_always_on(genpd)      (genpd->flags & GENPD_FLAG_ALWAYS_ON)
+#define genpd_is_active_wakeup(genpd)  (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP)
 
 static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev,
                const struct generic_pm_domain *genpd)
@@ -237,6 +238,95 @@ static void genpd_update_accounting(struct generic_pm_domain *genpd)
 static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
 #endif
 
+/**
+ * dev_pm_genpd_set_performance_state- Set performance state of device's power
+ * domain.
+ *
+ * @dev: Device for which the performance-state needs to be set.
+ * @state: Target performance state of the device. This can be set as 0 when the
+ *        device doesn't have any performance state constraints left (And so
+ *        the device wouldn't participate anymore to find the target
+ *        performance state of the genpd).
+ *
+ * It is assumed that the users guarantee that the genpd wouldn't be detached
+ * while this routine is getting called.
+ *
+ * Returns 0 on success and negative error values on failures.
+ */
+int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
+{
+       struct generic_pm_domain *genpd;
+       struct generic_pm_domain_data *gpd_data, *pd_data;
+       struct pm_domain_data *pdd;
+       unsigned int prev;
+       int ret = 0;
+
+       genpd = dev_to_genpd(dev);
+       if (IS_ERR(genpd))
+               return -ENODEV;
+
+       if (unlikely(!genpd->set_performance_state))
+               return -EINVAL;
+
+       if (unlikely(!dev->power.subsys_data ||
+                    !dev->power.subsys_data->domain_data)) {
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       genpd_lock(genpd);
+
+       gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+       prev = gpd_data->performance_state;
+       gpd_data->performance_state = state;
+
+       /* New requested state is same as Max requested state */
+       if (state == genpd->performance_state)
+               goto unlock;
+
+       /* New requested state is higher than Max requested state */
+       if (state > genpd->performance_state)
+               goto update_state;
+
+       /* Traverse all devices within the domain */
+       list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+               pd_data = to_gpd_data(pdd);
+
+               if (pd_data->performance_state > state)
+                       state = pd_data->performance_state;
+       }
+
+       if (state == genpd->performance_state)
+               goto unlock;
+
+       /*
+        * We aren't propagating performance state changes of a subdomain to its
+        * masters as we don't have hardware that needs it. Over that, the
+        * performance states of subdomain and its masters may not have
+        * one-to-one mapping and would require additional information. We can
+        * get back to this once we have hardware that needs it. For that
+        * reason, we don't have to consider performance state of the subdomains
+        * of genpd here.
+        */
+
+update_state:
+       if (genpd_status_on(genpd)) {
+               ret = genpd->set_performance_state(genpd, state);
+               if (ret) {
+                       gpd_data->performance_state = prev;
+                       goto unlock;
+               }
+       }
+
+       genpd->performance_state = state;
+
+unlock:
+       genpd_unlock(genpd);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_set_performance_state);
+
 static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 {
        unsigned int state_idx = genpd->state_idx;
@@ -256,6 +346,15 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
                return ret;
 
        elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+
+       if (unlikely(genpd->set_performance_state)) {
+               ret = genpd->set_performance_state(genpd, genpd->performance_state);
+               if (ret) {
+                       pr_warn("%s: Failed to set performance state %d (%d)\n",
+                               genpd->name, genpd->performance_state, ret);
+               }
+       }
+
        if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
                return ret;
 
@@ -346,9 +445,7 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
        list_for_each_entry(pdd, &genpd->dev_list, list_node) {
                enum pm_qos_flags_status stat;
 
-               stat = dev_pm_qos_flags(pdd->dev,
-                                       PM_QOS_FLAG_NO_POWER_OFF
-                                               | PM_QOS_FLAG_REMOTE_WAKEUP);
+               stat = dev_pm_qos_flags(pdd->dev, PM_QOS_FLAG_NO_POWER_OFF);
                if (stat > PM_QOS_FLAGS_NONE)
                        return -EBUSY;
 
@@ -749,11 +846,7 @@ late_initcall(genpd_power_off_unused);
 
 #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_GENERIC_DOMAINS_OF)
 
-/**
- * pm_genpd_present - Check if the given PM domain has been initialized.
- * @genpd: PM domain to check.
- */
-static bool pm_genpd_present(const struct generic_pm_domain *genpd)
+static bool genpd_present(const struct generic_pm_domain *genpd)
 {
        const struct generic_pm_domain *gpd;
 
@@ -771,12 +864,6 @@ static bool pm_genpd_present(const struct generic_pm_domain *genpd)
 
 #ifdef CONFIG_PM_SLEEP
 
-static bool genpd_dev_active_wakeup(const struct generic_pm_domain *genpd,
-                                   struct device *dev)
-{
-       return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev);
-}
-
 /**
  * genpd_sync_power_off - Synchronously power off a PM domain and its masters.
  * @genpd: PM domain to power off, if possible.
@@ -863,7 +950,7 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock,
  * @genpd: PM domain the device belongs to.
  *
  * There are two cases in which a device that can wake up the system from sleep
- * states should be resumed by pm_genpd_prepare(): (1) if the device is enabled
+ * states should be resumed by genpd_prepare(): (1) if the device is enabled
  * to wake up the system and it has to remain active for this purpose while the
  * system is in the sleep state and (2) if the device is not enabled to wake up
  * the system from sleep states and it generally doesn't generate wakeup signals
@@ -881,12 +968,12 @@ static bool resume_needed(struct device *dev,
        if (!device_can_wakeup(dev))
                return false;
 
-       active_wakeup = genpd_dev_active_wakeup(genpd, dev);
+       active_wakeup = genpd_is_active_wakeup(genpd);
        return device_may_wakeup(dev) ? active_wakeup : !active_wakeup;
 }
 
 /**
- * pm_genpd_prepare - Start power transition of a device in a PM domain.
+ * genpd_prepare - Start power transition of a device in a PM domain.
  * @dev: Device to start the transition of.
  *
  * Start a power transition of a device (during a system-wide power transition)
@@ -894,7 +981,7 @@ static bool resume_needed(struct device *dev,
  * an object of type struct generic_pm_domain representing a PM domain
  * consisting of I/O devices.
  */
-static int pm_genpd_prepare(struct device *dev)
+static int genpd_prepare(struct device *dev)
 {
        struct generic_pm_domain *genpd;
        int ret;
@@ -921,7 +1008,7 @@ static int pm_genpd_prepare(struct device *dev)
        genpd_unlock(genpd);
 
        ret = pm_generic_prepare(dev);
-       if (ret) {
+       if (ret < 0) {
                genpd_lock(genpd);
 
                genpd->prepared_count--;
@@ -929,7 +1016,8 @@ static int pm_genpd_prepare(struct device *dev)
                genpd_unlock(genpd);
        }
 
-       return ret;
+       /* Never return 1, as genpd don't cope with the direct_complete path. */
+       return ret >= 0 ? 0 : ret;
 }
 
 /**
@@ -950,7 +1038,7 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
+       if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd))
                return 0;
 
        if (poweroff)
@@ -975,13 +1063,13 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff)
 }
 
 /**
- * pm_genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain.
+ * genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain.
  * @dev: Device to suspend.
  *
  * Stop the device and remove power from the domain if all devices in it have
  * been stopped.
  */
-static int pm_genpd_suspend_noirq(struct device *dev)
+static int genpd_suspend_noirq(struct device *dev)
 {
        dev_dbg(dev, "%s()\n", __func__);
 
@@ -989,12 +1077,12 @@ static int pm_genpd_suspend_noirq(struct device *dev)
 }
 
 /**
- * pm_genpd_resume_noirq - Start of resume of device in an I/O PM domain.
+ * genpd_resume_noirq - Start of resume of device in an I/O PM domain.
  * @dev: Device to resume.
  *
  * Restore power to the device's PM domain, if necessary, and start the device.
  */
-static int pm_genpd_resume_noirq(struct device *dev)
+static int genpd_resume_noirq(struct device *dev)
 {
        struct generic_pm_domain *genpd;
        int ret = 0;
@@ -1005,7 +1093,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
+       if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd))
                return 0;
 
        genpd_lock(genpd);
@@ -1024,7 +1112,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
 }
 
 /**
- * pm_genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain.
+ * genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain.
  * @dev: Device to freeze.
  *
  * Carry out a late freeze of a device under the assumption that its
@@ -1032,7 +1120,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
  * struct generic_pm_domain representing a power domain consisting of I/O
  * devices.
  */
-static int pm_genpd_freeze_noirq(struct device *dev)
+static int genpd_freeze_noirq(struct device *dev)
 {
        const struct generic_pm_domain *genpd;
        int ret = 0;
@@ -1054,13 +1142,13 @@ static int pm_genpd_freeze_noirq(struct device *dev)
 }
 
 /**
- * pm_genpd_thaw_noirq - Early thaw of device in an I/O PM domain.
+ * genpd_thaw_noirq - Early thaw of device in an I/O PM domain.
  * @dev: Device to thaw.
  *
  * Start the device, unless power has been removed from the domain already
  * before the system transition.
  */
-static int pm_genpd_thaw_noirq(struct device *dev)
+static int genpd_thaw_noirq(struct device *dev)
 {
        const struct generic_pm_domain *genpd;
        int ret = 0;
@@ -1081,14 +1169,14 @@ static int pm_genpd_thaw_noirq(struct device *dev)
 }
 
 /**
- * pm_genpd_poweroff_noirq - Completion of hibernation of device in an
+ * genpd_poweroff_noirq - Completion of hibernation of device in an
  *   I/O PM domain.
  * @dev: Device to poweroff.
  *
  * Stop the device and remove power from the domain if all devices in it have
  * been stopped.
  */
-static int pm_genpd_poweroff_noirq(struct device *dev)
+static int genpd_poweroff_noirq(struct device *dev)
 {
        dev_dbg(dev, "%s()\n", __func__);
 
@@ -1096,13 +1184,13 @@ static int pm_genpd_poweroff_noirq(struct device *dev)
 }
 
 /**
- * pm_genpd_restore_noirq - Start of restore of device in an I/O PM domain.
+ * genpd_restore_noirq - Start of restore of device in an I/O PM domain.
  * @dev: Device to resume.
  *
  * Make sure the domain will be in the same power state as before the
  * hibernation the system is resuming from and start the device if necessary.
  */
-static int pm_genpd_restore_noirq(struct device *dev)
+static int genpd_restore_noirq(struct device *dev)
 {
        struct generic_pm_domain *genpd;
        int ret = 0;
@@ -1139,7 +1227,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
 }
 
 /**
- * pm_genpd_complete - Complete power transition of a device in a power domain.
+ * genpd_complete - Complete power transition of a device in a power domain.
  * @dev: Device to complete the transition of.
  *
  * Complete a power transition of a device (during a system-wide power
@@ -1147,7 +1235,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
  * domain member of an object of type struct generic_pm_domain representing
  * a power domain consisting of I/O devices.
  */
-static void pm_genpd_complete(struct device *dev)
+static void genpd_complete(struct device *dev)
 {
        struct generic_pm_domain *genpd;
 
@@ -1180,7 +1268,7 @@ static void genpd_syscore_switch(struct device *dev, bool suspend)
        struct generic_pm_domain *genpd;
 
        genpd = dev_to_genpd(dev);
-       if (!pm_genpd_present(genpd))
+       if (!genpd_present(genpd))
                return;
 
        if (suspend) {
@@ -1206,14 +1294,14 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron);
 
 #else /* !CONFIG_PM_SLEEP */
 
-#define pm_genpd_prepare               NULL
-#define pm_genpd_suspend_noirq         NULL
-#define pm_genpd_resume_noirq          NULL
-#define pm_genpd_freeze_noirq          NULL
-#define pm_genpd_thaw_noirq            NULL
-#define pm_genpd_poweroff_noirq                NULL
-#define pm_genpd_restore_noirq         NULL
-#define pm_genpd_complete              NULL
+#define genpd_prepare          NULL
+#define genpd_suspend_noirq    NULL
+#define genpd_resume_noirq     NULL
+#define genpd_freeze_noirq     NULL
+#define genpd_thaw_noirq       NULL
+#define genpd_poweroff_noirq   NULL
+#define genpd_restore_noirq    NULL
+#define genpd_complete         NULL
 
 #endif /* CONFIG_PM_SLEEP */
 
@@ -1239,7 +1327,7 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
 
        gpd_data->base.dev = dev;
        gpd_data->td.constraint_changed = true;
-       gpd_data->td.effective_constraint_ns = -1;
+       gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
        gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
 
        spin_lock_irq(&dev->power.lock);
@@ -1574,14 +1662,14 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
        genpd->accounting_time = ktime_get();
        genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
        genpd->domain.ops.runtime_resume = genpd_runtime_resume;
-       genpd->domain.ops.prepare = pm_genpd_prepare;
-       genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq;
-       genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq;
-       genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
-       genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
-       genpd->domain.ops.poweroff_noirq = pm_genpd_poweroff_noirq;
-       genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
-       genpd->domain.ops.complete = pm_genpd_complete;
+       genpd->domain.ops.prepare = genpd_prepare;
+       genpd->domain.ops.suspend_noirq = genpd_suspend_noirq;
+       genpd->domain.ops.resume_noirq = genpd_resume_noirq;
+       genpd->domain.ops.freeze_noirq = genpd_freeze_noirq;
+       genpd->domain.ops.thaw_noirq = genpd_thaw_noirq;
+       genpd->domain.ops.poweroff_noirq = genpd_poweroff_noirq;
+       genpd->domain.ops.restore_noirq = genpd_restore_noirq;
+       genpd->domain.ops.complete = genpd_complete;
 
        if (genpd->flags & GENPD_FLAG_PM_CLK) {
                genpd->dev_ops.stop = pm_clk_suspend;
@@ -1795,7 +1883,7 @@ int of_genpd_add_provider_simple(struct device_node *np,
 
        mutex_lock(&gpd_list_lock);
 
-       if (pm_genpd_present(genpd)) {
+       if (genpd_present(genpd)) {
                ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
                if (!ret) {
                        genpd->provider = &np->fwnode;
@@ -1831,7 +1919,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
        for (i = 0; i < data->num_domains; i++) {
                if (!data->domains[i])
                        continue;
-               if (!pm_genpd_present(data->domains[i]))
+               if (!genpd_present(data->domains[i]))
                        goto error;
 
                data->domains[i]->provider = &np->fwnode;
@@ -2274,7 +2362,7 @@ EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/kobject.h>
-static struct dentry *pm_genpd_debugfs_dir;
+static struct dentry *genpd_debugfs_dir;
 
 /*
  * TODO: This function is a slightly modified version of rtpm_status_show
@@ -2302,8 +2390,8 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
        seq_puts(s, p);
 }
 
-static int pm_genpd_summary_one(struct seq_file *s,
-                               struct generic_pm_domain *genpd)
+static int genpd_summary_one(struct seq_file *s,
+                       struct generic_pm_domain *genpd)
 {
        static const char * const status_lookup[] = {
                [GPD_STATE_ACTIVE] = "on",
@@ -2373,7 +2461,7 @@ static int genpd_summary_show(struct seq_file *s, void *data)
                return -ERESTARTSYS;
 
        list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
-               ret = pm_genpd_summary_one(s, genpd);
+               ret = genpd_summary_one(s, genpd);
                if (ret)
                        break;
        }
@@ -2559,23 +2647,23 @@ define_genpd_debugfs_fops(active_time);
 define_genpd_debugfs_fops(total_idle_time);
 define_genpd_debugfs_fops(devices);
 
-static int __init pm_genpd_debug_init(void)
+static int __init genpd_debug_init(void)
 {
        struct dentry *d;
        struct generic_pm_domain *genpd;
 
-       pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
+       genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
 
-       if (!pm_genpd_debugfs_dir)
+       if (!genpd_debugfs_dir)
                return -ENOMEM;
 
        d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
-                       pm_genpd_debugfs_dir, NULL, &genpd_summary_fops);
+                       genpd_debugfs_dir, NULL, &genpd_summary_fops);
        if (!d)
                return -ENOMEM;
 
        list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
-               d = debugfs_create_dir(genpd->name, pm_genpd_debugfs_dir);
+               d = debugfs_create_dir(genpd->name, genpd_debugfs_dir);
                if (!d)
                        return -ENOMEM;
 
@@ -2595,11 +2683,11 @@ static int __init pm_genpd_debug_init(void)
 
        return 0;
 }
-late_initcall(pm_genpd_debug_init);
+late_initcall(genpd_debug_init);
 
-static void __exit pm_genpd_debug_exit(void)
+static void __exit genpd_debug_exit(void)
 {
-       debugfs_remove_recursive(pm_genpd_debugfs_dir);
+       debugfs_remove_recursive(genpd_debugfs_dir);
 }
-__exitcall(pm_genpd_debug_exit);
+__exitcall(genpd_debug_exit);
 #endif /* CONFIG_DEBUG_FS */
index 281f949c5ffeb22828e0363c6c4c302c7635eb92..99896fbf18e439003095ccf18f2689ec6b7c1be3 100644 (file)
 static int dev_update_qos_constraint(struct device *dev, void *data)
 {
        s64 *constraint_ns_p = data;
-       s32 constraint_ns = -1;
+       s64 constraint_ns;
 
-       if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
+       if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
+               /*
+                * Only take suspend-time QoS constraints of devices into
+                * account, because constraints updated after the device has
+                * been suspended are not guaranteed to be taken into account
+                * anyway.  In order for them to take effect, the device has to
+                * be resumed and suspended again.
+                */
                constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
-
-       if (constraint_ns < 0) {
+       } else {
+               /*
+                * The child is not in a domain and there's no info on its
+                * suspend/resume latencies, so assume them to be negligible and
+                * 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 *= NSEC_PER_USEC;
        }
-       if (constraint_ns == 0)
-               return 0;
 
-       /*
-        * constraint_ns cannot be negative here, because the device has been
-        * suspended.
-        */
-       if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+       if (constraint_ns < *constraint_ns_p)
                *constraint_ns_p = constraint_ns;
 
        return 0;
@@ -58,12 +64,12 @@ static bool default_suspend_ok(struct device *dev)
        }
        td->constraint_changed = false;
        td->cached_suspend_ok = false;
-       td->effective_constraint_ns = -1;
+       td->effective_constraint_ns = 0;
        constraint_ns = __dev_pm_qos_read_value(dev);
 
        spin_unlock_irqrestore(&dev->power.lock, flags);
 
-       if (constraint_ns < 0)
+       if (constraint_ns == 0)
                return false;
 
        constraint_ns *= NSEC_PER_USEC;
@@ -76,14 +82,32 @@ static bool default_suspend_ok(struct device *dev)
                device_for_each_child(dev, &constraint_ns,
                                      dev_update_qos_constraint);
 
-       if (constraint_ns > 0) {
+       if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
+               /* "No restriction", so the device is allowed to suspend. */
+               td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
+               td->cached_suspend_ok = true;
+       } else if (constraint_ns == 0) {
+               /*
+                * This triggers if one of the children that don't belong to a
+                * domain has a zero PM QoS constraint and it's better not to
+                * suspend then.  effective_constraint_ns is zero already and
+                * cached_suspend_ok is false, so bail out.
+                */
+               return false;
+       } else {
                constraint_ns -= td->suspend_latency_ns +
                                td->resume_latency_ns;
-               if (constraint_ns == 0)
+               /*
+                * effective_constraint_ns is zero already and cached_suspend_ok
+                * is false, so if the computed value is not positive, return
+                * right away.
+                */
+               if (constraint_ns <= 0)
                        return false;
+
+               td->effective_constraint_ns = constraint_ns;
+               td->cached_suspend_ok = true;
        }
-       td->effective_constraint_ns = constraint_ns;
-       td->cached_suspend_ok = constraint_ns >= 0;
 
        /*
         * The children have been suspended already, so we don't need to take
@@ -144,18 +168,13 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
                 */
                td = &to_gpd_data(pdd)->td;
                constraint_ns = td->effective_constraint_ns;
-               /* default_suspend_ok() need not be called before us. */
-               if (constraint_ns < 0) {
-                       constraint_ns = dev_pm_qos_read_value(pdd->dev);
-                       constraint_ns *= NSEC_PER_USEC;
-               }
-               if (constraint_ns == 0)
-                       continue;
-
                /*
-                * constraint_ns cannot be negative here, because the device has
-                * been suspended.
+                * Zero means "no suspend at all" and this runs only when all
+                * devices in the domain are suspended, so it must be positive.
                 */
+               if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
+                       continue;
+
                if (constraint_ns <= off_on_time_ns)
                        return false;
 
index 07c3c4a9522d4e6bec1f0f540bd38f8c1ce6ed00..b2ed606265a8115a689ecf84979dc16f4dda645c 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/export.h>
-#include <linux/suspend.h>
 
 #ifdef CONFIG_PM
 /**
@@ -298,26 +297,4 @@ void pm_generic_complete(struct device *dev)
        if (drv && drv->pm && drv->pm->complete)
                drv->pm->complete(dev);
 }
-
-/**
- * pm_complete_with_resume_check - Complete a device power transition.
- * @dev: Device to handle.
- *
- * Complete a device power transition during a system-wide power transition and
- * optionally schedule a runtime resume of the device if the system resume in
- * progress has been initated by the platform firmware and the device had its
- * power.direct_complete flag set.
- */
-void pm_complete_with_resume_check(struct device *dev)
-{
-       pm_generic_complete(dev);
-       /*
-        * If the device had been runtime-suspended before the system went into
-        * the sleep state it is going out of and it has never been resumed till
-        * now, resume it in case the firmware powered it up.
-        */
-       if (dev->power.direct_complete && pm_resume_via_firmware())
-               pm_request_resume(dev);
-}
-EXPORT_SYMBOL_GPL(pm_complete_with_resume_check);
 #endif /* CONFIG_PM_SLEEP */
index 770b1539a083d111ba1a65b569d3a75eaa81dd38..db2f044159274a35457f4f1e5b3a55d226f08cd2 100644 (file)
@@ -478,9 +478,9 @@ struct dpm_watchdog {
  * There's not much we can do here to recover so panic() to
  * capture a crash-dump in pstore.
  */
-static void dpm_watchdog_handler(unsigned long data)
+static void dpm_watchdog_handler(struct timer_list *t)
 {
-       struct dpm_watchdog *wd = (void *)data;
+       struct dpm_watchdog *wd = from_timer(wd, t, timer);
 
        dev_emerg(wd->dev, "**** DPM device timeout ****\n");
        show_stack(wd->tsk, NULL);
@@ -500,11 +500,9 @@ static void dpm_watchdog_set(struct dpm_watchdog *wd, struct device *dev)
        wd->dev = dev;
        wd->tsk = current;
 
-       init_timer_on_stack(timer);
+       timer_setup_on_stack(timer, dpm_watchdog_handler, 0);
        /* use same timeout value for both suspend and resume */
        timer->expires = jiffies + HZ * CONFIG_DPM_WATCHDOG_TIMEOUT;
-       timer->function = dpm_watchdog_handler;
-       timer->data = (unsigned long)wd;
        add_timer(timer);
 }
 
@@ -528,7 +526,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
 /*------------------------- Resume routines -------------------------*/
 
 /**
- * device_resume_noirq - Execute an "early resume" callback for given device.
+ * device_resume_noirq - Execute a "noirq resume" callback for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
  * @async: If true, the device is being resumed asynchronously.
@@ -848,16 +846,10 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
                goto Driver;
        }
 
-       if (dev->class) {
-               if (dev->class->pm) {
-                       info = "class ";
-                       callback = pm_op(dev->class->pm, state);
-                       goto Driver;
-               } else if (dev->class->resume) {
-                       info = "legacy class ";
-                       callback = dev->class->resume;
-                       goto End;
-               }
+       if (dev->class && dev->class->pm) {
+               info = "class ";
+               callback = pm_op(dev->class->pm, state);
+               goto Driver;
        }
 
        if (dev->bus) {
@@ -1083,7 +1075,7 @@ static pm_message_t resume_event(pm_message_t sleep_state)
 }
 
 /**
- * device_suspend_noirq - Execute a "late suspend" callback for given device.
+ * __device_suspend_noirq - Execute a "noirq suspend" callback for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
  * @async: If true, the device is being suspended asynchronously.
@@ -1243,7 +1235,7 @@ int dpm_suspend_noirq(pm_message_t state)
 }
 
 /**
- * device_suspend_late - Execute a "late suspend" callback for given device.
+ * __device_suspend_late - Execute a "late suspend" callback for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
  * @async: If true, the device is being suspended asynchronously.
@@ -1445,7 +1437,7 @@ static void dpm_clear_suppliers_direct_complete(struct device *dev)
 }
 
 /**
- * device_suspend - Execute "suspend" callbacks for given device.
+ * __device_suspend - Execute "suspend" callbacks for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
  * @async: If true, the device is being suspended asynchronously.
@@ -1508,17 +1500,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                goto Run;
        }
 
-       if (dev->class) {
-               if (dev->class->pm) {
-                       info = "class ";
-                       callback = pm_op(dev->class->pm, state);
-                       goto Run;
-               } else if (dev->class->suspend) {
-                       pm_dev_dbg(dev, state, "legacy class ");
-                       error = legacy_suspend(dev, state, dev->class->suspend,
-                                               "legacy class ");
-                       goto End;
-               }
+       if (dev->class && dev->class->pm) {
+               info = "class ";
+               callback = pm_op(dev->class->pm, state);
+               goto Run;
        }
 
        if (dev->bus) {
@@ -1665,6 +1650,9 @@ static int device_prepare(struct device *dev, pm_message_t state)
        if (dev->power.syscore)
                return 0;
 
+       WARN_ON(dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) &&
+               !pm_runtime_enabled(dev));
+
        /*
         * If a device's parent goes into runtime suspend at the wrong time,
         * it won't be possible to resume the device.  To prevent this we
@@ -1713,7 +1701,9 @@ unlock:
         * applies to suspend transitions, however.
         */
        spin_lock_irq(&dev->power.lock);
-       dev->power.direct_complete = ret > 0 && state.event == PM_EVENT_SUSPEND;
+       dev->power.direct_complete = state.event == PM_EVENT_SUSPEND &&
+               pm_runtime_suspended(dev) && ret > 0 &&
+               !dev_pm_test_driver_flags(dev, DPM_FLAG_NEVER_SKIP);
        spin_unlock_irq(&dev->power.lock);
        return 0;
 }
@@ -1862,11 +1852,16 @@ void device_pm_check_callbacks(struct device *dev)
        dev->power.no_pm_callbacks =
                (!dev->bus || (pm_ops_is_empty(dev->bus->pm) &&
                 !dev->bus->suspend && !dev->bus->resume)) &&
-               (!dev->class || (pm_ops_is_empty(dev->class->pm) &&
-                !dev->class->suspend && !dev->class->resume)) &&
+               (!dev->class || pm_ops_is_empty(dev->class->pm)) &&
                (!dev->type || pm_ops_is_empty(dev->type->pm)) &&
                (!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) &&
                (!dev->driver || (pm_ops_is_empty(dev->driver->pm) &&
                 !dev->driver->suspend && !dev->driver->resume));
        spin_unlock_irq(&dev->power.lock);
 }
+
+bool dev_pm_smart_suspend_and_suspended(struct device *dev)
+{
+       return dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) &&
+               pm_runtime_status_suspended(dev);
+}
index 277d43a83f53e8dc011184ebaf6c783c02f7395b..3382542b39b77fc0af6676f7be940f4d0a5c331f 100644 (file)
@@ -139,6 +139,9 @@ static int apply_constraint(struct dev_pm_qos_request *req,
 
        switch(req->type) {
        case DEV_PM_QOS_RESUME_LATENCY:
+               if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
+                       value = 0;
+
                ret = pm_qos_update_target(&qos->resume_latency,
                                           &req->data.pnode, action, value);
                break;
@@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
        plist_head_init(&c->list);
        c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
        c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
-       c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+       c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
        c->type = PM_QOS_MIN;
        c->notifiers = n;
 
index 7bcf80fa9adad4d45b42d3c0eec10d9425dabbe0..2362b9e9701ec6a9a1b9f8fcbd70acf18ea2ec25 100644 (file)
@@ -134,11 +134,11 @@ unsigned long pm_runtime_autosuspend_expiration(struct device *dev)
        if (!dev->power.use_autosuspend)
                goto out;
 
-       autosuspend_delay = ACCESS_ONCE(dev->power.autosuspend_delay);
+       autosuspend_delay = READ_ONCE(dev->power.autosuspend_delay);
        if (autosuspend_delay < 0)
                goto out;
 
-       last_busy = ACCESS_ONCE(dev->power.last_busy);
+       last_busy = READ_ONCE(dev->power.last_busy);
        elapsed = jiffies - last_busy;
        if (elapsed < 0)
                goto out;       /* jiffies has wrapped around. */
@@ -253,7 +253,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_read_value(dev) == 0)
                retval = -EPERM;
        else if (dev->power.runtime_status == RPM_SUSPENDED)
                retval = 1;
@@ -894,9 +894,9 @@ static void pm_runtime_work(struct work_struct *work)
  *
  * Check if the time is right and queue a suspend request.
  */
-static void pm_suspend_timer_fn(unsigned long data)
+static void pm_suspend_timer_fn(struct timer_list *t)
 {
-       struct device *dev = (struct device *)data;
+       struct device *dev = from_timer(dev, t, power.suspend_timer);
        unsigned long flags;
        unsigned long expires;
 
@@ -1499,8 +1499,7 @@ void pm_runtime_init(struct device *dev)
        INIT_WORK(&dev->power.work, pm_runtime_work);
 
        dev->power.timer_expires = 0;
-       setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
-                       (unsigned long)dev);
+       timer_setup(&dev->power.suspend_timer, pm_suspend_timer_fn, 0);
 
        init_waitqueue_head(&dev->power.wait_queue);
 }
index 156ab57bca7715238571165b14e23d54ebbbd23a..e153e28b1857b84e3bf6fdf2bec2456d141b79e2 100644 (file)
@@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_show(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
 {
-       return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
+       s32 value = dev_pm_qos_requested_resume_latency(dev);
+
+       if (value == 0)
+               return sprintf(buf, "n/a\n");
+       else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+               value = 0;
+
+       return sprintf(buf, "%d\n", value);
 }
 
 static ssize_t pm_qos_resume_latency_store(struct device *dev,
@@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_store(struct device *dev,
        s32 value;
        int ret;
 
-       if (kstrtos32(buf, 0, &value))
-               return -EINVAL;
+       if (!kstrtos32(buf, 0, &value)) {
+               /*
+                * Prevent users from writing negative or "no constraint" values
+                * directly.
+                */
+               if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+                       return -EINVAL;
 
-       if (value < 0)
+               if (value == 0)
+                       value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+       } else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
+               value = 0;
+       } else {
                return -EINVAL;
+       }
 
        ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
                                        value);
@@ -309,33 +326,6 @@ static ssize_t pm_qos_no_power_off_store(struct device *dev,
 static DEVICE_ATTR(pm_qos_no_power_off, 0644,
                   pm_qos_no_power_off_show, pm_qos_no_power_off_store);
 
-static ssize_t pm_qos_remote_wakeup_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev)
-                                       & PM_QOS_FLAG_REMOTE_WAKEUP));
-}
-
-static ssize_t pm_qos_remote_wakeup_store(struct device *dev,
-                                         struct device_attribute *attr,
-                                         const char *buf, size_t n)
-{
-       int ret;
-
-       if (kstrtoint(buf, 0, &ret))
-               return -EINVAL;
-
-       if (ret != 0 && ret != 1)
-               return -EINVAL;
-
-       ret = dev_pm_qos_update_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP, ret);
-       return ret < 0 ? ret : n;
-}
-
-static DEVICE_ATTR(pm_qos_remote_wakeup, 0644,
-                  pm_qos_remote_wakeup_show, pm_qos_remote_wakeup_store);
-
 #ifdef CONFIG_PM_SLEEP
 static const char _enabled[] = "enabled";
 static const char _disabled[] = "disabled";
@@ -671,7 +661,6 @@ static const struct attribute_group pm_qos_latency_tolerance_attr_group = {
 
 static struct attribute *pm_qos_flags_attrs[] = {
        &dev_attr_pm_qos_no_power_off.attr,
-       &dev_attr_pm_qos_remote_wakeup.attr,
        NULL,
 };
 static const struct attribute_group pm_qos_flags_attr_group = {
index cdd6f256da597cb2abad069538d09723b2250d87..680ee1d36ac9a7f31b182b977f062aed1a590c8b 100644 (file)
@@ -54,7 +54,7 @@ static unsigned int saved_count;
 
 static DEFINE_SPINLOCK(events_lock);
 
-static void pm_wakeup_timer_fn(unsigned long data);
+static void pm_wakeup_timer_fn(struct timer_list *t);
 
 static LIST_HEAD(wakeup_sources);
 
@@ -176,7 +176,7 @@ void wakeup_source_add(struct wakeup_source *ws)
                return;
 
        spin_lock_init(&ws->lock);
-       setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
+       timer_setup(&ws->timer, pm_wakeup_timer_fn, 0);
        ws->active = false;
        ws->last_time = ktime_get();
 
@@ -481,8 +481,7 @@ static bool wakeup_source_not_registered(struct wakeup_source *ws)
         * Use timer struct to check if the given source is initialized
         * by wakeup_source_add.
         */
-       return ws->timer.function != pm_wakeup_timer_fn ||
-                  ws->timer.data != (unsigned long)ws;
+       return ws->timer.function != (TIMER_FUNC_TYPE)pm_wakeup_timer_fn;
 }
 
 /*
@@ -724,9 +723,9 @@ EXPORT_SYMBOL_GPL(pm_relax);
  * in @data if it is currently active and its timer has not been canceled and
  * the expiration time of the timer is not in future.
  */
-static void pm_wakeup_timer_fn(unsigned long data)
+static void pm_wakeup_timer_fn(struct timer_list *t)
 {
-       struct wakeup_source *ws = (struct wakeup_source *)data;
+       struct wakeup_source *ws = from_timer(ws, t, timer);
        unsigned long flags;
 
        spin_lock_irqsave(&ws->lock, flags);
index 0368fd7b3a414796f78db5e5d91788a3069358ca..3a1535d812d8c9d393338c30444cc64bb7d09651 100644 (file)
@@ -6,6 +6,7 @@
 config REGMAP
        default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
        select IRQ_DOMAIN if REGMAP_IRQ
+       select REGMAP_HWSPINLOCK if HWSPINLOCK=y
        bool
 
 config REGCACHE_COMPRESSED
@@ -37,3 +38,6 @@ config REGMAP_MMIO
 
 config REGMAP_IRQ
        bool
+
+config REGMAP_HWSPINLOCK
+       bool
index 2a4435d760289118f00882fb89693346972ae996..8641183cac2ff35ae883b8913b00831fa3a5af8a 100644 (file)
@@ -157,6 +157,8 @@ struct regmap {
 
        struct rb_root range_tree;
        void *selector_work_buf;        /* Scratch buffer used for selector */
+
+       struct hwspinlock *hwlock;
 };
 
 struct regcache_ops {
index edd9a839d004dcf98ab46b15c9002c958ad6fe56..c7150dd264d5806ca2fd0581b7c972c79949920e 100644 (file)
@@ -102,7 +102,7 @@ static int regmap_spi_read(void *context,
        return spi_write_then_read(spi, reg, reg_size, val, val_size);
 }
 
-static struct regmap_bus regmap_spi = {
+static const struct regmap_bus regmap_spi = {
        .write = regmap_spi_write,
        .gather_write = regmap_spi_gather_write,
        .async_write = regmap_spi_async_write,
index 4a36e415e938560ce2e3ba927b81888444767a7d..0bfb8ed244d50c054f3a1d88d78a32ea942930eb 100644 (file)
@@ -83,7 +83,7 @@ static int regmap_spmi_base_write(void *context, const void *data,
                                             count - 1);
 }
 
-static struct regmap_bus regmap_spmi_base = {
+static const struct regmap_bus regmap_spmi_base = {
        .read                           = regmap_spmi_base_read,
        .write                          = regmap_spmi_base_write,
        .gather_write                   = regmap_spmi_base_gather_write,
@@ -203,7 +203,7 @@ static int regmap_spmi_ext_write(void *context, const void *data,
                                            count - 2);
 }
 
-static struct regmap_bus regmap_spmi_ext = {
+static const struct regmap_bus regmap_spmi_ext = {
        .read                           = regmap_spmi_ext_read,
        .write                          = regmap_spmi_ext_write,
        .gather_write                   = regmap_spmi_ext_gather_write,
index b9a779a4a739cda497351be2b2dc51d69f35c022..8d516a9bfc01722567588523b92e7fdcc2b75339 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/log2.h>
+#include <linux/hwspinlock.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -413,6 +414,51 @@ static unsigned int regmap_parse_64_native(const void *buf)
 }
 #endif
 
+#ifdef REGMAP_HWSPINLOCK
+static void regmap_lock_hwlock(void *__map)
+{
+       struct regmap *map = __map;
+
+       hwspin_lock_timeout(map->hwlock, UINT_MAX);
+}
+
+static void regmap_lock_hwlock_irq(void *__map)
+{
+       struct regmap *map = __map;
+
+       hwspin_lock_timeout_irq(map->hwlock, UINT_MAX);
+}
+
+static void regmap_lock_hwlock_irqsave(void *__map)
+{
+       struct regmap *map = __map;
+
+       hwspin_lock_timeout_irqsave(map->hwlock, UINT_MAX,
+                                   &map->spinlock_flags);
+}
+
+static void regmap_unlock_hwlock(void *__map)
+{
+       struct regmap *map = __map;
+
+       hwspin_unlock(map->hwlock);
+}
+
+static void regmap_unlock_hwlock_irq(void *__map)
+{
+       struct regmap *map = __map;
+
+       hwspin_unlock_irq(map->hwlock);
+}
+
+static void regmap_unlock_hwlock_irqrestore(void *__map)
+{
+       struct regmap *map = __map;
+
+       hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags);
+}
+#endif
+
 static void regmap_lock_mutex(void *__map)
 {
        struct regmap *map = __map;
@@ -627,6 +673,34 @@ struct regmap *__regmap_init(struct device *dev,
                map->lock = config->lock;
                map->unlock = config->unlock;
                map->lock_arg = config->lock_arg;
+       } else if (config->hwlock_id) {
+#ifdef REGMAP_HWSPINLOCK
+               map->hwlock = hwspin_lock_request_specific(config->hwlock_id);
+               if (!map->hwlock) {
+                       ret = -ENXIO;
+                       goto err_map;
+               }
+
+               switch (config->hwlock_mode) {
+               case HWLOCK_IRQSTATE:
+                       map->lock = regmap_lock_hwlock_irqsave;
+                       map->unlock = regmap_unlock_hwlock_irqrestore;
+                       break;
+               case HWLOCK_IRQ:
+                       map->lock = regmap_lock_hwlock_irq;
+                       map->unlock = regmap_unlock_hwlock_irq;
+                       break;
+               default:
+                       map->lock = regmap_lock_hwlock;
+                       map->unlock = regmap_unlock_hwlock;
+                       break;
+               }
+
+               map->lock_arg = map;
+#else
+               ret = -EINVAL;
+               goto err_map;
+#endif
        } else {
                if ((bus && bus->fast_io) ||
                    config->fast_io) {
@@ -729,7 +803,7 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.format_write = regmap_format_2_6_write;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 
@@ -739,7 +813,7 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.format_write = regmap_format_4_12_write;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 
@@ -749,7 +823,7 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.format_write = regmap_format_7_9_write;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 
@@ -759,7 +833,7 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.format_write = regmap_format_10_14_write;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 
@@ -779,13 +853,13 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.format_reg = regmap_format_16_native;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 
        case 24:
                if (reg_endian != REGMAP_ENDIAN_BIG)
-                       goto err_map;
+                       goto err_hwlock;
                map->format.format_reg = regmap_format_24;
                break;
 
@@ -801,7 +875,7 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.format_reg = regmap_format_32_native;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 
@@ -818,13 +892,13 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.format_reg = regmap_format_64_native;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 #endif
 
        default:
-               goto err_map;
+               goto err_hwlock;
        }
 
        if (val_endian == REGMAP_ENDIAN_NATIVE)
@@ -853,12 +927,12 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.parse_val = regmap_parse_16_native;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
        case 24:
                if (val_endian != REGMAP_ENDIAN_BIG)
-                       goto err_map;
+                       goto err_hwlock;
                map->format.format_val = regmap_format_24;
                map->format.parse_val = regmap_parse_24;
                break;
@@ -879,7 +953,7 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.parse_val = regmap_parse_32_native;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 #ifdef CONFIG_64BIT
@@ -900,7 +974,7 @@ struct regmap *__regmap_init(struct device *dev,
                        map->format.parse_val = regmap_parse_64_native;
                        break;
                default:
-                       goto err_map;
+                       goto err_hwlock;
                }
                break;
 #endif
@@ -909,18 +983,18 @@ struct regmap *__regmap_init(struct device *dev,
        if (map->format.format_write) {
                if ((reg_endian != REGMAP_ENDIAN_BIG) ||
                    (val_endian != REGMAP_ENDIAN_BIG))
-                       goto err_map;
+                       goto err_hwlock;
                map->use_single_write = true;
        }
 
        if (!map->format.format_write &&
            !(map->format.format_reg && map->format.format_val))
-               goto err_map;
+               goto err_hwlock;
 
        map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL);
        if (map->work_buf == NULL) {
                ret = -ENOMEM;
-               goto err_map;
+               goto err_hwlock;
        }
 
        if (map->format.format_write) {
@@ -1041,6 +1115,9 @@ err_regcache:
 err_range:
        regmap_range_exit(map);
        kfree(map->work_buf);
+err_hwlock:
+       if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock)
+               hwspin_lock_free(map->hwlock);
 err_map:
        kfree(map);
 err:
@@ -1228,6 +1305,8 @@ void regmap_exit(struct regmap *map)
                kfree(async->work_buf);
                kfree(async);
        }
+       if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock)
+               hwspin_lock_free(map->hwlock);
        kfree(map);
 }
 EXPORT_SYMBOL_GPL(regmap_exit);
index 49908c74bfcb0fae9eb30f84d969a4c520192e39..4e3fb9f104aff36a575828d17d72cabf5ed5ea00 100644 (file)
@@ -323,7 +323,7 @@ static void fd_deselect (int drive)
 
 }
 
-static void motor_on_callback(unsigned long nr)
+static void motor_on_callback(unsigned long ignored)
 {
        if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) {
                complete_all(&motor_on_completion);
@@ -344,7 +344,6 @@ static int fd_motor_on(int nr)
                fd_select(nr);
 
                reinit_completion(&motor_on_completion);
-               motor_on_timer.data = nr;
                mod_timer(&motor_on_timer, jiffies + HZ/2);
 
                on_attempts = 10;
index 4b987c2fefbe5ececb3ded4002c3075167a3082c..25148206697775f3444d677b29302a35e0fe5a04 100644 (file)
@@ -15,49 +15,19 @@ MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>");
 MODULE_DESCRIPTION("AoE block/char driver for 2.6.2 and newer 2.6 kernels");
 MODULE_VERSION(VERSION);
 
-enum { TINIT, TRUN, TKILL };
+static struct timer_list timer;
 
-static void
-discover_timer(ulong vp)
+static void discover_timer(struct timer_list *t)
 {
-       static struct timer_list t;
-       static volatile ulong die;
-       static spinlock_t lock;
-       ulong flags;
-       enum { DTIMERTICK = HZ * 60 }; /* one minute */
-
-       switch (vp) {
-       case TINIT:
-               init_timer(&t);
-               spin_lock_init(&lock);
-               t.data = TRUN;
-               t.function = discover_timer;
-               die = 0;
-       case TRUN:
-               spin_lock_irqsave(&lock, flags);
-               if (!die) {
-                       t.expires = jiffies + DTIMERTICK;
-                       add_timer(&t);
-               }
-               spin_unlock_irqrestore(&lock, flags);
-
-               aoecmd_cfg(0xffff, 0xff);
-               return;
-       case TKILL:
-               spin_lock_irqsave(&lock, flags);
-               die = 1;
-               spin_unlock_irqrestore(&lock, flags);
+       mod_timer(t, jiffies + HZ * 60); /* one minute */
 
-               del_timer_sync(&t);
-       default:
-               return;
-       }
+       aoecmd_cfg(0xffff, 0xff);
 }
 
 static void
 aoe_exit(void)
 {
-       discover_timer(TKILL);
+       del_timer_sync(&timer);
 
        aoenet_exit();
        unregister_blkdev(AOE_MAJOR, DEVICE_NAME);
@@ -93,7 +63,9 @@ aoe_init(void)
                goto blkreg_fail;
        }
        printk(KERN_INFO "aoe: AoE v%s initialised.\n", VERSION);
-       discover_timer(TINIT);
+
+       timer_setup(&timer, discover_timer, 0);
+       discover_timer(&timer);
        return 0;
  blkreg_fail:
        aoecmd_exit();
index 92da886180aa10a994e01139c53d94130672343c..ae596e55bcb67c18594477b7f8b27ec02d82fcc6 100644 (file)
@@ -373,10 +373,10 @@ static void floppy_release(struct gendisk *disk, fmode_t mode);
 
 /************************* End of Prototypes **************************/
 
-static DEFINE_TIMER(motor_off_timer, fd_motor_off_timer, 0, 0);
-static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0);
-static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0);
-static DEFINE_TIMER(fd_timer, check_change, 0, 0);
+static DEFINE_TIMER(motor_off_timer, fd_motor_off_timer);
+static DEFINE_TIMER(readtrack_timer, fd_readtrack_check);
+static DEFINE_TIMER(timeout_timer, fd_times_out);
+static DEFINE_TIMER(fd_timer, check_change);
        
 static void fd_end_request_cur(blk_status_t err)
 {
index 7e8589ce631c72d9e023abb63cbe5680938c8f49..06ecee1b528ec1b457cc04124d34626eb3477878 100644 (file)
@@ -1551,8 +1551,8 @@ extern int w_restart_disk_io(struct drbd_work *, int);
 extern int w_send_out_of_sync(struct drbd_work *, int);
 extern int w_start_resync(struct drbd_work *, int);
 
-extern void resync_timer_fn(unsigned long data);
-extern void start_resync_timer_fn(unsigned long data);
+extern void resync_timer_fn(struct timer_list *t);
+extern void start_resync_timer_fn(struct timer_list *t);
 
 extern void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req);
 
index 8cb3791898ae935065f5581aec1dec3a46290988..4b4697a1f96386831fc764276545c03ebf18d6eb 100644 (file)
@@ -64,7 +64,7 @@
 static DEFINE_MUTEX(drbd_main_mutex);
 static int drbd_open(struct block_device *bdev, fmode_t mode);
 static void drbd_release(struct gendisk *gd, fmode_t mode);
-static void md_sync_timer_fn(unsigned long data);
+static void md_sync_timer_fn(struct timer_list *t);
 static int w_bitmap_io(struct drbd_work *w, int unused);
 
 MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
@@ -2023,14 +2023,10 @@ void drbd_init_set_defaults(struct drbd_device *device)
        device->unplug_work.cb  = w_send_write_hint;
        device->bm_io_work.w.cb = w_bitmap_io;
 
-       setup_timer(&device->resync_timer, resync_timer_fn,
-                       (unsigned long)device);
-       setup_timer(&device->md_sync_timer, md_sync_timer_fn,
-                       (unsigned long)device);
-       setup_timer(&device->start_resync_timer, start_resync_timer_fn,
-                       (unsigned long)device);
-       setup_timer(&device->request_timer, request_timer_fn,
-                       (unsigned long)device);
+       timer_setup(&device->resync_timer, resync_timer_fn, 0);
+       timer_setup(&device->md_sync_timer, md_sync_timer_fn, 0);
+       timer_setup(&device->start_resync_timer, start_resync_timer_fn, 0);
+       timer_setup(&device->request_timer, request_timer_fn, 0);
 
        init_waitqueue_head(&device->misc_wait);
        init_waitqueue_head(&device->state_wait);
@@ -3721,9 +3717,9 @@ int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag)
        return (bdev->md.flags & flag) != 0;
 }
 
-static void md_sync_timer_fn(unsigned long data)
+static void md_sync_timer_fn(struct timer_list *t)
 {
-       struct drbd_device *device = (struct drbd_device *) data;
+       struct drbd_device *device = from_timer(device, t, md_sync_timer);
        drbd_device_post_work(device, MD_SYNC);
 }
 
index 796eaf347dc096fb8e56b860c1b530c9cf9da8a2..cb2fa63f6bc057e7038ef3ef7ae9b7c4a2a63711 100644 (file)
@@ -5056,7 +5056,7 @@ static int drbd_disconnected(struct drbd_peer_device *peer_device)
        wake_up(&device->misc_wait);
 
        del_timer_sync(&device->resync_timer);
-       resync_timer_fn((unsigned long)device);
+       resync_timer_fn(&device->resync_timer);
 
        /* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier,
         * w_make_resync_request etc. which may still be on the worker queue
index de8566e5533499b6170c669a08c2aa8688e67057..a500e738d9299bb85bb911e4eb7086258f97ca21 100644 (file)
@@ -1714,9 +1714,9 @@ static bool net_timeout_reached(struct drbd_request *net_req,
  * to expire twice (worst case) to become effective. Good enough.
  */
 
-void request_timer_fn(unsigned long data)
+void request_timer_fn(struct timer_list *t)
 {
-       struct drbd_device *device = (struct drbd_device *) data;
+       struct drbd_device *device = from_timer(device, t, request_timer);
        struct drbd_connection *connection = first_peer_device(device)->connection;
        struct drbd_request *req_read, *req_write, *req_peer; /* oldest request */
        struct net_conf *nc;
index a2254f825601890fad999d9f7876b704b4a43c4d..cb97b3b30962b3bfe9cb7b5615e7977a26380d9e 100644 (file)
@@ -294,7 +294,7 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what,
                struct bio_and_error *m);
 extern void complete_master_bio(struct drbd_device *device,
                struct bio_and_error *m);
-extern void request_timer_fn(unsigned long data);
+extern void request_timer_fn(struct timer_list *t);
 extern void tl_restart(struct drbd_connection *connection, enum drbd_req_event what);
 extern void _tl_restart(struct drbd_connection *connection, enum drbd_req_event what);
 extern void tl_abort_disk_io(struct drbd_device *device);
index 03471b3fce86c7660617f7871bf63c78a3f6c585..1476cb3439f46e53a8f42a9397fb6b19afd8ff95 100644 (file)
@@ -457,9 +457,9 @@ int w_resync_timer(struct drbd_work *w, int cancel)
        return 0;
 }
 
-void resync_timer_fn(unsigned long data)
+void resync_timer_fn(struct timer_list *t)
 {
-       struct drbd_device *device = (struct drbd_device *) data;
+       struct drbd_device *device = from_timer(device, t, resync_timer);
 
        drbd_queue_work_if_unqueued(
                &first_peer_device(device)->connection->sender_work,
@@ -1705,9 +1705,9 @@ void drbd_rs_controller_reset(struct drbd_device *device)
        rcu_read_unlock();
 }
 
-void start_resync_timer_fn(unsigned long data)
+void start_resync_timer_fn(struct timer_list *t)
 {
-       struct drbd_device *device = (struct drbd_device *) data;
+       struct drbd_device *device = from_timer(device, t, start_resync_timer);
        drbd_device_post_work(device, RS_START);
 }
 
index b640ad8a6d206714b1c0f3042916b15340e01ecc..adc877dfef5c2c65ff572e864ef2ef19ad5f5f24 100644 (file)
@@ -2692,7 +2692,7 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request)
         * from the parent.
         */
        page_count = (u32)calc_pages_for(0, length);
-       pages = ceph_alloc_page_vector(page_count, GFP_KERNEL);
+       pages = ceph_alloc_page_vector(page_count, GFP_NOIO);
        if (IS_ERR(pages)) {
                result = PTR_ERR(pages);
                pages = NULL;
@@ -2827,7 +2827,7 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request)
         */
        size = sizeof (__le64) + sizeof (__le32) + sizeof (__le32);
        page_count = (u32)calc_pages_for(0, size);
-       pages = ceph_alloc_page_vector(page_count, GFP_KERNEL);
+       pages = ceph_alloc_page_vector(page_count, GFP_NOIO);
        if (IS_ERR(pages)) {
                ret = PTR_ERR(pages);
                goto fail_stat_request;
index 58471394beb92077617ae15b3dd80d4471c511fe..1a0385ed64171c2e62cc16c36b9a546a9bc24ed1 100644 (file)
@@ -84,7 +84,7 @@ static int dtlk_has_indexing;
 static unsigned int dtlk_portlist[] =
 {0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0};
 static wait_queue_head_t dtlk_process_list;
-static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick, 0, 0);
+static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick);
 
 /* prototypes for file_operations struct */
 static ssize_t dtlk_read(struct file *, char __user *,
index 5406b90bf626fdeea71eab3a6dab36ead644d236..5b8db2ed844d337ad51cc1868d2d34213f03dfe8 100644 (file)
@@ -124,7 +124,7 @@ static unsigned long long hangcheck_tsc, hangcheck_tsc_margin;
 
 static void hangcheck_fire(unsigned long);
 
-static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire, 0, 0);
+static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire);
 
 static void hangcheck_fire(unsigned long data)
 {
index 3c77645405e52019f01304ee2ee5c985f9a90865..71755790c32b2e7bfc8e65c614208099ce9627a1 100644 (file)
@@ -100,9 +100,9 @@ struct xgene_rng_dev {
        struct clk *clk;
 };
 
-static void xgene_rng_expired_timer(unsigned long arg)
+static void xgene_rng_expired_timer(struct timer_list *t)
 {
-       struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) arg;
+       struct xgene_rng_dev *ctx = from_timer(ctx, t, failure_timer);
 
        /* Clear failure counter as timer expired */
        disable_irq(ctx->irq);
@@ -113,8 +113,6 @@ static void xgene_rng_expired_timer(unsigned long arg)
 
 static void xgene_rng_start_timer(struct xgene_rng_dev *ctx)
 {
-       ctx->failure_timer.data = (unsigned long) ctx;
-       ctx->failure_timer.function = xgene_rng_expired_timer;
        ctx->failure_timer.expires = jiffies + 120 * HZ;
        add_timer(&ctx->failure_timer);
 }
@@ -292,7 +290,7 @@ static int xgene_rng_init(struct hwrng *rng)
        struct xgene_rng_dev *ctx = (struct xgene_rng_dev *) rng->priv;
 
        ctx->failure_cnt = 0;
-       init_timer(&ctx->failure_timer);
+       timer_setup(&ctx->failure_timer, xgene_rng_expired_timer, 0);
 
        ctx->revision = readl(ctx->csr_base + RNG_EIP_REV);
 
index e6d0d271c58c83073e3acb71c788867d4edfc846..44006ed9558f20690bb71b9f96a0ca382a996d93 100644 (file)
@@ -27,7 +27,7 @@ static void button_sequence_finished (unsigned long parameters);
 
 static int button_press_count;         /* The count of button presses */
 /* Times for the end of a sequence */
-static DEFINE_TIMER(button_timer, button_sequence_finished, 0, 0);
+static DEFINE_TIMER(button_timer, button_sequence_finished);
 static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */
 static char button_output_buffer[32];  /* Stores data to write out of device */
 static int bcount;                     /* The number of bytes in the buffer */
index 8ad92707e45f23b890203d5c5468d47473acf636..6c7ccac2679e7c4b0543ea9dbbdcca20196bdb64 100644 (file)
@@ -641,7 +641,7 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits)
                return;
 
 retry:
-       entropy_count = orig = ACCESS_ONCE(r->entropy_count);
+       entropy_count = orig = READ_ONCE(r->entropy_count);
        if (nfrac < 0) {
                /* Debit */
                entropy_count += nfrac;
@@ -1265,7 +1265,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
 
        /* Can we pull enough? */
 retry:
-       entropy_count = orig = ACCESS_ONCE(r->entropy_count);
+       entropy_count = orig = READ_ONCE(r->entropy_count);
        ibytes = nbytes;
        /* never pull more than available */
        have_bytes = entropy_count >> (ENTROPY_SHIFT + 3);
index 974d48927b07768b2fce005032ef6d9ae6e5ef84..616871e68e0901e147686ca6b3028151636fa8f8 100644 (file)
@@ -137,7 +137,7 @@ static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
 #ifdef RTC_IRQ
 static void rtc_dropped_irq(unsigned long data);
 
-static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0);
+static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq);
 #endif
 
 static ssize_t rtc_read(struct file *file, char __user *buf,
index 6210bff46341e88b2eb2b19028f41004849cf2bc..8eeb4190207d1ac7ac024433f043ae59f2b0cd71 100644 (file)
@@ -184,9 +184,8 @@ static unsigned int telclk_interrupt;
 static int int_events;         /* Event that generate a interrupt */
 static int got_event;          /* if events processing have been done */
 
-static void switchover_timeout(unsigned long data);
-static struct timer_list switchover_timer =
-       TIMER_INITIALIZER(switchover_timeout , 0, 0);
+static void switchover_timeout(struct timer_list *t);
+static struct timer_list switchover_timer;
 static unsigned long tlclk_timer_data;
 
 static struct tlclk_alarms *alarm_events;
@@ -805,7 +804,7 @@ static int __init tlclk_init(void)
                goto out3;
        }
 
-       init_timer(&switchover_timer);
+       timer_setup(&switchover_timer, switchover_timeout, 0);
 
        ret = misc_register(&tlclk_miscdev);
        if (ret < 0) {
@@ -855,9 +854,9 @@ static void __exit tlclk_cleanup(void)
 
 }
 
-static void switchover_timeout(unsigned long data)
+static void switchover_timeout(struct timer_list *unused)
 {
-       unsigned long flags = *(unsigned long *) data;
+       unsigned long flags = tlclk_timer_data;
 
        if ((flags & 1)) {
                if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
@@ -922,7 +921,6 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id)
                /* TIMEOUT in ~10ms */
                switchover_timer.expires = jiffies + msecs_to_jiffies(10);
                tlclk_timer_data = inb(TLCLK_REG1);
-               switchover_timer.data = (unsigned long) &tlclk_timer_data;
                mod_timer(&switchover_timer, switchover_timer.expires);
        } else {
                got_event = 1;
index 610638a80383d4a104a6fe1ec42479722f222f49..461bf0b8a09473dbadc89b9259473dc36be2cd77 100644 (file)
@@ -110,6 +110,12 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
                return -EFAULT;
        }
 
+       if (in_size < 6 ||
+           in_size < be32_to_cpu(*((__be32 *) (priv->data_buffer + 2)))) {
+               mutex_unlock(&priv->buffer_mutex);
+               return -EINVAL;
+       }
+
        /* atomic tpm command send and result receive. We only hold the ops
         * lock during this period so that the tpm can be unregistered even if
         * the char dev is held open.
index 86f38d239476ab00a70db97640e0ff843c7dd3de..83a77a4455380276ef8d4786cac2c330f3242460 100644 (file)
 #include <linux/device.h>
 #include "tpm.h"
 
-#define READ_PUBEK_RESULT_SIZE 314
+struct tpm_readpubek_out {
+       u8 algorithm[4];
+       u8 encscheme[2];
+       u8 sigscheme[2];
+       __be32 paramsize;
+       u8 parameters[12];
+       __be32 keysize;
+       u8 modulus[256];
+       u8 checksum[20];
+} __packed;
+
 #define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
 #define TPM_ORD_READPUBEK 124
-static const struct tpm_input_header tpm_readpubek_header = {
-       .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
-       .length = cpu_to_be32(30),
-       .ordinal = cpu_to_be32(TPM_ORD_READPUBEK)
-};
+
 static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
-       u8 *data;
-       struct tpm_cmd_t tpm_cmd;
-       ssize_t err;
-       int i, rc;
+       struct tpm_buf tpm_buf;
+       struct tpm_readpubek_out *out;
+       ssize_t rc;
+       int i;
        char *str = buf;
        struct tpm_chip *chip = to_tpm_chip(dev);
+       char anti_replay[20];
 
-       memset(&tpm_cmd, 0, sizeof(tpm_cmd));
-
-       tpm_cmd.header.in = tpm_readpubek_header;
-       err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
-                              READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
-                              "attempting to read the PUBEK");
-       if (err)
-               goto out;
-
-       /*
-          ignore header 10 bytes
-          algorithm 32 bits (1 == RSA )
-          encscheme 16 bits
-          sigscheme 16 bits
-          parameters (RSA 12->bytes: keybit, #primes, expbit)
-          keylenbytes 32 bits
-          256 byte modulus
-          ignore checksum 20 bytes
-        */
-       data = tpm_cmd.params.readpubek_out_buffer;
+       memset(&anti_replay, 0, sizeof(anti_replay));
+
+       rc = tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
+       if (rc)
+               return rc;
+
+       tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
+
+       rc = tpm_transmit_cmd(chip, NULL, tpm_buf.data, PAGE_SIZE,
+                             READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
+                             "attempting to read the PUBEK");
+       if (rc) {
+               tpm_buf_destroy(&tpm_buf);
+               return 0;
+       }
+
+       out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
        str +=
            sprintf(str,
                    "Algorithm: %02X %02X %02X %02X\n"
@@ -68,21 +72,26 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
                    "%02X %02X %02X %02X\n"
                    "Modulus length: %d\n"
                    "Modulus:\n",
-                   data[0], data[1], data[2], data[3],
-                   data[4], data[5],
-                   data[6], data[7],
-                   data[12], data[13], data[14], data[15],
-                   data[16], data[17], data[18], data[19],
-                   data[20], data[21], data[22], data[23],
-                   be32_to_cpu(*((__be32 *) (data + 24))));
+                   out->algorithm[0], out->algorithm[1], out->algorithm[2],
+                   out->algorithm[3],
+                   out->encscheme[0], out->encscheme[1],
+                   out->sigscheme[0], out->sigscheme[1],
+                   out->parameters[0], out->parameters[1],
+                   out->parameters[2], out->parameters[3],
+                   out->parameters[4], out->parameters[5],
+                   out->parameters[6], out->parameters[7],
+                   out->parameters[8], out->parameters[9],
+                   out->parameters[10], out->parameters[11],
+                   be32_to_cpu(out->keysize));
 
        for (i = 0; i < 256; i++) {
-               str += sprintf(str, "%02X ", data[i + 28]);
+               str += sprintf(str, "%02X ", out->modulus[i]);
                if ((i + 1) % 16 == 0)
                        str += sprintf(str, "\n");
        }
-out:
+
        rc = str - buf;
+       tpm_buf_destroy(&tpm_buf);
        return rc;
 }
 static DEVICE_ATTR_RO(pubek);
index 2d5466a72e40f82b3272b857b74a1f822f82b966..528cffbd49d376603eaf80ccb0a4865f0c742d0b 100644 (file)
@@ -345,17 +345,6 @@ enum tpm_sub_capabilities {
        TPM_CAP_PROP_TIS_DURATION = 0x120,
 };
 
-struct tpm_readpubek_params_out {
-       u8      algorithm[4];
-       u8      encscheme[2];
-       u8      sigscheme[2];
-       __be32  paramsize;
-       u8      parameters[12]; /*assuming RSA*/
-       __be32  keysize;
-       u8      modulus[256];
-       u8      checksum[20];
-} __packed;
-
 typedef union {
        struct  tpm_input_header in;
        struct  tpm_output_header out;
@@ -385,8 +374,6 @@ struct tpm_getrandom_in {
 } __packed;
 
 typedef union {
-       struct  tpm_readpubek_params_out readpubek_out;
-       u8      readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
        struct  tpm_pcrread_in  pcrread_in;
        struct  tpm_pcrread_out pcrread_out;
        struct  tpm_getrandom_in getrandom_in;
@@ -557,7 +544,7 @@ static inline void tpm_add_ppi(struct tpm_chip *chip)
 }
 #endif
 
-static inline inline u32 tpm2_rc_value(u32 rc)
+static inline u32 tpm2_rc_value(u32 rc)
 {
        return (rc & BIT(7)) ? rc & 0xff : rc;
 }
index e1a41b788f081c829ad0d0353ac7d3622752c82f..f40d20671a78fd8469c87074f18b5e81b5d3536d 100644 (file)
@@ -834,72 +834,43 @@ static const struct tpm_input_header tpm2_selftest_header = {
 };
 
 /**
- * tpm2_continue_selftest() - start a self test
- *
- * @chip: TPM chip to use
- * @full: test all commands instead of testing only those that were not
- *        previously tested.
- *
- * Return: Same as with tpm_transmit_cmd with exception of RC_TESTING.
- */
-static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
-{
-       int rc;
-       struct tpm2_cmd cmd;
-
-       cmd.header.in = tpm2_selftest_header;
-       cmd.params.selftest_in.full_test = full;
-
-       rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0,
-                             "continue selftest");
-
-       /* At least some prototype chips seem to give RC_TESTING error
-        * immediately. This is a workaround for that.
-        */
-       if (rc == TPM2_RC_TESTING) {
-               dev_warn(&chip->dev, "Got RC_TESTING, ignoring\n");
-               rc = 0;
-       }
-
-       return rc;
-}
-
-/**
- * tpm2_do_selftest() - run a full self test
+ * tpm2_do_selftest() - ensure that all self tests have passed
  *
  * @chip: TPM chip to use
  *
  * Return: Same as with tpm_transmit_cmd.
  *
- * During the self test TPM2 commands return with the error code RC_TESTING.
- * Waiting is done by issuing PCR read until it executes successfully.
+ * The TPM can either run all self tests synchronously and then return
+ * RC_SUCCESS once all tests were successful. Or it can choose to run the tests
+ * asynchronously and return RC_TESTING immediately while the self tests still
+ * execute in the background. This function handles both cases and waits until
+ * all tests have completed.
  */
 static int tpm2_do_selftest(struct tpm_chip *chip)
 {
        int rc;
-       unsigned int loops;
-       unsigned int delay_msec = 100;
-       unsigned long duration;
-       int i;
-
-       duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST);
+       unsigned int delay_msec = 20;
+       long duration;
+       struct tpm2_cmd cmd;
 
-       loops = jiffies_to_msecs(duration) / delay_msec;
+       duration = jiffies_to_msecs(
+               tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST));
 
-       rc = tpm2_start_selftest(chip, true);
-       if (rc)
-               return rc;
+       while (duration > 0) {
+               cmd.header.in = tpm2_selftest_header;
+               cmd.params.selftest_in.full_test = 0;
 
-       for (i = 0; i < loops; i++) {
-               /* Attempt to read a PCR value */
-               rc = tpm2_pcr_read(chip, 0, NULL);
-               if (rc < 0)
-                       break;
+               rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE,
+                                     0, 0, "continue selftest");
 
                if (rc != TPM2_RC_TESTING)
                        break;
 
                tpm_msleep(delay_msec);
+               duration -= delay_msec;
+
+               /* wait longer the next round */
+               delay_msec *= 2;
        }
 
        return rc;
@@ -1009,7 +980,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
 {
        struct tpm_buf buf;
        u32 nr_commands;
-       u32 *attrs;
+       __be32 *attrs;
        u32 cc;
        int i;
        int rc;
@@ -1049,7 +1020,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
 
        chip->nr_commands = nr_commands;
 
-       attrs = (u32 *)&buf.data[TPM_HEADER_SIZE + 9];
+       attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
        for (i = 0; i < nr_commands; i++, attrs++) {
                chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
                cc = chip->cc_attrs_tbl[i] & 0xFFFF;
index e2e059d8ffec0c16ec9e106d6c848a036857295f..4e4014eabdb9c34776d1fbd71c3a8747fcca8c6f 100644 (file)
@@ -242,7 +242,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
        struct tpm_space *space = &chip->work_space;
        unsigned int nr_handles;
        u32 attrs;
-       u32 *handle;
+       __be32 *handle;
        int i;
 
        i = tpm2_find_cc(chip, cc);
@@ -252,7 +252,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
        attrs = chip->cc_attrs_tbl[i];
        nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
 
-       handle = (u32 *)&cmd[TPM_HEADER_SIZE];
+       handle = (__be32 *)&cmd[TPM_HEADER_SIZE];
        for (i = 0; i < nr_handles; i++, handle++) {
                if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
                        if (!tpm2_map_to_phandle(space, handle))
index 8f0a98dea327a5bc90d7fcf3529c3701d17abd6b..7b3c2a8aa9defc33e4189658e797dbecdb38149f 100644 (file)
@@ -92,14 +92,9 @@ enum crb_status {
        CRB_DRV_STS_COMPLETE    = BIT(0),
 };
 
-enum crb_flags {
-       CRB_FL_ACPI_START       = BIT(0),
-       CRB_FL_CRB_START        = BIT(1),
-       CRB_FL_CRB_SMC_START    = BIT(2),
-};
-
 struct crb_priv {
-       unsigned int flags;
+       u32 sm;
+       const char *hid;
        void __iomem *iobase;
        struct crb_regs_head __iomem *regs_h;
        struct crb_regs_tail __iomem *regs_t;
@@ -128,14 +123,16 @@ struct tpm2_crb_smc {
  * Anyhow, we do not wait here as a consequent CMD_READY request
  * will be handled correctly even if idle was not completed.
  *
- * The function does nothing for devices with ACPI-start method.
+ * The function does nothing for devices with ACPI-start method
+ * or SMC-start method.
  *
  * Return: 0 always
  */
 static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv)
 {
-       if ((priv->flags & CRB_FL_ACPI_START) ||
-           (priv->flags & CRB_FL_CRB_SMC_START))
+       if ((priv->sm == ACPI_TPM2_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
                return 0;
 
        iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req);
@@ -174,14 +171,16 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
  * The device should respond within TIMEOUT_C.
  *
  * The function does nothing for devices with ACPI-start method
+ * or SMC-start method.
  *
  * Return: 0 on success -ETIME on timeout;
  */
 static int __maybe_unused crb_cmd_ready(struct device *dev,
                                        struct crb_priv *priv)
 {
-       if ((priv->flags & CRB_FL_ACPI_START) ||
-           (priv->flags & CRB_FL_CRB_SMC_START))
+       if ((priv->sm == ACPI_TPM2_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC))
                return 0;
 
        iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs_t->ctrl_req);
@@ -325,13 +324,20 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
        /* Make sure that cmd is populated before issuing start. */
        wmb();
 
-       if (priv->flags & CRB_FL_CRB_START)
+       /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
+        * report only ACPI start but in practice seems to require both
+        * CRB start, hence invoking CRB start method if hid == MSFT0101.
+        */
+       if ((priv->sm == ACPI_TPM2_COMMAND_BUFFER) ||
+           (priv->sm == ACPI_TPM2_MEMORY_MAPPED) ||
+           (!strcmp(priv->hid, "MSFT0101")))
                iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start);
 
-       if (priv->flags & CRB_FL_ACPI_START)
+       if ((priv->sm == ACPI_TPM2_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD))
                rc = crb_do_acpi_start(chip);
 
-       if (priv->flags & CRB_FL_CRB_SMC_START) {
+       if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) {
                iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start);
                rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id);
        }
@@ -345,7 +351,9 @@ static void crb_cancel(struct tpm_chip *chip)
 
        iowrite32(CRB_CANCEL_INVOKE, &priv->regs_t->ctrl_cancel);
 
-       if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip))
+       if (((priv->sm == ACPI_TPM2_START_METHOD) ||
+           (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)) &&
+            crb_do_acpi_start(chip))
                dev_err(&chip->dev, "ACPI Start failed\n");
 }
 
@@ -458,7 +466,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
         * the control area, as one nice sane region except for some older
         * stuff that puts the control area outside the ACPI IO region.
         */
-       if (!(priv->flags & CRB_FL_ACPI_START)) {
+       if ((priv->sm == ACPI_TPM2_COMMAND_BUFFER) ||
+           (priv->sm == ACPI_TPM2_MEMORY_MAPPED)) {
                if (buf->control_address == io_res.start +
                    sizeof(*priv->regs_h))
                        priv->regs_h = priv->iobase;
@@ -552,18 +561,6 @@ static int crb_acpi_add(struct acpi_device *device)
        if (!priv)
                return -ENOMEM;
 
-       /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
-        * report only ACPI start but in practice seems to require both
-        * ACPI start and CRB start.
-        */
-       if (sm == ACPI_TPM2_COMMAND_BUFFER || sm == ACPI_TPM2_MEMORY_MAPPED ||
-           !strcmp(acpi_device_hid(device), "MSFT0101"))
-               priv->flags |= CRB_FL_CRB_START;
-
-       if (sm == ACPI_TPM2_START_METHOD ||
-           sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
-               priv->flags |= CRB_FL_ACPI_START;
-
        if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) {
                if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) {
                        dev_err(dev,
@@ -574,9 +571,11 @@ static int crb_acpi_add(struct acpi_device *device)
                }
                crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf, sizeof(*buf));
                priv->smc_func_id = crb_smc->smc_func_id;
-               priv->flags |= CRB_FL_CRB_SMC_START;
        }
 
+       priv->sm = sm;
+       priv->hid = acpi_device_hid(device);
+
        rc = crb_map_io(device, priv, buf);
        if (rc)
                return rc;
index 7e55aa9ce680cbc6cd2802710625e41775c9b2e9..e2d1055fb814c3e7d2e8b2ed846e6e03d774892c 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/freezer.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/kernel.h>
 #include "tpm.h"
 #include "tpm_tis_core.h"
 
@@ -223,7 +224,7 @@ static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
 }
 
 static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
-                              u8 *value)
+                              const u8 *value)
 {
        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 
@@ -365,7 +366,7 @@ static struct pnp_driver tis_pnp_driver = {
        },
 };
 
-#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
+#define TIS_HID_USR_IDX (ARRAY_SIZE(tpm_pnp_tbl) - 2)
 module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
                    sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
index 63bc6c3b949e51406527a484d356e24959ed9615..fdde971bc8108b574eed3a9f1a500904207e3a1c 100644 (file)
@@ -252,7 +252,7 @@ out:
  * tpm.c can skip polling for the data to be available as the interrupt is
  * waited for here
  */
-static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
+static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
        int rc, status, burstcnt;
@@ -343,7 +343,7 @@ static void disable_interrupts(struct tpm_chip *chip)
  * tpm.c can skip polling for the data to be available as the interrupt is
  * waited for here
  */
-static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len)
+static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
        int rc;
@@ -445,7 +445,7 @@ static int probe_itpm(struct tpm_chip *chip)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
        int rc = 0;
-       u8 cmd_getticks[] = {
+       static const u8 cmd_getticks[] = {
                0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a,
                0x00, 0x00, 0x00, 0xf1
        };
index e2212f021a02eb67db9be8bf479edaa97d8b516d..6bbac319ff3bfe46169a948775e323e72f172893 100644 (file)
@@ -98,7 +98,7 @@ struct tpm_tis_phy_ops {
        int (*read_bytes)(struct tpm_tis_data *data, u32 addr, u16 len,
                          u8 *result);
        int (*write_bytes)(struct tpm_tis_data *data, u32 addr, u16 len,
-                          u8 *value);
+                          const u8 *value);
        int (*read16)(struct tpm_tis_data *data, u32 addr, u16 *result);
        int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result);
        int (*write32)(struct tpm_tis_data *data, u32 addr, u32 src);
@@ -128,7 +128,7 @@ static inline int tpm_tis_read32(struct tpm_tis_data *data, u32 addr,
 }
 
 static inline int tpm_tis_write_bytes(struct tpm_tis_data *data, u32 addr,
-                                     u16 len, u8 *value)
+                                     u16 len, const u8 *value)
 {
        return data->phy_ops->write_bytes(data, addr, len, value);
 }
index 88fe72ae967fec1a29ed309a26d823f41a2ee5d4..424ff2fde1f2d60e3e42298153cffbf16758cedd 100644 (file)
@@ -46,9 +46,7 @@
 struct tpm_tis_spi_phy {
        struct tpm_tis_data priv;
        struct spi_device *spi_device;
-
-       u8 tx_buf[4];
-       u8 rx_buf[4];
+       u8 *iobuf;
 };
 
 static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *data)
@@ -57,7 +55,7 @@ static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *da
 }
 
 static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
-                               u8 *buffer, u8 direction)
+                               u8 *in, const u8 *out)
 {
        struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
        int ret = 0;
@@ -71,14 +69,14 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
        while (len) {
                transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE);
 
-               phy->tx_buf[0] = direction | (transfer_len - 1);
-               phy->tx_buf[1] = 0xd4;
-               phy->tx_buf[2] = addr >> 8;
-               phy->tx_buf[3] = addr;
+               phy->iobuf[0] = (in ? 0x80 : 0) | (transfer_len - 1);
+               phy->iobuf[1] = 0xd4;
+               phy->iobuf[2] = addr >> 8;
+               phy->iobuf[3] = addr;
 
                memset(&spi_xfer, 0, sizeof(spi_xfer));
-               spi_xfer.tx_buf = phy->tx_buf;
-               spi_xfer.rx_buf = phy->rx_buf;
+               spi_xfer.tx_buf = phy->iobuf;
+               spi_xfer.rx_buf = phy->iobuf;
                spi_xfer.len = 4;
                spi_xfer.cs_change = 1;
 
@@ -88,9 +86,9 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
                if (ret < 0)
                        goto exit;
 
-               if ((phy->rx_buf[3] & 0x01) == 0) {
+               if ((phy->iobuf[3] & 0x01) == 0) {
                        // handle SPI wait states
-                       phy->tx_buf[0] = 0;
+                       phy->iobuf[0] = 0;
 
                        for (i = 0; i < TPM_RETRY; i++) {
                                spi_xfer.len = 1;
@@ -99,7 +97,7 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
                                ret = spi_sync_locked(phy->spi_device, &m);
                                if (ret < 0)
                                        goto exit;
-                               if (phy->rx_buf[0] & 0x01)
+                               if (phy->iobuf[0] & 0x01)
                                        break;
                        }
 
@@ -113,12 +111,12 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
                spi_xfer.len = transfer_len;
                spi_xfer.delay_usecs = 5;
 
-               if (direction) {
+               if (in) {
                        spi_xfer.tx_buf = NULL;
-                       spi_xfer.rx_buf = buffer;
-               } else {
-                       spi_xfer.tx_buf = buffer;
+               } else if (out) {
                        spi_xfer.rx_buf = NULL;
+                       memcpy(phy->iobuf, out, transfer_len);
+                       out += transfer_len;
                }
 
                spi_message_init(&m);
@@ -127,8 +125,12 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
                if (ret < 0)
                        goto exit;
 
+               if (in) {
+                       memcpy(in, phy->iobuf, transfer_len);
+                       in += transfer_len;
+               }
+
                len -= transfer_len;
-               buffer += transfer_len;
        }
 
 exit:
@@ -139,40 +141,51 @@ exit:
 static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr,
                                  u16 len, u8 *result)
 {
-       return tpm_tis_spi_transfer(data, addr, len, result, 0x80);
+       return tpm_tis_spi_transfer(data, addr, len, result, NULL);
 }
 
 static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr,
-                                  u16 len, u8 *value)
+                                  u16 len, const u8 *value)
 {
-       return tpm_tis_spi_transfer(data, addr, len, value, 0);
+       return tpm_tis_spi_transfer(data, addr, len, NULL, value);
 }
 
 static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
 {
+       __le16 result_le;
        int rc;
 
-       rc = data->phy_ops->read_bytes(data, addr, sizeof(u16), (u8 *)result);
+       rc = data->phy_ops->read_bytes(data, addr, sizeof(u16),
+                                      (u8 *)&result_le);
        if (!rc)
-               *result = le16_to_cpu(*result);
+               *result = le16_to_cpu(result_le);
+
        return rc;
 }
 
 static int tpm_tis_spi_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
 {
+       __le32 result_le;
        int rc;
 
-       rc = data->phy_ops->read_bytes(data, addr, sizeof(u32), (u8 *)result);
+       rc = data->phy_ops->read_bytes(data, addr, sizeof(u32),
+                                      (u8 *)&result_le);
        if (!rc)
-               *result = le32_to_cpu(*result);
+               *result = le32_to_cpu(result_le);
+
        return rc;
 }
 
 static int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value)
 {
-       value = cpu_to_le32(value);
-       return data->phy_ops->write_bytes(data, addr, sizeof(u32),
-                                          (u8 *)&value);
+       __le32 value_le;
+       int rc;
+
+       value_le = cpu_to_le32(value);
+       rc = data->phy_ops->write_bytes(data, addr, sizeof(u32),
+                                       (u8 *)&value_le);
+
+       return rc;
 }
 
 static const struct tpm_tis_phy_ops tpm_spi_phy_ops = {
@@ -194,6 +207,10 @@ static int tpm_tis_spi_probe(struct spi_device *dev)
 
        phy->spi_device = dev;
 
+       phy->iobuf = devm_kmalloc(&dev->dev, MAX_SPI_FRAMESIZE, GFP_KERNEL);
+       if (!phy->iobuf)
+               return -ENOMEM;
+
        return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_spi_phy_ops,
                                 NULL);
 }
index cc6062049170eb0b5a8001955497ed59cfa8c639..c729a88007d0fa7b0c5132ad36dec959e396607a 100644 (file)
@@ -1,9 +1,8 @@
 menu "Clock Source drivers"
-       depends on !ARCH_USES_GETTIMEOFFSET
+       depends on GENERIC_CLOCKEVENTS
 
 config TIMER_OF
        bool
-       depends on GENERIC_CLOCKEVENTS
        select TIMER_PROBE
 
 config TIMER_ACPI
@@ -30,21 +29,18 @@ config CLKSRC_MMIO
 
 config BCM2835_TIMER
        bool "BCM2835 timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables the support for the BCM2835 timer driver.
 
 config BCM_KONA_TIMER
        bool "BCM mobile timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables the support for the BCM Kona mobile timer driver.
 
 config DIGICOLOR_TIMER
        bool "Digicolor timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        depends on HAS_IOMEM
        help
@@ -52,7 +48,6 @@ config DIGICOLOR_TIMER
 
 config DW_APB_TIMER
        bool "DW APB timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        help
          Enables the support for the dw_apb timer.
 
@@ -63,7 +58,6 @@ config DW_APB_TIMER_OF
 
 config FTTMR010_TIMER
        bool "Faraday Technology timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        select CLKSRC_MMIO
        select TIMER_OF
@@ -90,7 +84,6 @@ config ARMADA_370_XP_TIMER
 
 config MESON6_TIMER
        bool "Meson6 timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables the support for the Meson6 timer driver.
@@ -105,14 +98,12 @@ config ORION_TIMER
 
 config OWL_TIMER
        bool "Owl timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables the support for the Actions Semi Owl timer driver.
 
 config SUN4I_TIMER
        bool "Sun4i timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        select CLKSRC_MMIO
        select TIMER_OF
@@ -135,7 +126,6 @@ config TEGRA_TIMER
 
 config VT8500_TIMER
        bool "VT8500 timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        help
          Enables support for the VT8500 driver.
@@ -148,7 +138,6 @@ config CADENCE_TTC_TIMER
 
 config ASM9260_TIMER
        bool "ASM9260 timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        select TIMER_OF
        help
@@ -171,28 +160,24 @@ config CLKSRC_NOMADIK_MTU_SCHED_CLOCK
 
 config CLKSRC_DBX500_PRCMU
        bool "Clocksource PRCMU Timer" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        help
          Use the always on PRCMU Timer as clocksource
 
 config CLPS711X_TIMER
        bool "Cirrus logic timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables support for the Cirrus Logic PS711 timer.
 
 config ATLAS7_TIMER
        bool "Atlas7 timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables support for the Atlas7 timer.
 
 config MXS_TIMER
        bool "Mxs timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        select STMP_DEVICE
        help
@@ -200,14 +185,12 @@ config MXS_TIMER
 
 config PRIMA2_TIMER
        bool "Prima2 timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables support for the Prima2 timer.
 
 config U300_TIMER
        bool "U300 timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on ARM
        select CLKSRC_MMIO
        help
@@ -215,14 +198,12 @@ config U300_TIMER
 
 config NSPIRE_TIMER
        bool "NSpire timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables support for the Nspire timer.
 
 config KEYSTONE_TIMER
        bool "Keystone timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on ARM || ARM64
        select CLKSRC_MMIO
        help
@@ -230,7 +211,6 @@ config KEYSTONE_TIMER
 
 config INTEGRATOR_AP_TIMER
        bool "Integrator-ap timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables support for the Integrator-ap timer.
@@ -253,7 +233,7 @@ config CLKSRC_EFM32
 
 config CLKSRC_LPC32XX
        bool "Clocksource for LPC32XX" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
+       depends on HAS_IOMEM
        depends on ARM
        select CLKSRC_MMIO
        select TIMER_OF
@@ -262,7 +242,7 @@ config CLKSRC_LPC32XX
 
 config CLKSRC_PISTACHIO
        bool "Clocksource for Pistachio SoC" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
+       depends on HAS_IOMEM
        select TIMER_OF
        help
          Enables the clocksource for the Pistachio SoC.
@@ -298,7 +278,6 @@ config CLKSRC_MPS2
 
 config ARC_TIMERS
        bool "Support for 32-bit TIMERn counters in ARC Cores" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select TIMER_OF
        help
          These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores
@@ -307,7 +286,6 @@ config ARC_TIMERS
 
 config ARC_TIMERS_64BIT
        bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on ARC_TIMERS
        select TIMER_OF
        help
@@ -407,7 +385,6 @@ config ATMEL_PIT
 
 config ATMEL_ST
        bool "Atmel ST timer support" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select TIMER_OF
        select MFD_SYSCON
        help
@@ -426,7 +403,6 @@ config CLKSRC_EXYNOS_MCT
 
 config CLKSRC_SAMSUNG_PWM
        bool "PWM timer driver for Samsung S3C, S5P" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        help
          This is a new clocksource driver for the PWM timer found in
@@ -436,7 +412,6 @@ config CLKSRC_SAMSUNG_PWM
 
 config FSL_FTM_TIMER
        bool "Freescale FlexTimer Module driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        select CLKSRC_MMIO
        help
@@ -450,7 +425,6 @@ config VF_PIT_TIMER
 
 config OXNAS_RPS_TIMER
        bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select TIMER_OF
        select CLKSRC_MMIO
        help
@@ -461,7 +435,7 @@ config SYS_SUPPORTS_SH_CMT
 
 config MTK_TIMER
        bool "Mediatek timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
+       depends on HAS_IOMEM
        select TIMER_OF
        select CLKSRC_MMIO
        help
@@ -479,7 +453,6 @@ config SYS_SUPPORTS_EM_STI
 config CLKSRC_JCORE_PIT
        bool "J-Core PIT timer driver" if COMPILE_TEST
        depends on OF
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        select CLKSRC_MMIO
        help
@@ -488,7 +461,6 @@ config CLKSRC_JCORE_PIT
 
 config SH_TIMER_CMT
        bool "Renesas CMT timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_CMT
        help
@@ -498,7 +470,6 @@ config SH_TIMER_CMT
 
 config SH_TIMER_MTU2
        bool "Renesas MTU2 timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_MTU2
        help
@@ -508,14 +479,12 @@ config SH_TIMER_MTU2
 
 config RENESAS_OSTM
        bool "Renesas OSTM timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        select CLKSRC_MMIO
        help
          Enables the support for the Renesas OSTM.
 
 config SH_TIMER_TMU
        bool "Renesas TMU timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        default SYS_SUPPORTS_SH_TMU
        help
@@ -525,7 +494,7 @@ config SH_TIMER_TMU
 
 config EM_TIMER_STI
        bool "Renesas STI timer driver" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
+       depends on HAS_IOMEM
        default SYS_SUPPORTS_EM_STI
        help
          This enables build of a clocksource and clockevent driver for
@@ -566,7 +535,6 @@ config CLKSRC_TANGO_XTAL
 
 config CLKSRC_PXA
        bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST
-       depends on GENERIC_CLOCKEVENTS
        depends on HAS_IOMEM
        select CLKSRC_MMIO
        help
@@ -575,20 +543,20 @@ config CLKSRC_PXA
 
 config H8300_TMR8
         bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
-        depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
+        depends on HAS_IOMEM
        help
          This enables the 8 bits timer for the H8300 platform.
 
 config H8300_TMR16
         bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
-        depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
+        depends on HAS_IOMEM
        help
          This enables the 16 bits timer for the H8300 platform with the
          H83069 cpu.
 
 config H8300_TPU
         bool "Clocksource for the H8300 platform" if COMPILE_TEST
-        depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
+        depends on HAS_IOMEM
        help
          This enables the clocksource for the H8300 platform with the
          H8S2678 cpu.
@@ -600,7 +568,7 @@ config CLKSRC_IMX_GPT
 
 config CLKSRC_IMX_TPM
        bool "Clocksource using i.MX TPM" if COMPILE_TEST
-       depends on ARM && CLKDEV_LOOKUP && GENERIC_CLOCKEVENTS
+       depends on ARM && CLKDEV_LOOKUP
        select CLKSRC_MMIO
        help
          Enable this option to use IMX Timer/PWM Module (TPM) timer as
index fd4b7f684bd030151d388071e05a3c2cfcb5e2c4..0ecf5beb56ec91083b991f9d8bc208ee95c07d5f 100644 (file)
@@ -299,8 +299,7 @@ static u64 notrace arm64_858921_read_cntvct_el0(void)
 #endif
 
 #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
-DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *,
-              timer_unstable_counter_workaround);
+DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround);
 EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
 
 DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled);
@@ -1268,10 +1267,6 @@ arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem)
 
        iounmap(cntctlbase);
 
-       if (!best_frame)
-               pr_err("Unable to find a suitable frame in timer @ %pa\n",
-                       &timer_mem->cntctlbase);
-
        return best_frame;
 }
 
@@ -1372,6 +1367,8 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
 
        frame = arch_timer_mem_find_best_frame(timer_mem);
        if (!frame) {
+               pr_err("Unable to find a suitable frame in timer @ %pa\n",
+                       &timer_mem->cntctlbase);
                ret = -EINVAL;
                goto out;
        }
@@ -1420,7 +1417,7 @@ arch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem)
 static int __init arch_timer_mem_acpi_init(int platform_timer_count)
 {
        struct arch_timer_mem *timers, *timer;
-       struct arch_timer_mem_frame *frame;
+       struct arch_timer_mem_frame *frame, *best_frame = NULL;
        int timer_count, i, ret = 0;
 
        timers = kcalloc(platform_timer_count, sizeof(*timers),
@@ -1432,14 +1429,6 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count)
        if (ret || !timer_count)
                goto out;
 
-       for (i = 0; i < timer_count; i++) {
-               ret = arch_timer_mem_verify_cntfrq(&timers[i]);
-               if (ret) {
-                       pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n");
-                       goto out;
-               }
-       }
-
        /*
         * While unlikely, it's theoretically possible that none of the frames
         * in a timer expose the combination of feature we want.
@@ -1448,12 +1437,26 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count)
                timer = &timers[i];
 
                frame = arch_timer_mem_find_best_frame(timer);
-               if (frame)
-                       break;
+               if (!best_frame)
+                       best_frame = frame;
+
+               ret = arch_timer_mem_verify_cntfrq(timer);
+               if (ret) {
+                       pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n");
+                       goto out;
+               }
+
+               if (!best_frame) /* implies !frame */
+                       /*
+                        * Only complain about missing suitable frames if we
+                        * haven't already found one in a previous iteration.
+                        */
+                       pr_err("Unable to find a suitable frame in timer @ %pa\n",
+                               &timer->cntctlbase);
        }
 
-       if (frame)
-               ret = arch_timer_mem_frame_register(frame);
+       if (best_frame)
+               ret = arch_timer_mem_frame_register(best_frame);
 out:
        kfree(timers);
        return ret;
index 39e489a96ad74f0f8e341aa2b3f9c8e6acfc4bfe..60da2537bef9303308498187c4fa542bca68aac6 100644 (file)
@@ -71,7 +71,7 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id)
        if (readl_relaxed(timer->control) & timer->match_mask) {
                writel_relaxed(timer->match_mask, timer->control);
 
-               event_handler = ACCESS_ONCE(timer->evt.event_handler);
+               event_handler = READ_ONCE(timer->evt.event_handler);
                if (event_handler)
                        event_handler(&timer->evt);
                return IRQ_HANDLED;
index ae3167c28b129b6c3d3cc0fbc5c4a0da1a9abacd..a04808a21d4ec9eef5d3c6d5e7ed140945d1001b 100644 (file)
@@ -39,16 +39,18 @@ static u64 notrace gic_read_count(void)
 
 static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
 {
-       unsigned long flags;
+       int cpu = cpumask_first(evt->cpumask);
        u64 cnt;
        int res;
 
        cnt = gic_read_count();
        cnt += (u64)delta;
-       local_irq_save(flags);
-       write_gic_vl_other(mips_cm_vp_id(cpumask_first(evt->cpumask)));
-       write_gic_vo_compare(cnt);
-       local_irq_restore(flags);
+       if (cpu == raw_smp_processor_id()) {
+               write_gic_vl_compare(cnt);
+       } else {
+               write_gic_vl_other(mips_cm_vp_id(cpu));
+               write_gic_vo_compare(cnt);
+       }
        res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
        return res;
 }
index d19c53c11094c20e31f08ffc125c3f8b83c0f780..c686305650797a8b75b2e7f5be4a2ec568d84c28 100644 (file)
@@ -125,7 +125,7 @@ static int __init owl_timer_init(struct device_node *node)
 
        owl_timer_base = of_io_request_and_map(node, 0, "owl-timer");
        if (IS_ERR(owl_timer_base)) {
-               pr_err("Can't map timer registers");
+               pr_err("Can't map timer registers\n");
                return PTR_ERR(owl_timer_base);
        }
 
@@ -134,7 +134,7 @@ static int __init owl_timer_init(struct device_node *node)
 
        timer1_irq = of_irq_get_byname(node, "timer1");
        if (timer1_irq <= 0) {
-               pr_err("Can't parse timer1 IRQ");
+               pr_err("Can't parse timer1 IRQ\n");
                return -EINVAL;
        }
 
index c27f4c850d83c6bbd82ba60da1140f3fee0e8ed0..33f370dbd0d62f533a0ce0fa2b1c1d674968f677 100644 (file)
@@ -274,7 +274,7 @@ static int __init rk_clksrc_init(struct device_node *np)
                TIMER_NAME, rk_clksrc->freq, 250, 32,
                clocksource_mmio_readl_down);
        if (ret) {
-               pr_err("Failed to register clocksource");
+               pr_err("Failed to register clocksource\n");
                goto out_clocksource;
        }
 
index e09e8bf0bb9bf53680ea50aebff431aa76f6078a..70b3cf8e23d01bd80caf92859171df39b3e171ff 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
@@ -39,16 +40,16 @@ struct sh_cmt_device;
  * SoC but also on the particular instance. The following table lists the main
  * characteristics of those flavours.
  *
- *                     16B     32B     32B-F   48B     48B-2
+ *                     16B     32B     32B-F   48B     R-Car Gen2
  * -----------------------------------------------------------------------------
  * Channels            2       1/4     1       6       2/8
  * Control Width       16      16      16      16      32
  * Counter Width       16      32      32      32/48   32/48
  * Shared Start/Stop   Y       Y       Y       Y       N
  *
- * The 48-bit gen2 version has a per-channel start/stop register located in the
- * channel registers block. All other versions have a shared start/stop register
- * located in the global space.
+ * The r8a73a4 / R-Car Gen2 version has a per-channel start/stop register
+ * located in the channel registers block. All other versions have a shared
+ * start/stop register located in the global space.
  *
  * Channels are indexed from 0 to N-1 in the documentation. The channel index
  * infers the start/stop bit position in the control register and the channel
@@ -66,14 +67,16 @@ struct sh_cmt_device;
 enum sh_cmt_model {
        SH_CMT_16BIT,
        SH_CMT_32BIT,
-       SH_CMT_32BIT_FAST,
        SH_CMT_48BIT,
-       SH_CMT_48BIT_GEN2,
+       SH_CMT0_RCAR_GEN2,
+       SH_CMT1_RCAR_GEN2,
 };
 
 struct sh_cmt_info {
        enum sh_cmt_model model;
 
+       unsigned int channels_mask;
+
        unsigned long width; /* 16 or 32 bit version of hardware block */
        unsigned long overflow_bit;
        unsigned long clear_bits;
@@ -200,18 +203,20 @@ static const struct sh_cmt_info sh_cmt_info[] = {
                .read_count = sh_cmt_read32,
                .write_count = sh_cmt_write32,
        },
-       [SH_CMT_32BIT_FAST] = {
-               .model = SH_CMT_32BIT_FAST,
+       [SH_CMT_48BIT] = {
+               .model = SH_CMT_48BIT,
+               .channels_mask = 0x3f,
                .width = 32,
                .overflow_bit = SH_CMT32_CMCSR_CMF,
                .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
-               .read_control = sh_cmt_read16,
-               .write_control = sh_cmt_write16,
+               .read_control = sh_cmt_read32,
+               .write_control = sh_cmt_write32,
                .read_count = sh_cmt_read32,
                .write_count = sh_cmt_write32,
        },
-       [SH_CMT_48BIT] = {
-               .model = SH_CMT_48BIT,
+       [SH_CMT0_RCAR_GEN2] = {
+               .model = SH_CMT0_RCAR_GEN2,
+               .channels_mask = 0x60,
                .width = 32,
                .overflow_bit = SH_CMT32_CMCSR_CMF,
                .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
@@ -220,8 +225,9 @@ static const struct sh_cmt_info sh_cmt_info[] = {
                .read_count = sh_cmt_read32,
                .write_count = sh_cmt_write32,
        },
-       [SH_CMT_48BIT_GEN2] = {
-               .model = SH_CMT_48BIT_GEN2,
+       [SH_CMT1_RCAR_GEN2] = {
+               .model = SH_CMT1_RCAR_GEN2,
+               .channels_mask = 0xff,
                .width = 32,
                .overflow_bit = SH_CMT32_CMCSR_CMF,
                .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
@@ -859,6 +865,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
        ch->cmt = cmt;
        ch->index = index;
        ch->hwidx = hwidx;
+       ch->timer_bit = hwidx;
 
        /*
         * Compute the address of the channel control register block. For the
@@ -873,16 +880,11 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
        case SH_CMT_48BIT:
                ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10;
                break;
-       case SH_CMT_32BIT_FAST:
-               /*
-                * The 32-bit "fast" timer has a single channel at hwidx 5 but
-                * is located at offset 0x40 instead of 0x60 for some reason.
-                */
-               ch->ioctrl = cmt->mapbase + 0x40;
-               break;
-       case SH_CMT_48BIT_GEN2:
+       case SH_CMT0_RCAR_GEN2:
+       case SH_CMT1_RCAR_GEN2:
                ch->iostart = cmt->mapbase + ch->hwidx * 0x100;
                ch->ioctrl = ch->iostart + 0x10;
+               ch->timer_bit = 0;
                break;
        }
 
@@ -894,8 +896,6 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
        ch->match_value = ch->max_match_value;
        raw_spin_lock_init(&ch->lock);
 
-       ch->timer_bit = cmt->info->model == SH_CMT_48BIT_GEN2 ? 0 : ch->hwidx;
-
        ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev),
                              clockevent, clocksource);
        if (ret) {
@@ -935,22 +935,18 @@ static const struct platform_device_id sh_cmt_id_table[] = {
 MODULE_DEVICE_TABLE(platform, sh_cmt_id_table);
 
 static const struct of_device_id sh_cmt_of_table[] __maybe_unused = {
-       { .compatible = "renesas,cmt-32", .data = &sh_cmt_info[SH_CMT_32BIT] },
-       { .compatible = "renesas,cmt-32-fast", .data = &sh_cmt_info[SH_CMT_32BIT_FAST] },
        { .compatible = "renesas,cmt-48", .data = &sh_cmt_info[SH_CMT_48BIT] },
-       { .compatible = "renesas,cmt-48-gen2", .data = &sh_cmt_info[SH_CMT_48BIT_GEN2] },
+       {
+               /* deprecated, preserved for backward compatibility */
+               .compatible = "renesas,cmt-48-gen2",
+               .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
+       },
+       { .compatible = "renesas,rcar-gen2-cmt0", .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2] },
+       { .compatible = "renesas,rcar-gen2-cmt1", .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2] },
        { }
 };
 MODULE_DEVICE_TABLE(of, sh_cmt_of_table);
 
-static int sh_cmt_parse_dt(struct sh_cmt_device *cmt)
-{
-       struct device_node *np = cmt->pdev->dev.of_node;
-
-       return of_property_read_u32(np, "renesas,channels-mask",
-                                   &cmt->hw_channels);
-}
-
 static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
 {
        unsigned int mask;
@@ -961,14 +957,8 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
        raw_spin_lock_init(&cmt->lock);
 
        if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
-               const struct of_device_id *id;
-
-               id = of_match_node(sh_cmt_of_table, pdev->dev.of_node);
-               cmt->info = id->data;
-
-               ret = sh_cmt_parse_dt(cmt);
-               if (ret < 0)
-                       return ret;
+               cmt->info = of_device_get_match_data(&pdev->dev);
+               cmt->hw_channels = cmt->info->channels_mask;
        } else if (pdev->dev.platform_data) {
                struct sh_timer_config *cfg = pdev->dev.platform_data;
                const struct platform_device_id *id = pdev->id_entry;
index cdf23b62868820adf8463a2ac494d96fea6cd905..c020038ebfab2242ed844a143f3ce6706985685c 100644 (file)
@@ -264,14 +264,14 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
 
        fttmr010->base = of_iomap(np, 0);
        if (!fttmr010->base) {
-               pr_err("Can't remap registers");
+               pr_err("Can't remap registers\n");
                ret = -ENXIO;
                goto out_free;
        }
        /* IRQ for timer 1 */
        irq = irq_of_parse_and_map(np, 0);
        if (irq <= 0) {
-               pr_err("Can't parse IRQ");
+               pr_err("Can't parse IRQ\n");
                ret = -EINVAL;
                goto out_unmap;
        }
index c79122d8e10d0b9abd8f5428ceb00d049fa20d05..7c64a5c1bfc13bb536bdefc1f3dab53273e315fb 100644 (file)
@@ -176,3 +176,15 @@ out_fail:
                timer_base_exit(&to->of_base);
        return ret;
 }
+
+void timer_of_exit(struct timer_of *to)
+{
+       if (to->flags & TIMER_OF_IRQ)
+               timer_irq_exit(&to->of_irq);
+
+       if (to->flags & TIMER_OF_CLOCK)
+               timer_clk_exit(&to->of_clk);
+
+       if (to->flags & TIMER_OF_BASE)
+               timer_base_exit(&to->of_base);
+}
index c6d995ab93d59959fe4a54d0a753a07be58bc05c..43f5ba3f8979d9005c09247f5cb87583bef773bf 100644 (file)
@@ -67,4 +67,7 @@ static inline unsigned long timer_of_period(struct timer_of *to)
 
 extern int __init timer_of_init(struct device_node *np,
                                struct timer_of *to);
+
+extern void timer_of_exit(struct timer_of *to);
+
 #endif
index 17504129fd778164aadcdbbee89dbbbdb40d22b4..65ec5f01aa8d7369517285188c1e4dc408dc4eb8 100644 (file)
@@ -57,7 +57,7 @@ static bool bL_switching_enabled;
 #define VIRT_FREQ(cluster, freq)    ((cluster == A7_CLUSTER) ? freq >> 1 : freq)
 
 static struct thermal_cooling_device *cdev[MAX_CLUSTERS];
-static struct cpufreq_arm_bL_ops *arm_bL_ops;
+static const struct cpufreq_arm_bL_ops *arm_bL_ops;
 static struct clk *clk[MAX_CLUSTERS];
 static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1];
 static atomic_t cluster_usage[MAX_CLUSTERS + 1];
@@ -213,6 +213,7 @@ static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
 {
        u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster;
        unsigned int freqs_new;
+       int ret;
 
        cur_cluster = cpu_to_cluster(cpu);
        new_cluster = actual_cluster = per_cpu(physical_cluster, cpu);
@@ -229,7 +230,14 @@ static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
                }
        }
 
-       return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new);
+       ret = bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new);
+
+       if (!ret) {
+               arch_set_freq_scale(policy->related_cpus, freqs_new,
+                                   policy->cpuinfo.max_freq);
+       }
+
+       return ret;
 }
 
 static inline u32 get_table_count(struct cpufreq_frequency_table *table)
@@ -609,7 +617,7 @@ static int __bLs_register_notifier(void) { return 0; }
 static int __bLs_unregister_notifier(void) { return 0; }
 #endif
 
-int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
+int bL_cpufreq_register(const struct cpufreq_arm_bL_ops *ops)
 {
        int ret, i;
 
@@ -653,7 +661,7 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
 }
 EXPORT_SYMBOL_GPL(bL_cpufreq_register);
 
-void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
+void bL_cpufreq_unregister(const struct cpufreq_arm_bL_ops *ops)
 {
        if (arm_bL_ops != ops) {
                pr_err("%s: Registered with: %s, can't unregister, exiting\n",
index 184d7c3a112a8ca45e652f4c519ef506144db5fc..88a176e466c87cc4adc67dc9e10d00218be85f3c 100644 (file)
@@ -37,7 +37,7 @@ struct cpufreq_arm_bL_ops {
        void (*free_opp_table)(const struct cpumask *cpumask);
 };
 
-int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
-void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
+int bL_cpufreq_register(const struct cpufreq_arm_bL_ops *ops);
+void bL_cpufreq_unregister(const struct cpufreq_arm_bL_ops *ops);
 
 #endif /* CPUFREQ_ARM_BIG_LITTLE_H */
index 39b3f51d9a30a971eebccc1e98c5d679ecafa500..b944f290c8a4e3cc7fb3f8e7d2062cffdd849627 100644 (file)
@@ -61,7 +61,7 @@ static int dt_get_transition_latency(struct device *cpu_dev)
        return transition_latency;
 }
 
-static struct cpufreq_arm_bL_ops dt_bL_ops = {
+static const struct cpufreq_arm_bL_ops dt_bL_ops = {
        .name   = "dt-bl",
        .get_transition_latency = dt_get_transition_latency,
        .init_opp_table = dev_pm_opp_of_cpumask_add_table,
index a753c50e9e412ea96cb69fa454e81e084a3016be..ecc56e26f8f64c3b5b60ada6cef6aeb04c3c1757 100644 (file)
@@ -48,7 +48,6 @@ static const struct of_device_id whitelist[] __initconst = {
 
        { .compatible = "samsung,exynos3250", },
        { .compatible = "samsung,exynos4210", },
-       { .compatible = "samsung,exynos4212", },
        { .compatible = "samsung,exynos5250", },
 #ifndef CONFIG_BL_SWITCHER
        { .compatible = "samsung,exynos5800", },
@@ -83,8 +82,6 @@ static const struct of_device_id whitelist[] __initconst = {
        { .compatible = "rockchip,rk3368", },
        { .compatible = "rockchip,rk3399", },
 
-       { .compatible = "socionext,uniphier-ld6b", },
-
        { .compatible = "st-ericsson,u8500", },
        { .compatible = "st-ericsson,u8540", },
        { .compatible = "st-ericsson,u9500", },
index d83ab94d041a89cd35529ac5cb43c542f9282dad..545946ad07527df11459b2d35011774f94f81cac 100644 (file)
@@ -43,9 +43,17 @@ static struct freq_attr *cpufreq_dt_attr[] = {
 static int set_target(struct cpufreq_policy *policy, unsigned int index)
 {
        struct private_data *priv = policy->driver_data;
+       unsigned long freq = policy->freq_table[index].frequency;
+       int ret;
+
+       ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000);
 
-       return dev_pm_opp_set_rate(priv->cpu_dev,
-                                  policy->freq_table[index].frequency * 1000);
+       if (!ret) {
+               arch_set_freq_scale(policy->related_cpus, freq,
+                                   policy->cpuinfo.max_freq);
+       }
+
+       return ret;
 }
 
 /*
index ea43b147a7fe93adc3c8229327532debec429486..41d148af77482a4f93bd2c415f936052302be507 100644 (file)
@@ -161,6 +161,12 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
 }
 EXPORT_SYMBOL_GPL(get_cpu_idle_time);
 
+__weak void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
+               unsigned long max_freq)
+{
+}
+EXPORT_SYMBOL_GPL(arch_set_freq_scale);
+
 /*
  * This is a generic cpufreq init() routine which can be used by cpufreq
  * drivers of SMP systems. It will do following:
index e75880eb037d3b358b8afcfa80fa5d8b41353610..1e55b5790853517dbd6605ebb4e1e328adff75ba 100644 (file)
@@ -118,8 +118,11 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
                        break;
                len += snprintf(buf + len, PAGE_SIZE - len, "\n");
        }
-       if (len >= PAGE_SIZE)
-               return PAGE_SIZE;
+
+       if (len >= PAGE_SIZE) {
+               pr_warn_once("cpufreq transition table exceeds PAGE_SIZE. Disabling\n");
+               return -EFBIG;
+       }
        return len;
 }
 cpufreq_freq_attr_ro(trans_table);
index 14466a9b01c0b42b4eaa10fc946e1c5ad70f0d82..628fe899cb483da9dbf0f7661b537734bc82f784 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/pm_opp.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
@@ -191,6 +192,57 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
        .suspend = cpufreq_generic_suspend,
 };
 
+#define OCOTP_CFG3                     0x440
+#define OCOTP_CFG3_SPEED_SHIFT         16
+#define OCOTP_CFG3_SPEED_1P2GHZ                0x3
+#define OCOTP_CFG3_SPEED_996MHZ                0x2
+#define OCOTP_CFG3_SPEED_852MHZ                0x1
+
+static void imx6q_opp_check_speed_grading(struct device *dev)
+{
+       struct device_node *np;
+       void __iomem *base;
+       u32 val;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
+       if (!np)
+               return;
+
+       base = of_iomap(np, 0);
+       if (!base) {
+               dev_err(dev, "failed to map ocotp\n");
+               goto put_node;
+       }
+
+       /*
+        * SPEED_GRADING[1:0] defines the max speed of ARM:
+        * 2b'11: 1200000000Hz;
+        * 2b'10: 996000000Hz;
+        * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
+        * 2b'00: 792000000Hz;
+        * We need to set the max speed of ARM according to fuse map.
+        */
+       val = readl_relaxed(base + OCOTP_CFG3);
+       val >>= OCOTP_CFG3_SPEED_SHIFT;
+       val &= 0x3;
+
+       if ((val != OCOTP_CFG3_SPEED_1P2GHZ) &&
+            of_machine_is_compatible("fsl,imx6q"))
+               if (dev_pm_opp_disable(dev, 1200000000))
+                       dev_warn(dev, "failed to disable 1.2GHz OPP\n");
+       if (val < OCOTP_CFG3_SPEED_996MHZ)
+               if (dev_pm_opp_disable(dev, 996000000))
+                       dev_warn(dev, "failed to disable 996MHz OPP\n");
+       if (of_machine_is_compatible("fsl,imx6q")) {
+               if (val != OCOTP_CFG3_SPEED_852MHZ)
+                       if (dev_pm_opp_disable(dev, 852000000))
+                               dev_warn(dev, "failed to disable 852MHz OPP\n");
+       }
+       iounmap(base);
+put_node:
+       of_node_put(np);
+}
+
 static int imx6q_cpufreq_probe(struct platform_device *pdev)
 {
        struct device_node *np;
@@ -252,28 +304,21 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
                goto put_reg;
        }
 
-       /*
-        * We expect an OPP table supplied by platform.
-        * Just, incase the platform did not supply the OPP
-        * table, it will try to get it.
-        */
-       num = dev_pm_opp_get_opp_count(cpu_dev);
-       if (num < 0) {
-               ret = dev_pm_opp_of_add_table(cpu_dev);
-               if (ret < 0) {
-                       dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
-                       goto put_reg;
-               }
+       ret = dev_pm_opp_of_add_table(cpu_dev);
+       if (ret < 0) {
+               dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
+               goto put_reg;
+       }
 
-               /* Because we have added the OPPs here, we must free them */
-               free_opp = true;
+       imx6q_opp_check_speed_grading(cpu_dev);
 
-               num = dev_pm_opp_get_opp_count(cpu_dev);
-               if (num < 0) {
-                       ret = num;
-                       dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
-                       goto out_free_opp;
-               }
+       /* Because we have added the OPPs here, we must free them */
+       free_opp = true;
+       num = dev_pm_opp_get_opp_count(cpu_dev);
+       if (num < 0) {
+               ret = num;
+               dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
+               goto out_free_opp;
        }
 
        ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
index 062d71434e470eeb452edcc10417aae7e4d809cc..b01e31db5f8371584ff26e807fe7a74b5724e100 100644 (file)
@@ -1043,7 +1043,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data) {
-               pr_err("unable to alloc powernow_k8_data");
+               pr_err("unable to alloc powernow_k8_data\n");
                return -ENOMEM;
        }
 
index 3ff5160451b436ec48511a9428ab611b2291b1f9..b6d7c4c98d0ab67a3d141c0cc8360d722863d388 100644 (file)
@@ -90,6 +90,7 @@ struct global_pstate_info {
        int last_gpstate_idx;
        spinlock_t gpstate_lock;
        struct timer_list timer;
+       struct cpufreq_policy *policy;
 };
 
 static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
@@ -625,10 +626,10 @@ static inline void  queue_gpstate_timer(struct global_pstate_info *gpstates)
  * according quadratic equation. Queues a new timer if it is still not equal
  * to local pstate
  */
-void gpstate_timer_handler(unsigned long data)
+void gpstate_timer_handler(struct timer_list *t)
 {
-       struct cpufreq_policy *policy = (struct cpufreq_policy *)data;
-       struct global_pstate_info *gpstates = policy->driver_data;
+       struct global_pstate_info *gpstates = from_timer(gpstates, t, timer);
+       struct cpufreq_policy *policy = gpstates->policy;
        int gpstate_idx, lpstate_idx;
        unsigned long val;
        unsigned int time_diff = jiffies_to_msecs(jiffies)
@@ -800,9 +801,9 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->driver_data = gpstates;
 
        /* initialize timer */
-       init_timer_pinned_deferrable(&gpstates->timer);
-       gpstates->timer.data = (unsigned long)policy;
-       gpstates->timer.function = gpstate_timer_handler;
+       gpstates->policy = policy;
+       timer_setup(&gpstates->timer, gpstate_timer_handler,
+                   TIMER_PINNED | TIMER_DEFERRABLE);
        gpstates->timer.expires = jiffies +
                                msecs_to_jiffies(GPSTATE_TIMER_INTERVAL);
        spin_lock_init(&gpstates->gpstate_lock);
index ce345bf34d5ddfec4f494deb84ca35021c088c0a..06b024a3e474fc6657830b5af1a300d330ab7e8e 100644 (file)
@@ -58,56 +58,40 @@ module_param(pxa27x_maxfreq, uint, 0);
 MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz"
                 "(typically 624=>pxa270, 416=>pxa271, 520=>pxa272)");
 
+struct pxa_cpufreq_data {
+       struct clk *clk_core;
+};
+static struct pxa_cpufreq_data  pxa_cpufreq_data;
+
 struct pxa_freqs {
        unsigned int khz;
-       unsigned int membus;
-       unsigned int cccr;
-       unsigned int div2;
-       unsigned int cclkcfg;
        int vmin;
        int vmax;
 };
 
-/* Define the refresh period in mSec for the SDRAM and the number of rows */
-#define SDRAM_TREF     64      /* standard 64ms SDRAM */
-static unsigned int sdram_rows;
-
-#define CCLKCFG_TURBO          0x1
-#define CCLKCFG_FCS            0x2
-#define CCLKCFG_HALFTURBO      0x4
-#define CCLKCFG_FASTBUS                0x8
-#define MDREFR_DB2_MASK                (MDREFR_K2DB2 | MDREFR_K1DB2)
-#define MDREFR_DRI_MASK                0xFFF
-
-#define MDCNFG_DRAC2(mdcnfg) (((mdcnfg) >> 21) & 0x3)
-#define MDCNFG_DRAC0(mdcnfg) (((mdcnfg) >> 5) & 0x3)
-
 /*
  * PXA255 definitions
  */
-/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
-#define CCLKCFG                        CCLKCFG_TURBO | CCLKCFG_FCS
-
 static const struct pxa_freqs pxa255_run_freqs[] =
 {
-       /* CPU   MEMBUS  CCCR  DIV2 CCLKCFG                run  turbo PXbus SDRAM */
-       { 99500,  99500, 0x121, 1,  CCLKCFG, -1, -1},   /*  99,   99,   50,   50  */
-       {132700, 132700, 0x123, 1,  CCLKCFG, -1, -1},   /* 133,  133,   66,   66  */
-       {199100,  99500, 0x141, 0,  CCLKCFG, -1, -1},   /* 199,  199,   99,   99  */
-       {265400, 132700, 0x143, 1,  CCLKCFG, -1, -1},   /* 265,  265,  133,   66  */
-       {331800, 165900, 0x145, 1,  CCLKCFG, -1, -1},   /* 331,  331,  166,   83  */
-       {398100,  99500, 0x161, 0,  CCLKCFG, -1, -1},   /* 398,  398,  196,   99  */
+       /* CPU   MEMBUS            run  turbo PXbus SDRAM */
+       { 99500, -1, -1},       /*  99,   99,   50,   50  */
+       {132700, -1, -1},       /* 133,  133,   66,   66  */
+       {199100, -1, -1},       /* 199,  199,   99,   99  */
+       {265400, -1, -1},       /* 265,  265,  133,   66  */
+       {331800, -1, -1},       /* 331,  331,  166,   83  */
+       {398100, -1, -1},       /* 398,  398,  196,   99  */
 };
 
 /* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
 static const struct pxa_freqs pxa255_turbo_freqs[] =
 {
-       /* CPU   MEMBUS  CCCR  DIV2 CCLKCFG        run  turbo PXbus SDRAM */
-       { 99500, 99500,  0x121, 1,  CCLKCFG, -1, -1},   /*  99,   99,   50,   50  */
-       {199100, 99500,  0x221, 0,  CCLKCFG, -1, -1},   /*  99,  199,   50,   99  */
-       {298500, 99500,  0x321, 0,  CCLKCFG, -1, -1},   /*  99,  287,   50,   99  */
-       {298600, 99500,  0x1c1, 0,  CCLKCFG, -1, -1},   /* 199,  287,   99,   99  */
-       {398100, 99500,  0x241, 0,  CCLKCFG, -1, -1},   /* 199,  398,   99,   99  */
+       /* CPU                     run  turbo PXbus SDRAM */
+       { 99500, -1, -1},       /*  99,   99,   50,   50  */
+       {199100, -1, -1},       /*  99,  199,   50,   99  */
+       {298500, -1, -1},       /*  99,  287,   50,   99  */
+       {298600, -1, -1},       /* 199,  287,   99,   99  */
+       {398100, -1, -1},       /* 199,  398,   99,   99  */
 };
 
 #define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs)
@@ -122,47 +106,14 @@ static unsigned int pxa255_turbo_table;
 module_param(pxa255_turbo_table, uint, 0);
 MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table, !0 = turbo table)");
 
-/*
- * PXA270 definitions
- *
- * For the PXA27x:
- * Control variables are A, L, 2N for CCCR; B, HT, T for CLKCFG.
- *
- * A = 0 => memory controller clock from table 3-7,
- * A = 1 => memory controller clock = system bus clock
- * Run mode frequency  = 13 MHz * L
- * Turbo mode frequency = 13 MHz * L * N
- * System bus frequency = 13 MHz * L / (B + 1)
- *
- * In CCCR:
- * A = 1
- * L = 16        oscillator to run mode ratio
- * 2N = 6        2 * (turbo mode to run mode ratio)
- *
- * In CCLKCFG:
- * B = 1         Fast bus mode
- * HT = 0        Half-Turbo mode
- * T = 1         Turbo mode
- *
- * For now, just support some of the combinations in table 3-7 of
- * PXA27x Processor Family Developer's Manual to simplify frequency
- * change sequences.
- */
-#define PXA27x_CCCR(A, L, N2) (A << 25 | N2 << 7 | L)
-#define CCLKCFG2(B, HT, T) \
-  (CCLKCFG_FCS | \
-   ((B)  ? CCLKCFG_FASTBUS : 0) | \
-   ((HT) ? CCLKCFG_HALFTURBO : 0) | \
-   ((T)  ? CCLKCFG_TURBO : 0))
-
 static struct pxa_freqs pxa27x_freqs[] = {
-       {104000, 104000, PXA27x_CCCR(1,  8, 2), 0, CCLKCFG2(1, 0, 1),  900000, 1705000 },
-       {156000, 104000, PXA27x_CCCR(1,  8, 3), 0, CCLKCFG2(1, 0, 1), 1000000, 1705000 },
-       {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1), 1180000, 1705000 },
-       {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1), 1250000, 1705000 },
-       {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1), 1350000, 1705000 },
-       {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1), 1450000, 1705000 },
-       {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1), 1550000, 1705000 }
+       {104000,  900000, 1705000 },
+       {156000, 1000000, 1705000 },
+       {208000, 1180000, 1705000 },
+       {312000, 1250000, 1705000 },
+       {416000, 1350000, 1705000 },
+       {520000, 1450000, 1705000 },
+       {624000, 1550000, 1705000 }
 };
 
 #define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs)
@@ -241,51 +192,29 @@ static void pxa27x_guess_max_freq(void)
        }
 }
 
-static void init_sdram_rows(void)
-{
-       uint32_t mdcnfg = __raw_readl(MDCNFG);
-       unsigned int drac2 = 0, drac0 = 0;
-
-       if (mdcnfg & (MDCNFG_DE2 | MDCNFG_DE3))
-               drac2 = MDCNFG_DRAC2(mdcnfg);
-
-       if (mdcnfg & (MDCNFG_DE0 | MDCNFG_DE1))
-               drac0 = MDCNFG_DRAC0(mdcnfg);
-
-       sdram_rows = 1 << (11 + max(drac0, drac2));
-}
-
-static u32 mdrefr_dri(unsigned int freq)
-{
-       u32 interval = freq * SDRAM_TREF / sdram_rows;
-
-       return (interval - (cpu_is_pxa27x() ? 31 : 0)) / 32;
-}
-
 static unsigned int pxa_cpufreq_get(unsigned int cpu)
 {
-       return get_clk_frequency_khz(0);
+       struct pxa_cpufreq_data *data = cpufreq_get_driver_data();
+
+       return (unsigned int) clk_get_rate(data->clk_core) / 1000;
 }
 
 static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
 {
        struct cpufreq_frequency_table *pxa_freqs_table;
        const struct pxa_freqs *pxa_freq_settings;
-       unsigned long flags;
-       unsigned int new_freq_cpu, new_freq_mem;
-       unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
+       struct pxa_cpufreq_data *data = cpufreq_get_driver_data();
+       unsigned int new_freq_cpu;
        int ret = 0;
 
        /* Get the current policy */
        find_freq_tables(&pxa_freqs_table, &pxa_freq_settings);
 
        new_freq_cpu = pxa_freq_settings[idx].khz;
-       new_freq_mem = pxa_freq_settings[idx].membus;
 
        if (freq_debug)
-               pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n",
-                        new_freq_cpu / 1000, (pxa_freq_settings[idx].div2) ?
-                        (new_freq_mem / 2000) : (new_freq_mem / 1000));
+               pr_debug("Changing CPU frequency from %d Mhz to %d Mhz\n",
+                        policy->cur / 1000,  new_freq_cpu / 1000);
 
        if (vcc_core && new_freq_cpu > policy->cur) {
                ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
@@ -293,53 +222,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
                        return ret;
        }
 
-       /* Calculate the next MDREFR.  If we're slowing down the SDRAM clock
-        * we need to preset the smaller DRI before the change.  If we're
-        * speeding up we need to set the larger DRI value after the change.
-        */
-       preset_mdrefr = postset_mdrefr = __raw_readl(MDREFR);
-       if ((preset_mdrefr & MDREFR_DRI_MASK) > mdrefr_dri(new_freq_mem)) {
-               preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK);
-               preset_mdrefr |= mdrefr_dri(new_freq_mem);
-       }
-       postset_mdrefr =
-               (postset_mdrefr & ~MDREFR_DRI_MASK) | mdrefr_dri(new_freq_mem);
-
-       /* If we're dividing the memory clock by two for the SDRAM clock, this
-        * must be set prior to the change.  Clearing the divide must be done
-        * after the change.
-        */
-       if (pxa_freq_settings[idx].div2) {
-               preset_mdrefr  |= MDREFR_DB2_MASK;
-               postset_mdrefr |= MDREFR_DB2_MASK;
-       } else {
-               postset_mdrefr &= ~MDREFR_DB2_MASK;
-       }
-
-       local_irq_save(flags);
-
-       /* Set new the CCCR and prepare CCLKCFG */
-       writel(pxa_freq_settings[idx].cccr, CCCR);
-       cclkcfg = pxa_freq_settings[idx].cclkcfg;
-
-       asm volatile("                                                  \n\
-               ldr     r4, [%1]                /* load MDREFR */       \n\
-               b       2f                                              \n\
-               .align  5                                               \n\
-1:                                                                     \n\
-               str     %3, [%1]                /* preset the MDREFR */ \n\
-               mcr     p14, 0, %2, c6, c0, 0   /* set CCLKCFG[FCS] */  \n\
-               str     %4, [%1]                /* postset the MDREFR */ \n\
-                                                                       \n\
-               b       3f                                              \n\
-2:             b       1b                                              \n\
-3:             nop                                                     \n\
-         "
-                    : "=&r" (unused)
-                    : "r" (MDREFR), "r" (cclkcfg),
-                      "r" (preset_mdrefr), "r" (postset_mdrefr)
-                    : "r4", "r5");
-       local_irq_restore(flags);
+       clk_set_rate(data->clk_core, new_freq_cpu * 1000);
 
        /*
         * Even if voltage setting fails, we don't report it, as the frequency
@@ -369,8 +252,6 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
 
        pxa_cpufreq_init_voltages();
 
-       init_sdram_rows();
-
        /* set default policy and cpuinfo */
        policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
 
@@ -429,11 +310,17 @@ static struct cpufreq_driver pxa_cpufreq_driver = {
        .init   = pxa_cpufreq_init,
        .get    = pxa_cpufreq_get,
        .name   = "PXA2xx",
+       .driver_data = &pxa_cpufreq_data,
 };
 
 static int __init pxa_cpu_init(void)
 {
        int ret = -ENODEV;
+
+       pxa_cpufreq_data.clk_core = clk_get_sys(NULL, "core");
+       if (IS_ERR(pxa_cpufreq_data.clk_core))
+               return PTR_ERR(pxa_cpufreq_data.clk_core);
+
        if (cpu_is_pxa25x() || cpu_is_pxa27x())
                ret = cpufreq_register_driver(&pxa_cpufreq_driver);
        return ret;
index 8de2364b5995ac676e833abec620af47328b555a..05d299052c5cc143015193d60cd91e6eefd5dda2 100644 (file)
@@ -53,7 +53,7 @@ static int scpi_init_opp_table(const struct cpumask *cpumask)
        return ret;
 }
 
-static struct cpufreq_arm_bL_ops scpi_cpufreq_ops = {
+static const struct cpufreq_arm_bL_ops scpi_cpufreq_ops = {
        .name   = "scpi",
        .get_transition_latency = scpi_get_transition_latency,
        .init_opp_table = scpi_init_opp_table,
index 4894924a3ca28c9deee52c4f3aab0dea96af2167..195f27f9c1cbe45b623089fa2a43612fb0034ee6 100644 (file)
@@ -177,7 +177,7 @@ static int spear_cpufreq_probe(struct platform_device *pdev)
 
        np = of_cpu_device_node_get(0);
        if (!np) {
-               pr_err("No cpu node found");
+               pr_err("No cpu node found\n");
                return -ENODEV;
        }
 
@@ -187,7 +187,7 @@ static int spear_cpufreq_probe(struct platform_device *pdev)
 
        prop = of_find_property(np, "cpufreq_tbl", NULL);
        if (!prop || !prop->value) {
-               pr_err("Invalid cpufreq_tbl");
+               pr_err("Invalid cpufreq_tbl\n");
                ret = -ENODEV;
                goto out_put_node;
        }
index ccab452a4ef5b739cd8294cfa3197211afa9afb8..8085ec9000d19eb3c1ed3800844f4eeb12be8511 100644 (file)
@@ -367,7 +367,7 @@ unsigned int speedstep_detect_processor(void)
                        } else
                                return SPEEDSTEP_CPU_PIII_C;
                }
-
+               /* fall through */
        default:
                return 0;
        }
index 4bf47de6101faca3896966cd4a3214d190568b5c..923317f03b4bc367b8ce3d79197bca1d2b6f9a52 100644 (file)
@@ -205,6 +205,7 @@ static int ti_cpufreq_init(void)
 
        np = of_find_node_by_path("/");
        match = of_match_node(ti_cpufreq_of_match, np);
+       of_node_put(np);
        if (!match)
                return -ENODEV;
 
@@ -217,7 +218,8 @@ static int ti_cpufreq_init(void)
        opp_data->cpu_dev = get_cpu_device(0);
        if (!opp_data->cpu_dev) {
                pr_err("%s: Failed to get device for CPU0\n", __func__);
-               return -ENODEV;
+               ret = ENODEV;
+               goto free_opp_data;
        }
 
        opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev);
@@ -262,6 +264,8 @@ register_cpufreq_dt:
 
 fail_put_node:
        of_node_put(opp_data->opp_node);
+free_opp_data:
+       kfree(opp_data);
 
        return ret;
 }
index 87e5bdc5ec74cb4e03be68ca4e7134e297bbfaad..53237289e6060a52f66b3f2a47ba72428eb6feab 100644 (file)
@@ -42,7 +42,7 @@ static int ve_spc_get_transition_latency(struct device *cpu_dev)
        return 1000000; /* 1 ms */
 }
 
-static struct cpufreq_arm_bL_ops ve_spc_cpufreq_ops = {
+static const struct cpufreq_arm_bL_ops ve_spc_cpufreq_ops = {
        .name   = "vexpress-spc",
        .get_transition_latency = ve_spc_get_transition_latency,
        .init_opp_table = ve_spc_init_opp_table,
index 52a75053ee0312146e0ab879bc351b46153faee7..ddee1b601b89f2ae2798b33a9c5b2c959a2e4e31 100644 (file)
@@ -72,12 +72,94 @@ static const struct of_device_id arm_idle_state_match[] __initconst = {
 };
 
 /*
- * arm_idle_init
+ * arm_idle_init_cpu
  *
  * Registers the arm specific cpuidle driver with the cpuidle
  * framework. It relies on core code to parse the idle states
  * and initialize them using driver data structures accordingly.
  */
+static int __init arm_idle_init_cpu(int cpu)
+{
+       int ret;
+       struct cpuidle_driver *drv;
+       struct cpuidle_device *dev;
+
+       drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL);
+       if (!drv)
+               return -ENOMEM;
+
+       drv->cpumask = (struct cpumask *)cpumask_of(cpu);
+
+       /*
+        * Initialize idle states data, starting at index 1.  This
+        * driver is DT only, if no DT idle states are detected (ret
+        * == 0) let the driver initialization fail accordingly since
+        * there is no reason to initialize the idle driver if only
+        * wfi is supported.
+        */
+       ret = dt_init_idle_driver(drv, arm_idle_state_match, 1);
+       if (ret <= 0) {
+               ret = ret ? : -ENODEV;
+               goto out_kfree_drv;
+       }
+
+       ret = cpuidle_register_driver(drv);
+       if (ret) {
+               pr_err("Failed to register cpuidle driver\n");
+               goto out_kfree_drv;
+       }
+
+       /*
+        * Call arch CPU operations in order to initialize
+        * idle states suspend back-end specific data
+        */
+       ret = arm_cpuidle_init(cpu);
+
+       /*
+        * Skip the cpuidle device initialization if the reported
+        * failure is a HW misconfiguration/breakage (-ENXIO).
+        */
+       if (ret == -ENXIO)
+               return 0;
+
+       if (ret) {
+               pr_err("CPU %d failed to init idle CPU ops\n", cpu);
+               goto out_unregister_drv;
+       }
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               pr_err("Failed to allocate cpuidle device\n");
+               ret = -ENOMEM;
+               goto out_unregister_drv;
+       }
+       dev->cpu = cpu;
+
+       ret = cpuidle_register_device(dev);
+       if (ret) {
+               pr_err("Failed to register cpuidle device for CPU %d\n",
+                      cpu);
+               goto out_kfree_dev;
+       }
+
+       return 0;
+
+out_kfree_dev:
+       kfree(dev);
+out_unregister_drv:
+       cpuidle_unregister_driver(drv);
+out_kfree_drv:
+       kfree(drv);
+       return ret;
+}
+
+/*
+ * arm_idle_init - Initializes arm cpuidle driver
+ *
+ * Initializes arm cpuidle driver for all CPUs, if any CPU fails
+ * to register cpuidle driver then rollback to cancel all CPUs
+ * registeration.
+ */
 static int __init arm_idle_init(void)
 {
        int cpu, ret;
@@ -85,79 +167,20 @@ static int __init arm_idle_init(void)
        struct cpuidle_device *dev;
 
        for_each_possible_cpu(cpu) {
-
-               drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL);
-               if (!drv) {
-                       ret = -ENOMEM;
-                       goto out_fail;
-               }
-
-               drv->cpumask = (struct cpumask *)cpumask_of(cpu);
-
-               /*
-                * Initialize idle states data, starting at index 1.  This
-                * driver is DT only, if no DT idle states are detected (ret
-                * == 0) let the driver initialization fail accordingly since
-                * there is no reason to initialize the idle driver if only
-                * wfi is supported.
-                */
-               ret = dt_init_idle_driver(drv, arm_idle_state_match, 1);
-               if (ret <= 0) {
-                       ret = ret ? : -ENODEV;
-                       goto init_fail;
-               }
-
-               ret = cpuidle_register_driver(drv);
-               if (ret) {
-                       pr_err("Failed to register cpuidle driver\n");
-                       goto init_fail;
-               }
-
-               /*
-                * Call arch CPU operations in order to initialize
-                * idle states suspend back-end specific data
-                */
-               ret = arm_cpuidle_init(cpu);
-
-               /*
-                * Skip the cpuidle device initialization if the reported
-                * failure is a HW misconfiguration/breakage (-ENXIO).
-                */
-               if (ret == -ENXIO)
-                       continue;
-
-               if (ret) {
-                       pr_err("CPU %d failed to init idle CPU ops\n", cpu);
-                       goto out_fail;
-               }
-
-               dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-               if (!dev) {
-                       pr_err("Failed to allocate cpuidle device\n");
-                       ret = -ENOMEM;
+               ret = arm_idle_init_cpu(cpu);
+               if (ret)
                        goto out_fail;
-               }
-               dev->cpu = cpu;
-
-               ret = cpuidle_register_device(dev);
-               if (ret) {
-                       pr_err("Failed to register cpuidle device for CPU %d\n",
-                              cpu);
-                       kfree(dev);
-                       goto out_fail;
-               }
        }
 
        return 0;
-init_fail:
-       kfree(drv);
+
 out_fail:
        while (--cpu >= 0) {
                dev = per_cpu(cpuidle_devices, cpu);
+               drv = cpuidle_get_cpu_driver(dev);
                cpuidle_unregister_device(dev);
-               kfree(dev);
-               drv = cpuidle_get_driver();
                cpuidle_unregister_driver(drv);
+               kfree(dev);
                kfree(drv);
        }
 
index 484cc8909d5c3630c197ae58ee4c98d2807f42c7..68a16827f45fd57f8bd89cbb15140662374db3d3 100644 (file)
@@ -208,6 +208,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
                        return -EBUSY;
                }
                target_state = &drv->states[index];
+               broadcast = false;
        }
 
        /* Take note of the planned idle state. */
@@ -387,9 +388,12 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
        if (dev->enabled)
                return 0;
 
+       if (!cpuidle_curr_governor)
+               return -EIO;
+
        drv = cpuidle_get_cpu_driver(dev);
 
-       if (!drv || !cpuidle_curr_governor)
+       if (!drv)
                return -EIO;
 
        if (!dev->registered)
@@ -399,9 +403,11 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
        if (ret)
                return ret;
 
-       if (cpuidle_curr_governor->enable &&
-           (ret = cpuidle_curr_governor->enable(drv, dev)))
-               goto fail_sysfs;
+       if (cpuidle_curr_governor->enable) {
+               ret = cpuidle_curr_governor->enable(drv, dev);
+               if (ret)
+                       goto fail_sysfs;
+       }
 
        smp_wmb();
 
index ce1a2ffffb2a0f88ad9c43d89b34f9f553bc9009..1ad8745fd6d648321bcae1323c33f2ae549afcce 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/pm_qos.h>
 #include <linux/jiffies.h>
 #include <linux/tick.h>
+#include <linux/cpu.h>
 
 #include <asm/io.h>
 #include <linux/uaccess.h>
@@ -67,10 +68,16 @@ static int ladder_select_state(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev)
 {
        struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
+       struct device *device = get_cpu_device(dev->cpu);
        struct ladder_device_state *last_state;
        int last_residency, last_idx = ldev->last_state_idx;
        int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0;
        int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+       int resume_latency = dev_pm_qos_raw_read_value(device);
+
+       if (resume_latency < latency_req &&
+           resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
+               latency_req = resume_latency;
 
        /* Special case when user has set very strict latency requirement */
        if (unlikely(latency_req == 0)) {
index 48eaf2879228371fa92fa0f314d7e3407295b78d..aa390404e85f132705e4ca80506d15d292469c7e 100644 (file)
@@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                data->needs_update = 0;
        }
 
-       /* resume_latency is 0 means no restriction */
-       if (resume_latency && resume_latency < latency_req)
+       if (resume_latency < latency_req &&
+           resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
                latency_req = resume_latency;
 
        /* Special case when user has set very strict latency requirement */
index 0f9754e077191e07f3ad985ad2897822f99a932c..456278440863b7b170bd7037e4a4eca9a122fdad 100644 (file)
@@ -2072,9 +2072,9 @@ static void artpec6_crypto_process_queue(struct artpec6_crypto *ac)
                del_timer(&ac->timer);
 }
 
-static void artpec6_crypto_timeout(unsigned long data)
+static void artpec6_crypto_timeout(struct timer_list *t)
 {
-       struct artpec6_crypto *ac = (struct artpec6_crypto *) data;
+       struct artpec6_crypto *ac = from_timer(ac, t, timer);
 
        dev_info_ratelimited(artpec6_crypto_dev, "timeout\n");
 
@@ -3063,7 +3063,7 @@ static int artpec6_crypto_probe(struct platform_device *pdev)
        spin_lock_init(&ac->queue_lock);
        INIT_LIST_HEAD(&ac->queue);
        INIT_LIST_HEAD(&ac->pending);
-       setup_timer(&ac->timer, artpec6_crypto_timeout, (unsigned long) ac);
+       timer_setup(&ac->timer, artpec6_crypto_timeout, 0);
 
        ac->base = base;
 
index d258953ff488331486334f8fc24a99c1bc5d0ca1..f4f258075b895a8c55fbd836d35b1b6b399beed8 100644 (file)
@@ -172,7 +172,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 
        while (rd_reg32(&jrp->rregs->outring_used)) {
 
-               head = ACCESS_ONCE(jrp->head);
+               head = READ_ONCE(jrp->head);
 
                spin_lock(&jrp->outlock);
 
@@ -341,7 +341,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
        spin_lock_bh(&jrp->inplock);
 
        head = jrp->head;
-       tail = ACCESS_ONCE(jrp->tail);
+       tail = READ_ONCE(jrp->tail);
 
        if (!rd_reg32(&jrp->rregs->inpring_avail) ||
            CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
index bf25f415eea659862478283eef4cd190173a8a45..0eb2706f23c898932f01438d9bf8b5cb3c3585a6 100644 (file)
@@ -149,7 +149,7 @@ struct mv_req_hash_ctx {
        int count_add;
 };
 
-static void mv_completion_timer_callback(unsigned long unused)
+static void mv_completion_timer_callback(struct timer_list *unused)
 {
        int active = readl(cpg->reg + SEC_ACCEL_CMD) & SEC_CMD_EN_SEC_ACCL0;
 
@@ -167,7 +167,7 @@ static void mv_completion_timer_callback(unsigned long unused)
 
 static void mv_setup_timer(void)
 {
-       setup_timer(&cpg->completion_timer, &mv_completion_timer_callback, 0);
+       timer_setup(&cpg->completion_timer, mv_completion_timer_callback, 0);
        mod_timer(&cpg->completion_timer,
                        jiffies + msecs_to_jiffies(MV_CESA_EXPIRE));
 }
index 874ddf5e9087e5a0fc62e09bad3889f964c57d5f..0f20f5ec96179a3505ac6f042242329ad18125df 100644 (file)
@@ -193,7 +193,7 @@ static int wait_for_csb(struct nx842_workmem *wmem,
        ktime_t start = wmem->start, now = ktime_get();
        ktime_t timeout = ktime_add_ms(start, CSB_WAIT_MAX);
 
-       while (!(ACCESS_ONCE(csb->flags) & CSB_V)) {
+       while (!(READ_ONCE(csb->flags) & CSB_V)) {
                cpu_relax();
                now = ktime_get();
                if (ktime_after(now, timeout))
index b6f14844702e0c866037c0079539fdfc09be9753..5a6dc53b2b9db221e0e006391ee78e0f32a2e180 100644 (file)
@@ -1125,9 +1125,9 @@ static irqreturn_t spacc_spacc_irq(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static void spacc_packet_timeout(unsigned long data)
+static void spacc_packet_timeout(struct timer_list *t)
 {
-       struct spacc_engine *engine = (struct spacc_engine *)data;
+       struct spacc_engine *engine = from_timer(engine, t, packet_timeout);
 
        spacc_process_done(engine);
 }
@@ -1714,8 +1714,7 @@ static int spacc_probe(struct platform_device *pdev)
        writel(SPA_IRQ_EN_STAT_EN | SPA_IRQ_EN_GLBL_EN,
               engine->regs + SPA_IRQ_EN_REG_OFFSET);
 
-       setup_timer(&engine->packet_timeout, spacc_packet_timeout,
-                   (unsigned long)engine);
+       timer_setup(&engine->packet_timeout, spacc_packet_timeout, 0);
 
        INIT_LIST_HEAD(&engine->pending);
        INIT_LIST_HEAD(&engine->completed);
index a1c4ee818614d2aaf403aa11f33724771bb1821e..78fb496ecb4e7775622176dc10550a7636c6afc0 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/of.h>
 #include "governor.h"
 
+#define MAX(a,b)       ((a > b) ? a : b)
+#define MIN(a,b)       ((a < b) ? a : b)
+
 static struct class *devfreq_class;
 
 /*
@@ -69,6 +72,34 @@ static struct devfreq *find_device_devfreq(struct device *dev)
        return ERR_PTR(-ENODEV);
 }
 
+static unsigned long find_available_min_freq(struct devfreq *devfreq)
+{
+       struct dev_pm_opp *opp;
+       unsigned long min_freq = 0;
+
+       opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &min_freq);
+       if (IS_ERR(opp))
+               min_freq = 0;
+       else
+               dev_pm_opp_put(opp);
+
+       return min_freq;
+}
+
+static unsigned long find_available_max_freq(struct devfreq *devfreq)
+{
+       struct dev_pm_opp *opp;
+       unsigned long max_freq = ULONG_MAX;
+
+       opp = dev_pm_opp_find_freq_floor(devfreq->dev.parent, &max_freq);
+       if (IS_ERR(opp))
+               max_freq = 0;
+       else
+               dev_pm_opp_put(opp);
+
+       return max_freq;
+}
+
 /**
  * devfreq_get_freq_level() - Lookup freq_table for the frequency
  * @devfreq:   the devfreq instance
@@ -85,11 +116,7 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
        return -EINVAL;
 }
 
-/**
- * devfreq_set_freq_table() - Initialize freq_table for the frequency
- * @devfreq:   the devfreq instance
- */
-static void devfreq_set_freq_table(struct devfreq *devfreq)
+static int set_freq_table(struct devfreq *devfreq)
 {
        struct devfreq_dev_profile *profile = devfreq->profile;
        struct dev_pm_opp *opp;
@@ -99,7 +126,7 @@ static void devfreq_set_freq_table(struct devfreq *devfreq)
        /* Initialize the freq_table from OPP table */
        count = dev_pm_opp_get_opp_count(devfreq->dev.parent);
        if (count <= 0)
-               return;
+               return -EINVAL;
 
        profile->max_state = count;
        profile->freq_table = devm_kcalloc(devfreq->dev.parent,
@@ -108,7 +135,7 @@ static void devfreq_set_freq_table(struct devfreq *devfreq)
                                        GFP_KERNEL);
        if (!profile->freq_table) {
                profile->max_state = 0;
-               return;
+               return -ENOMEM;
        }
 
        for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
@@ -116,11 +143,13 @@ static void devfreq_set_freq_table(struct devfreq *devfreq)
                if (IS_ERR(opp)) {
                        devm_kfree(devfreq->dev.parent, profile->freq_table);
                        profile->max_state = 0;
-                       return;
+                       return PTR_ERR(opp);
                }
                dev_pm_opp_put(opp);
                profile->freq_table[i] = freq;
        }
+
+       return 0;
 }
 
 /**
@@ -227,7 +256,7 @@ static int devfreq_notify_transition(struct devfreq *devfreq,
 int update_devfreq(struct devfreq *devfreq)
 {
        struct devfreq_freqs freqs;
-       unsigned long freq, cur_freq;
+       unsigned long freq, cur_freq, min_freq, max_freq;
        int err = 0;
        u32 flags = 0;
 
@@ -245,19 +274,21 @@ int update_devfreq(struct devfreq *devfreq)
                return err;
 
        /*
-        * Adjust the frequency with user freq and QoS.
+        * Adjust the frequency with user freq, QoS and available freq.
         *
         * List from the highest priority
         * max_freq
         * min_freq
         */
+       max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq);
+       min_freq = MAX(devfreq->scaling_min_freq, devfreq->min_freq);
 
-       if (devfreq->min_freq && freq < devfreq->min_freq) {
-               freq = devfreq->min_freq;
+       if (min_freq && freq < min_freq) {
+               freq = min_freq;
                flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
        }
-       if (devfreq->max_freq && freq > devfreq->max_freq) {
-               freq = devfreq->max_freq;
+       if (max_freq && freq > max_freq) {
+               freq = max_freq;
                flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
        }
 
@@ -280,10 +311,9 @@ int update_devfreq(struct devfreq *devfreq)
        freqs.new = freq;
        devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
 
-       if (devfreq->profile->freq_table)
-               if (devfreq_update_status(devfreq, freq))
-                       dev_err(&devfreq->dev,
-                               "Couldn't update frequency transition information.\n");
+       if (devfreq_update_status(devfreq, freq))
+               dev_err(&devfreq->dev,
+                       "Couldn't update frequency transition information.\n");
 
        devfreq->previous_freq = freq;
        return err;
@@ -466,6 +496,19 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
        int ret;
 
        mutex_lock(&devfreq->lock);
+
+       devfreq->scaling_min_freq = find_available_min_freq(devfreq);
+       if (!devfreq->scaling_min_freq) {
+               mutex_unlock(&devfreq->lock);
+               return -EINVAL;
+       }
+
+       devfreq->scaling_max_freq = find_available_max_freq(devfreq);
+       if (!devfreq->scaling_max_freq) {
+               mutex_unlock(&devfreq->lock);
+               return -EINVAL;
+       }
+
        ret = update_devfreq(devfreq);
        mutex_unlock(&devfreq->lock);
 
@@ -555,10 +598,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
        if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
                mutex_unlock(&devfreq->lock);
-               devfreq_set_freq_table(devfreq);
+               err = set_freq_table(devfreq);
+               if (err < 0)
+                       goto err_out;
                mutex_lock(&devfreq->lock);
        }
 
+       devfreq->min_freq = find_available_min_freq(devfreq);
+       if (!devfreq->min_freq) {
+               mutex_unlock(&devfreq->lock);
+               err = -EINVAL;
+               goto err_dev;
+       }
+       devfreq->scaling_min_freq = devfreq->min_freq;
+
+       devfreq->max_freq = find_available_max_freq(devfreq);
+       if (!devfreq->max_freq) {
+               mutex_unlock(&devfreq->lock);
+               err = -EINVAL;
+               goto err_dev;
+       }
+       devfreq->scaling_max_freq = devfreq->max_freq;
+
        dev_set_name(&devfreq->dev, "devfreq%d",
                                atomic_inc_return(&devfreq_no));
        err = device_register(&devfreq->dev);
@@ -1082,6 +1143,14 @@ unlock:
        return ret;
 }
 
+static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct devfreq *df = to_devfreq(dev);
+
+       return sprintf(buf, "%lu\n", MAX(df->scaling_min_freq, df->min_freq));
+}
+
 static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
                              const char *buf, size_t count)
 {
@@ -1108,17 +1177,15 @@ unlock:
        mutex_unlock(&df->lock);
        return ret;
 }
+static DEVICE_ATTR_RW(min_freq);
 
-#define show_one(name)                                         \
-static ssize_t name##_show                                     \
-(struct device *dev, struct device_attribute *attr, char *buf) \
-{                                                              \
-       return sprintf(buf, "%lu\n", to_devfreq(dev)->name);    \
-}
-show_one(min_freq);
-show_one(max_freq);
+static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct devfreq *df = to_devfreq(dev);
 
-static DEVICE_ATTR_RW(min_freq);
+       return sprintf(buf, "%lu\n", MIN(df->scaling_max_freq, df->max_freq));
+}
 static DEVICE_ATTR_RW(max_freq);
 
 static ssize_t available_frequencies_show(struct device *d,
@@ -1126,22 +1193,16 @@ static ssize_t available_frequencies_show(struct device *d,
                                          char *buf)
 {
        struct devfreq *df = to_devfreq(d);
-       struct device *dev = df->dev.parent;
-       struct dev_pm_opp *opp;
        ssize_t count = 0;
-       unsigned long freq = 0;
+       int i;
 
-       do {
-               opp = dev_pm_opp_find_freq_ceil(dev, &freq);
-               if (IS_ERR(opp))
-                       break;
+       mutex_lock(&df->lock);
 
-               dev_pm_opp_put(opp);
+       for (i = 0; i < df->profile->max_state; i++)
                count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
-                                  "%lu ", freq);
-               freq++;
-       } while (1);
+                               "%lu ", df->profile->freq_table[i]);
 
+       mutex_unlock(&df->lock);
        /* Truncate the trailing space */
        if (count)
                count--;
index 49f68929e024fa9fc95b8f31eda07edd5218bb53..c25658b265988b4fdd2a3f4304fdbfab83b7b9f3 100644 (file)
@@ -436,7 +436,8 @@ static int exynos_bus_probe(struct platform_device *pdev)
        ondemand_data->downdifferential = 5;
 
        /* Add devfreq device to monitor and handle the exynos bus */
-       bus->devfreq = devm_devfreq_add_device(dev, profile, "simple_ondemand",
+       bus->devfreq = devm_devfreq_add_device(dev, profile,
+                                               DEVFREQ_GOV_SIMPLE_ONDEMAND,
                                                ondemand_data);
        if (IS_ERR(bus->devfreq)) {
                dev_err(dev, "failed to add devfreq device\n");
@@ -488,7 +489,7 @@ passive:
        passive_data->parent = parent_devfreq;
 
        /* Add devfreq device for exynos bus with passive governor */
-       bus->devfreq = devm_devfreq_add_device(dev, profile, "passive",
+       bus->devfreq = devm_devfreq_add_device(dev, profile, DEVFREQ_GOV_PASSIVE,
                                                passive_data);
        if (IS_ERR(bus->devfreq)) {
                dev_err(dev,
index 673ad8cc9a1d093e3db6e2d335742a1aee529953..3bc29acbd54e85480d375514fd56e2878681fa96 100644 (file)
@@ -183,7 +183,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
 }
 
 static struct devfreq_governor devfreq_passive = {
-       .name = "passive",
+       .name = DEVFREQ_GOV_PASSIVE,
        .immutable = 1,
        .get_target_freq = devfreq_passive_get_target_freq,
        .event_handler = devfreq_passive_event_handler,
index c72f942f30a85a198b89514703b485d9f790867b..4d23ecfbd948eb7811288ec90920527d9393c9a8 100644 (file)
@@ -42,7 +42,7 @@ static int devfreq_performance_handler(struct devfreq *devfreq,
 }
 
 static struct devfreq_governor devfreq_performance = {
-       .name = "performance",
+       .name = DEVFREQ_GOV_PERFORMANCE,
        .get_target_freq = devfreq_performance_func,
        .event_handler = devfreq_performance_handler,
 };
index 0c6bed567e6d4a12249f9891f06ed97411e118bc..0c42f23249ef6de7e4aa8a6c7693714a288b3c62 100644 (file)
@@ -39,7 +39,7 @@ static int devfreq_powersave_handler(struct devfreq *devfreq,
 }
 
 static struct devfreq_governor devfreq_powersave = {
-       .name = "powersave",
+       .name = DEVFREQ_GOV_POWERSAVE,
        .get_target_freq = devfreq_powersave_func,
        .event_handler = devfreq_powersave_handler,
 };
index ae72ba5e78dfce046804a7dc5b7a08017d8a25c7..28e0f2de7100ee0cee83b1e1179c750694b942af 100644 (file)
@@ -125,7 +125,7 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
 }
 
 static struct devfreq_governor devfreq_simple_ondemand = {
-       .name = "simple_ondemand",
+       .name = DEVFREQ_GOV_SIMPLE_ONDEMAND,
        .get_target_freq = devfreq_simple_ondemand_func,
        .event_handler = devfreq_simple_ondemand_handler,
 };
index 77028c27593c635d821fab28eea57c0084a89346..080607c3f34d62433365b57b0fd0fa196eb9b96c 100644 (file)
@@ -87,7 +87,7 @@ static struct attribute *dev_entries[] = {
        NULL,
 };
 static const struct attribute_group dev_attr_group = {
-       .name   = "userspace",
+       .name   = DEVFREQ_GOV_USERSPACE,
        .attrs  = dev_entries,
 };
 
index 1b89ebbad02c0a3d546587b74ea32aef11df1884..5dfbfa3cc878f0d295a55a93cfeb9e581f56a377 100644 (file)
@@ -431,7 +431,7 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
 
        data->devfreq = devm_devfreq_add_device(dev,
                                           &rk3399_devfreq_dmc_profile,
-                                          "simple_ondemand",
+                                          DEVFREQ_GOV_SIMPLE_ONDEMAND,
                                           &data->ondemand_data);
        if (IS_ERR(data->devfreq))
                return PTR_ERR(data->devfreq);
index 346c4987b2848782336db887150b88db1a9b91a4..11d6419788c2d45eb467c3fb53614236e112d248 100644 (file)
@@ -175,11 +175,11 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
        /*
         * To trigger the error, we need to read the data back
         * (the data was written with errors above).
-        * The ACCESS_ONCE macros and printk are used to prevent the
+        * The READ_ONCE macros and printk are used to prevent the
         * the compiler optimizing these reads out.
         */
-       reg = ACCESS_ONCE(ptemp[0]);
-       read_reg = ACCESS_ONCE(ptemp[1]);
+       reg = READ_ONCE(ptemp[0]);
+       read_reg = READ_ONCE(ptemp[1]);
        /* Force Read */
        rmb();
 
@@ -618,7 +618,7 @@ static ssize_t altr_edac_device_trig(struct file *file,
        for (i = 0; i < (priv->trig_alloc_sz / sizeof(*ptemp)); i++) {
                /* Read data so we're in the correct state */
                rmb();
-               if (ACCESS_ONCE(ptemp[i]))
+               if (READ_ONCE(ptemp[i]))
                        result = -1;
                /* Toggle Error bit (it is latched), leave ECC enabled */
                writel(error_mask, (drvdata->base + priv->set_err_ofst));
@@ -635,7 +635,7 @@ static ssize_t altr_edac_device_trig(struct file *file,
 
        /* Read out written data. ECC error caused here */
        for (i = 0; i < ALTR_TRIGGER_READ_WRD_CNT; i++)
-               if (ACCESS_ONCE(ptemp[i]) != i)
+               if (READ_ONCE(ptemp[i]) != i)
                        edac_printk(KERN_ERR, EDAC_DEVICE,
                                    "Read doesn't match written data\n");
 
index ac2f30295efe45a9d13da484c9f0e07c0192a5eb..8b16ec595fa7273f125d4d0f0bdfaa8a41999c17 100644 (file)
@@ -3434,9 +3434,14 @@ MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
 
 static int __init amd64_edac_init(void)
 {
+       const char *owner;
        int err = -ENODEV;
        int i;
 
+       owner = edac_get_owner();
+       if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
+               return -EBUSY;
+
        if (!x86_match_cpu(amd64_cpuids))
                return -ENODEV;
 
index 480072139b7aa00db3d27d9381c0e6eace04835e..48193f5f3b56eb874505480a0c0a4ea12d039a64 100644 (file)
@@ -53,7 +53,7 @@ static LIST_HEAD(mc_devices);
  * Used to lock EDAC MC to just one module, avoiding two drivers e. g.
  *     apei/ghes and i7core_edac to be used at the same time.
  */
-static void const *edac_mc_owner;
+static const char *edac_mc_owner;
 
 static struct bus_type mc_bus[EDAC_MAX_MCS];
 
@@ -701,6 +701,11 @@ unlock:
 }
 EXPORT_SYMBOL(edac_mc_find);
 
+const char *edac_get_owner(void)
+{
+       return edac_mc_owner;
+}
+EXPORT_SYMBOL_GPL(edac_get_owner);
 
 /* FIXME - should a warning be printed if no error detection? correction? */
 int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
index 5357800e418d344b32d21d200c523803cbbcecbb..4165e15995ad8a16975744ac5440b2db10ca4b8e 100644 (file)
@@ -128,6 +128,14 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
                                   unsigned sz_pvt);
 
 /**
+ * edac_get_owner - Return the owner's mod_name of EDAC MC
+ *
+ * Returns:
+ *     Pointer to mod_name string when EDAC MC is owned. NULL otherwise.
+ */
+extern const char *edac_get_owner(void);
+
+/*
  * edac_mc_add_mc_with_groups() - Insert the @mci structure into the mci
  *     global list and create sysfs entries associated with @mci structure.
  *
index 6f80eb65c26caac11ebd9d9d91c099efb9365558..68b6ee18bea644cb9adfe395424adb48ddfae4f4 100644 (file)
@@ -28,10 +28,19 @@ struct ghes_edac_pvt {
        char msg[80];
 };
 
-static LIST_HEAD(ghes_reglist);
-static DEFINE_MUTEX(ghes_edac_lock);
-static int ghes_edac_mc_num;
+static atomic_t ghes_init = ATOMIC_INIT(0);
+static struct ghes_edac_pvt *ghes_pvt;
 
+/*
+ * Sync with other, potentially concurrent callers of
+ * ghes_edac_report_mem_error(). We don't know what the
+ * "inventive" firmware would do.
+ */
+static DEFINE_SPINLOCK(ghes_lock);
+
+/* "ghes_edac.force_load=1" skips the platform check */
+static bool __read_mostly force_load;
+module_param(force_load, bool, 0);
 
 /* Memory Device - Type 17 of SMBIOS spec */
 struct memdev_dmi_entry {
@@ -169,18 +178,26 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
        enum hw_event_mc_err_type type;
        struct edac_raw_error_desc *e;
        struct mem_ctl_info *mci;
-       struct ghes_edac_pvt *pvt = NULL;
+       struct ghes_edac_pvt *pvt = ghes_pvt;
+       unsigned long flags;
        char *p;
        u8 grain_bits;
 
-       list_for_each_entry(pvt, &ghes_reglist, list) {
-               if (ghes == pvt->ghes)
-                       break;
-       }
        if (!pvt) {
                pr_err("Internal error: Can't find EDAC structure\n");
                return;
        }
+
+       /*
+        * We can do the locking below because GHES defers error processing
+        * from NMI to IRQ context. Whenever that changes, we'd at least
+        * know.
+        */
+       if (WARN_ON_ONCE(in_nmi()))
+               return;
+
+       spin_lock_irqsave(&ghes_lock, flags);
+
        mci = pvt->mci;
        e = &mci->error_desc;
 
@@ -398,10 +415,17 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
                       (e->page_frame_number << PAGE_SHIFT) | e->offset_in_page,
                       grain_bits, e->syndrome, pvt->detail_location);
 
-       /* Report the error via EDAC API */
        edac_raw_mc_handle_error(type, mci, e);
+       spin_unlock_irqrestore(&ghes_lock, flags);
 }
-EXPORT_SYMBOL_GPL(ghes_edac_report_mem_error);
+
+/*
+ * Known systems that are safe to enable this module.
+ */
+static struct acpi_platform_list plat_list[] = {
+       {"HPE   ", "Server  ", 0, ACPI_SIG_FADT, all_versions},
+       { } /* End */
+};
 
 int ghes_edac_register(struct ghes *ghes, struct device *dev)
 {
@@ -409,8 +433,19 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
        int rc, num_dimm = 0;
        struct mem_ctl_info *mci;
        struct edac_mc_layer layers[1];
-       struct ghes_edac_pvt *pvt;
        struct ghes_edac_dimm_fill dimm_fill;
+       int idx;
+
+       /* Check if safe to enable on this system */
+       idx = acpi_match_platform_list(plat_list);
+       if (!force_load && idx < 0)
+               return 0;
+
+       /*
+        * We have only one logical memory controller to which all DIMMs belong.
+        */
+       if (atomic_inc_return(&ghes_init) > 1)
+               return 0;
 
        /* Get the number of DIMMs */
        dmi_walk(ghes_edac_count_dimms, &num_dimm);
@@ -425,26 +460,17 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
        layers[0].size = num_dimm;
        layers[0].is_virt_csrow = true;
 
-       /*
-        * We need to serialize edac_mc_alloc() and edac_mc_add_mc(),
-        * to avoid duplicated memory controller numbers
-        */
-       mutex_lock(&ghes_edac_lock);
-       mci = edac_mc_alloc(ghes_edac_mc_num, ARRAY_SIZE(layers), layers,
-                           sizeof(*pvt));
+       mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(struct ghes_edac_pvt));
        if (!mci) {
                pr_info("Can't allocate memory for EDAC data\n");
-               mutex_unlock(&ghes_edac_lock);
                return -ENOMEM;
        }
 
-       pvt = mci->pvt_info;
-       memset(pvt, 0, sizeof(*pvt));
-       list_add_tail(&pvt->list, &ghes_reglist);
-       pvt->ghes = ghes;
-       pvt->mci  = mci;
-       mci->pdev = dev;
+       ghes_pvt        = mci->pvt_info;
+       ghes_pvt->ghes  = ghes;
+       ghes_pvt->mci   = mci;
 
+       mci->pdev = dev;
        mci->mtype_cap = MEM_FLAG_EMPTY;
        mci->edac_ctl_cap = EDAC_FLAG_NONE;
        mci->edac_cap = EDAC_FLAG_NONE;
@@ -452,36 +478,23 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
        mci->ctl_name = "ghes_edac";
        mci->dev_name = "ghes";
 
-       if (!ghes_edac_mc_num) {
-               if (!fake) {
-                       pr_info("This EDAC driver relies on BIOS to enumerate memory and get error reports.\n");
-                       pr_info("Unfortunately, not all BIOSes reflect the memory layout correctly.\n");
-                       pr_info("So, the end result of using this driver varies from vendor to vendor.\n");
-                       pr_info("If you find incorrect reports, please contact your hardware vendor\n");
-                       pr_info("to correct its BIOS.\n");
-                       pr_info("This system has %d DIMM sockets.\n",
-                               num_dimm);
-               } else {
-                       pr_info("This system has a very crappy BIOS: It doesn't even list the DIMMS.\n");
-                       pr_info("Its SMBIOS info is wrong. It is doubtful that the error report would\n");
-                       pr_info("work on such system. Use this driver with caution\n");
-               }
+       if (fake) {
+               pr_info("This system has a very crappy BIOS: It doesn't even list the DIMMS.\n");
+               pr_info("Its SMBIOS info is wrong. It is doubtful that the error report would\n");
+               pr_info("work on such system. Use this driver with caution\n");
+       } else if (idx < 0) {
+               pr_info("This EDAC driver relies on BIOS to enumerate memory and get error reports.\n");
+               pr_info("Unfortunately, not all BIOSes reflect the memory layout correctly.\n");
+               pr_info("So, the end result of using this driver varies from vendor to vendor.\n");
+               pr_info("If you find incorrect reports, please contact your hardware vendor\n");
+               pr_info("to correct its BIOS.\n");
+               pr_info("This system has %d DIMM sockets.\n", num_dimm);
        }
 
        if (!fake) {
-               /*
-                * Fill DIMM info from DMI for the memory controller #0
-                *
-                * Keep it in blank for the other memory controllers, as
-                * there's no reliable way to properly credit each DIMM to
-                * the memory controller, as different BIOSes fill the
-                * DMI bank location fields on different ways
-                */
-               if (!ghes_edac_mc_num) {
-                       dimm_fill.count = 0;
-                       dimm_fill.mci = mci;
-                       dmi_walk(ghes_edac_dmidecode, &dimm_fill);
-               }
+               dimm_fill.count = 0;
+               dimm_fill.mci = mci;
+               dmi_walk(ghes_edac_dmidecode, &dimm_fill);
        } else {
                struct dimm_info *dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
                                                       mci->n_layers, 0, 0, 0);
@@ -497,28 +510,16 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
        if (rc < 0) {
                pr_info("Can't register at EDAC core\n");
                edac_mc_free(mci);
-               mutex_unlock(&ghes_edac_lock);
                return -ENODEV;
        }
-
-       ghes_edac_mc_num++;
-       mutex_unlock(&ghes_edac_lock);
        return 0;
 }
-EXPORT_SYMBOL_GPL(ghes_edac_register);
 
 void ghes_edac_unregister(struct ghes *ghes)
 {
        struct mem_ctl_info *mci;
-       struct ghes_edac_pvt *pvt, *tmp;
-
-       list_for_each_entry_safe(pvt, tmp, &ghes_reglist, list) {
-               if (ghes == pvt->ghes) {
-                       mci = pvt->mci;
-                       edac_mc_del_mc(mci->pdev);
-                       edac_mc_free(mci);
-                       list_del(&pvt->list);
-               }
-       }
+
+       mci = ghes_pvt->mci;
+       edac_mc_del_mc(mci->pdev);
+       edac_mc_free(mci);
 }
-EXPORT_SYMBOL_GPL(ghes_edac_unregister);
index c16c3b931b3d0ef9cd68b01e6d81de4987d5c794..8c5540160a23be06fbada0708cd216d62bd61b15 100644 (file)
@@ -2159,8 +2159,13 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
        mci->edac_ctl_cap = EDAC_FLAG_NONE;
        mci->edac_cap = EDAC_FLAG_NONE;
        mci->mod_name = "i7core_edac.c";
-       mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d",
-                                 i7core_dev->socket);
+
+       mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d", i7core_dev->socket);
+       if (!mci->ctl_name) {
+               rc = -ENOMEM;
+               goto fail1;
+       }
+
        mci->dev_name = pci_name(i7core_dev->pdev[0]);
        mci->ctl_page_to_phys = NULL;
 
@@ -2214,6 +2219,8 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 
 fail0:
        kfree(mci->ctl_name);
+
+fail1:
        edac_mc_free(mci);
        i7core_dev->mci = NULL;
        return rc;
index 4395c84cdcbfe1f5d6f18c4714114a28d3997592..df28b65358d26f26a6ec054222752fb2e497ba5f 100644 (file)
@@ -45,6 +45,8 @@
 #include "edac_module.h"
 #include "pnd2_edac.h"
 
+#define EDAC_MOD_STR           "pnd2_edac"
+
 #define APL_NUM_CHANNELS       4
 #define DNV_NUM_CHANNELS       2
 #define DNV_MAX_DIMMS          2 /* Max DIMMs per channel */
@@ -1355,7 +1357,7 @@ static int pnd2_register_mci(struct mem_ctl_info **ppmci)
        pvt = mci->pvt_info;
        memset(pvt, 0, sizeof(*pvt));
 
-       mci->mod_name = "pnd2_edac.c";
+       mci->mod_name = EDAC_MOD_STR;
        mci->dev_name = ops->name;
        mci->ctl_name = "Pondicherry2";
 
@@ -1547,10 +1549,15 @@ MODULE_DEVICE_TABLE(x86cpu, pnd2_cpuids);
 static int __init pnd2_init(void)
 {
        const struct x86_cpu_id *id;
+       const char *owner;
        int rc;
 
        edac_dbg(2, "\n");
 
+       owner = edac_get_owner();
+       if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
+               return -EBUSY;
+
        id = x86_match_cpu(pnd2_cpuids);
        if (!id)
                return -ENODEV;
index dc059165401164859956c29d3e0044fdc830e06f..f34430f99fd805414085fea26540f3c152dd6b0c 100644 (file)
@@ -36,7 +36,7 @@ static LIST_HEAD(sbridge_edac_list);
  * Alter this version for the module when modifications are made
  */
 #define SBRIDGE_REVISION    " Ver: 1.1.2 "
-#define EDAC_MOD_STR      "sbridge_edac"
+#define EDAC_MOD_STR       "sb_edac"
 
 /*
  * Debug macros
@@ -462,6 +462,7 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {
 static const struct pci_id_descr pci_dev_descr_ibridge[] = {
                /* Processor Home Agent */
        { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0,        0, IMC0) },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1,        1, IMC1) },
 
                /* Memory controller */
        { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA,     0, IMC0) },
@@ -472,7 +473,6 @@ static const struct pci_id_descr pci_dev_descr_ibridge[] = {
        { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3,   0, IMC0) },
 
                /* Optional, mode 2HA */
-       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1,        1, IMC1) },
        { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA,     1, IMC1) },
        { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS,    1, IMC1) },
        { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0,   1, IMC1) },
@@ -1318,9 +1318,7 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
        int cur_reg_start;
        int mc;
        int channel;
-       int way;
        int participants[KNL_MAX_CHANNELS];
-       int participant_count = 0;
 
        for (i = 0; i < KNL_MAX_CHANNELS; i++)
                mc_sizes[i] = 0;
@@ -1495,21 +1493,14 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
                 * this channel mapped to the given target?
                 */
                for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
-                       for (way = 0; way < intrlv_ways; way++) {
-                               int target;
-                               int cha;
-
-                               if (KNL_MOD3(dram_rule))
-                                       target = way;
-                               else
-                                       target = 0x7 & sad_pkg(
-                               pvt->info.interleave_pkg, interleave_reg, way);
+                       int target;
+                       int cha;
 
+                       for (target = 0; target < KNL_MAX_CHANNELS; target++) {
                                for (cha = 0; cha < KNL_MAX_CHAS; cha++) {
                                        if (knl_get_mc_route(target,
                                                mc_route_reg[cha]) == channel
                                                && !participants[channel]) {
-                                               participant_count++;
                                                participants[channel] = 1;
                                                break;
                                        }
@@ -1517,10 +1508,6 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
                        }
                }
 
-               if (participant_count != intrlv_ways)
-                       edac_dbg(0, "participant_count (%d) != interleave_ways (%d): DIMM size may be incorrect\n",
-                               participant_count, intrlv_ways);
-
                for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
                        mc = knl_channel_mc(channel);
                        if (participants[channel]) {
@@ -2291,6 +2278,13 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 next_imc:
        sbridge_dev = get_sbridge_dev(bus, dev_descr->dom, multi_bus, sbridge_dev);
        if (!sbridge_dev) {
+               /* If the HA1 wasn't found, don't create EDAC second memory controller */
+               if (dev_descr->dom == IMC1 && devno != 1) {
+                       edac_dbg(0, "Skip IMC1: %04x:%04x (since HA1 was absent)\n",
+                                PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+                       pci_dev_put(pdev);
+                       return 0;
+               }
 
                if (dev_descr->dom == SOCK)
                        goto out_imc;
@@ -2491,6 +2485,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
                case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
                case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA:
                        pvt->pci_ta = pdev;
+                       break;
                case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS:
                case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS:
                        pvt->pci_ras = pdev;
@@ -3155,7 +3150,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                MEM_FLAG_DDR4 : MEM_FLAG_DDR3;
        mci->edac_ctl_cap = EDAC_FLAG_NONE;
        mci->edac_cap = EDAC_FLAG_NONE;
-       mci->mod_name = "sb_edac.c";
+       mci->mod_name = EDAC_MOD_STR;
        mci->dev_name = pci_name(pdev);
        mci->ctl_page_to_phys = NULL;
 
@@ -3287,6 +3282,11 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                break;
        }
 
+       if (!mci->ctl_name) {
+               rc = -ENOMEM;
+               goto fail0;
+       }
+
        /* Get dimm basic config and the memory layout */
        rc = get_dimm_config(mci);
        if (rc < 0) {
@@ -3402,10 +3402,15 @@ static void sbridge_remove(void)
 static int __init sbridge_init(void)
 {
        const struct x86_cpu_id *id;
+       const char *owner;
        int rc;
 
        edac_dbg(2, "\n");
 
+       owner = edac_get_owner();
+       if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
+               return -EBUSY;
+
        id = x86_match_cpu(sbridge_cpuids);
        if (!id)
                return -ENODEV;
index 16dea97568a1ede6e8a36aa613f35329e1d9d902..912c4930c9efb8e58116731c9711d53311515574 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "edac_module.h"
 
+#define EDAC_MOD_STR    "skx_edac"
+
 /*
  * Debug macros
  */
@@ -65,6 +67,7 @@ static u64 skx_tolm, skx_tohm;
 struct skx_dev {
        struct list_head        list;
        u8                      bus[4];
+       int                     seg;
        struct pci_dev  *sad_all;
        struct pci_dev  *util_all;
        u32     mcroute;
@@ -110,12 +113,12 @@ struct decoded_addr {
        int     bank_group;
 };
 
-static struct skx_dev *get_skx_dev(u8 bus, u8 idx)
+static struct skx_dev *get_skx_dev(struct pci_bus *bus, u8 idx)
 {
        struct skx_dev *d;
 
        list_for_each_entry(d, &skx_edac_list, list) {
-               if (d->bus[idx] == bus)
+               if (d->seg == pci_domain_nr(bus) && d->bus[idx] == bus->number)
                        return d;
        }
 
@@ -172,6 +175,7 @@ static int get_all_bus_mappings(void)
                        pci_dev_put(pdev);
                        return -ENOMEM;
                }
+               d->seg = pci_domain_nr(pdev->bus);
                pci_read_config_dword(pdev, 0xCC, &reg);
                d->bus[0] =  GET_BITFIELD(reg, 0, 7);
                d->bus[1] =  GET_BITFIELD(reg, 8, 15);
@@ -207,7 +211,7 @@ static int get_all_munits(const struct munit *m)
                        if (i == NUM_IMC)
                                goto fail;
                }
-               d = get_skx_dev(pdev->bus->number, m->busidx);
+               d = get_skx_dev(pdev->bus, m->busidx);
                if (!d)
                        goto fail;
 
@@ -299,7 +303,7 @@ static int get_dimm_attr(u32 reg, int lobit, int hibit, int add, int minval,
 
 #define IS_DIMM_PRESENT(mtr)           GET_BITFIELD((mtr), 15, 15)
 
-#define numrank(reg) get_dimm_attr((reg), 12, 13, 0, 1, 2, "ranks")
+#define numrank(reg) get_dimm_attr((reg), 12, 13, 0, 0, 2, "ranks")
 #define numrow(reg) get_dimm_attr((reg), 2, 4, 12, 1, 6, "rows")
 #define numcol(reg) get_dimm_attr((reg), 0, 1, 10, 0, 2, "cols")
 
@@ -360,7 +364,7 @@ static int get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
 
        edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
                 imc->mc, chan, dimmno, size, npages,
-                banks, ranks, rows, cols);
+                banks, 1 << ranks, rows, cols);
 
        imc->chan[chan].dimms[dimmno].close_pg = GET_BITFIELD(mtr, 0, 0);
        imc->chan[chan].dimms[dimmno].bank_xor_enable = GET_BITFIELD(mtr, 9, 9);
@@ -464,12 +468,16 @@ static int skx_register_mci(struct skx_imc *imc)
        pvt = mci->pvt_info;
        pvt->imc = imc;
 
-       mci->ctl_name = kasprintf(GFP_KERNEL, "Skylake Socket#%d IMC#%d",
-                                 imc->node_id, imc->lmc);
+       mci->ctl_name = kasprintf(GFP_KERNEL, "Skylake Socket#%d IMC#%d", imc->node_id, imc->lmc);
+       if (!mci->ctl_name) {
+               rc = -ENOMEM;
+               goto fail0;
+       }
+
        mci->mtype_cap = MEM_FLAG_DDR4;
        mci->edac_ctl_cap = EDAC_FLAG_NONE;
        mci->edac_cap = EDAC_FLAG_NONE;
-       mci->mod_name = "skx_edac.c";
+       mci->mod_name = EDAC_MOD_STR;
        mci->dev_name = pci_name(imc->chan[0].cdev);
        mci->ctl_page_to_phys = NULL;
 
@@ -491,6 +499,7 @@ static int skx_register_mci(struct skx_imc *imc)
 
 fail:
        kfree(mci->ctl_name);
+fail0:
        edac_mc_free(mci);
        imc->mci = NULL;
        return rc;
@@ -1039,12 +1048,17 @@ static int __init skx_init(void)
 {
        const struct x86_cpu_id *id;
        const struct munit *m;
+       const char *owner;
        int rc = 0, i;
        u8 mc = 0, src_id, node_id;
        struct skx_dev *d;
 
        edac_dbg(2, "\n");
 
+       owner = edac_get_owner();
+       if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
+               return -EBUSY;
+
        id = x86_match_cpu(skx_cpuids);
        if (!id)
                return -ENODEV;
index f35d87519a3e84824258a993141851afe0a438d4..4803c6468bab4d18eafe65514344c2de02dd909c 100644 (file)
@@ -639,27 +639,6 @@ err_free:
        return ret;
 }
 
-#ifdef CONFIG_PM
-static int thunderx_lmc_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
-       return 0;
-}
-
-static int thunderx_lmc_resume(struct pci_dev *pdev)
-{
-       pci_set_power_state(pdev, PCI_D0);
-       pci_enable_wake(pdev, PCI_D0, 0);
-       pci_restore_state(pdev);
-
-       return 0;
-}
-#endif
-
 static const struct pci_device_id thunderx_lmc_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_LMC) },
        { 0, },
@@ -834,10 +813,6 @@ static struct pci_driver thunderx_lmc_driver = {
        .name     = "thunderx_lmc_edac",
        .probe    = thunderx_lmc_probe,
        .remove   = thunderx_lmc_remove,
-#ifdef CONFIG_PM
-       .suspend  = thunderx_lmc_suspend,
-       .resume   = thunderx_lmc_resume,
-#endif
        .id_table = thunderx_lmc_pci_tbl,
 };
 
index d6a09b9cd8ccae2c35cee866ac35b1d4ba066975..4372f9e4b0daeb97a45a08588b8064b73f2434e1 100644 (file)
@@ -137,9 +137,9 @@ int fw_cancel_transaction(struct fw_card *card,
 }
 EXPORT_SYMBOL(fw_cancel_transaction);
 
-static void split_transaction_timeout_callback(unsigned long data)
+static void split_transaction_timeout_callback(struct timer_list *timer)
 {
-       struct fw_transaction *t = (struct fw_transaction *)data;
+       struct fw_transaction *t = from_timer(t, timer, split_timeout_timer);
        struct fw_card *card = t->card;
        unsigned long flags;
 
@@ -373,8 +373,8 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
        t->tlabel = tlabel;
        t->card = card;
        t->is_split_transaction = false;
-       setup_timer(&t->split_timeout_timer,
-                   split_transaction_timeout_callback, (unsigned long)t);
+       timer_setup(&t->split_timeout_timer,
+                   split_transaction_timeout_callback, 0);
        t->callback = callback;
        t->callback_data = callback_data;
 
@@ -423,7 +423,7 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
        struct transaction_callback_data d;
        struct fw_transaction t;
 
-       init_timer_on_stack(&t.split_timeout_timer);
+       timer_setup_on_stack(&t.split_timeout_timer, NULL, 0);
        init_completion(&d.done);
        d.payload = payload;
        fw_send_request(card, &t, tcode, destination_id, generation, speed,
index 8bf89267dc252f260a3fc6e640c0c1809f04ef2d..ccf52368a073ecf0518b946853a8f7980087d8f1 100644 (file)
@@ -734,7 +734,7 @@ static unsigned int ar_search_last_active_buffer(struct ar_context *ctx,
        __le16 res_count, next_res_count;
 
        i = ar_first_buffer_index(ctx);
-       res_count = ACCESS_ONCE(ctx->descriptors[i].res_count);
+       res_count = READ_ONCE(ctx->descriptors[i].res_count);
 
        /* A buffer that is not yet completely filled must be the last one. */
        while (i != last && res_count == 0) {
@@ -742,8 +742,7 @@ static unsigned int ar_search_last_active_buffer(struct ar_context *ctx,
                /* Peek at the next descriptor. */
                next_i = ar_next_buffer_index(i);
                rmb(); /* read descriptors in order */
-               next_res_count = ACCESS_ONCE(
-                               ctx->descriptors[next_i].res_count);
+               next_res_count = READ_ONCE(ctx->descriptors[next_i].res_count);
                /*
                 * If the next descriptor is still empty, we must stop at this
                 * descriptor.
@@ -759,8 +758,7 @@ static unsigned int ar_search_last_active_buffer(struct ar_context *ctx,
                        if (MAX_AR_PACKET_SIZE > PAGE_SIZE && i != last) {
                                next_i = ar_next_buffer_index(next_i);
                                rmb();
-                               next_res_count = ACCESS_ONCE(
-                                       ctx->descriptors[next_i].res_count);
+                               next_res_count = READ_ONCE(ctx->descriptors[next_i].res_count);
                                if (next_res_count != cpu_to_le16(PAGE_SIZE))
                                        goto next_buffer_is_active;
                        }
@@ -2812,7 +2810,7 @@ static int handle_ir_buffer_fill(struct context *context,
        u32 buffer_dma;
 
        req_count = le16_to_cpu(last->req_count);
-       res_count = le16_to_cpu(ACCESS_ONCE(last->res_count));
+       res_count = le16_to_cpu(READ_ONCE(last->res_count));
        completed = req_count - res_count;
        buffer_dma = le32_to_cpu(last->data_address);
 
index a01461d63f6851cbf80f9c015b89280f18bda6dc..00de793e6423a03c235a6678ee1d16d88edd8f4a 100644 (file)
@@ -99,11 +99,11 @@ static inline bool tegra_ivc_empty(struct tegra_ivc *ivc,
 {
        /*
         * This function performs multiple checks on the same values with
-        * security implications, so create snapshots with ACCESS_ONCE() to
+        * security implications, so create snapshots with READ_ONCE() to
         * ensure that these checks use the same values.
         */
-       u32 tx = ACCESS_ONCE(header->tx.count);
-       u32 rx = ACCESS_ONCE(header->rx.count);
+       u32 tx = READ_ONCE(header->tx.count);
+       u32 rx = READ_ONCE(header->rx.count);
 
        /*
         * Perform an over-full check to prevent denial of service attacks
@@ -124,8 +124,8 @@ static inline bool tegra_ivc_empty(struct tegra_ivc *ivc,
 static inline bool tegra_ivc_full(struct tegra_ivc *ivc,
                                  struct tegra_ivc_header *header)
 {
-       u32 tx = ACCESS_ONCE(header->tx.count);
-       u32 rx = ACCESS_ONCE(header->rx.count);
+       u32 tx = READ_ONCE(header->tx.count);
+       u32 rx = READ_ONCE(header->rx.count);
 
        /*
         * Invalid cases where the counters indicate that the queue is over
@@ -137,8 +137,8 @@ static inline bool tegra_ivc_full(struct tegra_ivc *ivc,
 static inline u32 tegra_ivc_available(struct tegra_ivc *ivc,
                                      struct tegra_ivc_header *header)
 {
-       u32 tx = ACCESS_ONCE(header->tx.count);
-       u32 rx = ACCESS_ONCE(header->rx.count);
+       u32 tx = READ_ONCE(header->tx.count);
+       u32 rx = READ_ONCE(header->rx.count);
 
        /*
         * This function isn't expected to be used in scenarios where an
@@ -151,8 +151,8 @@ static inline u32 tegra_ivc_available(struct tegra_ivc *ivc,
 
 static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
 {
-       ACCESS_ONCE(ivc->tx.channel->tx.count) =
-               ACCESS_ONCE(ivc->tx.channel->tx.count) + 1;
+       WRITE_ONCE(ivc->tx.channel->tx.count,
+                  READ_ONCE(ivc->tx.channel->tx.count) + 1);
 
        if (ivc->tx.position == ivc->num_frames - 1)
                ivc->tx.position = 0;
@@ -162,8 +162,8 @@ static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
 
 static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
 {
-       ACCESS_ONCE(ivc->rx.channel->rx.count) =
-               ACCESS_ONCE(ivc->rx.channel->rx.count) + 1;
+       WRITE_ONCE(ivc->rx.channel->rx.count,
+                  READ_ONCE(ivc->rx.channel->rx.count) + 1);
 
        if (ivc->rx.position == ivc->num_frames - 1)
                ivc->rx.position = 0;
@@ -428,7 +428,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
 
        /* Copy the receiver's state out of shared memory. */
        tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
-       state = ACCESS_ONCE(ivc->rx.channel->tx.state);
+       state = READ_ONCE(ivc->rx.channel->tx.state);
 
        if (state == TEGRA_IVC_STATE_SYNC) {
                offset = offsetof(struct tegra_ivc_header, tx.count);
index 033258634b8c37300df3598e3fd24570aab1597d..b5843fe6a44d88d080f9611858dcb98c074a64ee 100644 (file)
@@ -140,8 +140,9 @@ static int xgene_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio)
        return irq_create_fwspec_mapping(&fwspec);
 }
 
-static void xgene_gpio_sb_domain_activate(struct irq_domain *d,
-               struct irq_data *irq_data)
+static int xgene_gpio_sb_domain_activate(struct irq_domain *d,
+                                        struct irq_data *irq_data,
+                                        bool early)
 {
        struct xgene_gpio_sb *priv = d->host_data;
        u32 gpio = HWIRQ_TO_GPIO(priv, irq_data->hwirq);
@@ -150,11 +151,12 @@ static void xgene_gpio_sb_domain_activate(struct irq_domain *d,
                dev_err(priv->gc.parent,
                "Unable to configure XGene GPIO standby pin %d as IRQ\n",
                                gpio);
-               return;
+               return -ENOSPC;
        }
 
        xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO,
                        gpio * 2, 1);
+       return 0;
 }
 
 static void xgene_gpio_sb_domain_deactivate(struct irq_domain *d,
index 333bad74906784f7ecc7a794c3d1d4e1dd915978..303b5e099a98e6c3f6fe355f520ca61b133a6534 100644 (file)
@@ -260,7 +260,7 @@ static void amdgpu_fence_fallback(unsigned long arg)
  */
 int amdgpu_fence_wait_empty(struct amdgpu_ring *ring)
 {
-       uint64_t seq = ACCESS_ONCE(ring->fence_drv.sync_seq);
+       uint64_t seq = READ_ONCE(ring->fence_drv.sync_seq);
        struct dma_fence *fence, **ptr;
        int r;
 
@@ -300,7 +300,7 @@ unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring)
        amdgpu_fence_process(ring);
        emitted = 0x100000000ull;
        emitted -= atomic_read(&ring->fence_drv.last_seq);
-       emitted += ACCESS_ONCE(ring->fence_drv.sync_seq);
+       emitted += READ_ONCE(ring->fence_drv.sync_seq);
        return lower_32_bits(emitted);
 }
 
index 7171968f261e1a13094f3c94b2d649a382b2f6a0..6149a47fe63d5edbd4f2561bd5e500f3a4078746 100644 (file)
@@ -788,11 +788,11 @@ static int amdgpu_debugfs_gem_bo_info(int id, void *ptr, void *data)
        seq_printf(m, "\t0x%08x: %12ld byte %s",
                   id, amdgpu_bo_size(bo), placement);
 
-       offset = ACCESS_ONCE(bo->tbo.mem.start);
+       offset = READ_ONCE(bo->tbo.mem.start);
        if (offset != AMDGPU_BO_INVALID_OFFSET)
                seq_printf(m, " @ 0x%010Lx", offset);
 
-       pin_count = ACCESS_ONCE(bo->pin_count);
+       pin_count = READ_ONCE(bo->pin_count);
        if (pin_count)
                seq_printf(m, " pin count %d", pin_count);
        seq_printf(m, "\n");
index 38cea6fb25a8b9221d64b43da04c4268a2c986b8..a25f6c72f219358c9b436a714cf9ec658b8bcaf9 100644 (file)
@@ -187,7 +187,7 @@ static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity)
        if (kfifo_is_empty(&entity->job_queue))
                return false;
 
-       if (ACCESS_ONCE(entity->dependency))
+       if (READ_ONCE(entity->dependency))
                return false;
 
        return true;
index fc9a6a83dfc7726d9213f5a22ed1cee7fed474b5..4b152e0d31a658970f6d7f5387f88d2a299fcbce 100644 (file)
@@ -975,9 +975,9 @@ static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
                  round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES));
 }
 
-static void hangcheck_handler(unsigned long data)
+static void hangcheck_handler(struct timer_list *t)
 {
-       struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data;
+       struct etnaviv_gpu *gpu = from_timer(gpu, t, hangcheck_timer);
        u32 fence = gpu->completed_fence;
        bool progress = false;
 
@@ -1648,8 +1648,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
        INIT_WORK(&gpu->recover_work, recover_worker);
        init_waitqueue_head(&gpu->fence_event);
 
-       setup_deferrable_timer(&gpu->hangcheck_timer, hangcheck_handler,
-                              (unsigned long)gpu);
+       timer_setup(&gpu->hangcheck_timer, hangcheck_handler, TIMER_DEFERRABLE);
 
        priv->gpu[priv->num_gpus++] = gpu;
 
index 1d2ebb5e530f9bcafc805ac03190e56084f5f311..be6dda58fcae3d5e71a0e8e56d7884334240897f 100644 (file)
@@ -23,9 +23,9 @@
 #include "psb_intel_reg.h"
 #include <linux/spinlock.h>
 
-static void psb_lid_timer_func(unsigned long data)
+static void psb_lid_timer_func(struct timer_list *t)
 {
-       struct drm_psb_private * dev_priv = (struct drm_psb_private *)data;
+       struct drm_psb_private *dev_priv = from_timer(dev_priv, t, lid_timer);
        struct drm_device *dev = (struct drm_device *)dev_priv->dev;
        struct timer_list *lid_timer = &dev_priv->lid_timer;
        unsigned long irq_flags;
@@ -77,10 +77,8 @@ void psb_lid_timer_init(struct drm_psb_private *dev_priv)
        spin_lock_init(&dev_priv->lid_lock);
        spin_lock_irqsave(&dev_priv->lid_lock, irq_flags);
 
-       init_timer(lid_timer);
+       timer_setup(lid_timer, psb_lid_timer_func, 0);
 
-       lid_timer->data = (unsigned long)dev_priv;
-       lid_timer->function = psb_lid_timer_func;
        lid_timer->expires = jiffies + PSB_LID_DELAY;
 
        add_timer(lid_timer);
index 9f45cfeae775545f7dc85688f1f2a20a3de9c561..f124de3a0668d5f02f3b0015bdacd4c78177f8cc 100644 (file)
@@ -1304,7 +1304,7 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
         * becaue the HDA driver may require us to enable the audio power
         * domain during system suspend.
         */
-       pdev->dev_flags |= PCI_DEV_FLAGS_NEEDS_RESUME;
+       dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
 
        ret = i915_driver_init_early(dev_priv, ent);
        if (ret < 0)
index 4ac454ae54d73068ef3b79b673ad0c7c0e4e00cc..83876a1c8d98b86037d50f6f007af7fa722c2652 100644 (file)
@@ -2094,6 +2094,11 @@ get_fence_array(struct drm_i915_gem_execbuffer2 *args,
                        goto err;
                }
 
+               if (fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) {
+                       err = -EINVAL;
+                       goto err;
+               }
+
                syncobj = drm_syncobj_find(file, fence.handle);
                if (!syncobj) {
                        DRM_DEBUG("Invalid syncobj handle provided\n");
@@ -2101,6 +2106,9 @@ get_fence_array(struct drm_i915_gem_execbuffer2 *args,
                        goto err;
                }
 
+               BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) &
+                            ~__I915_EXEC_FENCE_UNKNOWN_FLAGS);
+
                fences[n] = ptr_pack_bits(syncobj, fence.flags, 2);
        }
 
index e2410eb5d96e01ce208f565fee182da9a99ee604..ad524cb0f6fc5a18c3bc18214b7acaef5dab7896 100644 (file)
@@ -832,10 +832,14 @@ static void gen8_ppgtt_clear_4lvl(struct i915_address_space *vm,
        }
 }
 
-struct sgt_dma {
+static inline struct sgt_dma {
        struct scatterlist *sg;
        dma_addr_t dma, max;
-};
+} sgt_dma(struct i915_vma *vma) {
+       struct scatterlist *sg = vma->pages->sgl;
+       dma_addr_t addr = sg_dma_address(sg);
+       return (struct sgt_dma) { sg, addr, addr + sg->length };
+}
 
 struct gen8_insert_pte {
        u16 pml4e;
@@ -916,11 +920,7 @@ static void gen8_ppgtt_insert_3lvl(struct i915_address_space *vm,
                                   u32 unused)
 {
        struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-       struct sgt_dma iter = {
-               .sg = vma->pages->sgl,
-               .dma = sg_dma_address(iter.sg),
-               .max = iter.dma + iter.sg->length,
-       };
+       struct sgt_dma iter = sgt_dma(vma);
        struct gen8_insert_pte idx = gen8_insert_pte(vma->node.start);
 
        gen8_ppgtt_insert_pte_entries(ppgtt, &ppgtt->pdp, &iter, &idx,
@@ -933,11 +933,7 @@ static void gen8_ppgtt_insert_4lvl(struct i915_address_space *vm,
                                   u32 unused)
 {
        struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-       struct sgt_dma iter = {
-               .sg = vma->pages->sgl,
-               .dma = sg_dma_address(iter.sg),
-               .max = iter.dma + iter.sg->length,
-       };
+       struct sgt_dma iter = sgt_dma(vma);
        struct i915_page_directory_pointer **pdps = ppgtt->pml4.pdps;
        struct gen8_insert_pte idx = gen8_insert_pte(vma->node.start);
 
@@ -1632,13 +1628,10 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
        unsigned act_pt = first_entry / GEN6_PTES;
        unsigned act_pte = first_entry % GEN6_PTES;
        const u32 pte_encode = vm->pte_encode(0, cache_level, flags);
-       struct sgt_dma iter;
+       struct sgt_dma iter = sgt_dma(vma);
        gen6_pte_t *vaddr;
 
        vaddr = kmap_atomic_px(ppgtt->pd.page_table[act_pt]);
-       iter.sg = vma->pages->sgl;
-       iter.dma = sg_dma_address(iter.sg);
-       iter.max = iter.dma + iter.sg->length;
        do {
                vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma);
 
index 3386452bd2f057239c4ae63bea1eeb6e040c3acc..cf3deb283da561914ee26904b57915fcf39ac24b 100644 (file)
@@ -451,7 +451,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
        else
                r = 0;
 
-       cur_placement = ACCESS_ONCE(robj->tbo.mem.mem_type);
+       cur_placement = READ_ONCE(robj->tbo.mem.mem_type);
        args->domain = radeon_mem_type_to_domain(cur_placement);
        drm_gem_object_put_unlocked(gobj);
        return r;
@@ -481,7 +481,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
                r = ret;
 
        /* Flush HDP cache via MMIO if necessary */
-       cur_placement = ACCESS_ONCE(robj->tbo.mem.mem_type);
+       cur_placement = READ_ONCE(robj->tbo.mem.mem_type);
        if (rdev->asic->mmio_hdp_flush &&
            radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM)
                robj->rdev->asic->mmio_hdp_flush(rdev);
index e84fee3ec4f333d48519c91ba690770cb5633f17..184340d486c377d38a2f21bb66cc56385a52d37b 100644 (file)
@@ -721,7 +721,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                 * allocation taken by fbdev
                 */
                if (!(dev_priv->capabilities & SVGA_CAP_3D))
-                       mem_size *= 2;
+                       mem_size *= 3;
 
                dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE;
                dev_priv->prim_bb_mem =
index 3bbad22b37488cec5417b8e605b77ef8a4f2e399..d6b1c509ae019d1aae404ff5163506d5e819155e 100644 (file)
@@ -224,7 +224,7 @@ out:
        return ret;
 }
 
-static struct dma_fence_ops vmw_fence_ops = {
+static const struct dma_fence_ops vmw_fence_ops = {
        .get_driver_name = vmw_fence_get_driver_name,
        .get_timeline_name = vmw_fence_get_timeline_name,
        .enable_signaling = vmw_fence_enable_signaling,
index a552e4ea54407bf18e00974ac704990cf6179702..6ac094ee898356593d73c1b615d8c1b9115fc892 100644 (file)
@@ -904,7 +904,7 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
                if (unlikely(drm_is_render_client(file_priv)))
                        require_exist = true;
 
-               if (ACCESS_ONCE(vmw_fpriv(file_priv)->locked_master)) {
+               if (READ_ONCE(vmw_fpriv(file_priv)->locked_master)) {
                        DRM_ERROR("Locked master refused legacy "
                                  "surface reference.\n");
                        return -EACCES;
index 93d28c0ec8bf0ef867bc958592c58f60d3ce2913..9b167bc6eee48ca498a070ca46cc09836f02d8c1 100644 (file)
@@ -464,10 +464,10 @@ static void ssip_error(struct hsi_client *cl)
        hsi_async_read(cl, msg);
 }
 
-static void ssip_keep_alive(unsigned long data)
+static void ssip_keep_alive(struct timer_list *t)
 {
-       struct hsi_client *cl = (struct hsi_client *)data;
-       struct ssi_protocol *ssi = hsi_client_drvdata(cl);
+       struct ssi_protocol *ssi = from_timer(ssi, t, keep_alive);
+       struct hsi_client *cl = ssi->cl;
 
        dev_dbg(&cl->device, "Keep alive kick in: m(%d) r(%d) s(%d)\n",
                ssi->main_state, ssi->recv_state, ssi->send_state);
@@ -490,9 +490,19 @@ static void ssip_keep_alive(unsigned long data)
        spin_unlock(&ssi->lock);
 }
 
-static void ssip_wd(unsigned long data)
+static void ssip_rx_wd(struct timer_list *t)
+{
+       struct ssi_protocol *ssi = from_timer(ssi, t, rx_wd);
+       struct hsi_client *cl = ssi->cl;
+
+       dev_err(&cl->device, "Watchdog trigerred\n");
+       ssip_error(cl);
+}
+
+static void ssip_tx_wd(struct timer_list *t)
 {
-       struct hsi_client *cl = (struct hsi_client *)data;
+       struct ssi_protocol *ssi = from_timer(ssi, t, tx_wd);
+       struct hsi_client *cl = ssi->cl;
 
        dev_err(&cl->device, "Watchdog trigerred\n");
        ssip_error(cl);
@@ -1084,15 +1094,9 @@ static int ssi_protocol_probe(struct device *dev)
        }
 
        spin_lock_init(&ssi->lock);
-       init_timer_deferrable(&ssi->rx_wd);
-       init_timer_deferrable(&ssi->tx_wd);
-       init_timer(&ssi->keep_alive);
-       ssi->rx_wd.data = (unsigned long)cl;
-       ssi->rx_wd.function = ssip_wd;
-       ssi->tx_wd.data = (unsigned long)cl;
-       ssi->tx_wd.function = ssip_wd;
-       ssi->keep_alive.data = (unsigned long)cl;
-       ssi->keep_alive.function = ssip_keep_alive;
+       timer_setup(&ssi->rx_wd, ssip_rx_wd, TIMER_DEFERRABLE);
+       timer_setup(&ssi->tx_wd, ssip_tx_wd, TIMER_DEFERRABLE);
+       timer_setup(&ssi->keep_alive, ssip_keep_alive, 0);
        INIT_LIST_HEAD(&ssi->txqueue);
        INIT_LIST_HEAD(&ssi->cmdqueue);
        atomic_set(&ssi->tx_usecnt, 0);
index 937801ac2fe0eafb3d148072a604c4e50a159572..2cd134dd94d2140c0ee49a87d1b2ca7f89d56ddc 100644 (file)
@@ -1534,7 +1534,7 @@ static int __init hv_acpi_init(void)
 {
        int ret, t;
 
-       if (x86_hyper != &x86_hyper_ms_hyperv)
+       if (x86_hyper_type != X86_HYPER_MS_HYPERV)
                return -ENODEV;
 
        init_completion(&probe_event);
index d65431417b17c4280ab791bef63fa5150dfcc34a..7ad017690e3a36f6ca880fa9ecd707a075085e9b 100644 (file)
@@ -552,6 +552,7 @@ config SENSORS_G762
 
 config SENSORS_GPIO_FAN
        tristate "GPIO fan"
+       depends on OF_GPIO
        depends on GPIOLIB || COMPILE_TEST
        depends on THERMAL || THERMAL=n
        help
@@ -862,6 +863,20 @@ tristate "MAX31722 temperature sensor"
          This driver can also be built as a module. If so, the module
          will be called max31722.
 
+config SENSORS_MAX6621
+       tristate "Maxim MAX6621 sensor chip"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for MAX6621 sensor chip.
+         MAX6621 is a PECI-to-I2C translator provides an efficient,
+         low-cost solution for PECI-to-SMBus/I2C protocol conversion.
+         It allows reading the temperature from the PECI-compliant
+         host directly from up to four PECI-enabled CPUs.
+
+         This driver can also be built as a module. If so, the module
+         will be called max6621.
+
 config SENSORS_MAX6639
        tristate "Maxim MAX6639 sensor chip"
        depends on I2C
index 23e195a5a2f330f9873d9a460d265e6e5169d818..0fe489fab663f788175bf0e68d104e2b0fd18e84 100644 (file)
@@ -118,6 +118,7 @@ obj-$(CONFIG_SENSORS_MAX1619)       += max1619.o
 obj-$(CONFIG_SENSORS_MAX1668)  += max1668.o
 obj-$(CONFIG_SENSORS_MAX197)   += max197.o
 obj-$(CONFIG_SENSORS_MAX31722) += max31722.o
+obj-$(CONFIG_SENSORS_MAX6621)  += max6621.o
 obj-$(CONFIG_SENSORS_MAX6639)  += max6639.o
 obj-$(CONFIG_SENSORS_MAX6642)  += max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
index 4875e99b59c97e52a80e453a8a04297152fb43ec..6d34c05a4f830496386240e2750cd0f20fbd4067 100644 (file)
@@ -579,7 +579,6 @@ static ssize_t show_pwm_enable(struct device *dev,
        mutex_unlock(&data->update_lock);
 
        val = config | (altbit << 3);
-       newval = 0;
 
        if (val == 3 || val >= 10)
                newval = 255;
index 69b97d45e3cbb459ccdf73321dc4c3ef8ae23488..63a95e23ca818038dac27324b5ee276895657250 100644 (file)
@@ -7,19 +7,19 @@
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/gpio/consumer.h>
-#include <linux/delay.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/of_platform.h>
 #include <linux/of_device.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
-#include <linux/sysfs.h>
 #include <linux/regmap.h>
+#include <linux/sysfs.h>
 #include <linux/thermal.h>
 
 /* ASPEED PWM & FAN Tach Register Definition */
  * 11: reserved.
  */
 #define M_TACH_MODE 0x02 /* 10b */
-#define M_TACH_UNIT 0x00c0
+#define M_TACH_UNIT 0x0210
 #define INIT_FAN_CTRL 0xFF
 
 /* How long we sleep in us while waiting for an RPM result. */
index 9c355b9d31c57ac23b663fe5d83460dd11130bba..5c9a52599cf68ff8d7dcb181ac3cfdc162ea3d1b 100644 (file)
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/hwmon.h>
-#include <linux/gpio.h>
-#include <linux/gpio-fan.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
-#include <linux/of_gpio.h>
 #include <linux/thermal.h>
 
+struct gpio_fan_speed {
+       int rpm;
+       int ctrl_val;
+};
+
 struct gpio_fan_data {
-       struct platform_device  *pdev;
+       struct device           *dev;
        struct device           *hwmon_dev;
        /* Cooling device if any */
        struct thermal_cooling_device *cdev;
        struct mutex            lock; /* lock GPIOs operations. */
-       int                     num_ctrl;
-       unsigned                *ctrl;
+       int                     num_gpios;
+       struct gpio_desc        **gpios;
        int                     num_speed;
        struct gpio_fan_speed   *speed;
        int                     speed_index;
@@ -51,7 +54,7 @@ struct gpio_fan_data {
        int                     resume_speed;
 #endif
        bool                    pwm_enable;
-       struct gpio_fan_alarm   *alarm;
+       struct gpio_desc        *alarm_gpio;
        struct work_struct      alarm_work;
 };
 
@@ -64,8 +67,8 @@ static void fan_alarm_notify(struct work_struct *ws)
        struct gpio_fan_data *fan_data =
                container_of(ws, struct gpio_fan_data, alarm_work);
 
-       sysfs_notify(&fan_data->pdev->dev.kobj, NULL, "fan1_alarm");
-       kobject_uevent(&fan_data->pdev->dev.kobj, KOBJ_CHANGE);
+       sysfs_notify(&fan_data->dev->kobj, NULL, "fan1_alarm");
+       kobject_uevent(&fan_data->dev->kobj, KOBJ_CHANGE);
 }
 
 static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
@@ -81,47 +84,30 @@ static ssize_t fan1_alarm_show(struct device *dev,
                               struct device_attribute *attr, char *buf)
 {
        struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
-       struct gpio_fan_alarm *alarm = fan_data->alarm;
-       int value = gpio_get_value_cansleep(alarm->gpio);
 
-       if (alarm->active_low)
-               value = !value;
-
-       return sprintf(buf, "%d\n", value);
+       return sprintf(buf, "%d\n",
+                      gpiod_get_value_cansleep(fan_data->alarm_gpio));
 }
 
 static DEVICE_ATTR_RO(fan1_alarm);
 
-static int fan_alarm_init(struct gpio_fan_data *fan_data,
-                         struct gpio_fan_alarm *alarm)
+static int fan_alarm_init(struct gpio_fan_data *fan_data)
 {
-       int err;
        int alarm_irq;
-       struct platform_device *pdev = fan_data->pdev;
-
-       fan_data->alarm = alarm;
-
-       err = devm_gpio_request(&pdev->dev, alarm->gpio, "GPIO fan alarm");
-       if (err)
-               return err;
-
-       err = gpio_direction_input(alarm->gpio);
-       if (err)
-               return err;
+       struct device *dev = fan_data->dev;
 
        /*
         * If the alarm GPIO don't support interrupts, just leave
         * without initializing the fail notification support.
         */
-       alarm_irq = gpio_to_irq(alarm->gpio);
-       if (alarm_irq < 0)
+       alarm_irq = gpiod_to_irq(fan_data->alarm_gpio);
+       if (alarm_irq <= 0)
                return 0;
 
        INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
        irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
-       err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
-                              IRQF_SHARED, "GPIO fan alarm", fan_data);
-       return err;
+       return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler,
+                               IRQF_SHARED, "GPIO fan alarm", fan_data);
 }
 
 /*
@@ -133,8 +119,9 @@ static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
 {
        int i;
 
-       for (i = 0; i < fan_data->num_ctrl; i++)
-               gpio_set_value_cansleep(fan_data->ctrl[i], (ctrl_val >> i) & 1);
+       for (i = 0; i < fan_data->num_gpios; i++)
+               gpiod_set_value_cansleep(fan_data->gpios[i],
+                                        (ctrl_val >> i) & 1);
 }
 
 static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
@@ -142,10 +129,10 @@ static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
        int i;
        int ctrl_val = 0;
 
-       for (i = 0; i < fan_data->num_ctrl; i++) {
+       for (i = 0; i < fan_data->num_gpios; i++) {
                int value;
 
-               value = gpio_get_value_cansleep(fan_data->ctrl[i]);
+               value = gpiod_get_value_cansleep(fan_data->gpios[i]);
                ctrl_val |= (value << i);
        }
        return ctrl_val;
@@ -170,7 +157,7 @@ static int get_fan_speed_index(struct gpio_fan_data *fan_data)
                if (fan_data->speed[i].ctrl_val == ctrl_val)
                        return i;
 
-       dev_warn(&fan_data->pdev->dev,
+       dev_warn(fan_data->dev,
                 "missing speed array entry for GPIO value 0x%x\n", ctrl_val);
 
        return -ENODEV;
@@ -328,9 +315,9 @@ static umode_t gpio_fan_is_visible(struct kobject *kobj,
        struct device *dev = container_of(kobj, struct device, kobj);
        struct gpio_fan_data *data = dev_get_drvdata(dev);
 
-       if (index == 0 && !data->alarm)
+       if (index == 0 && !data->alarm_gpio)
                return 0;
-       if (index > 0 && !data->ctrl)
+       if (index > 0 && !data->gpios)
                return 0;
 
        return attr->mode;
@@ -358,30 +345,25 @@ static const struct attribute_group *gpio_fan_groups[] = {
        NULL
 };
 
-static int fan_ctrl_init(struct gpio_fan_data *fan_data,
-                        struct gpio_fan_platform_data *pdata)
+static int fan_ctrl_init(struct gpio_fan_data *fan_data)
 {
-       struct platform_device *pdev = fan_data->pdev;
-       int num_ctrl = pdata->num_ctrl;
-       unsigned *ctrl = pdata->ctrl;
+       int num_gpios = fan_data->num_gpios;
+       struct gpio_desc **gpios = fan_data->gpios;
        int i, err;
 
-       for (i = 0; i < num_ctrl; i++) {
-               err = devm_gpio_request(&pdev->dev, ctrl[i],
-                                       "GPIO fan control");
-               if (err)
-                       return err;
-
-               err = gpio_direction_output(ctrl[i],
-                                           gpio_get_value_cansleep(ctrl[i]));
+       for (i = 0; i < num_gpios; i++) {
+               /*
+                * The GPIO descriptors were retrieved with GPIOD_ASIS so here
+                * we set the GPIO into output mode, carefully preserving the
+                * current value by setting it to whatever it is already set
+                * (no surprise changes in default fan speed).
+                */
+               err = gpiod_direction_output(gpios[i],
+                                       gpiod_get_value_cansleep(gpios[i]));
                if (err)
                        return err;
        }
 
-       fan_data->num_ctrl = num_ctrl;
-       fan_data->ctrl = ctrl;
-       fan_data->num_speed = pdata->num_speed;
-       fan_data->speed = pdata->speed;
        fan_data->pwm_enable = true; /* Enable manual fan speed control. */
        fan_data->speed_index = get_fan_speed_index(fan_data);
        if (fan_data->speed_index < 0)
@@ -432,67 +414,47 @@ static const struct thermal_cooling_device_ops gpio_fan_cool_ops = {
        .set_cur_state = gpio_fan_set_cur_state,
 };
 
-#ifdef CONFIG_OF_GPIO
 /*
  * Translate OpenFirmware node properties into platform_data
  */
-static int gpio_fan_get_of_pdata(struct device *dev,
-                           struct gpio_fan_platform_data *pdata)
+static int gpio_fan_get_of_data(struct gpio_fan_data *fan_data)
 {
-       struct device_node *node;
        struct gpio_fan_speed *speed;
-       unsigned *ctrl;
+       struct device *dev = fan_data->dev;
+       struct device_node *np = dev->of_node;
+       struct gpio_desc **gpios;
        unsigned i;
        u32 u;
        struct property *prop;
        const __be32 *p;
 
-       node = dev->of_node;
-
        /* Alarm GPIO if one exists */
-       if (of_gpio_named_count(node, "alarm-gpios") > 0) {
-               struct gpio_fan_alarm *alarm;
-               int val;
-               enum of_gpio_flags flags;
-
-               alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm),
-                                       GFP_KERNEL);
-               if (!alarm)
-                       return -ENOMEM;
-
-               val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags);
-               if (val < 0)
-                       return val;
-               alarm->gpio = val;
-               alarm->active_low = flags & OF_GPIO_ACTIVE_LOW;
-
-               pdata->alarm = alarm;
-       }
+       fan_data->alarm_gpio = devm_gpiod_get_optional(dev, "alarm", GPIOD_IN);
+       if (IS_ERR(fan_data->alarm_gpio))
+               return PTR_ERR(fan_data->alarm_gpio);
 
        /* Fill GPIO pin array */
-       pdata->num_ctrl = of_gpio_count(node);
-       if (pdata->num_ctrl <= 0) {
-               if (pdata->alarm)
+       fan_data->num_gpios = gpiod_count(dev, NULL);
+       if (fan_data->num_gpios <= 0) {
+               if (fan_data->alarm_gpio)
                        return 0;
                dev_err(dev, "DT properties empty / missing");
                return -ENODEV;
        }
-       ctrl = devm_kzalloc(dev, pdata->num_ctrl * sizeof(unsigned),
-                               GFP_KERNEL);
-       if (!ctrl)
+       gpios = devm_kzalloc(dev,
+                            fan_data->num_gpios * sizeof(struct gpio_desc *),
+                            GFP_KERNEL);
+       if (!gpios)
                return -ENOMEM;
-       for (i = 0; i < pdata->num_ctrl; i++) {
-               int val;
-
-               val = of_get_gpio(node, i);
-               if (val < 0)
-                       return val;
-               ctrl[i] = val;
+       for (i = 0; i < fan_data->num_gpios; i++) {
+               gpios[i] = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS);
+               if (IS_ERR(gpios[i]))
+                       return PTR_ERR(gpios[i]);
        }
-       pdata->ctrl = ctrl;
+       fan_data->gpios = gpios;
 
        /* Get number of RPM/ctrl_val pairs in speed map */
-       prop = of_find_property(node, "gpio-fan,speed-map", &i);
+       prop = of_find_property(np, "gpio-fan,speed-map", &i);
        if (!prop) {
                dev_err(dev, "gpio-fan,speed-map DT property missing");
                return -ENODEV;
@@ -502,7 +464,7 @@ static int gpio_fan_get_of_pdata(struct device *dev,
                dev_err(dev, "gpio-fan,speed-map contains zero/odd number of entries");
                return -ENODEV;
        }
-       pdata->num_speed = i / 2;
+       fan_data->num_speed = i / 2;
 
        /*
         * Populate speed map
@@ -510,12 +472,12 @@ static int gpio_fan_get_of_pdata(struct device *dev,
         * this needs splitting into pairs to create gpio_fan_speed structs
         */
        speed = devm_kzalloc(dev,
-                       pdata->num_speed * sizeof(struct gpio_fan_speed),
+                       fan_data->num_speed * sizeof(struct gpio_fan_speed),
                        GFP_KERNEL);
        if (!speed)
                return -ENOMEM;
        p = NULL;
-       for (i = 0; i < pdata->num_speed; i++) {
+       for (i = 0; i < fan_data->num_speed; i++) {
                p = of_prop_next_u32(prop, p, &u);
                if (!p)
                        return -ENODEV;
@@ -525,7 +487,7 @@ static int gpio_fan_get_of_pdata(struct device *dev,
                        return -ENODEV;
                speed[i].ctrl_val = u;
        }
-       pdata->speed = speed;
+       fan_data->speed = speed;
 
        return 0;
 }
@@ -535,76 +497,58 @@ static const struct of_device_id of_gpio_fan_match[] = {
        {},
 };
 MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
-#endif /* CONFIG_OF_GPIO */
 
 static int gpio_fan_probe(struct platform_device *pdev)
 {
        int err;
        struct gpio_fan_data *fan_data;
-       struct gpio_fan_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
 
-       fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
+       fan_data = devm_kzalloc(dev, sizeof(struct gpio_fan_data),
                                GFP_KERNEL);
        if (!fan_data)
                return -ENOMEM;
 
-#ifdef CONFIG_OF_GPIO
-       if (!pdata) {
-               pdata = devm_kzalloc(&pdev->dev,
-                                       sizeof(struct gpio_fan_platform_data),
-                                       GFP_KERNEL);
-               if (!pdata)
-                       return -ENOMEM;
-
-               err = gpio_fan_get_of_pdata(&pdev->dev, pdata);
-               if (err)
-                       return err;
-       }
-#else /* CONFIG_OF_GPIO */
-       if (!pdata)
-               return -EINVAL;
-#endif /* CONFIG_OF_GPIO */
+       fan_data->dev = dev;
+       err = gpio_fan_get_of_data(fan_data);
+       if (err)
+               return err;
 
-       fan_data->pdev = pdev;
        platform_set_drvdata(pdev, fan_data);
        mutex_init(&fan_data->lock);
 
        /* Configure alarm GPIO if available. */
-       if (pdata->alarm) {
-               err = fan_alarm_init(fan_data, pdata->alarm);
+       if (fan_data->alarm_gpio) {
+               err = fan_alarm_init(fan_data);
                if (err)
                        return err;
        }
 
        /* Configure control GPIOs if available. */
-       if (pdata->ctrl && pdata->num_ctrl > 0) {
-               if (!pdata->speed || pdata->num_speed <= 1)
+       if (fan_data->gpios && fan_data->num_gpios > 0) {
+               if (!fan_data->speed || fan_data->num_speed <= 1)
                        return -EINVAL;
-               err = fan_ctrl_init(fan_data, pdata);
+               err = fan_ctrl_init(fan_data);
                if (err)
                        return err;
        }
 
        /* Make this driver part of hwmon class. */
        fan_data->hwmon_dev =
-               devm_hwmon_device_register_with_groups(&pdev->dev,
+               devm_hwmon_device_register_with_groups(dev,
                                                       "gpio_fan", fan_data,
                                                       gpio_fan_groups);
        if (IS_ERR(fan_data->hwmon_dev))
                return PTR_ERR(fan_data->hwmon_dev);
-#ifdef CONFIG_OF_GPIO
+
        /* Optional cooling device register for Device tree platforms */
-       fan_data->cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
+       fan_data->cdev = thermal_of_cooling_device_register(np,
                                                            "gpio-fan",
                                                            fan_data,
                                                            &gpio_fan_cool_ops);
-#else /* CONFIG_OF_GPIO */
-       /* Optional cooling device register for non Device tree platforms */
-       fan_data->cdev = thermal_cooling_device_register("gpio-fan", fan_data,
-                                                        &gpio_fan_cool_ops);
-#endif /* CONFIG_OF_GPIO */
 
-       dev_info(&pdev->dev, "GPIO fan initialized\n");
+       dev_info(dev, "GPIO fan initialized\n");
 
        return 0;
 }
@@ -616,7 +560,7 @@ static int gpio_fan_remove(struct platform_device *pdev)
        if (!IS_ERR(fan_data->cdev))
                thermal_cooling_device_unregister(fan_data->cdev);
 
-       if (fan_data->ctrl)
+       if (fan_data->gpios)
                set_fan_speed(fan_data, 0);
 
        return 0;
@@ -632,7 +576,7 @@ static int gpio_fan_suspend(struct device *dev)
 {
        struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
 
-       if (fan_data->ctrl) {
+       if (fan_data->gpios) {
                fan_data->resume_speed = fan_data->speed_index;
                set_fan_speed(fan_data, 0);
        }
@@ -644,7 +588,7 @@ static int gpio_fan_resume(struct device *dev)
 {
        struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
 
-       if (fan_data->ctrl)
+       if (fan_data->gpios)
                set_fan_speed(fan_data, fan_data->resume_speed);
 
        return 0;
@@ -663,9 +607,7 @@ static struct platform_driver gpio_fan_driver = {
        .driver = {
                .name   = "gpio-fan",
                .pm     = GPIO_FAN_PM,
-#ifdef CONFIG_OF_GPIO
                .of_match_table = of_match_ptr(of_gpio_fan_match),
-#endif
        },
 };
 
index ce3b91f22e30afb474d81f981eca7f326c076e25..46a54ed234105040ecda4644cadeb48d6639aca2 100644 (file)
@@ -36,6 +36,10 @@ MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
 /* Provide lock for writing to NB_SMU_IND_ADDR */
 static DEFINE_MUTEX(nb_smu_ind_mutex);
 
+#ifndef PCI_DEVICE_ID_AMD_17H_DF_F3
+#define PCI_DEVICE_ID_AMD_17H_DF_F3    0x1463
+#endif
+
 /* CPUID function 0x80000001, ebx */
 #define CPUID_PKGTYPE_MASK     0xf0000000
 #define CPUID_PKGTYPE_F                0x00000000
@@ -61,31 +65,72 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
  */
 #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET    0xd8200ca4
 
-static void amd_nb_smu_index_read(struct pci_dev *pdev, unsigned int devfn,
-                                 int offset, u32 *val)
+/* F17h M01h Access througn SMN */
+#define F17H_M01H_REPORTED_TEMP_CTRL_OFFSET    0x00059800
+
+struct k10temp_data {
+       struct pci_dev *pdev;
+       void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
+       int temp_offset;
+};
+
+struct tctl_offset {
+       u8 model;
+       char const *id;
+       int offset;
+};
+
+static const struct tctl_offset tctl_offset_table[] = {
+       { 0x17, "AMD Ryzen 7 1600X", 20000 },
+       { 0x17, "AMD Ryzen 7 1700X", 20000 },
+       { 0x17, "AMD Ryzen 7 1800X", 20000 },
+       { 0x17, "AMD Ryzen Threadripper 1950X", 27000 },
+       { 0x17, "AMD Ryzen Threadripper 1920X", 27000 },
+       { 0x17, "AMD Ryzen Threadripper 1950", 10000 },
+       { 0x17, "AMD Ryzen Threadripper 1920", 10000 },
+       { 0x17, "AMD Ryzen Threadripper 1910", 10000 },
+};
+
+static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval)
+{
+       pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, regval);
+}
+
+static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn,
+                             unsigned int base, int offset, u32 *val)
 {
        mutex_lock(&nb_smu_ind_mutex);
        pci_bus_write_config_dword(pdev->bus, devfn,
-                                  0xb8, offset);
+                                  base, offset);
        pci_bus_read_config_dword(pdev->bus, devfn,
-                                 0xbc, val);
+                                 base + 4, val);
        mutex_unlock(&nb_smu_ind_mutex);
 }
 
+static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
+{
+       amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
+                         F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval);
+}
+
+static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval)
+{
+       amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0x60,
+                         F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval);
+}
+
 static ssize_t temp1_input_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
+       struct k10temp_data *data = dev_get_drvdata(dev);
        u32 regval;
-       struct pci_dev *pdev = dev_get_drvdata(dev);
-
-       if (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model == 0x60) {
-               amd_nb_smu_index_read(pdev, PCI_DEVFN(0, 0),
-                                     F15H_M60H_REPORTED_TEMP_CTRL_OFFSET,
-                                     &regval);
-       } else {
-               pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, &regval);
-       }
-       return sprintf(buf, "%u\n", (regval >> 21) * 125);
+       unsigned int temp;
+
+       data->read_tempreg(data->pdev, &regval);
+       temp = (regval >> 21) * 125;
+       temp -= data->temp_offset;
+
+       return sprintf(buf, "%u\n", temp);
 }
 
 static ssize_t temp1_max_show(struct device *dev,
@@ -98,11 +143,12 @@ static ssize_t show_temp_crit(struct device *dev,
                              struct device_attribute *devattr, char *buf)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct k10temp_data *data = dev_get_drvdata(dev);
        int show_hyst = attr->index;
        u32 regval;
        int value;
 
-       pci_read_config_dword(dev_get_drvdata(dev),
+       pci_read_config_dword(data->pdev,
                              REG_HARDWARE_THERMAL_CONTROL, &regval);
        value = ((regval >> 16) & 0x7f) * 500 + 52000;
        if (show_hyst)
@@ -119,7 +165,8 @@ static umode_t k10temp_is_visible(struct kobject *kobj,
                                  struct attribute *attr, int index)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
-       struct pci_dev *pdev = dev_get_drvdata(dev);
+       struct k10temp_data *data = dev_get_drvdata(dev);
+       struct pci_dev *pdev = data->pdev;
 
        if (index >= 2) {
                u32 reg_caps, reg_htc;
@@ -187,7 +234,9 @@ static int k10temp_probe(struct pci_dev *pdev,
 {
        int unreliable = has_erratum_319(pdev);
        struct device *dev = &pdev->dev;
+       struct k10temp_data *data;
        struct device *hwmon_dev;
+       int i;
 
        if (unreliable) {
                if (!force) {
@@ -199,7 +248,31 @@ static int k10temp_probe(struct pci_dev *pdev,
                         "unreliable CPU thermal sensor; check erratum 319\n");
        }
 
-       hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", pdev,
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->pdev = pdev;
+
+       if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
+                                         boot_cpu_data.x86_model == 0x70))
+               data->read_tempreg = read_tempreg_nb_f15;
+       else if (boot_cpu_data.x86 == 0x17)
+               data->read_tempreg = read_tempreg_nb_f17;
+       else
+               data->read_tempreg = read_tempreg_pci;
+
+       for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) {
+               const struct tctl_offset *entry = &tctl_offset_table[i];
+
+               if (boot_cpu_data.x86 == entry->model &&
+                   strstr(boot_cpu_data.x86_model_id, entry->id)) {
+                       data->temp_offset = entry->offset;
+                       break;
+               }
+       }
+
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", data,
                                                           k10temp_groups);
        return PTR_ERR_OR_ZERO(hwmon_dev);
 }
@@ -214,6 +287,7 @@ static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
        {}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
index a182789384948d2f08f6c11aee20b9fac7f8b20d..76d966932941dccdc96abd54a32d07750d4760eb 100644 (file)
@@ -303,10 +303,20 @@ static const struct i2c_device_id max1619_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max1619_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id max1619_of_match[] = {
+       { .compatible = "maxim,max1619", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, max1619_of_match);
+#endif
+
 static struct i2c_driver max1619_driver = {
        .class          = I2C_CLASS_HWMON,
        .driver = {
                .name   = "max1619",
+               .of_match_table = of_match_ptr(max1619_of_match),
        },
        .probe          = max1619_probe,
        .id_table       = max1619_id,
diff --git a/drivers/hwmon/max6621.c b/drivers/hwmon/max6621.c
new file mode 100644 (file)
index 0000000..35555f0
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Hardware monitoring driver for Maxim MAX6621
+ *
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+#define MAX6621_DRV_NAME               "max6621"
+#define MAX6621_TEMP_INPUT_REG_NUM     9
+#define MAX6621_TEMP_INPUT_MIN         -127000
+#define MAX6621_TEMP_INPUT_MAX         128000
+#define MAX6621_TEMP_ALERT_CHAN_SHIFT  1
+
+#define MAX6621_TEMP_S0D0_REG          0x00
+#define MAX6621_TEMP_S0D1_REG          0x01
+#define MAX6621_TEMP_S1D0_REG          0x02
+#define MAX6621_TEMP_S1D1_REG          0x03
+#define MAX6621_TEMP_S2D0_REG          0x04
+#define MAX6621_TEMP_S2D1_REG          0x05
+#define MAX6621_TEMP_S3D0_REG          0x06
+#define MAX6621_TEMP_S3D1_REG          0x07
+#define MAX6621_TEMP_MAX_REG           0x08
+#define MAX6621_TEMP_MAX_ADDR_REG      0x0a
+#define MAX6621_TEMP_ALERT_CAUSE_REG   0x0b
+#define MAX6621_CONFIG0_REG            0x0c
+#define MAX6621_CONFIG1_REG            0x0d
+#define MAX6621_CONFIG2_REG            0x0e
+#define MAX6621_CONFIG3_REG            0x0f
+#define MAX6621_TEMP_S0_ALERT_REG      0x10
+#define MAX6621_TEMP_S1_ALERT_REG      0x11
+#define MAX6621_TEMP_S2_ALERT_REG      0x12
+#define MAX6621_TEMP_S3_ALERT_REG      0x13
+#define MAX6621_CLEAR_ALERT_REG                0x15
+#define MAX6621_REG_MAX                        (MAX6621_CLEAR_ALERT_REG + 1)
+#define MAX6621_REG_TEMP_SHIFT         0x06
+
+#define MAX6621_ENABLE_TEMP_ALERTS_BIT 4
+#define MAX6621_ENABLE_I2C_CRC_BIT     5
+#define MAX6621_ENABLE_ALTERNATE_DATA  6
+#define MAX6621_ENABLE_LOCKUP_TO       7
+#define MAX6621_ENABLE_S0D0_BIT                8
+#define MAX6621_ENABLE_S3D1_BIT                15
+#define MAX6621_ENABLE_TEMP_ALL                GENMASK(MAX6621_ENABLE_S3D1_BIT, \
+                                               MAX6621_ENABLE_S0D0_BIT)
+#define MAX6621_POLL_DELAY_MASK                0x5
+#define MAX6621_CONFIG0_INIT           (MAX6621_ENABLE_TEMP_ALL | \
+                                        BIT(MAX6621_ENABLE_LOCKUP_TO) | \
+                                        BIT(MAX6621_ENABLE_I2C_CRC_BIT) | \
+                                        MAX6621_POLL_DELAY_MASK)
+#define MAX6621_PECI_BIT_TIME          0x2
+#define MAX6621_PECI_RETRY_NUM         0x3
+#define MAX6621_CONFIG1_INIT           ((MAX6621_PECI_BIT_TIME << 8) | \
+                                        MAX6621_PECI_RETRY_NUM)
+
+/* Error codes */
+#define MAX6621_TRAN_FAILED    0x8100  /*
+                                        * PECI transaction failed for more
+                                        * than the configured number of
+                                        * consecutive retries.
+                                        */
+#define MAX6621_POOL_DIS       0x8101  /*
+                                        * Polling disabled for requested
+                                        * socket/domain.
+                                        */
+#define MAX6621_POOL_UNCOMPLETE        0x8102  /*
+                                        * First poll not yet completed for
+                                        * requested socket/domain (on
+                                        * startup).
+                                        */
+#define MAX6621_SD_DIS         0x8103  /*
+                                        * Read maximum temperature requested,
+                                        * but no sockets/domains enabled or
+                                        * all enabled sockets/domains have
+                                        * errors; or read maximum temperature
+                                        * address requested, but read maximum
+                                        * temperature was not called.
+                                        */
+#define MAX6621_ALERT_DIS      0x8104  /*
+                                        * Get alert socket/domain requested,
+                                        * but no alert active.
+                                        */
+#define MAX6621_PECI_ERR_MIN   0x8000  /* Intel spec PECI error min value. */
+#define MAX6621_PECI_ERR_MAX   0x80ff  /* Intel spec PECI error max value. */
+
+static const u32 max6621_temp_regs[] = {
+       MAX6621_TEMP_MAX_REG, MAX6621_TEMP_S0D0_REG, MAX6621_TEMP_S1D0_REG,
+       MAX6621_TEMP_S2D0_REG, MAX6621_TEMP_S3D0_REG, MAX6621_TEMP_S0D1_REG,
+       MAX6621_TEMP_S1D1_REG, MAX6621_TEMP_S2D1_REG, MAX6621_TEMP_S3D1_REG,
+};
+
+static const char *const max6621_temp_labels[] = {
+       "maximum",
+       "socket0_0",
+       "socket1_0",
+       "socket2_0",
+       "socket3_0",
+       "socket0_1",
+       "socket1_1",
+       "socket2_1",
+       "socket3_1",
+};
+
+static const int max6621_temp_alert_chan2reg[] = {
+       MAX6621_TEMP_S0_ALERT_REG,
+       MAX6621_TEMP_S1_ALERT_REG,
+       MAX6621_TEMP_S2_ALERT_REG,
+       MAX6621_TEMP_S3_ALERT_REG,
+};
+
+/**
+ * struct max6621_data - private data:
+ *
+ * @client: I2C client;
+ * @regmap: register map handle;
+ * @input_chan2reg: mapping from channel to register;
+ */
+struct max6621_data {
+       struct i2c_client       *client;
+       struct regmap           *regmap;
+       int                     input_chan2reg[MAX6621_TEMP_INPUT_REG_NUM + 1];
+};
+
+static long max6621_temp_mc2reg(long val)
+{
+       return (val / 1000L) << MAX6621_REG_TEMP_SHIFT;
+}
+
+static umode_t
+max6621_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
+                  int channel)
+{
+       /* Skip channels which are not physically conncted. */
+       if (((struct max6621_data *)data)->input_chan2reg[channel] < 0)
+               return 0;
+
+       switch (type) {
+       case hwmon_temp:
+               switch (attr) {
+               case hwmon_temp_input:
+               case hwmon_temp_label:
+               case hwmon_temp_crit_alarm:
+                       return 0444;
+               case hwmon_temp_offset:
+               case hwmon_temp_crit:
+                       return 0644;
+               default:
+                       break;
+               }
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int max6621_verify_reg_data(struct device *dev, int regval)
+{
+       if (regval >= MAX6621_PECI_ERR_MIN &&
+           regval <= MAX6621_PECI_ERR_MAX) {
+               dev_dbg(dev, "PECI error code - err 0x%04x.\n",
+                       regval);
+
+               return -EIO;
+       }
+
+       switch (regval) {
+       case MAX6621_TRAN_FAILED:
+               dev_dbg(dev, "PECI transaction failed - err 0x%04x.\n",
+                       regval);
+               return -EIO;
+       case MAX6621_POOL_DIS:
+               dev_dbg(dev, "Polling disabled - err 0x%04x.\n", regval);
+               return -EOPNOTSUPP;
+       case MAX6621_POOL_UNCOMPLETE:
+               dev_dbg(dev, "First poll not completed on startup - err 0x%04x.\n",
+                       regval);
+               return -EIO;
+       case MAX6621_SD_DIS:
+               dev_dbg(dev, "Resource is disabled - err 0x%04x.\n", regval);
+               return -EOPNOTSUPP;
+       case MAX6621_ALERT_DIS:
+               dev_dbg(dev, "No alert active - err 0x%04x.\n", regval);
+               return -EOPNOTSUPP;
+       default:
+               return 0;
+       }
+}
+
+static int
+max6621_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+            int channel, long *val)
+{
+       struct max6621_data *data = dev_get_drvdata(dev);
+       u32 regval;
+       int reg;
+       s8 temp;
+       int ret;
+
+       switch (type) {
+       case hwmon_temp:
+               switch (attr) {
+               case hwmon_temp_input:
+                       reg = data->input_chan2reg[channel];
+                       ret = regmap_read(data->regmap, reg, &regval);
+                       if (ret)
+                               return ret;
+
+                       ret = max6621_verify_reg_data(dev, regval);
+                       if (ret)
+                               return ret;
+
+                       /*
+                        * Bit MAX6621_REG_TEMP_SHIFT represents 1 degree step.
+                        * The temperature is given in two's complement and 8
+                        * bits is used for the register conversion.
+                        */
+                       temp = (regval >> MAX6621_REG_TEMP_SHIFT);
+                       *val = temp * 1000L;
+
+                       break;
+               case hwmon_temp_offset:
+                       ret = regmap_read(data->regmap, MAX6621_CONFIG2_REG,
+                                         &regval);
+                       if (ret)
+                               return ret;
+
+                       ret = max6621_verify_reg_data(dev, regval);
+                       if (ret)
+                               return ret;
+
+                       *val = (regval >> MAX6621_REG_TEMP_SHIFT) *
+                              1000L;
+
+                       break;
+               case hwmon_temp_crit:
+                       channel -= MAX6621_TEMP_ALERT_CHAN_SHIFT;
+                       reg = max6621_temp_alert_chan2reg[channel];
+                       ret = regmap_read(data->regmap, reg, &regval);
+                       if (ret)
+                               return ret;
+
+                       ret = max6621_verify_reg_data(dev, regval);
+                       if (ret)
+                               return ret;
+
+                       *val = regval * 1000L;
+
+                       break;
+               case hwmon_temp_crit_alarm:
+                       /*
+                        * Set val to zero to recover the case, when reading
+                        * MAX6621_TEMP_ALERT_CAUSE_REG results in for example
+                        * MAX6621_ALERT_DIS. Reading will return with error,
+                        * but in such case alarm should be returned as 0.
+                        */
+                       *val = 0;
+                       ret = regmap_read(data->regmap,
+                                         MAX6621_TEMP_ALERT_CAUSE_REG,
+                                         &regval);
+                       if (ret)
+                               return ret;
+
+                       ret = max6621_verify_reg_data(dev, regval);
+                       if (ret) {
+                               /* Do not report error if alert is disabled. */
+                               if (regval == MAX6621_ALERT_DIS)
+                                       return 0;
+                               else
+                                       return ret;
+                       }
+
+                       /*
+                        * Clear the alert automatically, using send-byte
+                        * smbus protocol for clearing alert.
+                        */
+                       if (regval) {
+                               ret = i2c_smbus_write_byte(data->client,
+                                               MAX6621_CLEAR_ALERT_REG);
+                               if (ret)
+                                       return ret;
+                       }
+
+                       *val = !!regval;
+
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int
+max6621_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+             int channel, long val)
+{
+       struct max6621_data *data = dev_get_drvdata(dev);
+       u32 reg;
+
+       switch (type) {
+       case hwmon_temp:
+               switch (attr) {
+               case hwmon_temp_offset:
+                       /* Clamp to allowed range to prevent overflow. */
+                       val = clamp_val(val, MAX6621_TEMP_INPUT_MIN,
+                                       MAX6621_TEMP_INPUT_MAX);
+                       val = max6621_temp_mc2reg(val);
+
+                       return regmap_write(data->regmap,
+                                           MAX6621_CONFIG2_REG, val);
+               case hwmon_temp_crit:
+                       channel -= MAX6621_TEMP_ALERT_CHAN_SHIFT;
+                       reg = max6621_temp_alert_chan2reg[channel];
+                       /* Clamp to allowed range to prevent overflow. */
+                       val = clamp_val(val, MAX6621_TEMP_INPUT_MIN,
+                                       MAX6621_TEMP_INPUT_MAX);
+                       val = val / 1000L;
+
+                       return regmap_write(data->regmap, reg, val);
+               default:
+                       return -EOPNOTSUPP;
+               }
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static int
+max6621_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+                   int channel, const char **str)
+{
+       switch (type) {
+       case hwmon_temp:
+               switch (attr) {
+               case hwmon_temp_label:
+                       *str = max6621_temp_labels[channel];
+                       return 0;
+               default:
+                       return -EOPNOTSUPP;
+               }
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static bool max6621_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MAX6621_CONFIG0_REG:
+       case MAX6621_CONFIG1_REG:
+       case MAX6621_CONFIG2_REG:
+       case MAX6621_CONFIG3_REG:
+       case MAX6621_TEMP_S0_ALERT_REG:
+       case MAX6621_TEMP_S1_ALERT_REG:
+       case MAX6621_TEMP_S2_ALERT_REG:
+       case MAX6621_TEMP_S3_ALERT_REG:
+       case MAX6621_TEMP_ALERT_CAUSE_REG:
+               return true;
+       }
+       return false;
+}
+
+static bool max6621_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MAX6621_TEMP_S0D0_REG:
+       case MAX6621_TEMP_S0D1_REG:
+       case MAX6621_TEMP_S1D0_REG:
+       case MAX6621_TEMP_S1D1_REG:
+       case MAX6621_TEMP_S2D0_REG:
+       case MAX6621_TEMP_S2D1_REG:
+       case MAX6621_TEMP_S3D0_REG:
+       case MAX6621_TEMP_S3D1_REG:
+       case MAX6621_TEMP_MAX_REG:
+       case MAX6621_TEMP_MAX_ADDR_REG:
+       case MAX6621_CONFIG0_REG:
+       case MAX6621_CONFIG1_REG:
+       case MAX6621_CONFIG2_REG:
+       case MAX6621_CONFIG3_REG:
+       case MAX6621_TEMP_S0_ALERT_REG:
+       case MAX6621_TEMP_S1_ALERT_REG:
+       case MAX6621_TEMP_S2_ALERT_REG:
+       case MAX6621_TEMP_S3_ALERT_REG:
+               return true;
+       }
+       return false;
+}
+
+static bool max6621_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MAX6621_TEMP_S0D0_REG:
+       case MAX6621_TEMP_S0D1_REG:
+       case MAX6621_TEMP_S1D0_REG:
+       case MAX6621_TEMP_S1D1_REG:
+       case MAX6621_TEMP_S2D0_REG:
+       case MAX6621_TEMP_S2D1_REG:
+       case MAX6621_TEMP_S3D0_REG:
+       case MAX6621_TEMP_S3D1_REG:
+       case MAX6621_TEMP_MAX_REG:
+       case MAX6621_TEMP_S0_ALERT_REG:
+       case MAX6621_TEMP_S1_ALERT_REG:
+       case MAX6621_TEMP_S2_ALERT_REG:
+       case MAX6621_TEMP_S3_ALERT_REG:
+       case MAX6621_TEMP_ALERT_CAUSE_REG:
+               return true;
+       }
+       return false;
+}
+
+static const struct reg_default max6621_regmap_default[] = {
+       { MAX6621_CONFIG0_REG, MAX6621_CONFIG0_INIT },
+       { MAX6621_CONFIG1_REG, MAX6621_CONFIG1_INIT },
+};
+
+static const struct regmap_config max6621_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .max_register = MAX6621_REG_MAX,
+       .val_format_endian = REGMAP_ENDIAN_LITTLE,
+       .cache_type = REGCACHE_FLAT,
+       .writeable_reg = max6621_writeable_reg,
+       .readable_reg = max6621_readable_reg,
+       .volatile_reg = max6621_volatile_reg,
+       .reg_defaults = max6621_regmap_default,
+       .num_reg_defaults = ARRAY_SIZE(max6621_regmap_default),
+};
+
+static u32 max6621_chip_config[] = {
+       HWMON_C_REGISTER_TZ,
+       0
+};
+
+static const struct hwmon_channel_info max6621_chip = {
+       .type = hwmon_chip,
+       .config = max6621_chip_config,
+};
+
+static const u32 max6621_temp_config[] = {
+       HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
+       HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL,
+       HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL,
+       HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL,
+       HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL,
+       HWMON_T_INPUT | HWMON_T_LABEL,
+       HWMON_T_INPUT | HWMON_T_LABEL,
+       HWMON_T_INPUT | HWMON_T_LABEL,
+       HWMON_T_INPUT | HWMON_T_LABEL,
+       0
+};
+
+static const struct hwmon_channel_info max6621_temp = {
+       .type = hwmon_temp,
+       .config = max6621_temp_config,
+};
+
+static const struct hwmon_channel_info *max6621_info[] = {
+       &max6621_chip,
+       &max6621_temp,
+       NULL
+};
+
+static const struct hwmon_ops max6621_hwmon_ops = {
+       .read = max6621_read,
+       .write = max6621_write,
+       .read_string = max6621_read_string,
+       .is_visible = max6621_is_visible,
+};
+
+static const struct hwmon_chip_info max6621_chip_info = {
+       .ops = &max6621_hwmon_ops,
+       .info = max6621_info,
+};
+
+static int max6621_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct max6621_data *data;
+       struct device *hwmon_dev;
+       int i;
+       int ret;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->regmap = devm_regmap_init_i2c(client, &max6621_regmap_config);
+       if (IS_ERR(data->regmap))
+               return PTR_ERR(data->regmap);
+
+       i2c_set_clientdata(client, data);
+       data->client = client;
+
+       /* Set CONFIG0 register masking temperature alerts and PEC. */
+       ret = regmap_write(data->regmap, MAX6621_CONFIG0_REG,
+                          MAX6621_CONFIG0_INIT);
+       if (ret)
+               return ret;
+
+       /* Set CONFIG1 register for PEC access retry number. */
+       ret = regmap_write(data->regmap, MAX6621_CONFIG1_REG,
+                          MAX6621_CONFIG1_INIT);
+       if (ret)
+               return ret;
+
+       /* Sync registers with hardware. */
+       regcache_mark_dirty(data->regmap);
+       ret = regcache_sync(data->regmap);
+       if (ret)
+               return ret;
+
+       /* Verify which temperature input registers are enabled. */
+       for (i = 0; i < MAX6621_TEMP_INPUT_REG_NUM; i++) {
+               ret = i2c_smbus_read_word_data(client, max6621_temp_regs[i]);
+               if (ret < 0)
+                       return ret;
+               ret = max6621_verify_reg_data(dev, ret);
+               if (ret) {
+                       data->input_chan2reg[i] = -1;
+                       continue;
+               }
+
+               data->input_chan2reg[i] = max6621_temp_regs[i];
+       }
+
+       hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
+                                                        data,
+                                                        &max6621_chip_info,
+                                                        NULL);
+
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id max6621_id[] = {
+       { MAX6621_DRV_NAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max6621_id);
+
+static const struct of_device_id max6621_of_match[] = {
+       { .compatible = "maxim,max6621" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, max6621_of_match);
+
+static struct i2c_driver max6621_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name = MAX6621_DRV_NAME,
+               .of_match_table = of_match_ptr(max6621_of_match),
+       },
+       .probe          = max6621_probe,
+       .id_table       = max6621_id,
+};
+
+module_i2c_driver(max6621_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
+MODULE_DESCRIPTION("Driver for Maxim MAX6621");
+MODULE_LICENSE("GPL");
index 40019325b517f413bf3fae5bf9561ebfb993bfd5..08479006c7f9e9f65e6deaebb6031e5e9e5d3ef5 100644 (file)
@@ -114,6 +114,16 @@ config SENSORS_MAX20751
          This driver can also be built as a module. If so, the module will
          be called max20751.
 
+config SENSORS_MAX31785
+       tristate "Maxim MAX31785 and compatibles"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Maxim
+         MAX31785.
+
+         This driver can also be built as a module. If so, the module will
+         be called max31785.
+
 config SENSORS_MAX34440
        tristate "Maxim MAX34440 and compatibles"
        default n
index e9364420a5123d9bfe4f0ae9b3b1fe8548acaa29..ea0e39518c2168a3c1e0150a8f7482c12f3c78e7 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
 obj-$(CONFIG_SENSORS_LTC3815)  += ltc3815.o
 obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
 obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
+obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
 obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
 obj-$(CONFIG_SENSORS_MAX8688)  += max8688.o
 obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c
new file mode 100644 (file)
index 0000000..9313849
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+enum max31785_regs {
+       MFR_REVISION            = 0x9b,
+};
+
+#define MAX31785_NR_PAGES              23
+
+#define MAX31785_FAN_FUNCS \
+       (PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12)
+
+#define MAX31785_TEMP_FUNCS \
+       (PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
+
+#define MAX31785_VOUT_FUNCS \
+       (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
+
+static const struct pmbus_driver_info max31785_info = {
+       .pages = MAX31785_NR_PAGES,
+
+       /* RPM */
+       .format[PSC_FAN] = direct,
+       .m[PSC_FAN] = 1,
+       .b[PSC_FAN] = 0,
+       .R[PSC_FAN] = 0,
+       .func[0] = MAX31785_FAN_FUNCS,
+       .func[1] = MAX31785_FAN_FUNCS,
+       .func[2] = MAX31785_FAN_FUNCS,
+       .func[3] = MAX31785_FAN_FUNCS,
+       .func[4] = MAX31785_FAN_FUNCS,
+       .func[5] = MAX31785_FAN_FUNCS,
+
+       .format[PSC_TEMPERATURE] = direct,
+       .m[PSC_TEMPERATURE] = 1,
+       .b[PSC_TEMPERATURE] = 0,
+       .R[PSC_TEMPERATURE] = 2,
+       .func[6]  = MAX31785_TEMP_FUNCS,
+       .func[7]  = MAX31785_TEMP_FUNCS,
+       .func[8]  = MAX31785_TEMP_FUNCS,
+       .func[9]  = MAX31785_TEMP_FUNCS,
+       .func[10] = MAX31785_TEMP_FUNCS,
+       .func[11] = MAX31785_TEMP_FUNCS,
+       .func[12] = MAX31785_TEMP_FUNCS,
+       .func[13] = MAX31785_TEMP_FUNCS,
+       .func[14] = MAX31785_TEMP_FUNCS,
+       .func[15] = MAX31785_TEMP_FUNCS,
+       .func[16] = MAX31785_TEMP_FUNCS,
+
+       .format[PSC_VOLTAGE_OUT] = direct,
+       .m[PSC_VOLTAGE_OUT] = 1,
+       .b[PSC_VOLTAGE_OUT] = 0,
+       .R[PSC_VOLTAGE_OUT] = 0,
+       .func[17] = MAX31785_VOUT_FUNCS,
+       .func[18] = MAX31785_VOUT_FUNCS,
+       .func[19] = MAX31785_VOUT_FUNCS,
+       .func[20] = MAX31785_VOUT_FUNCS,
+       .func[21] = MAX31785_VOUT_FUNCS,
+       .func[22] = MAX31785_VOUT_FUNCS,
+};
+
+static int max31785_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct pmbus_driver_info *info;
+       s64 ret;
+
+       info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       *info = max31785_info;
+
+       ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
+       if (ret < 0)
+               return ret;
+
+       return pmbus_do_probe(client, id, info);
+}
+
+static const struct i2c_device_id max31785_id[] = {
+       { "max31785", 0 },
+       { "max31785a", 0 },
+       { },
+};
+
+MODULE_DEVICE_TABLE(i2c, max31785_id);
+
+static struct i2c_driver max31785_driver = {
+       .driver = {
+               .name = "max31785",
+       },
+       .probe = max31785_probe,
+       .remove = pmbus_do_remove,
+       .id_table = max31785_id,
+};
+
+module_i2c_driver(max31785_driver);
+
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
+MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
+MODULE_LICENSE("GPL");
index 4efa2bd4f6d8aaa485367c0ff23d57a8d46678b3..fa613bd209e344d90349fc316c7e9db64088d991 100644 (file)
@@ -404,9 +404,9 @@ extern const struct regulator_ops pmbus_regulator_ops;
 /* Function declarations */
 
 void pmbus_clear_cache(struct i2c_client *client);
-int pmbus_set_page(struct i2c_client *client, u8 page);
-int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
-int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
+int pmbus_set_page(struct i2c_client *client, int page);
+int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg);
+int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, u16 word);
 int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
 int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
 int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg,
index 302f0aef59dede142a4c9618b17de9db6768a168..52a58b8b6e1bd002f6b91b17e1c06cda94a1069b 100644 (file)
@@ -136,13 +136,13 @@ void pmbus_clear_cache(struct i2c_client *client)
 }
 EXPORT_SYMBOL_GPL(pmbus_clear_cache);
 
-int pmbus_set_page(struct i2c_client *client, u8 page)
+int pmbus_set_page(struct i2c_client *client, int page)
 {
        struct pmbus_data *data = i2c_get_clientdata(client);
        int rv = 0;
        int newpage;
 
-       if (page != data->currpage) {
+       if (page >= 0 && page != data->currpage) {
                rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
                newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
                if (newpage != page)
@@ -158,11 +158,9 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
 {
        int rv;
 
-       if (page >= 0) {
-               rv = pmbus_set_page(client, page);
-               if (rv < 0)
-                       return rv;
-       }
+       rv = pmbus_set_page(client, page);
+       if (rv < 0)
+               return rv;
 
        return i2c_smbus_write_byte(client, value);
 }
@@ -186,7 +184,8 @@ static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value)
        return pmbus_write_byte(client, page, value);
 }
 
-int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word)
+int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg,
+                         u16 word)
 {
        int rv;
 
@@ -219,7 +218,7 @@ static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg,
        return pmbus_write_word_data(client, page, reg, word);
 }
 
-int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
+int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg)
 {
        int rv;
 
@@ -255,11 +254,9 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
 {
        int rv;
 
-       if (page >= 0) {
-               rv = pmbus_set_page(client, page);
-               if (rv < 0)
-                       return rv;
-       }
+       rv = pmbus_set_page(client, page);
+       if (rv < 0)
+               return rv;
 
        return i2c_smbus_read_byte_data(client, reg);
 }
index e4d642b673c6d9e5dfebb7bc23360f4d8f46fb3e..25d28343ba936f42c3de33272f6d8bef20dda2ac 100644 (file)
 
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/mutex.h>
-#include <linux/platform_data/sht15.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
@@ -34,7 +32,8 @@
 #include <linux/slab.h>
 #include <linux/atomic.h>
 #include <linux/bitrev.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
 
 /* Commands */
 #define SHT15_MEASURE_TEMP             0x03
@@ -122,7 +121,8 @@ static const u8 sht15_crc8_table[] = {
 
 /**
  * struct sht15_data - device instance specific data
- * @pdata:             platform data (gpio's etc).
+ * @sck:               clock GPIO line
+ * @data:              data GPIO line
  * @read_work:         bh of interrupt handler.
  * @wait_queue:                wait queue for getting values from device.
  * @val_temp:          last temperature value read from device.
@@ -150,7 +150,8 @@ static const u8 sht15_crc8_table[] = {
  * @interrupt_handled: flag used to indicate a handler has been scheduled.
  */
 struct sht15_data {
-       struct sht15_platform_data      *pdata;
+       struct gpio_desc                *sck;
+       struct gpio_desc                *data;
        struct work_struct              read_work;
        wait_queue_head_t               wait_queue;
        uint16_t                        val_temp;
@@ -205,16 +206,16 @@ static int sht15_connection_reset(struct sht15_data *data)
 {
        int i, err;
 
-       err = gpio_direction_output(data->pdata->gpio_data, 1);
+       err = gpiod_direction_output(data->data, 1);
        if (err)
                return err;
        ndelay(SHT15_TSCKL);
-       gpio_set_value(data->pdata->gpio_sck, 0);
+       gpiod_set_value(data->sck, 0);
        ndelay(SHT15_TSCKL);
        for (i = 0; i < 9; ++i) {
-               gpio_set_value(data->pdata->gpio_sck, 1);
+               gpiod_set_value(data->sck, 1);
                ndelay(SHT15_TSCKH);
-               gpio_set_value(data->pdata->gpio_sck, 0);
+               gpiod_set_value(data->sck, 0);
                ndelay(SHT15_TSCKL);
        }
        return 0;
@@ -227,11 +228,11 @@ static int sht15_connection_reset(struct sht15_data *data)
  */
 static inline void sht15_send_bit(struct sht15_data *data, int val)
 {
-       gpio_set_value(data->pdata->gpio_data, val);
+       gpiod_set_value(data->data, val);
        ndelay(SHT15_TSU);
-       gpio_set_value(data->pdata->gpio_sck, 1);
+       gpiod_set_value(data->sck, 1);
        ndelay(SHT15_TSCKH);
-       gpio_set_value(data->pdata->gpio_sck, 0);
+       gpiod_set_value(data->sck, 0);
        ndelay(SHT15_TSCKL); /* clock low time */
 }
 
@@ -248,23 +249,23 @@ static int sht15_transmission_start(struct sht15_data *data)
        int err;
 
        /* ensure data is high and output */
-       err = gpio_direction_output(data->pdata->gpio_data, 1);
+       err = gpiod_direction_output(data->data, 1);
        if (err)
                return err;
        ndelay(SHT15_TSU);
-       gpio_set_value(data->pdata->gpio_sck, 0);
+       gpiod_set_value(data->sck, 0);
        ndelay(SHT15_TSCKL);
-       gpio_set_value(data->pdata->gpio_sck, 1);
+       gpiod_set_value(data->sck, 1);
        ndelay(SHT15_TSCKH);
-       gpio_set_value(data->pdata->gpio_data, 0);
+       gpiod_set_value(data->data, 0);
        ndelay(SHT15_TSU);
-       gpio_set_value(data->pdata->gpio_sck, 0);
+       gpiod_set_value(data->sck, 0);
        ndelay(SHT15_TSCKL);
-       gpio_set_value(data->pdata->gpio_sck, 1);
+       gpiod_set_value(data->sck, 1);
        ndelay(SHT15_TSCKH);
-       gpio_set_value(data->pdata->gpio_data, 1);
+       gpiod_set_value(data->data, 1);
        ndelay(SHT15_TSU);
-       gpio_set_value(data->pdata->gpio_sck, 0);
+       gpiod_set_value(data->sck, 0);
        ndelay(SHT15_TSCKL);
        return 0;
 }
@@ -292,20 +293,20 @@ static int sht15_wait_for_response(struct sht15_data *data)
 {
        int err;
 
-       err = gpio_direction_input(data->pdata->gpio_data);
+       err = gpiod_direction_input(data->data);
        if (err)
                return err;
-       gpio_set_value(data->pdata->gpio_sck, 1);
+       gpiod_set_value(data->sck, 1);
        ndelay(SHT15_TSCKH);
-       if (gpio_get_value(data->pdata->gpio_data)) {
-               gpio_set_value(data->pdata->gpio_sck, 0);
+       if (gpiod_get_value(data->data)) {
+               gpiod_set_value(data->sck, 0);
                dev_err(data->dev, "Command not acknowledged\n");
                err = sht15_connection_reset(data);
                if (err)
                        return err;
                return -EIO;
        }
-       gpio_set_value(data->pdata->gpio_sck, 0);
+       gpiod_set_value(data->sck, 0);
        ndelay(SHT15_TSCKL);
        return 0;
 }
@@ -360,17 +361,17 @@ static int sht15_ack(struct sht15_data *data)
 {
        int err;
 
-       err = gpio_direction_output(data->pdata->gpio_data, 0);
+       err = gpiod_direction_output(data->data, 0);
        if (err)
                return err;
        ndelay(SHT15_TSU);
-       gpio_set_value(data->pdata->gpio_sck, 1);
+       gpiod_set_value(data->sck, 1);
        ndelay(SHT15_TSU);
-       gpio_set_value(data->pdata->gpio_sck, 0);
+       gpiod_set_value(data->sck, 0);
        ndelay(SHT15_TSU);
-       gpio_set_value(data->pdata->gpio_data, 1);
+       gpiod_set_value(data->data, 1);
 
-       return gpio_direction_input(data->pdata->gpio_data);
+       return gpiod_direction_input(data->data);
 }
 
 /**
@@ -383,13 +384,13 @@ static int sht15_end_transmission(struct sht15_data *data)
 {
        int err;
 
-       err = gpio_direction_output(data->pdata->gpio_data, 1);
+       err = gpiod_direction_output(data->data, 1);
        if (err)
                return err;
        ndelay(SHT15_TSU);
-       gpio_set_value(data->pdata->gpio_sck, 1);
+       gpiod_set_value(data->sck, 1);
        ndelay(SHT15_TSCKH);
-       gpio_set_value(data->pdata->gpio_sck, 0);
+       gpiod_set_value(data->sck, 0);
        ndelay(SHT15_TSCKL);
        return 0;
 }
@@ -405,10 +406,10 @@ static u8 sht15_read_byte(struct sht15_data *data)
 
        for (i = 0; i < 8; ++i) {
                byte <<= 1;
-               gpio_set_value(data->pdata->gpio_sck, 1);
+               gpiod_set_value(data->sck, 1);
                ndelay(SHT15_TSCKH);
-               byte |= !!gpio_get_value(data->pdata->gpio_data);
-               gpio_set_value(data->pdata->gpio_sck, 0);
+               byte |= !!gpiod_get_value(data->data);
+               gpiod_set_value(data->sck, 0);
                ndelay(SHT15_TSCKL);
        }
        return byte;
@@ -428,7 +429,7 @@ static int sht15_send_status(struct sht15_data *data, u8 status)
        err = sht15_send_cmd(data, SHT15_WRITE_STATUS);
        if (err)
                return err;
-       err = gpio_direction_output(data->pdata->gpio_data, 1);
+       err = gpiod_direction_output(data->data, 1);
        if (err)
                return err;
        ndelay(SHT15_TSU);
@@ -528,14 +529,14 @@ static int sht15_measurement(struct sht15_data *data,
        if (ret)
                return ret;
 
-       ret = gpio_direction_input(data->pdata->gpio_data);
+       ret = gpiod_direction_input(data->data);
        if (ret)
                return ret;
        atomic_set(&data->interrupt_handled, 0);
 
-       enable_irq(gpio_to_irq(data->pdata->gpio_data));
-       if (gpio_get_value(data->pdata->gpio_data) == 0) {
-               disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
+       enable_irq(gpiod_to_irq(data->data));
+       if (gpiod_get_value(data->data) == 0) {
+               disable_irq_nosync(gpiod_to_irq(data->data));
                /* Only relevant if the interrupt hasn't occurred. */
                if (!atomic_read(&data->interrupt_handled))
                        schedule_work(&data->read_work);
@@ -547,7 +548,7 @@ static int sht15_measurement(struct sht15_data *data,
                data->state = SHT15_READING_NOTHING;
                return -EIO;
        } else if (ret == 0) { /* timeout occurred */
-               disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
+               disable_irq_nosync(gpiod_to_irq(data->data));
                ret = sht15_connection_reset(data);
                if (ret)
                        return ret;
@@ -826,15 +827,15 @@ static void sht15_bh_read_data(struct work_struct *work_s)
                               read_work);
 
        /* Firstly, verify the line is low */
-       if (gpio_get_value(data->pdata->gpio_data)) {
+       if (gpiod_get_value(data->data)) {
                /*
                 * If not, then start the interrupt again - care here as could
                 * have gone low in meantime so verify it hasn't!
                 */
                atomic_set(&data->interrupt_handled, 0);
-               enable_irq(gpio_to_irq(data->pdata->gpio_data));
+               enable_irq(gpiod_to_irq(data->data));
                /* If still not occurred or another handler was scheduled */
-               if (gpio_get_value(data->pdata->gpio_data)
+               if (gpiod_get_value(data->data)
                    || atomic_read(&data->interrupt_handled))
                        return;
        }
@@ -918,53 +919,12 @@ static const struct of_device_id sht15_dt_match[] = {
        { },
 };
 MODULE_DEVICE_TABLE(of, sht15_dt_match);
-
-/*
- * This function returns NULL if pdev isn't a device instatiated by dt,
- * a pointer to pdata if it could successfully get all information
- * from dt or a negative ERR_PTR() on error.
- */
-static struct sht15_platform_data *sht15_probe_dt(struct device *dev)
-{
-       struct device_node *np = dev->of_node;
-       struct sht15_platform_data *pdata;
-
-       /* no device tree device */
-       if (!np)
-               return NULL;
-
-       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata)
-               return ERR_PTR(-ENOMEM);
-
-       pdata->gpio_data = of_get_named_gpio(np, "data-gpios", 0);
-       if (pdata->gpio_data < 0) {
-               if (pdata->gpio_data != -EPROBE_DEFER)
-                       dev_err(dev, "data-gpios not found\n");
-               return ERR_PTR(pdata->gpio_data);
-       }
-
-       pdata->gpio_sck = of_get_named_gpio(np, "clk-gpios", 0);
-       if (pdata->gpio_sck < 0) {
-               if (pdata->gpio_sck != -EPROBE_DEFER)
-                       dev_err(dev, "clk-gpios not found\n");
-               return ERR_PTR(pdata->gpio_sck);
-       }
-
-       return pdata;
-}
-#else
-static inline struct sht15_platform_data *sht15_probe_dt(struct device *dev)
-{
-       return NULL;
-}
 #endif
 
 static int sht15_probe(struct platform_device *pdev)
 {
        int ret;
        struct sht15_data *data;
-       u8 status = 0;
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
@@ -977,25 +937,6 @@ static int sht15_probe(struct platform_device *pdev)
        data->dev = &pdev->dev;
        init_waitqueue_head(&data->wait_queue);
 
-       data->pdata = sht15_probe_dt(&pdev->dev);
-       if (IS_ERR(data->pdata))
-               return PTR_ERR(data->pdata);
-       if (data->pdata == NULL) {
-               data->pdata = dev_get_platdata(&pdev->dev);
-               if (data->pdata == NULL) {
-                       dev_err(&pdev->dev, "no platform data supplied\n");
-                       return -EINVAL;
-               }
-       }
-
-       data->supply_uv = data->pdata->supply_mv * 1000;
-       if (data->pdata->checksum)
-               data->checksumming = true;
-       if (data->pdata->no_otp_reload)
-               status |= SHT15_STATUS_NO_OTP_RELOAD;
-       if (data->pdata->low_resolution)
-               status |= SHT15_STATUS_LOW_RESOLUTION;
-
        /*
         * If a regulator is available,
         * query what the supply voltage actually is!
@@ -1030,21 +971,20 @@ static int sht15_probe(struct platform_device *pdev)
        }
 
        /* Try requesting the GPIOs */
-       ret = devm_gpio_request_one(&pdev->dev, data->pdata->gpio_sck,
-                       GPIOF_OUT_INIT_LOW, "SHT15 sck");
-       if (ret) {
+       data->sck = devm_gpiod_get(&pdev->dev, "clk", GPIOD_OUT_LOW);
+       if (IS_ERR(data->sck)) {
+               ret = PTR_ERR(data->sck);
                dev_err(&pdev->dev, "clock line GPIO request failed\n");
                goto err_release_reg;
        }
-
-       ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
-                               "SHT15 data");
-       if (ret) {
+       data->data = devm_gpiod_get(&pdev->dev, "data", GPIOD_IN);
+       if (IS_ERR(data->data)) {
+               ret = PTR_ERR(data->data);
                dev_err(&pdev->dev, "data line GPIO request failed\n");
                goto err_release_reg;
        }
 
-       ret = devm_request_irq(&pdev->dev, gpio_to_irq(data->pdata->gpio_data),
+       ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
                               sht15_interrupt_fired,
                               IRQF_TRIGGER_FALLING,
                               "sht15 data",
@@ -1053,7 +993,7 @@ static int sht15_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "failed to get irq for data line\n");
                goto err_release_reg;
        }
-       disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
+       disable_irq_nosync(gpiod_to_irq(data->data));
        ret = sht15_connection_reset(data);
        if (ret)
                goto err_release_reg;
@@ -1061,13 +1001,6 @@ static int sht15_probe(struct platform_device *pdev)
        if (ret)
                goto err_release_reg;
 
-       /* write status with platform data options */
-       if (status) {
-               ret = sht15_send_status(data, status);
-               if (ret)
-                       goto err_release_reg;
-       }
-
        ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
        if (ret) {
                dev_err(&pdev->dev, "sysfs create failed\n");
index 3f940fb67dc622cc096745b9e6950e68f73d6b73..7fe152d92350e18b6c972ebcf0a7f0be0bbf94e4 100644 (file)
@@ -396,7 +396,7 @@ static ssize_t show_max_alarm(struct device *dev, struct device_attribute *attr,
        if (ret < 0)
                return ret;
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->max_alert);
+       return snprintf(buf, PAGE_SIZE, "%d\n", priv->max_alert);
 }
 
 static ssize_t show_min_alarm(struct device *dev, struct device_attribute *attr,
@@ -413,7 +413,7 @@ static ssize_t show_min_alarm(struct device *dev, struct device_attribute *attr,
        if (ret < 0)
                return ret;
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->min_alert);
+       return snprintf(buf, PAGE_SIZE, "%d\n", priv->min_alert);
 }
 
 static ssize_t show_input(struct device *dev, struct device_attribute *attr,
@@ -428,7 +428,7 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr,
        if (ret < 0)
                return ret;
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->temp);
+       return snprintf(buf, PAGE_SIZE, "%d\n", priv->temp);
 }
 
 static ssize_t show_therm(struct device *dev, struct device_attribute *attr,
@@ -436,7 +436,7 @@ static ssize_t show_therm(struct device *dev, struct device_attribute *attr,
 {
        struct stts751_priv *priv = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->therm);
+       return snprintf(buf, PAGE_SIZE, "%d\n", priv->therm);
 }
 
 static ssize_t set_therm(struct device *dev, struct device_attribute *attr,
@@ -478,7 +478,7 @@ static ssize_t show_hyst(struct device *dev, struct device_attribute *attr,
 {
        struct stts751_priv *priv = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->hyst);
+       return snprintf(buf, PAGE_SIZE, "%d\n", priv->hyst);
 }
 
 static ssize_t set_hyst(struct device *dev, struct device_attribute *attr,
@@ -518,7 +518,7 @@ static ssize_t show_therm_trip(struct device *dev,
        if (ret < 0)
                return ret;
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->therm_trip);
+       return snprintf(buf, PAGE_SIZE, "%d\n", priv->therm_trip);
 }
 
 static ssize_t show_max(struct device *dev, struct device_attribute *attr,
@@ -526,7 +526,7 @@ static ssize_t show_max(struct device *dev, struct device_attribute *attr,
 {
        struct stts751_priv *priv = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->event_max);
+       return snprintf(buf, PAGE_SIZE, "%d\n", priv->event_max);
 }
 
 static ssize_t set_max(struct device *dev, struct device_attribute *attr,
@@ -560,7 +560,7 @@ static ssize_t show_min(struct device *dev, struct device_attribute *attr,
 {
        struct stts751_priv *priv = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->event_min);
+       return snprintf(buf, PAGE_SIZE, "%d\n", priv->event_min);
 }
 
 static ssize_t set_min(struct device *dev, struct device_attribute *attr,
@@ -594,7 +594,7 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
 {
        struct stts751_priv *priv = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+       return snprintf(buf, PAGE_SIZE, "%d\n",
                        stts751_intervals[priv->interval]);
 }
 
index dab5c515d5a3d141449645717edbd35688b13fbb..5ba9d9f1daa1f5f65933edd58bc32adb8525e10b 100644 (file)
@@ -1676,7 +1676,9 @@ static int w83793_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
-       const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
+       static const int watchdog_minors[] = {
+               WATCHDOG_MINOR, 212, 213, 214, 215
+       };
        struct w83793_data *data;
        int i, tmp, val, err;
        int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
index e1be61095532f03dda79effe36fbde2147a31d66..a3cd91f232679afd21c9ebbd206be377f5394333 100644 (file)
 #define to_xgene_hwmon_dev(cl)         \
        container_of(cl, struct xgene_hwmon_dev, mbox_client)
 
+enum xgene_hwmon_version {
+       XGENE_HWMON_V1 = 0,
+       XGENE_HWMON_V2 = 1,
+};
+
 struct slimpro_resp_msg {
        u32 msg;
        u32 param1;
@@ -609,6 +614,15 @@ static void xgene_hwmon_tx_done(struct mbox_client *cl, void *msg, int ret)
        }
 }
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_hwmon_acpi_match[] = {
+       {"APMC0D29", XGENE_HWMON_V1},
+       {"APMC0D8A", XGENE_HWMON_V2},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, xgene_hwmon_acpi_match);
+#endif
+
 static int xgene_hwmon_probe(struct platform_device *pdev)
 {
        struct xgene_hwmon_dev *ctx;
@@ -651,6 +665,15 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
                }
        } else {
                struct acpi_pcct_hw_reduced *cppc_ss;
+               const struct acpi_device_id *acpi_id;
+               int version;
+
+               acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
+                                           &pdev->dev);
+               if (!acpi_id)
+                       return -EINVAL;
+
+               version = (int)acpi_id->driver_data;
 
                if (device_property_read_u32(&pdev->dev, "pcc-channel",
                                             &ctx->mbox_idx)) {
@@ -693,7 +716,13 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
                 */
                ctx->comm_base_addr = cppc_ss->base_address;
                if (ctx->comm_base_addr) {
-                       ctx->pcc_comm_addr = memremap(ctx->comm_base_addr,
+                       if (version == XGENE_HWMON_V2)
+                               ctx->pcc_comm_addr = (void __force *)ioremap(
+                                                       ctx->comm_base_addr,
+                                                       cppc_ss->length);
+                       else
+                               ctx->pcc_comm_addr = memremap(
+                                                       ctx->comm_base_addr,
                                                        cppc_ss->length,
                                                        MEMREMAP_WB);
                } else {
@@ -761,14 +790,6 @@ static int xgene_hwmon_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id xgene_hwmon_acpi_match[] = {
-       {"APMC0D29", 0},
-       {},
-};
-MODULE_DEVICE_TABLE(acpi, xgene_hwmon_acpi_match);
-#endif
-
 static const struct of_device_id xgene_hwmon_of_match[] = {
        {.compatible = "apm,xgene-slimpro-hwmon"},
        {}
index a7355ab3bb221a0a6438d336719f1f3a30e4e00a..6ff0be8cbdc980e1671e6a6bcd4faaf5537f0014 100644 (file)
@@ -867,11 +867,16 @@ static void msf_from_bcd(struct atapi_msf *msf)
 int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
 {
        struct cdrom_info *info = drive->driver_data;
-       struct cdrom_device_info *cdi = &info->devinfo;
+       struct cdrom_device_info *cdi;
        unsigned char cmd[BLK_MAX_CDB];
 
        ide_debug_log(IDE_DBG_FUNC, "enter");
 
+       if (!info)
+               return -EIO;
+
+       cdi = &info->devinfo;
+
        memset(cmd, 0, BLK_MAX_CDB);
        cmd[0] = GPCMD_TEST_UNIT_READY;
 
index 3a234701d92c4ac3965cce3e48edc6ef856ca9a0..6f25da56a1690cfaaa3183a5b9b489474865dab5 100644 (file)
@@ -611,9 +611,9 @@ static int drive_is_ready(ide_drive_t *drive)
  *     logic that wants cleaning up.
  */
  
-void ide_timer_expiry (unsigned long data)
+void ide_timer_expiry (struct timer_list *t)
 {
-       ide_hwif_t      *hwif = (ide_hwif_t *)data;
+       ide_hwif_t      *hwif = from_timer(hwif, t, timer);
        ide_drive_t     *uninitialized_var(drive);
        ide_handler_t   *handler;
        unsigned long   flags;
index eaf39e5db08ba98ad2bfcc32e9892e2f2c8be972..17fd55af4d9247ee89c0b581c5de3ab3437860a2 100644 (file)
@@ -1184,7 +1184,7 @@ static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
 
        spin_lock_init(&hwif->lock);
 
-       setup_timer(&hwif->timer, &ide_timer_expiry, (unsigned long)hwif);
+       timer_setup(&hwif->timer, ide_timer_expiry, 0);
 
        init_completion(&hwif->gendev_rel_comp);
 
index f0b06b14e782b5b926b5ba7876d827551ce4cfa9..b2ccce5fb0718303971dec46581482ff1d2e7e76 100644 (file)
@@ -913,10 +913,9 @@ static __cpuidle int intel_idle(struct cpuidle_device *dev,
        struct cpuidle_state *state = &drv->states[index];
        unsigned long eax = flg2MWAIT(state->flags);
        unsigned int cstate;
+       bool uninitialized_var(tick);
        int cpu = smp_processor_id();
 
-       cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
-
        /*
         * leave_mm() to avoid costly and often unnecessary wakeups
         * for flushing the user TLB's associated with the active mm.
@@ -924,12 +923,19 @@ static __cpuidle int intel_idle(struct cpuidle_device *dev,
        if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
                leave_mm(cpu);
 
-       if (!(lapic_timer_reliable_states & (1 << (cstate))))
-               tick_broadcast_enter();
+       if (!static_cpu_has(X86_FEATURE_ARAT)) {
+               cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) &
+                               MWAIT_CSTATE_MASK) + 1;
+               tick = false;
+               if (!(lapic_timer_reliable_states & (1 << (cstate)))) {
+                       tick = true;
+                       tick_broadcast_enter();
+               }
+       }
 
        mwait_idle_with_hints(eax, ecx);
 
-       if (!(lapic_timer_reliable_states & (1 << (cstate))))
+       if (!static_cpu_has(X86_FEATURE_ARAT) && tick)
                tick_broadcast_exit();
 
        return index;
@@ -1061,7 +1067,7 @@ static const struct idle_cpu idle_cpu_dnv = {
 };
 
 #define ICPU(model, cpu) \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
+       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&cpu }
 
 static const struct x86_cpu_id intel_idle_ids[] __initconst = {
        ICPU(INTEL_FAM6_NEHALEM_EP,             idle_cpu_nehalem),
@@ -1125,6 +1131,11 @@ static int __init intel_idle_probe(void)
                return -ENODEV;
        }
 
+       if (!boot_cpu_has(X86_FEATURE_MWAIT)) {
+               pr_debug("Please enable MWAIT in BIOS SETUP\n");
+               return -ENODEV;
+       }
+
        if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
                return -ENODEV;
 
index d9a1e989313641b06f32ffdd4677ce8aa7e32802..97bea2e1aa6a7739d6c73a343258d551bbbc61d2 100644 (file)
@@ -380,7 +380,7 @@ static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
                if (sc->flags & SCF_FROZEN) {
                        wait_event_interruptible_timeout(
                                dd->event_queue,
-                               !(ACCESS_ONCE(dd->flags) & HFI1_FROZEN),
+                               !(READ_ONCE(dd->flags) & HFI1_FROZEN),
                                msecs_to_jiffies(SEND_CTXT_HALT_TIMEOUT));
                        if (dd->flags & HFI1_FROZEN)
                                return -ENOLCK;
index 7108a4b5e94cdef45f27722847065388a36a6f85..75e740780285d050c41f2aa20a6ad9e888e2acd3 100644 (file)
@@ -1423,14 +1423,14 @@ retry:
                        goto done;
                }
                /* copy from receiver cache line and recalculate */
-               sc->alloc_free = ACCESS_ONCE(sc->free);
+               sc->alloc_free = READ_ONCE(sc->free);
                avail =
                        (unsigned long)sc->credits -
                        (sc->fill - sc->alloc_free);
                if (blocks > avail) {
                        /* still no room, actively update */
                        sc_release_update(sc);
-                       sc->alloc_free = ACCESS_ONCE(sc->free);
+                       sc->alloc_free = READ_ONCE(sc->free);
                        trycount++;
                        goto retry;
                }
@@ -1667,7 +1667,7 @@ void sc_release_update(struct send_context *sc)
 
        /* call sent buffer callbacks */
        code = -1;                              /* code not yet set */
-       head = ACCESS_ONCE(sc->sr_head);        /* snapshot the head */
+       head = READ_ONCE(sc->sr_head);  /* snapshot the head */
        tail = sc->sr_tail;
        while (head != tail) {
                pbuf = &sc->sr[tail].pbuf;
index b3291f0fde9a41ccf1119822a857ff5fd717a141..a7fc664f0d4e1c3195b216014eb1337bdac23cc4 100644 (file)
@@ -363,7 +363,7 @@ static void ruc_loopback(struct rvt_qp *sqp)
 
 again:
        smp_read_barrier_depends(); /* see post_one_send() */
-       if (sqp->s_last == ACCESS_ONCE(sqp->s_head))
+       if (sqp->s_last == READ_ONCE(sqp->s_head))
                goto clr_busy;
        wqe = rvt_get_swqe_ptr(sqp, sqp->s_last);
 
index 6781bcdb10b3153246d1f3e7b0f8bc056657dde3..08346d25441cb48c6deda6c27dc52c1f19d14853 100644 (file)
@@ -1725,7 +1725,7 @@ retry:
 
                swhead = sde->descq_head & sde->sdma_mask;
                /* this code is really bad for cache line trading */
-               swtail = ACCESS_ONCE(sde->descq_tail) & sde->sdma_mask;
+               swtail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
                cnt = sde->descq_cnt;
 
                if (swhead < swtail)
@@ -1872,7 +1872,7 @@ retry:
        if ((status & sde->idle_mask) && !idle_check_done) {
                u16 swtail;
 
-               swtail = ACCESS_ONCE(sde->descq_tail) & sde->sdma_mask;
+               swtail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
                if (swtail != hwhead) {
                        hwhead = (u16)read_sde_csr(sde, SD(HEAD));
                        idle_check_done = 1;
@@ -2222,7 +2222,7 @@ void sdma_seqfile_dump_sde(struct seq_file *s, struct sdma_engine *sde)
        u16 len;
 
        head = sde->descq_head & sde->sdma_mask;
-       tail = ACCESS_ONCE(sde->descq_tail) & sde->sdma_mask;
+       tail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
        seq_printf(s, SDE_FMT, sde->this_idx,
                   sde->cpu,
                   sdma_state_name(sde->state.current_state),
@@ -3305,7 +3305,7 @@ int sdma_ahg_alloc(struct sdma_engine *sde)
                return -EINVAL;
        }
        while (1) {
-               nr = ffz(ACCESS_ONCE(sde->ahg_bits));
+               nr = ffz(READ_ONCE(sde->ahg_bits));
                if (nr > 31) {
                        trace_hfi1_ahg_allocate(sde, -ENOSPC);
                        return -ENOSPC;
index 107011d8613b9127fe63162b2c7080bee138e60d..374c59784950650e7845be591496b5be6b1403a4 100644 (file)
@@ -445,7 +445,7 @@ static inline u16 sdma_descq_freecnt(struct sdma_engine *sde)
 {
        return sde->descq_cnt -
                (sde->descq_tail -
-                ACCESS_ONCE(sde->descq_head)) - 1;
+                READ_ONCE(sde->descq_head)) - 1;
 }
 
 static inline u16 sdma_descq_inprocess(struct sdma_engine *sde)
index 0b646173ca22272fc5a5cca17b231f4675462a1d..9a31c585427f91790d392d444ca8570a7917e33f 100644 (file)
@@ -80,7 +80,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                        goto bail;
                /* We are in the error state, flush the work request. */
                smp_read_barrier_depends(); /* see post_one_send() */
-               if (qp->s_last == ACCESS_ONCE(qp->s_head))
+               if (qp->s_last == READ_ONCE(qp->s_head))
                        goto bail;
                /* If DMAs are in progress, we can't flush immediately. */
                if (iowait_sdma_pending(&priv->s_iowait)) {
@@ -121,7 +121,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                        goto bail;
                /* Check if send work queue is empty. */
                smp_read_barrier_depends(); /* see post_one_send() */
-               if (qp->s_cur == ACCESS_ONCE(qp->s_head)) {
+               if (qp->s_cur == READ_ONCE(qp->s_head)) {
                        clear_ahg(qp);
                        goto bail;
                }
index 2ba74fdd6f153dc33c0c153d09e2be1f73f8ed73..7fec6b984e3e5a8ca621447bc631aa92352dc7a6 100644 (file)
@@ -487,7 +487,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                        goto bail;
                /* We are in the error state, flush the work request. */
                smp_read_barrier_depends(); /* see post_one_send */
-               if (qp->s_last == ACCESS_ONCE(qp->s_head))
+               if (qp->s_last == READ_ONCE(qp->s_head))
                        goto bail;
                /* If DMAs are in progress, we can't flush immediately. */
                if (iowait_sdma_pending(&priv->s_iowait)) {
@@ -501,7 +501,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
 
        /* see post_one_send() */
        smp_read_barrier_depends();
-       if (qp->s_cur == ACCESS_ONCE(qp->s_head))
+       if (qp->s_cur == READ_ONCE(qp->s_head))
                goto bail;
 
        wqe = rvt_get_swqe_ptr(qp, qp->s_cur);
index c0c0e0445cbfbd72938fe07520f574515992298b..8ec6e8a8d6f76f15dc4759c228f52d1ebb69bd2a 100644 (file)
@@ -276,7 +276,7 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd,
                /* Wait until all requests have been freed. */
                wait_event_interruptible(
                        pq->wait,
-                       (ACCESS_ONCE(pq->state) == SDMA_PKT_Q_INACTIVE));
+                       (READ_ONCE(pq->state) == SDMA_PKT_Q_INACTIVE));
                kfree(pq->reqs);
                kfree(pq->req_in_use);
                kmem_cache_destroy(pq->txreq_cache);
@@ -591,7 +591,7 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
                        if (ret != -EBUSY) {
                                req->status = ret;
                                WRITE_ONCE(req->has_error, 1);
-                               if (ACCESS_ONCE(req->seqcomp) ==
+                               if (READ_ONCE(req->seqcomp) ==
                                    req->seqsubmitted - 1)
                                        goto free_req;
                                return ret;
@@ -825,7 +825,7 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
                 */
                if (req->data_len) {
                        iovec = &req->iovs[req->iov_idx];
-                       if (ACCESS_ONCE(iovec->offset) == iovec->iov.iov_len) {
+                       if (READ_ONCE(iovec->offset) == iovec->iov.iov_len) {
                                if (++req->iov_idx == req->data_iovs) {
                                        ret = -EFAULT;
                                        goto free_txreq;
@@ -1390,7 +1390,7 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status)
        } else {
                if (status != SDMA_TXREQ_S_OK)
                        req->status = status;
-               if (req->seqcomp == (ACCESS_ONCE(req->seqsubmitted) - 1) &&
+               if (req->seqcomp == (READ_ONCE(req->seqsubmitted) - 1) &&
                    (READ_ONCE(req->done) ||
                     READ_ONCE(req->has_error))) {
                        user_sdma_free_request(req, false);
index 53efbb0b40c4a1137e0de152ccad5036ad423f74..9a37e844d4c8739087f82fa728ecc42cb262ff80 100644 (file)
@@ -368,7 +368,7 @@ static void qib_ruc_loopback(struct rvt_qp *sqp)
 
 again:
        smp_read_barrier_depends(); /* see post_one_send() */
-       if (sqp->s_last == ACCESS_ONCE(sqp->s_head))
+       if (sqp->s_last == READ_ONCE(sqp->s_head))
                goto clr_busy;
        wqe = rvt_get_swqe_ptr(sqp, sqp->s_last);
 
index 498e2202e72c9d96622d8c21c3e27a473057cbe6..bddcc37ace4420937c5fde681edf29169a3e36c3 100644 (file)
@@ -61,7 +61,7 @@ int qib_make_uc_req(struct rvt_qp *qp, unsigned long *flags)
                        goto bail;
                /* We are in the error state, flush the work request. */
                smp_read_barrier_depends(); /* see post_one_send() */
-               if (qp->s_last == ACCESS_ONCE(qp->s_head))
+               if (qp->s_last == READ_ONCE(qp->s_head))
                        goto bail;
                /* If DMAs are in progress, we can't flush immediately. */
                if (atomic_read(&priv->s_dma_busy)) {
@@ -91,7 +91,7 @@ int qib_make_uc_req(struct rvt_qp *qp, unsigned long *flags)
                        goto bail;
                /* Check if send work queue is empty. */
                smp_read_barrier_depends(); /* see post_one_send() */
-               if (qp->s_cur == ACCESS_ONCE(qp->s_head))
+               if (qp->s_cur == READ_ONCE(qp->s_head))
                        goto bail;
                /*
                 * Start a new request.
index be4907453ac4d031f2b1e7d8ed5ddd09235b0837..15962ed193cea0515bcda715ed536f3983d66ed8 100644 (file)
@@ -253,7 +253,7 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags)
                        goto bail;
                /* We are in the error state, flush the work request. */
                smp_read_barrier_depends(); /* see post_one_send */
-               if (qp->s_last == ACCESS_ONCE(qp->s_head))
+               if (qp->s_last == READ_ONCE(qp->s_head))
                        goto bail;
                /* If DMAs are in progress, we can't flush immediately. */
                if (atomic_read(&priv->s_dma_busy)) {
@@ -267,7 +267,7 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags)
 
        /* see post_one_send() */
        smp_read_barrier_depends();
-       if (qp->s_cur == ACCESS_ONCE(qp->s_head))
+       if (qp->s_cur == READ_ONCE(qp->s_head))
                goto bail;
 
        wqe = rvt_get_swqe_ptr(qp, qp->s_cur);
index 22df09ae809e42553e865a2152539b88bd5d79ae..b670cb9d200630215ac38cc591aed2891ac1d25f 100644 (file)
@@ -1073,7 +1073,7 @@ int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err)
        rdi->driver_f.notify_error_qp(qp);
 
        /* Schedule the sending tasklet to drain the send work queue. */
-       if (ACCESS_ONCE(qp->s_last) != qp->s_head)
+       if (READ_ONCE(qp->s_last) != qp->s_head)
                rdi->driver_f.schedule_send(qp);
 
        rvt_clear_mr_refs(qp, 0);
@@ -1686,7 +1686,7 @@ static inline int rvt_qp_is_avail(
        if (likely(qp->s_avail))
                return 0;
        smp_read_barrier_depends(); /* see rc.c */
-       slast = ACCESS_ONCE(qp->s_last);
+       slast = READ_ONCE(qp->s_last);
        if (qp->s_head >= slast)
                avail = qp->s_size - (qp->s_head - slast);
        else
@@ -1917,7 +1917,7 @@ int rvt_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
         * ahead and kick the send engine into gear. Otherwise we will always
         * just schedule the send to happen later.
         */
-       call_send = qp->s_head == ACCESS_ONCE(qp->s_last) && !wr->next;
+       call_send = qp->s_head == READ_ONCE(qp->s_last) && !wr->next;
 
        for (; wr; wr = wr->next) {
                err = rvt_post_one_wr(qp, wr, &call_send);
index 2e8f801932be723c91e3ff4beb643580b66fa4c6..a1db1e5040dcf13937e54199f7d8d696885f90a4 100644 (file)
@@ -233,7 +233,7 @@ static int __maybe_unused regulator_haptic_resume(struct device *dev)
 
        haptic->suspended = false;
 
-       magnitude = ACCESS_ONCE(haptic->magnitude);
+       magnitude = READ_ONCE(haptic->magnitude);
        if (magnitude)
                regulator_haptic_set_voltage(haptic, magnitude);
 
index 6d6b092e2da901969b8e3a2cfe65f2d0f2651098..d6135900da649680e9e23cd924541f63a3423fa7 100644 (file)
@@ -1258,6 +1258,7 @@ static const struct acpi_device_id elan_acpi_id[] = {
        { "ELAN0605", 0 },
        { "ELAN0609", 0 },
        { "ELAN060B", 0 },
+       { "ELAN060C", 0 },
        { "ELAN0611", 0 },
        { "ELAN1000", 0 },
        { }
index 0f586780ceb4bee18a38428b889dba8d994ea4c7..1ae5c1ef3f5bbbc0c8cd0e4e35c24d37e493f703 100644 (file)
@@ -316,11 +316,9 @@ static int vmmouse_enable(struct psmouse *psmouse)
 /*
  * Array of supported hypervisors.
  */
-static const struct hypervisor_x86 *vmmouse_supported_hypervisors[] = {
-       &x86_hyper_vmware,
-#ifdef CONFIG_KVM_GUEST
-       &x86_hyper_kvm,
-#endif
+static enum x86_hypervisor_type vmmouse_supported_hypervisors[] = {
+       X86_HYPER_VMWARE,
+       X86_HYPER_KVM,
 };
 
 /**
@@ -331,7 +329,7 @@ static bool vmmouse_check_hypervisor(void)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(vmmouse_supported_hypervisors); i++)
-               if (vmmouse_supported_hypervisors[i] == x86_hyper)
+               if (vmmouse_supported_hypervisors[i] == x86_hyper_type)
                        return true;
 
        return false;
index 225025a0940cfe09bc2dcbae711b6bb7b2f9e412..b6ccf39c6a7bb46bc67bf086952a799e27f4f930 100644 (file)
@@ -312,7 +312,7 @@ static int rmi_smb_probe(struct i2c_client *client,
        rmi_smb->xport.dev = &client->dev;
        rmi_smb->xport.pdata = *pdata;
        rmi_smb->xport.pdata.irq = client->irq;
-       rmi_smb->xport.proto_name = "smb2";
+       rmi_smb->xport.proto_name = "smb";
        rmi_smb->xport.ops = &rmi_smb_ops;
 
        smbus_version = rmi_smb_get_version(rmi_smb);
@@ -322,7 +322,7 @@ static int rmi_smb_probe(struct i2c_client *client,
        rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
                smbus_version);
 
-       if (smbus_version != 2) {
+       if (smbus_version != 2 && smbus_version != 3) {
                dev_err(&client->dev, "Unrecognized SMB version %d\n",
                                smbus_version);
                return -ENODEV;
index 3b3db8c868e01f81878563a1ae8a74cda41cf372..d3265b6b58b8ebc06b69e8a40983d5303b938054 100644 (file)
@@ -145,7 +145,7 @@ static void touch_timer_fire(unsigned long data)
        }
 }
 
-static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0);
+static DEFINE_TIMER(touch_timer, touch_timer_fire);
 
 /**
  * stylus_irq - touchscreen stylus event interrupt
index 88ea5e1b72aedd023c0fdf817cbeee906fdda292..abf27578beb149e71a8a9f4ab4027f108c6b2b98 100644 (file)
@@ -531,6 +531,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
 
        input_set_drvdata(input_dev, ts);
 
+       __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
        input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
 
        input_set_abs_params(input_dev, ABS_X,
index 8e8874d23717ab5120c87f180146562be3e03ef6..9c848e36f20904b0397bbb643906fbc3474c70c2 100644 (file)
@@ -4173,16 +4173,26 @@ static void irq_remapping_free(struct irq_domain *domain, unsigned int virq,
        irq_domain_free_irqs_common(domain, virq, nr_irqs);
 }
 
-static void irq_remapping_activate(struct irq_domain *domain,
-                                  struct irq_data *irq_data)
+static void amd_ir_update_irte(struct irq_data *irqd, struct amd_iommu *iommu,
+                              struct amd_ir_data *ir_data,
+                              struct irq_2_irte *irte_info,
+                              struct irq_cfg *cfg);
+
+static int irq_remapping_activate(struct irq_domain *domain,
+                                 struct irq_data *irq_data, bool early)
 {
        struct amd_ir_data *data = irq_data->chip_data;
        struct irq_2_irte *irte_info = &data->irq_2_irte;
        struct amd_iommu *iommu = amd_iommu_rlookup_table[irte_info->devid];
+       struct irq_cfg *cfg = irqd_cfg(irq_data);
 
-       if (iommu)
-               iommu->irte_ops->activate(data->entry, irte_info->devid,
-                                         irte_info->index);
+       if (!iommu)
+               return 0;
+
+       iommu->irte_ops->activate(data->entry, irte_info->devid,
+                                 irte_info->index);
+       amd_ir_update_irte(irq_data, iommu, data, irte_info, cfg);
+       return 0;
 }
 
 static void irq_remapping_deactivate(struct irq_domain *domain,
@@ -4269,6 +4279,22 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
        return modify_irte_ga(irte_info->devid, irte_info->index, irte, ir_data);
 }
 
+
+static void amd_ir_update_irte(struct irq_data *irqd, struct amd_iommu *iommu,
+                              struct amd_ir_data *ir_data,
+                              struct irq_2_irte *irte_info,
+                              struct irq_cfg *cfg)
+{
+
+       /*
+        * Atomically updates the IRTE with the new destination, vector
+        * and flushes the interrupt entry cache.
+        */
+       iommu->irte_ops->set_affinity(ir_data->entry, irte_info->devid,
+                                     irte_info->index, cfg->vector,
+                                     cfg->dest_apicid);
+}
+
 static int amd_ir_set_affinity(struct irq_data *data,
                               const struct cpumask *mask, bool force)
 {
@@ -4286,13 +4312,7 @@ static int amd_ir_set_affinity(struct irq_data *data,
        if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
                return ret;
 
-       /*
-        * Atomically updates the IRTE with the new destination, vector
-        * and flushes the interrupt entry cache.
-        */
-       iommu->irte_ops->set_affinity(ir_data->entry, irte_info->devid,
-                           irte_info->index, cfg->vector, cfg->dest_apicid);
-
+       amd_ir_update_irte(data, iommu, ir_data, irte_info, cfg);
        /*
         * After this point, all the interrupts will start arriving
         * at the new destination. So, time to cleanup the previous
index 25842b566c39c1497d1cecd91b6af8a079492185..76a193c7fcfc69b012d3e6e1f1dd246ab8d5acc8 100644 (file)
@@ -1122,6 +1122,24 @@ struct irq_remap_ops intel_irq_remap_ops = {
        .get_irq_domain         = intel_get_irq_domain,
 };
 
+static void intel_ir_reconfigure_irte(struct irq_data *irqd, bool force)
+{
+       struct intel_ir_data *ir_data = irqd->chip_data;
+       struct irte *irte = &ir_data->irte_entry;
+       struct irq_cfg *cfg = irqd_cfg(irqd);
+
+       /*
+        * Atomically updates the IRTE with the new destination, vector
+        * and flushes the interrupt entry cache.
+        */
+       irte->vector = cfg->vector;
+       irte->dest_id = IRTE_DEST(cfg->dest_apicid);
+
+       /* Update the hardware only if the interrupt is in remapped mode. */
+       if (!force || ir_data->irq_2_iommu.mode == IRQ_REMAPPING)
+               modify_irte(&ir_data->irq_2_iommu, irte);
+}
+
 /*
  * Migrate the IO-APIC irq in the presence of intr-remapping.
  *
@@ -1140,27 +1158,15 @@ static int
 intel_ir_set_affinity(struct irq_data *data, const struct cpumask *mask,
                      bool force)
 {
-       struct intel_ir_data *ir_data = data->chip_data;
-       struct irte *irte = &ir_data->irte_entry;
-       struct irq_cfg *cfg = irqd_cfg(data);
        struct irq_data *parent = data->parent_data;
+       struct irq_cfg *cfg = irqd_cfg(data);
        int ret;
 
        ret = parent->chip->irq_set_affinity(parent, mask, force);
        if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
                return ret;
 
-       /*
-        * Atomically updates the IRTE with the new destination, vector
-        * and flushes the interrupt entry cache.
-        */
-       irte->vector = cfg->vector;
-       irte->dest_id = IRTE_DEST(cfg->dest_apicid);
-
-       /* Update the hardware only if the interrupt is in remapped mode. */
-       if (ir_data->irq_2_iommu.mode == IRQ_REMAPPING)
-               modify_irte(&ir_data->irq_2_iommu, irte);
-
+       intel_ir_reconfigure_irte(data, false);
        /*
         * After this point, all the interrupts will start arriving
         * at the new destination. So, time to cleanup the previous
@@ -1390,12 +1396,11 @@ static void intel_irq_remapping_free(struct irq_domain *domain,
        irq_domain_free_irqs_common(domain, virq, nr_irqs);
 }
 
-static void intel_irq_remapping_activate(struct irq_domain *domain,
-                                        struct irq_data *irq_data)
+static int intel_irq_remapping_activate(struct irq_domain *domain,
+                                       struct irq_data *irq_data, bool early)
 {
-       struct intel_ir_data *data = irq_data->chip_data;
-
-       modify_irte(&data->irq_2_iommu, &data->irte_entry);
+       intel_ir_reconfigure_irte(irq_data, true);
+       return 0;
 }
 
 static void intel_irq_remapping_deactivate(struct irq_domain *domain,
index 9d8a1dd2e2c25a8f3bca727f795a8b1fc7de858d..53380bd72ea4068ec394a60e371b093727a6e543 100644 (file)
@@ -1,3 +1,5 @@
+menu "IRQ chip support"
+
 config IRQCHIP
        def_bool y
        depends on OF_IRQ
@@ -151,6 +153,9 @@ config CLPS711X_IRQCHIP
        select SPARSE_IRQ
        default y
 
+config OMPIC
+       bool
+
 config OR1K_PIC
        bool
        select IRQ_DOMAIN
@@ -304,6 +309,7 @@ config EZNPS_GIC
 config STM32_EXTI
        bool
        select IRQ_DOMAIN
+       select GENERIC_IRQ_CHIP
 
 config QCOM_IRQ_COMBINER
        bool "QCOM IRQ combiner support"
@@ -321,3 +327,13 @@ config IRQ_UNIPHIER_AIDET
        select IRQ_DOMAIN_HIERARCHY
        help
          Support for the UniPhier AIDET (ARM Interrupt Detector).
+
+config MESON_IRQ_GPIO
+       bool "Meson GPIO Interrupt Multiplexer"
+       depends on ARCH_MESON
+       select IRQ_DOMAIN
+       select IRQ_DOMAIN_HIERARCHY
+       help
+         Support Meson SoC Family GPIO Interrupt Multiplexer
+
+endmenu
index b842dfdc903f1f9649a27a907157a049e1cde4a2..dae7282bfdef31fc0ce7475854cdff995dbcae93 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_DW_APB_ICTL)             += irq-dw-apb-ictl.o
 obj-$(CONFIG_METAG)                    += irq-metag-ext.o
 obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)   += irq-metag.o
 obj-$(CONFIG_CLPS711X_IRQCHIP)         += irq-clps711x.o
+obj-$(CONFIG_OMPIC)                    += irq-ompic.o
 obj-$(CONFIG_OR1K_PIC)                 += irq-or1k-pic.o
 obj-$(CONFIG_ORION_IRQCHIP)            += irq-orion.o
 obj-$(CONFIG_OMAP_IRQCHIP)             += irq-omap-intc.o
@@ -80,3 +81,5 @@ obj-$(CONFIG_ARCH_ASPEED)             += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
 obj-$(CONFIG_STM32_EXTI)               += irq-stm32-exti.o
 obj-$(CONFIG_QCOM_IRQ_COMBINER)                += qcom-irq-combiner.o
 obj-$(CONFIG_IRQ_UNIPHIER_AIDET)       += irq-uniphier-aidet.o
+obj-$(CONFIG_ARCH_SYNQUACER)           += irq-sni-exiu.o
+obj-$(CONFIG_MESON_IRQ_GPIO)           += irq-meson-gpio.o
index 815b88dd18f25ad0ff6b818c6cd493d47e556e6c..f20200af0992721d9ae7437ec75066f313545415 100644 (file)
@@ -76,8 +76,8 @@ static int __init aspeed_i2c_ic_of_init(struct device_node *node,
                return -ENOMEM;
 
        i2c_ic->base = of_iomap(node, 0);
-       if (IS_ERR(i2c_ic->base)) {
-               ret = PTR_ERR(i2c_ic->base);
+       if (!i2c_ic->base) {
+               ret = -ENOMEM;
                goto err_free_ic;
        }
 
index b009b916a2923504414aafe6961b404614770da5..691d20eb0bec1137c403c6d91097c67a1d906fac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Generic Broadcom Set Top Box Level 2 Interrupt controller driver
  *
- * Copyright (C) 2014 Broadcom Corporation
+ * Copyright (C) 2014-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <linux/irqchip.h>
 #include <linux/irqchip/chained_irq.h>
 
-/* Register offsets in the L2 interrupt controller */
-#define CPU_STATUS     0x00
-#define CPU_SET                0x04
-#define CPU_CLEAR      0x08
-#define CPU_MASK_STATUS        0x0c
-#define CPU_MASK_SET   0x10
-#define CPU_MASK_CLEAR 0x14
+struct brcmstb_intc_init_params {
+       irq_flow_handler_t handler;
+       int cpu_status;
+       int cpu_clear;
+       int cpu_mask_status;
+       int cpu_mask_set;
+       int cpu_mask_clear;
+};
+
+/* Register offsets in the L2 latched interrupt controller */
+static const struct brcmstb_intc_init_params l2_edge_intc_init = {
+       .handler                = handle_edge_irq,
+       .cpu_status             = 0x00,
+       .cpu_clear              = 0x08,
+       .cpu_mask_status        = 0x0c,
+       .cpu_mask_set           = 0x10,
+       .cpu_mask_clear         = 0x14
+};
+
+/* Register offsets in the L2 level interrupt controller */
+static const struct brcmstb_intc_init_params l2_lvl_intc_init = {
+       .handler                = handle_level_irq,
+       .cpu_status             = 0x00,
+       .cpu_clear              = -1, /* Register not present */
+       .cpu_mask_status        = 0x04,
+       .cpu_mask_set           = 0x08,
+       .cpu_mask_clear         = 0x0C
+};
 
 /* L2 intc private data structure */
 struct brcmstb_l2_intc_data {
-       int parent_irq;
-       void __iomem *base;
        struct irq_domain *domain;
+       struct irq_chip_generic *gc;
+       int status_offset;
+       int mask_offset;
        bool can_wake;
        u32 saved_mask; /* for suspend/resume */
 };
 
+/**
+ * brcmstb_l2_mask_and_ack - Mask and ack pending interrupt
+ * @d: irq_data
+ *
+ * Chip has separate enable/disable registers instead of a single mask
+ * register and pending interrupt is acknowledged by setting a bit.
+ *
+ * Note: This function is generic and could easily be added to the
+ * generic irqchip implementation if there ever becomes a will to do so.
+ * Perhaps with a name like irq_gc_mask_disable_and_ack_set().
+ *
+ * e.g.: https://patchwork.kernel.org/patch/9831047/
+ */
+static void brcmstb_l2_mask_and_ack(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = d->mask;
+
+       irq_gc_lock(gc);
+       irq_reg_writel(gc, mask, ct->regs.disable);
+       *ct->mask_cache &= ~mask;
+       irq_reg_writel(gc, mask, ct->regs.ack);
+       irq_gc_unlock(gc);
+}
+
 static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc)
 {
        struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc);
-       struct irq_chip_generic *gc = irq_get_domain_generic_chip(b->domain, 0);
        struct irq_chip *chip = irq_desc_get_chip(desc);
        unsigned int irq;
        u32 status;
 
        chained_irq_enter(chip, desc);
 
-       status = irq_reg_readl(gc, CPU_STATUS) &
-               ~(irq_reg_readl(gc, CPU_MASK_STATUS));
+       status = irq_reg_readl(b->gc, b->status_offset) &
+               ~(irq_reg_readl(b->gc, b->mask_offset));
 
        if (status == 0) {
                raw_spin_lock(&desc->lock);
@@ -70,10 +117,8 @@ static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc)
 
        do {
                irq = ffs(status) - 1;
-               /* ack at our level */
-               irq_reg_writel(gc, 1 << irq, CPU_CLEAR);
                status &= ~(1 << irq);
-               generic_handle_irq(irq_find_mapping(b->domain, irq));
+               generic_handle_irq(irq_linear_revmap(b->domain, irq));
        } while (status);
 out:
        chained_irq_exit(chip, desc);
@@ -82,16 +127,17 @@ out:
 static void brcmstb_l2_intc_suspend(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
        struct brcmstb_l2_intc_data *b = gc->private;
 
        irq_gc_lock(gc);
        /* Save the current mask */
-       b->saved_mask = irq_reg_readl(gc, CPU_MASK_STATUS);
+       b->saved_mask = irq_reg_readl(gc, ct->regs.mask);
 
        if (b->can_wake) {
                /* Program the wakeup mask */
-               irq_reg_writel(gc, ~gc->wake_active, CPU_MASK_SET);
-               irq_reg_writel(gc, gc->wake_active, CPU_MASK_CLEAR);
+               irq_reg_writel(gc, ~gc->wake_active, ct->regs.disable);
+               irq_reg_writel(gc, gc->wake_active, ct->regs.enable);
        }
        irq_gc_unlock(gc);
 }
@@ -99,49 +145,56 @@ static void brcmstb_l2_intc_suspend(struct irq_data *d)
 static void brcmstb_l2_intc_resume(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
        struct brcmstb_l2_intc_data *b = gc->private;
 
        irq_gc_lock(gc);
-       /* Clear unmasked non-wakeup interrupts */
-       irq_reg_writel(gc, ~b->saved_mask & ~gc->wake_active, CPU_CLEAR);
+       if (ct->chip.irq_ack) {
+               /* Clear unmasked non-wakeup interrupts */
+               irq_reg_writel(gc, ~b->saved_mask & ~gc->wake_active,
+                               ct->regs.ack);
+       }
 
        /* Restore the saved mask */
-       irq_reg_writel(gc, b->saved_mask, CPU_MASK_SET);
-       irq_reg_writel(gc, ~b->saved_mask, CPU_MASK_CLEAR);
+       irq_reg_writel(gc, b->saved_mask, ct->regs.disable);
+       irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable);
        irq_gc_unlock(gc);
 }
 
 static int __init brcmstb_l2_intc_of_init(struct device_node *np,
-                                         struct device_node *parent)
+                                         struct device_node *parent,
+                                         const struct brcmstb_intc_init_params
+                                         *init_params)
 {
        unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
        struct brcmstb_l2_intc_data *data;
-       struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
        int ret;
        unsigned int flags;
+       int parent_irq;
+       void __iomem *base;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       data->base = of_iomap(np, 0);
-       if (!data->base) {
+       base = of_iomap(np, 0);
+       if (!base) {
                pr_err("failed to remap intc L2 registers\n");
                ret = -ENOMEM;
                goto out_free;
        }
 
        /* Disable all interrupts by default */
-       writel(0xffffffff, data->base + CPU_MASK_SET);
+       writel(0xffffffff, base + init_params->cpu_mask_set);
 
        /* Wakeup interrupts may be retained from S5 (cold boot) */
        data->can_wake = of_property_read_bool(np, "brcm,irq-can-wake");
-       if (!data->can_wake)
-               writel(0xffffffff, data->base + CPU_CLEAR);
+       if (!data->can_wake && (init_params->cpu_clear >= 0))
+               writel(0xffffffff, base + init_params->cpu_clear);
 
-       data->parent_irq = irq_of_parse_and_map(np, 0);
-       if (!data->parent_irq) {
+       parent_irq = irq_of_parse_and_map(np, 0);
+       if (!parent_irq) {
                pr_err("failed to find parent interrupt\n");
                ret = -EINVAL;
                goto out_unmap;
@@ -163,29 +216,39 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np,
 
        /* Allocate a single Generic IRQ chip for this node */
        ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
-                               np->full_name, handle_edge_irq, clr, 0, flags);
+                       np->full_name, init_params->handler, clr, 0, flags);
        if (ret) {
                pr_err("failed to allocate generic irq chip\n");
                goto out_free_domain;
        }
 
        /* Set the IRQ chaining logic */
-       irq_set_chained_handler_and_data(data->parent_irq,
+       irq_set_chained_handler_and_data(parent_irq,
                                         brcmstb_l2_intc_irq_handle, data);
 
-       gc = irq_get_domain_generic_chip(data->domain, 0);
-       gc->reg_base = data->base;
-       gc->private = data;
-       ct = gc->chip_types;
-
-       ct->chip.irq_ack = irq_gc_ack_set_bit;
-       ct->regs.ack = CPU_CLEAR;
+       data->gc = irq_get_domain_generic_chip(data->domain, 0);
+       data->gc->reg_base = base;
+       data->gc->private = data;
+       data->status_offset = init_params->cpu_status;
+       data->mask_offset = init_params->cpu_mask_status;
+
+       ct = data->gc->chip_types;
+
+       if (init_params->cpu_clear >= 0) {
+               ct->regs.ack = init_params->cpu_clear;
+               ct->chip.irq_ack = irq_gc_ack_set_bit;
+               ct->chip.irq_mask_ack = brcmstb_l2_mask_and_ack;
+       } else {
+               /* No Ack - but still slightly more efficient to define this */
+               ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
+       }
 
        ct->chip.irq_mask = irq_gc_mask_disable_reg;
-       ct->regs.disable = CPU_MASK_SET;
+       ct->regs.disable = init_params->cpu_mask_set;
+       ct->regs.mask = init_params->cpu_mask_status;
 
        ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
-       ct->regs.enable = CPU_MASK_CLEAR;
+       ct->regs.enable = init_params->cpu_mask_clear;
 
        ct->chip.irq_suspend = brcmstb_l2_intc_suspend;
        ct->chip.irq_resume = brcmstb_l2_intc_resume;
@@ -195,21 +258,35 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np,
                /* This IRQ chip can wake the system, set all child interrupts
                 * in wake_enabled mask
                 */
-               gc->wake_enabled = 0xffffffff;
+               data->gc->wake_enabled = 0xffffffff;
                ct->chip.irq_set_wake = irq_gc_set_wake;
        }
 
        pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n",
-                       data->base, data->parent_irq);
+                       base, parent_irq);
 
        return 0;
 
 out_free_domain:
        irq_domain_remove(data->domain);
 out_unmap:
-       iounmap(data->base);
+       iounmap(base);
 out_free:
        kfree(data);
        return ret;
 }
-IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,l2-intc", brcmstb_l2_intc_of_init);
+
+int __init brcmstb_l2_edge_intc_of_init(struct device_node *np,
+       struct device_node *parent)
+{
+       return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init);
+}
+IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,l2-intc", brcmstb_l2_edge_intc_of_init);
+
+int __init brcmstb_l2_lvl_intc_of_init(struct device_node *np,
+       struct device_node *parent)
+{
+       return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init);
+}
+IRQCHIP_DECLARE(bcm7271_l2_intc, "brcm,bcm7271-l2-intc",
+       brcmstb_l2_lvl_intc_of_init);
index 9ae71804b5dd67bf27322f88b7066f9e646fbdb5..30017df5b54c8c440be595579703d2f52fbceac2 100644 (file)
@@ -40,8 +40,9 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
        for (; quirks->desc; quirks++) {
                if (quirks->iidr != (quirks->mask & iidr))
                        continue;
-               quirks->init(data);
-               pr_info("GIC: enabling workaround for %s\n", quirks->desc);
+               if (quirks->init(data))
+                       pr_info("GIC: enabling workaround for %s\n",
+                               quirks->desc);
        }
 }
 
index 205e5fddf6da6e870bd90174c486c9a8d3440855..3919cd7c5285d3490290b7e271c5e283cff07d55 100644 (file)
@@ -23,7 +23,7 @@
 
 struct gic_quirk {
        const char *desc;
-       void (*init)(void *data);
+       bool (*init)(void *data);
        u32 iidr;
        u32 mask;
 };
index e88395605e32dc32960974a4e8707a30037b107b..4039e64cd34211db8fac8ebc2f993c5e081e9c83 100644 (file)
@@ -83,6 +83,8 @@ struct its_baser {
        u32             psz;
 };
 
+struct its_device;
+
 /*
  * The ITS structure - contains most of the infrastructure, with the
  * top-level MSI domain, the command queue, the collections, and the
@@ -97,12 +99,18 @@ struct its_node {
        struct its_cmd_block    *cmd_write;
        struct its_baser        tables[GITS_BASER_NR_REGS];
        struct its_collection   *collections;
+       struct fwnode_handle    *fwnode_handle;
+       u64                     (*get_msi_base)(struct its_device *its_dev);
        struct list_head        its_device_list;
        u64                     flags;
+       unsigned long           list_nr;
        u32                     ite_size;
        u32                     device_ids;
        int                     numa_node;
+       unsigned int            msi_domain_flags;
+       u32                     pre_its_base; /* for Socionext Synquacer */
        bool                    is_v4;
+       int                     vlpi_redist_offset;
 };
 
 #define ITS_ITT_ALIGN          SZ_256
@@ -152,12 +160,6 @@ static DEFINE_SPINLOCK(its_lock);
 static struct rdists *gic_rdists;
 static struct irq_domain *its_parent;
 
-/*
- * We have a maximum number of 16 ITSs in the whole system if we're
- * using the ITSList mechanism
- */
-#define ITS_LIST_MAX           16
-
 static unsigned long its_list_map;
 static u16 vmovp_seq_num;
 static DEFINE_RAW_SPINLOCK(vmovp_lock);
@@ -272,10 +274,12 @@ struct its_cmd_block {
 #define ITS_CMD_QUEUE_SZ               SZ_64K
 #define ITS_CMD_QUEUE_NR_ENTRIES       (ITS_CMD_QUEUE_SZ / sizeof(struct its_cmd_block))
 
-typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
+typedef struct its_collection *(*its_cmd_builder_t)(struct its_node *,
+                                                   struct its_cmd_block *,
                                                    struct its_cmd_desc *);
 
-typedef struct its_vpe *(*its_cmd_vbuilder_t)(struct its_cmd_block *,
+typedef struct its_vpe *(*its_cmd_vbuilder_t)(struct its_node *,
+                                             struct its_cmd_block *,
                                              struct its_cmd_desc *);
 
 static void its_mask_encode(u64 *raw_cmd, u64 val, int h, int l)
@@ -379,7 +383,8 @@ static inline void its_fixup_cmd(struct its_cmd_block *cmd)
        cmd->raw_cmd[3] = cpu_to_le64(cmd->raw_cmd[3]);
 }
 
-static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_mapd_cmd(struct its_node *its,
+                                                struct its_cmd_block *cmd,
                                                 struct its_cmd_desc *desc)
 {
        unsigned long itt_addr;
@@ -399,7 +404,8 @@ static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
        return NULL;
 }
 
-static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_mapc_cmd(struct its_node *its,
+                                                struct its_cmd_block *cmd,
                                                 struct its_cmd_desc *desc)
 {
        its_encode_cmd(cmd, GITS_CMD_MAPC);
@@ -412,7 +418,8 @@ static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
        return desc->its_mapc_cmd.col;
 }
 
-static struct its_collection *its_build_mapti_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_mapti_cmd(struct its_node *its,
+                                                 struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
        struct its_collection *col;
@@ -431,7 +438,8 @@ static struct its_collection *its_build_mapti_cmd(struct its_cmd_block *cmd,
        return col;
 }
 
-static struct its_collection *its_build_movi_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_movi_cmd(struct its_node *its,
+                                                struct its_cmd_block *cmd,
                                                 struct its_cmd_desc *desc)
 {
        struct its_collection *col;
@@ -449,7 +457,8 @@ static struct its_collection *its_build_movi_cmd(struct its_cmd_block *cmd,
        return col;
 }
 
-static struct its_collection *its_build_discard_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_discard_cmd(struct its_node *its,
+                                                   struct its_cmd_block *cmd,
                                                    struct its_cmd_desc *desc)
 {
        struct its_collection *col;
@@ -466,7 +475,8 @@ static struct its_collection *its_build_discard_cmd(struct its_cmd_block *cmd,
        return col;
 }
 
-static struct its_collection *its_build_inv_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_inv_cmd(struct its_node *its,
+                                               struct its_cmd_block *cmd,
                                                struct its_cmd_desc *desc)
 {
        struct its_collection *col;
@@ -483,7 +493,8 @@ static struct its_collection *its_build_inv_cmd(struct its_cmd_block *cmd,
        return col;
 }
 
-static struct its_collection *its_build_int_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_int_cmd(struct its_node *its,
+                                               struct its_cmd_block *cmd,
                                                struct its_cmd_desc *desc)
 {
        struct its_collection *col;
@@ -500,7 +511,8 @@ static struct its_collection *its_build_int_cmd(struct its_cmd_block *cmd,
        return col;
 }
 
-static struct its_collection *its_build_clear_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_clear_cmd(struct its_node *its,
+                                                 struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
        struct its_collection *col;
@@ -517,7 +529,8 @@ static struct its_collection *its_build_clear_cmd(struct its_cmd_block *cmd,
        return col;
 }
 
-static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
+static struct its_collection *its_build_invall_cmd(struct its_node *its,
+                                                  struct its_cmd_block *cmd,
                                                   struct its_cmd_desc *desc)
 {
        its_encode_cmd(cmd, GITS_CMD_INVALL);
@@ -528,7 +541,8 @@ static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
        return NULL;
 }
 
-static struct its_vpe *its_build_vinvall_cmd(struct its_cmd_block *cmd,
+static struct its_vpe *its_build_vinvall_cmd(struct its_node *its,
+                                            struct its_cmd_block *cmd,
                                             struct its_cmd_desc *desc)
 {
        its_encode_cmd(cmd, GITS_CMD_VINVALL);
@@ -539,17 +553,20 @@ static struct its_vpe *its_build_vinvall_cmd(struct its_cmd_block *cmd,
        return desc->its_vinvall_cmd.vpe;
 }
 
-static struct its_vpe *its_build_vmapp_cmd(struct its_cmd_block *cmd,
+static struct its_vpe *its_build_vmapp_cmd(struct its_node *its,
+                                          struct its_cmd_block *cmd,
                                           struct its_cmd_desc *desc)
 {
        unsigned long vpt_addr;
+       u64 target;
 
        vpt_addr = virt_to_phys(page_address(desc->its_vmapp_cmd.vpe->vpt_page));
+       target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset;
 
        its_encode_cmd(cmd, GITS_CMD_VMAPP);
        its_encode_vpeid(cmd, desc->its_vmapp_cmd.vpe->vpe_id);
        its_encode_valid(cmd, desc->its_vmapp_cmd.valid);
-       its_encode_target(cmd, desc->its_vmapp_cmd.col->target_address);
+       its_encode_target(cmd, target);
        its_encode_vpt_addr(cmd, vpt_addr);
        its_encode_vpt_size(cmd, LPI_NRBITS - 1);
 
@@ -558,7 +575,8 @@ static struct its_vpe *its_build_vmapp_cmd(struct its_cmd_block *cmd,
        return desc->its_vmapp_cmd.vpe;
 }
 
-static struct its_vpe *its_build_vmapti_cmd(struct its_cmd_block *cmd,
+static struct its_vpe *its_build_vmapti_cmd(struct its_node *its,
+                                           struct its_cmd_block *cmd,
                                            struct its_cmd_desc *desc)
 {
        u32 db;
@@ -580,7 +598,8 @@ static struct its_vpe *its_build_vmapti_cmd(struct its_cmd_block *cmd,
        return desc->its_vmapti_cmd.vpe;
 }
 
-static struct its_vpe *its_build_vmovi_cmd(struct its_cmd_block *cmd,
+static struct its_vpe *its_build_vmovi_cmd(struct its_node *its,
+                                          struct its_cmd_block *cmd,
                                           struct its_cmd_desc *desc)
 {
        u32 db;
@@ -602,14 +621,18 @@ static struct its_vpe *its_build_vmovi_cmd(struct its_cmd_block *cmd,
        return desc->its_vmovi_cmd.vpe;
 }
 
-static struct its_vpe *its_build_vmovp_cmd(struct its_cmd_block *cmd,
+static struct its_vpe *its_build_vmovp_cmd(struct its_node *its,
+                                          struct its_cmd_block *cmd,
                                           struct its_cmd_desc *desc)
 {
+       u64 target;
+
+       target = desc->its_vmovp_cmd.col->target_address + its->vlpi_redist_offset;
        its_encode_cmd(cmd, GITS_CMD_VMOVP);
        its_encode_seq_num(cmd, desc->its_vmovp_cmd.seq_num);
        its_encode_its_list(cmd, desc->its_vmovp_cmd.its_list);
        its_encode_vpeid(cmd, desc->its_vmovp_cmd.vpe->vpe_id);
-       its_encode_target(cmd, desc->its_vmovp_cmd.col->target_address);
+       its_encode_target(cmd, target);
 
        its_fixup_cmd(cmd);
 
@@ -688,9 +711,9 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
                dsb(ishst);
 }
 
-static void its_wait_for_range_completion(struct its_node *its,
-                                         struct its_cmd_block *from,
-                                         struct its_cmd_block *to)
+static int its_wait_for_range_completion(struct its_node *its,
+                                        struct its_cmd_block *from,
+                                        struct its_cmd_block *to)
 {
        u64 rd_idx, from_idx, to_idx;
        u32 count = 1000000;    /* 1s! */
@@ -711,12 +734,15 @@ static void its_wait_for_range_completion(struct its_node *its,
 
                count--;
                if (!count) {
-                       pr_err_ratelimited("ITS queue timeout\n");
-                       return;
+                       pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n",
+                                          from_idx, to_idx, rd_idx);
+                       return -1;
                }
                cpu_relax();
                udelay(1);
        }
+
+       return 0;
 }
 
 /* Warning, macro hell follows */
@@ -736,7 +762,7 @@ void name(struct its_node *its,                                             \
                raw_spin_unlock_irqrestore(&its->lock, flags);          \
                return;                                                 \
        }                                                               \
-       sync_obj = builder(cmd, desc);                                  \
+       sync_obj = builder(its, cmd, desc);                             \
        its_flush_cmd(its, cmd);                                        \
                                                                        \
        if (sync_obj) {                                                 \
@@ -744,7 +770,7 @@ void name(struct its_node *its,                                             \
                if (!sync_cmd)                                          \
                        goto post;                                      \
                                                                        \
-               buildfn(sync_cmd, sync_obj);                            \
+               buildfn(its, sync_cmd, sync_obj);                       \
                its_flush_cmd(its, sync_cmd);                           \
        }                                                               \
                                                                        \
@@ -752,10 +778,12 @@ post:                                                                     \
        next_cmd = its_post_commands(its);                              \
        raw_spin_unlock_irqrestore(&its->lock, flags);                  \
                                                                        \
-       its_wait_for_range_completion(its, cmd, next_cmd);              \
+       if (its_wait_for_range_completion(its, cmd, next_cmd))          \
+               pr_err_ratelimited("ITS cmd %ps failed\n", builder);    \
 }
 
-static void its_build_sync_cmd(struct its_cmd_block *sync_cmd,
+static void its_build_sync_cmd(struct its_node *its,
+                              struct its_cmd_block *sync_cmd,
                               struct its_collection *sync_col)
 {
        its_encode_cmd(sync_cmd, GITS_CMD_SYNC);
@@ -767,7 +795,8 @@ static void its_build_sync_cmd(struct its_cmd_block *sync_cmd,
 static BUILD_SINGLE_CMD_FUNC(its_send_single_command, its_cmd_builder_t,
                             struct its_collection, its_build_sync_cmd)
 
-static void its_build_vsync_cmd(struct its_cmd_block *sync_cmd,
+static void its_build_vsync_cmd(struct its_node *its,
+                               struct its_cmd_block *sync_cmd,
                                struct its_vpe *sync_vpe)
 {
        its_encode_cmd(sync_cmd, GITS_CMD_VSYNC);
@@ -899,21 +928,16 @@ static void its_send_vmovi(struct its_device *dev, u32 id)
        its_send_single_vcommand(dev->its, its_build_vmovi_cmd, &desc);
 }
 
-static void its_send_vmapp(struct its_vpe *vpe, bool valid)
+static void its_send_vmapp(struct its_node *its,
+                          struct its_vpe *vpe, bool valid)
 {
        struct its_cmd_desc desc;
-       struct its_node *its;
 
        desc.its_vmapp_cmd.vpe = vpe;
        desc.its_vmapp_cmd.valid = valid;
+       desc.its_vmapp_cmd.col = &its->collections[vpe->col_idx];
 
-       list_for_each_entry(its, &its_nodes, entry) {
-               if (!its->is_v4)
-                       continue;
-
-               desc.its_vmapp_cmd.col = &its->collections[vpe->col_idx];
-               its_send_single_vcommand(its, its_build_vmapp_cmd, &desc);
-       }
+       its_send_single_vcommand(its, its_build_vmapp_cmd, &desc);
 }
 
 static void its_send_vmovp(struct its_vpe *vpe)
@@ -951,6 +975,9 @@ static void its_send_vmovp(struct its_vpe *vpe)
                if (!its->is_v4)
                        continue;
 
+               if (!vpe->its_vm->vlpi_count[its->list_nr])
+                       continue;
+
                desc.its_vmovp_cmd.col = &its->collections[col_id];
                its_send_single_vcommand(its, its_build_vmovp_cmd, &desc);
        }
@@ -958,18 +985,12 @@ static void its_send_vmovp(struct its_vpe *vpe)
        raw_spin_unlock_irqrestore(&vmovp_lock, flags);
 }
 
-static void its_send_vinvall(struct its_vpe *vpe)
+static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)
 {
        struct its_cmd_desc desc;
-       struct its_node *its;
 
        desc.its_vinvall_cmd.vpe = vpe;
-
-       list_for_each_entry(its, &its_nodes, entry) {
-               if (!its->is_v4)
-                       continue;
-               its_send_single_vcommand(its, its_build_vinvall_cmd, &desc);
-       }
+       its_send_single_vcommand(its, its_build_vinvall_cmd, &desc);
 }
 
 /*
@@ -991,9 +1012,15 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
        if (irqd_is_forwarded_to_vcpu(d)) {
                struct its_device *its_dev = irq_data_get_irq_chip_data(d);
                u32 event = its_get_event_id(d);
+               struct its_vlpi_map *map;
 
                prop_page = its_dev->event_map.vm->vprop_page;
-               hwirq = its_dev->event_map.vlpi_maps[event].vintid;
+               map = &its_dev->event_map.vlpi_maps[event];
+               hwirq = map->vintid;
+
+               /* Remember the updated property */
+               map->properties &= ~clr;
+               map->properties |= set | LPI_PROP_GROUP1;
        } else {
                prop_page = gic_rdists->prop_page;
                hwirq = d->hwirq;
@@ -1099,6 +1126,13 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        return IRQ_SET_MASK_OK_DONE;
 }
 
+static u64 its_irq_get_msi_base(struct its_device *its_dev)
+{
+       struct its_node *its = its_dev->its;
+
+       return its->phys_base + GITS_TRANSLATER;
+}
+
 static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
@@ -1106,7 +1140,7 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
        u64 addr;
 
        its = its_dev->its;
-       addr = its->phys_base + GITS_TRANSLATER;
+       addr = its->get_msi_base(its_dev);
 
        msg->address_lo         = lower_32_bits(addr);
        msg->address_hi         = upper_32_bits(addr);
@@ -1133,6 +1167,60 @@ static int its_irq_set_irqchip_state(struct irq_data *d,
        return 0;
 }
 
+static void its_map_vm(struct its_node *its, struct its_vm *vm)
+{
+       unsigned long flags;
+
+       /* Not using the ITS list? Everything is always mapped. */
+       if (!its_list_map)
+               return;
+
+       raw_spin_lock_irqsave(&vmovp_lock, flags);
+
+       /*
+        * If the VM wasn't mapped yet, iterate over the vpes and get
+        * them mapped now.
+        */
+       vm->vlpi_count[its->list_nr]++;
+
+       if (vm->vlpi_count[its->list_nr] == 1) {
+               int i;
+
+               for (i = 0; i < vm->nr_vpes; i++) {
+                       struct its_vpe *vpe = vm->vpes[i];
+                       struct irq_data *d = irq_get_irq_data(vpe->irq);
+
+                       /* Map the VPE to the first possible CPU */
+                       vpe->col_idx = cpumask_first(cpu_online_mask);
+                       its_send_vmapp(its, vpe, true);
+                       its_send_vinvall(its, vpe);
+                       irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx));
+               }
+       }
+
+       raw_spin_unlock_irqrestore(&vmovp_lock, flags);
+}
+
+static void its_unmap_vm(struct its_node *its, struct its_vm *vm)
+{
+       unsigned long flags;
+
+       /* Not using the ITS list? Everything is always mapped. */
+       if (!its_list_map)
+               return;
+
+       raw_spin_lock_irqsave(&vmovp_lock, flags);
+
+       if (!--vm->vlpi_count[its->list_nr]) {
+               int i;
+
+               for (i = 0; i < vm->nr_vpes; i++)
+                       its_send_vmapp(its, vm->vpes[i], false);
+       }
+
+       raw_spin_unlock_irqrestore(&vmovp_lock, flags);
+}
+
 static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
@@ -1168,12 +1256,23 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
                /* Already mapped, move it around */
                its_send_vmovi(its_dev, event);
        } else {
+               /* Ensure all the VPEs are mapped on this ITS */
+               its_map_vm(its_dev->its, info->map->vm);
+
+               /*
+                * Flag the interrupt as forwarded so that we can
+                * start poking the virtual property table.
+                */
+               irqd_set_forwarded_to_vcpu(d);
+
+               /* Write out the property to the prop table */
+               lpi_write_config(d, 0xff, info->map->properties);
+
                /* Drop the physical mapping */
                its_send_discard(its_dev, event);
 
                /* and install the virtual one */
                its_send_vmapti(its_dev, event);
-               irqd_set_forwarded_to_vcpu(d);
 
                /* Increment the number of VLPIs */
                its_dev->event_map.nr_vlpis++;
@@ -1229,6 +1328,9 @@ static int its_vlpi_unmap(struct irq_data *d)
                                    LPI_PROP_ENABLED |
                                    LPI_PROP_GROUP1));
 
+       /* Potentially unmap the VM from this ITS */
+       its_unmap_vm(its_dev->its, its_dev->event_map.vm);
+
        /*
         * Drop the refcount and make the device available again if
         * this was the last VLPI.
@@ -1669,23 +1771,14 @@ static void its_free_tables(struct its_node *its)
 
 static int its_alloc_tables(struct its_node *its)
 {
-       u64 typer = gic_read_typer(its->base + GITS_TYPER);
-       u32 ids = GITS_TYPER_DEVBITS(typer);
        u64 shr = GITS_BASER_InnerShareable;
        u64 cache = GITS_BASER_RaWaWb;
        u32 psz = SZ_64K;
        int err, i;
 
-       if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_22375) {
-               /*
-               * erratum 22375: only alloc 8MB table size
-               * erratum 24313: ignore memory access type
-               */
-               cache   = GITS_BASER_nCnB;
-               ids     = 0x14;                 /* 20 bits, 8MB */
-       }
-
-       its->device_ids = ids;
+       if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_22375)
+               /* erratum 24313: ignore memory access type */
+               cache = GITS_BASER_nCnB;
 
        for (i = 0; i < GITS_BASER_NR_REGS; i++) {
                struct its_baser *baser = its->tables + i;
@@ -2209,8 +2302,8 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
        return 0;
 }
 
-static void its_irq_domain_activate(struct irq_domain *domain,
-                                   struct irq_data *d)
+static int its_irq_domain_activate(struct irq_domain *domain,
+                                  struct irq_data *d, bool early)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
        u32 event = its_get_event_id(d);
@@ -2228,6 +2321,7 @@ static void its_irq_domain_activate(struct irq_domain *domain,
 
        /* Map the GIC IRQ and event to the device */
        its_send_mapti(its_dev, d->hwirq, event);
+       return 0;
 }
 
 static void its_irq_domain_deactivate(struct irq_domain *domain,
@@ -2394,6 +2488,8 @@ static int its_vpe_set_affinity(struct irq_data *d,
                its_vpe_db_proxy_move(vpe, from, cpu);
        }
 
+       irq_data_update_effective_affinity(d, cpumask_of(cpu));
+
        return IRQ_SET_MASK_OK_DONE;
 }
 
@@ -2461,6 +2557,26 @@ static void its_vpe_deschedule(struct its_vpe *vpe)
        }
 }
 
+static void its_vpe_invall(struct its_vpe *vpe)
+{
+       struct its_node *its;
+
+       list_for_each_entry(its, &its_nodes, entry) {
+               if (!its->is_v4)
+                       continue;
+
+               if (its_list_map && !vpe->its_vm->vlpi_count[its->list_nr])
+                       continue;
+
+               /*
+                * Sending a VINVALL to a single ITS is enough, as all
+                * we need is to reach the redistributors.
+                */
+               its_send_vinvall(its, vpe);
+               return;
+       }
+}
+
 static int its_vpe_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
 {
        struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
@@ -2476,7 +2592,7 @@ static int its_vpe_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
                return 0;
 
        case INVALL_VPE:
-               its_send_vinvall(vpe);
+               its_vpe_invall(vpe);
                return 0;
 
        default:
@@ -2701,23 +2817,51 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq
        return err;
 }
 
-static void its_vpe_irq_domain_activate(struct irq_domain *domain,
-                                       struct irq_data *d)
+static int its_vpe_irq_domain_activate(struct irq_domain *domain,
+                                      struct irq_data *d, bool early)
 {
        struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+       struct its_node *its;
+
+       /* If we use the list map, we issue VMAPP on demand... */
+       if (its_list_map)
+               return 0;
 
        /* Map the VPE to the first possible CPU */
        vpe->col_idx = cpumask_first(cpu_online_mask);
-       its_send_vmapp(vpe, true);
-       its_send_vinvall(vpe);
+
+       list_for_each_entry(its, &its_nodes, entry) {
+               if (!its->is_v4)
+                       continue;
+
+               its_send_vmapp(its, vpe, true);
+               its_send_vinvall(its, vpe);
+       }
+
+       irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx));
+
+       return 0;
 }
 
 static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,
                                          struct irq_data *d)
 {
        struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+       struct its_node *its;
+
+       /*
+        * If we use the list map, we unmap the VPE once no VLPIs are
+        * associated with the VM.
+        */
+       if (its_list_map)
+               return;
 
-       its_send_vmapp(vpe, false);
+       list_for_each_entry(its, &its_nodes, entry) {
+               if (!its->is_v4)
+                       continue;
+
+               its_send_vmapp(its, vpe, false);
+       }
 }
 
 static const struct irq_domain_ops its_vpe_domain_ops = {
@@ -2760,26 +2904,85 @@ static int its_force_quiescent(void __iomem *base)
        }
 }
 
-static void __maybe_unused its_enable_quirk_cavium_22375(void *data)
+static bool __maybe_unused its_enable_quirk_cavium_22375(void *data)
 {
        struct its_node *its = data;
 
+       /* erratum 22375: only alloc 8MB table size */
+       its->device_ids = 0x14;         /* 20 bits, 8MB */
        its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375;
+
+       return true;
 }
 
-static void __maybe_unused its_enable_quirk_cavium_23144(void *data)
+static bool __maybe_unused its_enable_quirk_cavium_23144(void *data)
 {
        struct its_node *its = data;
 
        its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_23144;
+
+       return true;
 }
 
-static void __maybe_unused its_enable_quirk_qdf2400_e0065(void *data)
+static bool __maybe_unused its_enable_quirk_qdf2400_e0065(void *data)
 {
        struct its_node *its = data;
 
        /* On QDF2400, the size of the ITE is 16Bytes */
        its->ite_size = 16;
+
+       return true;
+}
+
+static u64 its_irq_get_msi_base_pre_its(struct its_device *its_dev)
+{
+       struct its_node *its = its_dev->its;
+
+       /*
+        * The Socionext Synquacer SoC has a so-called 'pre-ITS',
+        * which maps 32-bit writes targeted at a separate window of
+        * size '4 << device_id_bits' onto writes to GITS_TRANSLATER
+        * with device ID taken from bits [device_id_bits + 1:2] of
+        * the window offset.
+        */
+       return its->pre_its_base + (its_dev->device_id << 2);
+}
+
+static bool __maybe_unused its_enable_quirk_socionext_synquacer(void *data)
+{
+       struct its_node *its = data;
+       u32 pre_its_window[2];
+       u32 ids;
+
+       if (!fwnode_property_read_u32_array(its->fwnode_handle,
+                                          "socionext,synquacer-pre-its",
+                                          pre_its_window,
+                                          ARRAY_SIZE(pre_its_window))) {
+
+               its->pre_its_base = pre_its_window[0];
+               its->get_msi_base = its_irq_get_msi_base_pre_its;
+
+               ids = ilog2(pre_its_window[1]) - 2;
+               if (its->device_ids > ids)
+                       its->device_ids = ids;
+
+               /* the pre-ITS breaks isolation, so disable MSI remapping */
+               its->msi_domain_flags &= ~IRQ_DOMAIN_FLAG_MSI_REMAP;
+               return true;
+       }
+       return false;
+}
+
+static bool __maybe_unused its_enable_quirk_hip07_161600802(void *data)
+{
+       struct its_node *its = data;
+
+       /*
+        * Hip07 insists on using the wrong address for the VLPI
+        * page. Trick it into doing the right thing...
+        */
+       its->vlpi_redist_offset = SZ_128K;
+       return true;
 }
 
 static const struct gic_quirk its_quirks[] = {
@@ -2806,6 +3009,27 @@ static const struct gic_quirk its_quirks[] = {
                .mask   = 0xffffffff,
                .init   = its_enable_quirk_qdf2400_e0065,
        },
+#endif
+#ifdef CONFIG_SOCIONEXT_SYNQUACER_PREITS
+       {
+               /*
+                * The Socionext Synquacer SoC incorporates ARM's own GIC-500
+                * implementation, but with a 'pre-ITS' added that requires
+                * special handling in software.
+                */
+               .desc   = "ITS: Socionext Synquacer pre-ITS",
+               .iidr   = 0x0001143b,
+               .mask   = 0xffffffff,
+               .init   = its_enable_quirk_socionext_synquacer,
+       },
+#endif
+#ifdef CONFIG_HISILICON_ERRATUM_161600802
+       {
+               .desc   = "ITS: Hip07 erratum 161600802",
+               .iidr   = 0x00000004,
+               .mask   = 0xffffffff,
+               .init   = its_enable_quirk_hip07_161600802,
+       },
 #endif
        {
        }
@@ -2835,7 +3059,7 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
 
        inner_domain->parent = its_parent;
        irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_NEXUS);
-       inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP;
+       inner_domain->flags |= its->msi_domain_flags;
        info->ops = &its_msi_domain_ops;
        info->data = its;
        inner_domain->host_data = info;
@@ -2896,8 +3120,8 @@ static int __init its_compute_its_list_map(struct resource *res,
         * locking. Should this change, we should address
         * this.
         */
-       its_number = find_first_zero_bit(&its_list_map, ITS_LIST_MAX);
-       if (its_number >= ITS_LIST_MAX) {
+       its_number = find_first_zero_bit(&its_list_map, GICv4_ITS_LIST_MAX);
+       if (its_number >= GICv4_ITS_LIST_MAX) {
                pr_err("ITS@%pa: No ITSList entry available!\n",
                       &res->start);
                return -EINVAL;
@@ -2965,6 +3189,7 @@ static int __init its_probe_one(struct resource *res,
        its->base = its_base;
        its->phys_base = res->start;
        its->ite_size = GITS_TYPER_ITT_ENTRY_SIZE(typer);
+       its->device_ids = GITS_TYPER_DEVBITS(typer);
        its->is_v4 = !!(typer & GITS_TYPER_VLPIS);
        if (its->is_v4) {
                if (!(typer & GITS_TYPER_VMOVP)) {
@@ -2972,6 +3197,8 @@ static int __init its_probe_one(struct resource *res,
                        if (err < 0)
                                goto out_free_its;
 
+                       its->list_nr = err;
+
                        pr_info("ITS@%pa: Using ITS number %d\n",
                                &res->start, err);
                } else {
@@ -2988,6 +3215,9 @@ static int __init its_probe_one(struct resource *res,
                goto out_free_its;
        }
        its->cmd_write = its->cmd_base;
+       its->fwnode_handle = handle;
+       its->get_msi_base = its_irq_get_msi_base;
+       its->msi_domain_flags = IRQ_DOMAIN_FLAG_MSI_REMAP;
 
        its_enable_quirks(its);
 
index b5df99c6f680f940a48223455a377a1ef8e07cb2..b54b55597ffb9c8351ff98e97dc05535503ec493 100644 (file)
@@ -55,6 +55,7 @@ struct gic_chip_data {
        struct irq_domain       *domain;
        u64                     redist_stride;
        u32                     nr_redist_regions;
+       bool                    has_rss;
        unsigned int            irq_nr;
        struct partition_desc   *ppi_descs[16];
 };
@@ -63,7 +64,9 @@ static struct gic_chip_data gic_data __read_mostly;
 static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
 
 static struct gic_kvm_info gic_v3_kvm_info;
+static DEFINE_PER_CPU(bool, has_rss);
 
+#define MPIDR_RS(mpidr)                        (((mpidr) & 0xF0UL) >> 4)
 #define gic_data_rdist()               (this_cpu_ptr(gic_data.rdists.rdist))
 #define gic_data_rdist_rd_base()       (gic_data_rdist()->rd_base)
 #define gic_data_rdist_sgi_base()      (gic_data_rdist_rd_base() + SZ_64K)
@@ -526,6 +529,10 @@ static void gic_update_vlpi_properties(void)
 
 static void gic_cpu_sys_reg_init(void)
 {
+       int i, cpu = smp_processor_id();
+       u64 mpidr = cpu_logical_map(cpu);
+       u64 need_rss = MPIDR_RS(mpidr);
+
        /*
         * Need to check that the SRE bit has actually been set. If
         * not, it means that SRE is disabled at EL2. We're going to
@@ -557,6 +564,30 @@ static void gic_cpu_sys_reg_init(void)
 
        /* ... and let's hit the road... */
        gic_write_grpen1(1);
+
+       /* Keep the RSS capability status in per_cpu variable */
+       per_cpu(has_rss, cpu) = !!(gic_read_ctlr() & ICC_CTLR_EL1_RSS);
+
+       /* Check all the CPUs have capable of sending SGIs to other CPUs */
+       for_each_online_cpu(i) {
+               bool have_rss = per_cpu(has_rss, i) && per_cpu(has_rss, cpu);
+
+               need_rss |= MPIDR_RS(cpu_logical_map(i));
+               if (need_rss && (!have_rss))
+                       pr_crit("CPU%d (%lx) can't SGI CPU%d (%lx), no RSS\n",
+                               cpu, (unsigned long)mpidr,
+                               i, (unsigned long)cpu_logical_map(i));
+       }
+
+       /**
+        * GIC spec says, when ICC_CTLR_EL1.RSS==1 and GICD_TYPER.RSS==0,
+        * writing ICC_ASGI1R_EL1 register with RS != 0 is a CONSTRAINED
+        * UNPREDICTABLE choice of :
+        *   - The write is ignored.
+        *   - The RS field is treated as 0.
+        */
+       if (need_rss && (!gic_data.has_rss))
+               pr_crit_once("RSS is required but GICD doesn't support it\n");
 }
 
 static int gic_dist_supports_lpis(void)
@@ -591,6 +622,9 @@ static void gic_cpu_init(void)
 
 #ifdef CONFIG_SMP
 
+#define MPIDR_TO_SGI_RS(mpidr) (MPIDR_RS(mpidr) << ICC_SGI1R_RS_SHIFT)
+#define MPIDR_TO_SGI_CLUSTER_ID(mpidr) ((mpidr) & ~0xFUL)
+
 static int gic_starting_cpu(unsigned int cpu)
 {
        gic_cpu_init();
@@ -605,13 +639,6 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
        u16 tlist = 0;
 
        while (cpu < nr_cpu_ids) {
-               /*
-                * If we ever get a cluster of more than 16 CPUs, just
-                * scream and skip that CPU.
-                */
-               if (WARN_ON((mpidr & 0xff) >= 16))
-                       goto out;
-
                tlist |= 1 << (mpidr & 0xf);
 
                next_cpu = cpumask_next(cpu, mask);
@@ -621,7 +648,7 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
 
                mpidr = cpu_logical_map(cpu);
 
-               if (cluster_id != (mpidr & ~0xffUL)) {
+               if (cluster_id != MPIDR_TO_SGI_CLUSTER_ID(mpidr)) {
                        cpu--;
                        goto out;
                }
@@ -643,6 +670,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
               MPIDR_TO_SGI_AFFINITY(cluster_id, 2)     |
               irq << ICC_SGI1R_SGI_ID_SHIFT            |
               MPIDR_TO_SGI_AFFINITY(cluster_id, 1)     |
+              MPIDR_TO_SGI_RS(cluster_id)              |
               tlist << ICC_SGI1R_TARGET_LIST_SHIFT);
 
        pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
@@ -663,7 +691,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
        smp_wmb();
 
        for_each_cpu(cpu, mask) {
-               unsigned long cluster_id = cpu_logical_map(cpu) & ~0xffUL;
+               u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(cpu_logical_map(cpu));
                u16 tlist;
 
                tlist = gic_compute_target_list(&cpu, mask, cluster_id);
@@ -1007,6 +1035,10 @@ static int __init gic_init_bases(void __iomem *dist_base,
                goto out_free;
        }
 
+       gic_data.has_rss = !!(typer & GICD_TYPER_RSS);
+       pr_info("Distributor has %sRange Selector support\n",
+               gic_data.has_rss ? "" : "no ");
+
        set_handle_irq(gic_handle_irq);
 
        gic_update_vlpi_properties();
index 651d726e8b123f541281504ed14e4d7ed6cea5e6..f641e8e2c78d1e7af926b808fa46d00285c86fff 100644 (file)
@@ -1256,6 +1256,19 @@ static void gic_teardown(struct gic_chip_data *gic)
 
 #ifdef CONFIG_OF
 static int gic_cnt __initdata;
+static bool gicv2_force_probe;
+
+static int __init gicv2_force_probe_cfg(char *buf)
+{
+       return strtobool(buf, &gicv2_force_probe);
+}
+early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg);
+
+static bool gic_check_gicv2(void __iomem *base)
+{
+       u32 val = readl_relaxed(base + GIC_CPU_IDENT);
+       return (val & 0xff0fff) == 0x02043B;
+}
 
 static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
 {
@@ -1265,20 +1278,60 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
 
        if (!is_hyp_mode_available())
                return false;
-       if (resource_size(&cpuif_res) < SZ_8K)
-               return false;
-       if (resource_size(&cpuif_res) == SZ_128K) {
-               u32 val_low, val_high;
+       if (resource_size(&cpuif_res) < SZ_8K) {
+               void __iomem *alt;
+               /*
+                * Check for a stupid firmware that only exposes the
+                * first page of a GICv2.
+                */
+               if (!gic_check_gicv2(*base))
+                       return false;
 
+               if (!gicv2_force_probe) {
+                       pr_warn("GIC: GICv2 detected, but range too small and irqchip.gicv2_force_probe not set\n");
+                       return false;
+               }
+
+               alt = ioremap(cpuif_res.start, SZ_8K);
+               if (!alt)
+                       return false;
+               if (!gic_check_gicv2(alt + SZ_4K)) {
+                       /*
+                        * The first page was that of a GICv2, and
+                        * the second was *something*. Let's trust it
+                        * to be a GICv2, and update the mapping.
+                        */
+                       pr_warn("GIC: GICv2 at %pa, but range is too small (broken DT?), assuming 8kB\n",
+                               &cpuif_res.start);
+                       iounmap(*base);
+                       *base = alt;
+                       return true;
+               }
+
+               /*
+                * We detected *two* initial GICv2 pages in a
+                * row. Could be a GICv2 aliased over two 64kB
+                * pages. Update the resource, map the iospace, and
+                * pray.
+                */
+               iounmap(alt);
+               alt = ioremap(cpuif_res.start, SZ_128K);
+               if (!alt)
+                       return false;
+               pr_warn("GIC: Aliased GICv2 at %pa, trying to find the canonical range over 128kB\n",
+                       &cpuif_res.start);
+               cpuif_res.end = cpuif_res.start + SZ_128K -1;
+               iounmap(*base);
+               *base = alt;
+       }
+       if (resource_size(&cpuif_res) == SZ_128K) {
                /*
-                * Verify that we have the first 4kB of a GIC400
+                * Verify that we have the first 4kB of a GICv2
                 * aliased over the first 64kB by checking the
                 * GICC_IIDR register on both ends.
                 */
-               val_low = readl_relaxed(*base + GIC_CPU_IDENT);
-               val_high = readl_relaxed(*base + GIC_CPU_IDENT + 0xf000);
-               if ((val_low & 0xffff0fff) != 0x0202043B ||
-                   val_low != val_high)
+               if (!gic_check_gicv2(*base) ||
+                   !gic_check_gicv2(*base + 0xf000))
                        return false;
 
                /*
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
new file mode 100644 (file)
index 0000000..a59bdbc
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ * Copyright (c) 2016 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, 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/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define NUM_CHANNEL 8
+#define MAX_INPUT_MUX 256
+
+#define REG_EDGE_POL   0x00
+#define REG_PIN_03_SEL 0x04
+#define REG_PIN_47_SEL 0x08
+#define REG_FILTER_SEL 0x0c
+
+#define REG_EDGE_POL_MASK(x)   (BIT(x) | BIT(16 + (x)))
+#define REG_EDGE_POL_EDGE(x)   BIT(x)
+#define REG_EDGE_POL_LOW(x)    BIT(16 + (x))
+#define REG_PIN_SEL_SHIFT(x)   (((x) % 4) * 8)
+#define REG_FILTER_SEL_SHIFT(x)        ((x) * 4)
+
+struct meson_gpio_irq_params {
+       unsigned int nr_hwirq;
+};
+
+static const struct meson_gpio_irq_params meson8_params = {
+       .nr_hwirq = 134,
+};
+
+static const struct meson_gpio_irq_params meson8b_params = {
+       .nr_hwirq = 119,
+};
+
+static const struct meson_gpio_irq_params gxbb_params = {
+       .nr_hwirq = 133,
+};
+
+static const struct meson_gpio_irq_params gxl_params = {
+       .nr_hwirq = 110,
+};
+
+static const struct of_device_id meson_irq_gpio_matches[] = {
+       { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
+       { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
+       { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params },
+       { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
+       { }
+};
+
+struct meson_gpio_irq_controller {
+       unsigned int nr_hwirq;
+       void __iomem *base;
+       u32 channel_irqs[NUM_CHANNEL];
+       DECLARE_BITMAP(channel_map, NUM_CHANNEL);
+       spinlock_t lock;
+};
+
+static void meson_gpio_irq_update_bits(struct meson_gpio_irq_controller *ctl,
+                                      unsigned int reg, u32 mask, u32 val)
+{
+       u32 tmp;
+
+       tmp = readl_relaxed(ctl->base + reg);
+       tmp &= ~mask;
+       tmp |= val;
+       writel_relaxed(tmp, ctl->base + reg);
+}
+
+static unsigned int meson_gpio_irq_channel_to_reg(unsigned int channel)
+{
+       return (channel < 4) ? REG_PIN_03_SEL : REG_PIN_47_SEL;
+}
+
+static int
+meson_gpio_irq_request_channel(struct meson_gpio_irq_controller *ctl,
+                              unsigned long  hwirq,
+                              u32 **channel_hwirq)
+{
+       unsigned int reg, idx;
+
+       spin_lock(&ctl->lock);
+
+       /* Find a free channel */
+       idx = find_first_zero_bit(ctl->channel_map, NUM_CHANNEL);
+       if (idx >= NUM_CHANNEL) {
+               spin_unlock(&ctl->lock);
+               pr_err("No channel available\n");
+               return -ENOSPC;
+       }
+
+       /* Mark the channel as used */
+       set_bit(idx, ctl->channel_map);
+
+       /*
+        * Setup the mux of the channel to route the signal of the pad
+        * to the appropriate input of the GIC
+        */
+       reg = meson_gpio_irq_channel_to_reg(idx);
+       meson_gpio_irq_update_bits(ctl, reg,
+                                  0xff << REG_PIN_SEL_SHIFT(idx),
+                                  hwirq << REG_PIN_SEL_SHIFT(idx));
+
+       /*
+        * Get the hwirq number assigned to this channel through
+        * a pointer the channel_irq table. The added benifit of this
+        * method is that we can also retrieve the channel index with
+        * it, using the table base.
+        */
+       *channel_hwirq = &(ctl->channel_irqs[idx]);
+
+       spin_unlock(&ctl->lock);
+
+       pr_debug("hwirq %lu assigned to channel %d - irq %u\n",
+                hwirq, idx, **channel_hwirq);
+
+       return 0;
+}
+
+static unsigned int
+meson_gpio_irq_get_channel_idx(struct meson_gpio_irq_controller *ctl,
+                              u32 *channel_hwirq)
+{
+       return channel_hwirq - ctl->channel_irqs;
+}
+
+static void
+meson_gpio_irq_release_channel(struct meson_gpio_irq_controller *ctl,
+                              u32 *channel_hwirq)
+{
+       unsigned int idx;
+
+       idx = meson_gpio_irq_get_channel_idx(ctl, channel_hwirq);
+       clear_bit(idx, ctl->channel_map);
+}
+
+static int meson_gpio_irq_type_setup(struct meson_gpio_irq_controller *ctl,
+                                    unsigned int type,
+                                    u32 *channel_hwirq)
+{
+       u32 val = 0;
+       unsigned int idx;
+
+       idx = meson_gpio_irq_get_channel_idx(ctl, channel_hwirq);
+
+       /*
+        * The controller has a filter block to operate in either LEVEL or
+        * EDGE mode, then signal is sent to the GIC. To enable LEVEL_LOW and
+        * EDGE_FALLING support (which the GIC does not support), the filter
+        * block is also able to invert the input signal it gets before
+        * providing it to the GIC.
+        */
+       type &= IRQ_TYPE_SENSE_MASK;
+
+       if (type == IRQ_TYPE_EDGE_BOTH)
+               return -EINVAL;
+
+       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+               val |= REG_EDGE_POL_EDGE(idx);
+
+       if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
+               val |= REG_EDGE_POL_LOW(idx);
+
+       spin_lock(&ctl->lock);
+
+       meson_gpio_irq_update_bits(ctl, REG_EDGE_POL,
+                                  REG_EDGE_POL_MASK(idx), val);
+
+       spin_unlock(&ctl->lock);
+
+       return 0;
+}
+
+static unsigned int meson_gpio_irq_type_output(unsigned int type)
+{
+       unsigned int sense = type & IRQ_TYPE_SENSE_MASK;
+
+       type &= ~IRQ_TYPE_SENSE_MASK;
+
+       /*
+        * The polarity of the signal provided to the GIC should always
+        * be high.
+        */
+       if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+               type |= IRQ_TYPE_LEVEL_HIGH;
+       else if (sense & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+               type |= IRQ_TYPE_EDGE_RISING;
+
+       return type;
+}
+
+static int meson_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       struct meson_gpio_irq_controller *ctl = data->domain->host_data;
+       u32 *channel_hwirq = irq_data_get_irq_chip_data(data);
+       int ret;
+
+       ret = meson_gpio_irq_type_setup(ctl, type, channel_hwirq);
+       if (ret)
+               return ret;
+
+       return irq_chip_set_type_parent(data,
+                                       meson_gpio_irq_type_output(type));
+}
+
+static struct irq_chip meson_gpio_irq_chip = {
+       .name                   = "meson-gpio-irqchip",
+       .irq_mask               = irq_chip_mask_parent,
+       .irq_unmask             = irq_chip_unmask_parent,
+       .irq_eoi                = irq_chip_eoi_parent,
+       .irq_set_type           = meson_gpio_irq_set_type,
+       .irq_retrigger          = irq_chip_retrigger_hierarchy,
+#ifdef CONFIG_SMP
+       .irq_set_affinity       = irq_chip_set_affinity_parent,
+#endif
+       .flags                  = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static int meson_gpio_irq_domain_translate(struct irq_domain *domain,
+                                          struct irq_fwspec *fwspec,
+                                          unsigned long *hwirq,
+                                          unsigned int *type)
+{
+       if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
+               *hwirq  = fwspec->param[0];
+               *type   = fwspec->param[1];
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int meson_gpio_irq_allocate_gic_irq(struct irq_domain *domain,
+                                          unsigned int virq,
+                                          u32 hwirq,
+                                          unsigned int type)
+{
+       struct irq_fwspec fwspec;
+
+       fwspec.fwnode = domain->parent->fwnode;
+       fwspec.param_count = 3;
+       fwspec.param[0] = 0;    /* SPI */
+       fwspec.param[1] = hwirq;
+       fwspec.param[2] = meson_gpio_irq_type_output(type);
+
+       return irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
+}
+
+static int meson_gpio_irq_domain_alloc(struct irq_domain *domain,
+                                      unsigned int virq,
+                                      unsigned int nr_irqs,
+                                      void *data)
+{
+       struct irq_fwspec *fwspec = data;
+       struct meson_gpio_irq_controller *ctl = domain->host_data;
+       unsigned long hwirq;
+       u32 *channel_hwirq;
+       unsigned int type;
+       int ret;
+
+       if (WARN_ON(nr_irqs != 1))
+               return -EINVAL;
+
+       ret = meson_gpio_irq_domain_translate(domain, fwspec, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       ret = meson_gpio_irq_request_channel(ctl, hwirq, &channel_hwirq);
+       if (ret)
+               return ret;
+
+       ret = meson_gpio_irq_allocate_gic_irq(domain, virq,
+                                             *channel_hwirq, type);
+       if (ret < 0) {
+               pr_err("failed to allocate gic irq %u\n", *channel_hwirq);
+               meson_gpio_irq_release_channel(ctl, channel_hwirq);
+               return ret;
+       }
+
+       irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+                                     &meson_gpio_irq_chip, channel_hwirq);
+
+       return 0;
+}
+
+static void meson_gpio_irq_domain_free(struct irq_domain *domain,
+                                      unsigned int virq,
+                                      unsigned int nr_irqs)
+{
+       struct meson_gpio_irq_controller *ctl = domain->host_data;
+       struct irq_data *irq_data;
+       u32 *channel_hwirq;
+
+       if (WARN_ON(nr_irqs != 1))
+               return;
+
+       irq_domain_free_irqs_parent(domain, virq, 1);
+
+       irq_data = irq_domain_get_irq_data(domain, virq);
+       channel_hwirq = irq_data_get_irq_chip_data(irq_data);
+
+       meson_gpio_irq_release_channel(ctl, channel_hwirq);
+}
+
+static const struct irq_domain_ops meson_gpio_irq_domain_ops = {
+       .alloc          = meson_gpio_irq_domain_alloc,
+       .free           = meson_gpio_irq_domain_free,
+       .translate      = meson_gpio_irq_domain_translate,
+};
+
+static int __init meson_gpio_irq_parse_dt(struct device_node *node,
+                                         struct meson_gpio_irq_controller *ctl)
+{
+       const struct of_device_id *match;
+       const struct meson_gpio_irq_params *params;
+       int ret;
+
+       match = of_match_node(meson_irq_gpio_matches, node);
+       if (!match)
+               return -ENODEV;
+
+       params = match->data;
+       ctl->nr_hwirq = params->nr_hwirq;
+
+       ret = of_property_read_variable_u32_array(node,
+                                                 "amlogic,channel-interrupts",
+                                                 ctl->channel_irqs,
+                                                 NUM_CHANNEL,
+                                                 NUM_CHANNEL);
+       if (ret < 0) {
+               pr_err("can't get %d channel interrupts\n", NUM_CHANNEL);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __init meson_gpio_irq_of_init(struct device_node *node,
+                                        struct device_node *parent)
+{
+       struct irq_domain *domain, *parent_domain;
+       struct meson_gpio_irq_controller *ctl;
+       int ret;
+
+       if (!parent) {
+               pr_err("missing parent interrupt node\n");
+               return -ENODEV;
+       }
+
+       parent_domain = irq_find_host(parent);
+       if (!parent_domain) {
+               pr_err("unable to obtain parent domain\n");
+               return -ENXIO;
+       }
+
+       ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
+       if (!ctl)
+               return -ENOMEM;
+
+       spin_lock_init(&ctl->lock);
+
+       ctl->base = of_iomap(node, 0);
+       if (!ctl->base) {
+               ret = -ENOMEM;
+               goto free_ctl;
+       }
+
+       ret = meson_gpio_irq_parse_dt(node, ctl);
+       if (ret)
+               goto free_channel_irqs;
+
+       domain = irq_domain_create_hierarchy(parent_domain, 0, ctl->nr_hwirq,
+                                            of_node_to_fwnode(node),
+                                            &meson_gpio_irq_domain_ops,
+                                            ctl);
+       if (!domain) {
+               pr_err("failed to add domain\n");
+               ret = -ENODEV;
+               goto free_channel_irqs;
+       }
+
+       pr_info("%d to %d gpio interrupt mux initialized\n",
+               ctl->nr_hwirq, NUM_CHANNEL);
+
+       return 0;
+
+free_channel_irqs:
+       iounmap(ctl->base);
+free_ctl:
+       kfree(ctl);
+
+       return ret;
+}
+
+IRQCHIP_DECLARE(meson_gpio_intc, "amlogic,meson-gpio-intc",
+               meson_gpio_irq_of_init);
index c90976d7e53ccc596b65a0864ef169f1aa1fafd8..ef92a4d2038eef7f2c09ad9eaabf91adc3957435 100644 (file)
@@ -6,8 +6,12 @@
  * Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
  */
+
+#define pr_fmt(fmt) "irq-mips-gic: " fmt
+
 #include <linux/bitmap.h>
 #include <linux/clocksource.h>
+#include <linux/cpuhotplug.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -48,12 +52,16 @@ static DEFINE_SPINLOCK(gic_lock);
 static struct irq_domain *gic_irq_domain;
 static struct irq_domain *gic_ipi_domain;
 static int gic_shared_intrs;
-static int gic_vpes;
 static unsigned int gic_cpu_pin;
 static unsigned int timer_cpu_pin;
 static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
-DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
-DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
+static DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
+static DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
+
+static struct gic_all_vpes_chip_data {
+       u32     map;
+       bool    mask;
+} gic_all_vpes_chip_data[GIC_NUM_LOCAL_INTRS];
 
 static void gic_clear_pcpu_masks(unsigned int intr)
 {
@@ -194,46 +202,46 @@ static void gic_ack_irq(struct irq_data *d)
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
-       unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
+       unsigned int irq, pol, trig, dual;
        unsigned long flags;
-       bool is_edge;
+
+       irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
 
        spin_lock_irqsave(&gic_lock, flags);
        switch (type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_FALLING:
-               change_gic_pol(irq, GIC_POL_FALLING_EDGE);
-               change_gic_trig(irq, GIC_TRIG_EDGE);
-               change_gic_dual(irq, GIC_DUAL_SINGLE);
-               is_edge = true;
+               pol = GIC_POL_FALLING_EDGE;
+               trig = GIC_TRIG_EDGE;
+               dual = GIC_DUAL_SINGLE;
                break;
        case IRQ_TYPE_EDGE_RISING:
-               change_gic_pol(irq, GIC_POL_RISING_EDGE);
-               change_gic_trig(irq, GIC_TRIG_EDGE);
-               change_gic_dual(irq, GIC_DUAL_SINGLE);
-               is_edge = true;
+               pol = GIC_POL_RISING_EDGE;
+               trig = GIC_TRIG_EDGE;
+               dual = GIC_DUAL_SINGLE;
                break;
        case IRQ_TYPE_EDGE_BOTH:
-               /* polarity is irrelevant in this case */
-               change_gic_trig(irq, GIC_TRIG_EDGE);
-               change_gic_dual(irq, GIC_DUAL_DUAL);
-               is_edge = true;
+               pol = 0; /* Doesn't matter */
+               trig = GIC_TRIG_EDGE;
+               dual = GIC_DUAL_DUAL;
                break;
        case IRQ_TYPE_LEVEL_LOW:
-               change_gic_pol(irq, GIC_POL_ACTIVE_LOW);
-               change_gic_trig(irq, GIC_TRIG_LEVEL);
-               change_gic_dual(irq, GIC_DUAL_SINGLE);
-               is_edge = false;
+               pol = GIC_POL_ACTIVE_LOW;
+               trig = GIC_TRIG_LEVEL;
+               dual = GIC_DUAL_SINGLE;
                break;
        case IRQ_TYPE_LEVEL_HIGH:
        default:
-               change_gic_pol(irq, GIC_POL_ACTIVE_HIGH);
-               change_gic_trig(irq, GIC_TRIG_LEVEL);
-               change_gic_dual(irq, GIC_DUAL_SINGLE);
-               is_edge = false;
+               pol = GIC_POL_ACTIVE_HIGH;
+               trig = GIC_TRIG_LEVEL;
+               dual = GIC_DUAL_SINGLE;
                break;
        }
 
-       if (is_edge)
+       change_gic_pol(irq, pol);
+       change_gic_trig(irq, trig);
+       change_gic_dual(irq, dual);
+
+       if (trig == GIC_TRIG_EDGE)
                irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller,
                                                 handle_edge_irq, NULL);
        else
@@ -338,13 +346,17 @@ static struct irq_chip gic_local_irq_controller = {
 
 static void gic_mask_local_irq_all_vpes(struct irq_data *d)
 {
-       int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
-       int i;
+       struct gic_all_vpes_chip_data *cd;
        unsigned long flags;
+       int intr, cpu;
+
+       intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
+       cd = irq_data_get_irq_chip_data(d);
+       cd->mask = false;
 
        spin_lock_irqsave(&gic_lock, flags);
-       for (i = 0; i < gic_vpes; i++) {
-               write_gic_vl_other(mips_cm_vp_id(i));
+       for_each_online_cpu(cpu) {
+               write_gic_vl_other(mips_cm_vp_id(cpu));
                write_gic_vo_rmask(BIT(intr));
        }
        spin_unlock_irqrestore(&gic_lock, flags);
@@ -352,22 +364,40 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d)
 
 static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
 {
-       int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
-       int i;
+       struct gic_all_vpes_chip_data *cd;
        unsigned long flags;
+       int intr, cpu;
+
+       intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
+       cd = irq_data_get_irq_chip_data(d);
+       cd->mask = true;
 
        spin_lock_irqsave(&gic_lock, flags);
-       for (i = 0; i < gic_vpes; i++) {
-               write_gic_vl_other(mips_cm_vp_id(i));
+       for_each_online_cpu(cpu) {
+               write_gic_vl_other(mips_cm_vp_id(cpu));
                write_gic_vo_smask(BIT(intr));
        }
        spin_unlock_irqrestore(&gic_lock, flags);
 }
 
+static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
+{
+       struct gic_all_vpes_chip_data *cd;
+       unsigned int intr;
+
+       intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
+       cd = irq_data_get_irq_chip_data(d);
+
+       write_gic_vl_map(intr, cd->map);
+       if (cd->mask)
+               write_gic_vl_smask(BIT(intr));
+}
+
 static struct irq_chip gic_all_vpes_local_irq_controller = {
-       .name                   =       "MIPS GIC Local",
-       .irq_mask               =       gic_mask_local_irq_all_vpes,
-       .irq_unmask             =       gic_unmask_local_irq_all_vpes,
+       .name                   = "MIPS GIC Local",
+       .irq_mask               = gic_mask_local_irq_all_vpes,
+       .irq_unmask             = gic_unmask_local_irq_all_vpes,
+       .irq_cpu_online         = gic_all_vpes_irq_cpu_online,
 };
 
 static void __gic_irq_dispatch(void)
@@ -382,39 +412,6 @@ static void gic_irq_dispatch(struct irq_desc *desc)
        gic_handle_shared_int(true);
 }
 
-static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
-                                   irq_hw_number_t hw)
-{
-       int intr = GIC_HWIRQ_TO_LOCAL(hw);
-       int i;
-       unsigned long flags;
-       u32 val;
-
-       if (!gic_local_irq_is_routable(intr))
-               return -EPERM;
-
-       if (intr > GIC_LOCAL_INT_FDC) {
-               pr_err("Invalid local IRQ %d\n", intr);
-               return -EINVAL;
-       }
-
-       if (intr == GIC_LOCAL_INT_TIMER) {
-               /* CONFIG_MIPS_CMP workaround (see __gic_init) */
-               val = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin;
-       } else {
-               val = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
-       }
-
-       spin_lock_irqsave(&gic_lock, flags);
-       for (i = 0; i < gic_vpes; i++) {
-               write_gic_vl_other(mips_cm_vp_id(i));
-               write_gic_vo_map(intr, val);
-       }
-       spin_unlock_irqrestore(&gic_lock, flags);
-
-       return 0;
-}
-
 static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
                                     irq_hw_number_t hw, unsigned int cpu)
 {
@@ -457,7 +454,11 @@ static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
 static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
                              irq_hw_number_t hwirq)
 {
-       int err;
+       struct gic_all_vpes_chip_data *cd;
+       unsigned long flags;
+       unsigned int intr;
+       int err, cpu;
+       u32 map;
 
        if (hwirq >= GIC_SHARED_HWIRQ_BASE) {
                /* verify that shared irqs don't conflict with an IPI irq */
@@ -474,8 +475,14 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
                return gic_shared_irq_domain_map(d, virq, hwirq, 0);
        }
 
-       switch (GIC_HWIRQ_TO_LOCAL(hwirq)) {
+       intr = GIC_HWIRQ_TO_LOCAL(hwirq);
+       map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
+
+       switch (intr) {
        case GIC_LOCAL_INT_TIMER:
+               /* CONFIG_MIPS_CMP workaround (see __gic_init) */
+               map = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin;
+               /* fall-through */
        case GIC_LOCAL_INT_PERFCTR:
        case GIC_LOCAL_INT_FDC:
                /*
@@ -483,9 +490,11 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
                 * the rest of the MIPS kernel code does not use the
                 * percpu IRQ API for them.
                 */
+               cd = &gic_all_vpes_chip_data[intr];
+               cd->map = map;
                err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
                                                    &gic_all_vpes_local_irq_controller,
-                                                   NULL);
+                                                   cd);
                if (err)
                        return err;
 
@@ -504,7 +513,17 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
                break;
        }
 
-       return gic_local_irq_domain_map(d, virq, hwirq);
+       if (!gic_local_irq_is_routable(intr))
+               return -EPERM;
+
+       spin_lock_irqsave(&gic_lock, flags);
+       for_each_online_cpu(cpu) {
+               write_gic_vl_other(mips_cm_vp_id(cpu));
+               write_gic_vo_map(intr, map);
+       }
+       spin_unlock_irqrestore(&gic_lock, flags);
+
+       return 0;
 }
 
 static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
@@ -636,11 +655,25 @@ static const struct irq_domain_ops gic_ipi_domain_ops = {
        .match = gic_ipi_domain_match,
 };
 
+static int gic_cpu_startup(unsigned int cpu)
+{
+       /* Enable or disable EIC */
+       change_gic_vl_ctl(GIC_VX_CTL_EIC,
+                         cpu_has_veic ? GIC_VX_CTL_EIC : 0);
+
+       /* Clear all local IRQ masks (ie. disable all local interrupts) */
+       write_gic_vl_rmask(~0);
+
+       /* Invoke irq_cpu_online callbacks to enable desired interrupts */
+       irq_cpu_online();
+
+       return 0;
+}
 
 static int __init gic_of_init(struct device_node *node,
                              struct device_node *parent)
 {
-       unsigned int cpu_vec, i, j, gicconfig, cpu, v[2];
+       unsigned int cpu_vec, i, gicconfig, v[2], num_ipis;
        unsigned long reserved;
        phys_addr_t gic_base;
        struct resource res;
@@ -655,7 +688,7 @@ static int __init gic_of_init(struct device_node *node,
 
        cpu_vec = find_first_zero_bit(&reserved, hweight_long(ST0_IM));
        if (cpu_vec == hweight_long(ST0_IM)) {
-               pr_err("No CPU vectors available for GIC\n");
+               pr_err("No CPU vectors available\n");
                return -ENODEV;
        }
 
@@ -668,8 +701,10 @@ static int __init gic_of_init(struct device_node *node,
                        gic_base = read_gcr_gic_base() &
                                ~CM_GCR_GIC_BASE_GICEN;
                        gic_len = 0x20000;
+                       pr_warn("Using inherited base address %pa\n",
+                               &gic_base);
                } else {
-                       pr_err("Failed to get GIC memory range\n");
+                       pr_err("Failed to get memory range\n");
                        return -ENODEV;
                }
        } else {
@@ -690,17 +725,7 @@ static int __init gic_of_init(struct device_node *node,
        gic_shared_intrs >>= __ffs(GIC_CONFIG_NUMINTERRUPTS);
        gic_shared_intrs = (gic_shared_intrs + 1) * 8;
 
-       gic_vpes = gicconfig & GIC_CONFIG_PVPS;
-       gic_vpes >>= __ffs(GIC_CONFIG_PVPS);
-       gic_vpes = gic_vpes + 1;
-
        if (cpu_has_veic) {
-               /* Set EIC mode for all VPEs */
-               for_each_present_cpu(cpu) {
-                       write_gic_vl_other(mips_cm_vp_id(cpu));
-                       write_gic_vo_ctl(GIC_VX_CTL_EIC);
-               }
-
                /* Always use vector 1 in EIC mode */
                gic_cpu_pin = 0;
                timer_cpu_pin = gic_cpu_pin;
@@ -737,7 +762,7 @@ static int __init gic_of_init(struct device_node *node,
                                               gic_shared_intrs, 0,
                                               &gic_irq_domain_ops, NULL);
        if (!gic_irq_domain) {
-               pr_err("Failed to add GIC IRQ domain");
+               pr_err("Failed to add IRQ domain");
                return -ENXIO;
        }
 
@@ -746,7 +771,7 @@ static int __init gic_of_init(struct device_node *node,
                                                  GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
                                                  node, &gic_ipi_domain_ops, NULL);
        if (!gic_ipi_domain) {
-               pr_err("Failed to add GIC IPI domain");
+               pr_err("Failed to add IPI domain");
                return -ENXIO;
        }
 
@@ -756,10 +781,12 @@ static int __init gic_of_init(struct device_node *node,
            !of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) {
                bitmap_set(ipi_resrv, v[0], v[1]);
        } else {
-               /* Make the last 2 * gic_vpes available for IPIs */
-               bitmap_set(ipi_resrv,
-                          gic_shared_intrs - 2 * gic_vpes,
-                          2 * gic_vpes);
+               /*
+                * Reserve 2 interrupts per possible CPU/VP for use as IPIs,
+                * meeting the requirements of arch/mips SMP.
+                */
+               num_ipis = 2 * num_possible_cpus();
+               bitmap_set(ipi_resrv, gic_shared_intrs - num_ipis, num_ipis);
        }
 
        bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
@@ -773,15 +800,8 @@ static int __init gic_of_init(struct device_node *node,
                write_gic_rmask(i);
        }
 
-       for (i = 0; i < gic_vpes; i++) {
-               write_gic_vl_other(mips_cm_vp_id(i));
-               for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
-                       if (!gic_local_irq_is_routable(j))
-                               continue;
-                       write_gic_vo_rmask(BIT(j));
-               }
-       }
-
-       return 0;
+       return cpuhp_setup_state(CPUHP_AP_IRQ_MIPS_GIC_STARTING,
+                                "irqchip/mips/gic:starting",
+                                gic_cpu_startup, NULL);
 }
 IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init);
index b04a8ac6e744bde9e7d9aa7159e4e9d3da7b86cd..d360a6eddd6d3696805af2225893092cb77e41ec 100644 (file)
 
 #include <linux/irqchip/irq-omap-intc.h>
 
-/* Define these here for now until we drop all board-files */
-#define OMAP24XX_IC_BASE       0x480fe000
-#define OMAP34XX_IC_BASE       0x48200000
-
 /* selected INTC register offsets */
 
 #define INTC_REVISION          0x0000
@@ -70,8 +66,8 @@ static struct omap_intc_regs intc_context;
 
 static struct irq_domain *domain;
 static void __iomem *omap_irq_base;
-static int omap_nr_pending = 3;
-static int omap_nr_irqs = 96;
+static int omap_nr_pending;
+static int omap_nr_irqs;
 
 static void intc_writel(u32 reg, u32 val)
 {
@@ -364,14 +360,6 @@ omap_intc_handle_irq(struct pt_regs *regs)
        handle_domain_irq(domain, irqnr, regs);
 }
 
-void __init omap3_init_irq(void)
-{
-       omap_nr_irqs = 96;
-       omap_nr_pending = 3;
-       omap_init_irq(OMAP34XX_IC_BASE, NULL);
-       set_handle_irq(omap_intc_handle_irq);
-}
-
 static int __init intc_of_init(struct device_node *node,
                             struct device_node *parent)
 {
diff --git a/drivers/irqchip/irq-ompic.c b/drivers/irqchip/irq-ompic.c
new file mode 100644 (file)
index 0000000..cf6d0c4
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Open Multi-Processor Interrupt Controller driver
+ *
+ * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * The ompic device handles IPI communication between cores in multi-core
+ * OpenRISC systems.
+ *
+ * Registers
+ *
+ * For each CPU the ompic has 2 registers. The control register for sending
+ * and acking IPIs and the status register for receiving IPIs. The register
+ * layouts are as follows:
+ *
+ *  Control register
+ *  +---------+---------+----------+---------+
+ *  | 31      | 30      | 29 .. 16 | 15 .. 0 |
+ *  ----------+---------+----------+----------
+ *  | IRQ ACK | IRQ GEN | DST CORE | DATA    |
+ *  +---------+---------+----------+---------+
+ *
+ *  Status register
+ *  +----------+-------------+----------+---------+
+ *  | 31       | 30          | 29 .. 16 | 15 .. 0 |
+ *  -----------+-------------+----------+---------+
+ *  | Reserved | IRQ Pending | SRC CORE | DATA    |
+ *  +----------+-------------+----------+---------+
+ *
+ * Architecture
+ *
+ * - The ompic generates a level interrupt to the CPU PIC when a message is
+ *   ready.  Messages are delivered via the memory bus.
+ * - The ompic does not have any interrupt input lines.
+ * - The ompic is wired to the same irq line on each core.
+ * - Devices are wired to the same irq line on each core.
+ *
+ *   +---------+                         +---------+
+ *   | CPU     |                         | CPU     |
+ *   |  Core 0 |<==\ (memory access) /==>|  Core 1 |
+ *   |  [ PIC ]|   |                 |   |  [ PIC ]|
+ *   +----^-^--+   |                 |   +----^-^--+
+ *        | |      v                 v        | |
+ *   <====|=|=================================|=|==> (memory bus)
+ *        | |      ^                  ^       | |
+ *  (ipi  | +------|---------+--------|-------|-+ (device irq)
+ *   irq  |        |         |        |       |
+ *  core0)| +------|---------|--------|-------+ (ipi irq core1)
+ *        | |      |         |        |
+ *   +----o-o-+    |    +--------+    |
+ *   | ompic  |<===/    | Device |<===/
+ *   |  IPI   |         +--------+
+ *   +--------+*
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <linux/irqchip.h>
+
+#define OMPIC_CPUBYTES         8
+#define OMPIC_CTRL(cpu)                (0x0 + (cpu * OMPIC_CPUBYTES))
+#define OMPIC_STAT(cpu)                (0x4 + (cpu * OMPIC_CPUBYTES))
+
+#define OMPIC_CTRL_IRQ_ACK     (1 << 31)
+#define OMPIC_CTRL_IRQ_GEN     (1 << 30)
+#define OMPIC_CTRL_DST(cpu)    (((cpu) & 0x3fff) << 16)
+
+#define OMPIC_STAT_IRQ_PENDING (1 << 30)
+
+#define OMPIC_DATA(x)          ((x) & 0xffff)
+
+DEFINE_PER_CPU(unsigned long, ops);
+
+static void __iomem *ompic_base;
+
+static inline u32 ompic_readreg(void __iomem *base, loff_t offset)
+{
+       return ioread32be(base + offset);
+}
+
+static void ompic_writereg(void __iomem *base, loff_t offset, u32 data)
+{
+       iowrite32be(data, base + offset);
+}
+
+static void ompic_raise_softirq(const struct cpumask *mask,
+                               unsigned int ipi_msg)
+{
+       unsigned int dst_cpu;
+       unsigned int src_cpu = smp_processor_id();
+
+       for_each_cpu(dst_cpu, mask) {
+               set_bit(ipi_msg, &per_cpu(ops, dst_cpu));
+
+               /*
+                * On OpenRISC the atomic set_bit() call implies a memory
+                * barrier.  Otherwise we would need: smp_wmb(); paired
+                * with the read in ompic_ipi_handler.
+                */
+
+               ompic_writereg(ompic_base, OMPIC_CTRL(src_cpu),
+                              OMPIC_CTRL_IRQ_GEN |
+                              OMPIC_CTRL_DST(dst_cpu) |
+                              OMPIC_DATA(1));
+       }
+}
+
+static irqreturn_t ompic_ipi_handler(int irq, void *dev_id)
+{
+       unsigned int cpu = smp_processor_id();
+       unsigned long *pending_ops = &per_cpu(ops, cpu);
+       unsigned long ops;
+
+       ompic_writereg(ompic_base, OMPIC_CTRL(cpu), OMPIC_CTRL_IRQ_ACK);
+       while ((ops = xchg(pending_ops, 0)) != 0) {
+
+               /*
+                * On OpenRISC the atomic xchg() call implies a memory
+                * barrier.  Otherwise we may need an smp_rmb(); paired
+                * with the write in ompic_raise_softirq.
+                */
+
+               do {
+                       unsigned long ipi_msg;
+
+                       ipi_msg = __ffs(ops);
+                       ops &= ~(1UL << ipi_msg);
+
+                       handle_IPI(ipi_msg);
+               } while (ops);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int __init ompic_of_init(struct device_node *node,
+                               struct device_node *parent)
+{
+       struct resource res;
+       int irq;
+       int ret;
+
+       /* Validate the DT */
+       if (ompic_base) {
+               pr_err("ompic: duplicate ompic's are not supported");
+               return -EEXIST;
+       }
+
+       if (of_address_to_resource(node, 0, &res)) {
+               pr_err("ompic: reg property requires an address and size");
+               return -EINVAL;
+       }
+
+       if (resource_size(&res) < (num_possible_cpus() * OMPIC_CPUBYTES)) {
+               pr_err("ompic: reg size, currently %d must be at least %d",
+                       resource_size(&res),
+                       (num_possible_cpus() * OMPIC_CPUBYTES));
+               return -EINVAL;
+       }
+
+       /* Setup the device */
+       ompic_base = ioremap(res.start, resource_size(&res));
+       if (IS_ERR(ompic_base)) {
+               pr_err("ompic: unable to map registers");
+               return PTR_ERR(ompic_base);
+       }
+
+       irq = irq_of_parse_and_map(node, 0);
+       if (irq <= 0) {
+               pr_err("ompic: unable to parse device irq");
+               ret = -EINVAL;
+               goto out_unmap;
+       }
+
+       ret = request_irq(irq, ompic_ipi_handler, IRQF_PERCPU,
+                               "ompic_ipi", NULL);
+       if (ret)
+               goto out_irq_disp;
+
+       set_smp_cross_call(ompic_raise_softirq);
+
+       return 0;
+
+out_irq_disp:
+       irq_dispose_mapping(irq);
+out_unmap:
+       iounmap(ompic_base);
+       ompic_base = NULL;
+       return ret;
+}
+IRQCHIP_DECLARE(ompic, "openrisc,ompic", ompic_of_init);
index 713177d97c7aa0b66210f5be611931d230f9421b..06f29cf5018a151f7d35641d90b8d043aec85516 100644 (file)
@@ -389,9 +389,8 @@ MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
 
 static int intc_irqpin_probe(struct platform_device *pdev)
 {
-       const struct intc_irqpin_config *config = NULL;
+       const struct intc_irqpin_config *config;
        struct device *dev = &pdev->dev;
-       const struct of_device_id *of_id;
        struct intc_irqpin_priv *p;
        struct intc_irqpin_iomem *i;
        struct resource *io[INTC_IRQPIN_REG_NR];
@@ -422,11 +421,9 @@ static int intc_irqpin_probe(struct platform_device *pdev)
        p->pdev = pdev;
        platform_set_drvdata(pdev, p);
 
-       of_id = of_match_device(intc_irqpin_dt_ids, dev);
-       if (of_id && of_id->data) {
-               config = of_id->data;
+       config = of_device_get_match_data(dev);
+       if (config)
                p->needs_clk = config->needs_clk;
-       }
 
        p->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(p->clk)) {
diff --git a/drivers/irqchip/irq-sni-exiu.c b/drivers/irqchip/irq-sni-exiu.c
new file mode 100644 (file)
index 0000000..1b6e2f7
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Driver for Socionext External Interrupt Unit (EXIU)
+ *
+ * Copyright (c) 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * Based on irq-tegra.c:
+ *   Copyright (C) 2011 Google, Inc.
+ *   Copyright (C) 2010,2013, NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define NUM_IRQS       32
+
+#define EIMASK         0x00
+#define EISRCSEL       0x04
+#define EIREQSTA       0x08
+#define EIRAWREQSTA    0x0C
+#define EIREQCLR       0x10
+#define EILVL          0x14
+#define EIEDG          0x18
+#define EISIR          0x1C
+
+struct exiu_irq_data {
+       void __iomem    *base;
+       u32             spi_base;
+};
+
+static void exiu_irq_eoi(struct irq_data *d)
+{
+       struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
+
+       writel(BIT(d->hwirq), data->base + EIREQCLR);
+       irq_chip_eoi_parent(d);
+}
+
+static void exiu_irq_mask(struct irq_data *d)
+{
+       struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
+       u32 val;
+
+       val = readl_relaxed(data->base + EIMASK) | BIT(d->hwirq);
+       writel_relaxed(val, data->base + EIMASK);
+       irq_chip_mask_parent(d);
+}
+
+static void exiu_irq_unmask(struct irq_data *d)
+{
+       struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
+       u32 val;
+
+       val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq);
+       writel_relaxed(val, data->base + EIMASK);
+       irq_chip_unmask_parent(d);
+}
+
+static void exiu_irq_enable(struct irq_data *d)
+{
+       struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
+       u32 val;
+
+       /* clear interrupts that were latched while disabled */
+       writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
+
+       val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq);
+       writel_relaxed(val, data->base + EIMASK);
+       irq_chip_enable_parent(d);
+}
+
+static int exiu_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
+       u32 val;
+
+       val = readl_relaxed(data->base + EILVL);
+       if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
+               val |= BIT(d->hwirq);
+       else
+               val &= ~BIT(d->hwirq);
+       writel_relaxed(val, data->base + EILVL);
+
+       val = readl_relaxed(data->base + EIEDG);
+       if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
+               val &= ~BIT(d->hwirq);
+       else
+               val |= BIT(d->hwirq);
+       writel_relaxed(val, data->base + EIEDG);
+
+       writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
+
+       return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
+}
+
+static struct irq_chip exiu_irq_chip = {
+       .name                   = "EXIU",
+       .irq_eoi                = exiu_irq_eoi,
+       .irq_enable             = exiu_irq_enable,
+       .irq_mask               = exiu_irq_mask,
+       .irq_unmask             = exiu_irq_unmask,
+       .irq_set_type           = exiu_irq_set_type,
+       .irq_set_affinity       = irq_chip_set_affinity_parent,
+       .flags                  = IRQCHIP_SET_TYPE_MASKED |
+                                 IRQCHIP_SKIP_SET_WAKE |
+                                 IRQCHIP_EOI_THREADED |
+                                 IRQCHIP_MASK_ON_SUSPEND,
+};
+
+static int exiu_domain_translate(struct irq_domain *domain,
+                                struct irq_fwspec *fwspec,
+                                unsigned long *hwirq,
+                                unsigned int *type)
+{
+       struct exiu_irq_data *info = domain->host_data;
+
+       if (is_of_node(fwspec->fwnode)) {
+               if (fwspec->param_count != 3)
+                       return -EINVAL;
+
+               if (fwspec->param[0] != GIC_SPI)
+                       return -EINVAL; /* No PPI should point to this domain */
+
+               *hwirq = fwspec->param[1] - info->spi_base;
+               *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
+                            unsigned int nr_irqs, void *data)
+{
+       struct irq_fwspec *fwspec = data;
+       struct irq_fwspec parent_fwspec;
+       struct exiu_irq_data *info = dom->host_data;
+       irq_hw_number_t hwirq;
+
+       if (fwspec->param_count != 3)
+               return -EINVAL; /* Not GIC compliant */
+       if (fwspec->param[0] != GIC_SPI)
+               return -EINVAL; /* No PPI should point to this domain */
+
+       WARN_ON(nr_irqs != 1);
+       hwirq = fwspec->param[1] - info->spi_base;
+       irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info);
+
+       parent_fwspec = *fwspec;
+       parent_fwspec.fwnode = dom->parent->fwnode;
+       return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec);
+}
+
+static const struct irq_domain_ops exiu_domain_ops = {
+       .translate      = exiu_domain_translate,
+       .alloc          = exiu_domain_alloc,
+       .free           = irq_domain_free_irqs_common,
+};
+
+static int __init exiu_init(struct device_node *node,
+                           struct device_node *parent)
+{
+       struct irq_domain *parent_domain, *domain;
+       struct exiu_irq_data *data;
+       int err;
+
+       if (!parent) {
+               pr_err("%pOF: no parent, giving up\n", node);
+               return -ENODEV;
+       }
+
+       parent_domain = irq_find_host(parent);
+       if (!parent_domain) {
+               pr_err("%pOF: unable to obtain parent domain\n", node);
+               return -ENXIO;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       if (of_property_read_u32(node, "socionext,spi-base", &data->spi_base)) {
+               pr_err("%pOF: failed to parse 'spi-base' property\n", node);
+               err = -ENODEV;
+               goto out_free;
+       }
+
+       data->base = of_iomap(node, 0);
+       if (IS_ERR(data->base)) {
+               err = PTR_ERR(data->base);
+               goto out_free;
+       }
+
+       /* clear and mask all interrupts */
+       writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR);
+       writel_relaxed(0xFFFFFFFF, data->base + EIMASK);
+
+       domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node,
+                                         &exiu_domain_ops, data);
+       if (!domain) {
+               pr_err("%pOF: failed to allocate domain\n", node);
+               err = -ENOMEM;
+               goto out_unmap;
+       }
+
+       pr_info("%pOF: %d interrupts forwarded to %pOF\n", node, NUM_IRQS,
+               parent);
+
+       return 0;
+
+out_unmap:
+       iounmap(data->base);
+out_free:
+       kfree(data);
+       return err;
+}
+IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_init);
index 45363ff8d06f0afb26c2b64d8bf5aa06d1f74aa3..31ab0dee2ce72c0685f47f679abf4ee52851ccf2 100644 (file)
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 
-#define EXTI_IMR       0x0
-#define EXTI_EMR       0x4
-#define EXTI_RTSR      0x8
-#define EXTI_FTSR      0xc
-#define EXTI_SWIER     0x10
-#define EXTI_PR                0x14
+#define IRQS_PER_BANK 32
+
+struct stm32_exti_bank {
+       u32 imr_ofst;
+       u32 emr_ofst;
+       u32 rtsr_ofst;
+       u32 ftsr_ofst;
+       u32 swier_ofst;
+       u32 pr_ofst;
+};
+
+static const struct stm32_exti_bank stm32f4xx_exti_b1 = {
+       .imr_ofst       = 0x00,
+       .emr_ofst       = 0x04,
+       .rtsr_ofst      = 0x08,
+       .ftsr_ofst      = 0x0C,
+       .swier_ofst     = 0x10,
+       .pr_ofst        = 0x14,
+};
+
+static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = {
+       &stm32f4xx_exti_b1,
+};
+
+static const struct stm32_exti_bank stm32h7xx_exti_b1 = {
+       .imr_ofst       = 0x80,
+       .emr_ofst       = 0x84,
+       .rtsr_ofst      = 0x00,
+       .ftsr_ofst      = 0x04,
+       .swier_ofst     = 0x08,
+       .pr_ofst        = 0x88,
+};
+
+static const struct stm32_exti_bank stm32h7xx_exti_b2 = {
+       .imr_ofst       = 0x90,
+       .emr_ofst       = 0x94,
+       .rtsr_ofst      = 0x20,
+       .ftsr_ofst      = 0x24,
+       .swier_ofst     = 0x28,
+       .pr_ofst        = 0x98,
+};
+
+static const struct stm32_exti_bank stm32h7xx_exti_b3 = {
+       .imr_ofst       = 0xA0,
+       .emr_ofst       = 0xA4,
+       .rtsr_ofst      = 0x40,
+       .ftsr_ofst      = 0x44,
+       .swier_ofst     = 0x48,
+       .pr_ofst        = 0xA8,
+};
+
+static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = {
+       &stm32h7xx_exti_b1,
+       &stm32h7xx_exti_b2,
+       &stm32h7xx_exti_b3,
+};
+
+static unsigned long stm32_exti_pending(struct irq_chip_generic *gc)
+{
+       const struct stm32_exti_bank *stm32_bank = gc->private;
+
+       return irq_reg_readl(gc, stm32_bank->pr_ofst);
+}
+
+static void stm32_exti_irq_ack(struct irq_chip_generic *gc, u32 mask)
+{
+       const struct stm32_exti_bank *stm32_bank = gc->private;
+
+       irq_reg_writel(gc, mask, stm32_bank->pr_ofst);
+}
 
 static void stm32_irq_handler(struct irq_desc *desc)
 {
        struct irq_domain *domain = irq_desc_get_handler_data(desc);
-       struct irq_chip_generic *gc = domain->gc->gc[0];
        struct irq_chip *chip = irq_desc_get_chip(desc);
+       unsigned int virq, nbanks = domain->gc->num_chips;
+       struct irq_chip_generic *gc;
+       const struct stm32_exti_bank *stm32_bank;
        unsigned long pending;
-       int n;
+       int n, i, irq_base = 0;
 
        chained_irq_enter(chip, desc);
 
-       while ((pending = irq_reg_readl(gc, EXTI_PR))) {
-               for_each_set_bit(n, &pending, BITS_PER_LONG) {
-                       generic_handle_irq(irq_find_mapping(domain, n));
-                       irq_reg_writel(gc, BIT(n), EXTI_PR);
+       for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) {
+               gc = irq_get_domain_generic_chip(domain, irq_base);
+               stm32_bank = gc->private;
+
+               while ((pending = stm32_exti_pending(gc))) {
+                       for_each_set_bit(n, &pending, IRQS_PER_BANK) {
+                               virq = irq_find_mapping(domain, irq_base + n);
+                               generic_handle_irq(virq);
+                               stm32_exti_irq_ack(gc, BIT(n));
+                       }
                }
        }
 
@@ -44,13 +116,14 @@ static void stm32_irq_handler(struct irq_desc *desc)
 static int stm32_irq_set_type(struct irq_data *data, unsigned int type)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-       int pin = data->hwirq;
+       const struct stm32_exti_bank *stm32_bank = gc->private;
+       int pin = data->hwirq % IRQS_PER_BANK;
        u32 rtsr, ftsr;
 
        irq_gc_lock(gc);
 
-       rtsr = irq_reg_readl(gc, EXTI_RTSR);
-       ftsr = irq_reg_readl(gc, EXTI_FTSR);
+       rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst);
+       ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst);
 
        switch (type) {
        case IRQ_TYPE_EDGE_RISING:
@@ -70,8 +143,8 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type)
                return -EINVAL;
        }
 
-       irq_reg_writel(gc, rtsr, EXTI_RTSR);
-       irq_reg_writel(gc, ftsr, EXTI_FTSR);
+       irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst);
+       irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst);
 
        irq_gc_unlock(gc);
 
@@ -81,17 +154,18 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type)
 static int stm32_irq_set_wake(struct irq_data *data, unsigned int on)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-       int pin = data->hwirq;
-       u32 emr;
+       const struct stm32_exti_bank *stm32_bank = gc->private;
+       int pin = data->hwirq % IRQS_PER_BANK;
+       u32 imr;
 
        irq_gc_lock(gc);
 
-       emr = irq_reg_readl(gc, EXTI_EMR);
+       imr = irq_reg_readl(gc, stm32_bank->imr_ofst);
        if (on)
-               emr |= BIT(pin);
+               imr |= BIT(pin);
        else
-               emr &= ~BIT(pin);
-       irq_reg_writel(gc, emr, EXTI_EMR);
+               imr &= ~BIT(pin);
+       irq_reg_writel(gc, imr, stm32_bank->imr_ofst);
 
        irq_gc_unlock(gc);
 
@@ -101,11 +175,12 @@ static int stm32_irq_set_wake(struct irq_data *data, unsigned int on)
 static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq,
                            unsigned int nr_irqs, void *data)
 {
-       struct irq_chip_generic *gc = d->gc->gc[0];
+       struct irq_chip_generic *gc;
        struct irq_fwspec *fwspec = data;
        irq_hw_number_t hwirq;
 
        hwirq = fwspec->param[0];
+       gc = irq_get_domain_generic_chip(d, hwirq);
 
        irq_map_generic_chip(d, virq, hwirq);
        irq_domain_set_info(d, virq, hwirq, &gc->chip_types->chip, gc,
@@ -129,8 +204,9 @@ struct irq_domain_ops irq_exti_domain_ops = {
        .free   = stm32_exti_free,
 };
 
-static int __init stm32_exti_init(struct device_node *node,
-                                 struct device_node *parent)
+static int
+__init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks,
+                      int bank_nr, struct device_node *node)
 {
        unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
        int nr_irqs, nr_exti, ret, i;
@@ -144,23 +220,16 @@ static int __init stm32_exti_init(struct device_node *node,
                return -ENOMEM;
        }
 
-       /* Determine number of irqs supported */
-       writel_relaxed(~0UL, base + EXTI_RTSR);
-       nr_exti = fls(readl_relaxed(base + EXTI_RTSR));
-       writel_relaxed(0, base + EXTI_RTSR);
-
-       pr_info("%pOF: %d External IRQs detected\n", node, nr_exti);
-
-       domain = irq_domain_add_linear(node, nr_exti,
+       domain = irq_domain_add_linear(node, bank_nr * IRQS_PER_BANK,
                                       &irq_exti_domain_ops, NULL);
        if (!domain) {
                pr_err("%s: Could not register interrupt domain.\n",
-                               node->name);
+                      node->name);
                ret = -ENOMEM;
                goto out_unmap;
        }
 
-       ret = irq_alloc_domain_generic_chips(domain, nr_exti, 1, "exti",
+       ret = irq_alloc_domain_generic_chips(domain, IRQS_PER_BANK, 1, "exti",
                                             handle_edge_irq, clr, 0, 0);
        if (ret) {
                pr_err("%pOF: Could not allocate generic interrupt chip.\n",
@@ -168,18 +237,41 @@ static int __init stm32_exti_init(struct device_node *node,
                goto out_free_domain;
        }
 
-       gc = domain->gc->gc[0];
-       gc->reg_base                         = base;
-       gc->chip_types->type               = IRQ_TYPE_EDGE_BOTH;
-       gc->chip_types->chip.name          = gc->chip_types[0].chip.name;
-       gc->chip_types->chip.irq_ack       = irq_gc_ack_set_bit;
-       gc->chip_types->chip.irq_mask      = irq_gc_mask_clr_bit;
-       gc->chip_types->chip.irq_unmask    = irq_gc_mask_set_bit;
-       gc->chip_types->chip.irq_set_type  = stm32_irq_set_type;
-       gc->chip_types->chip.irq_set_wake  = stm32_irq_set_wake;
-       gc->chip_types->regs.ack           = EXTI_PR;
-       gc->chip_types->regs.mask          = EXTI_IMR;
-       gc->chip_types->handler            = handle_edge_irq;
+       for (i = 0; i < bank_nr; i++) {
+               const struct stm32_exti_bank *stm32_bank = stm32_exti_banks[i];
+               u32 irqs_mask;
+
+               gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
+
+               gc->reg_base = base;
+               gc->chip_types->type = IRQ_TYPE_EDGE_BOTH;
+               gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit;
+               gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit;
+               gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit;
+               gc->chip_types->chip.irq_set_type = stm32_irq_set_type;
+               gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake;
+               gc->chip_types->regs.ack = stm32_bank->pr_ofst;
+               gc->chip_types->regs.mask = stm32_bank->imr_ofst;
+               gc->private = (void *)stm32_bank;
+
+               /* Determine number of irqs supported */
+               writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst);
+               irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst);
+               nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst));
+
+               /*
+                * This IP has no reset, so after hot reboot we should
+                * clear registers to avoid residue
+                */
+               writel_relaxed(0, base + stm32_bank->imr_ofst);
+               writel_relaxed(0, base + stm32_bank->emr_ofst);
+               writel_relaxed(0, base + stm32_bank->rtsr_ofst);
+               writel_relaxed(0, base + stm32_bank->ftsr_ofst);
+               writel_relaxed(~0UL, base + stm32_bank->pr_ofst);
+
+               pr_info("%s: bank%d, External IRQs available:%#x\n",
+                       node->full_name, i, irqs_mask);
+       }
 
        nr_irqs = of_irq_count(node);
        for (i = 0; i < nr_irqs; i++) {
@@ -198,4 +290,20 @@ out_unmap:
        return ret;
 }
 
-IRQCHIP_DECLARE(stm32_exti, "st,stm32-exti", stm32_exti_init);
+static int __init stm32f4_exti_of_init(struct device_node *np,
+                                      struct device_node *parent)
+{
+       return stm32_exti_init(stm32f4xx_exti_banks,
+                       ARRAY_SIZE(stm32f4xx_exti_banks), np);
+}
+
+IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init);
+
+static int __init stm32h7_exti_of_init(struct device_node *np,
+                                      struct device_node *parent)
+{
+       return stm32_exti_init(stm32h7xx_exti_banks,
+                       ARRAY_SIZE(stm32h7xx_exti_banks), np);
+}
+
+IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init);
index dbc4a3e63396f49662128006ad1d9dff2ea9ce71..15db69d8ba697deb1426eff545c872c8bfc6e62d 100644 (file)
@@ -30,8 +30,6 @@
 
 /*#define DEBUG_ADB_IOP*/
 
-extern void iop_ism_irq(int, void *);
-
 static struct adb_request *current_req;
 static struct adb_request *last_req;
 #if 0
@@ -266,7 +264,7 @@ int adb_iop_autopoll(int devs)
 void adb_iop_poll(void)
 {
        if (adb_iop_state == idle) adb_iop_start();
-       iop_ism_irq(0, (void *) ADB_IOP);
+       iop_ism_irq_poll(ADB_IOP);
 }
 
 int adb_iop_reset_bus(void)
index ea9bdc85a21dedc4a62d1fe3845d7366452c4d13..899ec1f4c83368919b76bcb0ed0b599015b706c8 100644 (file)
@@ -103,7 +103,7 @@ static DEFINE_MUTEX(smu_part_access);
 static int smu_irq_inited;
 static unsigned long smu_cmdbuf_abs;
 
-static void smu_i2c_retry(unsigned long data);
+static void smu_i2c_retry(struct timer_list *t);
 
 /*
  * SMU driver low level stuff
@@ -582,9 +582,7 @@ static int smu_late_init(void)
        if (!smu)
                return 0;
 
-       init_timer(&smu->i2c_timer);
-       smu->i2c_timer.function = smu_i2c_retry;
-       smu->i2c_timer.data = (unsigned long)smu;
+       timer_setup(&smu->i2c_timer, smu_i2c_retry, 0);
 
        if (smu->db_node) {
                smu->db_irq = irq_of_parse_and_map(smu->db_node, 0);
@@ -755,7 +753,7 @@ static void smu_i2c_complete_command(struct smu_i2c_cmd *cmd, int fail)
 }
 
 
-static void smu_i2c_retry(unsigned long data)
+static void smu_i2c_retry(struct timer_list *unused)
 {
        struct smu_i2c_cmd      *cmd = smu->cmd_i2c_cur;
 
@@ -795,7 +793,7 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
                BUG_ON(cmd != smu->cmd_i2c_cur);
                if (!smu_irq_inited) {
                        mdelay(5);
-                       smu_i2c_retry(0);
+                       smu_i2c_retry(NULL);
                        return;
                }
                mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5));
index bb682c926b0a048ab1918ba13a89c140dff19d96..bcb29df9549eb80512a2c9b4c5d299e941a790c0 100644 (file)
@@ -57,6 +57,7 @@ struct altera_mbox {
 
        /* If the controller supports only RX polling mode */
        struct timer_list rxpoll_timer;
+       struct mbox_chan *chan;
 };
 
 static struct altera_mbox *mbox_chan_to_altera_mbox(struct mbox_chan *chan)
@@ -138,12 +139,11 @@ static void altera_mbox_rx_data(struct mbox_chan *chan)
        }
 }
 
-static void altera_mbox_poll_rx(unsigned long data)
+static void altera_mbox_poll_rx(struct timer_list *t)
 {
-       struct mbox_chan *chan = (struct mbox_chan *)data;
-       struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+       struct altera_mbox *mbox = from_timer(mbox, t, rxpoll_timer);
 
-       altera_mbox_rx_data(chan);
+       altera_mbox_rx_data(mbox->chan);
 
        mod_timer(&mbox->rxpoll_timer,
                  jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
@@ -206,8 +206,8 @@ static int altera_mbox_startup_receiver(struct mbox_chan *chan)
 
 polling:
        /* Setup polling timer */
-       setup_timer(&mbox->rxpoll_timer, altera_mbox_poll_rx,
-                   (unsigned long)chan);
+       mbox->chan = chan;
+       timer_setup(&mbox->rxpoll_timer, altera_mbox_poll_rx, 0);
        mod_timer(&mbox->rxpoll_timer,
                  jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
 
index 9b7005e1345e1a2b0f76ddc8e429a070d4c65790..e5a69679cfa2a0ca4d60b4e18788db21a849ec66 100644 (file)
@@ -69,7 +69,6 @@
 
 #include "mailbox.h"
 
-#define MAX_PCC_SUBSPACES      256
 #define MBOX_IRQ_NAME          "pcc-mbox"
 
 static struct mbox_chan *pcc_mbox_channels;
index d216a8f7bc224c815c383cc588dd24b04c94ea1c..33bb074d694120a209ebac11d5e7ef93a3f445a3 100644 (file)
@@ -347,7 +347,7 @@ static void __cache_size_refresh(void)
        BUG_ON(!mutex_is_locked(&dm_bufio_clients_lock));
        BUG_ON(dm_bufio_client_count < 0);
 
-       dm_bufio_cache_size_latch = ACCESS_ONCE(dm_bufio_cache_size);
+       dm_bufio_cache_size_latch = READ_ONCE(dm_bufio_cache_size);
 
        /*
         * Use default if set to 0 and report the actual cache size used.
@@ -960,7 +960,7 @@ static void __get_memory_limit(struct dm_bufio_client *c,
 {
        unsigned long buffers;
 
-       if (unlikely(ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch)) {
+       if (unlikely(READ_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch)) {
                if (mutex_trylock(&dm_bufio_clients_lock)) {
                        __cache_size_refresh();
                        mutex_unlock(&dm_bufio_clients_lock);
@@ -1600,7 +1600,7 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp)
 
 static unsigned long get_retain_buffers(struct dm_bufio_client *c)
 {
-        unsigned long retain_bytes = ACCESS_ONCE(dm_bufio_retain_bytes);
+        unsigned long retain_bytes = READ_ONCE(dm_bufio_retain_bytes);
         return retain_bytes >> (c->sectors_per_block_bits + SECTOR_SHIFT);
 }
 
@@ -1647,7 +1647,7 @@ dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct dm_bufio_client *c = container_of(shrink, struct dm_bufio_client, shrinker);
 
-       return ACCESS_ONCE(c->n_buffers[LIST_CLEAN]) + ACCESS_ONCE(c->n_buffers[LIST_DIRTY]);
+       return READ_ONCE(c->n_buffers[LIST_CLEAN]) + READ_ONCE(c->n_buffers[LIST_DIRTY]);
 }
 
 /*
@@ -1818,7 +1818,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_set_sector_offset);
 
 static unsigned get_max_age_hz(void)
 {
-       unsigned max_age = ACCESS_ONCE(dm_bufio_max_age);
+       unsigned max_age = READ_ONCE(dm_bufio_max_age);
 
        if (max_age > UINT_MAX / HZ)
                max_age = UINT_MAX / HZ;
index 096fe9b66c50749cb841bcbafc4bc6cb6ca63be7..8c5756e1df9475237fca4a08460946bd114d93b0 100644 (file)
@@ -6,6 +6,7 @@
  * This file is released under the GPL.
  */
 
+#include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/device-mapper.h>
 #include <linux/dm-io.h>
@@ -80,13 +81,13 @@ struct journal_entry {
 #define journal_entry_tag(ic, je)              ((__u8 *)&(je)->last_bytes[(ic)->sectors_per_block])
 
 #if BITS_PER_LONG == 64
-#define journal_entry_set_sector(je, x)                do { smp_wmb(); ACCESS_ONCE((je)->u.sector) = cpu_to_le64(x); } while (0)
+#define journal_entry_set_sector(je, x)                do { smp_wmb(); WRITE_ONCE((je)->u.sector, cpu_to_le64(x)); } while (0)
 #define journal_entry_get_sector(je)           le64_to_cpu((je)->u.sector)
 #elif defined(CONFIG_LBDAF)
-#define journal_entry_set_sector(je, x)                do { (je)->u.s.sector_lo = cpu_to_le32(x); smp_wmb(); ACCESS_ONCE((je)->u.s.sector_hi) = cpu_to_le32((x) >> 32); } while (0)
+#define journal_entry_set_sector(je, x)                do { (je)->u.s.sector_lo = cpu_to_le32(x); smp_wmb(); WRITE_ONCE((je)->u.s.sector_hi, cpu_to_le32((x) >> 32)); } while (0)
 #define journal_entry_get_sector(je)           le64_to_cpu((je)->u.sector)
 #else
-#define journal_entry_set_sector(je, x)                do { (je)->u.s.sector_lo = cpu_to_le32(x); smp_wmb(); ACCESS_ONCE((je)->u.s.sector_hi) = cpu_to_le32(0); } while (0)
+#define journal_entry_set_sector(je, x)                do { (je)->u.s.sector_lo = cpu_to_le32(x); smp_wmb(); WRITE_ONCE((je)->u.s.sector_hi, cpu_to_le32(0)); } while (0)
 #define journal_entry_get_sector(je)           le32_to_cpu((je)->u.s.sector_lo)
 #endif
 #define journal_entry_is_unused(je)            ((je)->u.s.sector_hi == cpu_to_le32(-1))
@@ -320,7 +321,7 @@ static void dm_integrity_io_error(struct dm_integrity_c *ic, const char *msg, in
 
 static int dm_integrity_failed(struct dm_integrity_c *ic)
 {
-       return ACCESS_ONCE(ic->failed);
+       return READ_ONCE(ic->failed);
 }
 
 static commit_id_t dm_integrity_commit_id(struct dm_integrity_c *ic, unsigned i,
@@ -1545,7 +1546,7 @@ retry_kmap:
                smp_mb();
                if (unlikely(waitqueue_active(&ic->copy_to_journal_wait)))
                        wake_up(&ic->copy_to_journal_wait);
-               if (ACCESS_ONCE(ic->free_sectors) <= ic->free_sectors_threshold) {
+               if (READ_ONCE(ic->free_sectors) <= ic->free_sectors_threshold) {
                        queue_work(ic->commit_wq, &ic->commit_work);
                } else {
                        schedule_autocommit(ic);
@@ -1798,7 +1799,7 @@ static void integrity_commit(struct work_struct *w)
        ic->n_committed_sections += commit_sections;
        spin_unlock_irq(&ic->endio_wait.lock);
 
-       if (ACCESS_ONCE(ic->free_sectors) <= ic->free_sectors_threshold)
+       if (READ_ONCE(ic->free_sectors) <= ic->free_sectors_threshold)
                queue_work(ic->writer_wq, &ic->writer_work);
 
 release_flush_bios:
@@ -1980,7 +1981,7 @@ static void integrity_writer(struct work_struct *w)
        unsigned prev_free_sectors;
 
        /* the following test is not needed, but it tests the replay code */
-       if (ACCESS_ONCE(ic->suspending))
+       if (READ_ONCE(ic->suspending))
                return;
 
        spin_lock_irq(&ic->endio_wait.lock);
index cf2c67e35eafe75353e016d48efefd9aadd36291..eb45cc3df31da109bcb9846967cbf8926d7524b8 100644 (file)
@@ -107,7 +107,7 @@ static void io_job_start(struct dm_kcopyd_throttle *t)
 try_again:
        spin_lock_irq(&throttle_spinlock);
 
-       throttle = ACCESS_ONCE(t->throttle);
+       throttle = READ_ONCE(t->throttle);
 
        if (likely(throttle >= 100))
                goto skip_limit;
@@ -157,7 +157,7 @@ static void io_job_finish(struct dm_kcopyd_throttle *t)
 
        t->num_io_jobs--;
 
-       if (likely(ACCESS_ONCE(t->throttle) >= 100))
+       if (likely(READ_ONCE(t->throttle) >= 100))
                goto skip_limit;
 
        if (!t->num_io_jobs) {
index 11f273d2f018e722b1e9480c5a5eb0e59b0f0048..3f88c9d32f7ecc9a66613d6eb0a3df26cf1dc788 100644 (file)
@@ -366,7 +366,7 @@ static struct pgpath *choose_path_in_pg(struct multipath *m,
 
        pgpath = path_to_pgpath(path);
 
-       if (unlikely(lockless_dereference(m->current_pg) != pg)) {
+       if (unlikely(READ_ONCE(m->current_pg) != pg)) {
                /* Only update current_pgpath if pg changed */
                spin_lock_irqsave(&m->lock, flags);
                m->current_pgpath = pgpath;
@@ -390,7 +390,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes)
        }
 
        /* Were we instructed to switch PG? */
-       if (lockless_dereference(m->next_pg)) {
+       if (READ_ONCE(m->next_pg)) {
                spin_lock_irqsave(&m->lock, flags);
                pg = m->next_pg;
                if (!pg) {
@@ -406,7 +406,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes)
 
        /* Don't change PG until it has no remaining paths */
 check_current_pg:
-       pg = lockless_dereference(m->current_pg);
+       pg = READ_ONCE(m->current_pg);
        if (pg) {
                pgpath = choose_path_in_pg(m, pg, nr_bytes);
                if (!IS_ERR_OR_NULL(pgpath))
@@ -473,7 +473,7 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
        struct request *clone;
 
        /* Do we need to select a new pgpath? */
-       pgpath = lockless_dereference(m->current_pgpath);
+       pgpath = READ_ONCE(m->current_pgpath);
        if (!pgpath || !test_bit(MPATHF_QUEUE_IO, &m->flags))
                pgpath = choose_pgpath(m, nr_bytes);
 
@@ -535,7 +535,7 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio, struct dm_m
        bool queue_io;
 
        /* Do we need to select a new pgpath? */
-       pgpath = lockless_dereference(m->current_pgpath);
+       pgpath = READ_ONCE(m->current_pgpath);
        queue_io = test_bit(MPATHF_QUEUE_IO, &m->flags);
        if (!pgpath || !queue_io)
                pgpath = choose_pgpath(m, nr_bytes);
@@ -1804,7 +1804,7 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
        struct pgpath *current_pgpath;
        int r;
 
-       current_pgpath = lockless_dereference(m->current_pgpath);
+       current_pgpath = READ_ONCE(m->current_pgpath);
        if (!current_pgpath)
                current_pgpath = choose_pgpath(m, 0);
 
@@ -1826,7 +1826,7 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
        }
 
        if (r == -ENOTCONN) {
-               if (!lockless_dereference(m->current_pg)) {
+               if (!READ_ONCE(m->current_pg)) {
                        /* Path status changed, redo selection */
                        (void) choose_pgpath(m, 0);
                }
@@ -1895,9 +1895,9 @@ static int multipath_busy(struct dm_target *ti)
                return (m->queue_mode != DM_TYPE_MQ_REQUEST_BASED);
 
        /* Guess which priority_group will be used at next mapping time */
-       pg = lockless_dereference(m->current_pg);
-       next_pg = lockless_dereference(m->next_pg);
-       if (unlikely(!lockless_dereference(m->current_pgpath) && next_pg))
+       pg = READ_ONCE(m->current_pg);
+       next_pg = READ_ONCE(m->next_pg);
+       if (unlikely(!READ_ONCE(m->current_pgpath) && next_pg))
                pg = next_pg;
 
        if (!pg) {
index a7868503d1352dfee4927ceeac246d39160685a5..29bc51084c82be8527e65c9cd157c54b86a708cd 100644 (file)
@@ -432,7 +432,7 @@ do_sync_free:
                synchronize_rcu_expedited();
                dm_stat_free(&s->rcu_head);
        } else {
-               ACCESS_ONCE(dm_stat_need_rcu_barrier) = 1;
+               WRITE_ONCE(dm_stat_need_rcu_barrier, 1);
                call_rcu(&s->rcu_head, dm_stat_free);
        }
        return 0;
@@ -640,12 +640,12 @@ void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw,
                 */
                last = raw_cpu_ptr(stats->last);
                stats_aux->merged =
-                       (bi_sector == (ACCESS_ONCE(last->last_sector) &&
+                       (bi_sector == (READ_ONCE(last->last_sector) &&
                                       ((bi_rw == WRITE) ==
-                                       (ACCESS_ONCE(last->last_rw) == WRITE))
+                                       (READ_ONCE(last->last_rw) == WRITE))
                                       ));
-               ACCESS_ONCE(last->last_sector) = end_sector;
-               ACCESS_ONCE(last->last_rw) = bi_rw;
+               WRITE_ONCE(last->last_sector, end_sector);
+               WRITE_ONCE(last->last_rw, bi_rw);
        }
 
        rcu_read_lock();
@@ -694,22 +694,22 @@ static void __dm_stat_init_temporary_percpu_totals(struct dm_stat_shared *shared
 
        for_each_possible_cpu(cpu) {
                p = &s->stat_percpu[cpu][x];
-               shared->tmp.sectors[READ] += ACCESS_ONCE(p->sectors[READ]);
-               shared->tmp.sectors[WRITE] += ACCESS_ONCE(p->sectors[WRITE]);
-               shared->tmp.ios[READ] += ACCESS_ONCE(p->ios[READ]);
-               shared->tmp.ios[WRITE] += ACCESS_ONCE(p->ios[WRITE]);
-               shared->tmp.merges[READ] += ACCESS_ONCE(p->merges[READ]);
-               shared->tmp.merges[WRITE] += ACCESS_ONCE(p->merges[WRITE]);
-               shared->tmp.ticks[READ] += ACCESS_ONCE(p->ticks[READ]);
-               shared->tmp.ticks[WRITE] += ACCESS_ONCE(p->ticks[WRITE]);
-               shared->tmp.io_ticks[READ] += ACCESS_ONCE(p->io_ticks[READ]);
-               shared->tmp.io_ticks[WRITE] += ACCESS_ONCE(p->io_ticks[WRITE]);
-               shared->tmp.io_ticks_total += ACCESS_ONCE(p->io_ticks_total);
-               shared->tmp.time_in_queue += ACCESS_ONCE(p->time_in_queue);
+               shared->tmp.sectors[READ] += READ_ONCE(p->sectors[READ]);
+               shared->tmp.sectors[WRITE] += READ_ONCE(p->sectors[WRITE]);
+               shared->tmp.ios[READ] += READ_ONCE(p->ios[READ]);
+               shared->tmp.ios[WRITE] += READ_ONCE(p->ios[WRITE]);
+               shared->tmp.merges[READ] += READ_ONCE(p->merges[READ]);
+               shared->tmp.merges[WRITE] += READ_ONCE(p->merges[WRITE]);
+               shared->tmp.ticks[READ] += READ_ONCE(p->ticks[READ]);
+               shared->tmp.ticks[WRITE] += READ_ONCE(p->ticks[WRITE]);
+               shared->tmp.io_ticks[READ] += READ_ONCE(p->io_ticks[READ]);
+               shared->tmp.io_ticks[WRITE] += READ_ONCE(p->io_ticks[WRITE]);
+               shared->tmp.io_ticks_total += READ_ONCE(p->io_ticks_total);
+               shared->tmp.time_in_queue += READ_ONCE(p->time_in_queue);
                if (s->n_histogram_entries) {
                        unsigned i;
                        for (i = 0; i < s->n_histogram_entries + 1; i++)
-                               shared->tmp.histogram[i] += ACCESS_ONCE(p->histogram[i]);
+                               shared->tmp.histogram[i] += READ_ONCE(p->histogram[i]);
                }
        }
 }
index 4c8de1ff78cac8ad8a575fcbd42c81a93d6bd79e..8d0ba879777e486cbc4f9fc84600fdc7ba82c5ba 100644 (file)
@@ -144,7 +144,7 @@ static unsigned switch_region_table_read(struct switch_ctx *sctx, unsigned long
 
        switch_get_position(sctx, region_nr, &region_index, &bit);
 
-       return (ACCESS_ONCE(sctx->region_table[region_index]) >> bit) &
+       return (READ_ONCE(sctx->region_table[region_index]) >> bit) &
                ((1 << sctx->region_table_entry_bits) - 1);
 }
 
index 1e25705209c27fbb8e62f5d096c9dbe157d82c77..89e5dff9b4cfc1b87049529238c5c01978345b81 100644 (file)
@@ -2431,7 +2431,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
        struct pool_c *pt = pool->ti->private;
        bool needs_check = dm_pool_metadata_needs_check(pool->pmd);
        enum pool_mode old_mode = get_pool_mode(pool);
-       unsigned long no_space_timeout = ACCESS_ONCE(no_space_timeout_secs) * HZ;
+       unsigned long no_space_timeout = READ_ONCE(no_space_timeout_secs) * HZ;
 
        /*
         * Never allow the pool to transition to PM_WRITE mode if user
index bda3caca23ca69af2fe97592aa817a29b87851d6..fba93237a78044cafc163779ce2a7085dd8543d6 100644 (file)
@@ -589,7 +589,7 @@ static void verity_prefetch_io(struct work_struct *work)
                verity_hash_at_level(v, pw->block, i, &hash_block_start, NULL);
                verity_hash_at_level(v, pw->block + pw->n_blocks - 1, i, &hash_block_end, NULL);
                if (!i) {
-                       unsigned cluster = ACCESS_ONCE(dm_verity_prefetch_cluster);
+                       unsigned cluster = READ_ONCE(dm_verity_prefetch_cluster);
 
                        cluster >>= v->data_dev_block_bits;
                        if (unlikely(!cluster))
index 4be85324f44dc26177c17bf9ab6acf451dca3fcf..8aaffa19b29af44301542a87e7e660589cc4ec30 100644 (file)
@@ -114,7 +114,7 @@ static unsigned reserved_bio_based_ios = RESERVED_BIO_BASED_IOS;
 
 static int __dm_get_module_param_int(int *module_param, int min, int max)
 {
-       int param = ACCESS_ONCE(*module_param);
+       int param = READ_ONCE(*module_param);
        int modified_param = 0;
        bool modified = true;
 
@@ -136,7 +136,7 @@ static int __dm_get_module_param_int(int *module_param, int min, int max)
 unsigned __dm_get_module_param(unsigned *module_param,
                               unsigned def, unsigned max)
 {
-       unsigned param = ACCESS_ONCE(*module_param);
+       unsigned param = READ_ONCE(*module_param);
        unsigned modified_param = 0;
 
        if (!param)
index 0ff1bbf6c90e5cebc782268313ce39f8c66f7270..447ddcbc9566ab7c869fcf77e6fd1c1b83aedab1 100644 (file)
@@ -2651,7 +2651,7 @@ state_show(struct md_rdev *rdev, char *page)
 {
        char *sep = ",";
        size_t len = 0;
-       unsigned long flags = ACCESS_ONCE(rdev->flags);
+       unsigned long flags = READ_ONCE(rdev->flags);
 
        if (test_bit(Faulty, &flags) ||
            (!test_bit(ExternalBbl, &flags) &&
index 928e24a071338ab6e1fe7668c8caa42b2803ccfe..7d9a50eed9db8fa64e650e02b51103c5efc7143a 100644 (file)
@@ -6072,7 +6072,7 @@ static inline sector_t raid5_sync_request(struct mddev *mddev, sector_t sector_n
         */
        rcu_read_lock();
        for (i = 0; i < conf->raid_disks; i++) {
-               struct md_rdev *rdev = ACCESS_ONCE(conf->disks[i].rdev);
+               struct md_rdev *rdev = READ_ONCE(conf->disks[i].rdev);
 
                if (rdev == NULL || test_bit(Faulty, &rdev->flags))
                        still_degraded = 1;
index 2322af1b87429aab67454c4ca7f7f486ab9bf211..53011629c9ad6c66ebfe1d7ca54e41af574cf5fd 100644 (file)
@@ -66,12 +66,12 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
 {
        ssize_t free;
 
-       /* ACCESS_ONCE() to load read pointer on writer side
+       /* READ_ONCE() to load read pointer on writer side
         * this pairs with smp_store_release() in dvb_ringbuffer_read(),
         * dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(),
         * or dvb_ringbuffer_reset()
         */
-       free = ACCESS_ONCE(rbuf->pread) - rbuf->pwrite;
+       free = READ_ONCE(rbuf->pread) - rbuf->pwrite;
        if (free <= 0)
                free += rbuf->size;
        return free-1;
@@ -143,7 +143,7 @@ ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, si
                todo -= split;
                /* smp_store_release() for read pointer update to ensure
                 * that buf is not overwritten until read is complete,
-                * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
+                * this pairs with READ_ONCE() in dvb_ringbuffer_free()
                 */
                smp_store_release(&rbuf->pread, 0);
        }
@@ -168,7 +168,7 @@ void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
                todo -= split;
                /* smp_store_release() for read pointer update to ensure
                 * that buf is not overwritten until read is complete,
-                * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
+                * this pairs with READ_ONCE() in dvb_ringbuffer_free()
                 */
                smp_store_release(&rbuf->pread, 0);
        }
index ad5b25b896990eab69616ad6e454bb2bd2d9601c..8289ee482f495b63c5a55bf57b03a5e82e8779fe 100644 (file)
@@ -330,10 +330,10 @@ static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
 static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
 static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw);
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static void pvr2_hdw_quiescent_timeout(unsigned long);
-static void pvr2_hdw_decoder_stabilization_timeout(unsigned long);
-static void pvr2_hdw_encoder_wait_timeout(unsigned long);
-static void pvr2_hdw_encoder_run_timeout(unsigned long);
+static void pvr2_hdw_quiescent_timeout(struct timer_list *);
+static void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *);
+static void pvr2_hdw_encoder_wait_timeout(struct timer_list *);
+static void pvr2_hdw_encoder_run_timeout(struct timer_list *);
 static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32);
 static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
                                unsigned int timeout,int probe_fl,
@@ -2373,18 +2373,15 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        }
        if (!hdw) goto fail;
 
-       setup_timer(&hdw->quiescent_timer, pvr2_hdw_quiescent_timeout,
-                   (unsigned long)hdw);
+       timer_setup(&hdw->quiescent_timer, pvr2_hdw_quiescent_timeout, 0);
 
-       setup_timer(&hdw->decoder_stabilization_timer,
-                   pvr2_hdw_decoder_stabilization_timeout,
-                   (unsigned long)hdw);
+       timer_setup(&hdw->decoder_stabilization_timer,
+                   pvr2_hdw_decoder_stabilization_timeout, 0);
 
-       setup_timer(&hdw->encoder_wait_timer, pvr2_hdw_encoder_wait_timeout,
-                   (unsigned long)hdw);
+       timer_setup(&hdw->encoder_wait_timer, pvr2_hdw_encoder_wait_timeout,
+                   0);
 
-       setup_timer(&hdw->encoder_run_timer, pvr2_hdw_encoder_run_timeout,
-                   (unsigned long)hdw);
+       timer_setup(&hdw->encoder_run_timer, pvr2_hdw_encoder_run_timeout, 0);
 
        hdw->master_state = PVR2_STATE_DEAD;
 
@@ -3539,10 +3536,16 @@ static void pvr2_ctl_read_complete(struct urb *urb)
        complete(&hdw->ctl_done);
 }
 
+struct hdw_timer {
+       struct timer_list timer;
+       struct pvr2_hdw *hdw;
+};
 
-static void pvr2_ctl_timeout(unsigned long data)
+static void pvr2_ctl_timeout(struct timer_list *t)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       struct hdw_timer *timer = from_timer(timer, t, timer);
+       struct pvr2_hdw *hdw = timer->hdw;
+
        if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
                hdw->ctl_timeout_flag = !0;
                if (hdw->ctl_write_pend_flag)
@@ -3564,7 +3567,10 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
 {
        unsigned int idx;
        int status = 0;
-       struct timer_list timer;
+       struct hdw_timer timer = {
+               .hdw = hdw,
+       };
+
        if (!hdw->ctl_lock_held) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "Attempted to execute control transfer without lock!!");
@@ -3621,8 +3627,8 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
        hdw->ctl_timeout_flag = 0;
        hdw->ctl_write_pend_flag = 0;
        hdw->ctl_read_pend_flag = 0;
-       setup_timer(&timer, pvr2_ctl_timeout, (unsigned long)hdw);
-       timer.expires = jiffies + timeout;
+       timer_setup_on_stack(&timer.timer, pvr2_ctl_timeout, 0);
+       timer.timer.expires = jiffies + timeout;
 
        if (write_len && write_data) {
                hdw->cmd_debug_state = 2;
@@ -3677,7 +3683,7 @@ status);
        }
 
        /* Start timer */
-       add_timer(&timer);
+       add_timer(&timer.timer);
 
        /* Now wait for all I/O to complete */
        hdw->cmd_debug_state = 4;
@@ -3687,7 +3693,7 @@ status);
        hdw->cmd_debug_state = 5;
 
        /* Stop timer */
-       del_timer_sync(&timer);
+       del_timer_sync(&timer.timer);
 
        hdw->cmd_debug_state = 6;
        status = 0;
@@ -3769,6 +3775,8 @@ status);
        if ((status < 0) && (!probe_fl)) {
                pvr2_hdw_render_useless(hdw);
        }
+       destroy_timer_on_stack(&timer.timer);
+
        return status;
 }
 
@@ -4366,9 +4374,9 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw)
 
 
 /* Timeout function for quiescent timer. */
-static void pvr2_hdw_quiescent_timeout(unsigned long data)
+static void pvr2_hdw_quiescent_timeout(struct timer_list *t)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       struct pvr2_hdw *hdw = from_timer(hdw, t, quiescent_timer);
        hdw->state_decoder_quiescent = !0;
        trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
        hdw->state_stale = !0;
@@ -4377,9 +4385,9 @@ static void pvr2_hdw_quiescent_timeout(unsigned long data)
 
 
 /* Timeout function for decoder stabilization timer. */
-static void pvr2_hdw_decoder_stabilization_timeout(unsigned long data)
+static void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *t)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       struct pvr2_hdw *hdw = from_timer(hdw, t, decoder_stabilization_timer);
        hdw->state_decoder_ready = !0;
        trace_stbit("state_decoder_ready", hdw->state_decoder_ready);
        hdw->state_stale = !0;
@@ -4388,9 +4396,9 @@ static void pvr2_hdw_decoder_stabilization_timeout(unsigned long data)
 
 
 /* Timeout function for encoder wait timer. */
-static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
+static void pvr2_hdw_encoder_wait_timeout(struct timer_list *t)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_wait_timer);
        hdw->state_encoder_waitok = !0;
        trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
        hdw->state_stale = !0;
@@ -4399,9 +4407,9 @@ static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
 
 
 /* Timeout function for encoder run timer. */
-static void pvr2_hdw_encoder_run_timeout(unsigned long data)
+static void pvr2_hdw_encoder_run_timeout(struct timer_list *t)
 {
-       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_run_timer);
        if (!hdw->state_encoder_runok) {
                hdw->state_encoder_runok = !0;
                trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
index 48db922075e2adbcec880950edf7a9700827218b..bcdca9fbef51cc802d34b74a4fab19abd308b1bc 100644 (file)
@@ -59,6 +59,7 @@ struct jmb38x_ms_host {
        unsigned int            block_pos;
        unsigned long           timeout_jiffies;
        struct timer_list       timer;
+       struct memstick_host    *msh;
        struct memstick_request *req;
        unsigned char           cmd_flags;
        unsigned char           io_pos;
@@ -592,10 +593,10 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void jmb38x_ms_abort(unsigned long data)
+static void jmb38x_ms_abort(struct timer_list *t)
 {
-       struct memstick_host *msh = (struct memstick_host *)data;
-       struct jmb38x_ms_host *host = memstick_priv(msh);
+       struct jmb38x_ms_host *host = from_timer(host, t, timer);
+       struct memstick_host *msh = host->msh;
        unsigned long flags;
 
        dev_dbg(&host->chip->pdev->dev, "abort\n");
@@ -878,6 +879,7 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt)
                return NULL;
 
        host = memstick_priv(msh);
+       host->msh = msh;
        host->chip = jm;
        host->addr = ioremap(pci_resource_start(jm->pdev, cnt),
                             pci_resource_len(jm->pdev, cnt));
@@ -897,7 +899,7 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt)
 
        msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8;
 
-       setup_timer(&host->timer, jmb38x_ms_abort, (unsigned long)msh);
+       timer_setup(&host->timer, jmb38x_ms_abort, 0);
 
        if (!request_irq(host->irq, jmb38x_ms_isr, IRQF_SHARED, host->host_id,
                         msh))
index d5cfb503b9d693b1686bd1a13774ae0ac37bbf4c..627d6e62fe3133319f0da646a0b9f84fc12445d1 100644 (file)
@@ -616,9 +616,9 @@ static void r592_update_card_detect(struct r592_device *dev)
 }
 
 /* Timer routine that fires 1 second after last card detection event, */
-static void r592_detect_timer(long unsigned int data)
+static void r592_detect_timer(struct timer_list *t)
 {
-       struct r592_device *dev = (struct r592_device *)data;
+       struct r592_device *dev = from_timer(dev, t, detect_timer);
        r592_update_card_detect(dev);
        memstick_detect_change(dev->host);
 }
@@ -770,8 +770,7 @@ static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        spin_lock_init(&dev->io_thread_lock);
        init_completion(&dev->dma_done);
        INIT_KFIFO(dev->pio_fifo);
-       setup_timer(&dev->detect_timer,
-               r592_detect_timer, (long unsigned int)dev);
+       timer_setup(&dev->detect_timer, r592_detect_timer, 0);
 
        /* Host initialization */
        host->caps = MEMSTICK_CAP_PAR4;
index 7bafa72f8f5789ccec9cb9975e5f8aac293a0bcc..bed205849d027020e260dfa4b68ac3fba8aaa9ed 100644 (file)
@@ -538,9 +538,9 @@ static int tifm_ms_set_param(struct memstick_host *msh,
        return 0;
 }
 
-static void tifm_ms_abort(unsigned long data)
+static void tifm_ms_abort(struct timer_list *t)
 {
-       struct tifm_ms *host = (struct tifm_ms *)data;
+       struct tifm_ms *host = from_timer(host, t, timer);
 
        dev_dbg(&host->dev->dev, "status %x\n",
                readl(host->dev->addr + SOCK_MS_STATUS));
@@ -575,7 +575,7 @@ static int tifm_ms_probe(struct tifm_dev *sock)
        host->dev = sock;
        host->timeout_jiffies = msecs_to_jiffies(1000);
 
-       setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host);
+       timer_setup(&host->timer, tifm_ms_abort, 0);
        tasklet_init(&host->notify, tifm_ms_req_tasklet, (unsigned long)msh);
 
        msh->request = tifm_ms_submit_req;
index 981b3ef71e477ab976e67e20280271e8f133655a..ed7f0c61c59a969d4b57e253a0019c8dbb766ab4 100644 (file)
@@ -56,122 +56,54 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
                            size_t count, loff_t *off);
 
 #ifdef CONFIG_KPROBES
-static void lkdtm_handler(void);
+static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs);
 static ssize_t lkdtm_debugfs_entry(struct file *f,
                                   const char __user *user_buf,
                                   size_t count, loff_t *off);
-
-
-/* jprobe entry point handlers. */
-static unsigned int jp_do_irq(unsigned int irq)
-{
-       lkdtm_handler();
-       jprobe_return();
-       return 0;
-}
-
-static irqreturn_t jp_handle_irq_event(unsigned int irq,
-                                      struct irqaction *action)
-{
-       lkdtm_handler();
-       jprobe_return();
-       return 0;
-}
-
-static void jp_tasklet_action(struct softirq_action *a)
-{
-       lkdtm_handler();
-       jprobe_return();
-}
-
-static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
-{
-       lkdtm_handler();
-       jprobe_return();
-}
-
-struct scan_control;
-
-static unsigned long jp_shrink_inactive_list(unsigned long max_scan,
-                                            struct zone *zone,
-                                            struct scan_control *sc)
-{
-       lkdtm_handler();
-       jprobe_return();
-       return 0;
-}
-
-static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
-                           const enum hrtimer_mode mode)
-{
-       lkdtm_handler();
-       jprobe_return();
-       return 0;
-}
-
-static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
-{
-       lkdtm_handler();
-       jprobe_return();
-       return 0;
-}
-
-# ifdef CONFIG_IDE
-static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file,
-                       struct block_device *bdev, unsigned int cmd,
-                       unsigned long arg)
-{
-       lkdtm_handler();
-       jprobe_return();
-       return 0;
-}
-# endif
+# define CRASHPOINT_KPROBE(_symbol)                            \
+               .kprobe = {                                     \
+                       .symbol_name = (_symbol),               \
+                       .pre_handler = lkdtm_kprobe_handler,    \
+               },
+# define CRASHPOINT_WRITE(_symbol)                             \
+               (_symbol) ? lkdtm_debugfs_entry : direct_entry
+#else
+# define CRASHPOINT_KPROBE(_symbol)
+# define CRASHPOINT_WRITE(_symbol)             direct_entry
 #endif
 
 /* Crash points */
 struct crashpoint {
        const char *name;
        const struct file_operations fops;
-       struct jprobe jprobe;
+       struct kprobe kprobe;
 };
 
-#define CRASHPOINT(_name, _write, _symbol, _entry)             \
+#define CRASHPOINT(_name, _symbol)                             \
        {                                                       \
                .name = _name,                                  \
                .fops = {                                       \
                        .read   = lkdtm_debugfs_read,           \
                        .llseek = generic_file_llseek,          \
                        .open   = lkdtm_debugfs_open,           \
-                       .write  = _write,                       \
-               },                                              \
-               .jprobe = {                                     \
-                       .kp.symbol_name = _symbol,              \
-                       .entry = (kprobe_opcode_t *)_entry,     \
+                       .write  = CRASHPOINT_WRITE(_symbol)     \
                },                                              \
+               CRASHPOINT_KPROBE(_symbol)                      \
        }
 
 /* Define the possible places where we can trigger a crash point. */
-struct crashpoint crashpoints[] = {
-       CRASHPOINT("DIRECT",                    direct_entry,
-                  NULL,                        NULL),
+static struct crashpoint crashpoints[] = {
+       CRASHPOINT("DIRECT",             NULL),
 #ifdef CONFIG_KPROBES
-       CRASHPOINT("INT_HARDWARE_ENTRY",        lkdtm_debugfs_entry,
-                  "do_IRQ",                    jp_do_irq),
-       CRASHPOINT("INT_HW_IRQ_EN",             lkdtm_debugfs_entry,
-                  "handle_IRQ_event",          jp_handle_irq_event),
-       CRASHPOINT("INT_TASKLET_ENTRY",         lkdtm_debugfs_entry,
-                  "tasklet_action",            jp_tasklet_action),
-       CRASHPOINT("FS_DEVRW",                  lkdtm_debugfs_entry,
-                  "ll_rw_block",               jp_ll_rw_block),
-       CRASHPOINT("MEM_SWAPOUT",               lkdtm_debugfs_entry,
-                  "shrink_inactive_list",      jp_shrink_inactive_list),
-       CRASHPOINT("TIMERADD",                  lkdtm_debugfs_entry,
-                  "hrtimer_start",             jp_hrtimer_start),
-       CRASHPOINT("SCSI_DISPATCH_CMD",         lkdtm_debugfs_entry,
-                  "scsi_dispatch_cmd",         jp_scsi_dispatch_cmd),
+       CRASHPOINT("INT_HARDWARE_ENTRY", "do_IRQ"),
+       CRASHPOINT("INT_HW_IRQ_EN",      "handle_IRQ_event"),
+       CRASHPOINT("INT_TASKLET_ENTRY",  "tasklet_action"),
+       CRASHPOINT("FS_DEVRW",           "ll_rw_block"),
+       CRASHPOINT("MEM_SWAPOUT",        "shrink_inactive_list"),
+       CRASHPOINT("TIMERADD",           "hrtimer_start"),
+       CRASHPOINT("SCSI_DISPATCH_CMD",  "scsi_dispatch_cmd"),
 # ifdef CONFIG_IDE
-       CRASHPOINT("IDE_CORE_CP",               lkdtm_debugfs_entry,
-                  "generic_ide_ioctl",         jp_generic_ide_ioctl),
+       CRASHPOINT("IDE_CORE_CP",        "generic_ide_ioctl"),
 # endif
 #endif
 };
@@ -254,8 +186,8 @@ struct crashtype crashtypes[] = {
 };
 
 
-/* Global jprobe entry and crashtype. */
-static struct jprobe *lkdtm_jprobe;
+/* Global kprobe entry and crashtype. */
+static struct kprobe *lkdtm_kprobe;
 struct crashpoint *lkdtm_crashpoint;
 struct crashtype *lkdtm_crashtype;
 
@@ -298,7 +230,8 @@ static struct crashtype *find_crashtype(const char *name)
  */
 static noinline void lkdtm_do_action(struct crashtype *crashtype)
 {
-       BUG_ON(!crashtype || !crashtype->func);
+       if (WARN_ON(!crashtype || !crashtype->func))
+               return;
        crashtype->func();
 }
 
@@ -308,22 +241,22 @@ static int lkdtm_register_cpoint(struct crashpoint *crashpoint,
        int ret;
 
        /* If this doesn't have a symbol, just call immediately. */
-       if (!crashpoint->jprobe.kp.symbol_name) {
+       if (!crashpoint->kprobe.symbol_name) {
                lkdtm_do_action(crashtype);
                return 0;
        }
 
-       if (lkdtm_jprobe != NULL)
-               unregister_jprobe(lkdtm_jprobe);
+       if (lkdtm_kprobe != NULL)
+               unregister_kprobe(lkdtm_kprobe);
 
        lkdtm_crashpoint = crashpoint;
        lkdtm_crashtype = crashtype;
-       lkdtm_jprobe = &crashpoint->jprobe;
-       ret = register_jprobe(lkdtm_jprobe);
+       lkdtm_kprobe = &crashpoint->kprobe;
+       ret = register_kprobe(lkdtm_kprobe);
        if (ret < 0) {
-               pr_info("Couldn't register jprobe %s\n",
-                       crashpoint->jprobe.kp.symbol_name);
-               lkdtm_jprobe = NULL;
+               pr_info("Couldn't register kprobe %s\n",
+                       crashpoint->kprobe.symbol_name);
+               lkdtm_kprobe = NULL;
                lkdtm_crashpoint = NULL;
                lkdtm_crashtype = NULL;
        }
@@ -336,13 +269,14 @@ static int lkdtm_register_cpoint(struct crashpoint *crashpoint,
 static int crash_count = DEFAULT_COUNT;
 static DEFINE_SPINLOCK(crash_count_lock);
 
-/* Called by jprobe entry points. */
-static void lkdtm_handler(void)
+/* Called by kprobe entry points. */
+static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs)
 {
        unsigned long flags;
        bool do_it = false;
 
-       BUG_ON(!lkdtm_crashpoint || !lkdtm_crashtype);
+       if (WARN_ON(!lkdtm_crashpoint || !lkdtm_crashtype))
+               return 0;
 
        spin_lock_irqsave(&crash_count_lock, flags);
        crash_count--;
@@ -357,6 +291,8 @@ static void lkdtm_handler(void)
 
        if (do_it)
                lkdtm_do_action(lkdtm_crashtype);
+
+       return 0;
 }
 
 static ssize_t lkdtm_debugfs_entry(struct file *f,
@@ -556,8 +492,8 @@ static void __exit lkdtm_module_exit(void)
        /* Handle test-specific clean-up. */
        lkdtm_usercopy_exit();
 
-       if (lkdtm_jprobe != NULL)
-               unregister_jprobe(lkdtm_jprobe);
+       if (lkdtm_kprobe != NULL)
+               unregister_kprobe(lkdtm_kprobe);
 
        pr_info("Crash point unregistered\n");
 }
index 78b3172c8e6e298fa8f74c93db2850c4f96b95a8..f4f17552c9b804c3667c6d3a7c702ac30a4eaac0 100644 (file)
@@ -225,7 +225,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * MEI requires to resume from runtime suspend mode
         * in order to perform link reset flow upon system suspend.
         */
-       pdev->dev_flags |= PCI_DEV_FLAGS_NEEDS_RESUME;
+       dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
 
        /*
         * ME maps runtime suspend/resume to D0i states,
index 0566f9bfa7de6c68c44d245e7e1deec84c345f71..e1b909123fb02d25539c8645cc51e4f4960035ff 100644 (file)
@@ -141,7 +141,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * MEI requires to resume from runtime suspend mode
         * in order to perform link reset flow upon system suspend.
         */
-       pdev->dev_flags |= PCI_DEV_FLAGS_NEEDS_RESUME;
+       dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
 
        /*
         * TXE maps runtime suspend/resume to own power gating states,
index 637cc468674278bb3a804f896ee588ca0c4e8fe4..b665757ca89a853243d929e6051fa993471544d3 100644 (file)
@@ -138,7 +138,7 @@ void scif_rb_commit(struct scif_rb *rb)
         * the read barrier in scif_rb_count(..)
         */
        wmb();
-       ACCESS_ONCE(*rb->write_ptr) = rb->current_write_offset;
+       WRITE_ONCE(*rb->write_ptr, rb->current_write_offset);
 #ifdef CONFIG_INTEL_MIC_CARD
        /*
         * X100 Si bug: For the case where a Core is performing an EXT_WR
@@ -147,7 +147,7 @@ void scif_rb_commit(struct scif_rb *rb)
         * This way, if ordering is violated for the Interrupt Message, it will
         * fall just behind the first Posted associated with the first EXT_WR.
         */
-       ACCESS_ONCE(*rb->write_ptr) = rb->current_write_offset;
+       WRITE_ONCE(*rb->write_ptr, rb->current_write_offset);
 #endif
 }
 
@@ -210,7 +210,7 @@ void scif_rb_update_read_ptr(struct scif_rb *rb)
         * scif_rb_space(..)
         */
        mb();
-       ACCESS_ONCE(*rb->read_ptr) = new_offset;
+       WRITE_ONCE(*rb->read_ptr, new_offset);
 #ifdef CONFIG_INTEL_MIC_CARD
        /*
         * X100 Si Bug: For the case where a Core is performing an EXT_WR
@@ -219,7 +219,7 @@ void scif_rb_update_read_ptr(struct scif_rb *rb)
         * This way, if ordering is violated for the Interrupt Message, it will
         * fall just behind the first Posted associated with the first EXT_WR.
         */
-       ACCESS_ONCE(*rb->read_ptr) = new_offset;
+       WRITE_ONCE(*rb->read_ptr, new_offset);
 #endif
 }
 
index e1ef8daedd5ac273d2f3caa711f2a347f1d2069b..a036dbb4101e7011a00374d206ded520ae9959a6 100644 (file)
@@ -277,7 +277,7 @@ retry:
                 * Need to restart list traversal if there has been
                 * an asynchronous list entry deletion.
                 */
-               if (ACCESS_ONCE(ep->rma_info.async_list_del))
+               if (READ_ONCE(ep->rma_info.async_list_del))
                        goto retry;
        }
        mutex_unlock(&ep->rma_info.rma_lock);
index 7f327121e6d7c43416a3ca6820cd39111796d683..0c775d6fcf590d1b1691926d144237ff02c960e1 100644 (file)
@@ -172,9 +172,9 @@ struct xpc_arch_operations xpc_arch_ops;
  * Timer function to enforce the timelimit on the partition disengage.
  */
 static void
-xpc_timeout_partition_disengage(unsigned long data)
+xpc_timeout_partition_disengage(struct timer_list *t)
 {
-       struct xpc_partition *part = (struct xpc_partition *)data;
+       struct xpc_partition *part = from_timer(part, t, disengage_timer);
 
        DBUG_ON(time_is_after_jiffies(part->disengage_timeout));
 
@@ -190,7 +190,7 @@ xpc_timeout_partition_disengage(unsigned long data)
  * specify when the next timeout should occur.
  */
 static void
-xpc_hb_beater(unsigned long dummy)
+xpc_hb_beater(struct timer_list *unused)
 {
        xpc_arch_ops.increment_heartbeat();
 
@@ -205,8 +205,7 @@ static void
 xpc_start_hb_beater(void)
 {
        xpc_arch_ops.heartbeat_init();
-       init_timer(&xpc_hb_timer);
-       xpc_hb_timer.function = xpc_hb_beater;
+       timer_setup(&xpc_hb_timer, xpc_hb_beater, 0);
        xpc_hb_beater(0);
 }
 
@@ -931,10 +930,8 @@ xpc_setup_partitions(void)
                part->act_state = XPC_P_AS_INACTIVE;
                XPC_SET_REASON(part, 0, 0);
 
-               init_timer(&part->disengage_timer);
-               part->disengage_timer.function =
-                   xpc_timeout_partition_disengage;
-               part->disengage_timer.data = (unsigned long)part;
+               timer_setup(&part->disengage_timer,
+                           xpc_timeout_partition_disengage, 0);
 
                part->setup_state = XPC_P_SS_UNSET;
                init_waitqueue_head(&part->teardown_wq);
index 7d71c04fc938873fa1798dfcc0e6a6b7a043346a..5a12d2a5404988718a19b7131dd125183e31912d 100644 (file)
@@ -323,16 +323,16 @@ xpc_handle_notify_IRQ_sn2(int irq, void *dev_id)
  * was received.
  */
 static void
-xpc_check_for_dropped_notify_IRQ_sn2(struct xpc_partition *part)
+xpc_check_for_dropped_notify_IRQ_sn2(struct timer_list *t)
 {
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
+       struct xpc_partition *part =
+               from_timer(part, t, sn.sn2.dropped_notify_IRQ_timer);
 
        if (xpc_part_ref(part)) {
                xpc_check_for_sent_chctl_flags_sn2(part);
 
-               part_sn2->dropped_notify_IRQ_timer.expires = jiffies +
-                   XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL;
-               add_timer(&part_sn2->dropped_notify_IRQ_timer);
+               t->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL;
+               add_timer(t);
                xpc_part_deref(part);
        }
 }
@@ -1232,10 +1232,7 @@ xpc_setup_ch_structures_sn2(struct xpc_partition *part)
 
        /* Setup a timer to check for dropped notify IRQs */
        timer = &part_sn2->dropped_notify_IRQ_timer;
-       init_timer(timer);
-       timer->function =
-           (void (*)(unsigned long))xpc_check_for_dropped_notify_IRQ_sn2;
-       timer->data = (unsigned long)part;
+       timer_setup(timer, xpc_check_for_dropped_notify_IRQ_sn2, 0);
        timer->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL;
        add_timer(timer);
 
index 1e688bfec56728c3d00ebc353031c26fde29f187..9047c0a529b28221da8458668cd0673c0c5144d0 100644 (file)
@@ -1271,7 +1271,7 @@ static int __init vmballoon_init(void)
         * Check if we are running on VMware's hypervisor and bail out
         * if we are not.
         */
-       if (x86_hyper != &x86_hyper_vmware)
+       if (x86_hyper_type != X86_HYPER_VMWARE)
                return -ENODEV;
 
        for (is_2m_pages = 0; is_2m_pages < VMW_BALLOON_NUM_PAGE_SIZES;
index 2ad7b5c691569e37cd366425c62c6ae0514f3857..ea80ff4cd7f99bc27aab2951ea8d3f9d67624912 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/hdreg.h>
 #include <linux/kdev_t.h>
 #include <linux/blkdev.h>
+#include <linux/cdev.h>
 #include <linux/mutex.h>
 #include <linux/scatterlist.h>
 #include <linux/string_helpers.h>
@@ -86,6 +87,7 @@ static int max_devices;
 #define MAX_DEVICES 256
 
 static DEFINE_IDA(mmc_blk_ida);
+static DEFINE_IDA(mmc_rpmb_ida);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -96,6 +98,7 @@ struct mmc_blk_data {
        struct gendisk  *disk;
        struct mmc_queue queue;
        struct list_head part;
+       struct list_head rpmbs;
 
        unsigned int    flags;
 #define MMC_BLK_CMD23  (1 << 0)        /* Can do SET_BLOCK_COUNT for multiblock */
@@ -121,6 +124,32 @@ struct mmc_blk_data {
        int     area_type;
 };
 
+/* Device type for RPMB character devices */
+static dev_t mmc_rpmb_devt;
+
+/* Bus type for RPMB character devices */
+static struct bus_type mmc_rpmb_bus_type = {
+       .name = "mmc_rpmb",
+};
+
+/**
+ * struct mmc_rpmb_data - special RPMB device type for these areas
+ * @dev: the device for the RPMB area
+ * @chrdev: character device for the RPMB area
+ * @id: unique device ID number
+ * @part_index: partition index (0 on first)
+ * @md: parent MMC block device
+ * @node: list item, so we can put this device on a list
+ */
+struct mmc_rpmb_data {
+       struct device dev;
+       struct cdev chrdev;
+       int id;
+       unsigned int part_index;
+       struct mmc_blk_data *md;
+       struct list_head node;
+};
+
 static DEFINE_MUTEX(open_lock);
 
 module_param(perdev_minors, int, 0444);
@@ -299,6 +328,7 @@ struct mmc_blk_ioc_data {
        struct mmc_ioc_cmd ic;
        unsigned char *buf;
        u64 buf_bytes;
+       struct mmc_rpmb_data *rpmb;
 };
 
 static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
@@ -437,14 +467,25 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
        struct mmc_request mrq = {};
        struct scatterlist sg;
        int err;
-       bool is_rpmb = false;
+       unsigned int target_part;
        u32 status = 0;
 
        if (!card || !md || !idata)
                return -EINVAL;
 
-       if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
-               is_rpmb = true;
+       /*
+        * The RPMB accesses comes in from the character device, so we
+        * need to target these explicitly. Else we just target the
+        * partition type for the block device the ioctl() was issued
+        * on.
+        */
+       if (idata->rpmb) {
+               /* Support multiple RPMB partitions */
+               target_part = idata->rpmb->part_index;
+               target_part |= EXT_CSD_PART_CONFIG_ACC_RPMB;
+       } else {
+               target_part = md->part_type;
+       }
 
        cmd.opcode = idata->ic.opcode;
        cmd.arg = idata->ic.arg;
@@ -488,7 +529,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
 
        mrq.cmd = &cmd;
 
-       err = mmc_blk_part_switch(card, md->part_type);
+       err = mmc_blk_part_switch(card, target_part);
        if (err)
                return err;
 
@@ -498,7 +539,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
                        return err;
        }
 
-       if (is_rpmb) {
+       if (idata->rpmb) {
                err = mmc_set_blockcount(card, data.blocks,
                        idata->ic.write_flag & (1 << 31));
                if (err)
@@ -538,7 +579,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
 
        memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp));
 
-       if (is_rpmb) {
+       if (idata->rpmb) {
                /*
                 * Ensure RPMB command has completed by polling CMD13
                 * "Send Status".
@@ -554,7 +595,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
 }
 
 static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
-                            struct mmc_ioc_cmd __user *ic_ptr)
+                            struct mmc_ioc_cmd __user *ic_ptr,
+                            struct mmc_rpmb_data *rpmb)
 {
        struct mmc_blk_ioc_data *idata;
        struct mmc_blk_ioc_data *idatas[1];
@@ -566,6 +608,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
        idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
        if (IS_ERR(idata))
                return PTR_ERR(idata);
+       /* This will be NULL on non-RPMB ioctl():s */
+       idata->rpmb = rpmb;
 
        card = md->queue.card;
        if (IS_ERR(card)) {
@@ -581,7 +625,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
                idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
                __GFP_RECLAIM);
        idatas[0] = idata;
-       req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
+       req_to_mmc_queue_req(req)->drv_op =
+               rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
        req_to_mmc_queue_req(req)->drv_op_data = idatas;
        req_to_mmc_queue_req(req)->ioc_count = 1;
        blk_execute_rq(mq->queue, NULL, req, 0);
@@ -596,7 +641,8 @@ cmd_done:
 }
 
 static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
-                                  struct mmc_ioc_multi_cmd __user *user)
+                                  struct mmc_ioc_multi_cmd __user *user,
+                                  struct mmc_rpmb_data *rpmb)
 {
        struct mmc_blk_ioc_data **idata = NULL;
        struct mmc_ioc_cmd __user *cmds = user->cmds;
@@ -627,6 +673,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
                        num_of_cmds = i;
                        goto cmd_err;
                }
+               /* This will be NULL on non-RPMB ioctl():s */
+               idata[i]->rpmb = rpmb;
        }
 
        card = md->queue.card;
@@ -643,7 +691,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
        req = blk_get_request(mq->queue,
                idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
                __GFP_RECLAIM);
-       req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
+       req_to_mmc_queue_req(req)->drv_op =
+               rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
        req_to_mmc_queue_req(req)->drv_op_data = idata;
        req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
        blk_execute_rq(mq->queue, NULL, req, 0);
@@ -691,7 +740,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
                if (!md)
                        return -EINVAL;
                ret = mmc_blk_ioctl_cmd(md,
-                                       (struct mmc_ioc_cmd __user *)arg);
+                                       (struct mmc_ioc_cmd __user *)arg,
+                                       NULL);
                mmc_blk_put(md);
                return ret;
        case MMC_IOC_MULTI_CMD:
@@ -702,7 +752,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
                if (!md)
                        return -EINVAL;
                ret = mmc_blk_ioctl_multi_cmd(md,
-                                       (struct mmc_ioc_multi_cmd __user *)arg);
+                                       (struct mmc_ioc_multi_cmd __user *)arg,
+                                       NULL);
                mmc_blk_put(md);
                return ret;
        default:
@@ -1152,18 +1203,6 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
        md->reset_done &= ~type;
 }
 
-int mmc_access_rpmb(struct mmc_queue *mq)
-{
-       struct mmc_blk_data *md = mq->blkdata;
-       /*
-        * If this is a RPMB partition access, return ture
-        */
-       if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
-               return true;
-
-       return false;
-}
-
 /*
  * The non-block commands come back from the block layer after it queued it and
  * processed it with all other requests and then they get issued in this
@@ -1174,17 +1213,19 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
        struct mmc_queue_req *mq_rq;
        struct mmc_card *card = mq->card;
        struct mmc_blk_data *md = mq->blkdata;
-       struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
        struct mmc_blk_ioc_data **idata;
+       bool rpmb_ioctl;
        u8 **ext_csd;
        u32 status;
        int ret;
        int i;
 
        mq_rq = req_to_mmc_queue_req(req);
+       rpmb_ioctl = (mq_rq->drv_op == MMC_DRV_OP_IOCTL_RPMB);
 
        switch (mq_rq->drv_op) {
        case MMC_DRV_OP_IOCTL:
+       case MMC_DRV_OP_IOCTL_RPMB:
                idata = mq_rq->drv_op_data;
                for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
                        ret = __mmc_blk_ioctl_cmd(card, md, idata[i]);
@@ -1192,8 +1233,8 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
                                break;
                }
                /* Always switch back to main area after RPMB access */
-               if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
-                       mmc_blk_part_switch(card, main_md->part_type);
+               if (rpmb_ioctl)
+                       mmc_blk_part_switch(card, 0);
                break;
        case MMC_DRV_OP_BOOT_WP:
                ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -1534,25 +1575,27 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card,
 }
 
 static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
-                             int disable_multi, bool *do_rel_wr,
-                             bool *do_data_tag)
+                             int disable_multi, bool *do_rel_wr_p,
+                             bool *do_data_tag_p)
 {
        struct mmc_blk_data *md = mq->blkdata;
        struct mmc_card *card = md->queue.card;
        struct mmc_blk_request *brq = &mqrq->brq;
        struct request *req = mmc_queue_req_to_req(mqrq);
+       bool do_rel_wr, do_data_tag;
 
        /*
         * Reliable writes are used to implement Forced Unit Access and
         * are supported only on MMCs.
         */
-       *do_rel_wr = (req->cmd_flags & REQ_FUA) &&
-                    rq_data_dir(req) == WRITE &&
-                    (md->flags & MMC_BLK_REL_WR);
+       do_rel_wr = (req->cmd_flags & REQ_FUA) &&
+                   rq_data_dir(req) == WRITE &&
+                   (md->flags & MMC_BLK_REL_WR);
 
        memset(brq, 0, sizeof(struct mmc_blk_request));
 
        brq->mrq.data = &brq->data;
+       brq->mrq.tag = req->tag;
 
        brq->stop.opcode = MMC_STOP_TRANSMISSION;
        brq->stop.arg = 0;
@@ -1567,6 +1610,14 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
 
        brq->data.blksz = 512;
        brq->data.blocks = blk_rq_sectors(req);
+       brq->data.blk_addr = blk_rq_pos(req);
+
+       /*
+        * The command queue supports 2 priorities: "high" (1) and "simple" (0).
+        * The eMMC will give "high" priority tasks priority over "simple"
+        * priority tasks. Here we always set "simple" priority by not setting
+        * MMC_DATA_PRIO.
+        */
 
        /*
         * The block layer doesn't support all sector count
@@ -1596,18 +1647,23 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
                                                brq->data.blocks);
        }
 
-       if (*do_rel_wr)
+       if (do_rel_wr) {
                mmc_apply_rel_rw(brq, card, req);
+               brq->data.flags |= MMC_DATA_REL_WR;
+       }
 
        /*
         * Data tag is used only during writing meta data to speed
         * up write and any subsequent read of this meta data
         */
-       *do_data_tag = card->ext_csd.data_tag_unit_size &&
-                      (req->cmd_flags & REQ_META) &&
-                      (rq_data_dir(req) == WRITE) &&
-                      ((brq->data.blocks * brq->data.blksz) >=
-                       card->ext_csd.data_tag_unit_size);
+       do_data_tag = card->ext_csd.data_tag_unit_size &&
+                     (req->cmd_flags & REQ_META) &&
+                     (rq_data_dir(req) == WRITE) &&
+                     ((brq->data.blocks * brq->data.blksz) >=
+                      card->ext_csd.data_tag_unit_size);
+
+       if (do_data_tag)
+               brq->data.flags |= MMC_DATA_DAT_TAG;
 
        mmc_set_data_timeout(&brq->data, card);
 
@@ -1634,6 +1690,12 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
        }
 
        mqrq->areq.mrq = &brq->mrq;
+
+       if (do_rel_wr_p)
+               *do_rel_wr_p = do_rel_wr;
+
+       if (do_data_tag_p)
+               *do_data_tag_p = do_data_tag;
 }
 
 static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
@@ -1948,7 +2010,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
        if (req && !mq->qcnt)
                /* claim host only for the first request */
-               mmc_get_card(card);
+               mmc_get_card(card, NULL);
 
        ret = mmc_blk_part_switch(card, md->part_type);
        if (ret) {
@@ -2011,7 +2073,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
 out:
        if (!mq->qcnt)
-               mmc_put_card(card);
+               mmc_put_card(card, NULL);
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -2068,6 +2130,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 
        spin_lock_init(&md->lock);
        INIT_LIST_HEAD(&md->part);
+       INIT_LIST_HEAD(&md->rpmbs);
        md->usage = 1;
 
        ret = mmc_init_queue(&md->queue, card, &md->lock, subname);
@@ -2186,6 +2249,158 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
        return 0;
 }
 
+/**
+ * mmc_rpmb_ioctl() - ioctl handler for the RPMB chardev
+ * @filp: the character device file
+ * @cmd: the ioctl() command
+ * @arg: the argument from userspace
+ *
+ * This will essentially just redirect the ioctl()s coming in over to
+ * the main block device spawning the RPMB character device.
+ */
+static long mmc_rpmb_ioctl(struct file *filp, unsigned int cmd,
+                          unsigned long arg)
+{
+       struct mmc_rpmb_data *rpmb = filp->private_data;
+       int ret;
+
+       switch (cmd) {
+       case MMC_IOC_CMD:
+               ret = mmc_blk_ioctl_cmd(rpmb->md,
+                                       (struct mmc_ioc_cmd __user *)arg,
+                                       rpmb);
+               break;
+       case MMC_IOC_MULTI_CMD:
+               ret = mmc_blk_ioctl_multi_cmd(rpmb->md,
+                                       (struct mmc_ioc_multi_cmd __user *)arg,
+                                       rpmb);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long mmc_rpmb_ioctl_compat(struct file *filp, unsigned int cmd,
+                             unsigned long arg)
+{
+       return mmc_rpmb_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static int mmc_rpmb_chrdev_open(struct inode *inode, struct file *filp)
+{
+       struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
+                                                 struct mmc_rpmb_data, chrdev);
+
+       get_device(&rpmb->dev);
+       filp->private_data = rpmb;
+       mmc_blk_get(rpmb->md->disk);
+
+       return nonseekable_open(inode, filp);
+}
+
+static int mmc_rpmb_chrdev_release(struct inode *inode, struct file *filp)
+{
+       struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
+                                                 struct mmc_rpmb_data, chrdev);
+
+       put_device(&rpmb->dev);
+       mmc_blk_put(rpmb->md);
+
+       return 0;
+}
+
+static const struct file_operations mmc_rpmb_fileops = {
+       .release = mmc_rpmb_chrdev_release,
+       .open = mmc_rpmb_chrdev_open,
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .unlocked_ioctl = mmc_rpmb_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = mmc_rpmb_ioctl_compat,
+#endif
+};
+
+static void mmc_blk_rpmb_device_release(struct device *dev)
+{
+       struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev);
+
+       ida_simple_remove(&mmc_rpmb_ida, rpmb->id);
+       kfree(rpmb);
+}
+
+static int mmc_blk_alloc_rpmb_part(struct mmc_card *card,
+                                  struct mmc_blk_data *md,
+                                  unsigned int part_index,
+                                  sector_t size,
+                                  const char *subname)
+{
+       int devidx, ret;
+       char rpmb_name[DISK_NAME_LEN];
+       char cap_str[10];
+       struct mmc_rpmb_data *rpmb;
+
+       /* This creates the minor number for the RPMB char device */
+       devidx = ida_simple_get(&mmc_rpmb_ida, 0, max_devices, GFP_KERNEL);
+       if (devidx < 0)
+               return devidx;
+
+       rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL);
+       if (!rpmb) {
+               ida_simple_remove(&mmc_rpmb_ida, devidx);
+               return -ENOMEM;
+       }
+
+       snprintf(rpmb_name, sizeof(rpmb_name),
+                "mmcblk%u%s", card->host->index, subname ? subname : "");
+
+       rpmb->id = devidx;
+       rpmb->part_index = part_index;
+       rpmb->dev.init_name = rpmb_name;
+       rpmb->dev.bus = &mmc_rpmb_bus_type;
+       rpmb->dev.devt = MKDEV(MAJOR(mmc_rpmb_devt), rpmb->id);
+       rpmb->dev.parent = &card->dev;
+       rpmb->dev.release = mmc_blk_rpmb_device_release;
+       device_initialize(&rpmb->dev);
+       dev_set_drvdata(&rpmb->dev, rpmb);
+       rpmb->md = md;
+
+       cdev_init(&rpmb->chrdev, &mmc_rpmb_fileops);
+       rpmb->chrdev.owner = THIS_MODULE;
+       ret = cdev_device_add(&rpmb->chrdev, &rpmb->dev);
+       if (ret) {
+               pr_err("%s: could not add character device\n", rpmb_name);
+               goto out_put_device;
+       }
+
+       list_add(&rpmb->node, &md->rpmbs);
+
+       string_get_size((u64)size, 512, STRING_UNITS_2,
+                       cap_str, sizeof(cap_str));
+
+       pr_info("%s: %s %s partition %u %s, chardev (%d:%d)\n",
+               rpmb_name, mmc_card_id(card),
+               mmc_card_name(card), EXT_CSD_PART_CONFIG_ACC_RPMB, cap_str,
+               MAJOR(mmc_rpmb_devt), rpmb->id);
+
+       return 0;
+
+out_put_device:
+       put_device(&rpmb->dev);
+       return ret;
+}
+
+static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb)
+
+{
+       cdev_device_del(&rpmb->chrdev, &rpmb->dev);
+       put_device(&rpmb->dev);
+}
+
 /* MMC Physical partitions consist of two boot partitions and
  * up to four general purpose partitions.
  * For each partition enabled in EXT_CSD a block device will be allocatedi
@@ -2194,13 +2409,26 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
 
 static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
 {
-       int idx, ret = 0;
+       int idx, ret;
 
        if (!mmc_card_mmc(card))
                return 0;
 
        for (idx = 0; idx < card->nr_parts; idx++) {
-               if (card->part[idx].size) {
+               if (card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB) {
+                       /*
+                        * RPMB partitions does not provide block access, they
+                        * are only accessed using ioctl():s. Thus create
+                        * special RPMB block devices that do not have a
+                        * backing block queue for these.
+                        */
+                       ret = mmc_blk_alloc_rpmb_part(card, md,
+                               card->part[idx].part_cfg,
+                               card->part[idx].size >> 9,
+                               card->part[idx].name);
+                       if (ret)
+                               return ret;
+               } else if (card->part[idx].size) {
                        ret = mmc_blk_alloc_part(card, md,
                                card->part[idx].part_cfg,
                                card->part[idx].size >> 9,
@@ -2212,7 +2440,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
                }
        }
 
-       return ret;
+       return 0;
 }
 
 static void mmc_blk_remove_req(struct mmc_blk_data *md)
@@ -2249,7 +2477,15 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
 {
        struct list_head *pos, *q;
        struct mmc_blk_data *part_md;
+       struct mmc_rpmb_data *rpmb;
 
+       /* Remove RPMB partitions */
+       list_for_each_safe(pos, q, &md->rpmbs) {
+               rpmb = list_entry(pos, struct mmc_rpmb_data, node);
+               list_del(pos);
+               mmc_blk_remove_rpmb_part(rpmb);
+       }
+       /* Remove block partitions */
        list_for_each_safe(pos, q, &md->part) {
                part_md = list_entry(pos, struct mmc_blk_data, part);
                list_del(pos);
@@ -2568,6 +2804,17 @@ static int __init mmc_blk_init(void)
 {
        int res;
 
+       res  = bus_register(&mmc_rpmb_bus_type);
+       if (res < 0) {
+               pr_err("mmcblk: could not register RPMB bus type\n");
+               return res;
+       }
+       res = alloc_chrdev_region(&mmc_rpmb_devt, 0, MAX_DEVICES, "rpmb");
+       if (res < 0) {
+               pr_err("mmcblk: failed to allocate rpmb chrdev region\n");
+               goto out_bus_unreg;
+       }
+
        if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
                pr_info("mmcblk: using %d minors per device\n", perdev_minors);
 
@@ -2575,16 +2822,20 @@ static int __init mmc_blk_init(void)
 
        res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
        if (res)
-               goto out;
+               goto out_chrdev_unreg;
 
        res = mmc_register_driver(&mmc_driver);
        if (res)
-               goto out2;
+               goto out_blkdev_unreg;
 
        return 0;
- out2:
+
+out_blkdev_unreg:
        unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
- out:
+out_chrdev_unreg:
+       unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES);
+out_bus_unreg:
+       bus_unregister(&mmc_rpmb_bus_type);
        return res;
 }
 
@@ -2592,6 +2843,7 @@ static void __exit mmc_blk_exit(void)
 {
        mmc_unregister_driver(&mmc_driver);
        unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
+       unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES);
 }
 
 module_init(mmc_blk_init);
index 301246513a3709dfa73b9d07d2daab900252e5ba..a4b49e25fe963b135d71c0532ce0bf5c8951a3cd 100644 (file)
@@ -369,10 +369,17 @@ int mmc_add_card(struct mmc_card *card)
  */
 void mmc_remove_card(struct mmc_card *card)
 {
+       struct mmc_host *host = card->host;
+
 #ifdef CONFIG_DEBUG_FS
        mmc_remove_card_debugfs(card);
 #endif
 
+       if (host->cqe_enabled) {
+               host->cqe_ops->cqe_disable(host);
+               host->cqe_enabled = false;
+       }
+
        if (mmc_card_present(card)) {
                if (mmc_host_is_spi(card->host)) {
                        pr_info("%s: SPI card removed\n",
index 66c9cf49ad2f11fe59de05eae716b6b797766cc4..1f0f44f4dd5f3d6ba24c724f3c870064b0bc1560 100644 (file)
@@ -266,7 +266,8 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
        host->ops->request(host, mrq);
 }
 
-static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
+static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq,
+                            bool cqe)
 {
        if (mrq->sbc) {
                pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
@@ -275,9 +276,12 @@ static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
        }
 
        if (mrq->cmd) {
-               pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
-                        mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg,
-                        mrq->cmd->flags);
+               pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n",
+                        mmc_hostname(host), cqe ? "CQE direct " : "",
+                        mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
+       } else if (cqe) {
+               pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n",
+                        mmc_hostname(host), mrq->tag, mrq->data->blk_addr);
        }
 
        if (mrq->data) {
@@ -333,7 +337,7 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
        return 0;
 }
 
-static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 {
        int err;
 
@@ -342,7 +346,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
        if (mmc_card_removed(host->card))
                return -ENOMEDIUM;
 
-       mmc_mrq_pr_debug(host, mrq);
+       mmc_mrq_pr_debug(host, mrq, false);
 
        WARN_ON(!host->claimed);
 
@@ -355,6 +359,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 
        return 0;
 }
+EXPORT_SYMBOL(mmc_start_request);
 
 /*
  * mmc_wait_data_done() - done callback for data request
@@ -482,6 +487,155 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
 }
 EXPORT_SYMBOL(mmc_wait_for_req_done);
 
+/*
+ * mmc_cqe_start_req - Start a CQE request.
+ * @host: MMC host to start the request
+ * @mrq: request to start
+ *
+ * Start the request, re-tuning if needed and it is possible. Returns an error
+ * code if the request fails to start or -EBUSY if CQE is busy.
+ */
+int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+       int err;
+
+       /*
+        * CQE cannot process re-tuning commands. Caller must hold retuning
+        * while CQE is in use.  Re-tuning can happen here only when CQE has no
+        * active requests i.e. this is the first.  Note, re-tuning will call
+        * ->cqe_off().
+        */
+       err = mmc_retune(host);
+       if (err)
+               goto out_err;
+
+       mrq->host = host;
+
+       mmc_mrq_pr_debug(host, mrq, true);
+
+       err = mmc_mrq_prep(host, mrq);
+       if (err)
+               goto out_err;
+
+       err = host->cqe_ops->cqe_request(host, mrq);
+       if (err)
+               goto out_err;
+
+       trace_mmc_request_start(host, mrq);
+
+       return 0;
+
+out_err:
+       if (mrq->cmd) {
+               pr_debug("%s: failed to start CQE direct CMD%u, error %d\n",
+                        mmc_hostname(host), mrq->cmd->opcode, err);
+       } else {
+               pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n",
+                        mmc_hostname(host), mrq->tag, err);
+       }
+       return err;
+}
+EXPORT_SYMBOL(mmc_cqe_start_req);
+
+/**
+ *     mmc_cqe_request_done - CQE has finished processing an MMC request
+ *     @host: MMC host which completed request
+ *     @mrq: MMC request which completed
+ *
+ *     CQE drivers should call this function when they have completed
+ *     their processing of a request.
+ */
+void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq)
+{
+       mmc_should_fail_request(host, mrq);
+
+       /* Flag re-tuning needed on CRC errors */
+       if ((mrq->cmd && mrq->cmd->error == -EILSEQ) ||
+           (mrq->data && mrq->data->error == -EILSEQ))
+               mmc_retune_needed(host);
+
+       trace_mmc_request_done(host, mrq);
+
+       if (mrq->cmd) {
+               pr_debug("%s: CQE req done (direct CMD%u): %d\n",
+                        mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->error);
+       } else {
+               pr_debug("%s: CQE transfer done tag %d\n",
+                        mmc_hostname(host), mrq->tag);
+       }
+
+       if (mrq->data) {
+               pr_debug("%s:     %d bytes transferred: %d\n",
+                        mmc_hostname(host),
+                        mrq->data->bytes_xfered, mrq->data->error);
+       }
+
+       mrq->done(mrq);
+}
+EXPORT_SYMBOL(mmc_cqe_request_done);
+
+/**
+ *     mmc_cqe_post_req - CQE post process of a completed MMC request
+ *     @host: MMC host
+ *     @mrq: MMC request to be processed
+ */
+void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+       if (host->cqe_ops->cqe_post_req)
+               host->cqe_ops->cqe_post_req(host, mrq);
+}
+EXPORT_SYMBOL(mmc_cqe_post_req);
+
+/* Arbitrary 1 second timeout */
+#define MMC_CQE_RECOVERY_TIMEOUT       1000
+
+/*
+ * mmc_cqe_recovery - Recover from CQE errors.
+ * @host: MMC host to recover
+ *
+ * Recovery consists of stopping CQE, stopping eMMC, discarding the queue in
+ * in eMMC, and discarding the queue in CQE. CQE must call
+ * mmc_cqe_request_done() on all requests. An error is returned if the eMMC
+ * fails to discard its queue.
+ */
+int mmc_cqe_recovery(struct mmc_host *host)
+{
+       struct mmc_command cmd;
+       int err;
+
+       mmc_retune_hold_now(host);
+
+       /*
+        * Recovery is expected seldom, if at all, but it reduces performance,
+        * so make sure it is not completely silent.
+        */
+       pr_warn("%s: running CQE recovery\n", mmc_hostname(host));
+
+       host->cqe_ops->cqe_recovery_start(host);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.opcode       = MMC_STOP_TRANSMISSION,
+       cmd.flags        = MMC_RSP_R1B | MMC_CMD_AC,
+       cmd.flags       &= ~MMC_RSP_CRC; /* Ignore CRC */
+       cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
+       mmc_wait_for_cmd(host, &cmd, 0);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.opcode       = MMC_CMDQ_TASK_MGMT;
+       cmd.arg          = 1; /* Discard entire queue */
+       cmd.flags        = MMC_RSP_R1B | MMC_CMD_AC;
+       cmd.flags       &= ~MMC_RSP_CRC; /* Ignore CRC */
+       cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
+       err = mmc_wait_for_cmd(host, &cmd, 0);
+
+       host->cqe_ops->cqe_recovery_finish(host);
+
+       mmc_retune_release(host);
+
+       return err;
+}
+EXPORT_SYMBOL(mmc_cqe_recovery);
+
 /**
  *     mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
  *     @host: MMC host
@@ -832,9 +986,36 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
 }
 EXPORT_SYMBOL(mmc_align_data_size);
 
+/*
+ * Allow claiming an already claimed host if the context is the same or there is
+ * no context but the task is the same.
+ */
+static inline bool mmc_ctx_matches(struct mmc_host *host, struct mmc_ctx *ctx,
+                                  struct task_struct *task)
+{
+       return host->claimer == ctx ||
+              (!ctx && task && host->claimer->task == task);
+}
+
+static inline void mmc_ctx_set_claimer(struct mmc_host *host,
+                                      struct mmc_ctx *ctx,
+                                      struct task_struct *task)
+{
+       if (!host->claimer) {
+               if (ctx)
+                       host->claimer = ctx;
+               else
+                       host->claimer = &host->default_ctx;
+       }
+       if (task)
+               host->claimer->task = task;
+}
+
 /**
  *     __mmc_claim_host - exclusively claim a host
  *     @host: mmc host to claim
+ *     @ctx: context that claims the host or NULL in which case the default
+ *     context will be used
  *     @abort: whether or not the operation should be aborted
  *
  *     Claim a host for a set of operations.  If @abort is non null and
@@ -842,8 +1023,10 @@ EXPORT_SYMBOL(mmc_align_data_size);
  *     that non-zero value without acquiring the lock.  Returns zero
  *     with the lock held otherwise.
  */
-int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
+int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
+                    atomic_t *abort)
 {
+       struct task_struct *task = ctx ? NULL : current;
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        int stop;
@@ -856,7 +1039,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
        while (1) {
                set_current_state(TASK_UNINTERRUPTIBLE);
                stop = abort ? atomic_read(abort) : 0;
-               if (stop || !host->claimed || host->claimer == current)
+               if (stop || !host->claimed || mmc_ctx_matches(host, ctx, task))
                        break;
                spin_unlock_irqrestore(&host->lock, flags);
                schedule();
@@ -865,7 +1048,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
        set_current_state(TASK_RUNNING);
        if (!stop) {
                host->claimed = 1;
-               host->claimer = current;
+               mmc_ctx_set_claimer(host, ctx, task);
                host->claim_cnt += 1;
                if (host->claim_cnt == 1)
                        pm = true;
@@ -900,6 +1083,7 @@ void mmc_release_host(struct mmc_host *host)
                spin_unlock_irqrestore(&host->lock, flags);
        } else {
                host->claimed = 0;
+               host->claimer->task = NULL;
                host->claimer = NULL;
                spin_unlock_irqrestore(&host->lock, flags);
                wake_up(&host->wq);
@@ -913,10 +1097,10 @@ EXPORT_SYMBOL(mmc_release_host);
  * This is a helper function, which fetches a runtime pm reference for the
  * card device and also claims the host.
  */
-void mmc_get_card(struct mmc_card *card)
+void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx)
 {
        pm_runtime_get_sync(&card->dev);
-       mmc_claim_host(card->host);
+       __mmc_claim_host(card->host, ctx, NULL);
 }
 EXPORT_SYMBOL(mmc_get_card);
 
@@ -924,9 +1108,13 @@ EXPORT_SYMBOL(mmc_get_card);
  * This is a helper function, which releases the host and drops the runtime
  * pm reference for the card device.
  */
-void mmc_put_card(struct mmc_card *card)
+void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx)
 {
-       mmc_release_host(card->host);
+       struct mmc_host *host = card->host;
+
+       WARN_ON(ctx && host->claimer != ctx);
+
+       mmc_release_host(host);
        pm_runtime_mark_last_busy(&card->dev);
        pm_runtime_put_autosuspend(&card->dev);
 }
@@ -1400,6 +1588,16 @@ EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
 
 #endif /* CONFIG_REGULATOR */
 
+/**
+ * mmc_regulator_get_supply - try to get VMMC and VQMMC regulators for a host
+ * @mmc: the host to regulate
+ *
+ * Returns 0 or errno. errno should be handled, it is either a critical error
+ * or -EPROBE_DEFER. 0 means no critical error but it does not mean all
+ * regulators have been found because they all are optional. If you require
+ * certain regulators, you need to check separately in your driver if they got
+ * populated after calling this function.
+ */
 int mmc_regulator_get_supply(struct mmc_host *mmc)
 {
        struct device *dev = mmc_dev(mmc);
@@ -1484,11 +1682,33 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
 
 }
 
+int mmc_host_set_uhs_voltage(struct mmc_host *host)
+{
+       u32 clock;
+
+       /*
+        * During a signal voltage level switch, the clock must be gated
+        * for 5 ms according to the SD spec
+        */
+       clock = host->ios.clock;
+       host->ios.clock = 0;
+       mmc_set_ios(host);
+
+       if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
+               return -EAGAIN;
+
+       /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
+       mmc_delay(10);
+       host->ios.clock = clock;
+       mmc_set_ios(host);
+
+       return 0;
+}
+
 int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
 {
        struct mmc_command cmd = {};
        int err = 0;
-       u32 clock;
 
        /*
         * If we cannot switch voltages, return failure so the caller
@@ -1520,15 +1740,8 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
                err = -EAGAIN;
                goto power_cycle;
        }
-       /*
-        * During a signal voltage level switch, the clock must be gated
-        * for 5 ms according to the SD spec
-        */
-       clock = host->ios.clock;
-       host->ios.clock = 0;
-       mmc_set_ios(host);
 
-       if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
+       if (mmc_host_set_uhs_voltage(host)) {
                /*
                 * Voltages may not have been switched, but we've already
                 * sent CMD11, so a power cycle is required anyway
@@ -1537,11 +1750,6 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
                goto power_cycle;
        }
 
-       /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
-       mmc_delay(10);
-       host->ios.clock = clock;
-       mmc_set_ios(host);
-
        /* Wait for at least 1 ms according to spec */
        mmc_delay(1);
 
index ca861091a776bb1c23db5e5b894a51df58ad2fbf..71e6c6d7ceb70df8841b21921ab9ebfd0d671d39 100644 (file)
@@ -49,6 +49,7 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
 int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
+int mmc_host_set_uhs_voltage(struct mmc_host *host);
 int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
@@ -107,6 +108,8 @@ static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
 void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
 bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
 
+int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq);
+
 struct mmc_async_req;
 
 struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
@@ -128,10 +131,11 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
 int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
                        bool is_rel_write);
 
-int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
+int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
+                    atomic_t *abort);
 void mmc_release_host(struct mmc_host *host);
-void mmc_get_card(struct mmc_card *card);
-void mmc_put_card(struct mmc_card *card);
+void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx);
+void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx);
 
 /**
  *     mmc_claim_host - exclusively claim a host
@@ -141,7 +145,11 @@ void mmc_put_card(struct mmc_card *card);
  */
 static inline void mmc_claim_host(struct mmc_host *host)
 {
-       __mmc_claim_host(host, NULL);
+       __mmc_claim_host(host, NULL, NULL);
 }
 
+int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq);
+void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq);
+int mmc_cqe_recovery(struct mmc_host *host);
+
 #endif
index ad88deb2e8f3b046838a3539841717951c33a6c6..35a9e4fd1a9f514ae61e4ec77455915e4870009e 100644 (file)
@@ -111,12 +111,6 @@ void mmc_retune_hold(struct mmc_host *host)
        host->hold_retune += 1;
 }
 
-void mmc_retune_hold_now(struct mmc_host *host)
-{
-       host->retune_now = 0;
-       host->hold_retune += 1;
-}
-
 void mmc_retune_release(struct mmc_host *host)
 {
        if (host->hold_retune)
@@ -124,6 +118,7 @@ void mmc_retune_release(struct mmc_host *host)
        else
                WARN_ON(1);
 }
+EXPORT_SYMBOL(mmc_retune_release);
 
 int mmc_retune(struct mmc_host *host)
 {
@@ -184,7 +179,7 @@ static void mmc_retune_timer(unsigned long data)
 int mmc_of_parse(struct mmc_host *host)
 {
        struct device *dev = host->parent;
-       u32 bus_width;
+       u32 bus_width, drv_type;
        int ret;
        bool cd_cap_invert, cd_gpio_invert = false;
        bool ro_cap_invert, ro_gpio_invert = false;
@@ -326,6 +321,15 @@ int mmc_of_parse(struct mmc_host *host)
        if (device_property_read_bool(dev, "no-mmc"))
                host->caps2 |= MMC_CAP2_NO_MMC;
 
+       /* Must be after "non-removable" check */
+       if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
+               if (host->caps & MMC_CAP_NONREMOVABLE)
+                       host->fixed_drv_type = drv_type;
+               else
+                       dev_err(host->parent,
+                               "can't use fixed driver type, media is removable\n");
+       }
+
        host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr);
        if (host->dsr_req && (host->dsr & ~0xffff)) {
                dev_err(host->parent,
@@ -398,6 +402,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
        host->max_blk_size = 512;
        host->max_blk_count = PAGE_SIZE / 512;
 
+       host->fixed_drv_type = -EINVAL;
+
        return host;
 }
 
index 77d6f60d1bf96814f921cb2a37b8bb429356bf8d..fb689a1065ed366040dd0c74d724ea40670b5640 100644 (file)
@@ -19,12 +19,17 @@ void mmc_unregister_host_class(void);
 void mmc_retune_enable(struct mmc_host *host);
 void mmc_retune_disable(struct mmc_host *host);
 void mmc_retune_hold(struct mmc_host *host);
-void mmc_retune_hold_now(struct mmc_host *host);
 void mmc_retune_release(struct mmc_host *host);
 int mmc_retune(struct mmc_host *host);
 void mmc_retune_pause(struct mmc_host *host);
 void mmc_retune_unpause(struct mmc_host *host);
 
+static inline void mmc_retune_hold_now(struct mmc_host *host)
+{
+       host->retune_now = 0;
+       host->hold_retune += 1;
+}
+
 static inline void mmc_retune_recheck(struct mmc_host *host)
 {
        if (host->hold_retune <= 1)
index 36217ad5e9b1fbddb4c5dedf6dd711374fc27497..a552f61060d2127d2539f73abf0f3690829c0898 100644 (file)
@@ -780,6 +780,7 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
 MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
 MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
 MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
+MMC_DEV_ATTR(rev, "0x%x\n", card->ext_csd.rev);
 MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info);
 MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n",
        card->ext_csd.device_life_time_est_typ_a,
@@ -838,6 +839,7 @@ static struct attribute *mmc_std_attrs[] = {
        &dev_attr_name.attr,
        &dev_attr_oemid.attr,
        &dev_attr_prv.attr,
+       &dev_attr_rev.attr,
        &dev_attr_pre_eol_info.attr,
        &dev_attr_life_time.attr,
        &dev_attr_serial.attr,
@@ -1289,13 +1291,18 @@ out_err:
 static void mmc_select_driver_type(struct mmc_card *card)
 {
        int card_drv_type, drive_strength, drv_type;
+       int fixed_drv_type = card->host->fixed_drv_type;
 
        card_drv_type = card->ext_csd.raw_driver_strength |
                        mmc_driver_type_mask(0);
 
-       drive_strength = mmc_select_drive_strength(card,
-                                                  card->ext_csd.hs200_max_dtr,
-                                                  card_drv_type, &drv_type);
+       if (fixed_drv_type >= 0)
+               drive_strength = card_drv_type & mmc_driver_type_mask(fixed_drv_type)
+                                ? fixed_drv_type : 0;
+       else
+               drive_strength = mmc_select_drive_strength(card,
+                                                          card->ext_csd.hs200_max_dtr,
+                                                          card_drv_type, &drv_type);
 
        card->drive_strength = drive_strength;
 
@@ -1785,6 +1792,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
+       /*
+        * Enable Command Queue if supported. Note that Packed Commands cannot
+        * be used with Command Queue.
+        */
+       card->ext_csd.cmdq_en = false;
+       if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) {
+               err = mmc_cmdq_enable(card);
+               if (err && err != -EBADMSG)
+                       goto free_card;
+               if (err) {
+                       pr_warn("%s: Enabling CMDQ failed\n",
+                               mmc_hostname(card->host));
+                       card->ext_csd.cmdq_support = false;
+                       card->ext_csd.cmdq_depth = 0;
+                       err = 0;
+               }
+       }
        /*
         * In some cases (e.g. RPMB or mmc_test), the Command Queue must be
         * disabled for a time, so a flag is needed to indicate to re-enable the
@@ -1792,6 +1816,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        card->reenable_cmdq = card->ext_csd.cmdq_en;
 
+       if (card->ext_csd.cmdq_en && !host->cqe_enabled) {
+               err = host->cqe_ops->cqe_enable(host, card);
+               if (err) {
+                       pr_err("%s: Failed to enable CQE, error %d\n",
+                               mmc_hostname(host), err);
+               } else {
+                       host->cqe_enabled = true;
+                       pr_info("%s: Command Queue Engine enabled\n",
+                               mmc_hostname(host));
+               }
+       }
+
        if (!oldcard)
                host->card = card;
 
@@ -1911,14 +1947,14 @@ static void mmc_detect(struct mmc_host *host)
 {
        int err;
 
-       mmc_get_card(host->card);
+       mmc_get_card(host->card, NULL);
 
        /*
         * Just check if our card has been removed.
         */
        err = _mmc_detect_card_removed(host);
 
-       mmc_put_card(host->card);
+       mmc_put_card(host->card, NULL);
 
        if (err) {
                mmc_remove(host);
index 54686ca4bfb7e8d70dbd33bf04661a2117e4dd8f..908e4db03535b038d548563188c0a11ac1ce4761 100644 (file)
@@ -977,7 +977,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
            from_exception)
                return;
 
-       mmc_claim_host(card->host);
        if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
                timeout = MMC_OPS_TIMEOUT_MS;
                use_busy_signal = true;
@@ -995,7 +994,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
                pr_warn("%s: Error %d starting bkops\n",
                        mmc_hostname(card->host), err);
                mmc_retune_release(card->host);
-               goto out;
+               return;
        }
 
        /*
@@ -1007,9 +1006,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
                mmc_card_set_doing_bkops(card);
        else
                mmc_retune_release(card->host);
-out:
-       mmc_release_host(card->host);
 }
+EXPORT_SYMBOL(mmc_start_bkops);
 
 /*
  * Flush the cache to the non-volatile storage.
index 0a4e77a5ba33fe7e0009ab1f7f97078a38e1559c..4f33d277b125e8027564a7ccf96230cd08433f07 100644 (file)
@@ -30,7 +30,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
 {
        struct mmc_queue *mq = q->queuedata;
 
-       if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
+       if (mq && mmc_card_removed(mq->card))
                return BLKPREP_KILL;
 
        req->rq_flags |= RQF_DONTPREP;
@@ -177,6 +177,29 @@ static void mmc_exit_request(struct request_queue *q, struct request *req)
        mq_rq->sg = NULL;
 }
 
+static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
+{
+       struct mmc_host *host = card->host;
+       u64 limit = BLK_BOUNCE_HIGH;
+
+       if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
+               limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
+
+       queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
+       queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
+       if (mmc_can_erase(card))
+               mmc_queue_setup_discard(mq->queue, card);
+
+       blk_queue_bounce_limit(mq->queue, limit);
+       blk_queue_max_hw_sectors(mq->queue,
+               min(host->max_blk_count, host->max_req_size / 512));
+       blk_queue_max_segments(mq->queue, host->max_segs);
+       blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+
+       /* Initialize thread_sem even if it is not used */
+       sema_init(&mq->thread_sem, 1);
+}
+
 /**
  * mmc_init_queue - initialise a queue structure.
  * @mq: mmc queue
@@ -190,12 +213,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
                   spinlock_t *lock, const char *subname)
 {
        struct mmc_host *host = card->host;
-       u64 limit = BLK_BOUNCE_HIGH;
        int ret = -ENOMEM;
 
-       if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
-               limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
-
        mq->card = card;
        mq->queue = blk_alloc_queue(GFP_KERNEL);
        if (!mq->queue)
@@ -214,18 +233,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
        }
 
        blk_queue_prep_rq(mq->queue, mmc_prep_request);
-       queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
-       queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
-       if (mmc_can_erase(card))
-               mmc_queue_setup_discard(mq->queue, card);
 
-       blk_queue_bounce_limit(mq->queue, limit);
-       blk_queue_max_hw_sectors(mq->queue,
-               min(host->max_blk_count, host->max_req_size / 512));
-       blk_queue_max_segments(mq->queue, host->max_segs);
-       blk_queue_max_segment_size(mq->queue, host->max_seg_size);
-
-       sema_init(&mq->thread_sem, 1);
+       mmc_setup_queue(mq, card);
 
        mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
                host->index, subname ? subname : "");
index 6bfba32ffa66d94e4848e00f9e1e848fdcabe1a2..547b457c4251f5e8be71e33e7e9980d281ba6dd9 100644 (file)
@@ -36,12 +36,14 @@ struct mmc_blk_request {
 /**
  * enum mmc_drv_op - enumerates the operations in the mmc_queue_req
  * @MMC_DRV_OP_IOCTL: ioctl operation
+ * @MMC_DRV_OP_IOCTL_RPMB: RPMB-oriented ioctl operation
  * @MMC_DRV_OP_BOOT_WP: write protect boot partitions
  * @MMC_DRV_OP_GET_CARD_STATUS: get card status
  * @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card
  */
 enum mmc_drv_op {
        MMC_DRV_OP_IOCTL,
+       MMC_DRV_OP_IOCTL_RPMB,
        MMC_DRV_OP_BOOT_WP,
        MMC_DRV_OP_GET_CARD_STATUS,
        MMC_DRV_OP_GET_EXT_CSD,
@@ -82,6 +84,4 @@ extern void mmc_queue_resume(struct mmc_queue *);
 extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
                                     struct mmc_queue_req *);
 
-extern int mmc_access_rpmb(struct mmc_queue *);
-
 #endif
index 4fd1620b732d090311f845f6d138c80187517519..45bf78f327163e009d6dc2abd15b0c69ca06071c 100644 (file)
@@ -908,6 +908,18 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
        return max_dtr;
 }
 
+static bool mmc_sd_card_using_v18(struct mmc_card *card)
+{
+       /*
+        * According to the SD spec., the Bus Speed Mode (function group 1) bits
+        * 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus
+        * they can be used to determine if the card has already switched to
+        * 1.8V signaling.
+        */
+       return card->sw_caps.sd3_bus_mode &
+              (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -921,9 +933,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        int err;
        u32 cid[4];
        u32 rocr = 0;
+       bool v18_fixup_failed = false;
 
        WARN_ON(!host->claimed);
-
+retry:
        err = mmc_sd_get_cid(host, ocr, cid, &rocr);
        if (err)
                return err;
@@ -989,6 +1002,36 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        if (err)
                goto free_card;
 
+       /*
+        * If the card has not been power cycled, it may still be using 1.8V
+        * signaling. Detect that situation and try to initialize a UHS-I (1.8V)
+        * transfer mode.
+        */
+       if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_uhs(host) &&
+           mmc_sd_card_using_v18(card) &&
+           host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
+               /*
+                * Re-read switch information in case it has changed since
+                * oldcard was initialized.
+                */
+               if (oldcard) {
+                       err = mmc_read_switch(card);
+                       if (err)
+                               goto free_card;
+               }
+               if (mmc_sd_card_using_v18(card)) {
+                       if (mmc_host_set_uhs_voltage(host) ||
+                           mmc_sd_init_uhs_card(card)) {
+                               v18_fixup_failed = true;
+                               mmc_power_cycle(host, ocr);
+                               if (!oldcard)
+                                       mmc_remove_card(card);
+                               goto retry;
+                       }
+                       goto done;
+               }
+       }
+
        /* Initialization sequence for UHS-I cards */
        if (rocr & SD_ROCR_S18A) {
                err = mmc_sd_init_uhs_card(card);
@@ -1021,7 +1064,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
                        mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
                }
        }
-
+done:
        host->card = card;
        return 0;
 
@@ -1056,14 +1099,14 @@ static void mmc_sd_detect(struct mmc_host *host)
 {
        int err;
 
-       mmc_get_card(host->card);
+       mmc_get_card(host->card, NULL);
 
        /*
         * Just check if our card has been removed.
         */
        err = _mmc_detect_card_removed(host);
 
-       mmc_put_card(host->card);
+       mmc_put_card(host->card, NULL);
 
        if (err) {
                mmc_sd_remove(host);
index c771843e4c15a3d588bc511606c88eed5391a693..7a2eaf8410a3b36297b2bc1192fb2249a1859cb5 100644 (file)
@@ -155,7 +155,8 @@ static int sdio_irq_thread(void *_host)
                 * holding of the host lock does not cover too much work
                 * that doesn't require that lock to be held.
                 */
-               ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
+               ret = __mmc_claim_host(host, NULL,
+                                      &host->sdio_irq_thread_abort);
                if (ret)
                        break;
                ret = process_sdio_pending_irqs(host);
index 8c15637178ff3cec73b637633710f84e4dd93a00..567028c9219a98c09df88170a727eea7198a8afb 100644 (file)
@@ -352,6 +352,19 @@ config MMC_MESON_GX
 
          If you have a controller with this interface, say Y here.
 
+config MMC_MESON_MX_SDIO
+       tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support"
+       depends on ARCH_MESON || COMPILE_TEST
+       depends on COMMON_CLK
+       depends on HAS_DMA
+       depends on OF
+       help
+         This selects support for the SD/MMC Host Controller on
+         Amlogic Meson6, Meson8 and Meson8b SoCs.
+
+         If you have a controller with this interface, say Y or M here.
+         If unsure, say N.
+
 config MMC_MOXART
        tristate "MOXART SD/MMC Host Controller support"
        depends on ARCH_MOXART && MMC
@@ -429,6 +442,7 @@ config MMC_SDHCI_MSM
        tristate "Qualcomm SDHCI Controller Support"
        depends on ARCH_QCOM || (ARM && COMPILE_TEST)
        depends on MMC_SDHCI_PLTFM
+       select MMC_SDHCI_IO_ACCESSORS
        help
          This selects the Secure Digital Host Controller Interface (SDHCI)
          support present in Qualcomm SOCs. The controller supports
@@ -663,7 +677,7 @@ config MMC_CAVIUM_OCTEON
 config MMC_CAVIUM_THUNDERX
        tristate "Cavium ThunderX SD/MMC Card Interface support"
        depends on PCI && 64BIT && (ARM64 || COMPILE_TEST)
-       depends on GPIOLIB
+       depends on GPIO_THUNDERX
        depends on OF_ADDRESS
        help
          This selects Cavium ThunderX SD/MMC Card Interface.
@@ -899,3 +913,15 @@ config MMC_SDHCI_XENON
          This selects Marvell Xenon eMMC/SD/SDIO SDHCI.
          If you have a controller with this interface, say Y or M here.
          If unsure, say N.
+
+config MMC_SDHCI_OMAP
+       tristate "TI SDHCI Controller Support"
+       depends on MMC_SDHCI_PLTFM && OF
+       help
+         This selects the Secure Digital Host Controller Interface (SDHCI)
+         support present in TI's DRA7 SOCs. The controller supports
+         SD/MMC/SDIO devices.
+
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say N.
index 7c7b29ff591a1cac0fbc1a5832569377c0dbc01c..a43cf0d5a5d349b47be24d0bfe3543c7b5575b89 100644 (file)
@@ -65,6 +65,7 @@ obj-$(CONFIG_MMC_VUB300)      += vub300.o
 obj-$(CONFIG_MMC_USHC)         += ushc.o
 obj-$(CONFIG_MMC_WMT)          += wmt-sdmmc.o
 obj-$(CONFIG_MMC_MESON_GX)     += meson-gx-mmc.o
+obj-$(CONFIG_MMC_MESON_MX_SDIO)        += meson-mx-sdio.o
 obj-$(CONFIG_MMC_MOXART)       += moxart-mmc.o
 obj-$(CONFIG_MMC_SUNXI)                += sunxi-mmc.o
 obj-$(CONFIG_MMC_USDHI6ROL0)   += usdhi6rol0.o
@@ -90,6 +91,7 @@ obj-$(CONFIG_MMC_SDHCI_MSM)           += sdhci-msm.o
 obj-$(CONFIG_MMC_SDHCI_ST)             += sdhci-st.o
 obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32)        += sdhci-pic32.o
 obj-$(CONFIG_MMC_SDHCI_BRCMSTB)                += sdhci-brcmstb.o
+obj-$(CONFIG_MMC_SDHCI_OMAP)           += sdhci-omap.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
        CFLAGS-cb710-mmc        += -DDEBUG
index 0a0ebf3a096dd3ccefb484190eb1193ac0eb88fa..e55f3932d580b471681514b2ce23db91d90dc5de 100644 (file)
@@ -732,11 +732,11 @@ static inline unsigned int atmci_convert_chksize(struct atmel_mci *host,
                return 0;
 }
 
-static void atmci_timeout_timer(unsigned long data)
+static void atmci_timeout_timer(struct timer_list *t)
 {
        struct atmel_mci *host;
 
-       host = (struct atmel_mci *)data;
+       host = from_timer(host, t, timer);
 
        dev_dbg(&host->pdev->dev, "software timeout\n");
 
@@ -1661,9 +1661,9 @@ static void atmci_command_complete(struct atmel_mci *host,
                cmd->error = 0;
 }
 
-static void atmci_detect_change(unsigned long data)
+static void atmci_detect_change(struct timer_list *t)
 {
-       struct atmel_mci_slot   *slot = (struct atmel_mci_slot *)data;
+       struct atmel_mci_slot   *slot = from_timer(slot, t, detect_timer);
        bool                    present;
        bool                    present_old;
 
@@ -2349,8 +2349,7 @@ static int atmci_init_slot(struct atmel_mci *host,
        if (gpio_is_valid(slot->detect_pin)) {
                int ret;
 
-               setup_timer(&slot->detect_timer, atmci_detect_change,
-                               (unsigned long)slot);
+               timer_setup(&slot->detect_timer, atmci_detect_change, 0);
 
                ret = request_irq(gpio_to_irq(slot->detect_pin),
                                atmci_detect_interrupt,
@@ -2563,7 +2562,7 @@ static int atmci_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, host);
 
-       setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
+       timer_setup(&host->timer, atmci_timeout_timer, 0);
 
        pm_runtime_get_noresume(&pdev->dev);
        pm_runtime_set_active(&pdev->dev);
index fbd29f00fca05e5dc46e09d1aa10c9f619283097..ed5cefb8376838b401aba0ac394c6a69e37dd818 100644 (file)
@@ -967,7 +967,7 @@ static int cvm_mmc_of_parse(struct device *dev, struct cvm_mmc_slot *slot)
        }
 
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                return ret;
        /*
         * Legacy Octeon firmware has no regulator entry, fall-back to
index 64cda84b23029a5d40bcee5754576080ee406ae0..73fd75c3c824904d7171a51f16943192f6c1bc03 100644 (file)
@@ -75,7 +75,7 @@ struct hs_timing {
        u32 smpl_phase_min;
 };
 
-struct hs_timing hs_timing_cfg[TIMING_MODE][TIMING_CFG_NUM] = {
+static struct hs_timing hs_timing_cfg[TIMING_MODE][TIMING_CFG_NUM] = {
        { /* reserved */ },
        { /* SD */
                {7, 0, 15, 15,},  /* 0: LEGACY 400k */
index 4f2806720c5c355aad0f7c87a3c28ff641c25a4e..0aa39975f33b8fbf36f0995cb56ffe283c7ca1b2 100644 (file)
@@ -817,7 +817,7 @@ static int dw_mci_edmac_start_dma(struct dw_mci *host,
        struct dma_slave_config cfg;
        struct dma_async_tx_descriptor *desc = NULL;
        struct scatterlist *sgl = host->data->sg;
-       const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
+       static const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
        u32 sg_elems = host->data->sg_len;
        u32 fifoth_val;
        u32 fifo_offset = host->fifo_reg - host->regs;
@@ -1024,7 +1024,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
 static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
 {
        unsigned int blksz = data->blksz;
-       const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
+       static const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
        u32 fifo_width = 1 << host->data_shift;
        u32 blksz_depth = blksz / fifo_width, fifoth_val;
        u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
@@ -1938,6 +1938,7 @@ static void dw_mci_set_drto(struct dw_mci *host)
        unsigned int drto_clks;
        unsigned int drto_div;
        unsigned int drto_ms;
+       unsigned long irqflags;
 
        drto_clks = mci_readl(host, TMOUT) >> 8;
        drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
@@ -1949,7 +1950,11 @@ static void dw_mci_set_drto(struct dw_mci *host)
        /* add a bit spare time */
        drto_ms += 10;
 
-       mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
+       spin_lock_irqsave(&host->irq_lock, irqflags);
+       if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
+               mod_timer(&host->dto_timer,
+                         jiffies + msecs_to_jiffies(drto_ms));
+       spin_unlock_irqrestore(&host->irq_lock, irqflags);
 }
 
 static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
@@ -1970,6 +1975,18 @@ static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
        return true;
 }
 
+static bool dw_mci_clear_pending_data_complete(struct dw_mci *host)
+{
+       if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
+               return false;
+
+       /* Extra paranoia just like dw_mci_clear_pending_cmd_complete() */
+       WARN_ON(del_timer_sync(&host->dto_timer));
+       clear_bit(EVENT_DATA_COMPLETE, &host->pending_events);
+
+       return true;
+}
+
 static void dw_mci_tasklet_func(unsigned long priv)
 {
        struct dw_mci *host = (struct dw_mci *)priv;
@@ -2111,8 +2128,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        /* fall through */
 
                case STATE_DATA_BUSY:
-                       if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
-                                               &host->pending_events)) {
+                       if (!dw_mci_clear_pending_data_complete(host)) {
                                /*
                                 * If data error interrupt comes but data over
                                 * interrupt doesn't come within the given time.
@@ -2682,6 +2698,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                }
 
                if (pending & SDMMC_INT_DATA_OVER) {
+                       spin_lock_irqsave(&host->irq_lock, irqflags);
+
                        del_timer(&host->dto_timer);
 
                        mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
@@ -2694,6 +2712,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                        }
                        set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
                        tasklet_schedule(&host->tasklet);
+
+                       spin_unlock_irqrestore(&host->irq_lock, irqflags);
                }
 
                if (pending & SDMMC_INT_RXDR) {
@@ -2791,7 +2811,7 @@ static int dw_mci_init_slot(struct dw_mci *host)
 
        /*if there are external regulators, get them*/
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                goto err_host_allocated;
 
        if (!mmc->ocr_avail)
@@ -2971,9 +2991,9 @@ no_dma:
        host->use_dma = TRANS_MODE_PIO;
 }
 
-static void dw_mci_cmd11_timer(unsigned long arg)
+static void dw_mci_cmd11_timer(struct timer_list *t)
 {
-       struct dw_mci *host = (struct dw_mci *)arg;
+       struct dw_mci *host = from_timer(host, t, cmd11_timer);
 
        if (host->state != STATE_SENDING_CMD11) {
                dev_warn(host->dev, "Unexpected CMD11 timeout\n");
@@ -2985,9 +3005,9 @@ static void dw_mci_cmd11_timer(unsigned long arg)
        tasklet_schedule(&host->tasklet);
 }
 
-static void dw_mci_cto_timer(unsigned long arg)
+static void dw_mci_cto_timer(struct timer_list *t)
 {
-       struct dw_mci *host = (struct dw_mci *)arg;
+       struct dw_mci *host = from_timer(host, t, cto_timer);
        unsigned long irqflags;
        u32 pending;
 
@@ -3040,10 +3060,34 @@ exit:
        spin_unlock_irqrestore(&host->irq_lock, irqflags);
 }
 
-static void dw_mci_dto_timer(unsigned long arg)
+static void dw_mci_dto_timer(struct timer_list *t)
 {
-       struct dw_mci *host = (struct dw_mci *)arg;
+       struct dw_mci *host = from_timer(host, t, dto_timer);
+       unsigned long irqflags;
+       u32 pending;
+
+       spin_lock_irqsave(&host->irq_lock, irqflags);
 
+       /*
+        * The DTO timer is much longer than the CTO timer, so it's even less
+        * likely that we'll these cases, but it pays to be paranoid.
+        */
+       pending = mci_readl(host, MINTSTS); /* read-only mask reg */
+       if (pending & SDMMC_INT_DATA_OVER) {
+               /* The interrupt should fire; no need to act but we can warn */
+               dev_warn(host->dev, "Unexpected data interrupt latency\n");
+               goto exit;
+       }
+       if (test_bit(EVENT_DATA_COMPLETE, &host->pending_events)) {
+               /* Presumably interrupt handler couldn't delete the timer */
+               dev_warn(host->dev, "DTO timeout when already completed\n");
+               goto exit;
+       }
+
+       /*
+        * Continued paranoia to make sure we're in the state we expect.
+        * This paranoia isn't really justified but it seems good to be safe.
+        */
        switch (host->state) {
        case STATE_SENDING_DATA:
        case STATE_DATA_BUSY:
@@ -3058,8 +3102,13 @@ static void dw_mci_dto_timer(unsigned long arg)
                tasklet_schedule(&host->tasklet);
                break;
        default:
+               dev_warn(host->dev, "Unexpected data timeout, state %d\n",
+                        host->state);
                break;
        }
+
+exit:
+       spin_unlock_irqrestore(&host->irq_lock, irqflags);
 }
 
 #ifdef CONFIG_OF
@@ -3208,14 +3257,9 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
-       setup_timer(&host->cmd11_timer,
-                   dw_mci_cmd11_timer, (unsigned long)host);
-
-       setup_timer(&host->cto_timer,
-                   dw_mci_cto_timer, (unsigned long)host);
-
-       setup_timer(&host->dto_timer,
-                   dw_mci_dto_timer, (unsigned long)host);
+       timer_setup(&host->cmd11_timer, dw_mci_cmd11_timer, 0);
+       timer_setup(&host->cto_timer, dw_mci_cto_timer, 0);
+       timer_setup(&host->dto_timer, dw_mci_dto_timer, 0);
 
        spin_lock_init(&host->lock);
        spin_lock_init(&host->irq_lock);
index 34474ad731aa7007acf297e9a9474edc1c87d065..e3124f06a47ef52840dc5abb77a7febd104b083d 100644 (file)
@@ -74,7 +74,8 @@ struct dw_mci_dma_slave {
  * @stop_abort: The command currently prepared for stoping transfer.
  * @prev_blksz: The former transfer blksz record.
  * @timing: Record of current ios timing.
- * @use_dma: Whether DMA channel is initialized or not.
+ * @use_dma: Which DMA channel is in use for the current transfer, zero
+ *     denotes PIO mode.
  * @using_dma: Whether DMA is in use for the current transfer.
  * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
  * @sg_dma: Bus address of DMA buffer.
index 7db8c7a8d38df162879199be9a4941387d243f2f..712e08d9a45e452100d42a76fb5eed916f42bc93 100644 (file)
@@ -586,9 +586,9 @@ poll_timeout:
        return true;
 }
 
-static void jz4740_mmc_timeout(unsigned long data)
+static void jz4740_mmc_timeout(struct timer_list *t)
 {
-       struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data;
+       struct jz4740_mmc_host *host = from_timer(host, t, timeout_timer);
 
        if (!test_and_clear_bit(0, &host->waiting))
                return;
@@ -1036,8 +1036,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 
        jz4740_mmc_reset(host);
        jz4740_mmc_clock_disable(host);
-       setup_timer(&host->timeout_timer, jz4740_mmc_timeout,
-                       (unsigned long)host);
+       timer_setup(&host->timeout_timer, jz4740_mmc_timeout, 0);
 
        host->use_dma = true;
        if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0)
index 85745ef179e22b2e49e4b23e15df311891f192dc..e0862d3f65b346b5ef40c378530af206d2ea9f81 100644 (file)
@@ -1190,7 +1190,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
        /* Get regulators and the supported OCR mask */
        host->vqmmc_enabled = false;
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                goto free_host;
 
        ret = mmc_of_parse(mmc);
diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c
new file mode 100644 (file)
index 0000000..09cb896
--- /dev/null
@@ -0,0 +1,768 @@
+/*
+ * meson-mx-sdio.c - Meson6, Meson8 and Meson8b SDIO/MMC Host Controller
+ *
+ * Copyright (C) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/slot-gpio.h>
+
+#define MESON_MX_SDIO_ARGU                                     0x00
+
+#define MESON_MX_SDIO_SEND                                     0x04
+       #define MESON_MX_SDIO_SEND_COMMAND_INDEX_MASK           GENMASK(7, 0)
+       #define MESON_MX_SDIO_SEND_CMD_RESP_BITS_MASK           GENMASK(15, 8)
+       #define MESON_MX_SDIO_SEND_RESP_WITHOUT_CRC7            BIT(16)
+       #define MESON_MX_SDIO_SEND_RESP_HAS_DATA                BIT(17)
+       #define MESON_MX_SDIO_SEND_RESP_CRC7_FROM_8             BIT(18)
+       #define MESON_MX_SDIO_SEND_CHECK_DAT0_BUSY              BIT(19)
+       #define MESON_MX_SDIO_SEND_DATA                         BIT(20)
+       #define MESON_MX_SDIO_SEND_USE_INT_WINDOW               BIT(21)
+       #define MESON_MX_SDIO_SEND_REPEAT_PACKAGE_TIMES_MASK    GENMASK(31, 24)
+
+#define MESON_MX_SDIO_CONF                                     0x08
+       #define MESON_MX_SDIO_CONF_CMD_CLK_DIV_SHIFT            0
+       #define MESON_MX_SDIO_CONF_CMD_CLK_DIV_WIDTH            10
+       #define MESON_MX_SDIO_CONF_CMD_DISABLE_CRC              BIT(10)
+       #define MESON_MX_SDIO_CONF_CMD_OUT_AT_POSITIVE_EDGE     BIT(11)
+       #define MESON_MX_SDIO_CONF_CMD_ARGUMENT_BITS_MASK       GENMASK(17, 12)
+       #define MESON_MX_SDIO_CONF_RESP_LATCH_AT_NEGATIVE_EDGE  BIT(18)
+       #define MESON_MX_SDIO_CONF_DATA_LATCH_AT_NEGATIVE_EDGE  BIT(19)
+       #define MESON_MX_SDIO_CONF_BUS_WIDTH                    BIT(20)
+       #define MESON_MX_SDIO_CONF_M_ENDIAN_MASK                GENMASK(22, 21)
+       #define MESON_MX_SDIO_CONF_WRITE_NWR_MASK               GENMASK(28, 23)
+       #define MESON_MX_SDIO_CONF_WRITE_CRC_OK_STATUS_MASK     GENMASK(31, 29)
+
+#define MESON_MX_SDIO_IRQS                                     0x0c
+       #define MESON_MX_SDIO_IRQS_STATUS_STATE_MACHINE_MASK    GENMASK(3, 0)
+       #define MESON_MX_SDIO_IRQS_CMD_BUSY                     BIT(4)
+       #define MESON_MX_SDIO_IRQS_RESP_CRC7_OK                 BIT(5)
+       #define MESON_MX_SDIO_IRQS_DATA_READ_CRC16_OK           BIT(6)
+       #define MESON_MX_SDIO_IRQS_DATA_WRITE_CRC16_OK          BIT(7)
+       #define MESON_MX_SDIO_IRQS_IF_INT                       BIT(8)
+       #define MESON_MX_SDIO_IRQS_CMD_INT                      BIT(9)
+       #define MESON_MX_SDIO_IRQS_STATUS_INFO_MASK             GENMASK(15, 12)
+       #define MESON_MX_SDIO_IRQS_TIMING_OUT_INT               BIT(16)
+       #define MESON_MX_SDIO_IRQS_AMRISC_TIMING_OUT_INT_EN     BIT(17)
+       #define MESON_MX_SDIO_IRQS_ARC_TIMING_OUT_INT_EN        BIT(18)
+       #define MESON_MX_SDIO_IRQS_TIMING_OUT_COUNT_MASK        GENMASK(31, 19)
+
+#define MESON_MX_SDIO_IRQC                                     0x10
+       #define MESON_MX_SDIO_IRQC_ARC_IF_INT_EN                BIT(3)
+       #define MESON_MX_SDIO_IRQC_ARC_CMD_INT_EN               BIT(4)
+       #define MESON_MX_SDIO_IRQC_IF_CONFIG_MASK               GENMASK(7, 6)
+       #define MESON_MX_SDIO_IRQC_FORCE_DATA_CLK               BIT(8)
+       #define MESON_MX_SDIO_IRQC_FORCE_DATA_CMD               BIT(9)
+       #define MESON_MX_SDIO_IRQC_FORCE_DATA_DAT_MASK          GENMASK(10, 13)
+       #define MESON_MX_SDIO_IRQC_SOFT_RESET                   BIT(15)
+       #define MESON_MX_SDIO_IRQC_FORCE_HALT                   BIT(30)
+       #define MESON_MX_SDIO_IRQC_HALT_HOLE                    BIT(31)
+
+#define MESON_MX_SDIO_MULT                                     0x14
+       #define MESON_MX_SDIO_MULT_PORT_SEL_MASK                GENMASK(1, 0)
+       #define MESON_MX_SDIO_MULT_MEMORY_STICK_ENABLE          BIT(2)
+       #define MESON_MX_SDIO_MULT_MEMORY_STICK_SCLK_ALWAYS     BIT(3)
+       #define MESON_MX_SDIO_MULT_STREAM_ENABLE                BIT(4)
+       #define MESON_MX_SDIO_MULT_STREAM_8BITS_MODE            BIT(5)
+       #define MESON_MX_SDIO_MULT_WR_RD_OUT_INDEX              BIT(8)
+       #define MESON_MX_SDIO_MULT_DAT0_DAT1_SWAPPED            BIT(10)
+       #define MESON_MX_SDIO_MULT_DAT1_DAT0_SWAPPED            BIT(11)
+       #define MESON_MX_SDIO_MULT_RESP_READ_INDEX_MASK         GENMASK(15, 12)
+
+#define MESON_MX_SDIO_ADDR                                     0x18
+
+#define MESON_MX_SDIO_EXT                                      0x1c
+       #define MESON_MX_SDIO_EXT_DATA_RW_NUMBER_MASK           GENMASK(29, 16)
+
+#define MESON_MX_SDIO_BOUNCE_REQ_SIZE                          (128 * 1024)
+#define MESON_MX_SDIO_RESPONSE_CRC16_BITS                      (16 - 1)
+#define MESON_MX_SDIO_MAX_SLOTS                                        3
+
+struct meson_mx_mmc_host {
+       struct device                   *controller_dev;
+
+       struct clk                      *parent_clk;
+       struct clk                      *core_clk;
+       struct clk_divider              cfg_div;
+       struct clk                      *cfg_div_clk;
+       struct clk_fixed_factor         fixed_factor;
+       struct clk                      *fixed_factor_clk;
+
+       void __iomem                    *base;
+       int                             irq;
+       spinlock_t                      irq_lock;
+
+       struct timer_list               cmd_timeout;
+
+       unsigned int                    slot_id;
+       struct mmc_host                 *mmc;
+
+       struct mmc_request              *mrq;
+       struct mmc_command              *cmd;
+       int                             error;
+};
+
+static void meson_mx_mmc_mask_bits(struct mmc_host *mmc, char reg, u32 mask,
+                                  u32 val)
+{
+       struct meson_mx_mmc_host *host = mmc_priv(mmc);
+       u32 regval;
+
+       regval = readl(host->base + reg);
+       regval &= ~mask;
+       regval |= (val & mask);
+
+       writel(regval, host->base + reg);
+}
+
+static void meson_mx_mmc_soft_reset(struct meson_mx_mmc_host *host)
+{
+       writel(MESON_MX_SDIO_IRQC_SOFT_RESET, host->base + MESON_MX_SDIO_IRQC);
+       udelay(2);
+}
+
+static struct mmc_command *meson_mx_mmc_get_next_cmd(struct mmc_command *cmd)
+{
+       if (cmd->opcode == MMC_SET_BLOCK_COUNT && !cmd->error)
+               return cmd->mrq->cmd;
+       else if (mmc_op_multi(cmd->opcode) &&
+                (!cmd->mrq->sbc || cmd->error || cmd->data->error))
+               return cmd->mrq->stop;
+       else
+               return NULL;
+}
+
+static void meson_mx_mmc_start_cmd(struct mmc_host *mmc,
+                                  struct mmc_command *cmd)
+{
+       struct meson_mx_mmc_host *host = mmc_priv(mmc);
+       unsigned int pack_size;
+       unsigned long irqflags, timeout;
+       u32 mult, send = 0, ext = 0;
+
+       host->cmd = cmd;
+
+       if (cmd->busy_timeout)
+               timeout = msecs_to_jiffies(cmd->busy_timeout);
+       else
+               timeout = msecs_to_jiffies(1000);
+
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_R1:
+       case MMC_RSP_R1B:
+       case MMC_RSP_R3:
+               /* 7 (CMD) + 32 (response) + 7 (CRC) -1 */
+               send |= FIELD_PREP(MESON_MX_SDIO_SEND_CMD_RESP_BITS_MASK, 45);
+               break;
+       case MMC_RSP_R2:
+               /* 7 (CMD) + 120 (response) + 7 (CRC) -1 */
+               send |= FIELD_PREP(MESON_MX_SDIO_SEND_CMD_RESP_BITS_MASK, 133);
+               send |= MESON_MX_SDIO_SEND_RESP_CRC7_FROM_8;
+               break;
+       default:
+               break;
+       }
+
+       if (!(cmd->flags & MMC_RSP_CRC))
+               send |= MESON_MX_SDIO_SEND_RESP_WITHOUT_CRC7;
+
+       if (cmd->flags & MMC_RSP_BUSY)
+               send |= MESON_MX_SDIO_SEND_CHECK_DAT0_BUSY;
+
+       if (cmd->data) {
+               send |= FIELD_PREP(MESON_MX_SDIO_SEND_REPEAT_PACKAGE_TIMES_MASK,
+                                  (cmd->data->blocks - 1));
+
+               pack_size = cmd->data->blksz * BITS_PER_BYTE;
+               if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
+                       pack_size += MESON_MX_SDIO_RESPONSE_CRC16_BITS * 4;
+               else
+                       pack_size += MESON_MX_SDIO_RESPONSE_CRC16_BITS * 1;
+
+               ext |= FIELD_PREP(MESON_MX_SDIO_EXT_DATA_RW_NUMBER_MASK,
+                                 pack_size);
+
+               if (cmd->data->flags & MMC_DATA_WRITE)
+                       send |= MESON_MX_SDIO_SEND_DATA;
+               else
+                       send |= MESON_MX_SDIO_SEND_RESP_HAS_DATA;
+
+               cmd->data->bytes_xfered = 0;
+       }
+
+       send |= FIELD_PREP(MESON_MX_SDIO_SEND_COMMAND_INDEX_MASK,
+                          (0x40 | cmd->opcode));
+
+       spin_lock_irqsave(&host->irq_lock, irqflags);
+
+       mult = readl(host->base + MESON_MX_SDIO_MULT);
+       mult &= ~MESON_MX_SDIO_MULT_PORT_SEL_MASK;
+       mult |= FIELD_PREP(MESON_MX_SDIO_MULT_PORT_SEL_MASK, host->slot_id);
+       mult |= BIT(31);
+       writel(mult, host->base + MESON_MX_SDIO_MULT);
+
+       /* enable the CMD done interrupt */
+       meson_mx_mmc_mask_bits(mmc, MESON_MX_SDIO_IRQC,
+                              MESON_MX_SDIO_IRQC_ARC_CMD_INT_EN,
+                              MESON_MX_SDIO_IRQC_ARC_CMD_INT_EN);
+
+       /* clear pending interrupts */
+       meson_mx_mmc_mask_bits(mmc, MESON_MX_SDIO_IRQS,
+                              MESON_MX_SDIO_IRQS_CMD_INT,
+                              MESON_MX_SDIO_IRQS_CMD_INT);
+
+       writel(cmd->arg, host->base + MESON_MX_SDIO_ARGU);
+       writel(ext, host->base + MESON_MX_SDIO_EXT);
+       writel(send, host->base + MESON_MX_SDIO_SEND);
+
+       spin_unlock_irqrestore(&host->irq_lock, irqflags);
+
+       mod_timer(&host->cmd_timeout, jiffies + timeout);
+}
+
+static void meson_mx_mmc_request_done(struct meson_mx_mmc_host *host)
+{
+       struct mmc_request *mrq;
+
+       mrq = host->mrq;
+
+       host->mrq = NULL;
+       host->cmd = NULL;
+
+       mmc_request_done(host->mmc, mrq);
+}
+
+static void meson_mx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct meson_mx_mmc_host *host = mmc_priv(mmc);
+       unsigned short vdd = ios->vdd;
+       unsigned long clk_rate = ios->clock;
+
+       switch (ios->bus_width) {
+       case MMC_BUS_WIDTH_1:
+               meson_mx_mmc_mask_bits(mmc, MESON_MX_SDIO_CONF,
+                                      MESON_MX_SDIO_CONF_BUS_WIDTH, 0);
+               break;
+
+       case MMC_BUS_WIDTH_4:
+               meson_mx_mmc_mask_bits(mmc, MESON_MX_SDIO_CONF,
+                                      MESON_MX_SDIO_CONF_BUS_WIDTH,
+                                      MESON_MX_SDIO_CONF_BUS_WIDTH);
+               break;
+
+       case MMC_BUS_WIDTH_8:
+       default:
+               dev_err(mmc_dev(mmc), "unsupported bus width: %d\n",
+                       ios->bus_width);
+               host->error = -EINVAL;
+               return;
+       }
+
+       host->error = clk_set_rate(host->cfg_div_clk, ios->clock);
+       if (host->error) {
+               dev_warn(mmc_dev(mmc),
+                               "failed to set MMC clock to %lu: %d\n",
+                               clk_rate, host->error);
+               return;
+       }
+
+       mmc->actual_clock = clk_get_rate(host->cfg_div_clk);
+
+       switch (ios->power_mode) {
+       case MMC_POWER_OFF:
+               vdd = 0;
+               /* fall-through: */
+       case MMC_POWER_UP:
+               if (!IS_ERR(mmc->supply.vmmc)) {
+                       host->error = mmc_regulator_set_ocr(mmc,
+                                                           mmc->supply.vmmc,
+                                                           vdd);
+                       if (host->error)
+                               return;
+               }
+               break;
+       }
+}
+
+static int meson_mx_mmc_map_dma(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       int dma_len;
+       struct scatterlist *sg;
+
+       if (!data)
+               return 0;
+
+       sg = data->sg;
+       if (sg->offset & 3 || sg->length & 3) {
+               dev_err(mmc_dev(mmc),
+                       "unaligned scatterlist: offset %x length %d\n",
+                       sg->offset, sg->length);
+               return -EINVAL;
+       }
+
+       dma_len = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
+                            mmc_get_dma_dir(data));
+       if (dma_len <= 0) {
+               dev_err(mmc_dev(mmc), "dma_map_sg failed\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void meson_mx_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct meson_mx_mmc_host *host = mmc_priv(mmc);
+       struct mmc_command *cmd = mrq->cmd;
+
+       if (!host->error)
+               host->error = meson_mx_mmc_map_dma(mmc, mrq);
+
+       if (host->error) {
+               cmd->error = host->error;
+               mmc_request_done(mmc, mrq);
+               return;
+       }
+
+       host->mrq = mrq;
+
+       if (mrq->data)
+               writel(sg_dma_address(mrq->data->sg),
+                      host->base + MESON_MX_SDIO_ADDR);
+
+       if (mrq->sbc)
+               meson_mx_mmc_start_cmd(mmc, mrq->sbc);
+       else
+               meson_mx_mmc_start_cmd(mmc, mrq->cmd);
+}
+
+static int meson_mx_mmc_card_busy(struct mmc_host *mmc)
+{
+       struct meson_mx_mmc_host *host = mmc_priv(mmc);
+       u32 irqc = readl(host->base + MESON_MX_SDIO_IRQC);
+
+       return !!(irqc & MESON_MX_SDIO_IRQC_FORCE_DATA_DAT_MASK);
+}
+
+static void meson_mx_mmc_read_response(struct mmc_host *mmc,
+                                      struct mmc_command *cmd)
+{
+       struct meson_mx_mmc_host *host = mmc_priv(mmc);
+       u32 mult;
+       int i, resp[4];
+
+       mult = readl(host->base + MESON_MX_SDIO_MULT);
+       mult |= MESON_MX_SDIO_MULT_WR_RD_OUT_INDEX;
+       mult &= ~MESON_MX_SDIO_MULT_RESP_READ_INDEX_MASK;
+       mult |= FIELD_PREP(MESON_MX_SDIO_MULT_RESP_READ_INDEX_MASK, 0);
+       writel(mult, host->base + MESON_MX_SDIO_MULT);
+
+       if (cmd->flags & MMC_RSP_136) {
+               for (i = 0; i <= 3; i++)
+                       resp[3 - i] = readl(host->base + MESON_MX_SDIO_ARGU);
+               cmd->resp[0] = (resp[0] << 8) | ((resp[1] >> 24) & 0xff);
+               cmd->resp[1] = (resp[1] << 8) | ((resp[2] >> 24) & 0xff);
+               cmd->resp[2] = (resp[2] << 8) | ((resp[3] >> 24) & 0xff);
+               cmd->resp[3] = (resp[3] << 8);
+       } else if (cmd->flags & MMC_RSP_PRESENT) {
+               cmd->resp[0] = readl(host->base + MESON_MX_SDIO_ARGU);
+       }
+}
+
+static irqreturn_t meson_mx_mmc_process_cmd_irq(struct meson_mx_mmc_host *host,
+                                               u32 irqs, u32 send)
+{
+       struct mmc_command *cmd = host->cmd;
+
+       /*
+        * NOTE: even though it shouldn't happen we sometimes get command
+        * interrupts twice (at least this is what it looks like). Ideally
+        * we find out why this happens and warn here as soon as it occurs.
+        */
+       if (!cmd)
+               return IRQ_HANDLED;
+
+       cmd->error = 0;
+       meson_mx_mmc_read_response(host->mmc, cmd);
+
+       if (cmd->data) {
+               if (!((irqs & MESON_MX_SDIO_IRQS_DATA_READ_CRC16_OK) ||
+                     (irqs & MESON_MX_SDIO_IRQS_DATA_WRITE_CRC16_OK)))
+                       cmd->error = -EILSEQ;
+       } else {
+               if (!((irqs & MESON_MX_SDIO_IRQS_RESP_CRC7_OK) ||
+                     (send & MESON_MX_SDIO_SEND_RESP_WITHOUT_CRC7)))
+                       cmd->error = -EILSEQ;
+       }
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t meson_mx_mmc_irq(int irq, void *data)
+{
+       struct meson_mx_mmc_host *host = (void *) data;
+       u32 irqs, send;
+       unsigned long irqflags;
+       irqreturn_t ret;
+
+       spin_lock_irqsave(&host->irq_lock, irqflags);
+
+       irqs = readl(host->base + MESON_MX_SDIO_IRQS);
+       send = readl(host->base + MESON_MX_SDIO_SEND);
+
+       if (irqs & MESON_MX_SDIO_IRQS_CMD_INT)
+               ret = meson_mx_mmc_process_cmd_irq(host, irqs, send);
+       else
+               ret = IRQ_HANDLED;
+
+       /* finally ACK all pending interrupts */
+       writel(irqs, host->base + MESON_MX_SDIO_IRQS);
+
+       spin_unlock_irqrestore(&host->irq_lock, irqflags);
+
+       return ret;
+}
+
+static irqreturn_t meson_mx_mmc_irq_thread(int irq, void *irq_data)
+{
+       struct meson_mx_mmc_host *host = (void *) irq_data;
+       struct mmc_command *cmd = host->cmd, *next_cmd;
+
+       if (WARN_ON(!cmd))
+               return IRQ_HANDLED;
+
+       del_timer_sync(&host->cmd_timeout);
+
+       if (cmd->data) {
+               dma_unmap_sg(mmc_dev(host->mmc), cmd->data->sg,
+                               cmd->data->sg_len,
+                               mmc_get_dma_dir(cmd->data));
+
+               cmd->data->bytes_xfered = cmd->data->blksz * cmd->data->blocks;
+       }
+
+       next_cmd = meson_mx_mmc_get_next_cmd(cmd);
+       if (next_cmd)
+               meson_mx_mmc_start_cmd(host->mmc, next_cmd);
+       else
+               meson_mx_mmc_request_done(host);
+
+       return IRQ_HANDLED;
+}
+
+static void meson_mx_mmc_timeout(struct timer_list *t)
+{
+       struct meson_mx_mmc_host *host = from_timer(host, t, cmd_timeout);
+       unsigned long irqflags;
+       u32 irqc;
+
+       spin_lock_irqsave(&host->irq_lock, irqflags);
+
+       /* disable the CMD interrupt */
+       irqc = readl(host->base + MESON_MX_SDIO_IRQC);
+       irqc &= ~MESON_MX_SDIO_IRQC_ARC_CMD_INT_EN;
+       writel(irqc, host->base + MESON_MX_SDIO_IRQC);
+
+       spin_unlock_irqrestore(&host->irq_lock, irqflags);
+
+       /*
+        * skip the timeout handling if the interrupt handler already processed
+        * the command.
+        */
+       if (!host->cmd)
+               return;
+
+       dev_dbg(mmc_dev(host->mmc),
+               "Timeout on CMD%u (IRQS = 0x%08x, ARGU = 0x%08x)\n",
+               host->cmd->opcode, readl(host->base + MESON_MX_SDIO_IRQS),
+               readl(host->base + MESON_MX_SDIO_ARGU));
+
+       host->cmd->error = -ETIMEDOUT;
+
+       meson_mx_mmc_request_done(host);
+}
+
+static struct mmc_host_ops meson_mx_mmc_ops = {
+       .request                = meson_mx_mmc_request,
+       .set_ios                = meson_mx_mmc_set_ios,
+       .card_busy              = meson_mx_mmc_card_busy,
+       .get_cd                 = mmc_gpio_get_cd,
+       .get_ro                 = mmc_gpio_get_ro,
+};
+
+static struct platform_device *meson_mx_mmc_slot_pdev(struct device *parent)
+{
+       struct device_node *slot_node;
+
+       /*
+        * TODO: the MMC core framework currently does not support
+        * controllers with multiple slots properly. So we only register
+        * the first slot for now
+        */
+       slot_node = of_find_compatible_node(parent->of_node, NULL, "mmc-slot");
+       if (!slot_node) {
+               dev_warn(parent, "no 'mmc-slot' sub-node found\n");
+               return ERR_PTR(-ENOENT);
+       }
+
+       return of_platform_device_create(slot_node, NULL, parent);
+}
+
+static int meson_mx_mmc_add_host(struct meson_mx_mmc_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+       struct device *slot_dev = mmc_dev(mmc);
+       int ret;
+
+       if (of_property_read_u32(slot_dev->of_node, "reg", &host->slot_id)) {
+               dev_err(slot_dev, "missing 'reg' property\n");
+               return -EINVAL;
+       }
+
+       if (host->slot_id >= MESON_MX_SDIO_MAX_SLOTS) {
+               dev_err(slot_dev, "invalid 'reg' property value %d\n",
+                       host->slot_id);
+               return -EINVAL;
+       }
+
+       /* Get regulators and the supported OCR mask */
+       ret = mmc_regulator_get_supply(mmc);
+       if (ret)
+               return ret;
+
+       mmc->max_req_size = MESON_MX_SDIO_BOUNCE_REQ_SIZE;
+       mmc->max_seg_size = mmc->max_req_size;
+       mmc->max_blk_count =
+               FIELD_GET(MESON_MX_SDIO_SEND_REPEAT_PACKAGE_TIMES_MASK,
+                         0xffffffff);
+       mmc->max_blk_size = FIELD_GET(MESON_MX_SDIO_EXT_DATA_RW_NUMBER_MASK,
+                                     0xffffffff);
+       mmc->max_blk_size -= (4 * MESON_MX_SDIO_RESPONSE_CRC16_BITS);
+       mmc->max_blk_size /= BITS_PER_BYTE;
+
+       /* Get the min and max supported clock rates */
+       mmc->f_min = clk_round_rate(host->cfg_div_clk, 1);
+       mmc->f_max = clk_round_rate(host->cfg_div_clk,
+                                   clk_get_rate(host->parent_clk));
+
+       mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
+       mmc->ops = &meson_mx_mmc_ops;
+
+       ret = mmc_of_parse(mmc);
+       if (ret)
+               return ret;
+
+       ret = mmc_add_host(mmc);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int meson_mx_mmc_register_clks(struct meson_mx_mmc_host *host)
+{
+       struct clk_init_data init;
+       const char *clk_div_parent, *clk_fixed_factor_parent;
+
+       clk_fixed_factor_parent = __clk_get_name(host->parent_clk);
+       init.name = devm_kasprintf(host->controller_dev, GFP_KERNEL,
+                                  "%s#fixed_factor",
+                                  dev_name(host->controller_dev));
+       init.ops = &clk_fixed_factor_ops;
+       init.flags = 0;
+       init.parent_names = &clk_fixed_factor_parent;
+       init.num_parents = 1;
+       host->fixed_factor.div = 2;
+       host->fixed_factor.mult = 1;
+       host->fixed_factor.hw.init = &init;
+
+       host->fixed_factor_clk = devm_clk_register(host->controller_dev,
+                                                &host->fixed_factor.hw);
+       if (WARN_ON(IS_ERR(host->fixed_factor_clk)))
+               return PTR_ERR(host->fixed_factor_clk);
+
+       clk_div_parent = __clk_get_name(host->fixed_factor_clk);
+       init.name = devm_kasprintf(host->controller_dev, GFP_KERNEL,
+                                  "%s#div", dev_name(host->controller_dev));
+       init.ops = &clk_divider_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       init.parent_names = &clk_div_parent;
+       init.num_parents = 1;
+       host->cfg_div.reg = host->base + MESON_MX_SDIO_CONF;
+       host->cfg_div.shift = MESON_MX_SDIO_CONF_CMD_CLK_DIV_SHIFT;
+       host->cfg_div.width = MESON_MX_SDIO_CONF_CMD_CLK_DIV_WIDTH;
+       host->cfg_div.hw.init = &init;
+       host->cfg_div.flags = CLK_DIVIDER_ALLOW_ZERO;
+
+       host->cfg_div_clk = devm_clk_register(host->controller_dev,
+                                             &host->cfg_div.hw);
+       if (WARN_ON(IS_ERR(host->cfg_div_clk)))
+               return PTR_ERR(host->cfg_div_clk);
+
+       return 0;
+}
+
+static int meson_mx_mmc_probe(struct platform_device *pdev)
+{
+       struct platform_device *slot_pdev;
+       struct mmc_host *mmc;
+       struct meson_mx_mmc_host *host;
+       struct resource *res;
+       int ret, irq;
+       u32 conf;
+
+       slot_pdev = meson_mx_mmc_slot_pdev(&pdev->dev);
+       if (!slot_pdev)
+               return -ENODEV;
+       else if (IS_ERR(slot_pdev))
+               return PTR_ERR(slot_pdev);
+
+       mmc = mmc_alloc_host(sizeof(*host), &slot_pdev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto error_unregister_slot_pdev;
+       }
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+       host->controller_dev = &pdev->dev;
+
+       spin_lock_init(&host->irq_lock);
+       timer_setup(&host->cmd_timeout, meson_mx_mmc_timeout, 0);
+
+       platform_set_drvdata(pdev, host);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->base = devm_ioremap_resource(host->controller_dev, res);
+       if (IS_ERR(host->base)) {
+               ret = PTR_ERR(host->base);
+               goto error_free_mmc;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_request_threaded_irq(host->controller_dev, irq,
+                                       meson_mx_mmc_irq,
+                                       meson_mx_mmc_irq_thread, IRQF_ONESHOT,
+                                       NULL, host);
+       if (ret)
+               goto error_free_mmc;
+
+       host->core_clk = devm_clk_get(host->controller_dev, "core");
+       if (IS_ERR(host->core_clk)) {
+               ret = PTR_ERR(host->core_clk);
+               goto error_free_mmc;
+       }
+
+       host->parent_clk = devm_clk_get(host->controller_dev, "clkin");
+       if (IS_ERR(host->parent_clk)) {
+               ret = PTR_ERR(host->parent_clk);
+               goto error_free_mmc;
+       }
+
+       ret = meson_mx_mmc_register_clks(host);
+       if (ret)
+               goto error_free_mmc;
+
+       ret = clk_prepare_enable(host->core_clk);
+       if (ret) {
+               dev_err(host->controller_dev, "Failed to enable core clock\n");
+               goto error_free_mmc;
+       }
+
+       ret = clk_prepare_enable(host->cfg_div_clk);
+       if (ret) {
+               dev_err(host->controller_dev, "Failed to enable MMC clock\n");
+               goto error_disable_core_clk;
+       }
+
+       conf = 0;
+       conf |= FIELD_PREP(MESON_MX_SDIO_CONF_CMD_ARGUMENT_BITS_MASK, 39);
+       conf |= FIELD_PREP(MESON_MX_SDIO_CONF_M_ENDIAN_MASK, 0x3);
+       conf |= FIELD_PREP(MESON_MX_SDIO_CONF_WRITE_NWR_MASK, 0x2);
+       conf |= FIELD_PREP(MESON_MX_SDIO_CONF_WRITE_CRC_OK_STATUS_MASK, 0x2);
+       writel(conf, host->base + MESON_MX_SDIO_CONF);
+
+       meson_mx_mmc_soft_reset(host);
+
+       ret = meson_mx_mmc_add_host(host);
+       if (ret)
+               goto error_disable_clks;
+
+       return 0;
+
+error_disable_clks:
+       clk_disable_unprepare(host->cfg_div_clk);
+error_disable_core_clk:
+       clk_disable_unprepare(host->core_clk);
+error_free_mmc:
+       mmc_free_host(mmc);
+error_unregister_slot_pdev:
+       of_platform_device_destroy(&slot_pdev->dev, NULL);
+       return ret;
+}
+
+static int meson_mx_mmc_remove(struct platform_device *pdev)
+{
+       struct meson_mx_mmc_host *host = platform_get_drvdata(pdev);
+       struct device *slot_dev = mmc_dev(host->mmc);
+
+       del_timer_sync(&host->cmd_timeout);
+
+       mmc_remove_host(host->mmc);
+
+       of_platform_device_destroy(slot_dev, NULL);
+
+       clk_disable_unprepare(host->cfg_div_clk);
+       clk_disable_unprepare(host->core_clk);
+
+       mmc_free_host(host->mmc);
+
+       return 0;
+}
+
+static const struct of_device_id meson_mx_mmc_of_match[] = {
+       { .compatible = "amlogic,meson8-sdio", },
+       { .compatible = "amlogic,meson8b-sdio", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, meson_mx_mmc_of_match);
+
+static struct platform_driver meson_mx_mmc_driver = {
+       .probe   = meson_mx_mmc_probe,
+       .remove  = meson_mx_mmc_remove,
+       .driver  = {
+               .name = "meson-mx-sdio",
+               .of_match_table = of_match_ptr(meson_mx_mmc_of_match),
+       },
+};
+
+module_platform_driver(meson_mx_mmc_driver);
+
+MODULE_DESCRIPTION("Meson6, Meson8 and Meson8b SDIO/MMC Host Driver");
+MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_LICENSE("GPL v2");
index f1f54a818489512a9b0aa181bc15e3fef647100d..e8a1bb1ae694234c8d40cfb86e6a1b7917e8f39c 100644 (file)
@@ -1658,7 +1658,7 @@ static int mmci_probe(struct amba_device *dev,
 
        /* Get regulators and the supported OCR mask */
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                goto clk_disable;
 
        if (!mmc->ocr_avail)
index 267f7ab08420eb6c7ebb7df588d7787acf351a7e..6457a7d8880f058a75598cdf1431933fdf740d30 100644 (file)
@@ -67,6 +67,7 @@
 #define SDC_RESP2        0x48
 #define SDC_RESP3        0x4c
 #define SDC_BLK_NUM      0x50
+#define SDC_ADV_CFG0     0x64
 #define EMMC_IOCON       0x7c
 #define SDC_ACMD_RESP    0x80
 #define MSDC_DMA_SA      0x90
 #define MSDC_DMA_CFG     0x9c
 #define MSDC_PATCH_BIT   0xb0
 #define MSDC_PATCH_BIT1  0xb4
+#define MSDC_PATCH_BIT2  0xb8
 #define MSDC_PAD_TUNE    0xec
+#define MSDC_PAD_TUNE0   0xf0
 #define PAD_DS_TUNE      0x188
 #define PAD_CMD_TUNE     0x18c
 #define EMMC50_CFG0      0x208
+#define EMMC50_CFG3      0x220
+#define SDC_FIFO_CFG     0x228
 
 /*--------------------------------------------------------------------------*/
 /* Register Mask                                                            */
 #define MSDC_CFG_CKDIV          (0xff << 8)    /* RW */
 #define MSDC_CFG_CKMOD          (0x3 << 16)    /* RW */
 #define MSDC_CFG_HS400_CK_MODE  (0x1 << 18)    /* RW */
+#define MSDC_CFG_HS400_CK_MODE_EXTRA  (0x1 << 22)      /* RW */
+#define MSDC_CFG_CKDIV_EXTRA    (0xfff << 8)   /* RW */
+#define MSDC_CFG_CKMOD_EXTRA    (0x3 << 20)    /* RW */
 
 /* MSDC_IOCON mask */
 #define MSDC_IOCON_SDR104CKS    (0x1 << 0)     /* RW */
 #define SDC_STS_CMDBUSY         (0x1 << 1)     /* RW */
 #define SDC_STS_SWR_COMPL       (0x1 << 31)    /* RW */
 
+/* SDC_ADV_CFG0 mask */
+#define SDC_RX_ENHANCE_EN      (0x1 << 20)     /* RW */
+
 /* MSDC_DMA_CTRL mask */
 #define MSDC_DMA_CTRL_START     (0x1 << 0)     /* W */
 #define MSDC_DMA_CTRL_STOP      (0x1 << 1)     /* W */
 #define MSDC_PATCH_BIT_SPCPUSH    (0x1 << 29)  /* RW */
 #define MSDC_PATCH_BIT_DECRCTMO   (0x1 << 30)  /* RW */
 
+#define MSDC_PATCH_BIT1_STOP_DLY  (0xf << 8)    /* RW */
+
+#define MSDC_PATCH_BIT2_CFGRESP   (0x1 << 15)   /* RW */
+#define MSDC_PATCH_BIT2_CFGCRCSTS (0x1 << 28)   /* RW */
+#define MSDC_PB2_RESPWAIT         (0x3 << 2)    /* RW */
+#define MSDC_PB2_RESPSTSENSEL     (0x7 << 16)   /* RW */
+#define MSDC_PB2_CRCSTSENSEL      (0x7 << 29)   /* RW */
+
 #define MSDC_PAD_TUNE_DATWRDLY   (0x1f <<  0)  /* RW */
 #define MSDC_PAD_TUNE_DATRRDLY   (0x1f <<  8)  /* RW */
 #define MSDC_PAD_TUNE_CMDRDLY    (0x1f << 16)  /* RW */
 #define MSDC_PAD_TUNE_CMDRRDLY   (0x1f << 22)  /* RW */
 #define MSDC_PAD_TUNE_CLKTDLY    (0x1f << 27)  /* RW */
+#define MSDC_PAD_TUNE_RXDLYSEL   (0x1 << 15)   /* RW */
+#define MSDC_PAD_TUNE_RD_SEL     (0x1 << 13)   /* RW */
+#define MSDC_PAD_TUNE_CMD_SEL    (0x1 << 21)   /* RW */
 
 #define PAD_DS_TUNE_DLY1         (0x1f << 2)   /* RW */
 #define PAD_DS_TUNE_DLY2         (0x1f << 7)   /* RW */
 #define EMMC50_CFG_CRCSTS_EDGE    (0x1 << 3)   /* RW */
 #define EMMC50_CFG_CFCSTS_SEL     (0x1 << 4)   /* RW */
 
+#define EMMC50_CFG3_OUTS_WR       (0x1f << 0)  /* RW */
+
+#define SDC_FIFO_CFG_WRVALIDSEL   (0x1 << 24)  /* RW */
+#define SDC_FIFO_CFG_RDVALIDSEL   (0x1 << 25)  /* RW */
+
 #define REQ_CMD_EIO  (0x1 << 0)
 #define REQ_CMD_TMO  (0x1 << 1)
 #define REQ_DAT_ERR  (0x1 << 2)
@@ -290,9 +317,23 @@ struct msdc_save_para {
        u32 pad_tune;
        u32 patch_bit0;
        u32 patch_bit1;
+       u32 patch_bit2;
        u32 pad_ds_tune;
        u32 pad_cmd_tune;
        u32 emmc50_cfg0;
+       u32 emmc50_cfg3;
+       u32 sdc_fifo_cfg;
+};
+
+struct mtk_mmc_compatible {
+       u8 clk_div_bits;
+       bool hs400_tune; /* only used for MT8173 */
+       u32 pad_tune_reg;
+       bool async_fifo;
+       bool data_tune;
+       bool busy_check;
+       bool stop_clk_fix;
+       bool enhance_rx;
 };
 
 struct msdc_tune_para {
@@ -309,6 +350,7 @@ struct msdc_delay_phase {
 
 struct msdc_host {
        struct device *dev;
+       const struct mtk_mmc_compatible *dev_comp;
        struct mmc_host *mmc;   /* mmc structure */
        int cmd_rsp;
 
@@ -334,11 +376,13 @@ struct msdc_host {
 
        struct clk *src_clk;    /* msdc source clock */
        struct clk *h_clk;      /* msdc h_clk */
+       struct clk *src_clk_cg; /* msdc source clock control gate */
        u32 mclk;               /* mmc subsystem clock frequency */
        u32 src_clk_freq;       /* source clock frequency */
        u32 sclk;               /* SD/MS bus clock frequency */
        unsigned char timing;
        bool vqmmc_enabled;
+       u32 latch_ck;
        u32 hs400_ds_delay;
        u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */
        u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */
@@ -350,6 +394,59 @@ struct msdc_host {
        struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
 };
 
+static const struct mtk_mmc_compatible mt8135_compat = {
+       .clk_div_bits = 8,
+       .hs400_tune = false,
+       .pad_tune_reg = MSDC_PAD_TUNE,
+       .async_fifo = false,
+       .data_tune = false,
+       .busy_check = false,
+       .stop_clk_fix = false,
+       .enhance_rx = false,
+};
+
+static const struct mtk_mmc_compatible mt8173_compat = {
+       .clk_div_bits = 8,
+       .hs400_tune = true,
+       .pad_tune_reg = MSDC_PAD_TUNE,
+       .async_fifo = false,
+       .data_tune = false,
+       .busy_check = false,
+       .stop_clk_fix = false,
+       .enhance_rx = false,
+};
+
+static const struct mtk_mmc_compatible mt2701_compat = {
+       .clk_div_bits = 12,
+       .hs400_tune = false,
+       .pad_tune_reg = MSDC_PAD_TUNE0,
+       .async_fifo = true,
+       .data_tune = true,
+       .busy_check = false,
+       .stop_clk_fix = false,
+       .enhance_rx = false,
+};
+
+static const struct mtk_mmc_compatible mt2712_compat = {
+       .clk_div_bits = 12,
+       .hs400_tune = false,
+       .pad_tune_reg = MSDC_PAD_TUNE0,
+       .async_fifo = true,
+       .data_tune = true,
+       .busy_check = true,
+       .stop_clk_fix = true,
+       .enhance_rx = true,
+};
+
+static const struct of_device_id msdc_of_ids[] = {
+       { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
+       { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
+       { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
+       { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
+       {}
+};
+MODULE_DEVICE_TABLE(of, msdc_of_ids);
+
 static void sdr_set_bits(void __iomem *reg, u32 bs)
 {
        u32 val = readl(reg);
@@ -509,7 +606,12 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
                timeout = (ns + clk_ns - 1) / clk_ns + clks;
                /* in 1048576 sclk cycle unit */
                timeout = (timeout + (0x1 << 20) - 1) >> 20;
-               sdr_get_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD, &mode);
+               if (host->dev_comp->clk_div_bits == 8)
+                       sdr_get_field(host->base + MSDC_CFG,
+                                     MSDC_CFG_CKMOD, &mode);
+               else
+                       sdr_get_field(host->base + MSDC_CFG,
+                                     MSDC_CFG_CKMOD_EXTRA, &mode);
                /*DDR mode will double the clk cycles for data timeout */
                timeout = mode >= 2 ? timeout * 2 : timeout;
                timeout = timeout > 1 ? timeout - 1 : 0;
@@ -520,6 +622,7 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
 
 static void msdc_gate_clock(struct msdc_host *host)
 {
+       clk_disable_unprepare(host->src_clk_cg);
        clk_disable_unprepare(host->src_clk);
        clk_disable_unprepare(host->h_clk);
 }
@@ -528,6 +631,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
 {
        clk_prepare_enable(host->h_clk);
        clk_prepare_enable(host->src_clk);
+       clk_prepare_enable(host->src_clk_cg);
        while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
                cpu_relax();
 }
@@ -538,6 +642,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
        u32 flags;
        u32 div;
        u32 sclk;
+       u32 tune_reg = host->dev_comp->pad_tune_reg;
 
        if (!hz) {
                dev_dbg(host->dev, "set mclk to 0\n");
@@ -548,7 +653,11 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
 
        flags = readl(host->base + MSDC_INTEN);
        sdr_clr_bits(host->base + MSDC_INTEN, flags);
-       sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE);
+       if (host->dev_comp->clk_div_bits == 8)
+               sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE);
+       else
+               sdr_clr_bits(host->base + MSDC_CFG,
+                            MSDC_CFG_HS400_CK_MODE_EXTRA);
        if (timing == MMC_TIMING_UHS_DDR50 ||
            timing == MMC_TIMING_MMC_DDR52 ||
            timing == MMC_TIMING_MMC_HS400) {
@@ -568,8 +677,12 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
 
                if (timing == MMC_TIMING_MMC_HS400 &&
                    hz >= (host->src_clk_freq >> 1)) {
-                       sdr_set_bits(host->base + MSDC_CFG,
-                                    MSDC_CFG_HS400_CK_MODE);
+                       if (host->dev_comp->clk_div_bits == 8)
+                               sdr_set_bits(host->base + MSDC_CFG,
+                                            MSDC_CFG_HS400_CK_MODE);
+                       else
+                               sdr_set_bits(host->base + MSDC_CFG,
+                                            MSDC_CFG_HS400_CK_MODE_EXTRA);
                        sclk = host->src_clk_freq >> 1;
                        div = 0; /* div is ignore when bit18 is set */
                }
@@ -587,11 +700,31 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
                        sclk = (host->src_clk_freq >> 2) / div;
                }
        }
-       sdr_set_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD | MSDC_CFG_CKDIV,
-                     (mode << 8) | div);
-       sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
+       sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
+       /*
+        * As src_clk/HCLK use the same bit to gate/ungate,
+        * So if want to only gate src_clk, need gate its parent(mux).
+        */
+       if (host->src_clk_cg)
+               clk_disable_unprepare(host->src_clk_cg);
+       else
+               clk_disable_unprepare(clk_get_parent(host->src_clk));
+       if (host->dev_comp->clk_div_bits == 8)
+               sdr_set_field(host->base + MSDC_CFG,
+                             MSDC_CFG_CKMOD | MSDC_CFG_CKDIV,
+                             (mode << 8) | div);
+       else
+               sdr_set_field(host->base + MSDC_CFG,
+                             MSDC_CFG_CKMOD_EXTRA | MSDC_CFG_CKDIV_EXTRA,
+                             (mode << 12) | div);
+       if (host->src_clk_cg)
+               clk_prepare_enable(host->src_clk_cg);
+       else
+               clk_prepare_enable(clk_get_parent(host->src_clk));
+
        while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
                cpu_relax();
+       sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
        host->sclk = sclk;
        host->mclk = hz;
        host->timing = timing;
@@ -605,15 +738,16 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
         */
        if (host->sclk <= 52000000) {
                writel(host->def_tune_para.iocon, host->base + MSDC_IOCON);
-               writel(host->def_tune_para.pad_tune, host->base + MSDC_PAD_TUNE);
+               writel(host->def_tune_para.pad_tune, host->base + tune_reg);
        } else {
                writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON);
-               writel(host->saved_tune_para.pad_tune, host->base + MSDC_PAD_TUNE);
+               writel(host->saved_tune_para.pad_tune, host->base + tune_reg);
                writel(host->saved_tune_para.pad_cmd_tune,
                       host->base + PAD_CMD_TUNE);
        }
 
-       if (timing == MMC_TIMING_MMC_HS400)
+       if (timing == MMC_TIMING_MMC_HS400 &&
+           host->dev_comp->hs400_tune)
                sdr_set_field(host->base + PAD_CMD_TUNE,
                              MSDC_PAD_TUNE_CMDRRDLY,
                              host->hs400_cmd_int_delay);
@@ -1165,6 +1299,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
 static void msdc_init_hw(struct msdc_host *host)
 {
        u32 val;
+       u32 tune_reg = host->dev_comp->pad_tune_reg;
 
        /* Configure to MMC/SD mode, clock free running */
        sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN);
@@ -1180,14 +1315,53 @@ static void msdc_init_hw(struct msdc_host *host)
        val = readl(host->base + MSDC_INT);
        writel(val, host->base + MSDC_INT);
 
-       writel(0, host->base + MSDC_PAD_TUNE);
+       writel(0, host->base + tune_reg);
        writel(0, host->base + MSDC_IOCON);
        sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
        writel(0x403c0046, host->base + MSDC_PATCH_BIT);
        sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1);
-       writel(0xffff0089, host->base + MSDC_PATCH_BIT1);
+       writel(0xffff4089, host->base + MSDC_PATCH_BIT1);
        sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
 
+       if (host->dev_comp->stop_clk_fix) {
+               sdr_set_field(host->base + MSDC_PATCH_BIT1,
+                             MSDC_PATCH_BIT1_STOP_DLY, 3);
+               sdr_clr_bits(host->base + SDC_FIFO_CFG,
+                            SDC_FIFO_CFG_WRVALIDSEL);
+               sdr_clr_bits(host->base + SDC_FIFO_CFG,
+                            SDC_FIFO_CFG_RDVALIDSEL);
+       }
+
+       if (host->dev_comp->busy_check)
+               sdr_clr_bits(host->base + MSDC_PATCH_BIT1, (1 << 7));
+
+       if (host->dev_comp->async_fifo) {
+               sdr_set_field(host->base + MSDC_PATCH_BIT2,
+                             MSDC_PB2_RESPWAIT, 3);
+               if (host->dev_comp->enhance_rx) {
+                       sdr_set_bits(host->base + SDC_ADV_CFG0,
+                                    SDC_RX_ENHANCE_EN);
+               } else {
+                       sdr_set_field(host->base + MSDC_PATCH_BIT2,
+                                     MSDC_PB2_RESPSTSENSEL, 2);
+                       sdr_set_field(host->base + MSDC_PATCH_BIT2,
+                                     MSDC_PB2_CRCSTSENSEL, 2);
+               }
+               /* use async fifo, then no need tune internal delay */
+               sdr_clr_bits(host->base + MSDC_PATCH_BIT2,
+                            MSDC_PATCH_BIT2_CFGRESP);
+               sdr_set_bits(host->base + MSDC_PATCH_BIT2,
+                            MSDC_PATCH_BIT2_CFGCRCSTS);
+       }
+
+       if (host->dev_comp->data_tune) {
+               sdr_set_bits(host->base + tune_reg,
+                            MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL);
+       } else {
+               /* choose clock tune */
+               sdr_set_bits(host->base + tune_reg, MSDC_PAD_TUNE_RXDLYSEL);
+       }
+
        /* Configure to enable SDIO mode.
         * it's must otherwise sdio cmd5 failed
         */
@@ -1200,7 +1374,9 @@ static void msdc_init_hw(struct msdc_host *host)
        sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
 
        host->def_tune_para.iocon = readl(host->base + MSDC_IOCON);
-       host->def_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
+       host->def_tune_para.pad_tune = readl(host->base + tune_reg);
+       host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
+       host->saved_tune_para.pad_tune = readl(host->base + tune_reg);
        dev_dbg(host->dev, "init hardware done!");
 }
 
@@ -1343,18 +1519,19 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
        struct msdc_delay_phase internal_delay_phase;
        u8 final_delay, final_maxlen;
        u32 internal_delay = 0;
+       u32 tune_reg = host->dev_comp->pad_tune_reg;
        int cmd_err;
        int i, j;
 
        if (mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
            mmc->ios.timing == MMC_TIMING_UHS_SDR104)
-               sdr_set_field(host->base + MSDC_PAD_TUNE,
+               sdr_set_field(host->base + tune_reg,
                              MSDC_PAD_TUNE_CMDRRDLY,
                              host->hs200_cmd_int_delay);
 
        sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
        for (i = 0 ; i < PAD_DELAY_MAX; i++) {
-               sdr_set_field(host->base + MSDC_PAD_TUNE,
+               sdr_set_field(host->base + tune_reg,
                              MSDC_PAD_TUNE_CMDRDLY, i);
                /*
                 * Using the same parameters, it may sometimes pass the test,
@@ -1373,12 +1550,13 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
        }
        final_rise_delay = get_best_delay(host, rise_delay);
        /* if rising edge has enough margin, then do not scan falling edge */
-       if (final_rise_delay.maxlen >= 12 && final_rise_delay.start < 4)
+       if (final_rise_delay.maxlen >= 12 ||
+           (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
                goto skip_fall;
 
        sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
        for (i = 0; i < PAD_DELAY_MAX; i++) {
-               sdr_set_field(host->base + MSDC_PAD_TUNE,
+               sdr_set_field(host->base + tune_reg,
                              MSDC_PAD_TUNE_CMDRDLY, i);
                /*
                 * Using the same parameters, it may sometimes pass the test,
@@ -1403,20 +1581,20 @@ skip_fall:
                final_maxlen = final_fall_delay.maxlen;
        if (final_maxlen == final_rise_delay.maxlen) {
                sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
-               sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+               sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
                              final_rise_delay.final_phase);
                final_delay = final_rise_delay.final_phase;
        } else {
                sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
-               sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+               sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
                              final_fall_delay.final_phase);
                final_delay = final_fall_delay.final_phase;
        }
-       if (host->hs200_cmd_int_delay)
+       if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay)
                goto skip_internal;
 
        for (i = 0; i < PAD_DELAY_MAX; i++) {
-               sdr_set_field(host->base + MSDC_PAD_TUNE,
+               sdr_set_field(host->base + tune_reg,
                              MSDC_PAD_TUNE_CMDRRDLY, i);
                mmc_send_tuning(mmc, opcode, &cmd_err);
                if (!cmd_err)
@@ -1424,7 +1602,7 @@ skip_fall:
        }
        dev_dbg(host->dev, "Final internal delay: 0x%x\n", internal_delay);
        internal_delay_phase = get_best_delay(host, internal_delay);
-       sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY,
+       sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRRDLY,
                      internal_delay_phase.final_phase);
 skip_internal:
        dev_dbg(host->dev, "Final cmd pad delay: %x\n", final_delay);
@@ -1486,12 +1664,15 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
        u32 rise_delay = 0, fall_delay = 0;
        struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
        u8 final_delay, final_maxlen;
+       u32 tune_reg = host->dev_comp->pad_tune_reg;
        int i, ret;
 
+       sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL,
+                     host->latch_ck);
        sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
        sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
        for (i = 0 ; i < PAD_DELAY_MAX; i++) {
-               sdr_set_field(host->base + MSDC_PAD_TUNE,
+               sdr_set_field(host->base + tune_reg,
                              MSDC_PAD_TUNE_DATRRDLY, i);
                ret = mmc_send_tuning(mmc, opcode, NULL);
                if (!ret)
@@ -1506,7 +1687,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
        sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
        sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
        for (i = 0; i < PAD_DELAY_MAX; i++) {
-               sdr_set_field(host->base + MSDC_PAD_TUNE,
+               sdr_set_field(host->base + tune_reg,
                              MSDC_PAD_TUNE_DATRRDLY, i);
                ret = mmc_send_tuning(mmc, opcode, NULL);
                if (!ret)
@@ -1519,14 +1700,14 @@ skip_fall:
        if (final_maxlen == final_rise_delay.maxlen) {
                sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
                sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
-               sdr_set_field(host->base + MSDC_PAD_TUNE,
+               sdr_set_field(host->base + tune_reg,
                              MSDC_PAD_TUNE_DATRRDLY,
                              final_rise_delay.final_phase);
                final_delay = final_rise_delay.final_phase;
        } else {
                sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
                sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
-               sdr_set_field(host->base + MSDC_PAD_TUNE,
+               sdr_set_field(host->base + tune_reg,
                              MSDC_PAD_TUNE_DATRRDLY,
                              final_fall_delay.final_phase);
                final_delay = final_fall_delay.final_phase;
@@ -1540,8 +1721,10 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct msdc_host *host = mmc_priv(mmc);
        int ret;
+       u32 tune_reg = host->dev_comp->pad_tune_reg;
 
-       if (host->hs400_mode)
+       if (host->hs400_mode &&
+           host->dev_comp->hs400_tune)
                ret = hs400_tune_response(mmc, opcode);
        else
                ret = msdc_tune_response(mmc, opcode);
@@ -1556,7 +1739,7 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
        }
 
        host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
-       host->saved_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
+       host->saved_tune_para.pad_tune = readl(host->base + tune_reg);
        host->saved_tune_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE);
        return ret;
 }
@@ -1567,6 +1750,11 @@ static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
        host->hs400_mode = true;
 
        writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
+       /* hs400 mode must set it to 0 */
+       sdr_clr_bits(host->base + MSDC_PATCH_BIT2, MSDC_PATCH_BIT2_CFGCRCSTS);
+       /* to improve read performance, set outstanding to 2 */
+       sdr_set_field(host->base + EMMC50_CFG3, EMMC50_CFG3_OUTS_WR, 2);
+
        return 0;
 }
 
@@ -1596,6 +1784,9 @@ static const struct mmc_host_ops mt_msdc_ops = {
 static void msdc_of_property_parse(struct platform_device *pdev,
                                   struct msdc_host *host)
 {
+       of_property_read_u32(pdev->dev.of_node, "mediatek,latch-ck",
+                            &host->latch_ck);
+
        of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay",
                             &host->hs400_ds_delay);
 
@@ -1617,12 +1808,17 @@ static int msdc_drv_probe(struct platform_device *pdev)
        struct mmc_host *mmc;
        struct msdc_host *host;
        struct resource *res;
+       const struct of_device_id *of_id;
        int ret;
 
        if (!pdev->dev.of_node) {
                dev_err(&pdev->dev, "No DT found\n");
                return -EINVAL;
        }
+
+       of_id = of_match_node(msdc_of_ids, pdev->dev.of_node);
+       if (!of_id)
+               return -EINVAL;
        /* Allocate MMC host for this device */
        mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev);
        if (!mmc)
@@ -1641,7 +1837,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
        }
 
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                goto host_free;
 
        host->src_clk = devm_clk_get(&pdev->dev, "source");
@@ -1656,6 +1852,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
                goto host_free;
        }
 
+       /*source clock control gate is optional clock*/
+       host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg");
+       if (IS_ERR(host->src_clk_cg))
+               host->src_clk_cg = NULL;
+
        host->irq = platform_get_irq(pdev, 0);
        if (host->irq < 0) {
                ret = -EINVAL;
@@ -1686,11 +1887,15 @@ static int msdc_drv_probe(struct platform_device *pdev)
        msdc_of_property_parse(pdev, host);
 
        host->dev = &pdev->dev;
+       host->dev_comp = of_id->data;
        host->mmc = mmc;
        host->src_clk_freq = clk_get_rate(host->src_clk);
        /* Set host parameters to mmc */
        mmc->ops = &mt_msdc_ops;
-       mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 255);
+       if (host->dev_comp->clk_div_bits == 8)
+               mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 255);
+       else
+               mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095);
 
        mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
        /* MMC core transfer sizes tunable parameters */
@@ -1788,28 +1993,38 @@ static int msdc_drv_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static void msdc_save_reg(struct msdc_host *host)
 {
+       u32 tune_reg = host->dev_comp->pad_tune_reg;
+
        host->save_para.msdc_cfg = readl(host->base + MSDC_CFG);
        host->save_para.iocon = readl(host->base + MSDC_IOCON);
        host->save_para.sdc_cfg = readl(host->base + SDC_CFG);
-       host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
+       host->save_para.pad_tune = readl(host->base + tune_reg);
        host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
        host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
+       host->save_para.patch_bit2 = readl(host->base + MSDC_PATCH_BIT2);
        host->save_para.pad_ds_tune = readl(host->base + PAD_DS_TUNE);
        host->save_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE);
        host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0);
+       host->save_para.emmc50_cfg3 = readl(host->base + EMMC50_CFG3);
+       host->save_para.sdc_fifo_cfg = readl(host->base + SDC_FIFO_CFG);
 }
 
 static void msdc_restore_reg(struct msdc_host *host)
 {
+       u32 tune_reg = host->dev_comp->pad_tune_reg;
+
        writel(host->save_para.msdc_cfg, host->base + MSDC_CFG);
        writel(host->save_para.iocon, host->base + MSDC_IOCON);
        writel(host->save_para.sdc_cfg, host->base + SDC_CFG);
-       writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE);
+       writel(host->save_para.pad_tune, host->base + tune_reg);
        writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
        writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
+       writel(host->save_para.patch_bit2, host->base + MSDC_PATCH_BIT2);
        writel(host->save_para.pad_ds_tune, host->base + PAD_DS_TUNE);
        writel(host->save_para.pad_cmd_tune, host->base + PAD_CMD_TUNE);
        writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0);
+       writel(host->save_para.emmc50_cfg3, host->base + EMMC50_CFG3);
+       writel(host->save_para.sdc_fifo_cfg, host->base + SDC_FIFO_CFG);
 }
 
 static int msdc_runtime_suspend(struct device *dev)
@@ -1839,12 +2054,6 @@ static const struct dev_pm_ops msdc_dev_pm_ops = {
        SET_RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL)
 };
 
-static const struct of_device_id msdc_of_ids[] = {
-       {   .compatible = "mediatek,mt8135-mmc", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, msdc_of_ids);
-
 static struct platform_driver mt_msdc_driver = {
        .probe = msdc_drv_probe,
        .remove = msdc_drv_remove,
index 58d74b8d6c7984447177486e271c5759db740fe2..210247b3d11ad50d0998216f8ddce6fb0541de2f 100644 (file)
@@ -508,9 +508,9 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
        return IRQ_NONE;
 }
 
-static void mvsd_timeout_timer(unsigned long data)
+static void mvsd_timeout_timer(struct timer_list *t)
 {
-       struct mvsd_host *host = (struct mvsd_host *)data;
+       struct mvsd_host *host = from_timer(host, t, timer);
        void __iomem *iobase = host->base;
        struct mmc_request *mrq;
        unsigned long flags;
@@ -776,7 +776,7 @@ static int mvsd_probe(struct platform_device *pdev)
                goto out;
        }
 
-       setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host);
+       timer_setup(&host->timer, mvsd_timeout_timer, 0);
        platform_set_drvdata(pdev, mmc);
        ret = mmc_add_host(mmc);
        if (ret)
index 1d5418e4efaeb0f2a07002b19e004079e9ce0bfe..5ff8ef7223cc484814b5221b1758fd839def27c5 100644 (file)
@@ -963,10 +963,9 @@ static bool filter(struct dma_chan *chan, void *param)
        return true;
 }
 
-static void mxcmci_watchdog(unsigned long data)
+static void mxcmci_watchdog(struct timer_list *t)
 {
-       struct mmc_host *mmc = (struct mmc_host *)data;
-       struct mxcmci_host *host = mmc_priv(mmc);
+       struct mxcmci_host *host = from_timer(host, t, watchdog);
        struct mmc_request *req = host->req;
        unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS);
 
@@ -1075,7 +1074,7 @@ static int mxcmci_probe(struct platform_device *pdev)
                dat3_card_detect = true;
 
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                goto out_free;
 
        if (!mmc->ocr_avail) {
@@ -1165,9 +1164,7 @@ static int mxcmci_probe(struct platform_device *pdev)
                        goto out_free_dma;
        }
 
-       init_timer(&host->watchdog);
-       host->watchdog.function = &mxcmci_watchdog;
-       host->watchdog.data = (unsigned long)mmc;
+       timer_setup(&host->watchdog, mxcmci_watchdog, 0);
 
        mmc_add_host(mmc);
 
index bd49f34d765460283e13649a6030fa358e1eaaaf..adf32682f27a3c8f96c2c244af96cae2bafbd6a8 100644 (file)
@@ -625,9 +625,9 @@ static void mmc_omap_abort_command(struct work_struct *work)
 }
 
 static void
-mmc_omap_cmd_timer(unsigned long data)
+mmc_omap_cmd_timer(struct timer_list *t)
 {
-       struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+       struct mmc_omap_host *host = from_timer(host, t, cmd_abort_timer);
        unsigned long flags;
 
        spin_lock_irqsave(&host->slot_lock, flags);
@@ -654,9 +654,9 @@ mmc_omap_sg_to_buf(struct mmc_omap_host *host)
 }
 
 static void
-mmc_omap_clk_timer(unsigned long data)
+mmc_omap_clk_timer(struct timer_list *t)
 {
-       struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+       struct mmc_omap_host *host = from_timer(host, t, clk_timer);
 
        mmc_omap_fclk_enable(host, 0);
 }
@@ -874,9 +874,9 @@ void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed)
        tasklet_hi_schedule(&slot->cover_tasklet);
 }
 
-static void mmc_omap_cover_timer(unsigned long arg)
+static void mmc_omap_cover_timer(struct timer_list *t)
 {
-       struct mmc_omap_slot *slot = (struct mmc_omap_slot *) arg;
+       struct mmc_omap_slot *slot = from_timer(slot, t, cover_timer);
        tasklet_schedule(&slot->cover_tasklet);
 }
 
@@ -1264,8 +1264,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
        mmc->max_seg_size = mmc->max_req_size;
 
        if (slot->pdata->get_cover_state != NULL) {
-               setup_timer(&slot->cover_timer, mmc_omap_cover_timer,
-                           (unsigned long)slot);
+               timer_setup(&slot->cover_timer, mmc_omap_cover_timer, 0);
                tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler,
                             (unsigned long)slot);
        }
@@ -1352,11 +1351,10 @@ static int mmc_omap_probe(struct platform_device *pdev)
        INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work);
 
        INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command);
-       setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer,
-                   (unsigned long) host);
+       timer_setup(&host->cmd_abort_timer, mmc_omap_cmd_timer, 0);
 
        spin_lock_init(&host->clk_lock);
-       setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host);
+       timer_setup(&host->clk_timer, mmc_omap_clk_timer, 0);
 
        spin_lock_init(&host->dma_lock);
        spin_lock_init(&host->slot_lock);
index 3b5e6d11069bb58b80f3da5f257d617af9664571..071693ebfe18914fe799b7da1d91df1e6f8b99b9 100644 (file)
 #define OMAP_MMC_MAX_CLOCK     52000000
 #define DRIVER_NAME            "omap_hsmmc"
 
-#define VDD_1V8                        1800000         /* 180000 uV */
-#define VDD_3V0                        3000000         /* 300000 uV */
-#define VDD_165_195            (ffs(MMC_VDD_165_195) - 1)
-
 /*
  * One controller can have multiple slots, like on some omap boards using
  * omap.c controller driver. Luckily this is not currently done on any known
@@ -308,8 +304,7 @@ err_set_ocr:
        return ret;
 }
 
-static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
-                               int vdd)
+static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on)
 {
        int ret;
 
@@ -317,17 +312,6 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
                return 0;
 
        if (power_on) {
-               if (vdd <= VDD_165_195)
-                       ret = regulator_set_voltage(host->pbias, VDD_1V8,
-                                                   VDD_1V8);
-               else
-                       ret = regulator_set_voltage(host->pbias, VDD_3V0,
-                                                   VDD_3V0);
-               if (ret < 0) {
-                       dev_err(host->dev, "pbias set voltage fail\n");
-                       return ret;
-               }
-
                if (host->pbias_enabled == 0) {
                        ret = regulator_enable(host->pbias);
                        if (ret) {
@@ -350,8 +334,7 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
        return 0;
 }
 
-static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
-                               int vdd)
+static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on)
 {
        struct mmc_host *mmc = host->mmc;
        int ret = 0;
@@ -363,7 +346,7 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
        if (IS_ERR(mmc->supply.vmmc))
                return 0;
 
-       ret = omap_hsmmc_set_pbias(host, false, 0);
+       ret = omap_hsmmc_set_pbias(host, false);
        if (ret)
                return ret;
 
@@ -385,7 +368,7 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
                if (ret)
                        return ret;
 
-               ret = omap_hsmmc_set_pbias(host, true, vdd);
+               ret = omap_hsmmc_set_pbias(host, true);
                if (ret)
                        goto err_set_voltage;
        } else {
@@ -462,7 +445,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 
 
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                return ret;
 
        /* Allow an aux regulator */
@@ -1220,11 +1203,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
                clk_disable_unprepare(host->dbclk);
 
        /* Turn the power off */
-       ret = omap_hsmmc_set_power(host, 0, 0);
+       ret = omap_hsmmc_set_power(host, 0);
 
        /* Turn the power ON with given VDD 1.8 or 3.0v */
        if (!ret)
-               ret = omap_hsmmc_set_power(host, 1, vdd);
+               ret = omap_hsmmc_set_power(host, 1);
        if (host->dbclk)
                clk_prepare_enable(host->dbclk);
 
@@ -1621,10 +1604,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        if (ios->power_mode != host->power_mode) {
                switch (ios->power_mode) {
                case MMC_POWER_OFF:
-                       omap_hsmmc_set_power(host, 0, 0);
+                       omap_hsmmc_set_power(host, 0);
                        break;
                case MMC_POWER_UP:
-                       omap_hsmmc_set_power(host, 1, ios->vdd);
+                       omap_hsmmc_set_power(host, 1);
                        break;
                case MMC_POWER_ON:
                        do_send_init_stream = 1;
index 8bae88a150fd45b3284b594d2d090d4f78fe1fc7..41cbe84c1d18ad6a54e703874c8806d1c19aaa35 100644 (file)
@@ -88,6 +88,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
 static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
        { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
        { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
+       { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
        {},
 };
 MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
index df4465439e13c44245c136fb3e02f3eb81545e6f..9ab10436e4b8bafd13fa265a1e16c43acd9cfe96 100644 (file)
@@ -91,7 +91,6 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
 };
 
 static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
-       { .compatible = "renesas,sdhi-shmobile" },
        { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
        { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
        { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
@@ -107,6 +106,10 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
        { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
        { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
        { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
+       { .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
+       { .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
+       { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
+       { .compatible = "renesas,sdhi-shmobile" },
        {},
 };
 MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match);
index 41b57713b620aecdb2e3a3348c0a9d8949e7ce49..0848dc0f882e1b7c5269bff0416544bee0c94d21 100644 (file)
@@ -618,29 +618,22 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
                u8 sample_point, bool rx)
 {
        struct rtsx_pcr *pcr = host->pcr;
-       int err;
 
        dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n",
                        __func__, rx ? "RX" : "TX", sample_point);
 
-       rtsx_pci_init_cmd(pcr);
-
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK);
+       rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, CHANGE_CLK);
        if (rx)
-               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-                               SD_VPRX_CTL, 0x1F, sample_point);
+               rtsx_pci_write_register(pcr, SD_VPRX_CTL,
+                       PHASE_SELECT_MASK, sample_point);
        else
-               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-                               SD_VPTX_CTL, 0x1F, sample_point);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
-                       PHASE_NOT_RESET, PHASE_NOT_RESET);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, 0);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
-
-       err = rtsx_pci_send_cmd(pcr, 100);
-       if (err < 0)
-               return err;
+               rtsx_pci_write_register(pcr, SD_VPTX_CTL,
+                       PHASE_SELECT_MASK, sample_point);
+       rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
+       rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET,
+                               PHASE_NOT_RESET);
+       rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, 0);
+       rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
 
        return 0;
 }
@@ -708,10 +701,12 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
 {
        int err;
        struct mmc_command cmd = {};
+       struct rtsx_pcr *pcr = host->pcr;
 
-       err = sd_change_phase(host, sample_point, true);
-       if (err < 0)
-               return err;
+       sd_change_phase(host, sample_point, true);
+
+       rtsx_pci_write_register(pcr, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
+               SD_RSP_80CLK_TIMEOUT_EN);
 
        cmd.opcode = opcode;
        err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100);
@@ -719,9 +714,12 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
                /* Wait till SD DATA IDLE */
                sd_wait_data_idle(host);
                sd_clear_error(host);
+               rtsx_pci_write_register(pcr, SD_CFG3,
+                       SD_RSP_80CLK_TIMEOUT_EN, 0);
                return err;
        }
 
+       rtsx_pci_write_register(pcr, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, 0);
        return 0;
 }
 
index 08ae0ff13513bd795ae5517cd12dd1d2363792cf..b988997a1e80df0d3b70c343cb8d313db8eab891 100644 (file)
@@ -73,6 +73,7 @@ struct sdhci_acpi_slot {
        unsigned int    caps2;
        mmc_pm_flag_t   pm_caps;
        unsigned int    flags;
+       size_t          priv_size;
        int (*probe_slot)(struct platform_device *, const char *, const char *);
        int (*remove_slot)(struct platform_device *);
 };
@@ -82,13 +83,118 @@ struct sdhci_acpi_host {
        const struct sdhci_acpi_slot    *slot;
        struct platform_device          *pdev;
        bool                            use_runtime_pm;
+       unsigned long                   private[0] ____cacheline_aligned;
 };
 
+static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c)
+{
+       return (void *)c->private;
+}
+
 static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
 {
        return c->slot && (c->slot->flags & flag);
 }
 
+enum {
+       INTEL_DSM_FNS           =  0,
+       INTEL_DSM_V18_SWITCH    =  3,
+       INTEL_DSM_V33_SWITCH    =  4,
+};
+
+struct intel_host {
+       u32     dsm_fns;
+};
+
+static const guid_t intel_dsm_guid =
+       GUID_INIT(0xF6C13EA5, 0x65CD, 0x461F,
+                 0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61);
+
+static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
+                      unsigned int fn, u32 *result)
+{
+       union acpi_object *obj;
+       int err = 0;
+
+       obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL);
+       if (!obj)
+               return -EOPNOTSUPP;
+
+       if (obj->type == ACPI_TYPE_INTEGER) {
+               *result = obj->integer.value;
+       } else if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length > 0) {
+               size_t len = min_t(size_t, obj->buffer.length, 4);
+
+               *result = 0;
+               memcpy(result, obj->buffer.pointer, len);
+       } else {
+               dev_err(dev, "%s DSM fn %u obj->type %d obj->buffer.length %d\n",
+                       __func__, fn, obj->type, obj->buffer.length);
+               err = -EINVAL;
+       }
+
+       ACPI_FREE(obj);
+
+       return err;
+}
+
+static int intel_dsm(struct intel_host *intel_host, struct device *dev,
+                    unsigned int fn, u32 *result)
+{
+       if (fn > 31 || !(intel_host->dsm_fns & (1 << fn)))
+               return -EOPNOTSUPP;
+
+       return __intel_dsm(intel_host, dev, fn, result);
+}
+
+static void intel_dsm_init(struct intel_host *intel_host, struct device *dev,
+                          struct mmc_host *mmc)
+{
+       int err;
+
+       err = __intel_dsm(intel_host, dev, INTEL_DSM_FNS, &intel_host->dsm_fns);
+       if (err) {
+               pr_debug("%s: DSM not supported, error %d\n",
+                        mmc_hostname(mmc), err);
+               return;
+       }
+
+       pr_debug("%s: DSM function mask %#x\n",
+                mmc_hostname(mmc), intel_host->dsm_fns);
+}
+
+static int intel_start_signal_voltage_switch(struct mmc_host *mmc,
+                                            struct mmc_ios *ios)
+{
+       struct device *dev = mmc_dev(mmc);
+       struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+       struct intel_host *intel_host = sdhci_acpi_priv(c);
+       unsigned int fn;
+       u32 result = 0;
+       int err;
+
+       err = sdhci_start_signal_voltage_switch(mmc, ios);
+       if (err)
+               return err;
+
+       switch (ios->signal_voltage) {
+       case MMC_SIGNAL_VOLTAGE_330:
+               fn = INTEL_DSM_V33_SWITCH;
+               break;
+       case MMC_SIGNAL_VOLTAGE_180:
+               fn = INTEL_DSM_V18_SWITCH;
+               break;
+       default:
+               return 0;
+       }
+
+       err = intel_dsm(intel_host, dev, fn, &result);
+       pr_debug("%s: %s DSM fn %u error %d result %u\n",
+                mmc_hostname(mmc), __func__, fn, err, result);
+
+       return 0;
+}
+
 static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
 {
        u8 reg;
@@ -269,56 +375,26 @@ out:
        return ret;
 }
 
-static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev,
-                                     const char *hid, const char *uid)
+static int intel_probe_slot(struct platform_device *pdev, const char *hid,
+                           const char *uid)
 {
        struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
-       struct sdhci_host *host;
-
-       if (!c || !c->host)
-               return 0;
-
-       host = c->host;
-
-       /* Platform specific code during emmc probe slot goes here */
+       struct intel_host *intel_host = sdhci_acpi_priv(c);
+       struct sdhci_host *host = c->host;
 
        if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") &&
            sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 &&
            sdhci_readl(host, SDHCI_CAPABILITIES_1) == 0x00000807)
                host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
 
-       return 0;
-}
-
-static int sdhci_acpi_sdio_probe_slot(struct platform_device *pdev,
-                                     const char *hid, const char *uid)
-{
-       struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
-
-       if (!c || !c->host)
-               return 0;
-
-       /* Platform specific code during sdio probe slot goes here */
-
-       return 0;
-}
-
-static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
-                                   const char *hid, const char *uid)
-{
-       struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
-       struct sdhci_host *host;
-
-       if (!c || !c->host || !c->slot)
-               return 0;
-
-       host = c->host;
-
-       /* Platform specific code during sd probe slot goes here */
-
        if (hid && !strcmp(hid, "80865ACA"))
                host->mmc_host_ops.get_cd = bxt_get_cd;
 
+       intel_dsm_init(intel_host, &pdev->dev, host->mmc);
+
+       host->mmc_host_ops.start_signal_voltage_switch =
+                                       intel_start_signal_voltage_switch;
+
        return 0;
 }
 
@@ -332,7 +408,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
                   SDHCI_QUIRK2_STOP_WITH_TC |
                   SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
-       .probe_slot     = sdhci_acpi_emmc_probe_slot,
+       .probe_slot     = intel_probe_slot,
+       .priv_size      = sizeof(struct intel_host),
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
@@ -343,7 +420,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
                   MMC_CAP_WAIT_WHILE_BUSY,
        .flags   = SDHCI_ACPI_RUNTIME_PM,
        .pm_caps = MMC_PM_KEEP_POWER,
-       .probe_slot     = sdhci_acpi_sdio_probe_slot,
+       .probe_slot     = intel_probe_slot,
+       .priv_size      = sizeof(struct intel_host),
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
@@ -353,7 +431,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
        .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
                   SDHCI_QUIRK2_STOP_WITH_TC,
        .caps    = MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM,
-       .probe_slot     = sdhci_acpi_sd_probe_slot,
+       .probe_slot     = intel_probe_slot,
+       .priv_size      = sizeof(struct intel_host),
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = {
@@ -429,11 +508,13 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid,
 static int sdhci_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       const struct sdhci_acpi_slot *slot;
        struct acpi_device *device, *child;
        struct sdhci_acpi_host *c;
        struct sdhci_host *host;
        struct resource *iomem;
        resource_size_t len;
+       size_t priv_size;
        const char *hid;
        const char *uid;
        int err;
@@ -443,7 +524,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
                return -ENODEV;
 
        hid = acpi_device_hid(device);
-       uid = device->pnp.unique_id;
+       uid = acpi_device_uid(device);
+
+       slot = sdhci_acpi_get_slot(hid, uid);
 
        /* Power on the SDHCI controller and its children */
        acpi_device_fix_up_power(device);
@@ -467,13 +550,14 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev)))
                return -ENOMEM;
 
-       host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host));
+       priv_size = slot ? slot->priv_size : 0;
+       host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host) + priv_size);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
        c = sdhci_priv(host);
        c->host = host;
-       c->slot = sdhci_acpi_get_slot(hid, uid);
+       c->slot = slot;
        c->pdev = pdev;
        c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM);
 
index 56529c3d389ae389d647e1251cb486a8002ea09f..0f589e26ee6399d6087a776b174df7c3a6bc522b 100644 (file)
@@ -13,6 +13,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #define   SDHCI_CDNS_HRS04_ACK                 BIT(26)
 #define   SDHCI_CDNS_HRS04_RD                  BIT(25)
 #define   SDHCI_CDNS_HRS04_WR                  BIT(24)
-#define   SDHCI_CDNS_HRS04_RDATA_SHIFT         16
-#define   SDHCI_CDNS_HRS04_WDATA_SHIFT         8
-#define   SDHCI_CDNS_HRS04_ADDR_SHIFT          0
+#define   SDHCI_CDNS_HRS04_RDATA               GENMASK(23, 16)
+#define   SDHCI_CDNS_HRS04_WDATA               GENMASK(15, 8)
+#define   SDHCI_CDNS_HRS04_ADDR                        GENMASK(5, 0)
 
 #define SDHCI_CDNS_HRS06               0x18            /* eMMC control */
 #define   SDHCI_CDNS_HRS06_TUNE_UP             BIT(15)
-#define   SDHCI_CDNS_HRS06_TUNE_SHIFT          8
-#define   SDHCI_CDNS_HRS06_TUNE_MASK           0x3f
-#define   SDHCI_CDNS_HRS06_MODE_MASK           0x7
+#define   SDHCI_CDNS_HRS06_TUNE                        GENMASK(13, 8)
+#define   SDHCI_CDNS_HRS06_MODE                        GENMASK(2, 0)
 #define   SDHCI_CDNS_HRS06_MODE_SD             0x0
 #define   SDHCI_CDNS_HRS06_MODE_MMC_SDR                0x2
 #define   SDHCI_CDNS_HRS06_MODE_MMC_DDR                0x3
@@ -105,8 +105,8 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
        u32 tmp;
        int ret;
 
-       tmp = (data << SDHCI_CDNS_HRS04_WDATA_SHIFT) |
-             (addr << SDHCI_CDNS_HRS04_ADDR_SHIFT);
+       tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
+             FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
        writel(tmp, reg);
 
        tmp |= SDHCI_CDNS_HRS04_WR;
@@ -189,8 +189,8 @@ static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode)
 
        /* The speed mode for eMMC is selected by HRS06 register */
        tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06);
-       tmp &= ~SDHCI_CDNS_HRS06_MODE_MASK;
-       tmp |= mode;
+       tmp &= ~SDHCI_CDNS_HRS06_MODE;
+       tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode);
        writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS06);
 }
 
@@ -199,7 +199,7 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
        u32 tmp;
 
        tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06);
-       return tmp & SDHCI_CDNS_HRS06_MODE_MASK;
+       return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
 }
 
 static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
@@ -254,12 +254,12 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
        void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
        u32 tmp;
 
-       if (WARN_ON(val > SDHCI_CDNS_HRS06_TUNE_MASK))
+       if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
                return -EINVAL;
 
        tmp = readl(reg);
-       tmp &= ~(SDHCI_CDNS_HRS06_TUNE_MASK << SDHCI_CDNS_HRS06_TUNE_SHIFT);
-       tmp |= val << SDHCI_CDNS_HRS06_TUNE_SHIFT;
+       tmp &= ~SDHCI_CDNS_HRS06_TUNE;
+       tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
        tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
        writel(tmp, reg);
 
index fc73e56eb1e2ef4f22f29142899c45b809f2dad7..3fb7d2eec93f4d72d63dbc5983e47a2b8dbc710d 100644 (file)
 #define CMUX_SHIFT_PHASE_MASK  (7 << CMUX_SHIFT_PHASE_SHIFT)
 
 #define MSM_MMC_AUTOSUSPEND_DELAY_MS   50
+
+/* Timeout value to avoid infinite waiting for pwr_irq */
+#define MSM_PWR_IRQ_TIMEOUT_MS 5000
+
 struct sdhci_msm_host {
        struct platform_device *pdev;
        void __iomem *core_mem; /* MSM SDCC mapped address */
        int pwr_irq;            /* power irq */
-       struct clk *clk;        /* main SD/MMC bus clock */
-       struct clk *pclk;       /* SDHC peripheral bus clock */
        struct clk *bus_clk;    /* SDHC bus voter clock */
        struct clk *xo_clk;     /* TCXO clk needed for FLL feature of cm_dll*/
+       struct clk_bulk_data bulk_clks[4]; /* core, iface, cal, sleep clocks */
        unsigned long clk_rate;
        struct mmc_host *mmc;
        bool use_14lpp_dll_reset;
@@ -138,6 +141,10 @@ struct sdhci_msm_host {
        bool calibration_done;
        u8 saved_tuning_phase;
        bool use_cdclp533;
+       u32 curr_pwr_state;
+       u32 curr_io_level;
+       wait_queue_head_t pwr_irq_wait;
+       bool pwr_irq_flag;
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -164,10 +171,11 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host,
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
        struct mmc_ios curr_ios = host->mmc->ios;
+       struct clk *core_clk = msm_host->bulk_clks[0].clk;
        int rc;
 
        clock = msm_get_clock_rate_for_bus_mode(host, clock);
-       rc = clk_set_rate(msm_host->clk, clock);
+       rc = clk_set_rate(core_clk, clock);
        if (rc) {
                pr_err("%s: Failed to set clock at rate %u at timing %d\n",
                       mmc_hostname(host->mmc), clock,
@@ -176,7 +184,7 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host,
        }
        msm_host->clk_rate = clock;
        pr_debug("%s: Setting clock at rate %lu at timing %d\n",
-                mmc_hostname(host->mmc), clk_get_rate(msm_host->clk),
+                mmc_hostname(host->mmc), clk_get_rate(core_clk),
                 curr_ios.timing);
 }
 
@@ -995,21 +1003,142 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
                sdhci_msm_hs400(host, &mmc->ios);
 }
 
-static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+static inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host)
+{
+       init_waitqueue_head(&msm_host->pwr_irq_wait);
+}
+
+static inline void sdhci_msm_complete_pwr_irq_wait(
+               struct sdhci_msm_host *msm_host)
+{
+       wake_up(&msm_host->pwr_irq_wait);
+}
+
+/*
+ * sdhci_msm_check_power_status API should be called when registers writes
+ * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
+ * To what state the register writes will change the IO lines should be passed
+ * as the argument req_type. This API will check whether the IO line's state
+ * is already the expected state and will wait for power irq only if
+ * power irq is expected to be trigerred based on the current IO line state
+ * and expected IO line state.
+ */
+static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       bool done = false;
+
+       pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
+                       mmc_hostname(host->mmc), __func__, req_type,
+                       msm_host->curr_pwr_state, msm_host->curr_io_level);
+
+       /*
+        * The IRQ for request type IO High/LOW will be generated when -
+        * there is a state change in 1.8V enable bit (bit 3) of
+        * SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
+        * which indicates 3.3V IO voltage. So, when MMC core layer tries
+        * to set it to 3.3V before card detection happens, the
+        * IRQ doesn't get triggered as there is no state change in this bit.
+        * The driver already handles this case by changing the IO voltage
+        * level to high as part of controller power up sequence. Hence, check
+        * for host->pwr to handle a case where IO voltage high request is
+        * issued even before controller power up.
+        */
+       if ((req_type & REQ_IO_HIGH) && !host->pwr) {
+               pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n",
+                               mmc_hostname(host->mmc), req_type);
+               return;
+       }
+       if ((req_type & msm_host->curr_pwr_state) ||
+                       (req_type & msm_host->curr_io_level))
+               done = true;
+       /*
+        * This is needed here to handle cases where register writes will
+        * not change the current bus state or io level of the controller.
+        * In this case, no power irq will be triggerred and we should
+        * not wait.
+        */
+       if (!done) {
+               if (!wait_event_timeout(msm_host->pwr_irq_wait,
+                               msm_host->pwr_irq_flag,
+                               msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
+                       dev_warn(&msm_host->pdev->dev,
+                                "%s: pwr_irq for req: (%d) timed out\n",
+                                mmc_hostname(host->mmc), req_type);
+       }
+       pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
+                       __func__, req_type);
+}
+
+static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+       pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n",
+                       mmc_hostname(host->mmc),
+                       readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS),
+                       readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK),
+                       readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+}
+
+static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
        u32 irq_status, irq_ack = 0;
+       int retry = 10;
+       int pwr_state = 0, io_level = 0;
+
 
        irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
        irq_status &= INT_MASK;
 
        writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
 
-       if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
+       /*
+        * There is a rare HW scenario where the first clear pulse could be
+        * lost when actual reset and clear/read of status register is
+        * happening at a time. Hence, retry for at least 10 times to make
+        * sure status register is cleared. Otherwise, this will result in
+        * a spurious power IRQ resulting in system instability.
+        */
+       while (irq_status & readl_relaxed(msm_host->core_mem +
+                               CORE_PWRCTL_STATUS)) {
+               if (retry == 0) {
+                       pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
+                                       mmc_hostname(host->mmc), irq_status);
+                       sdhci_msm_dump_pwr_ctrl_regs(host);
+                       WARN_ON(1);
+                       break;
+               }
+               writel_relaxed(irq_status,
+                               msm_host->core_mem + CORE_PWRCTL_CLEAR);
+               retry--;
+               udelay(10);
+       }
+
+       /* Handle BUS ON/OFF*/
+       if (irq_status & CORE_PWRCTL_BUS_ON) {
+               pwr_state = REQ_BUS_ON;
+               io_level = REQ_IO_HIGH;
+               irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+       }
+       if (irq_status & CORE_PWRCTL_BUS_OFF) {
+               pwr_state = REQ_BUS_OFF;
+               io_level = REQ_IO_LOW;
                irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
-       if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
+       }
+       /* Handle IO LOW/HIGH */
+       if (irq_status & CORE_PWRCTL_IO_LOW) {
+               io_level = REQ_IO_LOW;
+               irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+       }
+       if (irq_status & CORE_PWRCTL_IO_HIGH) {
+               io_level = REQ_IO_HIGH;
                irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+       }
 
        /*
         * The driver has to acknowledge the interrupt, switch voltages and
@@ -1017,13 +1146,27 @@ static void sdhci_msm_voltage_switch(struct sdhci_host *host)
         * switches are handled by the sdhci core, so just report success.
         */
        writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+
+       if (pwr_state)
+               msm_host->curr_pwr_state = pwr_state;
+       if (io_level)
+               msm_host->curr_io_level = io_level;
+
+       pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
+               mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
+               irq_ack);
 }
 
 static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 {
        struct sdhci_host *host = (struct sdhci_host *)data;
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+       sdhci_msm_handle_pwr_irq(host, irq);
+       msm_host->pwr_irq_flag = 1;
+       sdhci_msm_complete_pwr_irq_wait(msm_host);
 
-       sdhci_msm_voltage_switch(host);
 
        return IRQ_HANDLED;
 }
@@ -1032,8 +1175,9 @@ static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       struct clk *core_clk = msm_host->bulk_clks[0].clk;
 
-       return clk_round_rate(msm_host->clk, ULONG_MAX);
+       return clk_round_rate(core_clk, ULONG_MAX);
 }
 
 static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
@@ -1092,6 +1236,69 @@ out:
        __sdhci_msm_set_clock(host, clock);
 }
 
+/*
+ * Platform specific register write functions. This is so that, if any
+ * register write needs to be followed up by platform specific actions,
+ * they can be added here. These functions can go to sleep when writes
+ * to certain registers are done.
+ * These functions are relying on sdhci_set_ios not using spinlock.
+ */
+static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       u32 req_type = 0;
+
+       switch (reg) {
+       case SDHCI_HOST_CONTROL2:
+               req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW :
+                       REQ_IO_HIGH;
+               break;
+       case SDHCI_SOFTWARE_RESET:
+               if (host->pwr && (val & SDHCI_RESET_ALL))
+                       req_type = REQ_BUS_OFF;
+               break;
+       case SDHCI_POWER_CONTROL:
+               req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
+               break;
+       }
+
+       if (req_type) {
+               msm_host->pwr_irq_flag = 0;
+               /*
+                * Since this register write may trigger a power irq, ensure
+                * all previous register writes are complete by this point.
+                */
+               mb();
+       }
+       return req_type;
+}
+
+/* This function may sleep*/
+static void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg)
+{
+       u32 req_type = 0;
+
+       req_type = __sdhci_msm_check_write(host, val, reg);
+       writew_relaxed(val, host->ioaddr + reg);
+
+       if (req_type)
+               sdhci_msm_check_power_status(host, req_type);
+}
+
+/* This function may sleep*/
+static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+       u32 req_type = 0;
+
+       req_type = __sdhci_msm_check_write(host, val, reg);
+
+       writeb_relaxed(val, host->ioaddr + reg);
+
+       if (req_type)
+               sdhci_msm_check_power_status(host, req_type);
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
        { .compatible = "qcom,sdhci-msm-v4" },
        {},
@@ -1106,7 +1313,8 @@ static const struct sdhci_ops sdhci_msm_ops = {
        .get_max_clock = sdhci_msm_get_max_clock,
        .set_bus_width = sdhci_set_bus_width,
        .set_uhs_signaling = sdhci_msm_set_uhs_signaling,
-       .voltage_switch = sdhci_msm_voltage_switch,
+       .write_w = sdhci_msm_writew,
+       .write_b = sdhci_msm_writeb,
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
@@ -1124,6 +1332,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_msm_host *msm_host;
        struct resource *core_memres;
+       struct clk *clk;
        int ret;
        u16 host_version, core_minor;
        u32 core_version, config;
@@ -1160,24 +1369,42 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        }
 
        /* Setup main peripheral bus clock */
-       msm_host->pclk = devm_clk_get(&pdev->dev, "iface");
-       if (IS_ERR(msm_host->pclk)) {
-               ret = PTR_ERR(msm_host->pclk);
+       clk = devm_clk_get(&pdev->dev, "iface");
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
                dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
                goto bus_clk_disable;
        }
-
-       ret = clk_prepare_enable(msm_host->pclk);
-       if (ret)
-               goto bus_clk_disable;
+       msm_host->bulk_clks[1].clk = clk;
 
        /* Setup SDC MMC clock */
-       msm_host->clk = devm_clk_get(&pdev->dev, "core");
-       if (IS_ERR(msm_host->clk)) {
-               ret = PTR_ERR(msm_host->clk);
+       clk = devm_clk_get(&pdev->dev, "core");
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
                dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
-               goto pclk_disable;
+               goto bus_clk_disable;
        }
+       msm_host->bulk_clks[0].clk = clk;
+
+       /* Vote for maximum clock rate for maximum performance */
+       ret = clk_set_rate(clk, INT_MAX);
+       if (ret)
+               dev_warn(&pdev->dev, "core clock boost failed\n");
+
+       clk = devm_clk_get(&pdev->dev, "cal");
+       if (IS_ERR(clk))
+               clk = NULL;
+       msm_host->bulk_clks[2].clk = clk;
+
+       clk = devm_clk_get(&pdev->dev, "sleep");
+       if (IS_ERR(clk))
+               clk = NULL;
+       msm_host->bulk_clks[3].clk = clk;
+
+       ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
+                                     msm_host->bulk_clks);
+       if (ret)
+               goto bus_clk_disable;
 
        /*
         * xo clock is needed for FLL feature of cm_dll.
@@ -1189,15 +1416,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret);
        }
 
-       /* Vote for maximum clock rate for maximum performance */
-       ret = clk_set_rate(msm_host->clk, INT_MAX);
-       if (ret)
-               dev_warn(&pdev->dev, "core clock boost failed\n");
-
-       ret = clk_prepare_enable(msm_host->clk);
-       if (ret)
-               goto pclk_disable;
-
        core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres);
 
@@ -1251,6 +1469,21 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                               CORE_VENDOR_SPEC_CAPABILITIES0);
        }
 
+       /*
+        * Power on reset state may trigger power irq if previous status of
+        * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
+        * interrupt in GIC, any pending power irq interrupt should be
+        * acknowledged. Otherwise power irq interrupt handler would be
+        * fired prematurely.
+        */
+       sdhci_msm_handle_pwr_irq(host, 0);
+
+       /*
+        * Ensure that above writes are propogated before interrupt enablement
+        * in GIC.
+        */
+       mb();
+
        /* Setup IRQ for handling power/voltage tasks with PMIC */
        msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
        if (msm_host->pwr_irq < 0) {
@@ -1260,6 +1493,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                goto clk_disable;
        }
 
+       sdhci_msm_init_pwr_irq_wait(msm_host);
+       /* Enable pwr irq interrupts */
+       writel_relaxed(INT_MASK, msm_host->core_mem + CORE_PWRCTL_MASK);
+
        ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
                                        sdhci_msm_pwr_irq, IRQF_ONESHOT,
                                        dev_name(&pdev->dev), host);
@@ -1290,9 +1527,8 @@ pm_runtime_disable:
        pm_runtime_set_suspended(&pdev->dev);
        pm_runtime_put_noidle(&pdev->dev);
 clk_disable:
-       clk_disable_unprepare(msm_host->clk);
-pclk_disable:
-       clk_disable_unprepare(msm_host->pclk);
+       clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
+                                  msm_host->bulk_clks);
 bus_clk_disable:
        if (!IS_ERR(msm_host->bus_clk))
                clk_disable_unprepare(msm_host->bus_clk);
@@ -1315,8 +1551,8 @@ static int sdhci_msm_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
        pm_runtime_put_noidle(&pdev->dev);
 
-       clk_disable_unprepare(msm_host->clk);
-       clk_disable_unprepare(msm_host->pclk);
+       clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
+                                  msm_host->bulk_clks);
        if (!IS_ERR(msm_host->bus_clk))
                clk_disable_unprepare(msm_host->bus_clk);
        sdhci_pltfm_free(pdev);
@@ -1330,8 +1566,8 @@ static int sdhci_msm_runtime_suspend(struct device *dev)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
 
-       clk_disable_unprepare(msm_host->clk);
-       clk_disable_unprepare(msm_host->pclk);
+       clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
+                                  msm_host->bulk_clks);
 
        return 0;
 }
@@ -1341,21 +1577,9 @@ static int sdhci_msm_runtime_resume(struct device *dev)
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
-       int ret;
 
-       ret = clk_prepare_enable(msm_host->clk);
-       if (ret) {
-               dev_err(dev, "clk_enable failed for core_clk: %d\n", ret);
-               return ret;
-       }
-       ret = clk_prepare_enable(msm_host->pclk);
-       if (ret) {
-               dev_err(dev, "clk_enable failed for iface_clk: %d\n", ret);
-               clk_disable_unprepare(msm_host->clk);
-               return ret;
-       }
-
-       return 0;
+       return clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
+                                      msm_host->bulk_clks);
 }
 #endif
 
index 4e47ed6bc7165be458feaef96d952826952908f9..682c573e20a727e118282b33eae9d982917e138f 100644 (file)
@@ -114,7 +114,8 @@ static void sdhci_at91_set_power(struct sdhci_host *host, unsigned char mode,
        sdhci_set_power_noreg(host, mode, vdd);
 }
 
-void sdhci_at91_set_uhs_signaling(struct sdhci_host *host, unsigned int timing)
+static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host,
+                                        unsigned int timing)
 {
        if (timing == MMC_TIMING_MMC_DDR52)
                sdhci_writeb(host, SDMMC_MC1R_DDR, SDMMC_MC1R);
index d96a057a7db88e8ae0d023aad9d0b2d4fab909eb..1f424374bbbb5de29aec74ded1f3137587f8e6de 100644 (file)
@@ -458,6 +458,33 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
        return clock / 256 / 16;
 }
 
+static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
+{
+       u32 val;
+       ktime_t timeout;
+
+       val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+
+       if (enable)
+               val |= ESDHC_CLOCK_SDCLKEN;
+       else
+               val &= ~ESDHC_CLOCK_SDCLKEN;
+
+       sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
+
+       /* Wait max 20 ms */
+       timeout = ktime_add_ms(ktime_get(), 20);
+       val = ESDHC_CLOCK_STABLE;
+       while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) {
+               if (ktime_after(ktime_get(), timeout)) {
+                       pr_err("%s: Internal clock never stabilised.\n",
+                               mmc_hostname(host->mmc));
+                       break;
+               }
+               udelay(10);
+       }
+}
+
 static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -469,8 +496,10 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 
        host->mmc->actual_clock = 0;
 
-       if (clock == 0)
+       if (clock == 0) {
+               esdhc_clock_enable(host, false);
                return;
+       }
 
        /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
        if (esdhc->vendor_ver < VENDOR_V_23)
@@ -558,33 +587,6 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
        sdhci_writel(host, ctrl, ESDHC_PROCTL);
 }
 
-static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
-{
-       u32 val;
-       ktime_t timeout;
-
-       val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
-
-       if (enable)
-               val |= ESDHC_CLOCK_SDCLKEN;
-       else
-               val &= ~ESDHC_CLOCK_SDCLKEN;
-
-       sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
-
-       /* Wait max 20 ms */
-       timeout = ktime_add_ms(ktime_get(), 20);
-       val = ESDHC_CLOCK_STABLE;
-       while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) {
-               if (ktime_after(ktime_get(), timeout)) {
-                       pr_err("%s: Internal clock never stabilised.\n",
-                               mmc_hostname(host->mmc));
-                       break;
-               }
-               udelay(10);
-       }
-}
-
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
 {
        sdhci_reset(host, mask);
diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
new file mode 100644 (file)
index 0000000..628bfe9
--- /dev/null
@@ -0,0 +1,607 @@
+/**
+ * SDHCI Controller driver for TI's OMAP SoCs
+ *
+ * Copyright (C) 2017 Texas Instruments
+ * Author: Kishon Vijay Abraham I <kishon@ti.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 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include "sdhci-pltfm.h"
+
+#define SDHCI_OMAP_CON         0x12c
+#define CON_DW8                        BIT(5)
+#define CON_DMA_MASTER         BIT(20)
+#define CON_INIT               BIT(1)
+#define CON_OD                 BIT(0)
+
+#define SDHCI_OMAP_CMD         0x20c
+
+#define SDHCI_OMAP_HCTL                0x228
+#define HCTL_SDBP              BIT(8)
+#define HCTL_SDVS_SHIFT                9
+#define HCTL_SDVS_MASK         (0x7 << HCTL_SDVS_SHIFT)
+#define HCTL_SDVS_33           (0x7 << HCTL_SDVS_SHIFT)
+#define HCTL_SDVS_30           (0x6 << HCTL_SDVS_SHIFT)
+#define HCTL_SDVS_18           (0x5 << HCTL_SDVS_SHIFT)
+
+#define SDHCI_OMAP_SYSCTL      0x22c
+#define SYSCTL_CEN             BIT(2)
+#define SYSCTL_CLKD_SHIFT      6
+#define SYSCTL_CLKD_MASK       0x3ff
+
+#define SDHCI_OMAP_STAT                0x230
+
+#define SDHCI_OMAP_IE          0x234
+#define INT_CC_EN              BIT(0)
+
+#define SDHCI_OMAP_AC12                0x23c
+#define AC12_V1V8_SIGEN                BIT(19)
+
+#define SDHCI_OMAP_CAPA                0x240
+#define CAPA_VS33              BIT(24)
+#define CAPA_VS30              BIT(25)
+#define CAPA_VS18              BIT(26)
+
+#define SDHCI_OMAP_TIMEOUT     1               /* 1 msec */
+
+#define SYSCTL_CLKD_MAX                0x3FF
+
+#define IOV_1V8                        1800000         /* 180000 uV */
+#define IOV_3V0                        3000000         /* 300000 uV */
+#define IOV_3V3                        3300000         /* 330000 uV */
+
+struct sdhci_omap_data {
+       u32 offset;
+};
+
+struct sdhci_omap_host {
+       void __iomem            *base;
+       struct device           *dev;
+       struct  regulator       *pbias;
+       bool                    pbias_enabled;
+       struct sdhci_host       *host;
+       u8                      bus_mode;
+       u8                      power_mode;
+};
+
+static inline u32 sdhci_omap_readl(struct sdhci_omap_host *host,
+                                  unsigned int offset)
+{
+       return readl(host->base + offset);
+}
+
+static inline void sdhci_omap_writel(struct sdhci_omap_host *host,
+                                    unsigned int offset, u32 data)
+{
+       writel(data, host->base + offset);
+}
+
+static int sdhci_omap_set_pbias(struct sdhci_omap_host *omap_host,
+                               bool power_on, unsigned int iov)
+{
+       int ret;
+       struct device *dev = omap_host->dev;
+
+       if (IS_ERR(omap_host->pbias))
+               return 0;
+
+       if (power_on) {
+               ret = regulator_set_voltage(omap_host->pbias, iov, iov);
+               if (ret) {
+                       dev_err(dev, "pbias set voltage failed\n");
+                       return ret;
+               }
+
+               if (omap_host->pbias_enabled)
+                       return 0;
+
+               ret = regulator_enable(omap_host->pbias);
+               if (ret) {
+                       dev_err(dev, "pbias reg enable fail\n");
+                       return ret;
+               }
+
+               omap_host->pbias_enabled = true;
+       } else {
+               if (!omap_host->pbias_enabled)
+                       return 0;
+
+               ret = regulator_disable(omap_host->pbias);
+               if (ret) {
+                       dev_err(dev, "pbias reg disable fail\n");
+                       return ret;
+               }
+               omap_host->pbias_enabled = false;
+       }
+
+       return 0;
+}
+
+static int sdhci_omap_enable_iov(struct sdhci_omap_host *omap_host,
+                                unsigned int iov)
+{
+       int ret;
+       struct sdhci_host *host = omap_host->host;
+       struct mmc_host *mmc = host->mmc;
+
+       ret = sdhci_omap_set_pbias(omap_host, false, 0);
+       if (ret)
+               return ret;
+
+       if (!IS_ERR(mmc->supply.vqmmc)) {
+               ret = regulator_set_voltage(mmc->supply.vqmmc, iov, iov);
+               if (ret) {
+                       dev_err(mmc_dev(mmc), "vqmmc set voltage failed\n");
+                       return ret;
+               }
+       }
+
+       ret = sdhci_omap_set_pbias(omap_host, true, iov);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
+                                     unsigned char signal_voltage)
+{
+       u32 reg;
+       ktime_t timeout;
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL);
+       reg &= ~HCTL_SDVS_MASK;
+
+       if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+               reg |= HCTL_SDVS_33;
+       else
+               reg |= HCTL_SDVS_18;
+
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, reg);
+
+       reg |= HCTL_SDBP;
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, reg);
+
+       /* wait 1ms */
+       timeout = ktime_add_ms(ktime_get(), SDHCI_OMAP_TIMEOUT);
+       while (!(sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL) & HCTL_SDBP)) {
+               if (WARN_ON(ktime_after(ktime_get(), timeout)))
+                       return;
+               usleep_range(5, 10);
+       }
+}
+
+static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc,
+                                                 struct mmc_ios *ios)
+{
+       u32 reg;
+       int ret;
+       unsigned int iov;
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_pltfm_host *pltfm_host;
+       struct sdhci_omap_host *omap_host;
+       struct device *dev;
+
+       pltfm_host = sdhci_priv(host);
+       omap_host = sdhci_pltfm_priv(pltfm_host);
+       dev = omap_host->dev;
+
+       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA);
+               if (!(reg & CAPA_VS33))
+                       return -EOPNOTSUPP;
+
+               sdhci_omap_conf_bus_power(omap_host, ios->signal_voltage);
+
+               reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+               reg &= ~AC12_V1V8_SIGEN;
+               sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg);
+
+               iov = IOV_3V3;
+       } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+               reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA);
+               if (!(reg & CAPA_VS18))
+                       return -EOPNOTSUPP;
+
+               sdhci_omap_conf_bus_power(omap_host, ios->signal_voltage);
+
+               reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+               reg |= AC12_V1V8_SIGEN;
+               sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg);
+
+               iov = IOV_1V8;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       ret = sdhci_omap_enable_iov(omap_host, iov);
+       if (ret) {
+               dev_err(dev, "failed to switch IO voltage to %dmV\n", iov);
+               return ret;
+       }
+
+       dev_dbg(dev, "IO voltage switched to %dmV\n", iov);
+       return 0;
+}
+
+static void sdhci_omap_set_bus_mode(struct sdhci_omap_host *omap_host,
+                                   unsigned int mode)
+{
+       u32 reg;
+
+       if (omap_host->bus_mode == mode)
+               return;
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+       if (mode == MMC_BUSMODE_OPENDRAIN)
+               reg |= CON_OD;
+       else
+               reg &= ~CON_OD;
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+
+       omap_host->bus_mode = mode;
+}
+
+static void sdhci_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_pltfm_host *pltfm_host;
+       struct sdhci_omap_host *omap_host;
+
+       pltfm_host = sdhci_priv(host);
+       omap_host = sdhci_pltfm_priv(pltfm_host);
+
+       sdhci_omap_set_bus_mode(omap_host, ios->bus_mode);
+       sdhci_set_ios(mmc, ios);
+}
+
+static u16 sdhci_omap_calc_divisor(struct sdhci_pltfm_host *host,
+                                  unsigned int clock)
+{
+       u16 dsor;
+
+       dsor = DIV_ROUND_UP(clk_get_rate(host->clk), clock);
+       if (dsor > SYSCTL_CLKD_MAX)
+               dsor = SYSCTL_CLKD_MAX;
+
+       return dsor;
+}
+
+static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host)
+{
+       u32 reg;
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL);
+       reg |= SYSCTL_CEN;
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, reg);
+}
+
+static void sdhci_omap_stop_clock(struct sdhci_omap_host *omap_host)
+{
+       u32 reg;
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL);
+       reg &= ~SYSCTL_CEN;
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, reg);
+}
+
+static void sdhci_omap_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+       unsigned long clkdiv;
+
+       sdhci_omap_stop_clock(omap_host);
+
+       if (!clock)
+               return;
+
+       clkdiv = sdhci_omap_calc_divisor(pltfm_host, clock);
+       clkdiv = (clkdiv & SYSCTL_CLKD_MASK) << SYSCTL_CLKD_SHIFT;
+       sdhci_enable_clk(host, clkdiv);
+
+       sdhci_omap_start_clock(omap_host);
+}
+
+static void sdhci_omap_set_power(struct sdhci_host *host, unsigned char mode,
+                         unsigned short vdd)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+}
+
+static int sdhci_omap_enable_dma(struct sdhci_host *host)
+{
+       u32 reg;
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+       reg |= CON_DMA_MASTER;
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+
+       return 0;
+}
+
+static unsigned int sdhci_omap_get_min_clock(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       return clk_get_rate(pltfm_host->clk) / SYSCTL_CLKD_MAX;
+}
+
+static void sdhci_omap_set_bus_width(struct sdhci_host *host, int width)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+       u32 reg;
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+       if (width == MMC_BUS_WIDTH_8)
+               reg |= CON_DW8;
+       else
+               reg &= ~CON_DW8;
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+
+       sdhci_set_bus_width(host, width);
+}
+
+static void sdhci_omap_init_74_clocks(struct sdhci_host *host, u8 power_mode)
+{
+       u32 reg;
+       ktime_t timeout;
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+
+       if (omap_host->power_mode == power_mode)
+               return;
+
+       if (power_mode != MMC_POWER_ON)
+               return;
+
+       disable_irq(host->irq);
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+       reg |= CON_INIT;
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_CMD, 0x0);
+
+       /* wait 1ms */
+       timeout = ktime_add_ms(ktime_get(), SDHCI_OMAP_TIMEOUT);
+       while (!(sdhci_omap_readl(omap_host, SDHCI_OMAP_STAT) & INT_CC_EN)) {
+               if (WARN_ON(ktime_after(ktime_get(), timeout)))
+                       return;
+               usleep_range(5, 10);
+       }
+
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+       reg &= ~CON_INIT;
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_STAT, INT_CC_EN);
+
+       enable_irq(host->irq);
+
+       omap_host->power_mode = power_mode;
+}
+
+static struct sdhci_ops sdhci_omap_ops = {
+       .set_clock = sdhci_omap_set_clock,
+       .set_power = sdhci_omap_set_power,
+       .enable_dma = sdhci_omap_enable_dma,
+       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .get_min_clock = sdhci_omap_get_min_clock,
+       .set_bus_width = sdhci_omap_set_bus_width,
+       .platform_send_init_74_clocks = sdhci_omap_init_74_clocks,
+       .reset = sdhci_reset,
+       .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host)
+{
+       u32 reg;
+       int ret = 0;
+       struct device *dev = omap_host->dev;
+       struct regulator *vqmmc;
+
+       vqmmc = regulator_get(dev, "vqmmc");
+       if (IS_ERR(vqmmc)) {
+               ret = PTR_ERR(vqmmc);
+               goto reg_put;
+       }
+
+       /* voltage capabilities might be set by boot loader, clear it */
+       reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA);
+       reg &= ~(CAPA_VS18 | CAPA_VS30 | CAPA_VS33);
+
+       if (regulator_is_supported_voltage(vqmmc, IOV_3V3, IOV_3V3))
+               reg |= CAPA_VS33;
+       if (regulator_is_supported_voltage(vqmmc, IOV_1V8, IOV_1V8))
+               reg |= CAPA_VS18;
+
+       sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, reg);
+
+reg_put:
+       regulator_put(vqmmc);
+
+       return ret;
+}
+
+static const struct sdhci_pltfm_data sdhci_omap_pdata = {
+       .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+                 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
+                 SDHCI_QUIRK_NO_HISPD_BIT |
+                 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
+       .quirks2 = SDHCI_QUIRK2_NO_1_8_V |
+                  SDHCI_QUIRK2_ACMD23_BROKEN |
+                  SDHCI_QUIRK2_RSP_136_HAS_CRC,
+       .ops = &sdhci_omap_ops,
+};
+
+static const struct sdhci_omap_data dra7_data = {
+       .offset = 0x200,
+};
+
+static const struct of_device_id omap_sdhci_match[] = {
+       { .compatible = "ti,dra7-sdhci", .data = &dra7_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, omap_sdhci_match);
+
+static int sdhci_omap_probe(struct platform_device *pdev)
+{
+       int ret;
+       u32 offset;
+       struct device *dev = &pdev->dev;
+       struct sdhci_host *host;
+       struct sdhci_pltfm_host *pltfm_host;
+       struct sdhci_omap_host *omap_host;
+       struct mmc_host *mmc;
+       const struct of_device_id *match;
+       struct sdhci_omap_data *data;
+
+       match = of_match_device(omap_sdhci_match, dev);
+       if (!match)
+               return -EINVAL;
+
+       data = (struct sdhci_omap_data *)match->data;
+       if (!data) {
+               dev_err(dev, "no sdhci omap data\n");
+               return -EINVAL;
+       }
+       offset = data->offset;
+
+       host = sdhci_pltfm_init(pdev, &sdhci_omap_pdata,
+                               sizeof(*omap_host));
+       if (IS_ERR(host)) {
+               dev_err(dev, "Failed sdhci_pltfm_init\n");
+               return PTR_ERR(host);
+       }
+
+       pltfm_host = sdhci_priv(host);
+       omap_host = sdhci_pltfm_priv(pltfm_host);
+       omap_host->host = host;
+       omap_host->base = host->ioaddr;
+       omap_host->dev = dev;
+       host->ioaddr += offset;
+
+       mmc = host->mmc;
+       ret = mmc_of_parse(mmc);
+       if (ret)
+               goto err_pltfm_free;
+
+       pltfm_host->clk = devm_clk_get(dev, "fck");
+       if (IS_ERR(pltfm_host->clk)) {
+               ret = PTR_ERR(pltfm_host->clk);
+               goto err_pltfm_free;
+       }
+
+       ret = clk_set_rate(pltfm_host->clk, mmc->f_max);
+       if (ret) {
+               dev_err(dev, "failed to set clock to %d\n", mmc->f_max);
+               goto err_pltfm_free;
+       }
+
+       omap_host->pbias = devm_regulator_get_optional(dev, "pbias");
+       if (IS_ERR(omap_host->pbias)) {
+               ret = PTR_ERR(omap_host->pbias);
+               if (ret != -ENODEV)
+                       goto err_pltfm_free;
+               dev_dbg(dev, "unable to get pbias regulator %d\n", ret);
+       }
+       omap_host->pbias_enabled = false;
+
+       /*
+        * omap_device_pm_domain has callbacks to enable the main
+        * functional clock, interface clock and also configure the
+        * SYSCONFIG register of omap devices. The callback will be invoked
+        * as part of pm_runtime_get_sync.
+        */
+       pm_runtime_enable(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+               dev_err(dev, "pm_runtime_get_sync failed\n");
+               pm_runtime_put_noidle(dev);
+               goto err_rpm_disable;
+       }
+
+       ret = sdhci_omap_set_capabilities(omap_host);
+       if (ret) {
+               dev_err(dev, "failed to set system capabilities\n");
+               goto err_put_sync;
+       }
+
+       host->mmc_host_ops.get_ro = mmc_gpio_get_ro;
+       host->mmc_host_ops.start_signal_voltage_switch =
+                                       sdhci_omap_start_signal_voltage_switch;
+       host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
+
+       sdhci_read_caps(host);
+       host->caps |= SDHCI_CAN_DO_ADMA2;
+
+       ret = sdhci_add_host(host);
+       if (ret)
+               goto err_put_sync;
+
+       return 0;
+
+err_put_sync:
+       pm_runtime_put_sync(dev);
+
+err_rpm_disable:
+       pm_runtime_disable(dev);
+
+err_pltfm_free:
+       sdhci_pltfm_free(pdev);
+       return ret;
+}
+
+static int sdhci_omap_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+
+       sdhci_remove_host(host, true);
+       pm_runtime_put_sync(dev);
+       pm_runtime_disable(dev);
+       sdhci_pltfm_free(pdev);
+
+       return 0;
+}
+
+static struct platform_driver sdhci_omap_driver = {
+       .probe = sdhci_omap_probe,
+       .remove = sdhci_omap_remove,
+       .driver = {
+                  .name = "sdhci-omap",
+                  .of_match_table = omap_sdhci_match,
+                 },
+};
+
+module_platform_driver(sdhci_omap_driver);
+
+MODULE_DESCRIPTION("SDHCI driver for OMAP SoCs");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sdhci_omap");
index 67d787fa330651738ce8c2bf4e58fd8eebcf6e2a..3e4f04fd51755c6473d3fff0e9adefdca013c32b 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "sdhci.h"
 #include "sdhci-pci.h"
-#include "sdhci-pci-o2micro.h"
 
 static int sdhci_pci_enable_dma(struct sdhci_host *host);
 static void sdhci_pci_hw_reset(struct sdhci_host *host);
@@ -798,15 +797,6 @@ static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = {
        .probe_slot     = intel_mrfld_mmc_probe_slot,
 };
 
-/* O2Micro extra registers */
-#define O2_SD_LOCK_WP          0xD3
-#define O2_SD_MULTI_VCC3V      0xEE
-#define O2_SD_CLKREQ           0xEC
-#define O2_SD_CAPS             0xE0
-#define O2_SD_ADMA1            0xE2
-#define O2_SD_ADMA2            0xE7
-#define O2_SD_INF_MOD          0xF1
-
 static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
 {
        u8 scratch;
@@ -1290,6 +1280,7 @@ static const struct pci_device_id pci_ids[] = {
        SDHCI_PCI_DEVICE(INTEL, SPT_SDIO,  intel_byt_sdio),
        SDHCI_PCI_DEVICE(INTEL, SPT_SD,    intel_byt_sd),
        SDHCI_PCI_DEVICE(INTEL, DNV_EMMC,  intel_byt_emmc),
+       SDHCI_PCI_DEVICE(INTEL, CDF_EMMC,  intel_glk_emmc),
        SDHCI_PCI_DEVICE(INTEL, BXT_EMMC,  intel_byt_emmc),
        SDHCI_PCI_DEVICE(INTEL, BXT_SDIO,  intel_byt_sdio),
        SDHCI_PCI_DEVICE(INTEL, BXT_SD,    intel_byt_sd),
index 14273ca0064195af371e9e0859f1d83caa34365a..555970a29c94d480b571b09c5e10a380662f315b 100644 (file)
 
 #include "sdhci.h"
 #include "sdhci-pci.h"
-#include "sdhci-pci-o2micro.h"
+
+/*
+ * O2Micro device registers
+ */
+
+#define O2_SD_MISC_REG5                0x64
+#define O2_SD_LD0_CTRL         0x68
+#define O2_SD_DEV_CTRL         0x88
+#define O2_SD_LOCK_WP          0xD3
+#define O2_SD_TEST_REG         0xD4
+#define O2_SD_FUNC_REG0                0xDC
+#define O2_SD_MULTI_VCC3V      0xEE
+#define O2_SD_CLKREQ           0xEC
+#define O2_SD_CAPS             0xE0
+#define O2_SD_ADMA1            0xE2
+#define O2_SD_ADMA2            0xE7
+#define O2_SD_INF_MOD          0xF1
+#define O2_SD_MISC_CTRL4       0xFC
+#define O2_SD_TUNING_CTRL      0x300
+#define O2_SD_PLL_SETTING      0x304
+#define O2_SD_CLK_SETTING      0x328
+#define O2_SD_CAP_REG2         0x330
+#define O2_SD_CAP_REG0         0x334
+#define O2_SD_UHS1_CAP_SETTING 0x33C
+#define O2_SD_DELAY_CTRL       0x350
+#define O2_SD_UHS2_L1_CTRL     0x35C
+#define O2_SD_FUNC_REG3                0x3E0
+#define O2_SD_FUNC_REG4                0x3E4
+#define O2_SD_LED_ENABLE       BIT(6)
+#define O2_SD_FREG0_LEDOFF     BIT(13)
+#define O2_SD_FREG4_ENABLE_CLK_SET     BIT(22)
+
+#define O2_SD_VENDOR_SETTING   0x110
+#define O2_SD_VENDOR_SETTING2  0x1C8
 
 static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value)
 {
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.h b/drivers/mmc/host/sdhci-pci-o2micro.h
deleted file mode 100644 (file)
index 770f538..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2013 BayHub Technology Ltd.
- *
- * Authors: Peter Guo <peter.guo@bayhubtech.com>
- *          Adam Lee <adam.lee@canonical.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef __SDHCI_PCI_O2MICRO_H
-#define __SDHCI_PCI_O2MICRO_H
-
-#include "sdhci-pci.h"
-
-/*
- * O2Micro device IDs
- */
-
-#define PCI_DEVICE_ID_O2_SDS0          0x8420
-#define PCI_DEVICE_ID_O2_SDS1          0x8421
-#define PCI_DEVICE_ID_O2_FUJIN2                0x8520
-#define PCI_DEVICE_ID_O2_SEABIRD0      0x8620
-#define PCI_DEVICE_ID_O2_SEABIRD1      0x8621
-
-/*
- * O2Micro device registers
- */
-
-#define O2_SD_MISC_REG5                0x64
-#define O2_SD_LD0_CTRL         0x68
-#define O2_SD_DEV_CTRL         0x88
-#define O2_SD_LOCK_WP          0xD3
-#define O2_SD_TEST_REG         0xD4
-#define O2_SD_FUNC_REG0                0xDC
-#define O2_SD_MULTI_VCC3V      0xEE
-#define O2_SD_CLKREQ           0xEC
-#define O2_SD_CAPS             0xE0
-#define O2_SD_ADMA1            0xE2
-#define O2_SD_ADMA2            0xE7
-#define O2_SD_INF_MOD          0xF1
-#define O2_SD_MISC_CTRL4       0xFC
-#define O2_SD_TUNING_CTRL      0x300
-#define O2_SD_PLL_SETTING      0x304
-#define O2_SD_CLK_SETTING      0x328
-#define O2_SD_CAP_REG2         0x330
-#define O2_SD_CAP_REG0         0x334
-#define O2_SD_UHS1_CAP_SETTING 0x33C
-#define O2_SD_DELAY_CTRL       0x350
-#define O2_SD_UHS2_L1_CTRL     0x35C
-#define O2_SD_FUNC_REG3                0x3E0
-#define O2_SD_FUNC_REG4                0x3E4
-#define O2_SD_LED_ENABLE       BIT(6)
-#define O2_SD_FREG0_LEDOFF     BIT(13)
-#define O2_SD_FREG4_ENABLE_CLK_SET     BIT(22)
-
-#define O2_SD_VENDOR_SETTING   0x110
-#define O2_SD_VENDOR_SETTING2  0x1C8
-
-extern int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot);
-
-extern int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip);
-
-extern int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip);
-
-#endif /* __SDHCI_PCI_O2MICRO_H */
index 3e8ea3e566f6ba41855ed4b89b5939972acc52d7..0056f08a29ccb32b06ae8dac9a155baffb64b428 100644 (file)
@@ -6,6 +6,12 @@
  * PCI device IDs, sub IDs
  */
 
+#define PCI_DEVICE_ID_O2_SDS0          0x8420
+#define PCI_DEVICE_ID_O2_SDS1          0x8421
+#define PCI_DEVICE_ID_O2_FUJIN2                0x8520
+#define PCI_DEVICE_ID_O2_SEABIRD0      0x8620
+#define PCI_DEVICE_ID_O2_SEABIRD1      0x8621
+
 #define PCI_DEVICE_ID_INTEL_PCH_SDIO0  0x8809
 #define PCI_DEVICE_ID_INTEL_PCH_SDIO1  0x880a
 #define PCI_DEVICE_ID_INTEL_BYT_EMMC   0x0f14
@@ -26,6 +32,7 @@
 #define PCI_DEVICE_ID_INTEL_SPT_SDIO   0x9d2c
 #define PCI_DEVICE_ID_INTEL_SPT_SD     0x9d2d
 #define PCI_DEVICE_ID_INTEL_DNV_EMMC   0x19db
+#define PCI_DEVICE_ID_INTEL_CDF_EMMC   0x18db
 #define PCI_DEVICE_ID_INTEL_BXT_SD     0x0aca
 #define PCI_DEVICE_ID_INTEL_BXT_EMMC   0x0acc
 #define PCI_DEVICE_ID_INTEL_BXT_SDIO   0x0ad0
@@ -164,4 +171,10 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot)
 int sdhci_pci_resume_host(struct sdhci_pci_chip *chip);
 #endif
 
+int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot);
+int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip);
+#ifdef CONFIG_PM_SLEEP
+int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip);
+#endif
+
 #endif /* __SDHCI_PCI_H */
index d328fcf284d1ce1eb08b983fd75596c42ca459eb..cda83ccb2702139856a059f9ceef84b650df3a38 100644 (file)
@@ -761,32 +761,24 @@ static const struct dev_pm_ops sdhci_s3c_pmops = {
                           NULL)
 };
 
-#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
-static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
-       .no_divider = true,
-};
-#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
-#else
-#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL)
-#endif
-
 static const struct platform_device_id sdhci_s3c_driver_ids[] = {
        {
                .name           = "s3c-sdhci",
                .driver_data    = (kernel_ulong_t)NULL,
-       }, {
-               .name           = "exynos4-sdhci",
-               .driver_data    = EXYNOS4_SDHCI_DRV_DATA,
        },
        { }
 };
 MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
 
 #ifdef CONFIG_OF
+static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
+       .no_divider = true,
+};
+
 static const struct of_device_id sdhci_s3c_dt_match[] = {
        { .compatible = "samsung,s3c6410-sdhci", },
        { .compatible = "samsung,exynos4210-sdhci",
-               .data = (void *)EXYNOS4_SDHCI_DRV_DATA },
+               .data = &exynos4_sdhci_drv_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match);
index 0cd6fa80db662a3ed2d8b10014047d50af4f2484..b877c13184c2dd2e519e4f7ff2f573d96a9f9c0e 100644 (file)
@@ -422,7 +422,15 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
                  SDHCI_QUIRK_NO_HISPD_BIT |
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
                  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
-       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+                  /* SDHCI controllers on Tegra186 support 40-bit addressing.
+                   * IOVA addresses are 48-bit wide on Tegra186.
+                   * With 64-bit dma mask used for SDHCI, accesses can
+                   * be broken. Disable 64-bit dma, which would fall back
+                   * to 32-bit dma mask. Ideally 40-bit dma mask would work,
+                   * But it is not supported as of now.
+                   */
+                  SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
        .ops  = &tegra114_sdhci_ops,
 };
 
index 0d5fcca18c9ec14344d63444a53a39e6f53dde03..2f14334e42df91135fc88fdc474c0d318c4dfad3 100644 (file)
@@ -2407,12 +2407,12 @@ static void sdhci_tasklet_finish(unsigned long param)
                ;
 }
 
-static void sdhci_timeout_timer(unsigned long data)
+static void sdhci_timeout_timer(struct timer_list *t)
 {
        struct sdhci_host *host;
        unsigned long flags;
 
-       host = (struct sdhci_host*)data;
+       host = from_timer(host, t, timer);
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -2429,12 +2429,12 @@ static void sdhci_timeout_timer(unsigned long data)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static void sdhci_timeout_data_timer(unsigned long data)
+static void sdhci_timeout_data_timer(struct timer_list *t)
 {
        struct sdhci_host *host;
        unsigned long flags;
 
-       host = (struct sdhci_host *)data;
+       host = from_timer(host, t, data_timer);
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -3238,7 +3238,7 @@ int sdhci_setup_host(struct sdhci_host *host)
         * available.
         */
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                return ret;
 
        DBG("Version:   0x%08x | Present:  0x%08x\n",
@@ -3749,9 +3749,8 @@ int __sdhci_add_host(struct sdhci_host *host)
        tasklet_init(&host->finish_tasklet,
                sdhci_tasklet_finish, (unsigned long)host);
 
-       setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
-       setup_timer(&host->data_timer, sdhci_timeout_data_timer,
-                   (unsigned long)host);
+       timer_setup(&host->timer, sdhci_timeout_timer, 0);
+       timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
 
        init_waitqueue_head(&host->buf_ready_int);
 
index 111b66f5439bc25a33c8ed1d8e925ce39d417bb1..04ca0d33a5211f235bd72719c6d2b192230bf2fb 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/property.h>
 #include <linux/clk.h>
 
 #include "sdhci-pltfm.h"
@@ -47,6 +48,7 @@ struct f_sdhost_priv {
        struct clk *clk;
        u32 vendor_hs200;
        struct device *dev;
+       bool enable_cmd_dat_delay;
 };
 
 static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
@@ -84,10 +86,19 @@ static unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host)
 
 static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
 {
+       struct f_sdhost_priv *priv = sdhci_priv(host);
+       u32 ctl;
+
        if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0)
                sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL);
 
        sdhci_reset(host, mask);
+
+       if (priv->enable_cmd_dat_delay) {
+               ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
+               ctl |= F_SDH30_CMD_DAT_DELAY;
+               sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
+       }
 }
 
 static const struct sdhci_ops sdhci_f_sdh30_ops = {
@@ -126,6 +137,9 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
        host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
                        SDHCI_QUIRK2_TUNING_WORK_AROUND;
 
+       priv->enable_cmd_dat_delay = device_property_read_bool(dev,
+                                               "fujitsu,cmd-dat-delay-select");
+
        ret = mmc_of_parse(host->mmc);
        if (ret)
                goto err;
index 53c970fe08739720c35f48be87be28f727a47428..cc98355dbdb9cca41acb2ad53a7e4418691d7485 100644 (file)
@@ -1175,11 +1175,8 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
                return -EINVAL;
 
        ret = mmc_regulator_get_supply(host->mmc);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "Could not get vmmc supply\n");
+       if (ret)
                return ret;
-       }
 
        host->reg_base = devm_ioremap_resource(&pdev->dev,
                              platform_get_resource(pdev, IORESOURCE_MEM, 0));
index 93c4b40df90a78bfcb16375d3669436112fa77a7..a3d8380ab480eafed27ab63339061435491571ba 100644 (file)
@@ -783,9 +783,9 @@ static void tifm_sd_end_cmd(unsigned long data)
        mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_abort(unsigned long data)
+static void tifm_sd_abort(struct timer_list *t)
 {
-       struct tifm_sd *host = (struct tifm_sd*)data;
+       struct tifm_sd *host = from_timer(host, t, timer);
 
        pr_err("%s : card failed to respond for a long period of time "
               "(%x, %x)\n",
@@ -968,7 +968,7 @@ static int tifm_sd_probe(struct tifm_dev *sock)
 
        tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,
                     (unsigned long)host);
-       setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+       timer_setup(&host->timer, tifm_sd_abort, 0);
 
        mmc->ops = &tifm_sd_ops;
        mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
index 9c4e6199b854d38c585ae1464d9056a754e4de33..583bf3262df5d4b33c702ee96e818e065592f2bc 100644 (file)
@@ -167,11 +167,11 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
 
        /* HW engineers overrode docs: no sleep needed on R-Car2+ */
        if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
-               msleep(10);
+               usleep_range(10000, 11000);
 
        if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
                sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
-               msleep(10);
+               usleep_range(10000, 11000);
        }
 }
 
@@ -179,7 +179,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
 {
        if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
                sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
-               msleep(10);
+               usleep_range(10000, 11000);
        }
 
        sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
@@ -187,7 +187,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
 
        /* HW engineers overrode docs: no sleep needed on R-Car2+ */
        if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
-               msleep(10);
+               usleep_range(10000, 11000);
 }
 
 static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
@@ -219,7 +219,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
                        sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
        sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
        if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
-               msleep(10);
+               usleep_range(10000, 11000);
 
        tmio_mmc_clk_start(host);
 }
@@ -230,11 +230,11 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
        sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
        if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
                sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
-       msleep(10);
+       usleep_range(10000, 11000);
        sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
        if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
                sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
-       msleep(10);
+       usleep_range(10000, 11000);
 
        if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) {
                sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
@@ -1113,8 +1113,11 @@ static int tmio_mmc_init_ocr(struct tmio_mmc_host *host)
 {
        struct tmio_mmc_data *pdata = host->pdata;
        struct mmc_host *mmc = host->mmc;
+       int err;
 
-       mmc_regulator_get_supply(mmc);
+       err = mmc_regulator_get_supply(mmc);
+       if (err)
+               return err;
 
        /* use ocr_mask if no regulator */
        if (!mmc->ocr_avail)
@@ -1299,23 +1302,24 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
        pm_runtime_enable(&pdev->dev);
 
        ret = mmc_add_host(mmc);
-       if (ret < 0) {
-               tmio_mmc_host_remove(_host);
-               return ret;
-       }
+       if (ret)
+               goto remove_host;
 
        dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
 
        if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
                ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio, 0);
-               if (ret < 0) {
-                       tmio_mmc_host_remove(_host);
-                       return ret;
-               }
+               if (ret)
+                       goto remove_host;
+
                mmc_gpiod_request_cd_irq(mmc);
        }
 
        return 0;
+
+remove_host:
+       tmio_mmc_host_remove(_host);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_probe);
 
index 64da6a88cfb90e1b87fe75f3c7fc37902df0a97b..cdfeb15b6f051170201e3ef238fb3203b817ca92 100644 (file)
@@ -1757,7 +1757,7 @@ static int usdhi6_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        ret = mmc_regulator_get_supply(mmc);
-       if (ret == -EPROBE_DEFER)
+       if (ret)
                goto e_free_mmc;
 
        ret = mmc_of_parse(mmc);
index a838bf5480d888935aeb79c5a1c3fcb734e07ad0..32c4211506fc8376f1ca4eb0d2967d810091114a 100644 (file)
@@ -932,12 +932,12 @@ out:
        return result;
 }
 
-static void via_sdc_timeout(unsigned long ulongdata)
+static void via_sdc_timeout(struct timer_list *t)
 {
        struct via_crdr_mmc_host *sdhost;
        unsigned long flags;
 
-       sdhost = (struct via_crdr_mmc_host *)ulongdata;
+       sdhost = from_timer(sdhost, t, timer);
 
        spin_lock_irqsave(&sdhost->lock, flags);
 
@@ -1036,9 +1036,7 @@ static void via_init_mmc_host(struct via_crdr_mmc_host *host)
        u32 lenreg;
        u32 status;
 
-       init_timer(&host->timer);
-       host->timer.data = (unsigned long)host;
-       host->timer.function = via_sdc_timeout;
+       timer_setup(&host->timer, via_sdc_timeout, 0);
 
        spin_lock_init(&host->lock);
 
index 8f569d257405f40b02e5d75eb6afd0662dfaf65c..1fe68137a30f2dcf93fbe3eb5aa800caf08becde 100644 (file)
@@ -741,9 +741,10 @@ static void vub300_deadwork_thread(struct work_struct *work)
        kref_put(&vub300->kref, vub300_delete);
 }
 
-static void vub300_inactivity_timer_expired(unsigned long data)
+static void vub300_inactivity_timer_expired(struct timer_list *t)
 {                              /* softirq */
-       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
+       struct vub300_mmc_host *vub300 = from_timer(vub300, t,
+                                                   inactivity_timer);
        if (!vub300->interface) {
                kref_put(&vub300->kref, vub300_delete);
        } else if (vub300->cmd) {
@@ -1180,9 +1181,10 @@ static void send_command(struct vub300_mmc_host *vub300)
  * timer callback runs in atomic mode
  *       so it cannot call usb_kill_urb()
  */
-static void vub300_sg_timed_out(unsigned long data)
+static void vub300_sg_timed_out(struct timer_list *t)
 {
-       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
+       struct vub300_mmc_host *vub300 = from_timer(vub300, t,
+                                                   sg_transfer_timer);
        vub300->usb_timed_out = 1;
        usb_sg_cancel(&vub300->sg_request);
        usb_unlink_urb(vub300->command_out_urb);
@@ -1244,12 +1246,8 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
                                                USB_RECIP_DEVICE, 0x0000, 0x0000,
                                                xfer_buffer, xfer_length, HZ);
                        kfree(xfer_buffer);
-                       if (retval < 0) {
-                               strncpy(vub300->vub_name,
-                                       "SDIO pseudocode download failed",
-                                       sizeof(vub300->vub_name));
-                               return;
-                       }
+                       if (retval < 0)
+                               goto copy_error_message;
                } else {
                        dev_err(&vub300->udev->dev,
                                "not enough memory for xfer buffer to send"
@@ -1291,12 +1289,8 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
                                                USB_RECIP_DEVICE, 0x0000, 0x0000,
                                                xfer_buffer, xfer_length, HZ);
                        kfree(xfer_buffer);
-                       if (retval < 0) {
-                               strncpy(vub300->vub_name,
-                                       "SDIO pseudocode download failed",
-                                       sizeof(vub300->vub_name));
-                               return;
-                       }
+                       if (retval < 0)
+                               goto copy_error_message;
                } else {
                        dev_err(&vub300->udev->dev,
                                "not enough memory for xfer buffer to send"
@@ -1349,6 +1343,12 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
                        sizeof(vub300->vub_name));
                return;
        }
+
+       return;
+
+copy_error_message:
+       strncpy(vub300->vub_name, "SDIO pseudocode download failed",
+               sizeof(vub300->vub_name));
 }
 
 /*
@@ -2323,13 +2323,10 @@ static int vub300_probe(struct usb_interface *interface,
        INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread);
        INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
        kref_init(&vub300->kref);
-       init_timer(&vub300->sg_transfer_timer);
-       vub300->sg_transfer_timer.data = (unsigned long)vub300;
-       vub300->sg_transfer_timer.function = vub300_sg_timed_out;
+       timer_setup(&vub300->sg_transfer_timer, vub300_sg_timed_out, 0);
        kref_get(&vub300->kref);
-       init_timer(&vub300->inactivity_timer);
-       vub300->inactivity_timer.data = (unsigned long)vub300;
-       vub300->inactivity_timer.function = vub300_inactivity_timer_expired;
+       timer_setup(&vub300->inactivity_timer,
+                   vub300_inactivity_timer_expired, 0);
        vub300->inactivity_timer.expires = jiffies + HZ;
        add_timer(&vub300->inactivity_timer);
        if (vub300->card_present)
index 546aaf8d15078746f2d6e0f0859142d1aca3cd5c..f4233576153bf40f0543435d248ea2c6fbe537fe 100644 (file)
@@ -956,9 +956,9 @@ static const struct mmc_host_ops wbsd_ops = {
  * Helper function to reset detection ignore
  */
 
-static void wbsd_reset_ignore(unsigned long data)
+static void wbsd_reset_ignore(struct timer_list *t)
 {
-       struct wbsd_host *host = (struct wbsd_host *)data;
+       struct wbsd_host *host = from_timer(host, t, ignore_timer);
 
        BUG_ON(host == NULL);
 
@@ -1224,9 +1224,7 @@ static int wbsd_alloc_mmc(struct device *dev)
        /*
         * Set up timers
         */
-       init_timer(&host->ignore_timer);
-       host->ignore_timer.data = (unsigned long)host;
-       host->ignore_timer.function = wbsd_reset_ignore;
+       timer_setup(&host->ignore_timer, wbsd_reset_ignore, 0);
 
        /*
         * Maximum number of segments. Worst case is one sector per segment
index c02cc817a490995498b9764594a632b7581a700c..1ed9529e7bd1de923697731dc0db0ceaa926ef1f 100644 (file)
@@ -1378,7 +1378,7 @@ int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                                unsigned int count;
 
                                slaves = rcu_dereference(bond->slave_arr);
-                               count = slaves ? ACCESS_ONCE(slaves->count) : 0;
+                               count = slaves ? READ_ONCE(slaves->count) : 0;
                                if (likely(count))
                                        tx_slave = slaves->arr[hash_index %
                                                               count];
index c99dc59d729b30dd3ffc4a673deae38630fb0a84..08a4f57cf40966d1ca45cb51c1b8131aa80d65f2 100644 (file)
@@ -1167,7 +1167,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
        slave = bond_slave_get_rcu(skb->dev);
        bond = slave->bond;
 
-       recv_probe = ACCESS_ONCE(bond->recv_probe);
+       recv_probe = READ_ONCE(bond->recv_probe);
        if (recv_probe) {
                ret = recv_probe(skb, bond, slave);
                if (ret == RX_HANDLER_CONSUMED) {
@@ -2042,6 +2042,7 @@ static int bond_miimon_inspect(struct bonding *bond)
 
        bond_for_each_slave_rcu(bond, slave, iter) {
                slave->new_link = BOND_LINK_NOCHANGE;
+               slave->link_new_state = slave->link;
 
                link_state = bond_check_dev_link(bond, slave->dev, 0);
 
@@ -3253,7 +3254,7 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
        hash ^= (hash >> 16);
        hash ^= (hash >> 8);
 
-       return hash;
+       return hash >> 1;
 }
 
 /*-------------------------- Device entry points ----------------------------*/
@@ -3810,7 +3811,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
                else
                        bond_xmit_slave_id(bond, skb, 0);
        } else {
-               int slave_cnt = ACCESS_ONCE(bond->slave_cnt);
+               int slave_cnt = READ_ONCE(bond->slave_cnt);
 
                if (likely(slave_cnt)) {
                        slave_id = bond_rr_gen_slave_id(bond);
@@ -3972,7 +3973,7 @@ static int bond_3ad_xor_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned int count;
 
        slaves = rcu_dereference(bond->slave_arr);
-       count = slaves ? ACCESS_ONCE(slaves->count) : 0;
+       count = slaves ? READ_ONCE(slaves->count) : 0;
        if (likely(count)) {
                slave = slaves->arr[bond_xmit_hash(bond, skb) % count];
                bond_dev_queue_xmit(bond, skb, slave->dev);
index cf7c18947189a1f5c2834ad5b0d14ac615686294..d065c0e2d18e611f9e28b22310731cd612106334 100644 (file)
@@ -178,7 +178,6 @@ static int c_can_pci_probe(struct pci_dev *pdev,
                break;
        case BOSCH_D_CAN:
                priv->regs = reg_map_d_can;
-               priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
                break;
        default:
                ret = -EINVAL;
index 46a746ee80bb02142d3187815fb2f6edfaefd2a9..b5145a7f874c2f1697500ef2596d25365d69244a 100644 (file)
@@ -320,7 +320,6 @@ static int c_can_plat_probe(struct platform_device *pdev)
                break;
        case BOSCH_D_CAN:
                priv->regs = reg_map_d_can;
-               priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
                priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
                priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
                priv->read_reg32 = d_can_plat_read_reg32;
index 4d1fe8d9504234f436a0b9dd739b41089f563225..2772d05ff11caafbdf074aebccd32b415feae0c4 100644 (file)
@@ -670,9 +670,9 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev)
               priv->base + IFI_CANFD_FTIME);
 
        /* Configure transmitter delay */
-       tdc = (dbt->brp * (dbt->phase_seg1 + 1)) & IFI_CANFD_TDELAY_MASK;
-       writel(IFI_CANFD_TDELAY_EN | IFI_CANFD_TDELAY_ABS | tdc,
-              priv->base + IFI_CANFD_TDELAY);
+       tdc = dbt->brp * (dbt->prop_seg + dbt->phase_seg1);
+       tdc &= IFI_CANFD_TDELAY_MASK;
+       writel(IFI_CANFD_TDELAY_EN | tdc, priv->base + IFI_CANFD_TDELAY);
 }
 
 static void ifi_canfd_set_filter(struct net_device *ndev, const u32 id,
index 51c2d182a33ae5b2ae96fa7df772ac3ab5f6a7cc..b4efd711f824ccd1c832af8817e09bf2e00b2b5c 100644 (file)
 #include "peak_canfd_user.h"
 
 MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCIe FD family cards");
-MODULE_SUPPORTED_DEVICE("PEAK PCAN PCIe FD CAN cards");
+MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCIe/M.2 FD family cards");
+MODULE_SUPPORTED_DEVICE("PEAK PCAN PCIe/M.2 FD CAN cards");
 MODULE_LICENSE("GPL v2");
 
 #define PCIEFD_DRV_NAME                "peak_pciefd"
 
 #define PEAK_PCI_VENDOR_ID     0x001c  /* The PCI device and vendor IDs */
 #define PEAK_PCIEFD_ID         0x0013  /* for PCIe slot cards */
+#define PCAN_CPCIEFD_ID                0x0014  /* for Compact-PCI Serial slot cards */
+#define PCAN_PCIE104FD_ID      0x0017  /* for PCIe-104 Express slot cards */
+#define PCAN_MINIPCIEFD_ID      0x0018 /* for mini-PCIe slot cards */
+#define PCAN_PCIEFD_OEM_ID      0x0019 /* for PCIe slot OEM cards */
+#define PCAN_M2_ID             0x001a  /* for M2 slot cards */
 
 /* PEAK PCIe board access description */
 #define PCIEFD_BAR0_SIZE               (64 * 1024)
@@ -203,6 +208,11 @@ struct pciefd_board {
 /* supported device ids. */
 static const struct pci_device_id peak_pciefd_tbl[] = {
        {PEAK_PCI_VENDOR_ID, PEAK_PCIEFD_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PEAK_PCI_VENDOR_ID, PCAN_CPCIEFD_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PEAK_PCI_VENDOR_ID, PCAN_PCIE104FD_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PEAK_PCI_VENDOR_ID, PCAN_MINIPCIEFD_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PEAK_PCI_VENDOR_ID, PCAN_PCIEFD_OEM_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PEAK_PCI_VENDOR_ID, PCAN_M2_ID, PCI_ANY_ID, PCI_ANY_ID,},
        {0,}
 };
 
index b0c80859f7467ef32a2683a506757c41ad13cb28..1ac2090a17216cf47e74be35994fbd4a5e267f6f 100644 (file)
@@ -539,6 +539,13 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
                }
                stats->rx_over_errors++;
                stats->rx_errors++;
+
+               /* reset the CAN IP by entering reset mode
+                * ignoring timeout error
+                */
+               set_reset_mode(dev);
+               set_normal_mode(dev);
+
                /* clear bit */
                sun4i_can_write_cmdreg(priv, SUN4I_CMD_CLEAR_OR_FLAG);
        }
@@ -653,8 +660,9 @@ static irqreturn_t sun4i_can_interrupt(int irq, void *dev_id)
                        netif_wake_queue(dev);
                        can_led_event(dev, CAN_LED_EVENT_TX);
                }
-               if (isrc & SUN4I_INT_RBUF_VLD) {
-                       /* receive interrupt */
+               if ((isrc & SUN4I_INT_RBUF_VLD) &&
+                   !(isrc & SUN4I_INT_DATA_OR)) {
+                       /* receive interrupt - don't read if overrun occurred */
                        while (status & SUN4I_STA_RBUF_RDY) {
                                /* RX buffer is not empty */
                                sun4i_can_rx(dev);
index 1cbca8e5741ed420f1b7e7f76a7056f93a706e18..b6e2bfd7d2d6aae5f05794c71f818e14a844a6b4 100644 (file)
@@ -166,8 +166,8 @@ static unsigned int network_rec_config_shadow = 0;
 static unsigned int network_tr_ctrl_shadow = 0;
 
 /* Network speed indication. */
-static DEFINE_TIMER(speed_timer, NULL, 0, 0);
-static DEFINE_TIMER(clear_led_timer, NULL, 0, 0);
+static DEFINE_TIMER(speed_timer, NULL);
+static DEFINE_TIMER(clear_led_timer, NULL);
 static int current_speed; /* Speed read from transceiver */
 static int current_speed_selection; /* Speed selected by user */
 static unsigned long led_next_time;
@@ -175,7 +175,7 @@ static int led_active;
 static int rx_queue_len;
 
 /* Duplex */
-static DEFINE_TIMER(duplex_timer, NULL, 0, 0);
+static DEFINE_TIMER(duplex_timer, NULL);
 static int full_duplex;
 static enum duplex current_duplex;
 
index 4ef68f69b58c45322d65f414e06d068ade4ab22d..43f52a8fe708becb0510419fb01d583f3d29e1e2 100644 (file)
@@ -405,7 +405,7 @@ void free_tx_desc(struct adapter *adap, struct sge_txq *q,
  */
 static inline int reclaimable(const struct sge_txq *q)
 {
-       int hw_cidx = ntohs(ACCESS_ONCE(q->stat->cidx));
+       int hw_cidx = ntohs(READ_ONCE(q->stat->cidx));
        hw_cidx -= q->cidx;
        return hw_cidx < 0 ? hw_cidx + q->size : hw_cidx;
 }
@@ -1375,7 +1375,7 @@ out_free: dev_kfree_skb_any(skb);
  */
 static inline void reclaim_completed_tx_imm(struct sge_txq *q)
 {
-       int hw_cidx = ntohs(ACCESS_ONCE(q->stat->cidx));
+       int hw_cidx = ntohs(READ_ONCE(q->stat->cidx));
        int reclaim = hw_cidx - q->cidx;
 
        if (reclaim < 0)
index f2d623a7aee04e21f1e4e52645d66788a59341ab..123e2c1b65f595b1d1d6e21e247f33541140717a 100644 (file)
@@ -37,7 +37,7 @@
 
 #define T4FW_VERSION_MAJOR 0x01
 #define T4FW_VERSION_MINOR 0x10
-#define T4FW_VERSION_MICRO 0x2D
+#define T4FW_VERSION_MICRO 0x3F
 #define T4FW_VERSION_BUILD 0x00
 
 #define T4FW_MIN_VERSION_MAJOR 0x01
@@ -46,7 +46,7 @@
 
 #define T5FW_VERSION_MAJOR 0x01
 #define T5FW_VERSION_MINOR 0x10
-#define T5FW_VERSION_MICRO 0x2D
+#define T5FW_VERSION_MICRO 0x3F
 #define T5FW_VERSION_BUILD 0x00
 
 #define T5FW_MIN_VERSION_MAJOR 0x00
@@ -55,7 +55,7 @@
 
 #define T6FW_VERSION_MAJOR 0x01
 #define T6FW_VERSION_MINOR 0x10
-#define T6FW_VERSION_MICRO 0x2D
+#define T6FW_VERSION_MICRO 0x3F
 #define T6FW_VERSION_BUILD 0x00
 
 #define T6FW_MIN_VERSION_MAJOR 0x00
index 0e3d9f39a80756b42542d60ff1a8df7846cb837a..c6e859a27ee634bd5d0e00ce9d64c85531427284 100644 (file)
@@ -605,7 +605,7 @@ static void accumulate_16bit_val(u32 *acc, u16 val)
 
        if (wrapped)
                newacc += 65536;
-       ACCESS_ONCE(*acc) = newacc;
+       WRITE_ONCE(*acc, newacc);
 }
 
 static void populate_erx_stats(struct be_adapter *adapter,
index 0cec06bec63ee1c0085019f0f1ee456b675c2ece..340e28211135a266b5a955ef432f6e8786d4f23b 100644 (file)
@@ -373,7 +373,7 @@ static int hip04_tx_reclaim(struct net_device *ndev, bool force)
        unsigned int count;
 
        smp_rmb();
-       count = tx_count(ACCESS_ONCE(priv->tx_head), tx_tail);
+       count = tx_count(READ_ONCE(priv->tx_head), tx_tail);
        if (count == 0)
                goto out;
 
@@ -431,7 +431,7 @@ static int hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        dma_addr_t phys;
 
        smp_rmb();
-       count = tx_count(tx_head, ACCESS_ONCE(priv->tx_tail));
+       count = tx_count(tx_head, READ_ONCE(priv->tx_tail));
        if (count == (TX_DESC_NUM - 1)) {
                netif_stop_queue(ndev);
                return NETDEV_TX_BUSY;
index 8f326f87a815bf8fd4ea1fe2c464fa9df19b4660..2cb9539c931e51f7a18696db9a307e3709c6d2f4 100644 (file)
@@ -264,7 +264,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                 vsi->rx_buf_failed, vsi->rx_page_failed);
        rcu_read_lock();
        for (i = 0; i < vsi->num_queue_pairs; i++) {
-               struct i40e_ring *rx_ring = ACCESS_ONCE(vsi->rx_rings[i]);
+               struct i40e_ring *rx_ring = READ_ONCE(vsi->rx_rings[i]);
 
                if (!rx_ring)
                        continue;
@@ -320,7 +320,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                         ITR_IS_DYNAMIC(rx_ring->rx_itr_setting) ? "dynamic" : "fixed");
        }
        for (i = 0; i < vsi->num_queue_pairs; i++) {
-               struct i40e_ring *tx_ring = ACCESS_ONCE(vsi->tx_rings[i]);
+               struct i40e_ring *tx_ring = READ_ONCE(vsi->tx_rings[i]);
 
                if (!tx_ring)
                        continue;
index 05e89864f781c361289f0a3170078a661988389b..e9e04a485e0a765e392afef2f943f8bd84bb3400 100644 (file)
@@ -1570,7 +1570,7 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
        }
        rcu_read_lock();
        for (j = 0; j < vsi->num_queue_pairs; j++) {
-               tx_ring = ACCESS_ONCE(vsi->tx_rings[j]);
+               tx_ring = READ_ONCE(vsi->tx_rings[j]);
 
                if (!tx_ring)
                        continue;
index 6498da8806cbf4bd50f001907c670a44526cf4b5..de1fcac7834de30173109b38001554b267e697d3 100644 (file)
@@ -455,7 +455,7 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev,
                u64 bytes, packets;
                unsigned int start;
 
-               tx_ring = ACCESS_ONCE(vsi->tx_rings[i]);
+               tx_ring = READ_ONCE(vsi->tx_rings[i]);
                if (!tx_ring)
                        continue;
                i40e_get_netdev_stats_struct_tx(tx_ring, stats);
@@ -791,7 +791,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        rcu_read_lock();
        for (q = 0; q < vsi->num_queue_pairs; q++) {
                /* locate Tx ring */
-               p = ACCESS_ONCE(vsi->tx_rings[q]);
+               p = READ_ONCE(vsi->tx_rings[q]);
 
                do {
                        start = u64_stats_fetch_begin_irq(&p->syncp);
index d8456c381c99d47b5de90e4680c9af7aaba5bfbd..97381238eb7c168f0f6887d039ae4d00f1e3a044 100644 (file)
@@ -130,7 +130,7 @@ static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
        }
 
        smp_mb(); /* Force any pending update before accessing. */
-       adj = ACCESS_ONCE(pf->ptp_base_adj);
+       adj = READ_ONCE(pf->ptp_base_adj);
 
        freq = adj;
        freq *= ppb;
@@ -499,7 +499,7 @@ void i40e_ptp_set_increment(struct i40e_pf *pf)
        wr32(hw, I40E_PRTTSYN_INC_H, incval >> 32);
 
        /* Update the base adjustement value. */
-       ACCESS_ONCE(pf->ptp_base_adj) = incval;
+       WRITE_ONCE(pf->ptp_base_adj, incval);
        smp_mb(); /* Force the above update. */
 }
 
index 58adbf234e07058b0705d847849243fca695609f..31a3f09df9f75fee5ab62472c64fb07446408f61 100644 (file)
@@ -375,7 +375,7 @@ u32 igb_rd32(struct e1000_hw *hw, u32 reg);
 /* write operations, indexed using DWORDS */
 #define wr32(reg, val) \
 do { \
-       u8 __iomem *hw_addr = ACCESS_ONCE((hw)->hw_addr); \
+       u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \
        if (!E1000_REMOVED(hw_addr)) \
                writel((val), &hw_addr[(reg)]); \
 } while (0)
index ea69af267d63522ae7f545c2cbb8a7a6e601adbc..18b6c25d4705b9ca12918c5369a7a9e02cf35634 100644 (file)
@@ -750,7 +750,7 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
 u32 igb_rd32(struct e1000_hw *hw, u32 reg)
 {
        struct igb_adapter *igb = container_of(hw, struct igb_adapter, hw);
-       u8 __iomem *hw_addr = ACCESS_ONCE(hw->hw_addr);
+       u8 __iomem *hw_addr = READ_ONCE(hw->hw_addr);
        u32 value = 0;
 
        if (E1000_REMOVED(hw_addr))
index e083732adf649106ee8ae56d665e77649dba6456..a01409e2e06c810d84ce4486024d9256e5181095 100644 (file)
@@ -161,7 +161,7 @@ static inline bool ixgbe_removed(void __iomem *addr)
 
 static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value)
 {
-       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+       u8 __iomem *reg_addr = READ_ONCE(hw->hw_addr);
 
        if (ixgbe_removed(reg_addr))
                return;
@@ -180,7 +180,7 @@ static inline void writeq(u64 val, void __iomem *addr)
 
 static inline void ixgbe_write_reg64(struct ixgbe_hw *hw, u32 reg, u64 value)
 {
-       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+       u8 __iomem *reg_addr = READ_ONCE(hw->hw_addr);
 
        if (ixgbe_removed(reg_addr))
                return;
index 6d5f31e943583df77f5fa1e6aa3e2703fff33518..935a2f15b0b00e72763214aad0248a504f5b3a45 100644 (file)
@@ -380,7 +380,7 @@ static void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
  */
 u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
 {
-       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+       u8 __iomem *reg_addr = READ_ONCE(hw->hw_addr);
        u32 value;
 
        if (ixgbe_removed(reg_addr))
@@ -8624,7 +8624,7 @@ static void ixgbe_get_stats64(struct net_device *netdev,
 
        rcu_read_lock();
        for (i = 0; i < adapter->num_rx_queues; i++) {
-               struct ixgbe_ring *ring = ACCESS_ONCE(adapter->rx_ring[i]);
+               struct ixgbe_ring *ring = READ_ONCE(adapter->rx_ring[i]);
                u64 bytes, packets;
                unsigned int start;
 
@@ -8640,12 +8640,12 @@ static void ixgbe_get_stats64(struct net_device *netdev,
        }
 
        for (i = 0; i < adapter->num_tx_queues; i++) {
-               struct ixgbe_ring *ring = ACCESS_ONCE(adapter->tx_ring[i]);
+               struct ixgbe_ring *ring = READ_ONCE(adapter->tx_ring[i]);
 
                ixgbe_get_ring_stats64(stats, ring);
        }
        for (i = 0; i < adapter->num_xdp_queues; i++) {
-               struct ixgbe_ring *ring = ACCESS_ONCE(adapter->xdp_ring[i]);
+               struct ixgbe_ring *ring = READ_ONCE(adapter->xdp_ring[i]);
 
                ixgbe_get_ring_stats64(stats, ring);
        }
index 86d6924a2b714ad7535e34149078f10f31ca53dc..ae312c45696afd8b85f25d675810029c5ea126a2 100644 (file)
@@ -378,7 +378,7 @@ static int ixgbe_ptp_adjfreq_82599(struct ptp_clock_info *ptp, s32 ppb)
        }
 
        smp_mb();
-       incval = ACCESS_ONCE(adapter->base_incval);
+       incval = READ_ONCE(adapter->base_incval);
 
        freq = incval;
        freq *= ppb;
@@ -1159,7 +1159,7 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
        }
 
        /* update the base incval used to calculate frequency adjustment */
-       ACCESS_ONCE(adapter->base_incval) = incval;
+       WRITE_ONCE(adapter->base_incval, incval);
        smp_mb();
 
        /* need lock to prevent incorrect read while modifying cyclecounter */
index 032f8ac06357aefa7a695c6685b8bbbbf7a8949e..cacb30682434b8685a0102fa51b883fe08caf547 100644 (file)
@@ -164,7 +164,7 @@ static void ixgbevf_check_remove(struct ixgbe_hw *hw, u32 reg)
 
 u32 ixgbevf_read_reg(struct ixgbe_hw *hw, u32 reg)
 {
-       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+       u8 __iomem *reg_addr = READ_ONCE(hw->hw_addr);
        u32 value;
 
        if (IXGBE_REMOVED(reg_addr))
index 04d8d4ee4f045e9fb929882c06f3bb5803981921..c651fefcc3d22b78e3ec1123394cf5604c94e43e 100644 (file)
@@ -182,7 +182,7 @@ struct ixgbevf_info {
 
 static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value)
 {
-       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+       u8 __iomem *reg_addr = READ_ONCE(hw->hw_addr);
 
        if (IXGBE_REMOVED(reg_addr))
                return;
index a37af5813f33758d1ed8debf6bcd77590363f349..fcf9ba5eb8d1db0ac9947bbb6ab7bb8790e34a8b 100644 (file)
@@ -6747,6 +6747,9 @@ static int mvpp2_irqs_init(struct mvpp2_port *port)
        for (i = 0; i < port->nqvecs; i++) {
                struct mvpp2_queue_vector *qv = port->qvecs + i;
 
+               if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE)
+                       irq_set_status_flags(qv->irq, IRQ_NO_BALANCING);
+
                err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv);
                if (err)
                        goto err;
@@ -6776,6 +6779,7 @@ static void mvpp2_irqs_deinit(struct mvpp2_port *port)
                struct mvpp2_queue_vector *qv = port->qvecs + i;
 
                irq_set_affinity_hint(qv->irq, NULL);
+               irq_clear_status_flags(qv->irq, IRQ_NO_BALANCING);
                free_irq(qv->irq, qv);
        }
 }
index 8a32a8f7f9c0c7316665294b5342051b46f8b623..3541a7f9d12e5a06f924f80d0fee20c355d1204a 100644 (file)
@@ -414,8 +414,8 @@ bool mlx4_en_process_tx_cq(struct net_device *dev,
 
        index = cons_index & size_mask;
        cqe = mlx4_en_get_cqe(buf, index, priv->cqe_size) + factor;
-       last_nr_txbb = ACCESS_ONCE(ring->last_nr_txbb);
-       ring_cons = ACCESS_ONCE(ring->cons);
+       last_nr_txbb = READ_ONCE(ring->last_nr_txbb);
+       ring_cons = READ_ONCE(ring->cons);
        ring_index = ring_cons & size_mask;
        stamp_index = ring_index;
 
@@ -479,8 +479,8 @@ bool mlx4_en_process_tx_cq(struct net_device *dev,
        wmb();
 
        /* we want to dirty this cache line once */
-       ACCESS_ONCE(ring->last_nr_txbb) = last_nr_txbb;
-       ACCESS_ONCE(ring->cons) = ring_cons + txbbs_skipped;
+       WRITE_ONCE(ring->last_nr_txbb, last_nr_txbb);
+       WRITE_ONCE(ring->cons, ring_cons + txbbs_skipped);
 
        if (cq->type == TX_XDP)
                return done < budget;
@@ -858,7 +858,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                goto tx_drop;
 
        /* fetch ring->cons far ahead before needing it to avoid stall */
-       ring_cons = ACCESS_ONCE(ring->cons);
+       ring_cons = READ_ONCE(ring->cons);
 
        real_size = get_real_size(skb, shinfo, dev, &lso_header_size,
                                  &inline_ok, &fragptr);
@@ -1066,7 +1066,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                 */
                smp_rmb();
 
-               ring_cons = ACCESS_ONCE(ring->cons);
+               ring_cons = READ_ONCE(ring->cons);
                if (unlikely(!mlx4_en_is_tx_ring_full(ring))) {
                        netif_tx_wake_queue(ring->tx_queue);
                        ring->wake_queue++;
index fc281712869b2e1c5c3321b46d1e8c5c562fcb74..17b723218b0c0d891a44379e0f69ad804d43c154 100644 (file)
@@ -93,7 +93,7 @@ static void delayed_event_release(struct mlx5_device_context *dev_ctx,
        list_splice_init(&priv->waiting_events_list, &temp);
        if (!dev_ctx->context)
                goto out;
-       list_for_each_entry_safe(de, n, &priv->waiting_events_list, list)
+       list_for_each_entry_safe(de, n, &temp, list)
                dev_ctx->intf->event(dev, dev_ctx->context, de->event, de->param);
 
 out:
index cc13d3dbd3666e346d169ca059900f1faf5ee06f..13b5ef9d8703fd21c3cd8d471d5d3ddae7180bde 100644 (file)
@@ -67,7 +67,7 @@
 #define MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE                0xa
 #define MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE                0xd
 
-#define MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE_MPW            0x1
+#define MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE_MPW            0x2
 #define MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE_MPW            0x3
 #define MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE_MPW            0x6
 
index 850cdc980ab5a5e9d21b85d50c6386def3c173bb..4837045ffba376afde13bd1a52931a07f3d4d268 100644 (file)
@@ -365,21 +365,24 @@ static void mlx5e_execute_l2_action(struct mlx5e_priv *priv,
                                    struct mlx5e_l2_hash_node *hn)
 {
        u8 action = hn->action;
+       u8 mac_addr[ETH_ALEN];
        int l2_err = 0;
 
+       ether_addr_copy(mac_addr, hn->ai.addr);
+
        switch (action) {
        case MLX5E_ACTION_ADD:
                mlx5e_add_l2_flow_rule(priv, &hn->ai, MLX5E_FULLMATCH);
-               if (!is_multicast_ether_addr(hn->ai.addr)) {
-                       l2_err = mlx5_mpfs_add_mac(priv->mdev, hn->ai.addr);
+               if (!is_multicast_ether_addr(mac_addr)) {
+                       l2_err = mlx5_mpfs_add_mac(priv->mdev, mac_addr);
                        hn->mpfs = !l2_err;
                }
                hn->action = MLX5E_ACTION_NONE;
                break;
 
        case MLX5E_ACTION_DEL:
-               if (!is_multicast_ether_addr(hn->ai.addr) && hn->mpfs)
-                       l2_err = mlx5_mpfs_del_mac(priv->mdev, hn->ai.addr);
+               if (!is_multicast_ether_addr(mac_addr) && hn->mpfs)
+                       l2_err = mlx5_mpfs_del_mac(priv->mdev, mac_addr);
                mlx5e_del_l2_flow_rule(priv, &hn->ai);
                mlx5e_del_l2_from_hash(hn);
                break;
@@ -387,7 +390,7 @@ static void mlx5e_execute_l2_action(struct mlx5e_priv *priv,
 
        if (l2_err)
                netdev_warn(priv->netdev, "MPFS, failed to %s mac %pM, err(%d)\n",
-                           action == MLX5E_ACTION_ADD ? "add" : "del", hn->ai.addr, l2_err);
+                           action == MLX5E_ACTION_ADD ? "add" : "del", mac_addr, l2_err);
 }
 
 static void mlx5e_sync_netdev_addr(struct mlx5e_priv *priv)
index 15a1687483cc5f6ed9b2943152ae1f54f9283617..91b1b093893148288a70ce42275b094b7cb454aa 100644 (file)
@@ -215,22 +215,20 @@ static inline bool mlx5e_rx_cache_get(struct mlx5e_rq *rq,
 static inline int mlx5e_page_alloc_mapped(struct mlx5e_rq *rq,
                                          struct mlx5e_dma_info *dma_info)
 {
-       struct page *page;
-
        if (mlx5e_rx_cache_get(rq, dma_info))
                return 0;
 
-       page = dev_alloc_pages(rq->buff.page_order);
-       if (unlikely(!page))
+       dma_info->page = dev_alloc_pages(rq->buff.page_order);
+       if (unlikely(!dma_info->page))
                return -ENOMEM;
 
-       dma_info->addr = dma_map_page(rq->pdev, page, 0,
+       dma_info->addr = dma_map_page(rq->pdev, dma_info->page, 0,
                                      RQ_PAGE_SIZE(rq), rq->buff.map_dir);
        if (unlikely(dma_mapping_error(rq->pdev, dma_info->addr))) {
-               put_page(page);
+               put_page(dma_info->page);
+               dma_info->page = NULL;
                return -ENOMEM;
        }
-       dma_info->page = page;
 
        return 0;
 }
index e906b754415c2877e799c623ee269280be1c6399..ab92298eafc37b43b21a0f020d841ec82d6a03ab 100644 (file)
@@ -49,7 +49,7 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
        struct mlx5e_channel *c = container_of(napi, struct mlx5e_channel,
                                               napi);
        bool busy = false;
-       int work_done;
+       int work_done = 0;
        int i;
 
        for (i = 0; i < c->num_tc; i++)
@@ -58,15 +58,17 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
        if (c->xdp)
                busy |= mlx5e_poll_xdpsq_cq(&c->rq.xdpsq.cq);
 
-       work_done = mlx5e_poll_rx_cq(&c->rq.cq, budget);
-       busy |= work_done == budget;
+       if (likely(budget)) { /* budget=0 means: don't poll rx rings */
+               work_done = mlx5e_poll_rx_cq(&c->rq.cq, budget);
+               busy |= work_done == budget;
+       }
 
        busy |= c->rq.post_wqes(&c->rq);
 
        if (busy) {
                if (likely(mlx5e_channel_no_affinity_change(c)))
                        return budget;
-               if (work_done == budget)
+               if (budget && work_done == budget)
                        work_done--;
        }
 
index 0d2c8dcd6eae40690b273938a7b87f0a9c7edd18..06562c9a6b9cb8f910b3c594e074f7bdb6421295 100644 (file)
@@ -1482,9 +1482,16 @@ static int mlx5_try_fast_unload(struct mlx5_core_dev *dev)
                return -EAGAIN;
        }
 
+       /* Panic tear down fw command will stop the PCI bus communication
+        * with the HCA, so the health polll is no longer needed.
+        */
+       mlx5_drain_health_wq(dev);
+       mlx5_stop_health_poll(dev);
+
        ret = mlx5_cmd_force_teardown_hca(dev);
        if (ret) {
                mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret);
+               mlx5_start_health_poll(dev);
                return ret;
        }
 
index 50ea69d88480c6108e82192d9b9ed57c985ccaf7..5dd5f61e1114bd1f7870fd1b34ed32d002a4d427 100644 (file)
@@ -2629,7 +2629,7 @@ static void vxge_poll_vp_lockup(unsigned long data)
                ring = &vdev->vpaths[i].ring;
 
                /* Truncated to machine word size number of frames */
-               rx_frms = ACCESS_ONCE(ring->stats.rx_frms);
+               rx_frms = READ_ONCE(ring->stats.rx_frms);
 
                /* Did this vpath received any packets */
                if (ring->stats.prev_rx_frms == rx_frms) {
index 9feec70094435e19ee039f18ea430291d9f7d1a0..29fea74bff2e6793a0305ef154a73886f1d2a82b 100644 (file)
@@ -4725,9 +4725,9 @@ static const struct net_device_ops qlge_netdev_ops = {
        .ndo_vlan_rx_kill_vid   = qlge_vlan_rx_kill_vid,
 };
 
-static void ql_timer(unsigned long data)
+static void ql_timer(struct timer_list *t)
 {
-       struct ql_adapter *qdev = (struct ql_adapter *)data;
+       struct ql_adapter *qdev = from_timer(qdev, t, timer);
        u32 var = 0;
 
        var = ql_read32(qdev, STS);
@@ -4806,11 +4806,8 @@ static int qlge_probe(struct pci_dev *pdev,
        /* Start up the timer to trigger EEH if
         * the bus goes dead
         */
-       init_timer_deferrable(&qdev->timer);
-       qdev->timer.data = (unsigned long)qdev;
-       qdev->timer.function = ql_timer;
-       qdev->timer.expires = jiffies + (5*HZ);
-       add_timer(&qdev->timer);
+       timer_setup(&qdev->timer, ql_timer, TIMER_DEFERRABLE);
+       mod_timer(&qdev->timer, jiffies + (5*HZ));
        ql_link_off(qdev);
        ql_display_dev_info(ndev);
        atomic_set(&qdev->lb_count, 0);
index 13f72f5b18d20d215b889e2caf3f5c075110832f..a95a46bcd339d824f442170b47f335c630c50b6b 100644 (file)
@@ -2073,7 +2073,7 @@ static irqreturn_t efx_ef10_msi_interrupt(int irq, void *dev_id)
        netif_vdbg(efx, intr, efx->net_dev,
                   "IRQ %d on CPU %d\n", irq, raw_smp_processor_id());
 
-       if (likely(ACCESS_ONCE(efx->irq_soft_enabled))) {
+       if (likely(READ_ONCE(efx->irq_soft_enabled))) {
                /* Note test interrupts */
                if (context->index == efx->irq_level)
                        efx->last_irq_cpu = raw_smp_processor_id();
@@ -2088,7 +2088,7 @@ static irqreturn_t efx_ef10_msi_interrupt(int irq, void *dev_id)
 static irqreturn_t efx_ef10_legacy_interrupt(int irq, void *dev_id)
 {
        struct efx_nic *efx = dev_id;
-       bool soft_enabled = ACCESS_ONCE(efx->irq_soft_enabled);
+       bool soft_enabled = READ_ONCE(efx->irq_soft_enabled);
        struct efx_channel *channel;
        efx_dword_t reg;
        u32 queues;
@@ -3291,7 +3291,7 @@ static int efx_ef10_handle_rx_event(struct efx_channel *channel,
        bool rx_cont;
        u16 flags = 0;
 
-       if (unlikely(ACCESS_ONCE(efx->reset_pending)))
+       if (unlikely(READ_ONCE(efx->reset_pending)))
                return 0;
 
        /* Basic packet information */
@@ -3428,7 +3428,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
        unsigned int tx_ev_q_label;
        int tx_descs = 0;
 
-       if (unlikely(ACCESS_ONCE(efx->reset_pending)))
+       if (unlikely(READ_ONCE(efx->reset_pending)))
                return 0;
 
        if (unlikely(EFX_QWORD_FIELD(*event, ESF_DZ_TX_DROP_EVENT)))
@@ -5316,7 +5316,7 @@ static void efx_ef10_filter_remove_old(struct efx_nic *efx)
        int i;
 
        for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) {
-               if (ACCESS_ONCE(table->entry[i].spec) &
+               if (READ_ONCE(table->entry[i].spec) &
                    EFX_EF10_FILTER_FLAG_AUTO_OLD) {
                        rc = efx_ef10_filter_remove_internal(efx,
                                        1U << EFX_FILTER_PRI_AUTO, i, true);
index b9cb697b281847a83aa511c577a6c790516f8012..016616a6388057c7107196ae7521543785a5c678 100644 (file)
@@ -2809,7 +2809,7 @@ static void efx_reset_work(struct work_struct *data)
        unsigned long pending;
        enum reset_type method;
 
-       pending = ACCESS_ONCE(efx->reset_pending);
+       pending = READ_ONCE(efx->reset_pending);
        method = fls(pending) - 1;
 
        if (method == RESET_TYPE_MC_BIST)
@@ -2874,7 +2874,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
        /* If we're not READY then just leave the flags set as the cue
         * to abort probing or reschedule the reset later.
         */
-       if (ACCESS_ONCE(efx->state) != STATE_READY)
+       if (READ_ONCE(efx->state) != STATE_READY)
                return;
 
        /* efx_process_channel() will no longer read events once a
index 29614da91cbf919f91841d8e644ab4b246741ec7..7263275fde4a1d6eb27d7bd3d358904b2a66313a 100644 (file)
@@ -2545,7 +2545,7 @@ static void ef4_reset_work(struct work_struct *data)
        unsigned long pending;
        enum reset_type method;
 
-       pending = ACCESS_ONCE(efx->reset_pending);
+       pending = READ_ONCE(efx->reset_pending);
        method = fls(pending) - 1;
 
        if ((method == RESET_TYPE_RECOVER_OR_DISABLE ||
@@ -2605,7 +2605,7 @@ void ef4_schedule_reset(struct ef4_nic *efx, enum reset_type type)
        /* If we're not READY then just leave the flags set as the cue
         * to abort probing or reschedule the reset later.
         */
-       if (ACCESS_ONCE(efx->state) != STATE_READY)
+       if (READ_ONCE(efx->state) != STATE_READY)
                return;
 
        queue_work(reset_workqueue, &efx->reset_work);
index 93c713c1f627a77965fb4fafb590995ba27b9a92..cd8bb472d75813773e645b6bf0e1c196523a38d0 100644 (file)
@@ -452,7 +452,7 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
                   "IRQ %d on CPU %d status " EF4_OWORD_FMT "\n",
                   irq, raw_smp_processor_id(), EF4_OWORD_VAL(*int_ker));
 
-       if (!likely(ACCESS_ONCE(efx->irq_soft_enabled)))
+       if (!likely(READ_ONCE(efx->irq_soft_enabled)))
                return IRQ_HANDLED;
 
        /* Check to see if we have a serious error condition */
@@ -1372,7 +1372,7 @@ static void falcon_reconfigure_mac_wrapper(struct ef4_nic *efx)
        ef4_oword_t reg;
        int link_speed, isolate;
 
-       isolate = !!ACCESS_ONCE(efx->reset_pending);
+       isolate = !!READ_ONCE(efx->reset_pending);
 
        switch (link_state->speed) {
        case 10000: link_speed = 3; break;
index 05916c710d8c87071a5aed864bb03d6d01bb6c91..494884f6af4afd1510a17111d6c311820f139b0c 100644 (file)
@@ -834,7 +834,7 @@ ef4_farch_handle_tx_event(struct ef4_channel *channel, ef4_qword_t *event)
        struct ef4_nic *efx = channel->efx;
        int tx_packets = 0;
 
-       if (unlikely(ACCESS_ONCE(efx->reset_pending)))
+       if (unlikely(READ_ONCE(efx->reset_pending)))
                return 0;
 
        if (likely(EF4_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) {
@@ -990,7 +990,7 @@ ef4_farch_handle_rx_event(struct ef4_channel *channel, const ef4_qword_t *event)
        struct ef4_rx_queue *rx_queue;
        struct ef4_nic *efx = channel->efx;
 
-       if (unlikely(ACCESS_ONCE(efx->reset_pending)))
+       if (unlikely(READ_ONCE(efx->reset_pending)))
                return;
 
        rx_ev_cont = EF4_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT);
@@ -1504,7 +1504,7 @@ irqreturn_t ef4_farch_fatal_interrupt(struct ef4_nic *efx)
 irqreturn_t ef4_farch_legacy_interrupt(int irq, void *dev_id)
 {
        struct ef4_nic *efx = dev_id;
-       bool soft_enabled = ACCESS_ONCE(efx->irq_soft_enabled);
+       bool soft_enabled = READ_ONCE(efx->irq_soft_enabled);
        ef4_oword_t *int_ker = efx->irq_status.addr;
        irqreturn_t result = IRQ_NONE;
        struct ef4_channel *channel;
@@ -1596,7 +1596,7 @@ irqreturn_t ef4_farch_msi_interrupt(int irq, void *dev_id)
                   "IRQ %d on CPU %d status " EF4_OWORD_FMT "\n",
                   irq, raw_smp_processor_id(), EF4_OWORD_VAL(*int_ker));
 
-       if (!likely(ACCESS_ONCE(efx->irq_soft_enabled)))
+       if (!likely(READ_ONCE(efx->irq_soft_enabled)))
                return IRQ_HANDLED;
 
        /* Handle non-event-queue sources */
index a4c4592f60232a886fd8a21d0c0b0ccca21df811..54ca457cdb15dc79f0d5175c83d530ed3c3440a9 100644 (file)
@@ -83,7 +83,7 @@ static inline struct ef4_tx_queue *ef4_tx_queue_partner(struct ef4_tx_queue *tx_
 static inline bool __ef4_nic_tx_is_empty(struct ef4_tx_queue *tx_queue,
                                         unsigned int write_count)
 {
-       unsigned int empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count);
+       unsigned int empty_read_count = READ_ONCE(tx_queue->empty_read_count);
 
        if (empty_read_count == 0)
                return false;
@@ -464,11 +464,11 @@ irqreturn_t ef4_farch_fatal_interrupt(struct ef4_nic *efx);
 
 static inline int ef4_nic_event_test_irq_cpu(struct ef4_channel *channel)
 {
-       return ACCESS_ONCE(channel->event_test_cpu);
+       return READ_ONCE(channel->event_test_cpu);
 }
 static inline int ef4_nic_irq_test_irq_cpu(struct ef4_nic *efx)
 {
-       return ACCESS_ONCE(efx->last_irq_cpu);
+       return READ_ONCE(efx->last_irq_cpu);
 }
 
 /* Global Resources */
index 6a75f4140a4be3c96782d79a72f7efc6162e2a3f..6486814e97dccee08431dea134739d2840c6c991 100644 (file)
@@ -134,8 +134,8 @@ static void ef4_tx_maybe_stop_queue(struct ef4_tx_queue *txq1)
         */
        netif_tx_stop_queue(txq1->core_txq);
        smp_mb();
-       txq1->old_read_count = ACCESS_ONCE(txq1->read_count);
-       txq2->old_read_count = ACCESS_ONCE(txq2->read_count);
+       txq1->old_read_count = READ_ONCE(txq1->read_count);
+       txq2->old_read_count = READ_ONCE(txq2->read_count);
 
        fill_level = max(txq1->insert_count - txq1->old_read_count,
                         txq2->insert_count - txq2->old_read_count);
@@ -524,7 +524,7 @@ void ef4_xmit_done(struct ef4_tx_queue *tx_queue, unsigned int index)
 
        /* Check whether the hardware queue is now empty */
        if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
-               tx_queue->old_write_count = ACCESS_ONCE(tx_queue->write_count);
+               tx_queue->old_write_count = READ_ONCE(tx_queue->write_count);
                if (tx_queue->read_count == tx_queue->old_write_count) {
                        smp_mb();
                        tx_queue->empty_read_count =
index ba45150f53c7a478c447d82be07f6d3174f0222d..86454d25a405ecbcdd3dd604b963659e0d128541 100644 (file)
@@ -827,7 +827,7 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
        struct efx_nic *efx = channel->efx;
        int tx_packets = 0;
 
-       if (unlikely(ACCESS_ONCE(efx->reset_pending)))
+       if (unlikely(READ_ONCE(efx->reset_pending)))
                return 0;
 
        if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) {
@@ -979,7 +979,7 @@ efx_farch_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
        struct efx_rx_queue *rx_queue;
        struct efx_nic *efx = channel->efx;
 
-       if (unlikely(ACCESS_ONCE(efx->reset_pending)))
+       if (unlikely(READ_ONCE(efx->reset_pending)))
                return;
 
        rx_ev_cont = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT);
@@ -1520,7 +1520,7 @@ irqreturn_t efx_farch_fatal_interrupt(struct efx_nic *efx)
 irqreturn_t efx_farch_legacy_interrupt(int irq, void *dev_id)
 {
        struct efx_nic *efx = dev_id;
-       bool soft_enabled = ACCESS_ONCE(efx->irq_soft_enabled);
+       bool soft_enabled = READ_ONCE(efx->irq_soft_enabled);
        efx_oword_t *int_ker = efx->irq_status.addr;
        irqreturn_t result = IRQ_NONE;
        struct efx_channel *channel;
@@ -1612,7 +1612,7 @@ irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id)
                   "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
                   irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 
-       if (!likely(ACCESS_ONCE(efx->irq_soft_enabled)))
+       if (!likely(READ_ONCE(efx->irq_soft_enabled)))
                return IRQ_HANDLED;
 
        /* Handle non-event-queue sources */
index 4d7fb8af880d0f36189f8475a9859b229a7bd078..7b51b637172465678b106e554055a2ccf970cecb 100644 (file)
@@ -81,7 +81,7 @@ static struct efx_tx_queue *efx_tx_queue_partner(struct efx_tx_queue *tx_queue)
 static inline bool __efx_nic_tx_is_empty(struct efx_tx_queue *tx_queue,
                                         unsigned int write_count)
 {
-       unsigned int empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count);
+       unsigned int empty_read_count = READ_ONCE(tx_queue->empty_read_count);
 
        if (empty_read_count == 0)
                return false;
@@ -617,11 +617,11 @@ irqreturn_t efx_farch_fatal_interrupt(struct efx_nic *efx);
 
 static inline int efx_nic_event_test_irq_cpu(struct efx_channel *channel)
 {
-       return ACCESS_ONCE(channel->event_test_cpu);
+       return READ_ONCE(channel->event_test_cpu);
 }
 static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx)
 {
-       return ACCESS_ONCE(efx->last_irq_cpu);
+       return READ_ONCE(efx->last_irq_cpu);
 }
 
 /* Global Resources */
index 60cdb97f58e2e315cf690ee58a16004926528583..56c2db398deff5f250f8cb729618daa61aa58cc7 100644 (file)
@@ -658,7 +658,7 @@ static void efx_ptp_send_times(struct efx_nic *efx,
 
        /* Write host time for specified period or until MC is done */
        while ((timespec64_compare(&now.ts_real, &limit) < 0) &&
-              ACCESS_ONCE(*mc_running)) {
+              READ_ONCE(*mc_running)) {
                struct timespec64 update_time;
                unsigned int host_time;
 
@@ -668,7 +668,7 @@ static void efx_ptp_send_times(struct efx_nic *efx,
                do {
                        pps_get_ts(&now);
                } while ((timespec64_compare(&now.ts_real, &update_time) < 0) &&
-                        ACCESS_ONCE(*mc_running));
+                        READ_ONCE(*mc_running));
 
                /* Synchronise NIC with single word of time only */
                host_time = (now.ts_real.tv_sec << MC_NANOSECOND_BITS |
@@ -832,14 +832,14 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
                       ptp->start.dma_addr);
 
        /* Clear flag that signals MC ready */
-       ACCESS_ONCE(*start) = 0;
+       WRITE_ONCE(*start, 0);
        rc = efx_mcdi_rpc_start(efx, MC_CMD_PTP, synch_buf,
                                MC_CMD_PTP_IN_SYNCHRONIZE_LEN);
        EFX_WARN_ON_ONCE_PARANOID(rc);
 
        /* Wait for start from MCDI (or timeout) */
        timeout = jiffies + msecs_to_jiffies(MAX_SYNCHRONISE_WAIT_MS);
-       while (!ACCESS_ONCE(*start) && (time_before(jiffies, timeout))) {
+       while (!READ_ONCE(*start) && (time_before(jiffies, timeout))) {
                udelay(20);     /* Usually start MCDI execution quickly */
                loops++;
        }
@@ -849,7 +849,7 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
        if (!time_before(jiffies, timeout))
                ++ptp->sync_timeouts;
 
-       if (ACCESS_ONCE(*start))
+       if (READ_ONCE(*start))
                efx_ptp_send_times(efx, &last_time);
 
        /* Collect results */
index 32bf1fecf86406d7a51cc61bd03388f5ad090312..efb66ea21f27d3d8fd458bba54bdd046a1a936a2 100644 (file)
@@ -136,8 +136,8 @@ static void efx_tx_maybe_stop_queue(struct efx_tx_queue *txq1)
         */
        netif_tx_stop_queue(txq1->core_txq);
        smp_mb();
-       txq1->old_read_count = ACCESS_ONCE(txq1->read_count);
-       txq2->old_read_count = ACCESS_ONCE(txq2->read_count);
+       txq1->old_read_count = READ_ONCE(txq1->read_count);
+       txq2->old_read_count = READ_ONCE(txq2->read_count);
 
        fill_level = max(txq1->insert_count - txq1->old_read_count,
                         txq2->insert_count - txq2->old_read_count);
@@ -752,7 +752,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
 
        /* Check whether the hardware queue is now empty */
        if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
-               tx_queue->old_write_count = ACCESS_ONCE(tx_queue->write_count);
+               tx_queue->old_write_count = READ_ONCE(tx_queue->write_count);
                if (tx_queue->read_count == tx_queue->old_write_count) {
                        smp_mb();
                        tx_queue->empty_read_count =
index 6a4e8e1bbd90e5028ac147f3134a8ec2348d0bb5..8ab0fb6892d5d3562e891d574331d816acb69a51 100644 (file)
@@ -6245,7 +6245,7 @@ static void niu_get_rx_stats(struct niu *np,
 
        pkts = dropped = errors = bytes = 0;
 
-       rx_rings = ACCESS_ONCE(np->rx_rings);
+       rx_rings = READ_ONCE(np->rx_rings);
        if (!rx_rings)
                goto no_rings;
 
@@ -6276,7 +6276,7 @@ static void niu_get_tx_stats(struct niu *np,
 
        pkts = errors = bytes = 0;
 
-       tx_rings = ACCESS_ONCE(np->tx_rings);
+       tx_rings = READ_ONCE(np->tx_rings);
        if (!tx_rings)
                goto no_rings;
 
index c00102b8145aea309e3a405b8b62803d70b1e4d4..b3e5816a4678fa7238286e53a470624088e51c43 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/tcp.h>
 #include <linux/net_tstamp.h>
 #include <linux/ptp_clock_kernel.h>
-#include <linux/tick.h>
+#include <linux/sched/isolation.h>
 
 #include <asm/checksum.h>
 #include <asm/homecache.h>
@@ -2270,8 +2270,8 @@ static int __init tile_net_init_module(void)
                tile_net_dev_init(name, mac);
 
        if (!network_cpus_init())
-               cpumask_and(&network_cpus_map, housekeeping_cpumask(),
-                           cpu_online_mask);
+               cpumask_and(&network_cpus_map,
+                           housekeeping_cpumask(HK_FLAG_MISC), cpu_online_mask);
 
        return 0;
 }
index 49ccee4b9aeccc3b6cd165b461d448f0aba7a6bd..56d06282fbde7343afa63f7df9b66fdd4fb10a5d 100644 (file)
@@ -608,9 +608,9 @@ static void tile_net_schedule_egress_timer(struct tile_net_cpu *info)
  * ISSUE: Maybe instead track number of expected completions, and free
  * only that many, resetting to zero if "pending" is ever false.
  */
-static void tile_net_handle_egress_timer(unsigned long arg)
+static void tile_net_handle_egress_timer(struct timer_list *t)
 {
-       struct tile_net_cpu *info = (struct tile_net_cpu *)arg;
+       struct tile_net_cpu *info = from_timer(info, t, egress_timer);
        struct net_device *dev = info->napi.dev;
 
        /* The timer is no longer scheduled. */
@@ -1004,9 +1004,8 @@ static void tile_net_register(void *dev_ptr)
                BUG();
 
        /* Initialize the egress timer. */
-       init_timer_pinned(&info->egress_timer);
-       info->egress_timer.data = (long)info;
-       info->egress_timer.function = tile_net_handle_egress_timer;
+       timer_setup(&info->egress_timer, tile_net_handle_egress_timer,
+                   TIMER_PINNED);
 
        u64_stats_init(&info->stats.syncp);
 
index 7a7c5224a3368785fa046640edfbf0888c0d4128..104f71fa9c5ed342df1988dc86d5389e1c49673b 100644 (file)
@@ -157,7 +157,7 @@ static struct net_device *yam_devs[NR_PORTS];
 
 static struct yam_mcs *yam_data;
 
-static DEFINE_TIMER(yam_timer, NULL, 0, 0);
+static DEFINE_TIMER(yam_timer, NULL);
 
 /* --------------------------------------------------------------------- */
 
index 6c0c84c33e1fb62f259881de910934470b6a8929..b13890953ebb92515b3924f511714942a912b120 100644 (file)
@@ -257,7 +257,7 @@ static struct tap_queue *tap_get_queue(struct tap_dev *tap,
         * and validate that the result isn't NULL - in case we are
         * racing against queue removal.
         */
-       int numvtaps = ACCESS_ONCE(tap->numvtaps);
+       int numvtaps = READ_ONCE(tap->numvtaps);
        __u32 rxq;
 
        if (!numvtaps)
index 42bb820a56c92e812d93e66ae2e87a9e0648f001..c1685a6d788360beb3a1a0b8cf3a01efe157618d 100644 (file)
@@ -469,7 +469,7 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,
        u32 numqueues = 0;
 
        rcu_read_lock();
-       numqueues = ACCESS_ONCE(tun->numqueues);
+       numqueues = READ_ONCE(tun->numqueues);
 
        txq = __skb_get_hash_symmetric(skb);
        if (txq) {
@@ -864,7 +864,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 
        rcu_read_lock();
        tfile = rcu_dereference(tun->tfiles[txq]);
-       numqueues = ACCESS_ONCE(tun->numqueues);
+       numqueues = READ_ONCE(tun->numqueues);
 
        /* Drop packet if interface is not attached */
        if (txq >= numqueues)
index b2ff88e69a819cc3098a720ece238d8847d6be57..3d4f7959dabb9c39e17754df4f72013c89743d5a 100644 (file)
@@ -626,7 +626,7 @@ static int asix_suspend(struct usb_interface *intf, pm_message_t message)
        struct usbnet *dev = usb_get_intfdata(intf);
        struct asix_common_private *priv = dev->driver_priv;
 
-       if (priv->suspend)
+       if (priv && priv->suspend)
                priv->suspend(dev);
 
        return usbnet_suspend(intf, message);
@@ -678,7 +678,7 @@ static int asix_resume(struct usb_interface *intf)
        struct usbnet *dev = usb_get_intfdata(intf);
        struct asix_common_private *priv = dev->driver_priv;
 
-       if (priv->resume)
+       if (priv && priv->resume)
                priv->resume(dev);
 
        return usbnet_resume(intf);
index 3e7a3ac3a36236054b897bc7beda770a765a95e5..05dca3e5c93d4baf7fb975a6fef30d3d322f1aaf 100644 (file)
@@ -230,7 +230,7 @@ skip:
                        goto bad_desc;
        }
 
-       if (header.usb_cdc_ether_desc) {
+       if (header.usb_cdc_ether_desc && info->ether->wMaxSegmentSize) {
                dev->hard_mtu = le16_to_cpu(info->ether->wMaxSegmentSize);
                /* because of Zaurus, we may be ignoring the host
                 * side link address we were given.
index 8c373360827108855717f6d139034ff9f264bf0b..8d4a6f7cba610a37779c3e9f7d341dbd9795c8fc 100644 (file)
@@ -499,6 +499,7 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                return 1;
        }
        if (rawip) {
+               skb_reset_mac_header(skb);
                skb->dev = dev->net; /* normally set by eth_type_trans */
                skb->protocol = proto;
                return 1;
@@ -681,7 +682,7 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
        }
 
        /* errors aren't fatal - we can live with the dynamic address */
-       if (cdc_ether) {
+       if (cdc_ether && cdc_ether->wMaxSegmentSize) {
                dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize);
                usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
        }
index d7c49cf1d5e91e2f962d499c4b88df87eec6dacd..3247d2feda07f8a671fe32aa45225cfbd34c50ff 100644 (file)
@@ -2325,9 +2325,9 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 }
 
 /* Walk the forwarding table and purge stale entries */
-static void vxlan_cleanup(unsigned long arg)
+static void vxlan_cleanup(struct timer_list *t)
 {
-       struct vxlan_dev *vxlan = (struct vxlan_dev *) arg;
+       struct vxlan_dev *vxlan = from_timer(vxlan, t, age_timer);
        unsigned long next_timer = jiffies + FDB_AGE_INTERVAL;
        unsigned int h;
 
@@ -2647,9 +2647,7 @@ static void vxlan_setup(struct net_device *dev)
        INIT_LIST_HEAD(&vxlan->next);
        spin_lock_init(&vxlan->hash_lock);
 
-       init_timer_deferrable(&vxlan->age_timer);
-       vxlan->age_timer.function = vxlan_cleanup;
-       vxlan->age_timer.data = (unsigned long) vxlan;
+       timer_setup(&vxlan->age_timer, vxlan_cleanup, TIMER_DEFERRABLE);
 
        vxlan->dev = dev;
 
index a408abc25512aca0d94f16bbe0cefa0cdd758aaf..f4b0ab34f04838d24333f47de7f1f5620fa8c018 100644 (file)
@@ -276,8 +276,6 @@ static void cisco_timer(unsigned long arg)
        spin_unlock(&st->lock);
 
        st->timer.expires = jiffies + st->settings.interval * HZ;
-       st->timer.function = cisco_timer;
-       st->timer.data = arg;
        add_timer(&st->timer);
 }
 
index 78596e42a3f3f27623284c86a0d791a2bf4a65b6..07f265fa2826a97333eedb0cc06fd40198166b13 100644 (file)
@@ -644,8 +644,6 @@ static void fr_timer(unsigned long arg)
                        state(hdlc)->settings.t391 * HZ;
        }
 
-       state(hdlc)->timer.function = fr_timer;
-       state(hdlc)->timer.data = arg;
        add_timer(&state(hdlc)->timer);
 }
 
index bd8d4392d68b3042594f5d9693816910cea3acbc..80f75139495fc25d3a2e7f085e9deedc3abb20f6 100644 (file)
@@ -500,13 +500,13 @@ ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
 
        tx_status = &desc->ud.ds_tx5212.tx_stat;
 
-       txstat1 = ACCESS_ONCE(tx_status->tx_status_1);
+       txstat1 = READ_ONCE(tx_status->tx_status_1);
 
        /* No frame has been send or error */
        if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE)))
                return -EINPROGRESS;
 
-       txstat0 = ACCESS_ONCE(tx_status->tx_status_0);
+       txstat0 = READ_ONCE(tx_status->tx_status_0);
 
        /*
         * Get descriptor status
@@ -700,14 +700,14 @@ ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
        u32 rxstat0, rxstat1;
 
        rx_status = &desc->ud.ds_rx.rx_stat;
-       rxstat1 = ACCESS_ONCE(rx_status->rx_status_1);
+       rxstat1 = READ_ONCE(rx_status->rx_status_1);
 
        /* No frame received / not ready */
        if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE)))
                return -EINPROGRESS;
 
        memset(rs, 0, sizeof(struct ath5k_rx_status));
-       rxstat0 = ACCESS_ONCE(rx_status->rx_status_0);
+       rxstat0 = READ_ONCE(rx_status->rx_status_0);
 
        /*
         * Frame receive status
index 3a8d5e97dc8efecf4907f8d1a2fbc99e7be697f5..c09e40c9010ff0339f0f0e672151e0905133a7e8 100644 (file)
@@ -60,9 +60,9 @@ void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie)
                ar->fw_recovery.hb_pending = false;
 }
 
-static void ath6kl_recovery_hb_timer(unsigned long data)
+static void ath6kl_recovery_hb_timer(struct timer_list *t)
 {
-       struct ath6kl *ar = (struct ath6kl *) data;
+       struct ath6kl *ar = from_timer(ar, t, fw_recovery.hb_timer);
        int err;
 
        if (test_bit(RECOVERY_CLEANUP, &ar->flag) ||
@@ -104,9 +104,8 @@ void ath6kl_recovery_init(struct ath6kl *ar)
        recovery->seq_num = 0;
        recovery->hb_misscnt = 0;
        ar->fw_recovery.hb_pending = false;
-       ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer;
-       ar->fw_recovery.hb_timer.data = (unsigned long) ar;
-       init_timer_deferrable(&ar->fw_recovery.hb_timer);
+       timer_setup(&ar->fw_recovery.hb_timer, ath6kl_recovery_hb_timer,
+                   TIMER_DEFERRABLE);
 
        if (ar->fw_recovery.hb_poll)
                mod_timer(&ar->fw_recovery.hb_timer, jiffies +
index 94bf01f8b2a88872ecee00504f1266858539edca..ede89d4ffc8824cbf8e43dc0e78e227f02bb1539 100644 (file)
@@ -519,7 +519,7 @@ exit:
 /* LED trigger */
 static int tx_activity;
 static void at76_ledtrig_tx_timerfunc(unsigned long data);
-static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc, 0, 0);
+static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc);
 DEFINE_LED_TRIGGER(ledtrig_tx);
 
 static void at76_ledtrig_tx_timerfunc(unsigned long data)
index 613caca7dc020a78985b22521422700022c37473..785a0f33b7e66ece24efc4f5b9e97904a2b07957 100644 (file)
@@ -3628,7 +3628,7 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
 
        bus->dpc_running = true;
        wmb();
-       while (ACCESS_ONCE(bus->dpc_triggered)) {
+       while (READ_ONCE(bus->dpc_triggered)) {
                bus->dpc_triggered = false;
                brcmf_sdio_dpc(bus);
                bus->idlecount = 0;
index 231878969332d9ad19423d227a2b383b30fe2dfe..0f45f34e39d3d549b78743d4683ef715296c7918 100644 (file)
@@ -1118,7 +1118,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
 static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
 {
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
-       bool calibrating = ACCESS_ONCE(mvm->calibrating);
+       bool calibrating = READ_ONCE(mvm->calibrating);
 
        if (state)
                set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
index 6f2e2af23219a27f856b9bb0bd3ce7cf0647856d..6e9d3289b9d0ef68ccb40603f8601b3552abeab9 100644 (file)
@@ -652,7 +652,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
                                return -1;
                } else if (info.control.vif->type == NL80211_IFTYPE_STATION &&
                           is_multicast_ether_addr(hdr->addr1)) {
-                       u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id);
+                       u8 ap_sta_id = READ_ONCE(mvmvif->ap_sta_id);
 
                        if (ap_sta_id != IWL_MVM_INVALID_STA)
                                sta_id = ap_sta_id;
@@ -700,7 +700,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
        snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
                tcp_hdrlen(skb);
 
-       dbg_max_amsdu_len = ACCESS_ONCE(mvm->max_amsdu_len);
+       dbg_max_amsdu_len = READ_ONCE(mvm->max_amsdu_len);
 
        if (!sta->max_amsdu_len ||
            !ieee80211_is_data_qos(hdr->frame_control) ||
index a06b6612b6583d6b5efa1d2396bc2060a2ffa37f..f25ce3a1ea50347678c5662e5868a3e37b9d139e 100644 (file)
@@ -1247,7 +1247,7 @@ restart:
        spin_lock(&rxq->lock);
        /* uCode's read index (stored in shared DRAM) indicates the last Rx
         * buffer that the driver may process (last buffer filled by ucode). */
-       r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF;
+       r = le16_to_cpu(READ_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF;
        i = rxq->read;
 
        /* W/A 9000 device step A0 wrap-around bug */
index 2e3e013ec95acf94eecb843edef305864cf6939b..9ad3f4fe589417ed752e397554575fdc4553fb0e 100644 (file)
@@ -2076,12 +2076,12 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx)
 
        IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", txq_idx);
        txq = trans_pcie->txq[txq_idx];
-       wr_ptr = ACCESS_ONCE(txq->write_ptr);
+       wr_ptr = READ_ONCE(txq->write_ptr);
 
-       while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) &&
+       while (txq->read_ptr != READ_ONCE(txq->write_ptr) &&
               !time_after(jiffies,
                           now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) {
-               u8 write_ptr = ACCESS_ONCE(txq->write_ptr);
+               u8 write_ptr = READ_ONCE(txq->write_ptr);
 
                if (WARN_ONCE(wr_ptr != write_ptr,
                              "WR pointer moved while flushing %d -> %d\n",
@@ -2553,7 +2553,7 @@ static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans,
 
        spin_lock(&rxq->lock);
 
-       r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF;
+       r = le16_to_cpu(READ_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF;
 
        for (i = rxq->read, j = 0;
             i != r && j < allocated_rb_nums;
@@ -2814,7 +2814,7 @@ static struct iwl_trans_dump_data
                /* Dump RBs is supported only for pre-9000 devices (1 queue) */
                struct iwl_rxq *rxq = &trans_pcie->rxq[0];
                /* RBs */
-               num_rbs = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num))
+               num_rbs = le16_to_cpu(READ_ONCE(rxq->rb_stts->closed_rb_num))
                                      & 0x0FFF;
                num_rbs = (num_rbs - rxq->read) & RX_QUEUE_MASK;
                len += num_rbs * (sizeof(*data) +
index 6467ffac9811e77649ab5c5f650b1e2004f5553d..d2b3d6177a556c39530a88666afebf01d996507a 100644 (file)
@@ -1380,7 +1380,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
        mac80211_hwsim_monitor_rx(hw, skb, channel);
 
        /* wmediumd mode check */
-       _portid = ACCESS_ONCE(data->wmediumd);
+       _portid = READ_ONCE(data->wmediumd);
 
        if (_portid)
                return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
@@ -1477,7 +1477,7 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                                    struct ieee80211_channel *chan)
 {
        struct mac80211_hwsim_data *data = hw->priv;
-       u32 _pid = ACCESS_ONCE(data->wmediumd);
+       u32 _pid = READ_ONCE(data->wmediumd);
 
        if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) {
                struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
index 8ce69c83336239dc40f076b3ec3e06f6603fdb64..b793727cd4f74b99713957fec6a2a111746236fa 100644 (file)
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/hwtest.h>
-#include <asm/mac_via.h>
-#include <asm/mac_oss.h>
-
-extern void via_nubus_init(void);
-extern void oss_nubus_init(void);
 
 /* Constants */
 
@@ -841,14 +836,6 @@ static int __init nubus_init(void)
        if (!MACH_IS_MAC)
                return 0;
 
-       /* Initialize the NuBus interrupts */
-       if (oss_present) {
-               oss_nubus_init();
-       } else {
-               via_nubus_init();
-       }
-
-       /* And probe */
        pr_info("NuBus: Scanning NuBus slots.\n");
        nubus_devices = NULL;
        nubus_boards = NULL;
diff --git a/drivers/opp/Kconfig b/drivers/opp/Kconfig
new file mode 100644 (file)
index 0000000..a7fbb93
--- /dev/null
@@ -0,0 +1,13 @@
+config PM_OPP
+       bool
+       select SRCU
+       ---help---
+         SOCs have a standard set of tuples consisting of frequency and
+         voltage pairs that the device will support per voltage domain. This
+         is called Operating Performance Point or OPP. The actual definitions
+         of OPP varies over silicon within the same family of devices.
+
+         OPP layer organizes the data internally using device pointers
+         representing individual voltage domains and provides SOC
+         implementations a ready to use framework to manage OPPs.
+         For more information, read <file:Documentation/power/opp.txt>
similarity index 92%
rename from drivers/base/power/opp/core.c
rename to drivers/opp/core.c
index a6de325306933b57928b8d16d741247e93274102..92fa94a6dcc111ab168056235e2c7f6acdb8a5a3 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/export.h>
+#include <linux/pm_domain.h>
 #include <linux/regulator/consumer.h>
 
 #include "opp.h"
@@ -296,7 +297,7 @@ int dev_pm_opp_get_opp_count(struct device *dev)
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table)) {
                count = PTR_ERR(opp_table);
-               dev_err(dev, "%s: OPP table not found (%d)\n",
+               dev_dbg(dev, "%s: OPP table not found (%d)\n",
                        __func__, count);
                return count;
        }
@@ -535,6 +536,44 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk,
        return ret;
 }
 
+static inline int
+_generic_set_opp_domain(struct device *dev, struct clk *clk,
+                       unsigned long old_freq, unsigned long freq,
+                       unsigned int old_pstate, unsigned int new_pstate)
+{
+       int ret;
+
+       /* Scaling up? Scale domain performance state before frequency */
+       if (freq > old_freq) {
+               ret = dev_pm_genpd_set_performance_state(dev, new_pstate);
+               if (ret)
+                       return ret;
+       }
+
+       ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
+       if (ret)
+               goto restore_domain_state;
+
+       /* Scaling down? Scale domain performance state after frequency */
+       if (freq < old_freq) {
+               ret = dev_pm_genpd_set_performance_state(dev, new_pstate);
+               if (ret)
+                       goto restore_freq;
+       }
+
+       return 0;
+
+restore_freq:
+       if (_generic_set_opp_clk_only(dev, clk, freq, old_freq))
+               dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
+                       __func__, old_freq);
+restore_domain_state:
+       if (freq > old_freq)
+               dev_pm_genpd_set_performance_state(dev, old_pstate);
+
+       return ret;
+}
+
 static int _generic_set_opp_regulator(const struct opp_table *opp_table,
                                      struct device *dev,
                                      unsigned long old_freq,
@@ -653,7 +692,16 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 
        /* Only frequency scaling */
        if (!opp_table->regulators) {
-               ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
+               /*
+                * We don't support devices with both regulator and
+                * domain performance-state for now.
+                */
+               if (opp_table->genpd_performance_state)
+                       ret = _generic_set_opp_domain(dev, clk, old_freq, freq,
+                                                     IS_ERR(old_opp) ? 0 : old_opp->pstate,
+                                                     opp->pstate);
+               else
+                       ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
        } else if (!opp_table->set_opp) {
                ret = _generic_set_opp_regulator(opp_table, dev, old_freq, freq,
                                                 IS_ERR(old_opp) ? NULL : old_opp->supplies,
@@ -988,6 +1036,9 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
                return ret;
        }
 
+       if (opp_table->get_pstate)
+               new_opp->pstate = opp_table->get_pstate(dev, new_opp->rate);
+
        list_add(&new_opp->node, head);
        mutex_unlock(&opp_table->lock);
 
@@ -1476,13 +1527,13 @@ err:
 EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper);
 
 /**
- * dev_pm_opp_register_put_opp_helper() - Releases resources blocked for
+ * dev_pm_opp_unregister_set_opp_helper() - Releases resources blocked for
  *                                        set_opp helper
  * @opp_table: OPP table returned from dev_pm_opp_register_set_opp_helper().
  *
  * Release resources blocked for platform specific set_opp helper.
  */
-void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table)
+void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table)
 {
        if (!opp_table->set_opp) {
                pr_err("%s: Doesn't have custom set_opp helper set\n",
@@ -1497,7 +1548,82 @@ void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table)
 
        dev_pm_opp_put_opp_table(opp_table);
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper);
+EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper);
+
+/**
+ * dev_pm_opp_register_get_pstate_helper() - Register get_pstate() helper.
+ * @dev: Device for which the helper is getting registered.
+ * @get_pstate: Helper.
+ *
+ * TODO: Remove this callback after the same information is available via Device
+ * Tree.
+ *
+ * This allows a platform to initialize the performance states of individual
+ * OPPs for its devices, until we get similar information directly from DT.
+ *
+ * This must be called before the OPPs are initialized for the device.
+ */
+struct opp_table *dev_pm_opp_register_get_pstate_helper(struct device *dev,
+               int (*get_pstate)(struct device *dev, unsigned long rate))
+{
+       struct opp_table *opp_table;
+       int ret;
+
+       if (!get_pstate)
+               return ERR_PTR(-EINVAL);
+
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return ERR_PTR(-ENOMEM);
+
+       /* This should be called before OPPs are initialized */
+       if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+               ret = -EBUSY;
+               goto err;
+       }
+
+       /* Already have genpd_performance_state set */
+       if (WARN_ON(opp_table->genpd_performance_state)) {
+               ret = -EBUSY;
+               goto err;
+       }
+
+       opp_table->genpd_performance_state = true;
+       opp_table->get_pstate = get_pstate;
+
+       return opp_table;
+
+err:
+       dev_pm_opp_put_opp_table(opp_table);
+
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_register_get_pstate_helper);
+
+/**
+ * dev_pm_opp_unregister_get_pstate_helper() - Releases resources blocked for
+ *                                        get_pstate() helper
+ * @opp_table: OPP table returned from dev_pm_opp_register_get_pstate_helper().
+ *
+ * Release resources blocked for platform specific get_pstate() helper.
+ */
+void dev_pm_opp_unregister_get_pstate_helper(struct opp_table *opp_table)
+{
+       if (!opp_table->genpd_performance_state) {
+               pr_err("%s: Doesn't have performance states set\n",
+                      __func__);
+               return;
+       }
+
+       /* Make sure there are no concurrent readers while updating opp_table */
+       WARN_ON(!list_empty(&opp_table->opp_list));
+
+       opp_table->genpd_performance_state = false;
+       opp_table->get_pstate = NULL;
+
+       dev_pm_opp_put_opp_table(opp_table);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_get_pstate_helper);
 
 /**
  * dev_pm_opp_add()  - Add an OPP table from a table definitions
@@ -1706,6 +1832,13 @@ void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev,
                        if (remove_all || !opp->dynamic)
                                dev_pm_opp_put(opp);
                }
+
+               /*
+                * The OPP table is getting removed, drop the performance state
+                * constraints.
+                */
+               if (opp_table->genpd_performance_state)
+                       dev_pm_genpd_set_performance_state(dev, 0);
        } else {
                _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table);
        }
similarity index 97%
rename from drivers/base/power/opp/debugfs.c
rename to drivers/opp/debugfs.c
index 81cf120fcf4338c838218a4f7e2eea3e0af8170b..b03c03576a624fe9c3af1ff09e75443a63fd8f5d 100644 (file)
@@ -41,16 +41,15 @@ static bool opp_debug_create_supplies(struct dev_pm_opp *opp,
 {
        struct dentry *d;
        int i;
-       char *name;
 
        for (i = 0; i < opp_table->regulator_count; i++) {
-               name = kasprintf(GFP_KERNEL, "supply-%d", i);
+               char name[15];
+
+               snprintf(name, sizeof(name), "supply-%d", i);
 
                /* Create per-opp directory */
                d = debugfs_create_dir(name, pdentry);
 
-               kfree(name);
-
                if (!d)
                        return false;
 
@@ -100,6 +99,9 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
        if (!debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend))
                return -ENOMEM;
 
+       if (!debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate))
+               return -ENOMEM;
+
        if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
                return -ENOMEM;
 
similarity index 99%
rename from drivers/base/power/opp/of.c
rename to drivers/opp/of.c
index 0b718886479bd539687e709583543e0e62eea332..cb716aa2f44be9d2cad2ff9d06a0b71a9f4d6b1c 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/device.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/slab.h>
 #include <linux/export.h>
 
@@ -397,6 +397,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
                        dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
                                ret);
                        _dev_pm_opp_remove_table(opp_table, dev, false);
+                       of_node_put(np);
                        goto put_opp_table;
                }
        }
@@ -603,7 +604,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
                if (cpu == cpu_dev->id)
                        continue;
 
-               cpu_np = of_get_cpu_node(cpu, NULL);
+               cpu_np = of_cpu_device_node_get(cpu);
                if (!cpu_np) {
                        dev_err(cpu_dev, "%s: failed to get cpu%d node\n",
                                __func__, cpu);
@@ -613,6 +614,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
 
                /* Get OPP descriptor node */
                tmp_np = _opp_of_get_opp_desc_node(cpu_np);
+               of_node_put(cpu_np);
                if (!tmp_np) {
                        pr_err("%pOF: Couldn't find opp node\n", cpu_np);
                        ret = -ENOENT;
similarity index 95%
rename from drivers/base/power/opp/opp.h
rename to drivers/opp/opp.h
index 166eef99059955ca315126cc1f62a6f239e16616..4d00061648a35468433081011a76f53bc43573a3 100644 (file)
@@ -58,6 +58,7 @@ extern struct list_head opp_tables;
  * @dynamic:   not-created from static DT entries.
  * @turbo:     true if turbo (boost) OPP
  * @suspend:   true if suspend OPP
+ * @pstate: Device's power domain's performance state.
  * @rate:      Frequency in hertz
  * @supplies:  Power supplies voltage/current values
  * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
@@ -76,6 +77,7 @@ struct dev_pm_opp {
        bool dynamic;
        bool turbo;
        bool suspend;
+       unsigned int pstate;
        unsigned long rate;
 
        struct dev_pm_opp_supply *supplies;
@@ -135,8 +137,10 @@ enum opp_table_access {
  * @clk: Device's clock handle
  * @regulators: Supply regulators
  * @regulator_count: Number of power supply regulators
+ * @genpd_performance_state: Device's power domain support performance state.
  * @set_opp: Platform specific set_opp callback
  * @set_opp_data: Data to be passed to set_opp callback
+ * @get_pstate: Platform specific get_pstate callback
  * @dentry:    debugfs dentry pointer of the real device directory (not links).
  * @dentry_name: Name of the real dentry.
  *
@@ -170,9 +174,11 @@ struct opp_table {
        struct clk *clk;
        struct regulator **regulators;
        unsigned int regulator_count;
+       bool genpd_performance_state;
 
        int (*set_opp)(struct dev_pm_set_opp_data *data);
        struct dev_pm_set_opp_data *set_opp_data;
+       int (*get_pstate)(struct device *dev, unsigned long rate);
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *dentry;
index 74cc6dd982d2aaf5313c4647e02f305d4f0702fa..2d1a5c737c6ef53070ff9cacacc805e5d1903599 100644 (file)
@@ -44,10 +44,11 @@ static void parport_ieee1284_wakeup (struct parport *port)
        up (&port->physport->ieee1284.irq);
 }
 
-static struct parport *port_from_cookie[PARPORT_MAX];
-static void timeout_waiting_on_port (unsigned long cookie)
+static void timeout_waiting_on_port (struct timer_list *t)
 {
-       parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
+       struct parport *port = from_timer(port, t, timer);
+
+       parport_ieee1284_wakeup (port);
 }
 
 /**
@@ -69,27 +70,19 @@ static void timeout_waiting_on_port (unsigned long cookie)
 int parport_wait_event (struct parport *port, signed long timeout)
 {
        int ret;
-       struct timer_list timer;
 
        if (!port->physport->cad->timeout)
                /* Zero timeout is special, and we can't down() the
                   semaphore. */
                return 1;
 
-       init_timer_on_stack(&timer);
-       timer.expires = jiffies + timeout;
-       timer.function = timeout_waiting_on_port;
-       port_from_cookie[port->number % PARPORT_MAX] = port;
-       timer.data = port->number;
-
-       add_timer (&timer);
+       timer_setup(&port->timer, timeout_waiting_on_port, 0);
+       mod_timer(&port->timer, jiffies + timeout);
        ret = down_interruptible (&port->physport->ieee1284.irq);
-       if (!del_timer_sync(&timer) && !ret)
+       if (!del_timer_sync(&port->timer) && !ret)
                /* Timed out. */
                ret = 1;
 
-       destroy_timer_on_stack(&timer);
-
        return ret;
 }
 
index 496ed9130600e90c2a78bf1dd815615db7594059..e066071678580271e68da7d962fa3fccfb69ab45 100644 (file)
@@ -1441,6 +1441,8 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
                pci_msi_domain_update_chip_ops(info);
 
        info->flags |= MSI_FLAG_ACTIVATE_EARLY;
+       if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
+               info->flags |= MSI_FLAG_MUST_REACTIVATE;
 
        domain = msi_create_irq_domain(fwnode, info, parent);
        if (!domain)
index 11bd267fc1371acc303795876a6fba0b7725767a..07b8a9b385abcb43506e42625204b0734d26e3d0 100644 (file)
@@ -680,17 +680,13 @@ static int pci_pm_prepare(struct device *dev)
 {
        struct device_driver *drv = dev->driver;
 
-       /*
-        * Devices having power.ignore_children set may still be necessary for
-        * suspending their children in the next phase of device suspend.
-        */
-       if (dev->power.ignore_children)
-               pm_runtime_resume(dev);
-
        if (drv && drv->pm && drv->pm->prepare) {
                int error = drv->pm->prepare(dev);
-               if (error)
+               if (error < 0)
                        return error;
+
+               if (!error && dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_PREPARE))
+                       return 0;
        }
        return pci_dev_keep_suspended(to_pci_dev(dev));
 }
@@ -731,18 +727,25 @@ static int pci_pm_suspend(struct device *dev)
 
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
-               goto Fixup;
+               return 0;
        }
 
        /*
-        * PCI devices suspended at run time need to be resumed at this point,
-        * because in general it is necessary to reconfigure them for system
-        * suspend.  Namely, if the device is supposed to wake up the system
-        * from the sleep state, we may need to reconfigure it for this purpose.
-        * In turn, if the device is not supposed to wake up the system from the
-        * sleep state, we'll have to prevent it from signaling wake-up.
+        * PCI devices suspended at run time may need to be resumed at this
+        * point, because in general it may be necessary to reconfigure them for
+        * system suspend.  Namely, if the device is expected to wake up the
+        * system from the sleep state, it may have to be reconfigured for this
+        * purpose, or if the device is not expected to wake up the system from
+        * the sleep state, it should be prevented from signaling wakeup events
+        * going forward.
+        *
+        * Also if the driver of the device does not indicate that its system
+        * suspend callbacks can cope with runtime-suspended devices, it is
+        * better to resume the device from runtime suspend here.
         */
-       pm_runtime_resume(dev);
+       if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
+           !pci_dev_keep_suspended(pci_dev))
+               pm_runtime_resume(dev);
 
        pci_dev->state_saved = false;
        if (pm->suspend) {
@@ -762,17 +765,27 @@ static int pci_pm_suspend(struct device *dev)
                }
        }
 
- Fixup:
-       pci_fixup_device(pci_fixup_suspend, pci_dev);
-
        return 0;
 }
 
+static int pci_pm_suspend_late(struct device *dev)
+{
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev));
+
+       return pm_generic_suspend_late(dev);
+}
+
 static int pci_pm_suspend_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
 
@@ -805,6 +818,9 @@ static int pci_pm_suspend_noirq(struct device *dev)
                        pci_prepare_to_sleep(pci_dev);
        }
 
+       dev_dbg(dev, "PCI PM: Suspend power state: %s\n",
+               pci_power_name(pci_dev->current_state));
+
        pci_pm_set_unknown_state(pci_dev);
 
        /*
@@ -831,6 +847,14 @@ static int pci_pm_resume_noirq(struct device *dev)
        struct device_driver *drv = dev->driver;
        int error = 0;
 
+       /*
+        * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend
+        * during system suspend, so update their runtime PM status to "active"
+        * as they are going to be put into D0 shortly.
+        */
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               pm_runtime_set_active(dev);
+
        pci_pm_default_resume_early(pci_dev);
 
        if (pci_has_legacy_pm_support(pci_dev))
@@ -873,6 +897,7 @@ static int pci_pm_resume(struct device *dev)
 #else /* !CONFIG_SUSPEND */
 
 #define pci_pm_suspend         NULL
+#define pci_pm_suspend_late    NULL
 #define pci_pm_suspend_noirq   NULL
 #define pci_pm_resume          NULL
 #define pci_pm_resume_noirq    NULL
@@ -907,7 +932,8 @@ static int pci_pm_freeze(struct device *dev)
         * devices should not be touched during freeze/thaw transitions,
         * however.
         */
-       pm_runtime_resume(dev);
+       if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
+               pm_runtime_resume(dev);
 
        pci_dev->state_saved = false;
        if (pm->freeze) {
@@ -919,17 +945,25 @@ static int pci_pm_freeze(struct device *dev)
                        return error;
        }
 
-       if (pcibios_pm_ops.freeze)
-               return pcibios_pm_ops.freeze(dev);
-
        return 0;
 }
 
+static int pci_pm_freeze_late(struct device *dev)
+{
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       return pm_generic_freeze_late(dev);;
+}
+
 static int pci_pm_freeze_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
 
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_FREEZE);
 
@@ -959,6 +993,16 @@ static int pci_pm_thaw_noirq(struct device *dev)
        struct device_driver *drv = dev->driver;
        int error = 0;
 
+       /*
+        * If the device is in runtime suspend, the code below may not work
+        * correctly with it, so skip that code and make the PM core skip all of
+        * the subsequent "thaw" callbacks for the device.
+        */
+       if (dev_pm_smart_suspend_and_suspended(dev)) {
+               dev->power.direct_complete = true;
+               return 0;
+       }
+
        if (pcibios_pm_ops.thaw_noirq) {
                error = pcibios_pm_ops.thaw_noirq(dev);
                if (error)
@@ -983,12 +1027,6 @@ static int pci_pm_thaw(struct device *dev)
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int error = 0;
 
-       if (pcibios_pm_ops.thaw) {
-               error = pcibios_pm_ops.thaw(dev);
-               if (error)
-                       return error;
-       }
-
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_resume(dev);
 
@@ -1014,11 +1052,13 @@ static int pci_pm_poweroff(struct device *dev)
 
        if (!pm) {
                pci_pm_default_suspend(pci_dev);
-               goto Fixup;
+               return 0;
        }
 
        /* The reason to do that is the same as in pci_pm_suspend(). */
-       pm_runtime_resume(dev);
+       if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
+           !pci_dev_keep_suspended(pci_dev))
+               pm_runtime_resume(dev);
 
        pci_dev->state_saved = false;
        if (pm->poweroff) {
@@ -1030,13 +1070,17 @@ static int pci_pm_poweroff(struct device *dev)
                        return error;
        }
 
- Fixup:
-       pci_fixup_device(pci_fixup_suspend, pci_dev);
+       return 0;
+}
 
-       if (pcibios_pm_ops.poweroff)
-               return pcibios_pm_ops.poweroff(dev);
+static int pci_pm_poweroff_late(struct device *dev)
+{
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
 
-       return 0;
+       pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev));
+
+       return pm_generic_poweroff_late(dev);
 }
 
 static int pci_pm_poweroff_noirq(struct device *dev)
@@ -1044,6 +1088,9 @@ static int pci_pm_poweroff_noirq(struct device *dev)
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
 
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
        if (pci_has_legacy_pm_support(to_pci_dev(dev)))
                return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
 
@@ -1085,6 +1132,10 @@ static int pci_pm_restore_noirq(struct device *dev)
        struct device_driver *drv = dev->driver;
        int error = 0;
 
+       /* This is analogous to the pci_pm_resume_noirq() case. */
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               pm_runtime_set_active(dev);
+
        if (pcibios_pm_ops.restore_noirq) {
                error = pcibios_pm_ops.restore_noirq(dev);
                if (error)
@@ -1108,12 +1159,6 @@ static int pci_pm_restore(struct device *dev)
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int error = 0;
 
-       if (pcibios_pm_ops.restore) {
-               error = pcibios_pm_ops.restore(dev);
-               if (error)
-                       return error;
-       }
-
        /*
         * This is necessary for the hibernation error path in which restore is
         * called without restoring the standard config registers of the device.
@@ -1139,10 +1184,12 @@ static int pci_pm_restore(struct device *dev)
 #else /* !CONFIG_HIBERNATE_CALLBACKS */
 
 #define pci_pm_freeze          NULL
+#define pci_pm_freeze_late     NULL
 #define pci_pm_freeze_noirq    NULL
 #define pci_pm_thaw            NULL
 #define pci_pm_thaw_noirq      NULL
 #define pci_pm_poweroff                NULL
+#define pci_pm_poweroff_late   NULL
 #define pci_pm_poweroff_noirq  NULL
 #define pci_pm_restore         NULL
 #define pci_pm_restore_noirq   NULL
@@ -1258,10 +1305,13 @@ static const struct dev_pm_ops pci_dev_pm_ops = {
        .prepare = pci_pm_prepare,
        .complete = pci_pm_complete,
        .suspend = pci_pm_suspend,
+       .suspend_late = pci_pm_suspend_late,
        .resume = pci_pm_resume,
        .freeze = pci_pm_freeze,
+       .freeze_late = pci_pm_freeze_late,
        .thaw = pci_pm_thaw,
        .poweroff = pci_pm_poweroff,
+       .poweroff_late = pci_pm_poweroff_late,
        .restore = pci_pm_restore,
        .suspend_noirq = pci_pm_suspend_noirq,
        .resume_noirq = pci_pm_resume_noirq,
index 6078dfc11b112a88aec1c58eb911de9f996b6644..374f5686e2bc13923a88c2b207b1b51ab651e847 100644 (file)
@@ -2166,8 +2166,7 @@ bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
 
        if (!pm_runtime_suspended(dev)
            || pci_target_state(pci_dev, wakeup) != pci_dev->current_state
-           || platform_pci_need_resume(pci_dev)
-           || (pci_dev->dev_flags & PCI_DEV_FLAGS_NEEDS_RESUME))
+           || platform_pci_need_resume(pci_dev))
                return false;
 
        /*
index 0802e0bc7d0c60dc4c0bfab927f3dd4fc8cfdb4b..16f573173471a89afac887d1df1a8ba118e95a46 100644 (file)
@@ -263,12 +263,12 @@ static int bcm63xx_pcmcia_get_status(struct pcmcia_socket *sock,
 /*
  * socket polling timer callback
  */
-static void bcm63xx_pcmcia_poll(unsigned long data)
+static void bcm63xx_pcmcia_poll(struct timer_list *t)
 {
        struct bcm63xx_pcmcia_socket *skt;
        unsigned int stat, events;
 
-       skt = (struct bcm63xx_pcmcia_socket *)data;
+       skt = from_timer(skt, t, timer);
 
        spin_lock_bh(&skt->lock);
 
@@ -392,7 +392,7 @@ static int bcm63xx_drv_pcmcia_probe(struct platform_device *pdev)
        sock->map_size = resource_size(skt->common_res);
 
        /* initialize polling timer */
-       setup_timer(&skt->timer, bcm63xx_pcmcia_poll, (unsigned long)skt);
+       timer_setup(&skt->timer, bcm63xx_pcmcia_poll, 0);
 
        /* initialize  pcmcia  control register,  drive  VS[12] to  0,
         * leave CB IDSEL to the old  value since it is set by the PCI
index 8b0923fd76c604322bd20fb482958a320e77ff36..00a296d431bab910be192d663660c99d221ce4e4 100644 (file)
@@ -86,9 +86,9 @@ static int bfin_cf_ss_init(struct pcmcia_socket *s)
 }
 
 /* the timer is primarily to kick this socket's pccardd */
-static void bfin_cf_timer(unsigned long _cf)
+static void bfin_cf_timer(struct timer_list *t)
 {
-       struct bfin_cf_socket *cf = (void *)_cf;
+       struct bfin_cf_socket *cf = from_timer(cf, t, timer);
        unsigned short present = bfin_cf_present(cf->cd_pfx);
 
        if (present != cf->present) {
@@ -227,7 +227,7 @@ static int bfin_cf_probe(struct platform_device *pdev)
 
        cf->cd_pfx = cd_pfx;
 
-       setup_timer(&cf->timer, bfin_cf_timer, (unsigned long)cf);
+       timer_setup(&cf->timer, bfin_cf_timer, 0);
 
        cf->pdev = pdev;
        platform_set_drvdata(pdev, cf);
index fb38cc01859f15ac3519e8310391bde330033156..891ccea2cccb0a7b455a9ab963df2b43c38ed93e 100644 (file)
@@ -875,7 +875,7 @@ static irqreturn_t pcic_interrupt(int irq, void *dev)
     return IRQ_RETVAL(handled);
 } /* pcic_interrupt */
 
-static void pcic_interrupt_wrapper(u_long data)
+static void pcic_interrupt_wrapper(struct timer_list *unused)
 {
     pcic_interrupt(0, NULL);
     poll_timer.expires = jiffies + poll_interval;
@@ -1289,9 +1289,7 @@ static int __init init_i82365(void)
 
     /* Finally, schedule a polling interrupt */
     if (poll_interval != 0) {
-       poll_timer.function = pcic_interrupt_wrapper;
-       poll_timer.data = 0;
-       init_timer(&poll_timer);
+       timer_setup(&poll_timer, pcic_interrupt_wrapper, 0);
        poll_timer.expires = jiffies + poll_interval;
        add_timer(&poll_timer);
     }
index 4e2f501e55486dbee297865f03148e5b46d09d91..c2a17a79f0b2ff86fa1fc5cd29a2ce49289bc669 100644 (file)
@@ -80,9 +80,9 @@ static int omap_cf_ss_init(struct pcmcia_socket *s)
 }
 
 /* the timer is primarily to kick this socket's pccardd */
-static void omap_cf_timer(unsigned long _cf)
+static void omap_cf_timer(struct timer_list *t)
 {
-       struct omap_cf_socket   *cf = (void *) _cf;
+       struct omap_cf_socket   *cf = from_timer(cf, t, timer);
        unsigned                present = omap_cf_present();
 
        if (present != cf->present) {
@@ -102,7 +102,9 @@ static void omap_cf_timer(unsigned long _cf)
  */
 static irqreturn_t omap_cf_irq(int irq, void *_cf)
 {
-       omap_cf_timer((unsigned long)_cf);
+       struct omap_cf_socket *cf = (struct omap_cf_socket *)_cf;
+
+       omap_cf_timer(&cf->timer);
        return IRQ_HANDLED;
 }
 
@@ -220,7 +222,7 @@ static int __init omap_cf_probe(struct platform_device *pdev)
        cf = kzalloc(sizeof *cf, GFP_KERNEL);
        if (!cf)
                return -ENOMEM;
-       setup_timer(&cf->timer, omap_cf_timer, (unsigned long)cf);
+       timer_setup(&cf->timer, omap_cf_timer, 0);
 
        cf->pdev = pdev;
        platform_set_drvdata(pdev, cf);
index 0f70b4d58f9e7c2d8bb2b9b6c0dc00d2dca3f308..959ae3e65ef8b2ae902141eb068865849e0deaad 100644 (file)
@@ -234,9 +234,9 @@ static irqreturn_t pd6729_interrupt(int irq, void *dev)
 
 /* socket functions */
 
-static void pd6729_interrupt_wrapper(unsigned long data)
+static void pd6729_interrupt_wrapper(struct timer_list *t)
 {
-       struct pd6729_socket *socket = (struct pd6729_socket *) data;
+       struct pd6729_socket *socket = from_timer(socket, t, poll_timer);
 
        pd6729_interrupt(0, (void *)socket);
        mod_timer(&socket->poll_timer, jiffies + HZ);
@@ -707,8 +707,7 @@ static int pd6729_pci_probe(struct pci_dev *dev,
                }
        } else {
                /* poll Card status change */
-               setup_timer(&socket->poll_timer, pd6729_interrupt_wrapper,
-                           (unsigned long)socket);
+               timer_setup(&socket->poll_timer, pd6729_interrupt_wrapper, 0);
                mod_timer(&socket->poll_timer, jiffies + HZ);
        }
 
index b6b316de055c7129648904cbdae92cafb593e8dd..764650eb8897995a55ccc7dc3aaf20c210b53199 100644 (file)
@@ -456,9 +456,9 @@ static void soc_common_check_status(struct soc_pcmcia_socket *skt)
 }
 
 /* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
-static void soc_common_pcmcia_poll_event(unsigned long dummy)
+static void soc_common_pcmcia_poll_event(struct timer_list *t)
 {
-       struct soc_pcmcia_socket *skt = (struct soc_pcmcia_socket *)dummy;
+       struct soc_pcmcia_socket *skt = from_timer(skt, t, poll_timer);
        debug(skt, 4, "polling for events\n");
 
        mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD);
@@ -794,8 +794,7 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
 
        skt->cs_state = dead_socket;
 
-       setup_timer(&skt->poll_timer, soc_common_pcmcia_poll_event,
-                   (unsigned long)skt);
+       timer_setup(&skt->poll_timer, soc_common_pcmcia_poll_event, 0);
        skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
 
        ret = request_resource(&iomem_resource, &skt->res_skt);
index a1ac72d51d707d816a15130cccdb45549424e098..1a0e3f0987599d8a8b6415ac31dac40bc4bab8a1 100644 (file)
@@ -98,7 +98,7 @@ module_param(cycle_time, int, 0444);
 /*====================================================================*/
 
 static irqreturn_t tcic_interrupt(int irq, void *dev);
-static void tcic_timer(u_long data);
+static void tcic_timer(struct timer_list *unused);
 static struct pccard_operations tcic_operations;
 
 struct tcic_socket {
@@ -435,9 +435,7 @@ static int __init init_tcic(void)
     }
     
     /* Set up polling */
-    poll_timer.function = &tcic_timer;
-    poll_timer.data = 0;
-    init_timer(&poll_timer);
+    timer_setup(&poll_timer, &tcic_timer, 0);
 
     /* Build interrupt mask */
     printk(KERN_CONT ", %d sockets\n", sockets);
@@ -583,7 +581,7 @@ static irqreturn_t tcic_interrupt(int irq, void *dev)
     return IRQ_HANDLED;
 } /* tcic_interrupt */
 
-static void tcic_timer(u_long data)
+static void tcic_timer(struct timer_list *unused)
 {
     pr_debug("tcic_timer()\n");
     tcic_timer_pending = 0;
index 5d6d9b1549bc4fa345a613da000e6efc1ea01b91..ab3da2262f0fc89f7b65fe898d6efa5bd3113d8f 100644 (file)
@@ -534,9 +534,9 @@ static irqreturn_t yenta_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void yenta_interrupt_wrapper(unsigned long data)
+static void yenta_interrupt_wrapper(struct timer_list *t)
 {
-       struct yenta_socket *socket = (struct yenta_socket *) data;
+       struct yenta_socket *socket = from_timer(socket, t, poll_timer);
 
        yenta_interrupt(0, (void *)socket);
        socket->poll_timer.expires = jiffies + HZ;
@@ -1233,8 +1233,7 @@ static int yenta_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, IRQF_SHARED, "yenta", socket)) {
                /* No IRQ or request_irq failed. Poll */
                socket->cb_irq = 0; /* But zero is a valid IRQ number. */
-               setup_timer(&socket->poll_timer, yenta_interrupt_wrapper,
-                           (unsigned long)socket);
+               timer_setup(&socket->poll_timer, yenta_interrupt_wrapper, 0);
                mod_timer(&socket->poll_timer, jiffies + HZ);
                dev_info(&dev->dev,
                         "no PCI IRQ, CardBus support disabled for this socket.\n");
index 50299ad966590e8ae0ce2813d1f803c790c6ce51..02b66588cac638fc2525655c1a3f75054ae26e60 100644 (file)
@@ -289,13 +289,14 @@ static int stm32_gpio_domain_translate(struct irq_domain *d,
        return 0;
 }
 
-static void stm32_gpio_domain_activate(struct irq_domain *d,
-                                      struct irq_data *irq_data)
+static int stm32_gpio_domain_activate(struct irq_domain *d,
+                                     struct irq_data *irq_data, bool early)
 {
        struct stm32_gpio_bank *bank = d->host_data;
        struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
 
        regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_nr);
+       return 0;
 }
 
 static int stm32_gpio_domain_alloc(struct irq_domain *d,
index 974fd684bab2c74400f8904fb557a5ac21ac9f26..89bf4d6cb4863916e3f7200adf0cfa2f79c15036 100644 (file)
@@ -355,7 +355,7 @@ int sr_configure_errgen(struct omap_sr *sr)
        u8 senp_shift, senn_shift;
 
        if (!sr) {
-               pr_warn("%s: NULL omap_sr from %pF\n",
+               pr_warn("%s: NULL omap_sr from %pS\n",
                        __func__, (void *)_RET_IP_);
                return -EINVAL;
        }
@@ -422,7 +422,7 @@ int sr_disable_errgen(struct omap_sr *sr)
        u32 vpboundint_en, vpboundint_st;
 
        if (!sr) {
-               pr_warn("%s: NULL omap_sr from %pF\n",
+               pr_warn("%s: NULL omap_sr from %pS\n",
                        __func__, (void *)_RET_IP_);
                return -EINVAL;
        }
@@ -477,7 +477,7 @@ int sr_configure_minmax(struct omap_sr *sr)
        u8 senp_shift, senn_shift;
 
        if (!sr) {
-               pr_warn("%s: NULL omap_sr from %pF\n",
+               pr_warn("%s: NULL omap_sr from %pS\n",
                        __func__, (void *)_RET_IP_);
                return -EINVAL;
        }
@@ -562,7 +562,7 @@ int sr_enable(struct omap_sr *sr, unsigned long volt)
        int ret;
 
        if (!sr) {
-               pr_warn("%s: NULL omap_sr from %pF\n",
+               pr_warn("%s: NULL omap_sr from %pS\n",
                        __func__, (void *)_RET_IP_);
                return -EINVAL;
        }
@@ -614,7 +614,7 @@ int sr_enable(struct omap_sr *sr, unsigned long volt)
 void sr_disable(struct omap_sr *sr)
 {
        if (!sr) {
-               pr_warn("%s: NULL omap_sr from %pF\n",
+               pr_warn("%s: NULL omap_sr from %pS\n",
                        __func__, (void *)_RET_IP_);
                return;
        }
index adbf1a9e089eec7f8292f27047137e39f777063b..ca44e6977cf2f7d7c58563e457cdcf3cb4b507ba 100644 (file)
@@ -169,11 +169,9 @@ static void cec_mod_timer(struct timer_list *t, unsigned long interval)
        mod_timer(t, round_jiffies(iv));
 }
 
-static void cec_timer_fn(unsigned long data)
+static void cec_timer_fn(struct timer_list *unused)
 {
-       struct ce_array *ca = (struct ce_array *)data;
-
-       do_spring_cleaning(ca);
+       do_spring_cleaning(&ce_arr);
 
        cec_mod_timer(&cec_timer, timer_interval);
 }
@@ -510,7 +508,7 @@ void __init cec_init(void)
        if (create_debugfs_nodes())
                return;
 
-       setup_timer(&cec_timer, cec_timer_fn, (unsigned long)&ce_arr);
+       timer_setup(&cec_timer, cec_timer_fn, 0);
        cec_mod_timer(&cec_timer, CEC_TIMER_DEFAULT_INTERVAL);
 
        pr_info("Correctable Errors collector initialized.\n");
index 0fd6195601baa6f0f53c858a532a6b6b37999c4f..96cd55f9e3c5ca77d4a64e27c45d755b3ef23743 100644 (file)
@@ -244,7 +244,7 @@ config REGULATOR_DA9210
          interface.
 
 config REGULATOR_DA9211
-       tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214/DA9215 regulator"
+       tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/DA9215/DA9225 regulator"
        depends on I2C
        select REGMAP_I2C
        help
index 376a99b7cf5da150794cbb3b2f1c72078985166c..181622b2813d94a963031f31c246944a52c881fb 100644 (file)
@@ -244,6 +244,7 @@ static const struct regulator_desc axp22x_drivevbus_regulator = {
        .ops            = &axp20x_ops_sw,
 };
 
+/* DCDC ranges shared with AXP813 */
 static const struct regulator_linear_range axp803_dcdc234_ranges[] = {
        REGULATOR_LINEAR_RANGE(500000, 0x0, 0x46, 10000),
        REGULATOR_LINEAR_RANGE(1220000, 0x47, 0x4b, 20000),
@@ -426,6 +427,69 @@ static const struct regulator_desc axp809_regulators[] = {
        AXP_DESC_SW(AXP809, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(6)),
 };
 
+static const struct regulator_desc axp813_regulators[] = {
+       AXP_DESC(AXP813, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
+                AXP803_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(0)),
+       AXP_DESC_RANGES(AXP813, DCDC2, "dcdc2", "vin2", axp803_dcdc234_ranges,
+                       76, AXP803_DCDC2_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
+                       BIT(1)),
+       AXP_DESC_RANGES(AXP813, DCDC3, "dcdc3", "vin3", axp803_dcdc234_ranges,
+                       76, AXP803_DCDC3_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
+                       BIT(2)),
+       AXP_DESC_RANGES(AXP813, DCDC4, "dcdc4", "vin4", axp803_dcdc234_ranges,
+                       76, AXP803_DCDC4_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
+                       BIT(3)),
+       AXP_DESC_RANGES(AXP813, DCDC5, "dcdc5", "vin5", axp803_dcdc5_ranges,
+                       68, AXP803_DCDC5_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
+                       BIT(4)),
+       AXP_DESC_RANGES(AXP813, DCDC6, "dcdc6", "vin6", axp803_dcdc6_ranges,
+                       72, AXP803_DCDC6_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
+                       BIT(5)),
+       AXP_DESC_RANGES(AXP813, DCDC7, "dcdc7", "vin7", axp803_dcdc6_ranges,
+                       72, AXP813_DCDC7_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
+                       BIT(6)),
+       AXP_DESC(AXP813, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
+                AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(5)),
+       AXP_DESC(AXP813, ALDO2, "aldo2", "aldoin", 700, 3300, 100,
+                AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(6)),
+       AXP_DESC(AXP813, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
+                AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)),
+       AXP_DESC(AXP813, DLDO1, "dldo1", "dldoin", 700, 3300, 100,
+                AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)),
+       AXP_DESC_RANGES(AXP813, DLDO2, "dldo2", "dldoin", axp803_dldo2_ranges,
+                       32, AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
+                       BIT(4)),
+       AXP_DESC(AXP813, DLDO3, "dldo3", "dldoin", 700, 3300, 100,
+                AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
+       AXP_DESC(AXP813, DLDO4, "dldo4", "dldoin", 700, 3300, 100,
+                AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)),
+       AXP_DESC(AXP813, ELDO1, "eldo1", "eldoin", 700, 1900, 50,
+                AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)),
+       AXP_DESC(AXP813, ELDO2, "eldo2", "eldoin", 700, 1900, 50,
+                AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
+       AXP_DESC(AXP813, ELDO3, "eldo3", "eldoin", 700, 1900, 50,
+                AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
+       /* to do / check ... */
+       AXP_DESC(AXP813, FLDO1, "fldo1", "fldoin", 700, 1450, 50,
+                AXP803_FLDO1_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(2)),
+       AXP_DESC(AXP813, FLDO2, "fldo2", "fldoin", 700, 1450, 50,
+                AXP803_FLDO2_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(3)),
+       /*
+        * TODO: FLDO3 = {DCDC5, FLDOIN} / 2
+        *
+        * This means FLDO3 effectively switches supplies at runtime,
+        * something the regulator subsystem does not support.
+        */
+       AXP_DESC_FIXED(AXP813, RTC_LDO, "rtc-ldo", "ips", 1800),
+       AXP_DESC_IO(AXP813, LDO_IO0, "ldo-io0", "ips", 700, 3300, 100,
+                   AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
+                   AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
+       AXP_DESC_IO(AXP813, LDO_IO1, "ldo-io1", "ips", 700, 3300, 100,
+                   AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
+                   AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
+       AXP_DESC_SW(AXP813, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(7)),
+};
+
 static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
 {
        struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
@@ -441,9 +505,10 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
                step = 75;
                break;
        case AXP803_ID:
+       case AXP813_ID:
                /*
-                * AXP803 DCDC work frequency setting has the same range and
-                * step as AXP22X, but at a different register.
+                * AXP803/AXP813 DCDC work frequency setting has the same
+                * range and step as AXP22X, but at a different register.
                 * Fall through to the check below.
                 * (See include/linux/mfd/axp20x.h)
                 */
@@ -561,6 +626,14 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
                workmode <<= id - AXP803_DCDC1;
                break;
 
+       case AXP813_ID:
+               if (id < AXP813_DCDC1 || id > AXP813_DCDC7)
+                       return -EINVAL;
+
+               mask = AXP22X_WORKMODE_DCDCX_MASK(id - AXP813_DCDC1);
+               workmode <<= id - AXP813_DCDC1;
+               break;
+
        default:
                /* should not happen */
                WARN_ON(1);
@@ -579,11 +652,12 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
        u32 reg = 0;
 
        /*
-        * Currently in our supported AXP variants, only AXP803 and AXP806
-        * have polyphase regulators.
+        * Currently in our supported AXP variants, only AXP803, AXP806,
+        * and AXP813 have polyphase regulators.
         */
        switch (axp20x->variant) {
        case AXP803_ID:
+       case AXP813_ID:
                regmap_read(axp20x->regmap, AXP803_POLYPHASE_CTRL, &reg);
 
                switch (id) {
@@ -656,6 +730,12 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
                regulators = axp809_regulators;
                nregulators = AXP809_REG_ID_MAX;
                break;
+       case AXP813_ID:
+               regulators = axp813_regulators;
+               nregulators = AXP813_REG_ID_MAX;
+               drivevbus = of_property_read_bool(pdev->dev.parent->of_node,
+                                                 "x-powers,drive-vbus-en");
+               break;
        default:
                dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n",
                        axp20x->variant);
@@ -677,6 +757,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
                if (axp20x_is_polyphase_slave(axp20x, i))
                        continue;
 
+               /* Support for AXP813's FLDO3 is not implemented */
+               if (axp20x->variant == AXP813_ID && i == AXP813_FLDO3)
+                       continue;
+
                /*
                 * Regulators DC1SW and DC5LDO are connected internally,
                 * so we have to handle their supply names separately.
index aa47280efd323a62f1f5b416c82e9a2d8edfa22e..9b8f476177249dac41a83e6e3121aaabd9f51f3d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * da9211-regulator.c - Regulator device driver for DA9211/DA9212
- * /DA9213/DA9214/DA9215
+ * /DA9213/DA9223/DA9214/DA9224/DA9215/DA9225
  * Copyright (C) 2015  Dialog Semiconductor Ltd.
  *
  * This library is free software; you can redistribute it and/or
@@ -496,8 +496,11 @@ static const struct i2c_device_id da9211_i2c_id[] = {
        {"da9211", DA9211},
        {"da9212", DA9212},
        {"da9213", DA9213},
+       {"da9223", DA9223},
        {"da9214", DA9214},
+       {"da9224", DA9224},
        {"da9215", DA9215},
+       {"da9225", DA9225},
        {},
 };
 MODULE_DEVICE_TABLE(i2c, da9211_i2c_id);
@@ -507,8 +510,11 @@ static const struct of_device_id da9211_dt_ids[] = {
        { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] },
        { .compatible = "dlg,da9212", .data = &da9211_i2c_id[1] },
        { .compatible = "dlg,da9213", .data = &da9211_i2c_id[2] },
-       { .compatible = "dlg,da9214", .data = &da9211_i2c_id[3] },
-       { .compatible = "dlg,da9215", .data = &da9211_i2c_id[4] },
+       { .compatible = "dlg,da9223", .data = &da9211_i2c_id[3] },
+       { .compatible = "dlg,da9214", .data = &da9211_i2c_id[4] },
+       { .compatible = "dlg,da9224", .data = &da9211_i2c_id[5] },
+       { .compatible = "dlg,da9215", .data = &da9211_i2c_id[6] },
+       { .compatible = "dlg,da9225", .data = &da9211_i2c_id[7] },
        {},
 };
 MODULE_DEVICE_TABLE(of, da9211_dt_ids);
@@ -526,5 +532,5 @@ static struct i2c_driver da9211_regulator_driver = {
 module_i2c_driver(da9211_regulator_driver);
 
 MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
-MODULE_DESCRIPTION("DA9211/DA9212/DA9213/DA9214/DA9215 regulator driver");
+MODULE_DESCRIPTION("DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/DA9215/DA9225 regulator driver");
 MODULE_LICENSE("GPL");
index b841bbf330cc3a9e25ca91c1012149be7803830d..2cb32aab4f825163b19236974461bda367d3b0ed 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * da9211-regulator.h - Regulator definitions for DA9211/DA9212
- * /DA9213/DA9214/DA9215
+ * /DA9213/DA9223/DA9214/DA9224/DA9215/DA9225
  * Copyright (C) 2015  Dialog Semiconductor Ltd.
  *
  * This program is free software; you can redistribute it and/or
index 0cb76ba29e84303b9eaf1e32a2c7b81445a32935..8f782d22fdbef61d4566c9bc63bc6120be461cbe 100644 (file)
@@ -34,6 +34,8 @@ struct pbias_reg_info {
        u32 vmode;
        unsigned int enable_time;
        char *name;
+       const unsigned int *pbias_volt_table;
+       int n_voltages;
 };
 
 struct pbias_regulator_data {
@@ -49,11 +51,16 @@ struct pbias_of_data {
        unsigned int offset;
 };
 
-static const unsigned int pbias_volt_table[] = {
+static const unsigned int pbias_volt_table_3_0V[] = {
        1800000,
        3000000
 };
 
+static const unsigned int pbias_volt_table_3_3V[] = {
+       1800000,
+       3300000
+};
+
 static const struct regulator_ops pbias_regulator_voltage_ops = {
        .list_voltage = regulator_list_voltage_table,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -69,6 +76,8 @@ static const struct pbias_reg_info pbias_mmc_omap2430 = {
        .vmode = BIT(0),
        .disable_val = 0,
        .enable_time = 100,
+       .pbias_volt_table = pbias_volt_table_3_0V,
+       .n_voltages = 2,
        .name = "pbias_mmc_omap2430"
 };
 
@@ -77,6 +86,8 @@ static const struct pbias_reg_info pbias_sim_omap3 = {
        .enable_mask = BIT(9),
        .vmode = BIT(8),
        .enable_time = 100,
+       .pbias_volt_table = pbias_volt_table_3_0V,
+       .n_voltages = 2,
        .name = "pbias_sim_omap3"
 };
 
@@ -86,6 +97,8 @@ static const struct pbias_reg_info pbias_mmc_omap4 = {
        .disable_val = BIT(25),
        .vmode = BIT(21),
        .enable_time = 100,
+       .pbias_volt_table = pbias_volt_table_3_0V,
+       .n_voltages = 2,
        .name = "pbias_mmc_omap4"
 };
 
@@ -95,6 +108,8 @@ static const struct pbias_reg_info pbias_mmc_omap5 = {
        .disable_val = BIT(25),
        .vmode = BIT(21),
        .enable_time = 100,
+       .pbias_volt_table = pbias_volt_table_3_3V,
+       .n_voltages = 2,
        .name = "pbias_mmc_omap5"
 };
 
@@ -199,8 +214,8 @@ static int pbias_regulator_probe(struct platform_device *pdev)
                drvdata[data_idx].desc.owner = THIS_MODULE;
                drvdata[data_idx].desc.type = REGULATOR_VOLTAGE;
                drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops;
-               drvdata[data_idx].desc.volt_table = pbias_volt_table;
-               drvdata[data_idx].desc.n_voltages = 2;
+               drvdata[data_idx].desc.volt_table = info->pbias_volt_table;
+               drvdata[data_idx].desc.n_voltages = info->n_voltages;
                drvdata[data_idx].desc.enable_time = info->enable_time;
                drvdata[data_idx].desc.vsel_reg = offset;
                drvdata[data_idx].desc.vsel_mask = info->vmode;
index 16c5f84e06a7590cac829f611f5d712baaab0a44..0241ada47d04bce724e3baebfa7a88dd520cca90 100644 (file)
@@ -593,13 +593,20 @@ static int spmi_sw_selector_to_hw(struct spmi_regulator *vreg,
                                  u8 *voltage_sel)
 {
        const struct spmi_voltage_range *range, *end;
+       unsigned offset;
 
        range = vreg->set_points->range;
        end = range + vreg->set_points->count;
 
        for (; range < end; range++) {
                if (selector < range->n_voltages) {
-                       *voltage_sel = selector;
+                       /*
+                        * hardware selectors between set point min and real
+                        * min are invalid so we ignore them
+                        */
+                       offset = range->set_point_min_uV - range->min_uV;
+                       offset /= range->step_uV;
+                       *voltage_sel = selector + offset;
                        *range_sel = range->range_sel;
                        return 0;
                }
@@ -613,15 +620,35 @@ static int spmi_sw_selector_to_hw(struct spmi_regulator *vreg,
 static int spmi_hw_selector_to_sw(struct spmi_regulator *vreg, u8 hw_sel,
                                  const struct spmi_voltage_range *range)
 {
-       int sw_sel = hw_sel;
+       unsigned sw_sel = 0;
+       unsigned offset, max_hw_sel;
        const struct spmi_voltage_range *r = vreg->set_points->range;
-
-       while (r != range) {
+       const struct spmi_voltage_range *end = r + vreg->set_points->count;
+
+       for (; r < end; r++) {
+               if (r == range && range->n_voltages) {
+                       /*
+                        * hardware selectors between set point min and real
+                        * min and between set point max and real max are
+                        * invalid so we return an error if they're
+                        * programmed into the hardware
+                        */
+                       offset = range->set_point_min_uV - range->min_uV;
+                       offset /= range->step_uV;
+                       if (hw_sel < offset)
+                               return -EINVAL;
+
+                       max_hw_sel = range->set_point_max_uV - range->min_uV;
+                       max_hw_sel /= range->step_uV;
+                       if (hw_sel > max_hw_sel)
+                               return -EINVAL;
+
+                       return sw_sel + hw_sel - offset;
+               }
                sw_sel += r->n_voltages;
-               r++;
        }
 
-       return sw_sel;
+       return -EINVAL;
 }
 
 static const struct spmi_voltage_range *
@@ -1619,11 +1646,20 @@ static const struct spmi_regulator_data pm8994_regulators[] = {
        { }
 };
 
+static const struct spmi_regulator_data pmi8994_regulators[] = {
+       { "s1", 0x1400, "vdd_s1", },
+       { "s2", 0x1700, "vdd_s2", },
+       { "s3", 0x1a00, "vdd_s3", },
+       { "l1", 0x4000, "vdd_l1", },
+        { }
+};
+
 static const struct of_device_id qcom_spmi_regulator_match[] = {
        { .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators },
        { .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators },
        { .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators },
        { .compatible = "qcom,pm8994-regulators", .data = &pm8994_regulators },
+       { .compatible = "qcom,pmi8994-regulators", .data = &pmi8994_regulators },
        { }
 };
 MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match);
index 9aafbb03482d735fcc55bdfab3df83249900a024..bc489958fed7537ffd6bbb559796b8f95f5d39a4 100644 (file)
@@ -154,7 +154,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev)
 
        if (!tps->strobes[rid]) {
                if (rid == TPS65218_DCDC_3)
-                       tps->info[rid]->strobe = 3;
+                       tps->strobes[rid] = 3;
                else
                        return -EINVAL;
        }
index 2ed970d61da140c23a266e43a8b3b6b0eae8914d..722d683e0b0f5fd3f024d1da7b65ac61e42320b0 100644 (file)
@@ -161,6 +161,9 @@ static struct rtc_device *rtc_allocate_device(void)
 
        device_initialize(&rtc->dev);
 
+       /* Drivers can revise this default after allocating the device. */
+       rtc->set_offset_nsec =  NSEC_PER_SEC / 2;
+
        rtc->irq_freq = 1;
        rtc->max_user_freq = 64;
        rtc->dev.class = rtc_class;
index b4a68ffcd06bb876231f2893de69f30a8fe854d9..0c177647ea6c71c00d5df725beea9b83c7e4e79e 100644 (file)
@@ -10,6 +10,7 @@
 /**
  * rtc_set_ntp_time - Save NTP synchronized time to the RTC
  * @now: Current time of day
+ * @target_nsec: pointer for desired now->tv_nsec value
  *
  * Replacement for the NTP platform function update_persistent_clock64
  * that stores time for later retrieval by rtc_hctosys.
  * possible at all, and various other -errno for specific temporary failure
  * cases.
  *
+ * -EPROTO is returned if now.tv_nsec is not close enough to *target_nsec.
+ (
  * If temporary failure is indicated the caller should try again 'soon'
  */
-int rtc_set_ntp_time(struct timespec64 now)
+int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec)
 {
        struct rtc_device *rtc;
        struct rtc_time tm;
+       struct timespec64 to_set;
        int err = -ENODEV;
-
-       if (now.tv_nsec < (NSEC_PER_SEC >> 1))
-               rtc_time64_to_tm(now.tv_sec, &tm);
-       else
-               rtc_time64_to_tm(now.tv_sec + 1, &tm);
+       bool ok;
 
        rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
-       if (rtc) {
-               /* rtc_hctosys exclusively uses UTC, so we call set_time here,
-                * not set_mmss. */
-               if (rtc->ops &&
-                   (rtc->ops->set_time ||
-                    rtc->ops->set_mmss64 ||
-                    rtc->ops->set_mmss))
-                       err = rtc_set_time(rtc, &tm);
-               rtc_class_close(rtc);
+       if (!rtc)
+               goto out_err;
+
+       if (!rtc->ops || (!rtc->ops->set_time && !rtc->ops->set_mmss64 &&
+                         !rtc->ops->set_mmss))
+               goto out_close;
+
+       /* Compute the value of tv_nsec we require the caller to supply in
+        * now.tv_nsec.  This is the value such that (now +
+        * set_offset_nsec).tv_nsec == 0.
+        */
+       set_normalized_timespec64(&to_set, 0, -rtc->set_offset_nsec);
+       *target_nsec = to_set.tv_nsec;
+
+       /* The ntp code must call this with the correct value in tv_nsec, if
+        * it does not we update target_nsec and return EPROTO to make the ntp
+        * code try again later.
+        */
+       ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now);
+       if (!ok) {
+               err = -EPROTO;
+               goto out_close;
        }
 
+       rtc_time64_to_tm(to_set.tv_sec, &tm);
+
+       /* rtc_hctosys exclusively uses UTC, so we call set_time here, not
+        * set_mmss.
+        */
+       err = rtc_set_time(rtc, &tm);
+
+out_close:
+       rtc_class_close(rtc);
+out_err:
        return err;
 }
index 4630782b545657443950c9377fc0f0e5cf37543e..a7917d473774bbf34874a147d7dd8960d87d1aa8 100644 (file)
@@ -296,7 +296,7 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device,
 {
        struct dasd_ccw_req *temp_cqr;
        int data_size;
-       struct timeval tv;
+       struct timespec64 ts;
        struct dasd_eer_header header;
        unsigned long flags;
        struct eerbuffer *eerb;
@@ -310,9 +310,9 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device,
 
        header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
        header.trigger = trigger;
-       do_gettimeofday(&tv);
-       header.tv_sec = tv.tv_sec;
-       header.tv_usec = tv.tv_usec;
+       ktime_get_real_ts64(&ts);
+       header.tv_sec = ts.tv_sec;
+       header.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
        strncpy(header.busid, dev_name(&device->cdev->dev),
                DASD_EER_BUSID_SIZE);
 
@@ -340,7 +340,7 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device,
 {
        int data_size;
        int snss_rc;
-       struct timeval tv;
+       struct timespec64 ts;
        struct dasd_eer_header header;
        unsigned long flags;
        struct eerbuffer *eerb;
@@ -353,9 +353,9 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device,
 
        header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
        header.trigger = DASD_EER_STATECHANGE;
-       do_gettimeofday(&tv);
-       header.tv_sec = tv.tv_sec;
-       header.tv_usec = tv.tv_usec;
+       ktime_get_real_ts64(&ts);
+       header.tv_sec = ts.tv_sec;
+       header.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
        strncpy(header.busid, dev_name(&device->cdev->dev),
                DASD_EER_BUSID_SIZE);
 
index e94080a5196f62e2a4cbc073ce196dbd73150ec0..b095a23bcc0c133c44f51b366aca53f790891461 100644 (file)
@@ -96,14 +96,6 @@ do { \
                            d_data); \
 } while(0)
 
-#define DBF_DEV_EXC(d_level, d_device, d_str, d_data...) \
-do { \
-       debug_sprintf_exception(d_device->debug_area, \
-                               d_level, \
-                               d_str "\n", \
-                               d_data); \
-} while(0)
-
 #define DBF_EVENT(d_level, d_str, d_data...)\
 do { \
        debug_sprintf_event(dasd_debug_area, \
@@ -122,14 +114,6 @@ do { \
                            __dev_id.ssid, __dev_id.devno, d_data);     \
 } while (0)
 
-#define DBF_EXC(d_level, d_str, d_data...)\
-do { \
-       debug_sprintf_exception(dasd_debug_area, \
-                               d_level,\
-                               d_str "\n", \
-                               d_data); \
-} while(0)
-
 /* limit size for an errorstring */
 #define ERRORLENGTH 30
 
index aa42c3a2c90ab2a9bdaab4d5b41687b1aef3dda6..a05a4297cfae20ab126b03acf10b4089a96d8e36 100644 (file)
@@ -56,13 +56,7 @@ extern debug_info_t *scm_debug;
 
 static inline void SCM_LOG_HEX(int level, void *data, int length)
 {
-       if (!debug_level_enabled(scm_debug, level))
-               return;
-       while (length > 0) {
-               debug_event(scm_debug, level, data, length);
-               length -= scm_debug->buf_size;
-               data += scm_debug->buf_size;
-       }
+       debug_event(scm_debug, level, data, length);
 }
 
 static inline void SCM_LOG_STATE(int level, struct scm_device *scmdev)
index d247f238faf8cf139b87ce4f50332ecb8ea91880..7027e61a6931028a2f2e5230110493f9659eb305 100644 (file)
@@ -211,11 +211,8 @@ sclp_console_write(struct console *console, const char *message,
        /* Setup timer to output current console buffer after 1/10 second */
        if (sclp_conbuf != NULL && sclp_chars_in_buffer(sclp_conbuf) != 0 &&
            !timer_pending(&sclp_con_timer)) {
-               init_timer(&sclp_con_timer);
-               sclp_con_timer.function = sclp_console_timeout;
-               sclp_con_timer.data = 0UL;
-               sclp_con_timer.expires = jiffies + HZ/10;
-               add_timer(&sclp_con_timer);
+               setup_timer(&sclp_con_timer, sclp_console_timeout, 0UL);
+               mod_timer(&sclp_con_timer, jiffies + HZ / 10);
        }
 out:
        spin_unlock_irqrestore(&sclp_con_lock, flags);
index 875628dab419cb8115eb72e2d06e37be33b2f113..1cceefdc03e08850b9cbfecd9a7d5126ecf112b5 100644 (file)
@@ -218,11 +218,8 @@ static int sclp_tty_write_string(const unsigned char *str, int count, int may_fa
        /* Setup timer to output current console buffer after 1/10 second */
        if (sclp_ttybuf && sclp_chars_in_buffer(sclp_ttybuf) &&
            !timer_pending(&sclp_tty_timer)) {
-               init_timer(&sclp_tty_timer);
-               sclp_tty_timer.function = sclp_tty_timeout;
-               sclp_tty_timer.data = 0UL;
-               sclp_tty_timer.expires = jiffies + HZ/10;
-               add_timer(&sclp_tty_timer);
+               setup_timer(&sclp_tty_timer, sclp_tty_timeout, 0UL);
+               mod_timer(&sclp_tty_timer, jiffies + HZ / 10);
        }
        spin_unlock_irqrestore(&sclp_tty_lock, flags);
 out:
index 997b25f6e4cc0a8cc6c935deeb58816589056fbe..8bec5f9ea92c900d9d26f1f4df0783daf5420c6d 100644 (file)
@@ -129,6 +129,7 @@ struct tape_request {
        int options;                    /* options for execution. */
        int retries;                    /* retry counter for error recovery. */
        int rescnt;                     /* residual count from devstat. */
+       struct timer_list timer;        /* timer for std_assign_timeout(). */
 
        /* Callback for delivering final status. */
        void (*callback)(struct tape_request *, void *);
index 91c3c642c76e44e97f8538da6e58672339c98e55..e7d23048d3f00d0ea1d2a59bf1128d38f4cb6d1d 100644 (file)
@@ -68,9 +68,8 @@ struct tape_class_device *register_tape_dev(
 
        tcd->char_device->owner = fops->owner;
        tcd->char_device->ops   = fops;
-       tcd->char_device->dev   = dev;
 
-       rc = cdev_add(tcd->char_device, tcd->char_device->dev, 1);
+       rc = cdev_add(tcd->char_device, dev, 1);
        if (rc)
                goto fail_with_cdev;
 
index 7caba0cc8b2af14b962877e352f04c391ab3bfae..1f5fab617b67901d73527e02e51c3c819f5af8dc 100644 (file)
  * tape_std_assign
  */
 static void
-tape_std_assign_timeout(unsigned long data)
+tape_std_assign_timeout(struct timer_list *t)
 {
-       struct tape_request *   request;
-       struct tape_device *    device;
+       struct tape_request *   request = from_timer(request, t, timer);
+       struct tape_device *    device = request->device;
        int rc;
 
-       request = (struct tape_request *) data;
-       device = request->device;
        BUG_ON(!device);
 
        DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",
@@ -71,16 +69,12 @@ tape_std_assign(struct tape_device *device)
         * to another host (actually this shouldn't happen but it does).
         * So we set up a timeout for this call.
         */
-       init_timer_on_stack(&timeout);
-       timeout.function = tape_std_assign_timeout;
-       timeout.data     = (unsigned long) request;
-       timeout.expires  = jiffies + 2 * HZ;
-       add_timer(&timeout);
+       timer_setup(&request->timer, tape_std_assign_timeout, 0);
+       mod_timer(&timeout, jiffies + 2 * HZ);
 
        rc = tape_do_io_interruptible(device, request);
 
-       del_timer_sync(&timeout);
-       destroy_timer_on_stack(&timeout);
+       del_timer_sync(&request->timer);
 
        if (rc != 0) {
                DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
index b19020b9efff895709a824dab788839262e0252e..62559dc0169f8c9f32a4677e946e0e88880ae17f 100644 (file)
@@ -812,8 +812,7 @@ static int vmlogrdr_register_cdev(dev_t dev)
        }
        vmlogrdr_cdev->owner = THIS_MODULE;
        vmlogrdr_cdev->ops = &vmlogrdr_fops;
-       vmlogrdr_cdev->dev = dev;
-       rc = cdev_add(vmlogrdr_cdev, vmlogrdr_cdev->dev, MAXMINOR);
+       rc = cdev_add(vmlogrdr_cdev, dev, MAXMINOR);
        if (!rc)
                return 0;
 
index 04aceb694d5158ef5261930a0da02f04ef132c03..fa90ef05afc00c32805238c4dccdb1a5c589390d 100644 (file)
@@ -110,7 +110,7 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev)
        mutex_init(&urd->io_mutex);
        init_waitqueue_head(&urd->wait);
        spin_lock_init(&urd->open_lock);
-       atomic_set(&urd->ref_count,  1);
+       refcount_set(&urd->ref_count,  1);
        urd->cdev = cdev;
        get_device(&cdev->dev);
        return urd;
@@ -126,7 +126,7 @@ static void urdev_free(struct urdev *urd)
 
 static void urdev_get(struct urdev *urd)
 {
-       atomic_inc(&urd->ref_count);
+       refcount_inc(&urd->ref_count);
 }
 
 static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev)
@@ -159,7 +159,7 @@ static struct urdev *urdev_get_from_devno(u16 devno)
 
 static void urdev_put(struct urdev *urd)
 {
-       if (atomic_dec_and_test(&urd->ref_count))
+       if (refcount_dec_and_test(&urd->ref_count))
                urdev_free(urd);
 }
 
@@ -892,10 +892,9 @@ static int ur_set_online(struct ccw_device *cdev)
        }
 
        urd->char_device->ops = &ur_fops;
-       urd->char_device->dev = MKDEV(major, minor);
        urd->char_device->owner = ur_fops.owner;
 
-       rc = cdev_add(urd->char_device, urd->char_device->dev, 1);
+       rc = cdev_add(urd->char_device, MKDEV(major, minor), 1);
        if (rc)
                goto fail_free_cdev;
        if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) {
@@ -946,7 +945,7 @@ static int ur_set_offline_force(struct ccw_device *cdev, int force)
                rc = -EBUSY;
                goto fail_urdev_put;
        }
-       if (!force && (atomic_read(&urd->ref_count) > 2)) {
+       if (!force && (refcount_read(&urd->ref_count) > 2)) {
                /* There is still a user of urd (e.g. ur_open) */
                TRACE("ur_set_offline: BUSY\n");
                rc = -EBUSY;
index 67164ba22f11db037ffa520fdf94b41efebffb24..608b0719ce17b68301d7f6df47743c3a64b403d2 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef _VMUR_H_
 #define _VMUR_H_
 
+#include <linux/refcount.h>
+
 #define DEV_CLASS_UR_I 0x20 /* diag210 unit record input device class */
 #define DEV_CLASS_UR_O 0x10 /* diag210 unit record output device class */
 /*
@@ -70,7 +72,7 @@ struct urdev {
        size_t reclen;                  /* Record length for *write* CCWs */
        int class;                      /* VM device class */
        int io_request_rc;              /* return code from I/O request */
-       atomic_t ref_count;             /* reference counter */
+       refcount_t ref_count;           /* reference counter */
        wait_queue_head_t wait;         /* wait queue to serialize open */
        int open_flag;                  /* "urdev is open" flag */
        spinlock_t open_lock;           /* serialize critical sections */
index 34b9ad6b31438fb8864a9068d7f72294722da169..e2f7b6e93efddf85dd45457d70ce3c3bc3602ba3 100644 (file)
@@ -373,6 +373,12 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv,
                rc = -EINVAL;
                goto error;
        }
+       /* Check if the devices are bound to the required ccw driver. */
+       if (gdev->count && gdrv && gdrv->ccw_driver &&
+           gdev->cdev[0]->drv != gdrv->ccw_driver) {
+               rc = -EINVAL;
+               goto error;
+       }
 
        dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev));
        gdev->dev.groups = ccwgroup_attr_groups;
index 735052ecd3e57e320136ad440612eca26340d97c..8e7e19b9e92c028e1097fe9ff82386203594bc37 100644 (file)
@@ -43,11 +43,7 @@ static DEFINE_MUTEX(on_close_mutex);
 
 static void CHSC_LOG_HEX(int level, void *data, int length)
 {
-       while (length > 0) {
-               debug_event(chsc_debug_log_id, level, data, length);
-               length -= chsc_debug_log_id->buf_size;
-               data += chsc_debug_log_id->buf_size;
-       }
+       debug_event(chsc_debug_log_id, level, data, length);
 }
 
 MODULE_AUTHOR("IBM Corporation");
index fa817efcec8fa5c077e26c84d2053c4d16614438..7bdbe73707c2c09bcbea62416fe4ddf92d27d49a 100644 (file)
@@ -23,13 +23,7 @@ extern debug_info_t *cio_debug_crw_id;
 
 static inline void CIO_HEX_EVENT(int level, void *data, int length)
 {
-       if (unlikely(!cio_debug_trace_id))
-               return;
-       while (length > 0) {
-               debug_event(cio_debug_trace_id, level, data, length);
-               length -= cio_debug_trace_id->buf_size;
-               data += cio_debug_trace_id->buf_size;
-       }
+       debug_event(cio_debug_trace_id, level, data, length);
 }
 
 #endif
index 220491d27ef4791f72ac85a9c921ede2a0370775..7d59230e88bb3a2452e8e4eaf667f25659d3d13d 100644 (file)
@@ -58,8 +58,9 @@
 
 /* indices for READCMB */
 enum cmb_index {
+       avg_utilization = -1,
  /* basic and exended format: */
-       cmb_ssch_rsch_count,
+       cmb_ssch_rsch_count = 0,
        cmb_sample_count,
        cmb_device_connect_time,
        cmb_function_pending_time,
@@ -215,71 +216,52 @@ struct set_schib_struct {
        unsigned long address;
        wait_queue_head_t wait;
        int ret;
-       struct kref kref;
 };
 
-static void cmf_set_schib_release(struct kref *kref)
-{
-       struct set_schib_struct *set_data;
-
-       set_data = container_of(kref, struct set_schib_struct, kref);
-       kfree(set_data);
-}
-
 #define CMF_PENDING 1
+#define SET_SCHIB_TIMEOUT (10 * HZ)
 
 static int set_schib_wait(struct ccw_device *cdev, u32 mme,
-                               int mbfc, unsigned long address)
+                         int mbfc, unsigned long address)
 {
-       struct set_schib_struct *set_data;
-       int ret;
+       struct set_schib_struct set_data;
+       int ret = -ENODEV;
 
        spin_lock_irq(cdev->ccwlock);
-       if (!cdev->private->cmb) {
-               ret = -ENODEV;
+       if (!cdev->private->cmb)
                goto out;
-       }
-       set_data = kzalloc(sizeof(struct set_schib_struct), GFP_ATOMIC);
-       if (!set_data) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       init_waitqueue_head(&set_data->wait);
-       kref_init(&set_data->kref);
-       set_data->mme = mme;
-       set_data->mbfc = mbfc;
-       set_data->address = address;
 
        ret = set_schib(cdev, mme, mbfc, address);
        if (ret != -EBUSY)
-               goto out_put;
+               goto out;
 
-       if (cdev->private->state != DEV_STATE_ONLINE) {
-               /* if the device is not online, don't even try again */
-               ret = -EBUSY;
-               goto out_put;
-       }
+       /* if the device is not online, don't even try again */
+       if (cdev->private->state != DEV_STATE_ONLINE)
+               goto out;
 
-       cdev->private->state = DEV_STATE_CMFCHANGE;
-       set_data->ret = CMF_PENDING;
-       cdev->private->cmb_wait = set_data;
+       init_waitqueue_head(&set_data.wait);
+       set_data.mme = mme;
+       set_data.mbfc = mbfc;
+       set_data.address = address;
+       set_data.ret = CMF_PENDING;
 
+       cdev->private->state = DEV_STATE_CMFCHANGE;
+       cdev->private->cmb_wait = &set_data;
        spin_unlock_irq(cdev->ccwlock);
-       if (wait_event_interruptible(set_data->wait,
-                                    set_data->ret != CMF_PENDING)) {
-               spin_lock_irq(cdev->ccwlock);
-               if (set_data->ret == CMF_PENDING) {
-                       set_data->ret = -ERESTARTSYS;
+
+       ret = wait_event_interruptible_timeout(set_data.wait,
+                                              set_data.ret != CMF_PENDING,
+                                              SET_SCHIB_TIMEOUT);
+       spin_lock_irq(cdev->ccwlock);
+       if (ret <= 0) {
+               if (set_data.ret == CMF_PENDING) {
+                       set_data.ret = (ret == 0) ? -ETIME : ret;
                        if (cdev->private->state == DEV_STATE_CMFCHANGE)
                                cdev->private->state = DEV_STATE_ONLINE;
                }
-               spin_unlock_irq(cdev->ccwlock);
        }
-       spin_lock_irq(cdev->ccwlock);
        cdev->private->cmb_wait = NULL;
-       ret = set_data->ret;
-out_put:
-       kref_put(&set_data->kref, cmf_set_schib_release);
+       ret = set_data.ret;
 out:
        spin_unlock_irq(cdev->ccwlock);
        return ret;
@@ -287,28 +269,21 @@ out:
 
 void retry_set_schib(struct ccw_device *cdev)
 {
-       struct set_schib_struct *set_data;
+       struct set_schib_struct *set_data = cdev->private->cmb_wait;
 
-       set_data = cdev->private->cmb_wait;
-       if (!set_data) {
-               WARN_ON(1);
+       if (!set_data)
                return;
-       }
-       kref_get(&set_data->kref);
+
        set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc,
                                  set_data->address);
        wake_up(&set_data->wait);
-       kref_put(&set_data->kref, cmf_set_schib_release);
 }
 
 static int cmf_copy_block(struct ccw_device *cdev)
 {
-       struct subchannel *sch;
-       void *reference_buf;
-       void *hw_block;
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
        struct cmb_data *cmb_data;
-
-       sch = to_subchannel(cdev->dev.parent);
+       void *hw_block;
 
        if (cio_update_schib(sch))
                return -ENODEV;
@@ -323,102 +298,65 @@ static int cmf_copy_block(struct ccw_device *cdev)
        }
        cmb_data = cdev->private->cmb;
        hw_block = cmb_data->hw_block;
-       if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size))
-               /* No need to copy. */
-               return 0;
-       reference_buf = kzalloc(cmb_data->size, GFP_ATOMIC);
-       if (!reference_buf)
-               return -ENOMEM;
-       /* Ensure consistency of block copied from hardware. */
-       do {
-               memcpy(cmb_data->last_block, hw_block, cmb_data->size);
-               memcpy(reference_buf, hw_block, cmb_data->size);
-       } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size));
+       memcpy(cmb_data->last_block, hw_block, cmb_data->size);
        cmb_data->last_update = get_tod_clock();
-       kfree(reference_buf);
        return 0;
 }
 
 struct copy_block_struct {
        wait_queue_head_t wait;
        int ret;
-       struct kref kref;
 };
 
-static void cmf_copy_block_release(struct kref *kref)
-{
-       struct copy_block_struct *copy_block;
-
-       copy_block = container_of(kref, struct copy_block_struct, kref);
-       kfree(copy_block);
-}
-
 static int cmf_cmb_copy_wait(struct ccw_device *cdev)
 {
-       struct copy_block_struct *copy_block;
-       int ret;
-       unsigned long flags;
+       struct copy_block_struct copy_block;
+       int ret = -ENODEV;
 
-       spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               ret = -ENODEV;
-               goto out;
-       }
-       copy_block = kzalloc(sizeof(struct copy_block_struct), GFP_ATOMIC);
-       if (!copy_block) {
-               ret = -ENOMEM;
+       spin_lock_irq(cdev->ccwlock);
+       if (!cdev->private->cmb)
                goto out;
-       }
-       init_waitqueue_head(&copy_block->wait);
-       kref_init(&copy_block->kref);
 
        ret = cmf_copy_block(cdev);
        if (ret != -EBUSY)
-               goto out_put;
+               goto out;
 
-       if (cdev->private->state != DEV_STATE_ONLINE) {
-               ret = -EBUSY;
-               goto out_put;
-       }
+       if (cdev->private->state != DEV_STATE_ONLINE)
+               goto out;
+
+       init_waitqueue_head(&copy_block.wait);
+       copy_block.ret = CMF_PENDING;
 
        cdev->private->state = DEV_STATE_CMFUPDATE;
-       copy_block->ret = CMF_PENDING;
-       cdev->private->cmb_wait = copy_block;
+       cdev->private->cmb_wait = &copy_block;
+       spin_unlock_irq(cdev->ccwlock);
 
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
-       if (wait_event_interruptible(copy_block->wait,
-                                    copy_block->ret != CMF_PENDING)) {
-               spin_lock_irqsave(cdev->ccwlock, flags);
-               if (copy_block->ret == CMF_PENDING) {
-                       copy_block->ret = -ERESTARTSYS;
+       ret = wait_event_interruptible(copy_block.wait,
+                                      copy_block.ret != CMF_PENDING);
+       spin_lock_irq(cdev->ccwlock);
+       if (ret) {
+               if (copy_block.ret == CMF_PENDING) {
+                       copy_block.ret = -ERESTARTSYS;
                        if (cdev->private->state == DEV_STATE_CMFUPDATE)
                                cdev->private->state = DEV_STATE_ONLINE;
                }
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
        }
-       spin_lock_irqsave(cdev->ccwlock, flags);
        cdev->private->cmb_wait = NULL;
-       ret = copy_block->ret;
-out_put:
-       kref_put(&copy_block->kref, cmf_copy_block_release);
+       ret = copy_block.ret;
 out:
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
+       spin_unlock_irq(cdev->ccwlock);
        return ret;
 }
 
 void cmf_retry_copy_block(struct ccw_device *cdev)
 {
-       struct copy_block_struct *copy_block;
+       struct copy_block_struct *copy_block = cdev->private->cmb_wait;
 
-       copy_block = cdev->private->cmb_wait;
-       if (!copy_block) {
-               WARN_ON(1);
+       if (!copy_block)
                return;
-       }
-       kref_get(&copy_block->kref);
+
        copy_block->ret = cmf_copy_block(cdev);
        wake_up(&copy_block->wait);
-       kref_put(&copy_block->kref, cmf_copy_block_release);
 }
 
 static void cmf_generic_reset(struct ccw_device *cdev)
@@ -650,25 +588,44 @@ static int set_cmb(struct ccw_device *cdev, u32 mme)
        return set_schib_wait(cdev, mme, 0, offset);
 }
 
+/* calculate utilization in 0.1 percent units */
+static u64 __cmb_utilization(u64 device_connect_time, u64 function_pending_time,
+                            u64 device_disconnect_time, u64 start_time)
+{
+       u64 utilization, elapsed_time;
+
+       utilization = time_to_nsec(device_connect_time +
+                                  function_pending_time +
+                                  device_disconnect_time);
+
+       elapsed_time = get_tod_clock() - start_time;
+       elapsed_time = tod_to_ns(elapsed_time);
+       elapsed_time /= 1000;
+
+       return elapsed_time ? (utilization / elapsed_time) : 0;
+}
+
 static u64 read_cmb(struct ccw_device *cdev, int index)
 {
+       struct cmb_data *cmb_data;
+       unsigned long flags;
        struct cmb *cmb;
+       u64 ret = 0;
        u32 val;
-       int ret;
-       unsigned long flags;
-
-       ret = cmf_cmb_copy_wait(cdev);
-       if (ret < 0)
-               return 0;
 
        spin_lock_irqsave(cdev->ccwlock, flags);
-       if (!cdev->private->cmb) {
-               ret = 0;
+       cmb_data = cdev->private->cmb;
+       if (!cmb_data)
                goto out;
-       }
-       cmb = ((struct cmb_data *)cdev->private->cmb)->last_block;
 
+       cmb = cmb_data->hw_block;
        switch (index) {
+       case avg_utilization:
+               ret = __cmb_utilization(cmb->device_connect_time,
+                                       cmb->function_pending_time,
+                                       cmb->device_disconnect_time,
+                                       cdev->private->cmb_start_time);
+               goto out;
        case cmb_ssch_rsch_count:
                ret = cmb->ssch_rsch_count;
                goto out;
@@ -691,7 +648,6 @@ static u64 read_cmb(struct ccw_device *cdev, int index)
                val = cmb->device_active_only_time;
                break;
        default:
-               ret = 0;
                goto out;
        }
        ret = time_to_avg_nsec(val, cmb->sample_count);
@@ -729,8 +685,7 @@ static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
        /* we only know values before device_busy_time */
        data->size = offsetof(struct cmbdata, device_busy_time);
 
-       /* convert to nanoseconds */
-       data->elapsed_time = (time * 1000) >> 12;
+       data->elapsed_time = tod_to_ns(time);
 
        /* copy data to new structure */
        data->ssch_rsch_count = cmb->ssch_rsch_count;
@@ -904,28 +859,27 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme)
        return set_schib_wait(cdev, mme, 1, mba);
 }
 
-
 static u64 read_cmbe(struct ccw_device *cdev, int index)
 {
-       struct cmbe *cmb;
        struct cmb_data *cmb_data;
-       u32 val;
-       int ret;
        unsigned long flags;
-
-       ret = cmf_cmb_copy_wait(cdev);
-       if (ret < 0)
-               return 0;
+       struct cmbe *cmb;
+       u64 ret = 0;
+       u32 val;
 
        spin_lock_irqsave(cdev->ccwlock, flags);
        cmb_data = cdev->private->cmb;
-       if (!cmb_data) {
-               ret = 0;
+       if (!cmb_data)
                goto out;
-       }
-       cmb = cmb_data->last_block;
 
+       cmb = cmb_data->hw_block;
        switch (index) {
+       case avg_utilization:
+               ret = __cmb_utilization(cmb->device_connect_time,
+                                       cmb->function_pending_time,
+                                       cmb->device_disconnect_time,
+                                       cdev->private->cmb_start_time);
+               goto out;
        case cmb_ssch_rsch_count:
                ret = cmb->ssch_rsch_count;
                goto out;
@@ -954,7 +908,6 @@ static u64 read_cmbe(struct ccw_device *cdev, int index)
                val = cmb->initial_command_response_time;
                break;
        default:
-               ret = 0;
                goto out;
        }
        ret = time_to_avg_nsec(val, cmb->sample_count);
@@ -991,8 +944,7 @@ static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
        /* we only know values before device_busy_time */
        data->size = offsetof(struct cmbdata, device_busy_time);
 
-       /* conver to nanoseconds */
-       data->elapsed_time = (time * 1000) >> 12;
+       data->elapsed_time = tod_to_ns(time);
 
        cmb = cmb_data->last_block;
        /* copy data to new structure */
@@ -1045,19 +997,15 @@ static ssize_t cmb_show_avg_sample_interval(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
 {
-       struct ccw_device *cdev;
-       long interval;
+       struct ccw_device *cdev = to_ccwdev(dev);
        unsigned long count;
-       struct cmb_data *cmb_data;
+       long interval;
 
-       cdev = to_ccwdev(dev);
        count = cmf_read(cdev, cmb_sample_count);
        spin_lock_irq(cdev->ccwlock);
-       cmb_data = cdev->private->cmb;
        if (count) {
-               interval = cmb_data->last_update -
-                       cdev->private->cmb_start_time;
-               interval = (interval * 1000) >> 12;
+               interval = get_tod_clock() - cdev->private->cmb_start_time;
+               interval = tod_to_ns(interval);
                interval /= count;
        } else
                interval = -1;
@@ -1069,27 +1017,9 @@ static ssize_t cmb_show_avg_utilization(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct cmbdata data;
-       u64 utilization;
-       unsigned long t, u;
-       int ret;
-
-       ret = cmf_readall(to_ccwdev(dev), &data);
-       if (ret == -EAGAIN || ret == -ENODEV)
-               /* No data (yet/currently) available to use for calculation. */
-               return sprintf(buf, "n/a\n");
-       else if (ret)
-               return ret;
-
-       utilization = data.device_connect_time +
-                     data.function_pending_time +
-                     data.device_disconnect_time;
-
-       /* calculate value in 0.1 percent units */
-       t = data.elapsed_time / 1000;
-       u = utilization / t;
+       unsigned long u = cmf_read(to_ccwdev(dev), avg_utilization);
 
-       return sprintf(buf, "%02ld.%01ld%%\n", u/ 10, u - (u/ 10) * 10);
+       return sprintf(buf, "%02lu.%01lu%%\n", u / 10, u % 10);
 }
 
 #define cmf_attr(name) \
index 0f11f3bcac8284d9a5191913ad9aaf3647cd3293..d14795f7110b4021a2fa58b08b332af34573a735 100644 (file)
@@ -43,13 +43,7 @@ static debug_info_t *eadm_debug;
 
 static void EADM_LOG_HEX(int level, void *data, int length)
 {
-       if (!debug_level_enabled(eadm_debug, level))
-               return;
-       while (length > 0) {
-               debug_event(eadm_debug, level, data, length);
-               length -= eadm_debug->buf_size;
-               data += eadm_debug->buf_size;
-       }
+       debug_event(eadm_debug, level, data, length);
 }
 
 static void orb_init(union orb *orb)
index e06496ab00368c6271d9c45a5abd68cdfd146d26..f85f5fa7cefc76889b0fb0c98ac5712707289f39 100644 (file)
@@ -34,11 +34,7 @@ extern debug_info_t *qdio_dbf_error;
 
 static inline void DBF_HEX(void *addr, int len)
 {
-       while (len > 0) {
-               debug_event(qdio_dbf_setup, DBF_ERR, addr, len);
-               len -= qdio_dbf_setup->buf_size;
-               addr += qdio_dbf_setup->buf_size;
-       }
+       debug_event(qdio_dbf_setup, DBF_ERR, addr, len);
 }
 
 #define DBF_ERROR(text...) \
@@ -50,11 +46,7 @@ static inline void DBF_HEX(void *addr, int len)
 
 static inline void DBF_ERROR_HEX(void *addr, int len)
 {
-       while (len > 0) {
-               debug_event(qdio_dbf_error, DBF_ERR, addr, len);
-               len -= qdio_dbf_error->buf_size;
-               addr += qdio_dbf_error->buf_size;
-       }
+       debug_event(qdio_dbf_error, DBF_ERR, addr, len);
 }
 
 #define DBF_DEV_EVENT(level, device, text...) \
@@ -69,11 +61,7 @@ static inline void DBF_ERROR_HEX(void *addr, int len)
 static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr,
                               int len, int level)
 {
-       while (len > 0) {
-               debug_event(dev->debug_area, level, addr, len);
-               len -= dev->debug_area->buf_size;
-               addr += dev->debug_area->buf_size;
-       }
+       debug_event(dev->debug_area, level, addr, len);
 }
 
 int qdio_allocate_dbf(struct qdio_initialize *init_data,
index a739bdf9630e70f1c905807fb27136664f7d9ce5..0787b587e4b8b690c9f1cb9bb511a6a6897f959b 100644 (file)
@@ -57,10 +57,8 @@ static u32 *get_indicator(void)
        int i;
 
        for (i = 0; i < TIQDIO_NR_NONSHARED_IND; i++)
-               if (!atomic_read(&q_indicators[i].count)) {
-                       atomic_set(&q_indicators[i].count, 1);
+               if (!atomic_cmpxchg(&q_indicators[i].count, 0, 1))
                        return &q_indicators[i].ind;
-               }
 
        /* use the shared indicator */
        atomic_inc(&q_indicators[TIQDIO_SHARED_IND].count);
@@ -69,13 +67,11 @@ static u32 *get_indicator(void)
 
 static void put_indicator(u32 *addr)
 {
-       int i;
+       struct indicator_t *ind = container_of(addr, struct indicator_t, ind);
 
        if (!addr)
                return;
-       i = ((unsigned long)addr - (unsigned long)q_indicators) /
-               sizeof(struct indicator_t);
-       atomic_dec(&q_indicators[i].count);
+       atomic_dec(&ind->count);
 }
 
 void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
index f20b4d66c75f7f3480b967bf3a48eae58acba12d..d9a2fffd034be1cdf6c18605c71140843c87d6f5 100644 (file)
@@ -106,7 +106,10 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev,
 {
        int ret = 0;
 
-       if (!len || pa->pa_nr)
+       if (!len)
+               return 0;
+
+       if (pa->pa_nr)
                return -EINVAL;
 
        pa->pa_iova = iova;
@@ -330,6 +333,8 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx)
 {
        struct ccw1 *ccw = chain->ch_ccw + idx;
 
+       if (ccw_is_test(ccw) || ccw_is_noop(ccw) || ccw_is_tic(ccw))
+               return;
        if (!ccw->count)
                return;
 
@@ -502,6 +507,16 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
 
        ccw = chain->ch_ccw + idx;
 
+       if (!ccw->count) {
+               /*
+                * We just want the translation result of any direct ccw
+                * to be an IDA ccw, so let's add the IDA flag for it.
+                * Although the flag will be ignored by firmware.
+                */
+               ccw->flags |= CCW_FLAG_IDA;
+               return 0;
+       }
+
        /*
         * Pin data page(s) in memory.
         * The number of pages actually is the count of the idaws which will be
@@ -542,6 +557,9 @@ static int ccwchain_fetch_idal(struct ccwchain *chain,
 
        ccw = chain->ch_ccw + idx;
 
+       if (!ccw->count)
+               return 0;
+
        /* Calculate size of idaws. */
        ret = copy_from_iova(cp->mdev, &idaw_iova, ccw->cda, sizeof(idaw_iova));
        if (ret)
@@ -570,10 +588,6 @@ static int ccwchain_fetch_idal(struct ccwchain *chain,
 
        for (i = 0; i < idaw_nr; i++) {
                idaw_iova = *(idaws + i);
-               if (IS_ERR_VALUE(idaw_iova)) {
-                       ret = -EFAULT;
-                       goto out_free_idaws;
-               }
 
                ret = pfn_array_alloc_pin(pat->pat_pa + i, cp->mdev,
                                          idaw_iova, 1);
index 6c0474c834d440d2e154d93668ca72107e9c0d32..16b59ce5e01d9f439f2050613cc6d6cfc6155776 100644 (file)
@@ -117,6 +117,49 @@ static inline int ap_qci(void *config)
        return reg1;
 }
 
+/*
+ * union ap_qact_ap_info - used together with the
+ * ap_aqic() function to provide a convenient way
+ * to handle the ap info needed by the qact function.
+ */
+union ap_qact_ap_info {
+       unsigned long val;
+       struct {
+               unsigned int      : 3;
+               unsigned int mode : 3;
+               unsigned int      : 26;
+               unsigned int cat  : 8;
+               unsigned int      : 8;
+               unsigned char ver[2];
+       };
+};
+
+/**
+ * ap_qact(): Query AP combatibility type.
+ * @qid: The AP queue number
+ * @apinfo: On input the info about the AP queue. On output the
+ *         alternate AP queue info provided by the qact function
+ *         in GR2 is stored in.
+ *
+ * Returns AP queue status. Check response_code field for failures.
+ */
+static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
+                                            union ap_qact_ap_info *apinfo)
+{
+       register unsigned long reg0 asm ("0") = qid | (5UL << 24)
+               | ((ifbit & 0x01) << 22);
+       register unsigned long reg1_in asm ("1") = apinfo->val;
+       register struct ap_queue_status reg1_out asm ("1");
+       register unsigned long reg2 asm ("2") = 0;
+
+       asm volatile(
+               ".long 0xb2af0000"              /* PQAP(QACT) */
+               : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2)
+               : : "cc");
+       apinfo->val = reg2;
+       return reg1_out;
+}
+
 /**
  * ap_nqap(): Send message to adjunct processor queue.
  * @qid: The AP queue number
index 5f0be20402726d7f6b9c0d4816cf32580077eb09..8b5658b0bec368784f140d3bbe3b7f4428cfc8f3 100644 (file)
@@ -176,6 +176,18 @@ static int ap_apft_available(void)
        return test_facility(15);
 }
 
+/*
+ * ap_qact_available(): Test if the PQAP(QACT) subfunction is available.
+ *
+ * Returns 1 if the QACT subfunction is available.
+ */
+static inline int ap_qact_available(void)
+{
+       if (ap_configuration)
+               return ap_configuration->qact;
+       return 0;
+}
+
 /**
  * ap_test_queue(): Test adjunct processor queue.
  * @qid: The AP queue number
@@ -987,6 +999,47 @@ static int ap_select_domain(void)
        return -ENODEV;
 }
 
+/*
+ * This function checks the type and returns either 0 for not
+ * supported or the highest compatible type value (which may
+ * include the input type value).
+ */
+static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
+{
+       int comp_type = 0;
+
+       /* < CEX2A is not supported */
+       if (rawtype < AP_DEVICE_TYPE_CEX2A)
+               return 0;
+       /* up to CEX6 known and fully supported */
+       if (rawtype <= AP_DEVICE_TYPE_CEX6)
+               return rawtype;
+       /*
+        * unknown new type > CEX6, check for compatibility
+        * to the highest known and supported type which is
+        * currently CEX6 with the help of the QACT function.
+        */
+       if (ap_qact_available()) {
+               struct ap_queue_status status;
+               union ap_qact_ap_info apinfo = {0};
+
+               apinfo.mode = (func >> 26) & 0x07;
+               apinfo.cat = AP_DEVICE_TYPE_CEX6;
+               status = ap_qact(qid, 0, &apinfo);
+               if (status.response_code == AP_RESPONSE_NORMAL
+                   && apinfo.cat >= AP_DEVICE_TYPE_CEX2A
+                   && apinfo.cat <= AP_DEVICE_TYPE_CEX6)
+                       comp_type = apinfo.cat;
+       }
+       if (!comp_type)
+               AP_DBF(DBF_WARN, "queue=%02x.%04x unable to map type %d\n",
+                      AP_QID_CARD(qid), AP_QID_QUEUE(qid), rawtype);
+       else if (comp_type != rawtype)
+               AP_DBF(DBF_INFO, "queue=%02x.%04x map type %d to %d\n",
+                      AP_QID_CARD(qid), AP_QID_QUEUE(qid), rawtype, comp_type);
+       return comp_type;
+}
+
 /*
  * helper function to be used with bus_find_dev
  * matches for the card device with the given id
@@ -1014,8 +1067,8 @@ static void ap_scan_bus(struct work_struct *unused)
        struct ap_card *ac;
        struct device *dev;
        ap_qid_t qid;
-       int depth = 0, type = 0;
-       unsigned int functions = 0;
+       int comp_type, depth = 0, type = 0;
+       unsigned int func = 0;
        int rc, id, dom, borked, domains, defdomdevs = 0;
 
        AP_DBF(DBF_DEBUG, "ap_scan_bus running\n");
@@ -1066,12 +1119,12 @@ static void ap_scan_bus(struct work_struct *unused)
                                }
                                continue;
                        }
-                       rc = ap_query_queue(qid, &depth, &type, &functions);
+                       rc = ap_query_queue(qid, &depth, &type, &func);
                        if (dev) {
                                spin_lock_bh(&aq->lock);
                                if (rc == -ENODEV ||
                                    /* adapter reconfiguration */
-                                   (ac && ac->functions != functions))
+                                   (ac && ac->functions != func))
                                        aq->state = AP_STATE_BORKED;
                                borked = aq->state == AP_STATE_BORKED;
                                spin_unlock_bh(&aq->lock);
@@ -1087,11 +1140,14 @@ static void ap_scan_bus(struct work_struct *unused)
                        }
                        if (rc)
                                continue;
-                       /* new queue device needed */
+                       /* a new queue device is needed, check out comp type */
+                       comp_type = ap_get_compatible_type(qid, type, func);
+                       if (!comp_type)
+                               continue;
+                       /* maybe a card device needs to be created first */
                        if (!ac) {
-                               /* but first create the card device */
-                               ac = ap_card_create(id, depth,
-                                                   type, functions);
+                               ac = ap_card_create(id, depth, type,
+                                                   comp_type, func);
                                if (!ac)
                                        continue;
                                ac->ap_dev.device.bus = &ap_bus_type;
@@ -1109,7 +1165,7 @@ static void ap_scan_bus(struct work_struct *unused)
                                get_device(&ac->ap_dev.device);
                        }
                        /* now create the new queue device */
-                       aq = ap_queue_create(qid, type);
+                       aq = ap_queue_create(qid, comp_type);
                        if (!aq)
                                continue;
                        aq->card = ac;
index 754cf2223cfbdde3f8312acc868e8aadae998851..3a0e19d87e7cebf295dca38e22910430440f5435 100644 (file)
@@ -250,8 +250,8 @@ void ap_queue_remove(struct ap_queue *aq);
 void ap_queue_suspend(struct ap_device *ap_dev);
 void ap_queue_resume(struct ap_device *ap_dev);
 
-struct ap_card *ap_card_create(int id, int queue_depth, int device_type,
-                              unsigned int device_functions);
+struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type,
+                              int comp_device_type, unsigned int functions);
 
 int ap_module_init(void);
 void ap_module_exit(void);
index 8a31c9e95430b419c5538e3109afb77dd1fdaf48..97a8cf578116ecd17b67e8cf544f3f1a228a66b3 100644 (file)
@@ -171,22 +171,20 @@ static void ap_card_device_release(struct device *dev)
        kfree(ac);
 }
 
-struct ap_card *ap_card_create(int id, int queue_depth, int device_type,
-                              unsigned int functions)
+struct ap_card *ap_card_create(int id, int queue_depth, int raw_type,
+                              int comp_type, unsigned int functions)
 {
        struct ap_card *ac;
 
        ac = kzalloc(sizeof(*ac), GFP_KERNEL);
        if (!ac)
                return NULL;
+       INIT_LIST_HEAD(&ac->list);
        INIT_LIST_HEAD(&ac->queues);
        ac->ap_dev.device.release = ap_card_device_release;
        ac->ap_dev.device.type = &ap_card_type;
-       ac->ap_dev.device_type = device_type;
-       /* CEX6 toleration: map to CEX5 */
-       if (device_type == AP_DEVICE_TYPE_CEX6)
-               ac->ap_dev.device_type = AP_DEVICE_TYPE_CEX5;
-       ac->raw_hwtype = device_type;
+       ac->ap_dev.device_type = comp_type;
+       ac->raw_hwtype = raw_type;
        ac->queue_depth = queue_depth;
        ac->functions = functions;
        ac->id = id;
index 6c8bd8ad618505a8f5b09e0446f128f1a33ff742..a550d40921e7b6e4c2636377140705230bc0134d 100644 (file)
@@ -627,13 +627,11 @@ struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type)
        aq->ap_dev.device.release = ap_queue_device_release;
        aq->ap_dev.device.type = &ap_queue_type;
        aq->ap_dev.device_type = device_type;
-       /* CEX6 toleration: map to CEX5 */
-       if (device_type == AP_DEVICE_TYPE_CEX6)
-               aq->ap_dev.device_type = AP_DEVICE_TYPE_CEX5;
        aq->qid = qid;
        aq->state = AP_STATE_RESET_START;
        aq->interrupt = AP_INTR_DISABLED;
        spin_lock_init(&aq->lock);
+       INIT_LIST_HEAD(&aq->list);
        INIT_LIST_HEAD(&aq->pendingq);
        INIT_LIST_HEAD(&aq->requestq);
        setup_timer(&aq->timeout, ap_request_timeout, (unsigned long) aq);
index f61fa47135a6c17dbf3660722c7a1ed959fba5dc..8dda5bb34a2f2710c6d0f8fc40b291d3e848d99e 100644 (file)
@@ -125,10 +125,9 @@ static int alloc_and_prep_cprbmem(size_t paramblen,
         * allocate consecutive memory for request CPRB, request param
         * block, reply CPRB and reply param block
         */
-       cprbmem = kmalloc(2 * cprbplusparamblen, GFP_KERNEL);
+       cprbmem = kzalloc(2 * cprbplusparamblen, GFP_KERNEL);
        if (!cprbmem)
                return -ENOMEM;
-       memset(cprbmem, 0, 2 * cprbplusparamblen);
 
        preqcblk = (struct CPRBX *) cprbmem;
        prepcblk = (struct CPRBX *) (cprbmem + cprbplusparamblen);
index 6c94efd23eacf7c6a20fa3880285485e26341f2c..73541a798db7a4a1c41bd0e555f33bd1a1bbbbde 100644 (file)
@@ -76,6 +76,7 @@ struct ica_z90_status {
 #define ZCRYPT_CEX3A           8
 #define ZCRYPT_CEX4           10
 #define ZCRYPT_CEX5           11
+#define ZCRYPT_CEX6           12
 
 /**
  * Large random numbers are pulled in 4096 byte chunks from the crypto cards
index 4e91163d70a6eb1341bb2306ca9a6b1137aa159a..e2eebc775a37a0e80ced5520cb5446d85e33fb23 100644 (file)
@@ -45,6 +45,8 @@ static struct ap_device_id zcrypt_cex4_card_ids[] = {
          .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
        { .dev_type = AP_DEVICE_TYPE_CEX5,
          .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX6,
+         .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
        { /* end of list */ },
 };
 
@@ -55,6 +57,8 @@ static struct ap_device_id zcrypt_cex4_queue_ids[] = {
          .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
        { .dev_type = AP_DEVICE_TYPE_CEX5,
          .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX6,
+         .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
        { /* end of list */ },
 };
 
@@ -72,17 +76,25 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
         * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
         */
        static const int CEX4A_SPEED_IDX[] = {
-               5,  6,    59,  20, 115,  581,  0,  0};
+                14, 19, 249, 42, 228, 1458, 0, 0};
        static const int CEX5A_SPEED_IDX[] = {
-               3,  3,     6,   8,  32,  218,  0,  0};
+                 8,  9,  20, 18,  66,  458, 0, 0};
+       static const int CEX6A_SPEED_IDX[] = {
+                 6,  9,  20, 17,  65,  438, 0, 0};
+
        static const int CEX4C_SPEED_IDX[] = {
-               24,  25,   82,  41, 138, 1111, 79,  8};
+                59,  69, 308, 83, 278, 2204, 209, 40};
        static const int CEX5C_SPEED_IDX[] = {
-               10,  14,   23,  17,  45,  242, 63,  4};
+                24,  31,  50, 37,  90,  479,  27, 10};
+       static const int CEX6C_SPEED_IDX[] = {
+                16,  20,  32, 27,  77,  455,  23,  9};
+
        static const int CEX4P_SPEED_IDX[] = {
-               142, 198, 1852, 203, 331, 1563,  0,  8};
+               224, 313, 3560, 359, 605, 2827, 0, 50};
        static const int CEX5P_SPEED_IDX[] = {
-               49,  67,  131,  52,  85,  287,  0,  4};
+                63,  84,  156,  83, 142,  533, 0, 10};
+       static const int CEX6P_SPEED_IDX[] = {
+                55,  70,  121,  73, 129,  522, 0,  9};
 
        struct ap_card *ac = to_ap_card(&ap_dev->device);
        struct zcrypt_card *zc;
@@ -99,11 +111,16 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
                        zc->user_space_type = ZCRYPT_CEX4;
                        memcpy(zc->speed_rating, CEX4A_SPEED_IDX,
                               sizeof(CEX4A_SPEED_IDX));
-               } else {
+               } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) {
                        zc->type_string = "CEX5A";
                        zc->user_space_type = ZCRYPT_CEX5;
                        memcpy(zc->speed_rating, CEX5A_SPEED_IDX,
                               sizeof(CEX5A_SPEED_IDX));
+               } else {
+                       zc->type_string = "CEX6A";
+                       zc->user_space_type = ZCRYPT_CEX6;
+                       memcpy(zc->speed_rating, CEX6A_SPEED_IDX,
+                              sizeof(CEX6A_SPEED_IDX));
                }
                zc->min_mod_size = CEX4A_MIN_MOD_SIZE;
                if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) &&
@@ -125,7 +142,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
                        zc->user_space_type = ZCRYPT_CEX3C;
                        memcpy(zc->speed_rating, CEX4C_SPEED_IDX,
                               sizeof(CEX4C_SPEED_IDX));
-               } else {
+               } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) {
                        zc->type_string = "CEX5C";
                        /* wrong user space type, must be CEX5
                         * just keep it for cca compatibility
@@ -133,6 +150,14 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
                        zc->user_space_type = ZCRYPT_CEX3C;
                        memcpy(zc->speed_rating, CEX5C_SPEED_IDX,
                               sizeof(CEX5C_SPEED_IDX));
+               } else {
+                       zc->type_string = "CEX6C";
+                       /* wrong user space type, must be CEX6
+                        * just keep it for cca compatibility
+                        */
+                       zc->user_space_type = ZCRYPT_CEX3C;
+                       memcpy(zc->speed_rating, CEX6C_SPEED_IDX,
+                              sizeof(CEX6C_SPEED_IDX));
                }
                zc->min_mod_size = CEX4C_MIN_MOD_SIZE;
                zc->max_mod_size = CEX4C_MAX_MOD_SIZE;
@@ -143,11 +168,16 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
                        zc->user_space_type = ZCRYPT_CEX4;
                        memcpy(zc->speed_rating, CEX4P_SPEED_IDX,
                               sizeof(CEX4P_SPEED_IDX));
-               } else {
+               } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) {
                        zc->type_string = "CEX5P";
                        zc->user_space_type = ZCRYPT_CEX5;
                        memcpy(zc->speed_rating, CEX5P_SPEED_IDX,
                               sizeof(CEX5P_SPEED_IDX));
+               } else {
+                       zc->type_string = "CEX6P";
+                       zc->user_space_type = ZCRYPT_CEX6;
+                       memcpy(zc->speed_rating, CEX6P_SPEED_IDX,
+                              sizeof(CEX6P_SPEED_IDX));
                }
                zc->min_mod_size = CEX4C_MIN_MOD_SIZE;
                zc->max_mod_size = CEX4C_MAX_MOD_SIZE;
index 6dd5d7c58dd08eae4f9d27074328069050f1b179..db5bde47dfb0d17b49a8dad9eeec8279c2a6e226 100644 (file)
@@ -240,8 +240,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq,
                mod = meb2->modulus + sizeof(meb2->modulus) - mod_len;
                exp = meb2->exponent + sizeof(meb2->exponent) - mod_len;
                inp = meb2->message + sizeof(meb2->message) - mod_len;
-       } else {
-               /* mod_len > 256 = 4096 bit RSA Key */
+       } else if (mod_len <= 512) {
                struct type50_meb3_msg *meb3 = ap_msg->message;
                memset(meb3, 0, sizeof(*meb3));
                ap_msg->length = sizeof(*meb3);
@@ -251,7 +250,8 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq,
                mod = meb3->modulus + sizeof(meb3->modulus) - mod_len;
                exp = meb3->exponent + sizeof(meb3->exponent) - mod_len;
                inp = meb3->message + sizeof(meb3->message) - mod_len;
-       }
+       } else
+               return -EINVAL;
 
        if (copy_from_user(mod, mex->n_modulus, mod_len) ||
            copy_from_user(exp, mex->b_key, mod_len) ||
index afd20cee7ea09fc15cb1463f144ab4a4b8a1f636..785620d3050433e33a2af975595d6969e067e45e 100644 (file)
@@ -474,7 +474,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
        *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1];
        *dom = (unsigned short *)&msg->cprbx.domain;
 
-       if (memcmp(function_code, "US", 2) == 0)
+       if (memcmp(function_code, "US", 2) == 0
+           || memcmp(function_code, "AU", 2) == 0)
                ap_msg->special = 1;
        else
                ap_msg->special = 0;
index 26363e0816fe4ac4c3ffa6aa5cdb03a285d7f9b8..be9f172185310ac081d6a44f0e061868bc5885d3 100644 (file)
@@ -1761,6 +1761,7 @@ static struct ccwgroup_driver ctcm_group_driver = {
                .owner  = THIS_MODULE,
                .name   = CTC_DRIVER_NAME,
        },
+       .ccw_driver  = &ctcm_ccw_driver,
        .setup       = ctcm_probe_device,
        .remove      = ctcm_remove_device,
        .set_online  = ctcm_new_device,
index d01b5c2a77600e4d21ce7f74bc00baf5fde29184..e131a03262ad7bcb3041a9e1e98da574930c727b 100644 (file)
@@ -834,13 +834,13 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd)
  * Emit buffer of a lan command.
  */
 static void
-lcs_lancmd_timeout(unsigned long data)
+lcs_lancmd_timeout(struct timer_list *t)
 {
-       struct lcs_reply *reply, *list_reply, *r;
+       struct lcs_reply *reply = from_timer(reply, t, timer);
+       struct lcs_reply *list_reply, *r;
        unsigned long flags;
 
        LCS_DBF_TEXT(4, trace, "timeout");
-       reply = (struct lcs_reply *) data;
        spin_lock_irqsave(&reply->card->lock, flags);
        list_for_each_entry_safe(list_reply, r,
                                 &reply->card->lancmd_waiters,list) {
@@ -864,7 +864,6 @@ lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer,
 {
        struct lcs_reply *reply;
        struct lcs_cmd *cmd;
-       struct timer_list timer;
        unsigned long flags;
        int rc;
 
@@ -885,14 +884,10 @@ lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer,
        rc = lcs_ready_buffer(&card->write, buffer);
        if (rc)
                return rc;
-       init_timer_on_stack(&timer);
-       timer.function = lcs_lancmd_timeout;
-       timer.data = (unsigned long) reply;
-       timer.expires = jiffies + HZ*card->lancmd_timeout;
-       add_timer(&timer);
+       timer_setup(&reply->timer, lcs_lancmd_timeout, 0);
+       mod_timer(&reply->timer, jiffies + HZ * card->lancmd_timeout);
        wait_event(reply->wait_q, reply->received);
-       del_timer_sync(&timer);
-       destroy_timer_on_stack(&timer);
+       del_timer_sync(&reply->timer);
        LCS_DBF_TEXT_(4, trace, "rc:%d",reply->rc);
        rc = reply->rc;
        lcs_put_reply(reply);
@@ -2396,6 +2391,7 @@ static struct ccwgroup_driver lcs_group_driver = {
                .owner  = THIS_MODULE,
                .name   = "lcs",
        },
+       .ccw_driver  = &lcs_ccw_driver,
        .setup       = lcs_probe_device,
        .remove      = lcs_remove_device,
        .set_online  = lcs_new_device,
index f94d8f6dd7a8e417de743234639db2c465e2812d..fbc8b90b1f85a098b8761602454e1d1d0506f916 100644 (file)
@@ -276,6 +276,7 @@ struct lcs_reply {
        void (*callback)(struct lcs_card *, struct lcs_cmd *);
        wait_queue_head_t wait_q;
        struct lcs_card *card;
+       struct timer_list timer;
        int received;
        int rc;
 };
index bae7440abc01e3560a987b39db440c375488a979..61cf3e9c0acb80683d60e27802b259a568b0a6ac 100644 (file)
@@ -5875,6 +5875,7 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
                .owner = THIS_MODULE,
                .name = "qeth",
        },
+       .ccw_driver = &qeth_ccw_driver,
        .setup = qeth_core_probe_device,
        .remove = qeth_core_remove_device,
        .set_online = qeth_core_set_online,
index df40692a9011ceb2cb2481af2eaa58a9ff92136e..f68af1f317f15460d489c9b8324ebc4d06142ca9 100644 (file)
@@ -6,8 +6,4 @@
 # it under the terms of the GNU General Public License (version 2 only)
 # as published by the Free Software Foundation.
 
-s390-virtio-objs := virtio_ccw.o
-ifdef CONFIG_S390_GUEST_OLD_TRANSPORT
-s390-virtio-objs += kvm_virtio.o
-endif
-obj-$(CONFIG_S390_GUEST) += $(s390-virtio-objs)
+obj-$(CONFIG_S390_GUEST) += virtio_ccw.o
diff --git a/drivers/s390/virtio/kvm_virtio.c b/drivers/s390/virtio/kvm_virtio.c
deleted file mode 100644 (file)
index a99d09a..0000000
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * virtio for kvm on s390
- *
- * Copyright IBM Corp. 2008
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (version 2 only)
- * as published by the Free Software Foundation.
- *
- *    Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
- */
-
-#include <linux/kernel_stat.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/err.h>
-#include <linux/virtio.h>
-#include <linux/virtio_config.h>
-#include <linux/slab.h>
-#include <linux/virtio_console.h>
-#include <linux/interrupt.h>
-#include <linux/virtio_ring.h>
-#include <linux/export.h>
-#include <linux/pfn.h>
-#include <asm/io.h>
-#include <asm/kvm_para.h>
-#include <asm/kvm_virtio.h>
-#include <asm/sclp.h>
-#include <asm/setup.h>
-#include <asm/irq.h>
-
-#define VIRTIO_SUBCODE_64 0x0D00
-
-/*
- * The pointer to our (page) of device descriptions.
- */
-static void *kvm_devices;
-static struct work_struct hotplug_work;
-
-struct kvm_device {
-       struct virtio_device vdev;
-       struct kvm_device_desc *desc;
-};
-
-#define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev)
-
-/*
- * memory layout:
- * - kvm_device_descriptor
- *        struct kvm_device_desc
- * - configuration
- *        struct kvm_vqconfig
- * - feature bits
- * - config space
- */
-static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc)
-{
-       return (struct kvm_vqconfig *)(desc + 1);
-}
-
-static u8 *kvm_vq_features(const struct kvm_device_desc *desc)
-{
-       return (u8 *)(kvm_vq_config(desc) + desc->num_vq);
-}
-
-static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc)
-{
-       return kvm_vq_features(desc) + desc->feature_len * 2;
-}
-
-/*
- * The total size of the config page used by this device (incl. desc)
- */
-static unsigned desc_size(const struct kvm_device_desc *desc)
-{
-       return sizeof(*desc)
-               + desc->num_vq * sizeof(struct kvm_vqconfig)
-               + desc->feature_len * 2
-               + desc->config_len;
-}
-
-/* This gets the device's feature bits. */
-static u64 kvm_get_features(struct virtio_device *vdev)
-{
-       unsigned int i;
-       u32 features = 0;
-       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-       u8 *in_features = kvm_vq_features(desc);
-
-       for (i = 0; i < min(desc->feature_len * 8, 32); i++)
-               if (in_features[i / 8] & (1 << (i % 8)))
-                       features |= (1 << i);
-       return features;
-}
-
-static int kvm_finalize_features(struct virtio_device *vdev)
-{
-       unsigned int i, bits;
-       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-       /* Second half of bitmap is features we accept. */
-       u8 *out_features = kvm_vq_features(desc) + desc->feature_len;
-
-       /* Give virtio_ring a chance to accept features. */
-       vring_transport_features(vdev);
-
-       /* Make sure we don't have any features > 32 bits! */
-       BUG_ON((u32)vdev->features != vdev->features);
-
-       memset(out_features, 0, desc->feature_len);
-       bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
-       for (i = 0; i < bits; i++) {
-               if (__virtio_test_bit(vdev, i))
-                       out_features[i / 8] |= (1 << (i % 8));
-       }
-
-       return 0;
-}
-
-/*
- * Reading and writing elements in config space
- */
-static void kvm_get(struct virtio_device *vdev, unsigned int offset,
-                  void *buf, unsigned len)
-{
-       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-
-       BUG_ON(offset + len > desc->config_len);
-       memcpy(buf, kvm_vq_configspace(desc) + offset, len);
-}
-
-static void kvm_set(struct virtio_device *vdev, unsigned int offset,
-                  const void *buf, unsigned len)
-{
-       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-
-       BUG_ON(offset + len > desc->config_len);
-       memcpy(kvm_vq_configspace(desc) + offset, buf, len);
-}
-
-/*
- * The operations to get and set the status word just access
- * the status field of the device descriptor. set_status will also
- * make a hypercall to the host, to tell about status changes
- */
-static u8 kvm_get_status(struct virtio_device *vdev)
-{
-       return to_kvmdev(vdev)->desc->status;
-}
-
-static void kvm_set_status(struct virtio_device *vdev, u8 status)
-{
-       BUG_ON(!status);
-       to_kvmdev(vdev)->desc->status = status;
-       kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS,
-                      (unsigned long) to_kvmdev(vdev)->desc);
-}
-
-/*
- * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the
- * descriptor address. The Host will zero the status and all the
- * features.
- */
-static void kvm_reset(struct virtio_device *vdev)
-{
-       kvm_hypercall1(KVM_S390_VIRTIO_RESET,
-                      (unsigned long) to_kvmdev(vdev)->desc);
-}
-
-/*
- * When the virtio_ring code wants to notify the Host, it calls us here and we
- * make a hypercall.  We hand the address  of the virtqueue so the Host
- * knows which virtqueue we're talking about.
- */
-static bool kvm_notify(struct virtqueue *vq)
-{
-       long rc;
-       struct kvm_vqconfig *config = vq->priv;
-
-       rc = kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address);
-       if (rc < 0)
-               return false;
-       return true;
-}
-
-/*
- * This routine finds the first virtqueue described in the configuration of
- * this device and sets it up.
- */
-static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
-                                    unsigned index,
-                                    void (*callback)(struct virtqueue *vq),
-                                    const char *name, bool ctx)
-{
-       struct kvm_device *kdev = to_kvmdev(vdev);
-       struct kvm_vqconfig *config;
-       struct virtqueue *vq;
-       int err;
-
-       if (index >= kdev->desc->num_vq)
-               return ERR_PTR(-ENOENT);
-
-       if (!name)
-               return NULL;
-
-       config = kvm_vq_config(kdev->desc)+index;
-
-       err = vmem_add_mapping(config->address,
-                              vring_size(config->num,
-                                         KVM_S390_VIRTIO_RING_ALIGN));
-       if (err)
-               goto out;
-
-       vq = vring_new_virtqueue(index, config->num, KVM_S390_VIRTIO_RING_ALIGN,
-                                vdev, true, ctx, (void *) config->address,
-                                kvm_notify, callback, name);
-       if (!vq) {
-               err = -ENOMEM;
-               goto unmap;
-       }
-
-       /*
-        * register a callback token
-        * The host will sent this via the external interrupt parameter
-        */
-       config->token = (u64) vq;
-
-       vq->priv = config;
-       return vq;
-unmap:
-       vmem_remove_mapping(config->address,
-                           vring_size(config->num,
-                                      KVM_S390_VIRTIO_RING_ALIGN));
-out:
-       return ERR_PTR(err);
-}
-
-static void kvm_del_vq(struct virtqueue *vq)
-{
-       struct kvm_vqconfig *config = vq->priv;
-
-       vring_del_virtqueue(vq);
-       vmem_remove_mapping(config->address,
-                           vring_size(config->num,
-                                      KVM_S390_VIRTIO_RING_ALIGN));
-}
-
-static void kvm_del_vqs(struct virtio_device *vdev)
-{
-       struct virtqueue *vq, *n;
-
-       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
-               kvm_del_vq(vq);
-}
-
-static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
-                       struct virtqueue *vqs[],
-                       vq_callback_t *callbacks[],
-                       const char * const names[],
-                       const bool *ctx,
-                       struct irq_affinity *desc)
-{
-       struct kvm_device *kdev = to_kvmdev(vdev);
-       int i;
-
-       /* We must have this many virtqueues. */
-       if (nvqs > kdev->desc->num_vq)
-               return -ENOENT;
-
-       for (i = 0; i < nvqs; ++i) {
-               vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i],
-                                    ctx ? ctx[i] : false);
-               if (IS_ERR(vqs[i]))
-                       goto error;
-       }
-       return 0;
-
-error:
-       kvm_del_vqs(vdev);
-       return PTR_ERR(vqs[i]);
-}
-
-static const char *kvm_bus_name(struct virtio_device *vdev)
-{
-       return "";
-}
-
-/*
- * The config ops structure as defined by virtio config
- */
-static const struct virtio_config_ops kvm_vq_configspace_ops = {
-       .get_features = kvm_get_features,
-       .finalize_features = kvm_finalize_features,
-       .get = kvm_get,
-       .set = kvm_set,
-       .get_status = kvm_get_status,
-       .set_status = kvm_set_status,
-       .reset = kvm_reset,
-       .find_vqs = kvm_find_vqs,
-       .del_vqs = kvm_del_vqs,
-       .bus_name = kvm_bus_name,
-};
-
-/*
- * The root device for the kvm virtio devices.
- * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2.
- */
-static struct device *kvm_root;
-
-/*
- * adds a new device and register it with virtio
- * appropriate drivers are loaded by the device model
- */
-static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset)
-{
-       struct kvm_device *kdev;
-
-       kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
-       if (!kdev) {
-               printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n",
-                      offset, d->type);
-               return;
-       }
-
-       kdev->vdev.dev.parent = kvm_root;
-       kdev->vdev.id.device = d->type;
-       kdev->vdev.config = &kvm_vq_configspace_ops;
-       kdev->desc = d;
-
-       if (register_virtio_device(&kdev->vdev) != 0) {
-               printk(KERN_ERR "Failed to register kvm device %u type %u\n",
-                      offset, d->type);
-               kfree(kdev);
-       }
-}
-
-/*
- * scan_devices() simply iterates through the device page.
- * The type 0 is reserved to mean "end of devices".
- */
-static void scan_devices(void)
-{
-       unsigned int i;
-       struct kvm_device_desc *d;
-
-       for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
-               d = kvm_devices + i;
-
-               if (d->type == 0)
-                       break;
-
-               add_kvm_device(d, i);
-       }
-}
-
-/*
- * match for a kvm device with a specific desc pointer
- */
-static int match_desc(struct device *dev, void *data)
-{
-       struct virtio_device *vdev = dev_to_virtio(dev);
-       struct kvm_device *kdev = to_kvmdev(vdev);
-
-       return kdev->desc == data;
-}
-
-/*
- * hotplug_device tries to find changes in the device page.
- */
-static void hotplug_devices(struct work_struct *dummy)
-{
-       unsigned int i;
-       struct kvm_device_desc *d;
-       struct device *dev;
-
-       for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
-               d = kvm_devices + i;
-
-               /* end of list */
-               if (d->type == 0)
-                       break;
-
-               /* device already exists */
-               dev = device_find_child(kvm_root, d, match_desc);
-               if (dev) {
-                       /* XXX check for hotplug remove */
-                       put_device(dev);
-                       continue;
-               }
-
-               /* new device */
-               printk(KERN_INFO "Adding new virtio device %p\n", d);
-               add_kvm_device(d, i);
-       }
-}
-
-/*
- * we emulate the request_irq behaviour on top of s390 extints
- */
-static void kvm_extint_handler(struct ext_code ext_code,
-                              unsigned int param32, unsigned long param64)
-{
-       struct virtqueue *vq;
-       u32 param;
-
-       if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64)
-               return;
-       inc_irq_stat(IRQEXT_VRT);
-
-       /* The LSB might be overloaded, we have to mask it */
-       vq = (struct virtqueue *)(param64 & ~1UL);
-
-       /* We use ext_params to decide what this interrupt means */
-       param = param32 & VIRTIO_PARAM_MASK;
-
-       switch (param) {
-       case VIRTIO_PARAM_CONFIG_CHANGED:
-               virtio_config_changed(vq->vdev);
-               break;
-       case VIRTIO_PARAM_DEV_ADD:
-               schedule_work(&hotplug_work);
-               break;
-       case VIRTIO_PARAM_VRING_INTERRUPT:
-       default:
-               vring_interrupt(0, vq);
-               break;
-       }
-}
-
-/*
- * For s390-virtio, we expect a page above main storage containing
- * the virtio configuration. Try to actually load from this area
- * in order to figure out if the host provides this page.
- */
-static int __init test_devices_support(unsigned long addr)
-{
-       int ret = -EIO;
-
-       asm volatile(
-               "0:     lura    0,%1\n"
-               "1:     xgr     %0,%0\n"
-               "2:\n"
-               EX_TABLE(0b,2b)
-               EX_TABLE(1b,2b)
-               : "+d" (ret)
-               : "a" (addr)
-               : "0", "cc");
-       return ret;
-}
-/*
- * Init function for virtio
- * devices are in a single page above top of "normal" + standby mem
- */
-static int __init kvm_devices_init(void)
-{
-       int rc;
-       unsigned long total_memory_size = sclp.rzm * sclp.rnmax;
-
-       if (!MACHINE_IS_KVM)
-               return -ENODEV;
-
-       if (test_devices_support(total_memory_size) < 0)
-               return -ENODEV;
-
-       pr_warn("The s390-virtio transport is deprecated. Please switch to a modern host providing virtio-ccw.\n");
-
-       rc = vmem_add_mapping(total_memory_size, PAGE_SIZE);
-       if (rc)
-               return rc;
-
-       kvm_devices = (void *) total_memory_size;
-
-       kvm_root = root_device_register("kvm_s390");
-       if (IS_ERR(kvm_root)) {
-               rc = PTR_ERR(kvm_root);
-               printk(KERN_ERR "Could not register kvm_s390 root device");
-               vmem_remove_mapping(total_memory_size, PAGE_SIZE);
-               return rc;
-       }
-
-       INIT_WORK(&hotplug_work, hotplug_devices);
-
-       irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
-       register_external_irq(EXT_IRQ_CP_SERVICE, kvm_extint_handler);
-
-       scan_devices();
-       return 0;
-}
-
-/* code for early console output with virtio_console */
-static int early_put_chars(u32 vtermno, const char *buf, int count)
-{
-       char scratch[17];
-       unsigned int len = count;
-
-       if (len > sizeof(scratch) - 1)
-               len = sizeof(scratch) - 1;
-       scratch[len] = '\0';
-       memcpy(scratch, buf, len);
-       kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch));
-       return len;
-}
-
-static int __init s390_virtio_console_init(void)
-{
-       if (sclp.has_vt220 || sclp.has_linemode)
-               return -ENODEV;
-       return virtio_cons_early_init(early_put_chars);
-}
-console_initcall(s390_virtio_console_init);
-
-
-/*
- * We do this after core stuff, but before the drivers.
- */
-postcore_initcall(kvm_devices_init);
index d47b527b25dd0423fe23630fdab6007ce0a7bd33..31f2bb9d71461900bec98a3049ed7495b4ba53d9 100644 (file)
@@ -1046,8 +1046,6 @@ typedef enum {
 
 typedef uint8_t ahd_mode_state;
 
-typedef void ahd_callback_t (void *);
-
 struct ahd_completion
 {
        uint16_t        tag;
@@ -1122,8 +1120,7 @@ struct ahd_softc {
        /*
         * Timer handles for timer driven callbacks.
         */
-       ahd_timer_t               reset_timer;
-       ahd_timer_t               stat_timer;
+       struct timer_list       stat_timer;
 
        /*
         * Statistics.
index 95d8f25cbccab7056dc4c7967814cd5932fd3507..b560f396ee99c6665013283059ef8137be1e927e 100644 (file)
@@ -207,7 +207,7 @@ static void         ahd_add_scb_to_free_list(struct ahd_softc *ahd,
 static u_int           ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
                                     u_int prev, u_int next, u_int tid);
 static void            ahd_reset_current_bus(struct ahd_softc *ahd);
-static ahd_callback_t  ahd_stat_timer;
+static void            ahd_stat_timer(struct timer_list *t);
 #ifdef AHD_DUMP_SEQ
 static void            ahd_dumpseq(struct ahd_softc *ahd);
 #endif
@@ -6104,8 +6104,7 @@ ahd_alloc(void *platform_arg, char *name)
        ahd->bugs = AHD_BUGNONE;
        ahd->flags = AHD_SPCHK_ENB_A|AHD_RESET_BUS_A|AHD_TERM_ENB_A
                   | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A;
-       ahd_timer_init(&ahd->reset_timer);
-       ahd_timer_init(&ahd->stat_timer);
+       timer_setup(&ahd->stat_timer, ahd_stat_timer, 0);
        ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT;
        ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT;
        ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT;
@@ -6235,8 +6234,7 @@ ahd_shutdown(void *arg)
        /*
         * Stop periodic timer callbacks.
         */
-       ahd_timer_stop(&ahd->reset_timer);
-       ahd_timer_stop(&ahd->stat_timer);
+       del_timer_sync(&ahd->stat_timer);
 
        /* This will reset most registers to 0, but not all */
        ahd_reset(ahd, /*reinit*/FALSE);
@@ -7039,20 +7037,11 @@ static const char *termstat_strings[] = {
 };
 
 /***************************** Timer Facilities *******************************/
-#define ahd_timer_init init_timer
-#define ahd_timer_stop del_timer_sync
-typedef void ahd_linux_callback_t (u_long);
-
 static void
-ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
+ahd_timer_reset(struct timer_list *timer, int usec)
 {
-       struct ahd_softc *ahd;
-
-       ahd = (struct ahd_softc *)arg;
        del_timer(timer);
-       timer->data = (u_long)arg;
        timer->expires = jiffies + (usec * HZ)/1000000;
-       timer->function = (ahd_linux_callback_t*)func;
        add_timer(timer);
 }
 
@@ -7279,8 +7268,7 @@ ahd_init(struct ahd_softc *ahd)
        }
 init_done:
        ahd_restart(ahd);
-       ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US,
-                       ahd_stat_timer, ahd);
+       ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US);
        return (0);
 }
 
@@ -8878,9 +8866,9 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
 
 /**************************** Statistics Processing ***************************/
 static void
-ahd_stat_timer(void *arg)
+ahd_stat_timer(struct timer_list *t)
 {
-       struct  ahd_softc *ahd = arg;
+       struct  ahd_softc *ahd = from_timer(ahd, t, stat_timer);
        u_long  s;
        int     enint_coal;
        
@@ -8907,8 +8895,7 @@ ahd_stat_timer(void *arg)
        ahd->cmdcmplt_bucket = (ahd->cmdcmplt_bucket+1) & (AHD_STAT_BUCKETS-1);
        ahd->cmdcmplt_total -= ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket];
        ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket] = 0;
-       ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US,
-                       ahd_stat_timer, ahd);
+       ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US);
        ahd_unlock(ahd, &s);
 }
 
index 728193a42e6e7a9e7cffab30332b5944e8c183cb..8a8b7ae7aed3ec74338a3d80ef8d8db2f3edfe2e 100644 (file)
@@ -203,9 +203,6 @@ int ahd_dmamap_unload(struct ahd_softc *, bus_dma_tag_t, bus_dmamap_t);
  */
 #define ahd_dmamap_sync(ahd, dma_tag, dmamap, offset, len, op)
 
-/************************** Timer DataStructures ******************************/
-typedef struct timer_list ahd_timer_t;
-
 /********************************** Includes **********************************/
 #ifdef CONFIG_AIC79XX_REG_PRETTY_PRINT
 #define AIC_DEBUG_REGISTERS 1
@@ -214,10 +211,6 @@ typedef struct timer_list ahd_timer_t;
 #endif
 #include "aic79xx.h"
 
-/***************************** Timer Facilities *******************************/
-#define ahd_timer_init init_timer
-#define ahd_timer_stop del_timer_sync
-
 /***************************** SMP support ************************************/
 #include <linux/spinlock.h>
 
index f2671a8fa7e3358f304c539e7431d73733b95258..7cbc7213b2b23a8a3b751e846396e427762666fd 100644 (file)
@@ -1178,8 +1178,7 @@ static void asd_start_scb_timers(struct list_head *list)
        struct asd_ascb *ascb;
        list_for_each_entry(ascb, list, list) {
                if (!ascb->uldd_timer) {
-                       ascb->timer.data = (unsigned long) ascb;
-                       ascb->timer.function = asd_ascb_timedout;
+                       ascb->timer.function = (TIMER_FUNC_TYPE)asd_ascb_timedout;
                        ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
                        add_timer(&ascb->timer);
                }
index 8c1c28239e9307bfd5f30aadad0f2ba852d961c8..8f147e720cfdfe54234eb36a0a8633620276086b 100644 (file)
@@ -291,8 +291,7 @@ static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
        INIT_LIST_HEAD(&ascb->list);
        ascb->scb = ascb->dma_scb.vaddr;
        ascb->ha = asd_ha;
-       ascb->timer.function = NULL;
-       init_timer(&ascb->timer);
+       timer_setup(&ascb->timer, NULL, 0);
        ascb->tc_index = -1;
 }
 
@@ -392,7 +391,7 @@ void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
 void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
 int  asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask);
 
-void asd_ascb_timedout(unsigned long data);
+void asd_ascb_timedout(struct timer_list *t);
 int  asd_chip_hardrst(struct asd_ha_struct *asd_ha);
 
 #endif
index fdac7c2fef379bdddd6570d1229bada750c6643b..22873ce8bbfaaf3b97c8d169e251eff8fdc50203 100644 (file)
@@ -866,12 +866,12 @@ void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
  * Upper layers can implement their own timeout function, say to free
  * resources they have with this SCB, and then call this one at the
  * end of their timeout function.  To do this, one should initialize
- * the ascb->timer.{function, data, expires} prior to calling the post
+ * the ascb->timer.{function, expires} prior to calling the post
  * function. The timer is started by the post function.
  */
-void asd_ascb_timedout(unsigned long data)
+void asd_ascb_timedout(struct timer_list *t)
 {
-       struct asd_ascb *ascb = (void *) data;
+       struct asd_ascb *ascb = from_timer(ascb, t, timer);
        struct asd_seq_data *seq = &ascb->ha->seq;
        unsigned long flags;
 
index d4c35df3d4ae600f9e5d0d7a02ed547f4c8ff905..4637119c09d8aad052c566cf6e9fb2d16c7e87f3 100644 (file)
 static int asd_enqueue_internal(struct asd_ascb *ascb,
                void (*tasklet_complete)(struct asd_ascb *,
                                         struct done_list_struct *),
-                               void (*timed_out)(unsigned long))
+                               void (*timed_out)(struct timer_list *t))
 {
        int res;
 
        ascb->tasklet_complete = tasklet_complete;
        ascb->uldd_timer = 1;
 
-       ascb->timer.data = (unsigned long) ascb;
-       ascb->timer.function = timed_out;
+       ascb->timer.function = (TIMER_FUNC_TYPE)timed_out;
        ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
 
        add_timer(&ascb->timer);
@@ -87,9 +86,9 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
        asd_ascb_free(ascb);
 }
 
-static void asd_clear_nexus_timedout(unsigned long data)
+static void asd_clear_nexus_timedout(struct timer_list *t)
 {
-       struct asd_ascb *ascb = (void *)data;
+       struct asd_ascb *ascb = from_timer(ascb, t, timer);
        struct tasklet_completion_status *tcs = ascb->uldd_task;
 
        ASD_DPRINTK("%s: here\n", __func__);
@@ -261,9 +260,9 @@ static int asd_clear_nexus_index(struct sas_task *task)
 
 /* ---------- TMFs ---------- */
 
-static void asd_tmf_timedout(unsigned long data)
+static void asd_tmf_timedout(struct timer_list *t)
 {
-       struct asd_ascb *ascb = (void *) data;
+       struct asd_ascb *ascb = from_timer(ascb, t, timer);
        struct tasklet_completion_status *tcs = ascb->uldd_task;
 
        ASD_DPRINTK("tmf timed out\n");
index b4542e7e2ad5b77cb910f25554ba98d3663fb1cb..d8bd6f2c9c830a837e76b2dabddb3f915afc4943 100644 (file)
@@ -5230,12 +5230,11 @@ static void beiscsi_eqd_update_work(struct work_struct *work)
                              msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL));
 }
 
-static void beiscsi_hw_tpe_check(unsigned long ptr)
+static void beiscsi_hw_tpe_check(struct timer_list *t)
 {
-       struct beiscsi_hba *phba;
+       struct beiscsi_hba *phba = from_timer(phba, t, hw_check);
        u32 wait;
 
-       phba = (struct beiscsi_hba *)ptr;
        /* if not TPE, do nothing */
        if (!beiscsi_detect_tpe(phba))
                return;
@@ -5248,11 +5247,10 @@ static void beiscsi_hw_tpe_check(unsigned long ptr)
                           msecs_to_jiffies(wait));
 }
 
-static void beiscsi_hw_health_check(unsigned long ptr)
+static void beiscsi_hw_health_check(struct timer_list *t)
 {
-       struct beiscsi_hba *phba;
+       struct beiscsi_hba *phba = from_timer(phba, t, hw_check);
 
-       phba = (struct beiscsi_hba *)ptr;
        beiscsi_detect_ue(phba);
        if (beiscsi_detect_ue(phba)) {
                __beiscsi_log(phba, KERN_ERR,
@@ -5264,7 +5262,7 @@ static void beiscsi_hw_health_check(unsigned long ptr)
                if (!test_bit(BEISCSI_HBA_UER_SUPP, &phba->state))
                        return;
                /* modify this timer to check TPE */
-               phba->hw_check.function = beiscsi_hw_tpe_check;
+               phba->hw_check.function = (TIMER_FUNC_TYPE)beiscsi_hw_tpe_check;
        }
 
        mod_timer(&phba->hw_check,
@@ -5351,7 +5349,7 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba)
         * Timer function gets modified for TPE detection.
         * Always reinit to do health check first.
         */
-       phba->hw_check.function = beiscsi_hw_health_check;
+       phba->hw_check.function = (TIMER_FUNC_TYPE)beiscsi_hw_health_check;
        mod_timer(&phba->hw_check,
                  jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
        return 0;
@@ -5708,9 +5706,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
         * Start UE detection here. UE before this will cause stall in probe
         * and eventually fail the probe.
         */
-       init_timer(&phba->hw_check);
-       phba->hw_check.function = beiscsi_hw_health_check;
-       phba->hw_check.data = (unsigned long)phba;
+       timer_setup(&phba->hw_check, beiscsi_hw_health_check, 0);
        mod_timer(&phba->hw_check,
                  jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
index 6844ba36161638d995f3d5d5135c160fc54bc9ed..e6b9de7d41ac08719835dc06ba6bcbd0b00df8fc 100644 (file)
@@ -823,7 +823,7 @@ static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev)
 
        skb_queue_head_init(&port->fcoe_pending_queue);
        port->fcoe_pending_queue_active = 0;
-       setup_timer(&port->timer, fcoe_queue_timer, (unsigned long) lport);
+       timer_setup(&port->timer, fcoe_queue_timer, 0);
 
        fcoe_link_speed_update(lport);
 
@@ -845,9 +845,9 @@ static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev)
        return 0;
 }
 
-static void bnx2fc_destroy_timer(unsigned long data)
+static void bnx2fc_destroy_timer(struct timer_list *t)
 {
-       struct bnx2fc_hba *hba = (struct bnx2fc_hba *)data;
+       struct bnx2fc_hba *hba = from_timer(hba, t, destroy_timer);
 
        printk(KERN_ERR PFX "ERROR:bnx2fc_destroy_timer - "
               "Destroy compl not received!!\n");
@@ -1946,11 +1946,10 @@ static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba)
 {
        if (test_and_clear_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) {
                if (bnx2fc_send_fw_fcoe_destroy_msg(hba) == 0) {
-                       init_timer(&hba->destroy_timer);
+                       timer_setup(&hba->destroy_timer, bnx2fc_destroy_timer,
+                                   0);
                        hba->destroy_timer.expires = BNX2FC_FW_TIMEOUT +
                                                                jiffies;
-                       hba->destroy_timer.function = bnx2fc_destroy_timer;
-                       hba->destroy_timer.data = (unsigned long)hba;
                        add_timer(&hba->destroy_timer);
                        wait_event_interruptible(hba->destroy_wait,
                                        test_bit(BNX2FC_FLAG_DESTROY_CMPL,
index 89ef1a1678d192d291dd5de4efb14fd537ac7aa3..663a63d4dae4dca425f39639d38308eb90e37f77 100644 (file)
@@ -858,7 +858,7 @@ extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba,
                               struct bnx2i_endpoint *ep);
 extern void bnx2i_free_qp_resc(struct bnx2i_hba *hba,
                               struct bnx2i_endpoint *ep);
-extern void bnx2i_ep_ofld_timer(unsigned long data);
+extern void bnx2i_ep_ofld_timer(struct timer_list *t);
 extern struct bnx2i_endpoint *bnx2i_find_ep_in_ofld_list(
                struct bnx2i_hba *hba, u32 iscsi_cid);
 extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list(
index 42921dbba9272f793a2a4a483e727dfa78809e4b..61a93994d5ed210b8fca4905871b95a6c98b4329 100644 (file)
@@ -698,9 +698,9 @@ void bnx2i_update_iscsi_conn(struct iscsi_conn *conn)
  *
  * routine to handle connection offload/destroy request timeout
  */
-void bnx2i_ep_ofld_timer(unsigned long data)
+void bnx2i_ep_ofld_timer(struct timer_list *t)
 {
-       struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) data;
+       struct bnx2i_endpoint *ep = from_timer(ep, t, ofld_timer);
 
        if (ep->state == EP_STATE_OFLD_START) {
                printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n");
index 03c104b47f31c98670d9a80d64e0b986d707d9f0..de0a507577ef56bc90330c8c0b532086823f1e85 100644 (file)
@@ -1611,9 +1611,8 @@ static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn)
         * this should normally not sleep for a long time so it should
         * not disrupt the caller.
         */
+       timer_setup(&bnx2i_conn->ep->ofld_timer, bnx2i_ep_ofld_timer, 0);
        bnx2i_conn->ep->ofld_timer.expires = 1 * HZ + jiffies;
-       bnx2i_conn->ep->ofld_timer.function = bnx2i_ep_ofld_timer;
-       bnx2i_conn->ep->ofld_timer.data = (unsigned long) bnx2i_conn->ep;
        add_timer(&bnx2i_conn->ep->ofld_timer);
        /* update iSCSI context for this conn, wait for CNIC to complete */
        wait_event_interruptible(bnx2i_conn->ep->ofld_wait,
@@ -1729,10 +1728,8 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
        }
 
        ep->state = EP_STATE_CLEANUP_START;
-       init_timer(&ep->ofld_timer);
+       timer_setup(&ep->ofld_timer, bnx2i_ep_ofld_timer, 0);
        ep->ofld_timer.expires = hba->conn_ctx_destroy_tmo + jiffies;
-       ep->ofld_timer.function = bnx2i_ep_ofld_timer;
-       ep->ofld_timer.data = (unsigned long) ep;
        add_timer(&ep->ofld_timer);
 
        bnx2i_ep_destroy_list_add(hba, ep);
@@ -1835,10 +1832,8 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
        bnx2i_ep->state = EP_STATE_OFLD_START;
        bnx2i_ep_ofld_list_add(hba, bnx2i_ep);
 
-       init_timer(&bnx2i_ep->ofld_timer);
+       timer_setup(&bnx2i_ep->ofld_timer, bnx2i_ep_ofld_timer, 0);
        bnx2i_ep->ofld_timer.expires = 2 * HZ + jiffies;
-       bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
-       bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
        add_timer(&bnx2i_ep->ofld_timer);
 
        if (bnx2i_send_conn_ofld_req(hba, bnx2i_ep)) {
@@ -2054,10 +2049,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
                session = conn->session;
        }
 
-       init_timer(&bnx2i_ep->ofld_timer);
+       timer_setup(&bnx2i_ep->ofld_timer, bnx2i_ep_ofld_timer, 0);
        bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies;
-       bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
-       bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
        add_timer(&bnx2i_ep->ofld_timer);
 
        if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
index 5be0086142cac6991598cd9099522212709a216c..0bd1131b6cc940fd731f754eb31f1b7672ba544e 100644 (file)
@@ -3347,9 +3347,10 @@ csio_mberr_worker(void *data)
  *
  **/
 static void
-csio_hw_mb_timer(uintptr_t data)
+csio_hw_mb_timer(struct timer_list *t)
 {
-       struct csio_hw *hw = (struct csio_hw *)data;
+       struct csio_mbm *mbm = from_timer(mbm, t, timer);
+       struct csio_hw *hw = mbm->hw;
        struct csio_mb *mbp = NULL;
 
        spin_lock_irq(&hw->lock);
@@ -3715,9 +3716,9 @@ csio_mgmt_req_lookup(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req)
  * Return - none.
  */
 static void
-csio_mgmt_tmo_handler(uintptr_t data)
+csio_mgmt_tmo_handler(struct timer_list *t)
 {
-       struct csio_mgmtm *mgmtm = (struct csio_mgmtm *) data;
+       struct csio_mgmtm *mgmtm = from_timer(mgmtm, t, mgmt_timer);
        struct list_head *tmp;
        struct csio_ioreq *io_req;
 
@@ -3797,11 +3798,7 @@ csio_mgmtm_cleanup(struct csio_mgmtm *mgmtm)
 static int
 csio_mgmtm_init(struct csio_mgmtm *mgmtm, struct csio_hw *hw)
 {
-       struct timer_list *timer = &mgmtm->mgmt_timer;
-
-       init_timer(timer);
-       timer->function = csio_mgmt_tmo_handler;
-       timer->data = (unsigned long)mgmtm;
+       timer_setup(&mgmtm->mgmt_timer, csio_mgmt_tmo_handler, 0);
 
        INIT_LIST_HEAD(&mgmtm->active_q);
        INIT_LIST_HEAD(&mgmtm->cbfn_q);
index 9451787ca7f299715a97e34692315d69e7968910..abcedfbcecda26ddec8d0feb87f1af633c6011d3 100644 (file)
@@ -1644,13 +1644,10 @@ csio_mb_cancel_all(struct csio_hw *hw, struct list_head *cbfn_q)
  */
 int
 csio_mbm_init(struct csio_mbm *mbm, struct csio_hw *hw,
-             void (*timer_fn)(uintptr_t))
+             void (*timer_fn)(struct timer_list *))
 {
-       struct timer_list *timer = &mbm->timer;
-
-       init_timer(timer);
-       timer->function = timer_fn;
-       timer->data = (unsigned long)hw;
+       mbm->hw = hw;
+       timer_setup(&mbm->timer, timer_fn, 0);
 
        INIT_LIST_HEAD(&mbm->req_q);
        INIT_LIST_HEAD(&mbm->cbfn_q);
index 1bc82d0bc260259a84f16a03e2049a19844a85f2..a6823df730154a10e74a5fb1084ec869eb048518 100644 (file)
@@ -137,6 +137,7 @@ struct csio_mbm {
        uint32_t                a_mbox;                 /* Async mbox num */
        uint32_t                intr_idx;               /* Interrupt index */
        struct timer_list       timer;                  /* Mbox timer */
+       struct csio_hw          *hw;                    /* Hardware pointer */
        struct list_head        req_q;                  /* Mbox request queue */
        struct list_head        cbfn_q;                 /* Mbox completion q */
        struct csio_mb          *mcurrent;              /* Current mailbox */
@@ -252,7 +253,7 @@ void csio_mb_process_portparams_rsp(struct csio_hw *hw, struct csio_mb *mbp,
 
 /* MB module functions */
 int csio_mbm_init(struct csio_mbm *, struct csio_hw *,
-                           void (*)(uintptr_t));
+                           void (*)(struct timer_list *));
 void csio_mbm_exit(struct csio_mbm *);
 void csio_mb_intr_enable(struct csio_hw *);
 void csio_mb_intr_disable(struct csio_hw *);
index 7b09e7ddf35e7b99c2c87a64e42b369ebd7dbed1..babd79361a461097f93dedba4fb400d8caecf390 100644 (file)
@@ -545,10 +545,10 @@ static int act_open_rpl_status_to_errno(int status)
        }
 }
 
-static void act_open_retry_timer(unsigned long data)
+static void act_open_retry_timer(struct timer_list *t)
 {
+       struct cxgbi_sock *csk = from_timer(csk, t, retry_timer);
        struct sk_buff *skb;
-       struct cxgbi_sock *csk = (struct cxgbi_sock *)data;
 
        log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK,
                "csk 0x%p,%u,0x%lx,%u.\n",
@@ -586,8 +586,8 @@ static int do_act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
        cxgbi_sock_get(csk);
        spin_lock_bh(&csk->lock);
        if (rpl->status == CPL_ERR_CONN_EXIST &&
-           csk->retry_timer.function != act_open_retry_timer) {
-               csk->retry_timer.function = act_open_retry_timer;
+           csk->retry_timer.function != (TIMER_FUNC_TYPE)act_open_retry_timer) {
+               csk->retry_timer.function = (TIMER_FUNC_TYPE)act_open_retry_timer;
                mod_timer(&csk->retry_timer, jiffies + HZ / 2);
        } else
                cxgbi_sock_fail_act_open(csk,
index 1d02cf9fe06c5e941e5d1a76254f86ce658fc04b..1bef2724eb783d7441b98e224eea3668f0792f28 100644 (file)
@@ -872,10 +872,10 @@ static int act_open_rpl_status_to_errno(int status)
        }
 }
 
-static void csk_act_open_retry_timer(unsigned long data)
+static void csk_act_open_retry_timer(struct timer_list *t)
 {
        struct sk_buff *skb = NULL;
-       struct cxgbi_sock *csk = (struct cxgbi_sock *)data;
+       struct cxgbi_sock *csk = from_timer(csk, t, retry_timer);
        struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev);
        void (*send_act_open_func)(struct cxgbi_sock *, struct sk_buff *,
                                   struct l2t_entry *);
@@ -963,8 +963,8 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb)
        spin_lock_bh(&csk->lock);
 
        if (status == CPL_ERR_CONN_EXIST &&
-           csk->retry_timer.function != csk_act_open_retry_timer) {
-               csk->retry_timer.function = csk_act_open_retry_timer;
+           csk->retry_timer.function != (TIMER_FUNC_TYPE)csk_act_open_retry_timer) {
+               csk->retry_timer.function = (TIMER_FUNC_TYPE)csk_act_open_retry_timer;
                mod_timer(&csk->retry_timer, jiffies + HZ / 2);
        } else
                cxgbi_sock_fail_act_open(csk,
index 512c8f1ea5b06efd4d42c2eed805be9e6a23d533..a61a152136a3c3dd9716157131d057245a62f887 100644 (file)
@@ -572,7 +572,7 @@ static struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev)
        kref_init(&csk->refcnt);
        skb_queue_head_init(&csk->receive_queue);
        skb_queue_head_init(&csk->write_queue);
-       setup_timer(&csk->retry_timer, NULL, (unsigned long)csk);
+       timer_setup(&csk->retry_timer, NULL, 0);
        rwlock_init(&csk->callback_lock);
        csk->cdev = cdev;
        csk->flags = 0;
index 5ee7f44cf869b906397447a0572b1b227e8951a1..60ef8df42b95c95f671cba4a0d9223161813b20c 100644 (file)
@@ -395,7 +395,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
                struct ScsiReqBlk *srb);
 static void set_xfer_rate(struct AdapterCtlBlk *acb,
                struct DeviceCtlBlk *dcb);
-static void waiting_timeout(unsigned long ptr);
+static void waiting_timeout(struct timer_list *t);
 
 
 /*---------------------------------------------------------------------------
@@ -857,9 +857,6 @@ static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to)
 {
        if (timer_pending(&acb->waiting_timer))
                return;
-       init_timer(&acb->waiting_timer);
-       acb->waiting_timer.function = waiting_timeout;
-       acb->waiting_timer.data = (unsigned long) acb;
        if (time_before(jiffies + to, acb->last_reset - HZ / 2))
                acb->waiting_timer.expires =
                    acb->last_reset - HZ / 2 + 1;
@@ -936,10 +933,10 @@ static void waiting_process_next(struct AdapterCtlBlk *acb)
 
 
 /* Wake up waiting queue */
-static void waiting_timeout(unsigned long ptr)
+static void waiting_timeout(struct timer_list *t)
 {
        unsigned long flags;
-       struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr;
+       struct AdapterCtlBlk *acb = from_timer(acb, t, waiting_timer);
        dprintkdbg(DBG_1,
                "waiting_timeout: Queue woken up by timer. acb=%p\n", acb);
        DC395x_LOCK_IO(acb->scsi_host, flags);
@@ -4366,8 +4363,8 @@ static void adapter_init_params(struct AdapterCtlBlk *acb)
        INIT_LIST_HEAD(&acb->srb_free_list);
        /*  temp SRB for Q tag used or abort command used  */
        acb->tmp_srb = &acb->srb;
-       init_timer(&acb->waiting_timer);
-       init_timer(&acb->selto_timer);
+       timer_setup(&acb->waiting_timer, waiting_timeout, 0);
+       timer_setup(&acb->selto_timer, NULL, 0);
 
        acb->srb_count = DC395x_MAX_SRB_CNT;
 
index 85f9a3eba387c47b37e7555d3a183aafa556a742..5cc09dce4d25080d44c442821034dd5297cdff80 100644 (file)
@@ -754,7 +754,7 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
 
        skb_queue_head_init(&port->fcoe_pending_queue);
        port->fcoe_pending_queue_active = 0;
-       setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport);
+       timer_setup(&port->timer, fcoe_queue_timer, 0);
 
        fcoe_link_speed_update(lport);
 
index 375c536cbc688f0e5b9467ca65e9885b96ea130d..1ba5f51713a3216353991e1d7aa54217f66ab851 100644 (file)
@@ -455,9 +455,11 @@ EXPORT_SYMBOL_GPL(fcoe_check_wait_queue);
  *
  * Calls fcoe_check_wait_queue on timeout
  */
-void fcoe_queue_timer(ulong lport)
+void fcoe_queue_timer(struct timer_list *t)
 {
-       fcoe_check_wait_queue((struct fc_lport *)lport, NULL);
+       struct fcoe_port *port = from_timer(port, t, timer);
+
+       fcoe_check_wait_queue(port->lport, NULL);
 }
 EXPORT_SYMBOL_GPL(fcoe_queue_timer);
 
index a4473356a9dc2a4fcfd1f4d34d3096ba50797b5f..c35f05c4c6bbbbb5e029201dc36564f322bb451a 100644 (file)
@@ -3705,7 +3705,7 @@ static void gdth_log_event(gdth_evt_data *dvr, char *buffer)
 #ifdef GDTH_STATISTICS
 static u8      gdth_timer_running;
 
-static void gdth_timeout(unsigned long data)
+static void gdth_timeout(struct timer_list *unused)
 {
     u32 i;
     Scsi_Cmnd *nscp;
@@ -3743,8 +3743,6 @@ static void gdth_timer_init(void)
        gdth_timer_running = 1;
        TRACE2(("gdth_detect(): Initializing timer !\n"));
        gdth_timer.expires = jiffies + HZ;
-       gdth_timer.data = 0L;
-       gdth_timer.function = gdth_timeout;
        add_timer(&gdth_timer);
 }
 #else
@@ -5165,7 +5163,7 @@ static int __init gdth_init(void)
        /* initializations */
        gdth_polling = TRUE;
        gdth_clear_events();
-       init_timer(&gdth_timer);
+       timer_setup(&gdth_timer, gdth_timeout, 0);
 
        /* As default we do not probe for EISA or ISA controllers */
        if (probe_eisa_isa) {
index 07f4a4cfbec1b3275280eb0193009fbf3e72b264..15692ea05cedd401917b6521fd8805e94897c2e4 100644 (file)
@@ -103,7 +103,6 @@ struct hisi_sas_phy {
        struct hisi_sas_port    *port;
        struct asd_sas_phy      sas_phy;
        struct sas_identify     identify;
-       struct timer_list       timer;
        struct work_struct      phyup_ws;
        u64             port_id; /* from hw */
        u64             dev_sas_addr;
index 16664f2e15fbadd77d30439d723f1d972d0efbbf..37c838be47577e26cb8c88fc6b402c142cc5c1e7 100644 (file)
@@ -627,7 +627,6 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
 
        phy->hisi_hba = hisi_hba;
        phy->port = NULL;
-       init_timer(&phy->timer);
        sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0;
        sas_phy->class = SAS;
        sas_phy->iproto = SAS_PROTOCOL_ALL;
@@ -792,9 +791,10 @@ static void hisi_sas_task_done(struct sas_task *task)
        complete(&task->slow_task->completion);
 }
 
-static void hisi_sas_tmf_timedout(unsigned long data)
+static void hisi_sas_tmf_timedout(struct timer_list *t)
 {
-       struct sas_task *task = (struct sas_task *)data;
+       struct sas_task_slow *slow = from_timer(slow, t, timer);
+       struct sas_task *task = slow->task;
        unsigned long flags;
 
        spin_lock_irqsave(&task->task_state_lock, flags);
@@ -833,8 +833,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
                }
                task->task_done = hisi_sas_task_done;
 
-               task->slow_task->timer.data = (unsigned long) task;
-               task->slow_task->timer.function = hisi_sas_tmf_timedout;
+               task->slow_task->timer.function = (TIMER_FUNC_TYPE)hisi_sas_tmf_timedout;
                task->slow_task->timer.expires = jiffies + TASK_TIMEOUT*HZ;
                add_timer(&task->slow_task->timer);
 
@@ -1447,8 +1446,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
        task->dev = device;
        task->task_proto = device->tproto;
        task->task_done = hisi_sas_task_done;
-       task->slow_task->timer.data = (unsigned long)task;
-       task->slow_task->timer.function = hisi_sas_tmf_timedout;
+       task->slow_task->timer.function = (TIMER_FUNC_TYPE)hisi_sas_tmf_timedout;
        task->slow_task->timer.expires = jiffies + msecs_to_jiffies(110);
        add_timer(&task->slow_task->timer);
 
@@ -1877,7 +1875,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
        hisi_hba->shost = shost;
        SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
 
-       init_timer(&hisi_hba->timer);
+       timer_setup(&hisi_hba->timer, NULL, 0);
 
        if (hisi_sas_get_fw_info(hisi_hba) < 0)
                goto err_out;
index 08eca20b0b81812a8ef32ac23d47a5ccbbb4f5ab..9385554e43a6095537f2852f02960fa0b8dbad92 100644 (file)
@@ -807,9 +807,9 @@ static void phy_hard_reset_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
        start_phy_v1_hw(hisi_hba, phy_no);
 }
 
-static void start_phys_v1_hw(unsigned long data)
+static void start_phys_v1_hw(struct timer_list *t)
 {
-       struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+       struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer);
        int i;
 
        for (i = 0; i < hisi_hba->n_phy; i++) {
@@ -828,7 +828,7 @@ static void phys_init_v1_hw(struct hisi_hba *hisi_hba)
                hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK);
        }
 
-       setup_timer(timer, start_phys_v1_hw, (unsigned long)hisi_hba);
+       timer_setup(timer, start_phys_v1_hw, 0);
        mod_timer(timer, jiffies + HZ);
 }
 
index 779af979b6db93380386210c4a19f6231ecf8fc1..b1f097dabd0187f55b8990b0939dda6614fcba8f 100644 (file)
@@ -728,7 +728,7 @@ enum {
 #define ERR_ON_RX_PHASE(err_phase) (err_phase == 0x10 || \
                err_phase == 0x20 || err_phase == 0x40)
 
-static void link_timeout_disable_link(unsigned long data);
+static void link_timeout_disable_link(struct timer_list *t);
 
 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 {
@@ -1270,9 +1270,9 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
                         upper_32_bits(hisi_hba->initial_fis_dma));
 }
 
-static void link_timeout_enable_link(unsigned long data)
+static void link_timeout_enable_link(struct timer_list *t)
 {
-       struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+       struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer);
        int i, reg_val;
 
        for (i = 0; i < hisi_hba->n_phy; i++) {
@@ -1287,13 +1287,13 @@ static void link_timeout_enable_link(unsigned long data)
                }
        }
 
-       hisi_hba->timer.function = link_timeout_disable_link;
+       hisi_hba->timer.function = (TIMER_FUNC_TYPE)link_timeout_disable_link;
        mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(900));
 }
 
-static void link_timeout_disable_link(unsigned long data)
+static void link_timeout_disable_link(struct timer_list *t)
 {
-       struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+       struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer);
        int i, reg_val;
 
        reg_val = hisi_sas_read32(hisi_hba, PHY_STATE);
@@ -1308,14 +1308,13 @@ static void link_timeout_disable_link(unsigned long data)
                }
        }
 
-       hisi_hba->timer.function = link_timeout_enable_link;
+       hisi_hba->timer.function = (TIMER_FUNC_TYPE)link_timeout_enable_link;
        mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(100));
 }
 
 static void set_link_timer_quirk(struct hisi_hba *hisi_hba)
 {
-       hisi_hba->timer.data = (unsigned long)hisi_hba;
-       hisi_hba->timer.function = link_timeout_disable_link;
+       hisi_hba->timer.function = (TIMER_FUNC_TYPE)link_timeout_disable_link;
        hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000);
        add_timer(&hisi_hba->timer);
 }
@@ -2574,9 +2573,9 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
        return 0;
 }
 
-static void hisi_sas_internal_abort_quirk_timeout(unsigned long data)
+static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t)
 {
-       struct hisi_sas_slot *slot = (struct hisi_sas_slot *)data;
+       struct hisi_sas_slot *slot = from_timer(slot, t, internal_abort_timer);
        struct hisi_sas_port *port = slot->port;
        struct asd_sas_port *asd_sas_port;
        struct asd_sas_phy *sas_phy;
@@ -2619,8 +2618,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
        struct timer_list *timer = &slot->internal_abort_timer;
 
        /* setup the quirk timer */
-       setup_timer(timer, hisi_sas_internal_abort_quirk_timeout,
-                   (unsigned long)slot);
+       timer_setup(timer, hisi_sas_internal_abort_quirk_timeout, 0);
        /* Set the timeout to 10ms less than internal abort timeout */
        mod_timer(timer, jiffies + msecs_to_jiffies(100));
 
index 2e5fa9717be89acdcc3b1565c0b1c85a5ab089c1..3f2f0baf2a5edf234749fcab089648c7b14cae17 100644 (file)
@@ -1823,7 +1823,7 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
        hisi_hba->shost = shost;
        SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
 
-       init_timer(&hisi_hba->timer);
+       timer_setup(&hisi_hba->timer, NULL, 0);
 
        if (hisi_sas_get_fw_info(hisi_hba) < 0)
                goto err_out;
index b491af31a5f8e0289c1a3dea2f1a588ff4a3796e..0d2f7eb3acb6933b8b38c353c9f1b283c01350e4 100644 (file)
@@ -1393,8 +1393,9 @@ static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd,
  *
  * Called when an internally generated command times out
  **/
-static void ibmvfc_timeout(struct ibmvfc_event *evt)
+static void ibmvfc_timeout(struct timer_list *t)
 {
+       struct ibmvfc_event *evt = from_timer(evt, t, timer);
        struct ibmvfc_host *vhost = evt->vhost;
        dev_err(vhost->dev, "Command timed out (%p). Resetting connection\n", evt);
        ibmvfc_reset_host(vhost);
@@ -1424,12 +1425,10 @@ static int ibmvfc_send_event(struct ibmvfc_event *evt,
                BUG();
 
        list_add_tail(&evt->queue, &vhost->sent);
-       init_timer(&evt->timer);
+       timer_setup(&evt->timer, ibmvfc_timeout, 0);
 
        if (timeout) {
-               evt->timer.data = (unsigned long) evt;
                evt->timer.expires = jiffies + (timeout * HZ);
-               evt->timer.function = (void (*)(unsigned long))ibmvfc_timeout;
                add_timer(&evt->timer);
        }
 
@@ -3692,8 +3691,9 @@ static void ibmvfc_tgt_adisc_cancel_done(struct ibmvfc_event *evt)
  * out, reset the CRQ. When the ADISC comes back as cancelled,
  * log back into the target.
  **/
-static void ibmvfc_adisc_timeout(struct ibmvfc_target *tgt)
+static void ibmvfc_adisc_timeout(struct timer_list *t)
 {
+       struct ibmvfc_target *tgt = from_timer(tgt, t, timer);
        struct ibmvfc_host *vhost = tgt->vhost;
        struct ibmvfc_event *evt;
        struct ibmvfc_tmf *tmf;
@@ -3778,9 +3778,7 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt)
        if (timer_pending(&tgt->timer))
                mod_timer(&tgt->timer, jiffies + (IBMVFC_ADISC_TIMEOUT * HZ));
        else {
-               tgt->timer.data = (unsigned long) tgt;
                tgt->timer.expires = jiffies + (IBMVFC_ADISC_TIMEOUT * HZ);
-               tgt->timer.function = (void (*)(unsigned long))ibmvfc_adisc_timeout;
                add_timer(&tgt->timer);
        }
 
@@ -3912,7 +3910,7 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id)
        tgt->vhost = vhost;
        tgt->need_login = 1;
        tgt->cancel_key = vhost->task_set++;
-       init_timer(&tgt->timer);
+       timer_setup(&tgt->timer, ibmvfc_adisc_timeout, 0);
        kref_init(&tgt->kref);
        ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout);
        spin_lock_irqsave(vhost->host->host_lock, flags);
index 7d156b161482988367ac323f8182d177421d1163..17df76f0be3c5212798f106539ccea6883fbe495 100644 (file)
@@ -837,8 +837,9 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
  *
  * Called when an internally generated command times out
 */
-static void ibmvscsi_timeout(struct srp_event_struct *evt_struct)
+static void ibmvscsi_timeout(struct timer_list *t)
 {
+       struct srp_event_struct *evt_struct = from_timer(evt_struct, t, timer);
        struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
 
        dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
@@ -927,11 +928,9 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
         */
        list_add_tail(&evt_struct->list, &hostdata->sent);
 
-       init_timer(&evt_struct->timer);
+       timer_setup(&evt_struct->timer, ibmvscsi_timeout, 0);
        if (timeout) {
-               evt_struct->timer.data = (unsigned long) evt_struct;
                evt_struct->timer.expires = jiffies + (timeout * HZ);
-               evt_struct->timer.function = (void (*)(unsigned long))ibmvscsi_timeout;
                add_timer(&evt_struct->timer);
        }
 
index f838bd73befa8f3b2fe915b8bbbe1990c563de1f..d53429371127a4eb3ea76ce52dc2408ec05b9a11 100644 (file)
@@ -694,7 +694,7 @@ static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd,
        ipr_cmd->sibling = NULL;
        ipr_cmd->eh_comp = NULL;
        ipr_cmd->fast_done = fast_done;
-       init_timer(&ipr_cmd->timer);
+       timer_setup(&ipr_cmd->timer, NULL, 0);
 }
 
 /**
@@ -990,15 +990,14 @@ static void ipr_send_command(struct ipr_cmnd *ipr_cmd)
  **/
 static void ipr_do_req(struct ipr_cmnd *ipr_cmd,
                       void (*done) (struct ipr_cmnd *),
-                      void (*timeout_func) (struct ipr_cmnd *), u32 timeout)
+                      void (*timeout_func) (struct timer_list *), u32 timeout)
 {
        list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_pending_q);
 
        ipr_cmd->done = done;
 
-       ipr_cmd->timer.data = (unsigned long) ipr_cmd;
        ipr_cmd->timer.expires = jiffies + timeout;
-       ipr_cmd->timer.function = (void (*)(unsigned long))timeout_func;
+       ipr_cmd->timer.function = (TIMER_FUNC_TYPE)timeout_func;
 
        add_timer(&ipr_cmd->timer);
 
@@ -1080,7 +1079,7 @@ static void ipr_init_ioadl(struct ipr_cmnd *ipr_cmd, dma_addr_t dma_addr,
  *     none
  **/
 static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd,
-                                 void (*timeout_func) (struct ipr_cmnd *ipr_cmd),
+                                 void (*timeout_func) (struct timer_list *),
                                  u32 timeout)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
@@ -2664,8 +2663,9 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
  * Return value:
  *     none
  **/
-static void ipr_timeout(struct ipr_cmnd *ipr_cmd)
+static void ipr_timeout(struct timer_list *t)
 {
+       struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer);
        unsigned long lock_flags = 0;
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 
@@ -2696,8 +2696,9 @@ static void ipr_timeout(struct ipr_cmnd *ipr_cmd)
  * Return value:
  *     none
  **/
-static void ipr_oper_timeout(struct ipr_cmnd *ipr_cmd)
+static void ipr_oper_timeout(struct timer_list *t)
 {
+       struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer);
        unsigned long lock_flags = 0;
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 
@@ -5449,8 +5450,9 @@ static void ipr_bus_reset_done(struct ipr_cmnd *ipr_cmd)
  * Return value:
  *     none
  **/
-static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd)
+static void ipr_abort_timeout(struct timer_list *t)
 {
+       struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer);
        struct ipr_cmnd *reset_cmd;
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_cmd_pkt *cmd_pkt;
@@ -8271,8 +8273,9 @@ static int ipr_ioafp_identify_hrrq(struct ipr_cmnd *ipr_cmd)
  * Return value:
  *     none
  **/
-static void ipr_reset_timer_done(struct ipr_cmnd *ipr_cmd)
+static void ipr_reset_timer_done(struct timer_list *t)
 {
+       struct ipr_cmnd *ipr_cmd = from_timer(ipr_cmd, t, timer);
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        unsigned long lock_flags = 0;
 
@@ -8308,9 +8311,8 @@ static void ipr_reset_start_timer(struct ipr_cmnd *ipr_cmd,
        list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_pending_q);
        ipr_cmd->done = ipr_reset_ioa_job;
 
-       ipr_cmd->timer.data = (unsigned long) ipr_cmd;
        ipr_cmd->timer.expires = jiffies + timeout;
-       ipr_cmd->timer.function = (void (*)(unsigned long))ipr_reset_timer_done;
+       ipr_cmd->timer.function = (TIMER_FUNC_TYPE)ipr_reset_timer_done;
        add_timer(&ipr_cmd->timer);
 }
 
@@ -8394,9 +8396,8 @@ static int ipr_reset_next_stage(struct ipr_cmnd *ipr_cmd)
                }
        }
 
-       ipr_cmd->timer.data = (unsigned long) ipr_cmd;
        ipr_cmd->timer.expires = jiffies + stage_time * HZ;
-       ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
+       ipr_cmd->timer.function = (TIMER_FUNC_TYPE)ipr_oper_timeout;
        ipr_cmd->done = ipr_reset_ioa_job;
        add_timer(&ipr_cmd->timer);
 
@@ -8466,9 +8467,8 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
                return IPR_RC_JOB_CONTINUE;
        }
 
-       ipr_cmd->timer.data = (unsigned long) ipr_cmd;
        ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ);
-       ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
+       ipr_cmd->timer.function = (TIMER_FUNC_TYPE)ipr_oper_timeout;
        ipr_cmd->done = ipr_reset_ioa_job;
        add_timer(&ipr_cmd->timer);
        list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_pending_q);
index 609dafd661d1437a0287c7511d8e31f7c1e1c199..13b37cdffa8edbf02ce56a09e40a80ff1c7cc5f7 100644 (file)
@@ -958,9 +958,9 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost)
        return status;
 }
 
-static void phy_startup_timeout(unsigned long data)
+static void phy_startup_timeout(struct timer_list *t)
 {
-       struct sci_timer *tmr = (struct sci_timer *)data;
+       struct sci_timer *tmr = from_timer(tmr, t, timer);
        struct isci_host *ihost = container_of(tmr, typeof(*ihost), phy_timer);
        unsigned long flags;
        enum sci_status status;
@@ -1592,9 +1592,9 @@ static const struct sci_base_state sci_controller_state_table[] = {
        [SCIC_FAILED] = {}
 };
 
-static void controller_timeout(unsigned long data)
+static void controller_timeout(struct timer_list *t)
 {
-       struct sci_timer *tmr = (struct sci_timer *)data;
+       struct sci_timer *tmr = from_timer(tmr, t, timer);
        struct isci_host *ihost = container_of(tmr, typeof(*ihost), timer);
        struct sci_base_state_machine *sm = &ihost->sm;
        unsigned long flags;
@@ -1737,9 +1737,9 @@ static u8 max_spin_up(struct isci_host *ihost)
                             MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT);
 }
 
-static void power_control_timeout(unsigned long data)
+static void power_control_timeout(struct timer_list *t)
 {
-       struct sci_timer *tmr = (struct sci_timer *)data;
+       struct sci_timer *tmr = from_timer(tmr, t, timer);
        struct isci_host *ihost = container_of(tmr, typeof(*ihost), power_control.timer);
        struct isci_phy *iphy;
        unsigned long flags;
index 234ab46fce3346948300d9ae95364e33103792ee..680e3094767160b74398ee41ad98939bc856f177 100644 (file)
@@ -498,12 +498,10 @@ struct sci_timer {
 };
 
 static inline
-void sci_init_timer(struct sci_timer *tmr, void (*fn)(unsigned long))
+void sci_init_timer(struct sci_timer *tmr, void (*fn)(struct timer_list *t))
 {
-       tmr->timer.function = fn;
-       tmr->timer.data = (unsigned long) tmr;
        tmr->cancel = 0;
-       init_timer(&tmr->timer);
+       timer_setup(&tmr->timer, fn, 0);
 }
 
 static inline void sci_mod_timer(struct sci_timer *tmr, unsigned long msec)
index cb87b2ef7c92ab2ab5b25cbedbb594e85956eb05..1deca8c5a94f5645f6f14d60c303c65ac1258d2b 100644 (file)
@@ -315,9 +315,9 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
        return SCI_SUCCESS;
 }
 
-static void phy_sata_timeout(unsigned long data)
+static void phy_sata_timeout(struct timer_list *t)
 {
-       struct sci_timer *tmr = (struct sci_timer *)data;
+       struct sci_timer *tmr = from_timer(tmr, t, timer);
        struct isci_phy *iphy = container_of(tmr, typeof(*iphy), sata_timer);
        struct isci_host *ihost = iphy->owning_port->owning_controller;
        unsigned long flags;
index a4dd5c91508cc379b2a52ea0414e6508f720ce02..1df45f028ea7570841d1b4ae7303cd8cafeb2d20 100644 (file)
@@ -769,9 +769,9 @@ bool sci_port_link_detected(struct isci_port *iport, struct isci_phy *iphy)
        return true;
 }
 
-static void port_timeout(unsigned long data)
+static void port_timeout(struct timer_list *t)
 {
-       struct sci_timer *tmr = (struct sci_timer *)data;
+       struct sci_timer *tmr = from_timer(tmr, t, timer);
        struct isci_port *iport = container_of(tmr, typeof(*iport), timer);
        struct isci_host *ihost = iport->owning_controller;
        unsigned long flags;
index ac879745ef8007ab2a4973aff26e3c950e8f1dba..edb7be786c6501602195b25285dda78ceb9ea537 100644 (file)
@@ -319,10 +319,10 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost,
        return sci_port_configuration_agent_validate_ports(ihost, port_agent);
 }
 
-static void mpc_agent_timeout(unsigned long data)
+static void mpc_agent_timeout(struct timer_list *t)
 {
        u8 index;
-       struct sci_timer *tmr = (struct sci_timer *)data;
+       struct sci_timer *tmr = from_timer(tmr, t, timer);
        struct sci_port_configuration_agent *port_agent;
        struct isci_host *ihost;
        unsigned long flags;
@@ -654,10 +654,10 @@ static void sci_apc_agent_link_down(
 }
 
 /* configure the phys into ports when the timer fires */
-static void apc_agent_timeout(unsigned long data)
+static void apc_agent_timeout(struct timer_list *t)
 {
        u32 index;
-       struct sci_timer *tmr = (struct sci_timer *)data;
+       struct sci_timer *tmr = from_timer(tmr, t, timer);
        struct sci_port_configuration_agent *port_agent;
        struct isci_host *ihost;
        unsigned long flags;
index 772c35a5c49ef7899ce0ef65417f566390fea712..1a4e701a844966e4a7db873a3c2dfe3a58768fc2 100644 (file)
@@ -97,7 +97,7 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
 static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
 static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
 static void fc_fcp_recovery(struct fc_fcp_pkt *, u8 code);
-static void fc_fcp_timeout(unsigned long);
+static void fc_fcp_timeout(struct timer_list *);
 static void fc_fcp_rec(struct fc_fcp_pkt *);
 static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
 static void fc_fcp_rec_resp(struct fc_seq *, struct fc_frame *, void *);
@@ -155,8 +155,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp)
                fsp->lp = lport;
                fsp->xfer_ddp = FC_XID_UNKNOWN;
                refcount_set(&fsp->ref_cnt, 1);
-               init_timer(&fsp->timer);
-               fsp->timer.data = (unsigned long)fsp;
+               timer_setup(&fsp->timer, NULL, 0);
                INIT_LIST_HEAD(&fsp->list);
                spin_lock_init(&fsp->scsi_pkt_lock);
        } else {
@@ -1215,7 +1214,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
        fsp->seq_ptr = seq;
        fc_fcp_pkt_hold(fsp);   /* hold for fc_fcp_pkt_destroy */
 
-       setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp);
+       fsp->timer.function = (TIMER_FUNC_TYPE)fc_fcp_timeout;
        if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
                fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp));
 
@@ -1298,9 +1297,9 @@ static int fc_fcp_pkt_abort(struct fc_fcp_pkt *fsp)
  * fc_lun_reset_send() - Send LUN reset command
  * @data: The FCP packet that identifies the LUN to be reset
  */
-static void fc_lun_reset_send(unsigned long data)
+static void fc_lun_reset_send(struct timer_list *t)
 {
-       struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data;
+       struct fc_fcp_pkt *fsp = from_timer(fsp, t, timer);
        struct fc_lport *lport = fsp->lp;
 
        if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) {
@@ -1308,7 +1307,7 @@ static void fc_lun_reset_send(unsigned long data)
                        return;
                if (fc_fcp_lock_pkt(fsp))
                        return;
-               setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp);
+               fsp->timer.function = (TIMER_FUNC_TYPE)fc_lun_reset_send;
                fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp));
                fc_fcp_unlock_pkt(fsp);
        }
@@ -1334,7 +1333,7 @@ static int fc_lun_reset(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
        fsp->wait_for_comp = 1;
        init_completion(&fsp->tm_done);
 
-       fc_lun_reset_send((unsigned long)fsp);
+       fc_lun_reset_send(&fsp->timer);
 
        /*
         * wait for completion of reset
@@ -1431,9 +1430,9 @@ static void fc_fcp_cleanup(struct fc_lport *lport)
  * received we see if data was received recently. If it has been then we
  * continue waiting, otherwise, we abort the command.
  */
-static void fc_fcp_timeout(unsigned long data)
+static void fc_fcp_timeout(struct timer_list *t)
 {
-       struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data;
+       struct fc_fcp_pkt *fsp = from_timer(fsp, t, timer);
        struct fc_rport *rport = fsp->rport;
        struct fc_rport_libfc_priv *rpriv = rport->dd_data;
 
@@ -1446,7 +1445,7 @@ static void fc_fcp_timeout(unsigned long data)
        if (fsp->lp->qfull) {
                FC_FCP_DBG(fsp, "fcp timeout, resetting timer delay %d\n",
                           fsp->timer_delay);
-               setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp);
+               fsp->timer.function = (TIMER_FUNC_TYPE)fc_fcp_timeout;
                fc_fcp_timer_set(fsp, fsp->timer_delay);
                goto unlock;
        }
index f8dc1601efd5f1eb51b4d776087d6ea20534d09e..9c50d2d9f27c2dc88de46f2fd743922002c1b841 100644 (file)
@@ -1805,9 +1805,9 @@ int iscsi_target_alloc(struct scsi_target *starget)
 }
 EXPORT_SYMBOL_GPL(iscsi_target_alloc);
 
-static void iscsi_tmf_timedout(unsigned long data)
+static void iscsi_tmf_timedout(struct timer_list *t)
 {
-       struct iscsi_conn *conn = (struct iscsi_conn *)data;
+       struct iscsi_conn *conn = from_timer(conn, t, tmf_timer);
        struct iscsi_session *session = conn->session;
 
        spin_lock(&session->frwd_lock);
@@ -1838,8 +1838,6 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
        }
        conn->tmfcmd_pdus_cnt++;
        conn->tmf_timer.expires = timeout * HZ + jiffies;
-       conn->tmf_timer.function = iscsi_tmf_timedout;
-       conn->tmf_timer.data = (unsigned long)conn;
        add_timer(&conn->tmf_timer);
        ISCSI_DBG_EH(session, "tmf set timeout\n");
 
@@ -2089,9 +2087,9 @@ done:
 }
 EXPORT_SYMBOL_GPL(iscsi_eh_cmd_timed_out);
 
-static void iscsi_check_transport_timeouts(unsigned long data)
+static void iscsi_check_transport_timeouts(struct timer_list *t)
 {
-       struct iscsi_conn *conn = (struct iscsi_conn *)data;
+       struct iscsi_conn *conn = from_timer(conn, t, transport_timer);
        struct iscsi_session *session = conn->session;
        unsigned long recv_timeout, next_timeout = 0, last_recv;
 
@@ -2913,9 +2911,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
        conn->exp_statsn = 0;
        conn->tmf_state = TMF_INITIAL;
 
-       init_timer(&conn->transport_timer);
-       conn->transport_timer.data = (unsigned long)conn;
-       conn->transport_timer.function = iscsi_check_transport_timeouts;
+       timer_setup(&conn->transport_timer, iscsi_check_transport_timeouts, 0);
 
        INIT_LIST_HEAD(&conn->mgmtqueue);
        INIT_LIST_HEAD(&conn->cmdqueue);
@@ -2939,7 +2935,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
                goto login_task_data_alloc_fail;
        conn->login_task->data = conn->data = data;
 
-       init_timer(&conn->tmf_timer);
+       timer_setup(&conn->tmf_timer, iscsi_tmf_timedout, 0);
        init_waitqueue_head(&conn->ehwait);
 
        return cls_conn;
index 6b4fd2375178588b5d6b899ae32da25766e0f3dd..174e5eff615579d3c2822692de37e59a0b219b03 100644 (file)
@@ -41,9 +41,10 @@ static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr);
 
 /* ---------- SMP task management ---------- */
 
-static void smp_task_timedout(unsigned long _task)
+static void smp_task_timedout(struct timer_list *t)
 {
-       struct sas_task *task = (void *) _task;
+       struct sas_task_slow *slow = from_timer(slow, t, timer);
+       struct sas_task *task = slow->task;
        unsigned long flags;
 
        spin_lock_irqsave(&task->task_state_lock, flags);
@@ -91,8 +92,7 @@ static int smp_execute_task_sg(struct domain_device *dev,
 
                task->task_done = smp_task_done;
 
-               task->slow_task->timer.data = (unsigned long) task;
-               task->slow_task->timer.function = smp_task_timedout;
+               task->slow_task->timer.function = (TIMER_FUNC_TYPE)smp_task_timedout;
                task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
                add_timer(&task->slow_task->timer);
 
index 64e9cdda1c3ca01d47d60fcbf535dea44507fdb3..681fcb837354ec497fdc5facbe1040418f279a72 100644 (file)
@@ -66,7 +66,8 @@ struct sas_task *sas_alloc_slow_task(gfp_t flags)
        }
 
        task->slow_task = slow;
-       init_timer(&slow->timer);
+       slow->task = task;
+       timer_setup(&slow->timer, NULL, 0);
        init_completion(&slow->completion);
 
        return task;
index ea8ad06ff582eef292a0b11d42248502aaef8b33..91795eb56206603bb0a52baa62237e9787dd2bcf 100644 (file)
@@ -919,7 +919,7 @@ void sas_task_abort(struct sas_task *task)
                        return;
                if (!del_timer(&slow->timer))
                        return;
-               slow->timer.function(slow->timer.data);
+               slow->timer.function((TIMER_DATA_TYPE)&slow->timer);
                return;
        }
 
index 7e300734b345443bace5dd76de1441ca7d254077..4e858b38529afc9ce46d47915785a17085ca2f26 100644 (file)
@@ -113,7 +113,7 @@ void lpfc_disc_list_loopmap(struct lpfc_vport *);
 void lpfc_disc_start(struct lpfc_vport *);
 void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
 void lpfc_cleanup(struct lpfc_vport *);
-void lpfc_disc_timeout(unsigned long);
+void lpfc_disc_timeout(struct timer_list *);
 
 int lpfc_unregister_fcf_prep(struct lpfc_hba *);
 struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
@@ -154,7 +154,7 @@ int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *,
 int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
                          struct lpfc_nodelist *);
 void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
-void lpfc_els_retry_delay(unsigned long);
+void lpfc_els_retry_delay(struct timer_list *);
 void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
 void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
                          struct lpfc_iocbq *);
@@ -165,7 +165,7 @@ void lpfc_els_flush_all_cmd(struct lpfc_hba *);
 void lpfc_els_flush_cmd(struct lpfc_vport *);
 int lpfc_els_disc_adisc(struct lpfc_vport *);
 int lpfc_els_disc_plogi(struct lpfc_vport *);
-void lpfc_els_timeout(unsigned long);
+void lpfc_els_timeout(struct timer_list *);
 void lpfc_els_timeout_handler(struct lpfc_vport *);
 struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t,
                                      uint8_t, struct lpfc_nodelist *,
@@ -180,7 +180,7 @@ int lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *iocbq);
 int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
 int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t);
 void lpfc_fdmi_num_disc_check(struct lpfc_vport *);
-void lpfc_delayed_disc_tmo(unsigned long);
+void lpfc_delayed_disc_tmo(struct timer_list *);
 void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
 
 int lpfc_config_port_prep(struct lpfc_hba *);
@@ -279,9 +279,9 @@ void lpfc_mem_free(struct lpfc_hba *);
 void lpfc_mem_free_all(struct lpfc_hba *);
 void lpfc_stop_vport_timers(struct lpfc_vport *);
 
-void lpfc_poll_timeout(unsigned long ptr);
+void lpfc_poll_timeout(struct timer_list *t);
 void lpfc_poll_start_timer(struct lpfc_hba *);
-void lpfc_poll_eratt(unsigned long);
+void lpfc_poll_eratt(struct timer_list *);
 int
 lpfc_sli_handle_fast_ring_event(struct lpfc_hba *,
                        struct lpfc_sli_ring *, uint32_t);
@@ -351,7 +351,7 @@ int
 lpfc_sli_abort_taskmgmt(struct lpfc_vport *, struct lpfc_sli_ring *,
                        uint16_t, uint64_t, lpfc_ctx_cmd);
 
-void lpfc_mbox_timeout(unsigned long);
+void lpfc_mbox_timeout(struct timer_list *t);
 void lpfc_mbox_timeout_handler(struct lpfc_hba *);
 
 struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
@@ -445,7 +445,7 @@ extern unsigned int lpfc_fcp_look_ahead;
 /* Interface exported by fabric iocb scheduler */
 void lpfc_fabric_abort_nport(struct lpfc_nodelist *);
 void lpfc_fabric_abort_hba(struct lpfc_hba *);
-void lpfc_fabric_block_timeout(unsigned long);
+void lpfc_fabric_block_timeout(struct timer_list *);
 void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
 void lpfc_rampdown_queue_depth(struct lpfc_hba *);
 void lpfc_ramp_down_queue_handler(struct lpfc_hba *);
index 33417681f5d40784ffc15517f1ed137f2c6f23e3..f77673ab4a8445b8a3ec34816c21727c1b0804f1 100644 (file)
@@ -2884,9 +2884,9 @@ fdmi_cmd_exit:
  * the worker thread.
  **/
 void
-lpfc_delayed_disc_tmo(unsigned long ptr)
+lpfc_delayed_disc_tmo(struct timer_list *t)
 {
-       struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
+       struct lpfc_vport *vport = from_timer(vport, t, delayed_disc_tmo);
        struct lpfc_hba   *phba = vport->phba;
        uint32_t tmo_posted;
        unsigned long iflag;
index 468a66371de9d0c30f6e522641e42677156701cd..0dd6c21433fe531de8110c8e040ea3f10c4abcda 100644 (file)
@@ -3131,9 +3131,9 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
  * to the event associated with the ndlp.
  **/
 void
-lpfc_els_retry_delay(unsigned long ptr)
+lpfc_els_retry_delay(struct timer_list *t)
 {
-       struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
+       struct lpfc_nodelist *ndlp = from_timer(ndlp, t, nlp_delayfunc);
        struct lpfc_vport *vport = ndlp->vport;
        struct lpfc_hba   *phba = vport->phba;
        unsigned long flags;
@@ -7385,9 +7385,9 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
  * lpfc_els_timeout_handler() to work on the posted event WORKER_ELS_TMO.
  **/
 void
-lpfc_els_timeout(unsigned long ptr)
+lpfc_els_timeout(struct timer_list *t)
 {
-       struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
+       struct lpfc_vport *vport = from_timer(vport, t, els_tmofunc);
        struct lpfc_hba   *phba = vport->phba;
        uint32_t tmo_posted;
        unsigned long iflag;
@@ -9017,9 +9017,9 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
  * posted event WORKER_FABRIC_BLOCK_TMO.
  **/
 void
-lpfc_fabric_block_timeout(unsigned long ptr)
+lpfc_fabric_block_timeout(struct timer_list *t)
 {
-       struct lpfc_hba  *phba = (struct lpfc_hba *) ptr;
+       struct lpfc_hba  *phba = from_timer(phba, t, fabric_block_timer);
        unsigned long iflags;
        uint32_t tmo_posted;
 
index 20808349a80e9908d6d535b5107aa50882c0f553..8d491084eb5d0aa85fe380d42b8be5b90643fb3f 100644 (file)
@@ -4370,8 +4370,7 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 {
        INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
        INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp);
-       setup_timer(&ndlp->nlp_delayfunc, lpfc_els_retry_delay,
-                       (unsigned long)ndlp);
+       timer_setup(&ndlp->nlp_delayfunc, lpfc_els_retry_delay, 0);
        ndlp->nlp_DID = did;
        ndlp->vport = vport;
        ndlp->phba = vport->phba;
@@ -5508,9 +5507,9 @@ lpfc_cleanup_discovery_resources(struct lpfc_vport *vport)
  */
 /*****************************************************************************/
 void
-lpfc_disc_timeout(unsigned long ptr)
+lpfc_disc_timeout(struct timer_list *t)
 {
-       struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
+       struct lpfc_vport *vport = from_timer(vport, t, fc_disctmo);
        struct lpfc_hba   *phba = vport->phba;
        uint32_t tmo_posted;
        unsigned long flags = 0;
index 100bc4c8798d76852adb9224edc763f70f0741ff..6a1e28ba92585a9219030d11a491facc7e7a0049 100644 (file)
@@ -1138,13 +1138,13 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
  * be cleared by the worker thread after it has taken the event bitmap out.
  **/
 static void
-lpfc_hb_timeout(unsigned long ptr)
+lpfc_hb_timeout(struct timer_list *t)
 {
        struct lpfc_hba *phba;
        uint32_t tmo_posted;
        unsigned long iflag;
 
-       phba = (struct lpfc_hba *)ptr;
+       phba = from_timer(phba, t, hb_tmofunc);
 
        /* Check for heart beat timeout conditions */
        spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
@@ -1172,12 +1172,12 @@ lpfc_hb_timeout(unsigned long ptr)
  * be cleared by the worker thread after it has taken the event bitmap out.
  **/
 static void
-lpfc_rrq_timeout(unsigned long ptr)
+lpfc_rrq_timeout(struct timer_list *t)
 {
        struct lpfc_hba *phba;
        unsigned long iflag;
 
-       phba = (struct lpfc_hba *)ptr;
+       phba = from_timer(phba, t, rrq_tmr);
        spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
        if (!(phba->pport->load_flag & FC_UNLOADING))
                phba->hba_flag |= HBA_RRQ_ACTIVE;
@@ -3937,14 +3937,11 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        INIT_LIST_HEAD(&vport->rcv_buffer_list);
        spin_lock_init(&vport->work_port_lock);
 
-       setup_timer(&vport->fc_disctmo, lpfc_disc_timeout,
-                       (unsigned long)vport);
+       timer_setup(&vport->fc_disctmo, lpfc_disc_timeout, 0);
 
-       setup_timer(&vport->els_tmofunc, lpfc_els_timeout,
-                       (unsigned long)vport);
+       timer_setup(&vport->els_tmofunc, lpfc_els_timeout, 0);
 
-       setup_timer(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo,
-                       (unsigned long)vport);
+       timer_setup(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo, 0);
 
        error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
        if (error)
@@ -4210,9 +4207,9 @@ lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *phba)
  * worker thread context.
  **/
 static void
-lpfc_sli4_fcf_redisc_wait_tmo(unsigned long ptr)
+lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t)
 {
-       struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+       struct lpfc_hba *phba = from_timer(phba, t, fcf.redisc_wait);
 
        /* Don't send FCF rediscovery event if timer cancelled */
        spin_lock_irq(&phba->hbalock);
@@ -5624,15 +5621,13 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)
        INIT_LIST_HEAD(&phba->luns);
 
        /* MBOX heartbeat timer */
-       setup_timer(&psli->mbox_tmo, lpfc_mbox_timeout, (unsigned long)phba);
+       timer_setup(&psli->mbox_tmo, lpfc_mbox_timeout, 0);
        /* Fabric block timer */
-       setup_timer(&phba->fabric_block_timer, lpfc_fabric_block_timeout,
-                       (unsigned long)phba);
+       timer_setup(&phba->fabric_block_timer, lpfc_fabric_block_timeout, 0);
        /* EA polling mode timer */
-       setup_timer(&phba->eratt_poll, lpfc_poll_eratt,
-                       (unsigned long)phba);
+       timer_setup(&phba->eratt_poll, lpfc_poll_eratt, 0);
        /* Heartbeat timer */
-       setup_timer(&phba->hb_tmofunc, lpfc_hb_timeout, (unsigned long)phba);
+       timer_setup(&phba->hb_tmofunc, lpfc_hb_timeout, 0);
 
        return 0;
 }
@@ -5658,8 +5653,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
         */
 
        /* FCP polling mode timer */
-       setup_timer(&phba->fcp_poll_timer, lpfc_poll_timeout,
-                       (unsigned long)phba);
+       timer_setup(&phba->fcp_poll_timer, lpfc_poll_timeout, 0);
 
        /* Host attention work mask setup */
        phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT);
@@ -5829,11 +5823,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
         * Initialize timers used by driver
         */
 
-       setup_timer(&phba->rrq_tmr, lpfc_rrq_timeout, (unsigned long)phba);
+       timer_setup(&phba->rrq_tmr, lpfc_rrq_timeout, 0);
 
        /* FCF rediscover timer */
-       setup_timer(&phba->fcf.redisc_wait, lpfc_sli4_fcf_redisc_wait_tmo,
-                       (unsigned long)phba);
+       timer_setup(&phba->fcf.redisc_wait, lpfc_sli4_fcf_redisc_wait_tmo, 0);
 
        /*
         * Control structure for handling external multi-buffer mailbox
index 1a6f122bb25db6697f7a5e705fdba992cf2bd9fd..c0cdaef4db24f1f124709d9ff3b0e9fcbcfbf361 100644 (file)
@@ -4501,9 +4501,9 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba)
  * and FCP Ring interrupt is disable.
  **/
 
-void lpfc_poll_timeout(unsigned long ptr)
+void lpfc_poll_timeout(struct timer_list *t)
 {
-       struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
+       struct lpfc_hba *phba = from_timer(phba, t, fcp_poll_timer);
 
        if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
                lpfc_sli_handle_fast_ring_event(phba,
index 8b119f87b51d67382b89aa60500d9ffe6f18ab19..4edb81073409df585e147cf5646e6ae51f7e99c5 100644 (file)
@@ -3004,13 +3004,13 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
  * and wake up worker thread to process it. Otherwise, it will set up the
  * Error Attention polling timer for the next poll.
  **/
-void lpfc_poll_eratt(unsigned long ptr)
+void lpfc_poll_eratt(struct timer_list *t)
 {
        struct lpfc_hba *phba;
        uint32_t eratt = 0;
        uint64_t sli_intr, cnt;
 
-       phba = (struct lpfc_hba *)ptr;
+       phba = from_timer(phba, t, eratt_poll);
 
        /* Here we will also keep track of interrupts per sec of the hba */
        sli_intr = phba->sli.slistat.sli_intr;
@@ -7167,9 +7167,9 @@ out_free_mbox:
  * done by the worker thread function lpfc_mbox_timeout_handler.
  **/
 void
-lpfc_mbox_timeout(unsigned long ptr)
+lpfc_mbox_timeout(struct timer_list *t)
 {
-       struct lpfc_hba  *phba = (struct lpfc_hba *) ptr;
+       struct lpfc_hba  *phba = from_timer(phba, t, sli.mbox_tmo);
        unsigned long iflag;
        uint32_t tmo_posted;
 
index 05f6e4ec345396931c5edfd374ef146c1eb340d4..eedcbde46459999ac42a602534191d3611711ff9 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/types.h>
 #include <linux/semaphore.h>
+#include <linux/timer.h>
 
 #include "mbox_defs.h"
 
@@ -153,6 +154,11 @@ typedef struct uioc {
 
 } __attribute__ ((aligned(1024),packed)) uioc_t;
 
+/* For on-stack uioc timers. */
+struct uioc_timeout {
+       struct timer_list timer;
+       uioc_t            *uioc;
+};
 
 /**
  * struct mraid_hba_info - information about the controller
index ec3c4385497865399c7d4cab92b0c6cd8558a7aa..530358cdcb3912e2c5c751b076905a348e32408e 100644 (file)
@@ -3904,19 +3904,19 @@ megaraid_sysfs_get_ldmap_done(uioc_t *uioc)
        wake_up(&raid_dev->sysfs_wait_q);
 }
 
-
 /**
  * megaraid_sysfs_get_ldmap_timeout - timeout handling for get ldmap
- * @data       : timed out packet
+ * @t  : timed out timer
  *
  * Timeout routine to recover and return to application, in case the adapter
  * has stopped responding. A timeout of 60 seconds for this command seems like
  * a good value.
  */
 static void
-megaraid_sysfs_get_ldmap_timeout(unsigned long data)
+megaraid_sysfs_get_ldmap_timeout(struct timer_list *t)
 {
-       uioc_t          *uioc = (uioc_t *)data;
+       struct uioc_timeout *timeout = from_timer(timeout, t, timer);
+       uioc_t          *uioc = timeout->uioc;
        adapter_t       *adapter = (adapter_t *)uioc->buf_vaddr;
        mraid_device_t  *raid_dev = ADAP2RAIDDEV(adapter);
 
@@ -3951,8 +3951,7 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter)
        mbox64_t                *mbox64;
        mbox_t                  *mbox;
        char                    *raw_mbox;
-       struct timer_list       sysfs_timer;
-       struct timer_list       *timerp;
+       struct uioc_timeout     timeout;
        caddr_t                 ldmap;
        int                     rval = 0;
 
@@ -3988,14 +3987,12 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter)
        /*
         * Setup a timer to recover from a non-responding controller
         */
-       timerp  = &sysfs_timer;
-       init_timer(timerp);
-
-       timerp->function        = megaraid_sysfs_get_ldmap_timeout;
-       timerp->data            = (unsigned long)uioc;
-       timerp->expires         = jiffies + 60 * HZ;
+       timeout.uioc = uioc;
+       timer_setup_on_stack(&timeout.timer,
+                            megaraid_sysfs_get_ldmap_timeout, 0);
 
-       add_timer(timerp);
+       timeout.timer.expires           = jiffies + 60 * HZ;
+       add_timer(&timeout.timer);
 
        /*
         * Send the command to the firmware
@@ -4033,7 +4030,8 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter)
        }
 
 
-       del_timer_sync(timerp);
+       del_timer_sync(&timeout.timer);
+       destroy_timer_on_stack(&timeout.timer);
 
        mutex_unlock(&raid_dev->sysfs_mtx);
 
index 65b6f6ace3a5334fc3c81b9480871abe3fe2ad04..bb802b0c12b8663570dbc57bf6f032d575360e7a 100644 (file)
@@ -35,7 +35,7 @@ static int kioc_to_mimd(uioc_t *, mimd_t __user *);
 static int handle_drvrcmd(void __user *, uint8_t, int *);
 static int lld_ioctl(mraid_mmadp_t *, uioc_t *);
 static void ioctl_done(uioc_t *);
-static void lld_timedout(unsigned long);
+static void lld_timedout(struct timer_list *);
 static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *);
 static mraid_mmadp_t *mraid_mm_get_adapter(mimd_t __user *, int *);
 static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *);
@@ -686,8 +686,7 @@ static int
 lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
 {
        int                     rval;
-       struct timer_list       timer;
-       struct timer_list       *tp = NULL;
+       struct uioc_timeout     timeout = { };
 
        kioc->status    = -ENODATA;
        rval            = adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE);
@@ -698,14 +697,12 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
         * Start the timer
         */
        if (adp->timeout > 0) {
-               tp              = &timer;
-               init_timer(tp);
+               timeout.uioc = kioc;
+               timer_setup_on_stack(&timeout.timer, lld_timedout, 0);
 
-               tp->function    = lld_timedout;
-               tp->data        = (unsigned long)kioc;
-               tp->expires     = jiffies + adp->timeout * HZ;
+               timeout.timer.expires   = jiffies + adp->timeout * HZ;
 
-               add_timer(tp);
+               add_timer(&timeout.timer);
        }
 
        /*
@@ -713,8 +710,9 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
         * call, the ioctl either completed successfully or timedout.
         */
        wait_event(wait_q, (kioc->status != -ENODATA));
-       if (tp) {
-               del_timer_sync(tp);
+       if (timeout.timer.function) {
+               del_timer_sync(&timeout.timer);
+               destroy_timer_on_stack(&timeout.timer);
        }
 
        /*
@@ -783,12 +781,13 @@ ioctl_done(uioc_t *kioc)
 
 /**
  * lld_timedout        - callback from the expired timer
- * @ptr                : ioctl packet that timed out
+ * @t          : timer that timed out
  */
 static void
-lld_timedout(unsigned long ptr)
+lld_timedout(struct timer_list *t)
 {
-       uioc_t *kioc    = (uioc_t *)ptr;
+       struct uioc_timeout *timeout = from_timer(timeout, t, timer);
+       uioc_t *kioc    = timeout->uioc;
 
        kioc->status    = -ETIME;
        kioc->timedout  = 1;
index e518dadc81615fd4e981b9127e840b9c7adc2d2b..a36e18156e49302ba91fb0eb4f73a3afada8f7b4 100644 (file)
@@ -2114,22 +2114,19 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
        megasas_check_and_restore_queue_depth(instance);
 }
 
+static void megasas_sriov_heartbeat_handler(struct timer_list *t);
+
 /**
- * megasas_start_timer - Initializes a timer object
+ * megasas_start_timer - Initializes sriov heartbeat timer object
  * @instance:          Adapter soft state
- * @timer:             timer object to be initialized
- * @fn:                        timer function
- * @interval:          time interval between timer function call
  *
  */
-void megasas_start_timer(struct megasas_instance *instance,
-                       struct timer_list *timer,
-                       void *fn, unsigned long interval)
-{
-       init_timer(timer);
-       timer->expires = jiffies + interval;
-       timer->data = (unsigned long)instance;
-       timer->function = fn;
+void megasas_start_timer(struct megasas_instance *instance)
+{
+       struct timer_list *timer = &instance->sriov_heartbeat_timer;
+
+       timer_setup(timer, megasas_sriov_heartbeat_handler, 0);
+       timer->expires = jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF;
        add_timer(timer);
 }
 
@@ -2515,10 +2512,10 @@ out:
 }
 
 /* Handler for SR-IOV heartbeat */
-void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
+static void megasas_sriov_heartbeat_handler(struct timer_list *t)
 {
        struct megasas_instance *instance =
-               (struct megasas_instance *)instance_addr;
+               from_timer(instance, t, sriov_heartbeat_timer);
 
        if (instance->hb_host_mem->HB.fwCounter !=
            instance->hb_host_mem->HB.driverCounter) {
@@ -5493,10 +5490,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
        /* Launch SR-IOV heartbeat timer */
        if (instance->requestorId) {
                if (!megasas_sriov_start_heartbeat(instance, 1))
-                       megasas_start_timer(instance,
-                                           &instance->sriov_heartbeat_timer,
-                                           megasas_sriov_heartbeat_handler,
-                                           MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+                       megasas_start_timer(instance);
                else
                        instance->skip_heartbeat_timer_del = 1;
        }
@@ -6507,10 +6501,7 @@ megasas_resume(struct pci_dev *pdev)
        /* Re-launch SR-IOV heartbeat timer */
        if (instance->requestorId) {
                if (!megasas_sriov_start_heartbeat(instance, 0))
-                       megasas_start_timer(instance,
-                                           &instance->sriov_heartbeat_timer,
-                                           megasas_sriov_heartbeat_handler,
-                                           MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+                       megasas_start_timer(instance);
                else {
                        instance->skip_heartbeat_timer_del = 1;
                        goto fail_init_mfi;
index 11bd2e698b84c6b9a637fea7d4aba8928d04e3fd..3c399e7b3fe1ca1dc74c5881e6acaa1aa7fd39f3 100644 (file)
@@ -85,12 +85,9 @@ int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
 void megaraid_sas_kill_hba(struct megasas_instance *instance);
 
 extern u32 megasas_dbg_lvl;
-void megasas_sriov_heartbeat_handler(unsigned long instance_addr);
 int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
                                  int initial);
-void megasas_start_timer(struct megasas_instance *instance,
-                       struct timer_list *timer,
-                        void *fn, unsigned long interval);
+void megasas_start_timer(struct megasas_instance *instance);
 extern struct megasas_mgmt_info megasas_mgmt_info;
 extern unsigned int resetwaittime;
 extern unsigned int dual_qdepth_disable;
@@ -4369,10 +4366,7 @@ transition_to_ready:
                        /* Restart SR-IOV heartbeat */
                        if (instance->requestorId) {
                                if (!megasas_sriov_start_heartbeat(instance, 0))
-                                       megasas_start_timer(instance,
-                                                           &instance->sriov_heartbeat_timer,
-                                                           megasas_sriov_heartbeat_handler,
-                                                           MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+                                       megasas_start_timer(instance);
                                else
                                        instance->skip_heartbeat_timer_del = 1;
                        }
@@ -4404,10 +4398,7 @@ fail_kill_adapter:
        } else {
                /* For VF: Restart HB timer if we didn't OCR */
                if (instance->requestorId) {
-                       megasas_start_timer(instance,
-                                           &instance->sriov_heartbeat_timer,
-                                           megasas_sriov_heartbeat_handler,
-                                           MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+                       megasas_start_timer(instance);
                }
                clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
                instance->instancet->enable_intr(instance);
index 718c88de328bff527c37ce1edd33f03208b8e711..8c91637cd598d971afd11b2ae5e4aceb024a7b22 100644 (file)
@@ -95,7 +95,7 @@ static void mvs_phy_init(struct mvs_info *mvi, int phy_id)
 
        phy->mvi = mvi;
        phy->port = NULL;
-       init_timer(&phy->timer);
+       timer_setup(&phy->timer, NULL, 0);
        sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
        sas_phy->class = SAS;
        sas_phy->iproto = SAS_PROTOCOL_ALL;
@@ -248,7 +248,6 @@ static int mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
                mvi->devices[i].dev_type = SAS_PHY_UNUSED;
                mvi->devices[i].device_id = i;
                mvi->devices[i].dev_status = MVS_DEV_NORMAL;
-               init_timer(&mvi->devices[i].timer);
        }
 
        /*
index ee81d10252e043fa1ed505d429ed7a7dbcebde3d..cff1c37b8d2e46374ffda812b97877851b1cea2c 100644 (file)
@@ -1283,9 +1283,10 @@ static void mvs_task_done(struct sas_task *task)
        complete(&task->slow_task->completion);
 }
 
-static void mvs_tmf_timedout(unsigned long data)
+static void mvs_tmf_timedout(struct timer_list *t)
 {
-       struct sas_task *task = (struct sas_task *)data;
+       struct sas_task_slow *slow = from_timer(slow, t, timer);
+       struct sas_task *task = slow->task;
 
        task->task_state_flags |= SAS_TASK_STATE_ABORTED;
        complete(&task->slow_task->completion);
@@ -1309,8 +1310,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
                memcpy(&task->ssp_task, parameter, para_len);
                task->task_done = mvs_task_done;
 
-               task->slow_task->timer.data = (unsigned long) task;
-               task->slow_task->timer.function = mvs_tmf_timedout;
+               task->slow_task->timer.function = (TIMER_FUNC_TYPE)mvs_tmf_timedout;
                task->slow_task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
                add_timer(&task->slow_task->timer);
 
@@ -1954,9 +1954,9 @@ static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler)
        return ret;
 }
 
-static void mvs_sig_time_out(unsigned long tphy)
+static void mvs_sig_time_out(struct timer_list *t)
 {
-       struct mvs_phy *phy = (struct mvs_phy *)tphy;
+       struct mvs_phy *phy = from_timer(phy, t, timer);
        struct mvs_info *mvi = phy->mvi;
        u8 phy_no;
 
@@ -2020,8 +2020,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no,
                                        tmp | PHYEV_SIG_FIS);
                if (phy->timer.function == NULL) {
-                       phy->timer.data = (unsigned long)phy;
-                       phy->timer.function = mvs_sig_time_out;
+                       phy->timer.function = (TIMER_FUNC_TYPE)mvs_sig_time_out;
                        phy->timer.expires = jiffies + 5*HZ;
                        add_timer(&phy->timer);
                }
index f9afd4cdd4c4e9784e2bf83736ca5c48ed675f7e..080676c1c9e5a1322829dcea71edd62e993b33c5 100644 (file)
@@ -247,7 +247,6 @@ struct mvs_device {
        enum sas_device_type dev_type;
        struct mvs_info *mvi_info;
        struct domain_device *sas_device;
-       struct timer_list timer;
        u32 attached_phy;
        u32 device_id;
        u32 running_req;
index ce584c31d36e505a005b2e09aab8ccbaa6e4025c..7b2f92ae986602e2ffba558ff069f05c3685c8e4 100644 (file)
@@ -656,9 +656,10 @@ void pm8001_task_done(struct sas_task *task)
        complete(&task->slow_task->completion);
 }
 
-static void pm8001_tmf_timedout(unsigned long data)
+static void pm8001_tmf_timedout(struct timer_list *t)
 {
-       struct sas_task *task = (struct sas_task *)data;
+       struct sas_task_slow *slow = from_timer(slow, t, timer);
+       struct sas_task *task = slow->task;
 
        task->task_state_flags |= SAS_TASK_STATE_ABORTED;
        complete(&task->slow_task->completion);
@@ -694,8 +695,7 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
                task->task_proto = dev->tproto;
                memcpy(&task->ssp_task, parameter, para_len);
                task->task_done = pm8001_task_done;
-               task->slow_task->timer.data = (unsigned long)task;
-               task->slow_task->timer.function = pm8001_tmf_timedout;
+               task->slow_task->timer.function = (TIMER_FUNC_TYPE)pm8001_tmf_timedout;
                task->slow_task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
                add_timer(&task->slow_task->timer);
 
@@ -781,8 +781,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
                task->dev = dev;
                task->task_proto = dev->tproto;
                task->task_done = pm8001_task_done;
-               task->slow_task->timer.data = (unsigned long)task;
-               task->slow_task->timer.function = pm8001_tmf_timedout;
+               task->slow_task->timer.function = (TIMER_FUNC_TYPE)pm8001_tmf_timedout;
                task->slow_task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ;
                add_timer(&task->slow_task->timer);
 
index b4d6cd8cd1ad5bc1ad0590ecefb31e6809a5c3f3..4f9f115fb6a0c8c9a3d3e5753d5d236c52897e60 100644 (file)
@@ -348,7 +348,7 @@ static void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index)
        cmd->sense_buffer = NULL;
        cmd->sense_buffer_dma = 0;
        cmd->dma_handle = 0;
-       init_timer(&cmd->timer);
+       timer_setup(&cmd->timer, NULL, 0);
 }
 
 /**
@@ -557,8 +557,9 @@ static void pmcraid_reset_type(struct pmcraid_instance *pinstance)
 
 static void pmcraid_ioa_reset(struct pmcraid_cmd *);
 
-static void pmcraid_bist_done(struct pmcraid_cmd *cmd)
+static void pmcraid_bist_done(struct timer_list *t)
 {
+       struct pmcraid_cmd *cmd = from_timer(cmd, t, timer);
        struct pmcraid_instance *pinstance = cmd->drv_inst;
        unsigned long lock_flags;
        int rc;
@@ -572,9 +573,6 @@ static void pmcraid_bist_done(struct pmcraid_cmd *cmd)
                pmcraid_info("BIST not complete, waiting another 2 secs\n");
                cmd->timer.expires = jiffies + cmd->time_left;
                cmd->time_left = 0;
-               cmd->timer.data = (unsigned long)cmd;
-               cmd->timer.function =
-                       (void (*)(unsigned long))pmcraid_bist_done;
                add_timer(&cmd->timer);
        } else {
                cmd->time_left = 0;
@@ -605,9 +603,8 @@ static void pmcraid_start_bist(struct pmcraid_cmd *cmd)
                      doorbells, intrs);
 
        cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
-       cmd->timer.data = (unsigned long)cmd;
        cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
-       cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done;
+       cmd->timer.function = (TIMER_FUNC_TYPE)pmcraid_bist_done;
        add_timer(&cmd->timer);
 }
 
@@ -617,8 +614,9 @@ static void pmcraid_start_bist(struct pmcraid_cmd *cmd)
  * Return value
  *  None
  */
-static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd)
+static void pmcraid_reset_alert_done(struct timer_list *t)
 {
+       struct pmcraid_cmd *cmd = from_timer(cmd, t, timer);
        struct pmcraid_instance *pinstance = cmd->drv_inst;
        u32 status = ioread32(pinstance->ioa_status);
        unsigned long lock_flags;
@@ -637,10 +635,8 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd)
                pmcraid_info("critical op is not yet reset waiting again\n");
                /* restart timer if some more time is available to wait */
                cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT;
-               cmd->timer.data = (unsigned long)cmd;
                cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT;
-               cmd->timer.function =
-                       (void (*)(unsigned long))pmcraid_reset_alert_done;
+               cmd->timer.function = (TIMER_FUNC_TYPE)pmcraid_reset_alert_done;
                add_timer(&cmd->timer);
        }
 }
@@ -676,10 +672,8 @@ static void pmcraid_reset_alert(struct pmcraid_cmd *cmd)
                 * bit to be reset.
                 */
                cmd->time_left = PMCRAID_RESET_TIMEOUT;
-               cmd->timer.data = (unsigned long)cmd;
                cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT;
-               cmd->timer.function =
-                       (void (*)(unsigned long))pmcraid_reset_alert_done;
+               cmd->timer.function = (TIMER_FUNC_TYPE)pmcraid_reset_alert_done;
                add_timer(&cmd->timer);
 
                iowrite32(DOORBELL_IOA_RESET_ALERT,
@@ -704,8 +698,9 @@ static void pmcraid_reset_alert(struct pmcraid_cmd *cmd)
  * Return value:
  *   None
  */
-static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd)
+static void pmcraid_timeout_handler(struct timer_list *t)
 {
+       struct pmcraid_cmd *cmd = from_timer(cmd, t, timer);
        struct pmcraid_instance *pinstance = cmd->drv_inst;
        unsigned long lock_flags;
 
@@ -919,7 +914,7 @@ static void pmcraid_send_cmd(
        struct pmcraid_cmd *cmd,
        void (*cmd_done) (struct pmcraid_cmd *),
        unsigned long timeout,
-       void (*timeout_func) (struct pmcraid_cmd *)
+       void (*timeout_func) (struct timer_list *)
 )
 {
        /* initialize done function */
@@ -927,9 +922,8 @@ static void pmcraid_send_cmd(
 
        if (timeout_func) {
                /* setup timeout handler */
-               cmd->timer.data = (unsigned long)cmd;
                cmd->timer.expires = jiffies + timeout;
-               cmd->timer.function = (void (*)(unsigned long))timeout_func;
+               cmd->timer.function = (TIMER_FUNC_TYPE)timeout_func;
                add_timer(&cmd->timer);
        }
 
@@ -1955,10 +1949,9 @@ static void pmcraid_soft_reset(struct pmcraid_cmd *cmd)
         * would re-initiate a reset
         */
        cmd->cmd_done = pmcraid_ioa_reset;
-       cmd->timer.data = (unsigned long)cmd;
        cmd->timer.expires = jiffies +
                             msecs_to_jiffies(PMCRAID_TRANSOP_TIMEOUT);
-       cmd->timer.function = (void (*)(unsigned long))pmcraid_timeout_handler;
+       cmd->timer.function = (TIMER_FUNC_TYPE)pmcraid_timeout_handler;
 
        if (!timer_pending(&cmd->timer))
                add_timer(&cmd->timer);
index 8a29fb09db141365832f3b62436d083357a6156b..390775d5c91888361ebaad09a5425a02217baaed 100644 (file)
@@ -758,9 +758,9 @@ enum action {
 };
 
 
-static void qla1280_mailbox_timeout(unsigned long __data)
+static void qla1280_mailbox_timeout(struct timer_list *t)
 {
-       struct scsi_qla_host *ha = (struct scsi_qla_host *)__data;
+       struct scsi_qla_host *ha = from_timer(ha, t, mailbox_timer);
        struct device_reg __iomem *reg;
        reg = ha->iobase;
 
@@ -2465,7 +2465,6 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
        uint16_t __iomem *mptr;
        uint16_t data;
        DECLARE_COMPLETION_ONSTACK(wait);
-       struct timer_list timer;
 
        ENTER("qla1280_mailbox_command");
 
@@ -2494,18 +2493,15 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
        /* Issue set host interrupt command. */
 
        /* set up a timer just in case we're really jammed */
-       init_timer_on_stack(&timer);
-       timer.expires = jiffies + 20*HZ;
-       timer.data = (unsigned long)ha;
-       timer.function = qla1280_mailbox_timeout;
-       add_timer(&timer);
+       timer_setup(&ha->mailbox_timer, qla1280_mailbox_timeout, 0);
+       mod_timer(&ha->mailbox_timer, jiffies + 20 * HZ);
 
        spin_unlock_irq(ha->host->host_lock);
        WRT_REG_WORD(&reg->host_cmd, HC_SET_HOST_INT);
        data = qla1280_debounce_register(&reg->istatus);
 
        wait_for_completion(&wait);
-       del_timer_sync(&timer);
+       del_timer_sync(&ha->mailbox_timer);
 
        spin_lock_irq(ha->host->host_lock);
 
index 834884b9eed5b579e62a622ce4725c80ad897a7b..1522aca2c8c83c603f61c06265b959da6ec254f2 100644 (file)
@@ -1055,6 +1055,7 @@ struct scsi_qla_host {
        struct list_head done_q;        /* Done queue */
 
        struct completion *mailbox_wait;
+       struct timer_list mailbox_timer;
 
        volatile struct {
                uint32_t online:1;                      /* 0 */
index f852ca60c49fd182192efaeb6853bf5c379f015c..3ad375f85b59e325c7e35ac1d7b0264963999e1d 100644 (file)
@@ -206,8 +206,8 @@ int qla24xx_async_abort_cmd(srb_t *);
  */
 extern struct scsi_host_template qla2xxx_driver_template;
 extern struct scsi_transport_template *qla2xxx_transport_vport_template;
-extern void qla2x00_timer(scsi_qla_host_t *);
-extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long);
+extern void qla2x00_timer(struct timer_list *);
+extern void qla2x00_start_timer(scsi_qla_host_t *, unsigned long);
 extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *);
 extern int qla24xx_disable_vp (scsi_qla_host_t *);
 extern int qla24xx_enable_vp (scsi_qla_host_t *);
@@ -753,7 +753,7 @@ extern int qla82xx_restart_isp(scsi_qla_host_t *);
 /* IOCB related functions */
 extern int qla82xx_start_scsi(srb_t *);
 extern void qla2x00_sp_free(void *);
-extern void qla2x00_sp_timeout(unsigned long);
+extern void qla2x00_sp_timeout(struct timer_list *);
 extern void qla2x00_bsg_job_done(void *, int);
 extern void qla2x00_bsg_sp_free(void *);
 extern void qla2x00_start_iocbs(struct scsi_qla_host *, struct req_que *);
index b5b48ddca9621d82bb9b7b674b8eb9f79f083fbe..44cf875a484adb4ac5e7afb98a5f5a87cc0f12f1 100644 (file)
@@ -45,9 +45,9 @@ static void qla24xx_handle_prli_done_event(struct scsi_qla_host *,
 /* SRB Extensions ---------------------------------------------------------- */
 
 void
-qla2x00_sp_timeout(unsigned long __data)
+qla2x00_sp_timeout(struct timer_list *t)
 {
-       srb_t *sp = (srb_t *)__data;
+       srb_t *sp = from_timer(sp, t, u.iocb_cmd.timer);
        struct srb_iocb *iocb;
        scsi_qla_host_t *vha = sp->vha;
        struct req_que *req;
index 9a2c86eacf44add92137dc94d5bf2846987e89e0..17d2c20f1f75a1084fd3328f558fa7f1d6eb234f 100644 (file)
@@ -269,10 +269,8 @@ qla2x00_rel_sp(srb_t *sp)
 static inline void
 qla2x00_init_timer(srb_t *sp, unsigned long tmo)
 {
-       init_timer(&sp->u.iocb_cmd.timer);
+       timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0);
        sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ;
-       sp->u.iocb_cmd.timer.data = (unsigned long)sp;
-       sp->u.iocb_cmd.timer.function = qla2x00_sp_timeout;
        add_timer(&sp->u.iocb_cmd.timer);
        sp->free = qla2x00_sp_free;
        if (IS_QLAFX00(sp->vha->hw) && (sp->type == SRB_FXIOCB_DCMD))
index c0f8f6c17b793384cd9f9c70ef34f8ec945642e7..cbf544dbf883d791c3a841b7ddc829cd0a0dff36 100644 (file)
@@ -487,7 +487,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
        atomic_set(&vha->loop_state, LOOP_DOWN);
        atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
 
-       qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
+       qla2x00_start_timer(vha, WATCH_INTERVAL);
 
        vha->req = base_vha->req;
        host->can_queue = base_vha->req->length + 128;
index dce42a416876573087e497c9cf7242e267b04b4d..50286cf02eca046b830b973ca4868c0f02944ec0 100644 (file)
@@ -330,12 +330,10 @@ struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
  */
 
 __inline__ void
-qla2x00_start_timer(scsi_qla_host_t *vha, void *func, unsigned long interval)
+qla2x00_start_timer(scsi_qla_host_t *vha, unsigned long interval)
 {
-       init_timer(&vha->timer);
+       timer_setup(&vha->timer, qla2x00_timer, 0);
        vha->timer.expires = jiffies + interval * HZ;
-       vha->timer.data = (unsigned long)vha;
-       vha->timer.function = (void (*)(unsigned long))func;
        add_timer(&vha->timer);
        vha->timer_active = 1;
 }
@@ -3247,7 +3245,7 @@ skip_dpc:
        base_vha->host->irq = ha->pdev->irq;
 
        /* Initialized the timer */
-       qla2x00_start_timer(base_vha, qla2x00_timer, WATCH_INTERVAL);
+       qla2x00_start_timer(base_vha, WATCH_INTERVAL);
        ql_dbg(ql_dbg_init, base_vha, 0x00ef,
            "Started qla2x00_timer with "
            "interval=%d.\n", WATCH_INTERVAL);
@@ -5996,8 +5994,9 @@ qla2x00_rst_aen(scsi_qla_host_t *vha)
 * Context: Interrupt
 ***************************************************************************/
 void
-qla2x00_timer(scsi_qla_host_t *vha)
+qla2x00_timer(struct timer_list *t)
 {
+       scsi_qla_host_t *vha = from_timer(vha, t, timer);
        unsigned long   cpu_flags = 0;
        int             start_dpc = 0;
        int             index;
index f05cfc83c9c8d0110c253d0e2331a7e970f72d26..f946bf88901540d2e5fd815427be3b57ff6afc9f 100644 (file)
@@ -996,7 +996,7 @@ static void qlt_free_session_done(struct work_struct *work)
        if (logout_started) {
                bool traced = false;
 
-               while (!ACCESS_ONCE(sess->logout_completed)) {
+               while (!READ_ONCE(sess->logout_completed)) {
                        if (!traced) {
                                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf086,
                                        "%s: waiting for sess %p logout\n",
index 64c6fa563fdb7562f6e33d83357879d8e572940e..2b8a8ce2a4313e3c44fdca937b8e1bd7a0838c82 100644 (file)
@@ -3955,16 +3955,15 @@ exit_session_conn_param:
 /*
  * Timer routines
  */
+static void qla4xxx_timer(struct timer_list *t);
 
-static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func,
+static void qla4xxx_start_timer(struct scsi_qla_host *ha,
                                unsigned long interval)
 {
        DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
                     __func__, ha->host->host_no));
-       init_timer(&ha->timer);
+       timer_setup(&ha->timer, qla4xxx_timer, 0);
        ha->timer.expires = jiffies + interval * HZ;
-       ha->timer.data = (unsigned long)ha;
-       ha->timer.function = (void (*)(unsigned long))func;
        add_timer(&ha->timer);
        ha->timer_active = 1;
 }
@@ -4508,8 +4507,9 @@ static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
  * qla4xxx_timer - checks every second for work to do.
  * @ha: Pointer to host adapter structure.
  **/
-static void qla4xxx_timer(struct scsi_qla_host *ha)
+static void qla4xxx_timer(struct timer_list *t)
 {
+       struct scsi_qla_host *ha = from_timer(ha, t, timer);
        int start_dpc = 0;
        uint16_t w;
 
@@ -8805,7 +8805,7 @@ skip_retry_init:
        ha->isp_ops->enable_intrs(ha);
 
        /* Start timer thread. */
-       qla4xxx_start_timer(ha, qla4xxx_timer, 1);
+       qla4xxx_start_timer(ha, 1);
 
        set_bit(AF_INIT_DONE, &ha->flags);
 
index ad3ea24f08859fb167e7297c2cacef81d646fb00..bcc1694cebcd3e184f40bba43f3a2200ea56c6e8 100644 (file)
@@ -2685,7 +2685,6 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 
        }
        sdev->sdev_state = state;
-       sysfs_notify(&sdev->sdev_gendev.kobj, NULL, "state");
        return 0;
 
  illegal:
@@ -3109,7 +3108,6 @@ int scsi_internal_device_unblock_nowait(struct scsi_device *sdev,
        case SDEV_BLOCK:
        case SDEV_TRANSPORT_OFFLINE:
                sdev->sdev_state = new_state;
-               sysfs_notify(&sdev->sdev_gendev.kobj, NULL, "state");
                break;
        case SDEV_CREATED_BLOCK:
                if (new_state == SDEV_TRANSPORT_OFFLINE ||
@@ -3117,7 +3115,6 @@ int scsi_internal_device_unblock_nowait(struct scsi_device *sdev,
                        sdev->sdev_state = new_state;
                else
                        sdev->sdev_state = SDEV_CREATED;
-               sysfs_notify(&sdev->sdev_gendev.kobj, NULL, "state");
                break;
        case SDEV_CANCEL:
        case SDEV_OFFLINE:
index 4f6f01cf9968e70c81e4dbd6d5603a3ae4fa4f1c..36f6190931bc07f194621ff2a51633c83561fa51 100644 (file)
@@ -556,11 +556,8 @@ int srp_reconnect_rport(struct srp_rport *rport)
                 */
                shost_for_each_device(sdev, shost) {
                        mutex_lock(&sdev->state_mutex);
-                       if (sdev->sdev_state == SDEV_OFFLINE) {
+                       if (sdev->sdev_state == SDEV_OFFLINE)
                                sdev->sdev_state = SDEV_RUNNING;
-                               sysfs_notify(&sdev->sdev_gendev.kobj,
-                                            NULL, "state");
-                       }
                        mutex_unlock(&sdev->state_mutex);
                }
        } else if (rport->state == SRP_RPORT_RUNNING) {
index 83bdbd84eb01f427e9d74d56526b2e1f1ceb9e33..90f6effc32b43834d06f7b6346791795bac5f9cf 100644 (file)
@@ -2860,11 +2860,12 @@ out:
 
 #define PQI_HEARTBEAT_TIMER_INTERVAL   (10 * HZ)
 
-static void pqi_heartbeat_timer_handler(unsigned long data)
+static void pqi_heartbeat_timer_handler(struct timer_list *t)
 {
        int num_interrupts;
        u32 heartbeat_count;
-       struct pqi_ctrl_info *ctrl_info = (struct pqi_ctrl_info *)data;
+       struct pqi_ctrl_info *ctrl_info = from_timer(ctrl_info, t,
+                                                    heartbeat_timer);
 
        pqi_check_ctrl_health(ctrl_info);
        if (pqi_ctrl_offline(ctrl_info))
@@ -2902,8 +2903,6 @@ static void pqi_start_heartbeat_timer(struct pqi_ctrl_info *ctrl_info)
 
        ctrl_info->heartbeat_timer.expires =
                jiffies + PQI_HEARTBEAT_TIMER_INTERVAL;
-       ctrl_info->heartbeat_timer.data = (unsigned long)ctrl_info;
-       ctrl_info->heartbeat_timer.function = pqi_heartbeat_timer_handler;
        add_timer(&ctrl_info->heartbeat_timer);
 }
 
@@ -6465,7 +6464,7 @@ static struct pqi_ctrl_info *pqi_alloc_ctrl_info(int numa_node)
        INIT_DELAYED_WORK(&ctrl_info->rescan_work, pqi_rescan_worker);
        INIT_DELAYED_WORK(&ctrl_info->update_time_work, pqi_update_time_worker);
 
-       init_timer(&ctrl_info->heartbeat_timer);
+       timer_setup(&ctrl_info->heartbeat_timer, pqi_heartbeat_timer_handler, 0);
        INIT_WORK(&ctrl_info->ctrl_offline_work, pqi_ctrl_offline_worker);
 
        sema_init(&ctrl_info->sync_request_sem,
index e1ce8b1b5090aa0a7b91b6abcd73ad7fa0760261..e570b6af2e6ffbddccf1fe76075375d4e39e3e0c 100644 (file)
@@ -361,17 +361,6 @@ out:
        return ret;
 }
 
-static bool scpsys_active_wakeup(struct device *dev)
-{
-       struct generic_pm_domain *genpd;
-       struct scp_domain *scpd;
-
-       genpd = pd_to_genpd(dev->pm_domain);
-       scpd = container_of(genpd, struct scp_domain, genpd);
-
-       return scpd->data->active_wakeup;
-}
-
 static void init_clks(struct platform_device *pdev, struct clk **clk)
 {
        int i;
@@ -466,7 +455,8 @@ static struct scp *init_scp(struct platform_device *pdev,
                genpd->name = data->name;
                genpd->power_off = scpsys_power_off;
                genpd->power_on = scpsys_power_on;
-               genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
+               if (scpd->data->active_wakeup)
+                       genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP;
        }
 
        return scp;
index 40b75748835f552cd4f5a08525a770f839c69d4e..5c342167b9db7a16378cde561098aaaebf50dc7f 100644 (file)
@@ -358,17 +358,6 @@ static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
        pm_clk_destroy(dev);
 }
 
-static bool rockchip_active_wakeup(struct device *dev)
-{
-       struct generic_pm_domain *genpd;
-       struct rockchip_pm_domain *pd;
-
-       genpd = pd_to_genpd(dev->pm_domain);
-       pd = container_of(genpd, struct rockchip_pm_domain, genpd);
-
-       return pd->info->active_wakeup;
-}
-
 static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
                                      struct device_node *node)
 {
@@ -489,8 +478,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
        pd->genpd.power_on = rockchip_pd_power_on;
        pd->genpd.attach_dev = rockchip_pd_attach_dev;
        pd->genpd.detach_dev = rockchip_pd_detach_dev;
-       pd->genpd.dev_ops.active_wakeup = rockchip_active_wakeup;
        pd->genpd.flags = GENPD_FLAG_PM_CLK;
+       if (pd_info->active_wakeup)
+               pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
        pm_genpd_init(&pd->genpd, NULL, false);
 
        pmu->genpd_data.domains[id] = &pd->genpd;
index a75f2a2cf7805539262536c11f1d1d46aa51d7aa..603783976b8152d4374b201a827a487f91a28592 100644 (file)
@@ -1,10 +1,6 @@
 #
 # SPI driver configuration
 #
-# NOTE:  the reason this doesn't show SPI slave support is mostly that
-# nobody's needed a slave side API yet.  The master-role API is not
-# fully appropriate there, so it'd need some thought to do well.
-#
 menuconfig SPI
        bool "SPI support"
        depends on HAS_IOMEM
@@ -379,7 +375,7 @@ config SPI_FSL_DSPI
        tristate "Freescale DSPI controller"
        select REGMAP_MMIO
        depends on HAS_DMA
-       depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
+       depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || M5441x || COMPILE_TEST
        help
          This enables support for the Freescale DSPI controller in master
          mode. VF610 platform uses the controller.
@@ -626,6 +622,13 @@ config SPI_SIRF
        help
          SPI driver for CSR SiRFprimaII SoCs
 
+config SPI_SPRD_ADI
+       tristate "Spreadtrum ADI controller"
+       depends on ARCH_SPRD || COMPILE_TEST
+       depends on HWSPINLOCK || (COMPILE_TEST && !HWSPINLOCK)
+       help
+         ADI driver based on SPI for Spreadtrum SoCs.
+
 config SPI_STM32
        tristate "STMicroelectronics STM32 SPI controller"
        depends on ARCH_STM32 || COMPILE_TEST
index 8e0cda73b324850fc6ab10971f2b9bc420929af3..34c5f2832ddfc19dd6ead22529da4d08a4e238c5 100644 (file)
@@ -91,6 +91,7 @@ obj-$(CONFIG_SPI_SH_HSPI)             += spi-sh-hspi.o
 obj-$(CONFIG_SPI_SH_MSIOF)             += spi-sh-msiof.o
 obj-$(CONFIG_SPI_SH_SCI)               += spi-sh-sci.o
 obj-$(CONFIG_SPI_SIRF)         += spi-sirf.o
+obj-$(CONFIG_SPI_SPRD_ADI)             += spi-sprd-adi.o
 obj-$(CONFIG_SPI_STM32)                += spi-stm32.o
 obj-$(CONFIG_SPI_ST_SSC4)              += spi-st-ssc4.o
 obj-$(CONFIG_SPI_SUN4I)                        += spi-sun4i.o
index 568e1c65aa82cb77a92b7df5ff066513c3d959a8..77fe55ce790c61a8835c4e2338a36be43dafcbac 100644 (file)
@@ -213,7 +213,7 @@ static void a3700_spi_mode_set(struct a3700_spi *a3700_spi,
 }
 
 static void a3700_spi_clock_set(struct a3700_spi *a3700_spi,
-                               unsigned int speed_hz, u16 mode)
+                               unsigned int speed_hz)
 {
        u32 val;
        u32 prescale;
@@ -231,17 +231,6 @@ static void a3700_spi_clock_set(struct a3700_spi *a3700_spi,
                val |= A3700_SPI_CLK_CAPT_EDGE;
                spireg_write(a3700_spi, A3700_SPI_IF_TIME_REG, val);
        }
-
-       val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
-       val &= ~(A3700_SPI_CLK_POL | A3700_SPI_CLK_PHA);
-
-       if (mode & SPI_CPOL)
-               val |= A3700_SPI_CLK_POL;
-
-       if (mode & SPI_CPHA)
-               val |= A3700_SPI_CLK_PHA;
-
-       spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
 }
 
 static void a3700_spi_bytelen_set(struct a3700_spi *a3700_spi, unsigned int len)
@@ -423,7 +412,7 @@ static void a3700_spi_transfer_setup(struct spi_device *spi,
 
        a3700_spi = spi_master_get_devdata(spi->master);
 
-       a3700_spi_clock_set(a3700_spi, xfer->speed_hz, spi->mode);
+       a3700_spi_clock_set(a3700_spi, xfer->speed_hz);
 
        byte_len = xfer->bits_per_word >> 3;
 
@@ -584,6 +573,8 @@ static int a3700_spi_prepare_message(struct spi_master *master,
 
        a3700_spi_bytelen_set(a3700_spi, 4);
 
+       a3700_spi_mode_set(a3700_spi, spi->mode);
+
        return 0;
 }
 
index 6ab4c770022882eacc338a31b345c0d80bc1b541..68cfc351b47f6e10848cb176c7022307badf2509 100644 (file)
@@ -553,7 +553,7 @@ err_put_master:
 
 static int spi_engine_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
        struct spi_engine *spi_engine = spi_master_get_devdata(master);
        int irq = platform_get_irq(pdev, 0);
 
@@ -561,6 +561,8 @@ static int spi_engine_remove(struct platform_device *pdev)
 
        free_irq(irq, master);
 
+       spi_master_put(master);
+
        writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
        writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
        writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET);
index d89127f4a46dfd567e2c7cfb290833d038c930ed..f652f70cb8db1652d5075e16f5b12fc5452362cc 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/regmap.h>
 #include <linux/sched.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/spi-fsl-dspi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/time.h>
 
@@ -151,6 +152,11 @@ static const struct fsl_dspi_devtype_data ls2085a_data = {
        .max_clock_factor = 8,
 };
 
+static const struct fsl_dspi_devtype_data coldfire_data = {
+       .trans_mode = DSPI_EOQ_MODE,
+       .max_clock_factor = 8,
+};
+
 struct fsl_dspi_dma {
        /* Length of transfer in words of DSPI_FIFO_SIZE */
        u32 curr_xfer_len;
@@ -741,6 +747,7 @@ static int dspi_setup(struct spi_device *spi)
 {
        struct chip_data *chip;
        struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
+       struct fsl_dspi_platform_data *pdata;
        u32 cs_sck_delay = 0, sck_cs_delay = 0;
        unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
        unsigned char pasc = 0, asc = 0, fmsz = 0;
@@ -761,11 +768,18 @@ static int dspi_setup(struct spi_device *spi)
                        return -ENOMEM;
        }
 
-       of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay",
-                       &cs_sck_delay);
+       pdata = dev_get_platdata(&dspi->pdev->dev);
 
-       of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay",
-                       &sck_cs_delay);
+       if (!pdata) {
+               of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay",
+                               &cs_sck_delay);
+
+               of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay",
+                               &sck_cs_delay);
+       } else {
+               cs_sck_delay = pdata->cs_sck_delay;
+               sck_cs_delay = pdata->sck_cs_delay;
+       }
 
        chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
                SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
@@ -949,6 +963,7 @@ static int dspi_probe(struct platform_device *pdev)
        struct fsl_dspi *dspi;
        struct resource *res;
        void __iomem *base;
+       struct fsl_dspi_platform_data *pdata;
        int ret = 0, cs_num, bus_num;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
@@ -969,25 +984,34 @@ static int dspi_probe(struct platform_device *pdev)
        master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) |
                                        SPI_BPW_MASK(16);
 
-       ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "can't get spi-num-chipselects\n");
-               goto out_master_put;
-       }
-       master->num_chipselect = cs_num;
+       pdata = dev_get_platdata(&pdev->dev);
+       if (pdata) {
+               master->num_chipselect = pdata->cs_num;
+               master->bus_num = pdata->bus_num;
 
-       ret = of_property_read_u32(np, "bus-num", &bus_num);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "can't get bus-num\n");
-               goto out_master_put;
-       }
-       master->bus_num = bus_num;
+               dspi->devtype_data = &coldfire_data;
+       } else {
 
-       dspi->devtype_data = of_device_get_match_data(&pdev->dev);
-       if (!dspi->devtype_data) {
-               dev_err(&pdev->dev, "can't get devtype_data\n");
-               ret = -EFAULT;
-               goto out_master_put;
+               ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "can't get spi-num-chipselects\n");
+                       goto out_master_put;
+               }
+               master->num_chipselect = cs_num;
+
+               ret = of_property_read_u32(np, "bus-num", &bus_num);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "can't get bus-num\n");
+                       goto out_master_put;
+               }
+               master->bus_num = bus_num;
+
+               dspi->devtype_data = of_device_get_match_data(&pdev->dev);
+               if (!dspi->devtype_data) {
+                       dev_err(&pdev->dev, "can't get devtype_data\n");
+                       ret = -EFAULT;
+                       goto out_master_put;
+               }
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index babb15f079951021ca2669e68898adcc44fb646c..79ddefe4180d6ccd643afd36e003af8997a8fa39 100644 (file)
 /* generic defines to abstract from the different register layouts */
 #define MXC_INT_RR     (1 << 0) /* Receive data ready interrupt */
 #define MXC_INT_TE     (1 << 1) /* Transmit FIFO empty interrupt */
+#define MXC_INT_RDR    BIT(4) /* Receive date threshold interrupt */
 
 /* The maximum  bytes that a sdma BD can transfer.*/
 #define MAX_SDMA_BD_BYTES  (1 << 15)
 #define MX51_ECSPI_CTRL_MAX_BURST      512
+/* The maximum bytes that IMX53_ECSPI can transfer in slave mode.*/
+#define MX53_MAX_TRANSFER_BYTES                512
 
 enum spi_imx_devtype {
        IMX1_CSPI,
@@ -76,7 +79,9 @@ struct spi_imx_devtype_data {
        void (*trigger)(struct spi_imx_data *);
        int (*rx_available)(struct spi_imx_data *);
        void (*reset)(struct spi_imx_data *);
+       void (*disable)(struct spi_imx_data *);
        bool has_dmamode;
+       bool has_slavemode;
        unsigned int fifo_size;
        bool dynamic_burst;
        enum spi_imx_devtype devtype;
@@ -108,6 +113,11 @@ struct spi_imx_data {
        unsigned int dynamic_burst, read_u32;
        unsigned int word_mask;
 
+       /* Slave mode */
+       bool slave_mode;
+       bool slave_aborted;
+       unsigned int slave_burst;
+
        /* DMA */
        bool usedma;
        u32 wml;
@@ -221,6 +231,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
        if (!master->dma_rx)
                return false;
 
+       if (spi_imx->slave_mode)
+               return false;
+
        bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
 
        if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
@@ -262,6 +275,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 #define MX51_ECSPI_INT         0x10
 #define MX51_ECSPI_INT_TEEN            (1 <<  0)
 #define MX51_ECSPI_INT_RREN            (1 <<  3)
+#define MX51_ECSPI_INT_RDREN           (1 <<  4)
 
 #define MX51_ECSPI_DMA      0x14
 #define MX51_ECSPI_DMA_TX_WML(wml)     ((wml) & 0x3f)
@@ -378,6 +392,44 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
                spi_imx_buf_tx_u16(spi_imx);
 }
 
+static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
+{
+       u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA));
+
+       if (spi_imx->rx_buf) {
+               int n_bytes = spi_imx->slave_burst % sizeof(val);
+
+               if (!n_bytes)
+                       n_bytes = sizeof(val);
+
+               memcpy(spi_imx->rx_buf,
+                      ((u8 *)&val) + sizeof(val) - n_bytes, n_bytes);
+
+               spi_imx->rx_buf += n_bytes;
+               spi_imx->slave_burst -= n_bytes;
+       }
+}
+
+static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
+{
+       u32 val = 0;
+       int n_bytes = spi_imx->count % sizeof(val);
+
+       if (!n_bytes)
+               n_bytes = sizeof(val);
+
+       if (spi_imx->tx_buf) {
+               memcpy(((u8 *)&val) + sizeof(val) - n_bytes,
+                      spi_imx->tx_buf, n_bytes);
+               val = cpu_to_be32(val);
+               spi_imx->tx_buf += n_bytes;
+       }
+
+       spi_imx->count -= n_bytes;
+
+       writel(val, spi_imx->base + MXC_CSPITXDATA);
+}
+
 /* MX51 eCSPI */
 static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
                                      unsigned int fspi, unsigned int *fres)
@@ -427,6 +479,9 @@ static void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
        if (enable & MXC_INT_RR)
                val |= MX51_ECSPI_INT_RREN;
 
+       if (enable & MXC_INT_RDR)
+               val |= MX51_ECSPI_INT_RDREN;
+
        writel(val, spi_imx->base + MX51_ECSPI_INT);
 }
 
@@ -439,6 +494,15 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
        writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
 }
 
+static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
+{
+       u32 ctrl;
+
+       ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+       ctrl &= ~MX51_ECSPI_CTRL_ENABLE;
+       writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+}
+
 static int mx51_ecspi_config(struct spi_device *spi)
 {
        struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
@@ -446,14 +510,11 @@ static int mx51_ecspi_config(struct spi_device *spi)
        u32 clk = spi_imx->speed_hz, delay, reg;
        u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
 
-       /*
-        * The hardware seems to have a race condition when changing modes. The
-        * current assumption is that the selection of the channel arrives
-        * earlier in the hardware than the mode bits when they are written at
-        * the same time.
-        * So set master mode for all channels as we do not support slave mode.
-        */
-       ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
+       /* set Master or Slave mode */
+       if (spi_imx->slave_mode)
+               ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK;
+       else
+               ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
 
        /*
         * Enable SPI_RDY handling (falling edge/level triggered).
@@ -468,9 +529,22 @@ static int mx51_ecspi_config(struct spi_device *spi)
        /* set chip select to use */
        ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
 
-       ctrl |= (spi_imx->bits_per_word - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
+       if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+               ctrl |= (spi_imx->slave_burst * 8 - 1)
+                       << MX51_ECSPI_CTRL_BL_OFFSET;
+       else
+               ctrl |= (spi_imx->bits_per_word - 1)
+                       << MX51_ECSPI_CTRL_BL_OFFSET;
 
-       cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
+       /*
+        * eCSPI burst completion by Chip Select signal in Slave mode
+        * is not functional for imx53 Soc, config SPI burst completed when
+        * BURST_LENGTH + 1 bits are received
+        */
+       if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+               cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
+       else
+               cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
 
        if (spi->mode & SPI_CPHA)
                cfg |= MX51_ECSPI_CONFIG_SCLKPHA(spi->chip_select);
@@ -805,6 +879,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
        .fifo_size = 8,
        .has_dmamode = false,
        .dynamic_burst = false,
+       .has_slavemode = false,
        .devtype = IMX1_CSPI,
 };
 
@@ -817,6 +892,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
        .fifo_size = 8,
        .has_dmamode = false,
        .dynamic_burst = false,
+       .has_slavemode = false,
        .devtype = IMX21_CSPI,
 };
 
@@ -830,6 +906,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
        .fifo_size = 8,
        .has_dmamode = false,
        .dynamic_burst = false,
+       .has_slavemode = false,
        .devtype = IMX27_CSPI,
 };
 
@@ -842,6 +919,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
        .fifo_size = 8,
        .has_dmamode = false,
        .dynamic_burst = false,
+       .has_slavemode = false,
        .devtype = IMX31_CSPI,
 };
 
@@ -855,6 +933,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
        .fifo_size = 8,
        .has_dmamode = true,
        .dynamic_burst = false,
+       .has_slavemode = false,
        .devtype = IMX35_CSPI,
 };
 
@@ -867,6 +946,8 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
        .fifo_size = 64,
        .has_dmamode = true,
        .dynamic_burst = true,
+       .has_slavemode = true,
+       .disable = mx51_ecspi_disable,
        .devtype = IMX51_ECSPI,
 };
 
@@ -878,6 +959,8 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
        .reset = mx51_ecspi_reset,
        .fifo_size = 64,
        .has_dmamode = true,
+       .has_slavemode = true,
+       .disable = mx51_ecspi_disable,
        .devtype = IMX53_ECSPI,
 };
 
@@ -945,14 +1028,16 @@ static void spi_imx_push(struct spi_imx_data *spi_imx)
                spi_imx->txfifo++;
        }
 
-       spi_imx->devtype_data->trigger(spi_imx);
+       if (!spi_imx->slave_mode)
+               spi_imx->devtype_data->trigger(spi_imx);
 }
 
 static irqreturn_t spi_imx_isr(int irq, void *dev_id)
 {
        struct spi_imx_data *spi_imx = dev_id;
 
-       while (spi_imx->devtype_data->rx_available(spi_imx)) {
+       while (spi_imx->txfifo &&
+              spi_imx->devtype_data->rx_available(spi_imx)) {
                spi_imx->rx(spi_imx);
                spi_imx->txfifo--;
        }
@@ -1034,7 +1119,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
        spi_imx->speed_hz  = t->speed_hz;
 
        /* Initialize the functions for transfer */
-       if (spi_imx->devtype_data->dynamic_burst) {
+       if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) {
                u32 mask;
 
                spi_imx->dynamic_burst = 0;
@@ -1078,6 +1163,12 @@ static int spi_imx_setupxfer(struct spi_device *spi,
                        return ret;
        }
 
+       if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
+               spi_imx->rx = mx53_ecspi_rx_slave;
+               spi_imx->tx = mx53_ecspi_tx_slave;
+               spi_imx->slave_burst = t->len;
+       }
+
        spi_imx->devtype_data->config(spi);
 
        return 0;
@@ -1262,11 +1353,61 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
        return transfer->len;
 }
 
+static int spi_imx_pio_transfer_slave(struct spi_device *spi,
+                                     struct spi_transfer *transfer)
+{
+       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+       int ret = transfer->len;
+
+       if (is_imx53_ecspi(spi_imx) &&
+           transfer->len > MX53_MAX_TRANSFER_BYTES) {
+               dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n",
+                       MX53_MAX_TRANSFER_BYTES);
+               return -EMSGSIZE;
+       }
+
+       spi_imx->tx_buf = transfer->tx_buf;
+       spi_imx->rx_buf = transfer->rx_buf;
+       spi_imx->count = transfer->len;
+       spi_imx->txfifo = 0;
+
+       reinit_completion(&spi_imx->xfer_done);
+       spi_imx->slave_aborted = false;
+
+       spi_imx_push(spi_imx);
+
+       spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE | MXC_INT_RDR);
+
+       if (wait_for_completion_interruptible(&spi_imx->xfer_done) ||
+           spi_imx->slave_aborted) {
+               dev_dbg(&spi->dev, "interrupted\n");
+               ret = -EINTR;
+       }
+
+       /* ecspi has a HW issue when works in Slave mode,
+        * after 64 words writtern to TXFIFO, even TXFIFO becomes empty,
+        * ECSPI_TXDATA keeps shift out the last word data,
+        * so we have to disable ECSPI when in slave mode after the
+        * transfer completes
+        */
+       if (spi_imx->devtype_data->disable)
+               spi_imx->devtype_data->disable(spi_imx);
+
+       return ret;
+}
+
 static int spi_imx_transfer(struct spi_device *spi,
                                struct spi_transfer *transfer)
 {
        struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
 
+       /* flush rxfifo before transfer */
+       while (spi_imx->devtype_data->rx_available(spi_imx))
+               spi_imx->rx(spi_imx);
+
+       if (spi_imx->slave_mode)
+               return spi_imx_pio_transfer_slave(spi, transfer);
+
        if (spi_imx->usedma)
                return spi_imx_dma_transfer(spi_imx, transfer);
        else
@@ -1323,6 +1464,16 @@ spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg)
        return 0;
 }
 
+static int spi_imx_slave_abort(struct spi_master *master)
+{
+       struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+
+       spi_imx->slave_aborted = true;
+       complete(&spi_imx->xfer_done);
+
+       return 0;
+}
+
 static int spi_imx_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -1334,13 +1485,23 @@ static int spi_imx_probe(struct platform_device *pdev)
        struct spi_imx_data *spi_imx;
        struct resource *res;
        int i, ret, irq, spi_drctl;
+       const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data :
+               (struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
+       bool slave_mode;
 
        if (!np && !mxc_platform_info) {
                dev_err(&pdev->dev, "can't get the platform data\n");
                return -EINVAL;
        }
 
-       master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
+       slave_mode = devtype_data->has_slavemode &&
+                       of_property_read_bool(np, "spi-slave");
+       if (slave_mode)
+               master = spi_alloc_slave(&pdev->dev,
+                                        sizeof(struct spi_imx_data));
+       else
+               master = spi_alloc_master(&pdev->dev,
+                                         sizeof(struct spi_imx_data));
        if (!master)
                return -ENOMEM;
 
@@ -1358,20 +1519,29 @@ static int spi_imx_probe(struct platform_device *pdev)
        spi_imx = spi_master_get_devdata(master);
        spi_imx->bitbang.master = master;
        spi_imx->dev = &pdev->dev;
+       spi_imx->slave_mode = slave_mode;
 
-       spi_imx->devtype_data = of_id ? of_id->data :
-               (struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
+       spi_imx->devtype_data = devtype_data;
 
+       /* Get number of chip selects, either platform data or OF */
        if (mxc_platform_info) {
                master->num_chipselect = mxc_platform_info->num_chipselect;
-               master->cs_gpios = devm_kzalloc(&master->dev,
-                       sizeof(int) * master->num_chipselect, GFP_KERNEL);
-               if (!master->cs_gpios)
-                       return -ENOMEM;
+               if (mxc_platform_info->chipselect) {
+                       master->cs_gpios = devm_kzalloc(&master->dev,
+                               sizeof(int) * master->num_chipselect, GFP_KERNEL);
+                       if (!master->cs_gpios)
+                               return -ENOMEM;
+
+                       for (i = 0; i < master->num_chipselect; i++)
+                               master->cs_gpios[i] = mxc_platform_info->chipselect[i];
+               }
+       } else {
+               u32 num_cs;
 
-               for (i = 0; i < master->num_chipselect; i++)
-                       master->cs_gpios[i] = mxc_platform_info->chipselect[i];
-       }
+               if (!of_property_read_u32(np, "num-cs", &num_cs))
+                       master->num_chipselect = num_cs;
+               /* If not preset, default value of 1 is used */
+       }
 
        spi_imx->bitbang.chipselect = spi_imx_chipselect;
        spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
@@ -1380,6 +1550,7 @@ static int spi_imx_probe(struct platform_device *pdev)
        spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
        spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
        spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
+       spi_imx->bitbang.master->slave_abort = spi_imx_slave_abort;
        spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
                                             | SPI_NO_CS;
        if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
@@ -1451,37 +1622,38 @@ static int spi_imx_probe(struct platform_device *pdev)
        spi_imx->devtype_data->intctrl(spi_imx, 0);
 
        master->dev.of_node = pdev->dev.of_node;
+
+       /* Request GPIO CS lines, if any */
+       if (!spi_imx->slave_mode && master->cs_gpios) {
+               for (i = 0; i < master->num_chipselect; i++) {
+                       if (!gpio_is_valid(master->cs_gpios[i]))
+                               continue;
+
+                       ret = devm_gpio_request(&pdev->dev,
+                                               master->cs_gpios[i],
+                                               DRIVER_NAME);
+                       if (ret) {
+                               dev_err(&pdev->dev, "Can't get CS GPIO %i\n",
+                                       master->cs_gpios[i]);
+                               goto out_spi_bitbang;
+                       }
+               }
+       }
+
        ret = spi_bitbang_start(&spi_imx->bitbang);
        if (ret) {
                dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
                goto out_clk_put;
        }
 
-       if (!master->cs_gpios) {
-               dev_err(&pdev->dev, "No CS GPIOs available\n");
-               ret = -EINVAL;
-               goto out_clk_put;
-       }
-
-       for (i = 0; i < master->num_chipselect; i++) {
-               if (!gpio_is_valid(master->cs_gpios[i]))
-                       continue;
-
-               ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
-                                       DRIVER_NAME);
-               if (ret) {
-                       dev_err(&pdev->dev, "Can't get CS GPIO %i\n",
-                               master->cs_gpios[i]);
-                       goto out_clk_put;
-               }
-       }
-
        dev_info(&pdev->dev, "probed\n");
 
        clk_disable(spi_imx->clk_ipg);
        clk_disable(spi_imx->clk_per);
        return ret;
 
+out_spi_bitbang:
+       spi_bitbang_stop(&spi_imx->bitbang);
 out_clk_put:
        clk_disable_unprepare(spi_imx->clk_ipg);
 out_put_per:
index 5b0e9a3e83f6944d90f23de597a3a9ff504e3a7b..3d216b950b415192309d8a6947387e92fec1d87d 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/completion.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 #include <linux/module.h>
 #include <linux/stmp_device.h>
 #include <linux/spi/spi.h>
@@ -442,6 +443,85 @@ static int mxs_spi_transfer_one(struct spi_master *master,
        return status;
 }
 
+static int mxs_spi_runtime_suspend(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mxs_spi *spi = spi_master_get_devdata(master);
+       struct mxs_ssp *ssp = &spi->ssp;
+       int ret;
+
+       clk_disable_unprepare(ssp->clk);
+
+       ret = pinctrl_pm_select_idle_state(dev);
+       if (ret) {
+               int ret2 = clk_prepare_enable(ssp->clk);
+
+               if (ret2)
+                       dev_warn(dev, "Failed to reenable clock after failing pinctrl request (pinctrl: %d, clk: %d)\n",
+                                ret, ret2);
+       }
+
+       return ret;
+}
+
+static int mxs_spi_runtime_resume(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mxs_spi *spi = spi_master_get_devdata(master);
+       struct mxs_ssp *ssp = &spi->ssp;
+       int ret;
+
+       ret = pinctrl_pm_select_default_state(dev);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(ssp->clk);
+       if (ret)
+               pinctrl_pm_select_idle_state(dev);
+
+       return ret;
+}
+
+static int __maybe_unused mxs_spi_suspend(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       int ret;
+
+       ret = spi_master_suspend(master);
+       if (ret)
+               return ret;
+
+       if (!pm_runtime_suspended(dev))
+               return mxs_spi_runtime_suspend(dev);
+       else
+               return 0;
+}
+
+static int __maybe_unused mxs_spi_resume(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       int ret;
+
+       if (!pm_runtime_suspended(dev))
+               ret = mxs_spi_runtime_resume(dev);
+       else
+               ret = 0;
+       if (ret)
+               return ret;
+
+       ret = spi_master_resume(master);
+       if (ret < 0 && !pm_runtime_suspended(dev))
+               mxs_spi_runtime_suspend(dev);
+
+       return ret;
+}
+
+static const struct dev_pm_ops mxs_spi_pm = {
+       SET_RUNTIME_PM_OPS(mxs_spi_runtime_suspend,
+                          mxs_spi_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(mxs_spi_suspend, mxs_spi_resume)
+};
+
 static const struct of_device_id mxs_spi_dt_ids[] = {
        { .compatible = "fsl,imx23-spi", .data = (void *) IMX23_SSP, },
        { .compatible = "fsl,imx28-spi", .data = (void *) IMX28_SSP, },
@@ -493,12 +573,15 @@ static int mxs_spi_probe(struct platform_device *pdev)
        if (!master)
                return -ENOMEM;
 
+       platform_set_drvdata(pdev, master);
+
        master->transfer_one_message = mxs_spi_transfer_one;
        master->bits_per_word_mask = SPI_BPW_MASK(8);
        master->mode_bits = SPI_CPOL | SPI_CPHA;
        master->num_chipselect = 3;
        master->dev.of_node = np;
        master->flags = SPI_MASTER_HALF_DUPLEX;
+       master->auto_runtime_pm = true;
 
        spi = spi_master_get_devdata(master);
        ssp = &spi->ssp;
@@ -521,28 +604,41 @@ static int mxs_spi_probe(struct platform_device *pdev)
                goto out_master_free;
        }
 
-       ret = clk_prepare_enable(ssp->clk);
-       if (ret)
-               goto out_dma_release;
+       pm_runtime_enable(ssp->dev);
+       if (!pm_runtime_enabled(ssp->dev)) {
+               ret = mxs_spi_runtime_resume(ssp->dev);
+               if (ret < 0) {
+                       dev_err(ssp->dev, "runtime resume failed\n");
+                       goto out_dma_release;
+               }
+       }
+
+       ret = pm_runtime_get_sync(ssp->dev);
+       if (ret < 0) {
+               dev_err(ssp->dev, "runtime_get_sync failed\n");
+               goto out_pm_runtime_disable;
+       }
 
        clk_set_rate(ssp->clk, clk_freq);
 
        ret = stmp_reset_block(ssp->base);
        if (ret)
-               goto out_disable_clk;
-
-       platform_set_drvdata(pdev, master);
+               goto out_pm_runtime_put;
 
        ret = devm_spi_register_master(&pdev->dev, master);
        if (ret) {
                dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
-               goto out_disable_clk;
+               goto out_pm_runtime_put;
        }
 
+       pm_runtime_put(ssp->dev);
+
        return 0;
 
-out_disable_clk:
-       clk_disable_unprepare(ssp->clk);
+out_pm_runtime_put:
+       pm_runtime_put(ssp->dev);
+out_pm_runtime_disable:
+       pm_runtime_disable(ssp->dev);
 out_dma_release:
        dma_release_channel(ssp->dmach);
 out_master_free:
@@ -560,7 +656,10 @@ static int mxs_spi_remove(struct platform_device *pdev)
        spi = spi_master_get_devdata(master);
        ssp = &spi->ssp;
 
-       clk_disable_unprepare(ssp->clk);
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               mxs_spi_runtime_suspend(&pdev->dev);
+
        dma_release_channel(ssp->dmach);
 
        return 0;
@@ -572,6 +671,7 @@ static struct platform_driver mxs_spi_driver = {
        .driver = {
                .name   = DRIVER_NAME,
                .of_match_table = mxs_spi_dt_ids,
+               .pm = &mxs_spi_pm,
        },
 };
 
index 4b6dd73b80da0f034976e5781dd34089377e408c..8974bb340b3abe40a438df71545396aa5c095f2d 100644 (file)
@@ -671,7 +671,6 @@ static int orion_spi_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "%pOF has no valid 'reg' property (%d)\n",
                                np, status);
-                       status = 0;
                        continue;
                }
 
index 2a10b3f94ff72a4ea3d6924a082ef6d2db174528..2ce875764ca646a2bdfb803cae33465ab8fa1786 100644 (file)
@@ -1221,7 +1221,6 @@ static int rspi_probe(struct platform_device *pdev)
        struct spi_master *master;
        struct rspi_data *rspi;
        int ret;
-       const struct of_device_id *of_id;
        const struct rspi_plat_data *rspi_pd;
        const struct spi_ops *ops;
 
@@ -1229,9 +1228,8 @@ static int rspi_probe(struct platform_device *pdev)
        if (master == NULL)
                return -ENOMEM;
 
-       of_id = of_match_device(rspi_of_match, &pdev->dev);
-       if (of_id) {
-               ops = of_id->data;
+       ops = of_device_get_match_data(&pdev->dev);
+       if (ops) {
                ret = rspi_parse_dt(&pdev->dev, master);
                if (ret)
                        goto error1;
index b392cca8fa4f5ba3c1c499ea8b1bc228fcabdbee..de7df20f8712dd74dc074e763555891f076b820f 100644 (file)
@@ -752,7 +752,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
 {
        struct s3c64xx_spi_csinfo *cs = spi->controller_data;
        struct s3c64xx_spi_driver_data *sdd;
-       struct s3c64xx_spi_info *sci;
        int err;
 
        sdd = spi_master_get_devdata(spi->master);
@@ -788,8 +787,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
                spi_set_ctldata(spi, cs);
        }
 
-       sci = sdd->cntrlr_info;
-
        pm_runtime_get_sync(&sdd->pdev->dev);
 
        /* Check if we can provide the requested rate */
index 0eb1e95834854fb658806b1aaefc19fb7bec69b3..fcd261f98b9fd92189f1eb9acd8aee7be484af82 100644 (file)
@@ -900,7 +900,7 @@ static int sh_msiof_transfer_one(struct spi_master *master,
                                break;
                        copy32 = copy_bswap32;
                } else if (bits <= 16) {
-                       if (l & 1)
+                       if (l & 3)
                                break;
                        copy32 = copy_wswap32;
                } else {
@@ -1021,6 +1021,8 @@ static const struct sh_msiof_chipdata rcar_gen3_data = {
 
 static const struct of_device_id sh_msiof_match[] = {
        { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
+       { .compatible = "renesas,msiof-r8a7743",   .data = &rcar_gen2_data },
+       { .compatible = "renesas,msiof-r8a7745",   .data = &rcar_gen2_data },
        { .compatible = "renesas,msiof-r8a7790",   .data = &rcar_gen2_data },
        { .compatible = "renesas,msiof-r8a7791",   .data = &rcar_gen2_data },
        { .compatible = "renesas,msiof-r8a7792",   .data = &rcar_gen2_data },
@@ -1188,12 +1190,10 @@ free_tx_chan:
 static void sh_msiof_release_dma(struct sh_msiof_spi_priv *p)
 {
        struct spi_master *master = p->master;
-       struct device *dev;
 
        if (!master->dma_tx)
                return;
 
-       dev = &p->pdev->dev;
        dma_unmap_single(master->dma_rx->device->dev, p->rx_dma_addr,
                         PAGE_SIZE, DMA_FROM_DEVICE);
        dma_unmap_single(master->dma_tx->device->dev, p->tx_dma_addr,
@@ -1209,15 +1209,13 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
        struct resource *r;
        struct spi_master *master;
        const struct sh_msiof_chipdata *chipdata;
-       const struct of_device_id *of_id;
        struct sh_msiof_spi_info *info;
        struct sh_msiof_spi_priv *p;
        int i;
        int ret;
 
-       of_id = of_match_device(sh_msiof_match, &pdev->dev);
-       if (of_id) {
-               chipdata = of_id->data;
+       chipdata = of_device_get_match_data(&pdev->dev);
+       if (chipdata) {
                info = sh_msiof_spi_parse_dt(&pdev->dev);
        } else {
                chipdata = (const void *)pdev->id_entry->driver_data;
diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c
new file mode 100644 (file)
index 0000000..5993bdb
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2017 Spreadtrum Communications Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/hwspinlock.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/sizes.h>
+
+/* Registers definitions for ADI controller */
+#define REG_ADI_CTRL0                  0x4
+#define REG_ADI_CHN_PRIL               0x8
+#define REG_ADI_CHN_PRIH               0xc
+#define REG_ADI_INT_EN                 0x10
+#define REG_ADI_INT_RAW                        0x14
+#define REG_ADI_INT_MASK               0x18
+#define REG_ADI_INT_CLR                        0x1c
+#define REG_ADI_GSSI_CFG0              0x20
+#define REG_ADI_GSSI_CFG1              0x24
+#define REG_ADI_RD_CMD                 0x28
+#define REG_ADI_RD_DATA                        0x2c
+#define REG_ADI_ARM_FIFO_STS           0x30
+#define REG_ADI_STS                    0x34
+#define REG_ADI_EVT_FIFO_STS           0x38
+#define REG_ADI_ARM_CMD_STS            0x3c
+#define REG_ADI_CHN_EN                 0x40
+#define REG_ADI_CHN_ADDR(id)           (0x44 + (id - 2) * 4)
+#define REG_ADI_CHN_EN1                        0x20c
+
+/* Bits definitions for register REG_ADI_GSSI_CFG0 */
+#define BIT_CLK_ALL_ON                 BIT(30)
+
+/* Bits definitions for register REG_ADI_RD_DATA */
+#define BIT_RD_CMD_BUSY                        BIT(31)
+#define RD_ADDR_SHIFT                  16
+#define RD_VALUE_MASK                  GENMASK(15, 0)
+#define RD_ADDR_MASK                   GENMASK(30, 16)
+
+/* Bits definitions for register REG_ADI_ARM_FIFO_STS */
+#define BIT_FIFO_FULL                  BIT(11)
+#define BIT_FIFO_EMPTY                 BIT(10)
+
+/*
+ * ADI slave devices include RTC, ADC, regulator, charger, thermal and so on.
+ * The slave devices address offset is always 0x8000 and size is 4K.
+ */
+#define ADI_SLAVE_ADDR_SIZE            SZ_4K
+#define ADI_SLAVE_OFFSET               0x8000
+
+/* Timeout (ms) for the trylock of hardware spinlocks */
+#define ADI_HWSPINLOCK_TIMEOUT         5000
+/*
+ * ADI controller has 50 channels including 2 software channels
+ * and 48 hardware channels.
+ */
+#define ADI_HW_CHNS                    50
+
+#define ADI_FIFO_DRAIN_TIMEOUT         1000
+#define ADI_READ_TIMEOUT               2000
+#define REG_ADDR_LOW_MASK              GENMASK(11, 0)
+
+struct sprd_adi {
+       struct spi_controller   *ctlr;
+       struct device           *dev;
+       void __iomem            *base;
+       struct hwspinlock       *hwlock;
+       unsigned long           slave_vbase;
+       unsigned long           slave_pbase;
+};
+
+static int sprd_adi_check_paddr(struct sprd_adi *sadi, u32 paddr)
+{
+       if (paddr < sadi->slave_pbase || paddr >
+           (sadi->slave_pbase + ADI_SLAVE_ADDR_SIZE)) {
+               dev_err(sadi->dev,
+                       "slave physical address is incorrect, addr = 0x%x\n",
+                       paddr);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static unsigned long sprd_adi_to_vaddr(struct sprd_adi *sadi, u32 paddr)
+{
+       return (paddr - sadi->slave_pbase + sadi->slave_vbase);
+}
+
+static int sprd_adi_drain_fifo(struct sprd_adi *sadi)
+{
+       u32 timeout = ADI_FIFO_DRAIN_TIMEOUT;
+       u32 sts;
+
+       do {
+               sts = readl_relaxed(sadi->base + REG_ADI_ARM_FIFO_STS);
+               if (sts & BIT_FIFO_EMPTY)
+                       break;
+
+               cpu_relax();
+       } while (--timeout);
+
+       if (timeout == 0) {
+               dev_err(sadi->dev, "drain write fifo timeout\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int sprd_adi_fifo_is_full(struct sprd_adi *sadi)
+{
+       return readl_relaxed(sadi->base + REG_ADI_ARM_FIFO_STS) & BIT_FIFO_FULL;
+}
+
+static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val)
+{
+       int read_timeout = ADI_READ_TIMEOUT;
+       u32 val, rd_addr;
+
+       /*
+        * Set the physical register address need to read into RD_CMD register,
+        * then ADI controller will start to transfer automatically.
+        */
+       writel_relaxed(reg_paddr, sadi->base + REG_ADI_RD_CMD);
+
+       /*
+        * Wait read operation complete, the BIT_RD_CMD_BUSY will be set
+        * simultaneously when writing read command to register, and the
+        * BIT_RD_CMD_BUSY will be cleared after the read operation is
+        * completed.
+        */
+       do {
+               val = readl_relaxed(sadi->base + REG_ADI_RD_DATA);
+               if (!(val & BIT_RD_CMD_BUSY))
+                       break;
+
+               cpu_relax();
+       } while (--read_timeout);
+
+       if (read_timeout == 0) {
+               dev_err(sadi->dev, "ADI read timeout\n");
+               return -EBUSY;
+       }
+
+       /*
+        * The return value includes data and read register address, from bit 0
+        * to bit 15 are data, and from bit 16 to bit 30 are read register
+        * address. Then we can check the returned register address to validate
+        * data.
+        */
+       rd_addr = (val & RD_ADDR_MASK ) >> RD_ADDR_SHIFT;
+
+       if (rd_addr != (reg_paddr & REG_ADDR_LOW_MASK)) {
+               dev_err(sadi->dev, "read error, reg addr = 0x%x, val = 0x%x\n",
+                       reg_paddr, val);
+               return -EIO;
+       }
+
+       *read_val = val & RD_VALUE_MASK;
+       return 0;
+}
+
+static int sprd_adi_write(struct sprd_adi *sadi, unsigned long reg, u32 val)
+{
+       u32 timeout = ADI_FIFO_DRAIN_TIMEOUT;
+       int ret;
+
+       ret = sprd_adi_drain_fifo(sadi);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * we should wait for write fifo is empty before writing data to PMIC
+        * registers.
+        */
+       do {
+               if (!sprd_adi_fifo_is_full(sadi)) {
+                       writel_relaxed(val, (void __iomem *)reg);
+                       break;
+               }
+
+               cpu_relax();
+       } while (--timeout);
+
+       if (timeout == 0) {
+               dev_err(sadi->dev, "write fifo is full\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int sprd_adi_transfer_one(struct spi_controller *ctlr,
+                                struct spi_device *spi_dev,
+                                struct spi_transfer *t)
+{
+       struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
+       unsigned long flags, virt_reg;
+       u32 phy_reg, val;
+       int ret;
+
+       if (t->rx_buf) {
+               phy_reg = *(u32 *)t->rx_buf + sadi->slave_pbase;
+
+               ret = sprd_adi_check_paddr(sadi, phy_reg);
+               if (ret)
+                       return ret;
+
+               ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
+                                                 ADI_HWSPINLOCK_TIMEOUT,
+                                                 &flags);
+               if (ret) {
+                       dev_err(sadi->dev, "get the hw lock failed\n");
+                       return ret;
+               }
+
+               ret = sprd_adi_read(sadi, phy_reg, &val);
+               hwspin_unlock_irqrestore(sadi->hwlock, &flags);
+               if (ret)
+                       return ret;
+
+               *(u32 *)t->rx_buf = val;
+       } else if (t->tx_buf) {
+               u32 *p = (u32 *)t->tx_buf;
+
+               /*
+                * Get the physical register address need to write and convert
+                * the physical address to virtual address. Since we need
+                * virtual register address to write.
+                */
+               phy_reg = *p++ + sadi->slave_pbase;
+               ret = sprd_adi_check_paddr(sadi, phy_reg);
+               if (ret)
+                       return ret;
+
+               virt_reg = sprd_adi_to_vaddr(sadi, phy_reg);
+               val = *p;
+
+               ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
+                                                 ADI_HWSPINLOCK_TIMEOUT,
+                                                 &flags);
+               if (ret) {
+                       dev_err(sadi->dev, "get the hw lock failed\n");
+                       return ret;
+               }
+
+               ret = sprd_adi_write(sadi, virt_reg, val);
+               hwspin_unlock_irqrestore(sadi->hwlock, &flags);
+               if (ret)
+                       return ret;
+       } else {
+               dev_err(sadi->dev, "no buffer for transfer\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void sprd_adi_hw_init(struct sprd_adi *sadi)
+{
+       struct device_node *np = sadi->dev->of_node;
+       int i, size, chn_cnt;
+       const __be32 *list;
+       u32 tmp;
+
+       /* Address bits select default 12 bits */
+       writel_relaxed(0, sadi->base + REG_ADI_CTRL0);
+
+       /* Set all channels as default priority */
+       writel_relaxed(0, sadi->base + REG_ADI_CHN_PRIL);
+       writel_relaxed(0, sadi->base + REG_ADI_CHN_PRIH);
+
+       /* Set clock auto gate mode */
+       tmp = readl_relaxed(sadi->base + REG_ADI_GSSI_CFG0);
+       tmp &= ~BIT_CLK_ALL_ON;
+       writel_relaxed(tmp, sadi->base + REG_ADI_GSSI_CFG0);
+
+       /* Set hardware channels setting */
+       list = of_get_property(np, "sprd,hw-channels", &size);
+       if (!list || !size) {
+               dev_info(sadi->dev, "no hw channels setting in node\n");
+               return;
+       }
+
+       chn_cnt = size / 8;
+       for (i = 0; i < chn_cnt; i++) {
+               u32 value;
+               u32 chn_id = be32_to_cpu(*list++);
+               u32 chn_config = be32_to_cpu(*list++);
+
+               /* Channel 0 and 1 are software channels */
+               if (chn_id < 2)
+                       continue;
+
+               writel_relaxed(chn_config, sadi->base +
+                              REG_ADI_CHN_ADDR(chn_id));
+
+               if (chn_id < 32) {
+                       value = readl_relaxed(sadi->base + REG_ADI_CHN_EN);
+                       value |= BIT(chn_id);
+                       writel_relaxed(value, sadi->base + REG_ADI_CHN_EN);
+               } else if (chn_id < ADI_HW_CHNS) {
+                       value = readl_relaxed(sadi->base + REG_ADI_CHN_EN1);
+                       value |= BIT(chn_id - 32);
+                       writel_relaxed(value, sadi->base + REG_ADI_CHN_EN1);
+               }
+       }
+}
+
+static int sprd_adi_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct spi_controller *ctlr;
+       struct sprd_adi *sadi;
+       struct resource *res;
+       u32 num_chipselect;
+       int ret;
+
+       if (!np) {
+               dev_err(&pdev->dev, "can not find the adi bus node\n");
+               return -ENODEV;
+       }
+
+       pdev->id = of_alias_get_id(np, "spi");
+       num_chipselect = of_get_child_count(np);
+
+       ctlr = spi_alloc_master(&pdev->dev, sizeof(struct sprd_adi));
+       if (!ctlr)
+               return -ENOMEM;
+
+       dev_set_drvdata(&pdev->dev, ctlr);
+       sadi = spi_controller_get_devdata(ctlr);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       sadi->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(sadi->base)) {
+               ret = PTR_ERR(sadi->base);
+               goto put_ctlr;
+       }
+
+       sadi->slave_vbase = (unsigned long)sadi->base + ADI_SLAVE_OFFSET;
+       sadi->slave_pbase = res->start + ADI_SLAVE_OFFSET;
+       sadi->ctlr = ctlr;
+       sadi->dev = &pdev->dev;
+       ret = of_hwspin_lock_get_id(np, 0);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "can not get the hardware spinlock\n");
+               goto put_ctlr;
+       }
+
+       sadi->hwlock = hwspin_lock_request_specific(ret);
+       if (!sadi->hwlock) {
+               ret = -ENXIO;
+               goto put_ctlr;
+       }
+
+       sprd_adi_hw_init(sadi);
+
+       ctlr->dev.of_node = pdev->dev.of_node;
+       ctlr->bus_num = pdev->id;
+       ctlr->num_chipselect = num_chipselect;
+       ctlr->flags = SPI_MASTER_HALF_DUPLEX;
+       ctlr->bits_per_word_mask = 0;
+       ctlr->transfer_one = sprd_adi_transfer_one;
+
+       ret = devm_spi_register_controller(&pdev->dev, ctlr);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register SPI controller\n");
+               goto free_hwlock;
+       }
+
+       return 0;
+
+free_hwlock:
+       hwspin_lock_free(sadi->hwlock);
+put_ctlr:
+       spi_controller_put(ctlr);
+       return ret;
+}
+
+static int sprd_adi_remove(struct platform_device *pdev)
+{
+       struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
+       struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
+
+       hwspin_lock_free(sadi->hwlock);
+       return 0;
+}
+
+static const struct of_device_id sprd_adi_of_match[] = {
+       {
+               .compatible = "sprd,sc9860-adi",
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, sprd_adi_of_match);
+
+static struct platform_driver sprd_adi_driver = {
+       .driver = {
+               .name = "sprd-adi",
+               .of_match_table = sprd_adi_of_match,
+       },
+       .probe = sprd_adi_probe,
+       .remove = sprd_adi_remove,
+};
+module_platform_driver(sprd_adi_driver);
+
+MODULE_DESCRIPTION("Spreadtrum ADI Controller Driver");
+MODULE_AUTHOR("Baolin Wang <Baolin.Wang@spreadtrum.com>");
+MODULE_LICENSE("GPL v2");
index 44550182a4a364e53ba1b62da634ca6362d2df90..a76acedd7e2f402190a3525804cc012770747fc7 100644 (file)
@@ -50,7 +50,7 @@
 #define SPI_IDLE_SDA_PULL_LOW                  (2 << 18)
 #define SPI_IDLE_SDA_PULL_HIGH                 (3 << 18)
 #define SPI_IDLE_SDA_MASK                      (3 << 18)
-#define SPI_CS_SS_VAL                          (1 << 20)
+#define SPI_CS_SW_VAL                          (1 << 20)
 #define SPI_CS_SW_HW                           (1 << 21)
 /* SPI_CS_POL_INACTIVE bits are default high */
                                                /* n from 0 to 3 */
@@ -705,9 +705,9 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
 
                command1 |= SPI_CS_SW_HW;
                if (spi->mode & SPI_CS_HIGH)
-                       command1 |= SPI_CS_SS_VAL;
+                       command1 |= SPI_CS_SW_VAL;
                else
-                       command1 &= ~SPI_CS_SS_VAL;
+                       command1 &= ~SPI_CS_SW_VAL;
 
                tegra_spi_writel(tspi, 0, SPI_COMMAND2);
        } else {
index e8b5a5e21b2e692e8af31e93ee3102b0c26872d9..b33a727a0158b19ebae1364a21fd8c9dff22e4e5 100644 (file)
@@ -2200,7 +2200,7 @@ static void devm_spi_unregister(struct device *dev, void *res)
  * Context: can sleep
  *
  * Register a SPI device as with spi_register_controller() which will
- * automatically be unregister
+ * automatically be unregistered and freed.
  *
  * Return: zero on success, else a negative error code.
  */
@@ -2241,15 +2241,18 @@ static int __unregister(struct device *dev, void *null)
  * only ones directly touching chip registers.
  *
  * This must be called from context that can sleep.
+ *
+ * Note that this function also drops a reference to the controller.
  */
 void spi_unregister_controller(struct spi_controller *ctlr)
 {
        struct spi_controller *found;
+       int id = ctlr->bus_num;
        int dummy;
 
        /* First make sure that this controller was ever added */
        mutex_lock(&board_lock);
-       found = idr_find(&spi_master_idr, ctlr->bus_num);
+       found = idr_find(&spi_master_idr, id);
        mutex_unlock(&board_lock);
        if (found != ctlr) {
                dev_dbg(&ctlr->dev,
@@ -2269,7 +2272,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
        device_unregister(&ctlr->dev);
        /* free bus id */
        mutex_lock(&board_lock);
-       idr_remove(&spi_master_idr, ctlr->bus_num);
+       idr_remove(&spi_master_idr, id);
        mutex_unlock(&board_lock);
 }
 EXPORT_SYMBOL_GPL(spi_unregister_controller);
index 56f7be6af1f695a873c9acfe6619d3ec8dafd496..585925bb49a4ec614ec6e3be0b97d9f2d1a257f5 100644 (file)
@@ -1165,7 +1165,7 @@ static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
 
 static void read_all_doc(struct vc_data *vc);
 static void cursor_done(u_long data);
-static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
+static DEFINE_TIMER(cursor_timer, cursor_done);
 
 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
 {
index a1ca68c765792cd73034bb41e0ca18725db50d04..6ddd3fc3f08d15d5aff35e296ee13868eb1ecd74 100644 (file)
@@ -158,7 +158,7 @@ static void thread_wake_up(u_long data)
        wake_up_interruptible_all(&speakup_event);
 }
 
-static DEFINE_TIMER(thread_timer, thread_wake_up, 0, 0);
+static DEFINE_TIMER(thread_timer, thread_wake_up);
 
 void synth_start(void)
 {
index af12925a9d2b58f0c92b8b68a5b01fc41eee63ea..de6ff59e3e6573fa630c7f80a8cfb2452143dbeb 100644 (file)
@@ -267,7 +267,7 @@ static void update_scan_time(void)
                last_scanned_shadow[i].time_scan = jiffies;
 }
 
-static void remove_network_from_shadow(unsigned long arg)
+static void remove_network_from_shadow(unsigned long unused)
 {
        unsigned long now = jiffies;
        int i, j;
@@ -288,7 +288,6 @@ static void remove_network_from_shadow(unsigned long arg)
        }
 
        if (last_scanned_cnt != 0) {
-               hAgingTimer.data = arg;
                mod_timer(&hAgingTimer, jiffies + msecs_to_jiffies(AGING_TIME));
        }
 }
@@ -305,7 +304,6 @@ static int is_network_in_shadow(struct network_info *pstrNetworkInfo,
        int i;
 
        if (last_scanned_cnt == 0) {
-               hAgingTimer.data = (unsigned long)user_void;
                mod_timer(&hAgingTimer, jiffies + msecs_to_jiffies(AGING_TIME));
                state = -1;
        } else {
index 5001261f5d69d759dd25161401510551d35c3da7..9e67c7678c86d2af0aa4617a40686103efa55fd2 100644 (file)
@@ -372,6 +372,8 @@ struct iscsi_np *iscsit_add_np(
        init_completion(&np->np_restart_comp);
        INIT_LIST_HEAD(&np->np_list);
 
+       timer_setup(&np->np_login_timer, iscsi_handle_login_thread_timeout, 0);
+
        ret = iscsi_target_setup_login_socket(np, sockaddr);
        if (ret != 0) {
                kfree(np);
index 7fe2aa73cff69e04f8df8d79e3af1c634fb5ca04..718fe9a1b709f8918a58b562c72a9aaba8e07c8e 100644 (file)
@@ -749,9 +749,9 @@ int iscsit_check_post_dataout(
        }
 }
 
-static void iscsit_handle_time2retain_timeout(unsigned long data)
+void iscsit_handle_time2retain_timeout(struct timer_list *t)
 {
-       struct iscsi_session *sess = (struct iscsi_session *) data;
+       struct iscsi_session *sess = from_timer(sess, t, time2retain_timer);
        struct iscsi_portal_group *tpg = sess->tpg;
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
 
@@ -809,14 +809,10 @@ void iscsit_start_time2retain_handler(struct iscsi_session *sess)
        pr_debug("Starting Time2Retain timer for %u seconds on"
                " SID: %u\n", sess->sess_ops->DefaultTime2Retain, sess->sid);
 
-       init_timer(&sess->time2retain_timer);
-       sess->time2retain_timer.expires =
-               (get_jiffies_64() + sess->sess_ops->DefaultTime2Retain * HZ);
-       sess->time2retain_timer.data = (unsigned long)sess;
-       sess->time2retain_timer.function = iscsit_handle_time2retain_timeout;
        sess->time2retain_timer_flags &= ~ISCSI_TF_STOP;
        sess->time2retain_timer_flags |= ISCSI_TF_RUNNING;
-       add_timer(&sess->time2retain_timer);
+       mod_timer(&sess->time2retain_timer,
+                 jiffies + sess->sess_ops->DefaultTime2Retain * HZ);
 }
 
 /*
index 3393407bc4e43dddb522bd87e9eba86ef2cced99..883ebf6d36cf07695119841301e7b3306cd8c498 100644 (file)
@@ -12,6 +12,7 @@ extern void iscsit_set_dataout_sequence_values(struct iscsi_cmd *);
 extern int iscsit_check_pre_dataout(struct iscsi_cmd *, unsigned char *);
 extern int iscsit_check_post_dataout(struct iscsi_cmd *, unsigned char *, u8);
 extern void iscsit_start_time2retain_handler(struct iscsi_session *);
+extern void iscsit_handle_time2retain_timeout(struct timer_list *t);
 extern int iscsit_stop_time2retain_timer(struct iscsi_session *);
 extern void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *);
 extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int);
index fe9b7f1e44aca5c8bcda8677310351f03e507095..76184094a0cf944efc26c0aa32626b71e56b07b8 100644 (file)
@@ -1148,11 +1148,11 @@ static int iscsit_set_dataout_timeout_values(
 /*
  *     NOTE: Called from interrupt (timer) context.
  */
-static void iscsit_handle_dataout_timeout(unsigned long data)
+void iscsit_handle_dataout_timeout(struct timer_list *t)
 {
        u32 pdu_length = 0, pdu_offset = 0;
        u32 r2t_length = 0, r2t_offset = 0;
-       struct iscsi_cmd *cmd = (struct iscsi_cmd *) data;
+       struct iscsi_cmd *cmd = from_timer(cmd, t, dataout_timer);
        struct iscsi_conn *conn = cmd->conn;
        struct iscsi_session *sess = NULL;
        struct iscsi_node_attrib *na;
@@ -1264,13 +1264,9 @@ void iscsit_start_dataout_timer(
        pr_debug("Starting DataOUT timer for ITT: 0x%08x on"
                " CID: %hu.\n", cmd->init_task_tag, conn->cid);
 
-       init_timer(&cmd->dataout_timer);
-       cmd->dataout_timer.expires = (get_jiffies_64() + na->dataout_timeout * HZ);
-       cmd->dataout_timer.data = (unsigned long)cmd;
-       cmd->dataout_timer.function = iscsit_handle_dataout_timeout;
        cmd->dataout_timer_flags &= ~ISCSI_TF_STOP;
        cmd->dataout_timer_flags |= ISCSI_TF_RUNNING;
-       add_timer(&cmd->dataout_timer);
+       mod_timer(&cmd->dataout_timer, jiffies + na->dataout_timeout * HZ);
 }
 
 void iscsit_stop_dataout_timer(struct iscsi_cmd *cmd)
index 5f66b265b25bf2d8b2baa44c0f05c9c5e791ff1a..1f6973f87fea06f4b7df9bda74ca1b1c57fe015e 100644 (file)
@@ -30,6 +30,7 @@ extern int iscsit_execute_ooo_cmdsns(struct iscsi_session *);
 extern int iscsit_execute_cmd(struct iscsi_cmd *, int);
 extern int iscsit_handle_ooo_cmdsn(struct iscsi_session *, struct iscsi_cmd *, u32);
 extern void iscsit_remove_ooo_cmdsn(struct iscsi_session *, struct iscsi_ooo_cmdsn *);
+extern void iscsit_handle_dataout_timeout(struct timer_list *t);
 extern void iscsit_mod_dataout_timer(struct iscsi_cmd *);
 extern void iscsit_start_dataout_timer(struct iscsi_cmd *, struct iscsi_conn *);
 extern void iscsit_stop_dataout_timer(struct iscsi_cmd *);
index dc13afbd4c88dec2390ca8e65b3332d2f78acd73..64c5a57b92e4923a1b8298cdc71637bd03314276 100644 (file)
@@ -333,6 +333,9 @@ static int iscsi_login_zero_tsih_s1(
        spin_lock_init(&sess->session_usage_lock);
        spin_lock_init(&sess->ttt_lock);
 
+       timer_setup(&sess->time2retain_timer,
+                   iscsit_handle_time2retain_timeout, 0);
+
        idr_preload(GFP_KERNEL);
        spin_lock_bh(&sess_idr_lock);
        ret = idr_alloc(&sess_idr, NULL, 0, 0, GFP_NOWAIT);
@@ -839,9 +842,9 @@ void iscsi_post_login_handler(
        iscsit_dec_conn_usage_count(conn);
 }
 
-static void iscsi_handle_login_thread_timeout(unsigned long data)
+void iscsi_handle_login_thread_timeout(struct timer_list *t)
 {
-       struct iscsi_np *np = (struct iscsi_np *) data;
+       struct iscsi_np *np = from_timer(np, t, np_login_timer);
 
        spin_lock_bh(&np->np_thread_lock);
        pr_err("iSCSI Login timeout on Network Portal %pISpc\n",
@@ -866,13 +869,9 @@ static void iscsi_start_login_thread_timer(struct iscsi_np *np)
         * point we do not have access to ISCSI_TPG_ATTRIB(tpg)->login_timeout
         */
        spin_lock_bh(&np->np_thread_lock);
-       init_timer(&np->np_login_timer);
-       np->np_login_timer.expires = (get_jiffies_64() + TA_LOGIN_TIMEOUT * HZ);
-       np->np_login_timer.data = (unsigned long)np;
-       np->np_login_timer.function = iscsi_handle_login_thread_timeout;
        np->np_login_timer_flags &= ~ISCSI_TF_STOP;
        np->np_login_timer_flags |= ISCSI_TF_RUNNING;
-       add_timer(&np->np_login_timer);
+       mod_timer(&np->np_login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ);
 
        pr_debug("Added timeout timer to iSCSI login request for"
                        " %u seconds.\n", TA_LOGIN_TIMEOUT);
@@ -1266,6 +1265,10 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
        conn->conn_state = TARG_CONN_STATE_FREE;
 
+       timer_setup(&conn->nopin_response_timer,
+                   iscsit_handle_nopin_response_timeout, 0);
+       timer_setup(&conn->nopin_timer, iscsit_handle_nopin_timeout, 0);
+
        if (iscsit_conn_set_transport(conn, np->np_transport) < 0) {
                kfree(conn);
                return 1;
index c2495e03625c5b6ecd68fc0caea25eb42b3eb3e4..74ac3abc44a02564ba1231e96c1338b1ecd87bd7 100644 (file)
@@ -25,5 +25,6 @@ extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8)
 extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
                                bool, bool);
 extern int iscsi_target_login_thread(void *);
+extern void iscsi_handle_login_thread_timeout(struct timer_list *t);
 
 #endif   /*** ISCSI_TARGET_LOGIN_H ***/
index 7a6751fecd323cf948a77e4508430487b3cc4717..b686e2ce9c0e5df3e6142f5cf4ab144ef6d5ef85 100644 (file)
@@ -559,9 +559,15 @@ static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login
        iscsi_target_login_sess_out(conn, np, zero_tsih, true);
 }
 
-static void iscsi_target_login_timeout(unsigned long data)
+struct conn_timeout {
+       struct timer_list timer;
+       struct iscsi_conn *conn;
+};
+
+static void iscsi_target_login_timeout(struct timer_list *t)
 {
-       struct iscsi_conn *conn = (struct iscsi_conn *)data;
+       struct conn_timeout *timeout = from_timer(timeout, t, timer);
+       struct iscsi_conn *conn = timeout->conn;
 
        pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n");
 
@@ -580,7 +586,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
        struct iscsi_np *np = login->np;
        struct iscsi_portal_group *tpg = conn->tpg;
        struct iscsi_tpg_np *tpg_np = conn->tpg_np;
-       struct timer_list login_timer;
+       struct conn_timeout timeout;
        int rc, zero_tsih = login->zero_tsih;
        bool state;
 
@@ -618,15 +624,14 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
        conn->login_kworker = current;
        allow_signal(SIGINT);
 
-       init_timer(&login_timer);
-       login_timer.expires = (get_jiffies_64() + TA_LOGIN_TIMEOUT * HZ);
-       login_timer.data = (unsigned long)conn;
-       login_timer.function = iscsi_target_login_timeout;
-       add_timer(&login_timer);
-       pr_debug("Starting login_timer for %s/%d\n", current->comm, current->pid);
+       timeout.conn = conn;
+       timer_setup_on_stack(&timeout.timer, iscsi_target_login_timeout, 0);
+       mod_timer(&timeout.timer, jiffies + TA_LOGIN_TIMEOUT * HZ);
+       pr_debug("Starting login timer for %s/%d\n", current->comm, current->pid);
 
        rc = conn->conn_transport->iscsit_get_login_rx(conn, login);
-       del_timer_sync(&login_timer);
+       del_timer_sync(&timeout.timer);
+       destroy_timer_on_stack(&timeout.timer);
        flush_signals(current);
        conn->login_kworker = NULL;
 
index 1e36f83b596164ec8932d5fb3f703229f052bedf..54f20f184dd6b5c8422f8e72f81e173c70d5efd0 100644 (file)
@@ -176,6 +176,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
        spin_lock_init(&cmd->istate_lock);
        spin_lock_init(&cmd->error_lock);
        spin_lock_init(&cmd->r2t_lock);
+       timer_setup(&cmd->dataout_timer, iscsit_handle_dataout_timeout, 0);
 
        return cmd;
 }
@@ -880,9 +881,9 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
        return 0;
 }
 
-static void iscsit_handle_nopin_response_timeout(unsigned long data)
+void iscsit_handle_nopin_response_timeout(struct timer_list *t)
 {
-       struct iscsi_conn *conn = (struct iscsi_conn *) data;
+       struct iscsi_conn *conn = from_timer(conn, t, nopin_response_timer);
 
        iscsit_inc_conn_usage_count(conn);
 
@@ -949,14 +950,10 @@ void iscsit_start_nopin_response_timer(struct iscsi_conn *conn)
                return;
        }
 
-       init_timer(&conn->nopin_response_timer);
-       conn->nopin_response_timer.expires =
-               (get_jiffies_64() + na->nopin_response_timeout * HZ);
-       conn->nopin_response_timer.data = (unsigned long)conn;
-       conn->nopin_response_timer.function = iscsit_handle_nopin_response_timeout;
        conn->nopin_response_timer_flags &= ~ISCSI_TF_STOP;
        conn->nopin_response_timer_flags |= ISCSI_TF_RUNNING;
-       add_timer(&conn->nopin_response_timer);
+       mod_timer(&conn->nopin_response_timer,
+                 jiffies + na->nopin_response_timeout * HZ);
 
        pr_debug("Started NOPIN Response Timer on CID: %d to %u"
                " seconds\n", conn->cid, na->nopin_response_timeout);
@@ -980,9 +977,9 @@ void iscsit_stop_nopin_response_timer(struct iscsi_conn *conn)
        spin_unlock_bh(&conn->nopin_timer_lock);
 }
 
-static void iscsit_handle_nopin_timeout(unsigned long data)
+void iscsit_handle_nopin_timeout(struct timer_list *t)
 {
-       struct iscsi_conn *conn = (struct iscsi_conn *) data;
+       struct iscsi_conn *conn = from_timer(conn, t, nopin_timer);
 
        iscsit_inc_conn_usage_count(conn);
 
@@ -1015,13 +1012,9 @@ void __iscsit_start_nopin_timer(struct iscsi_conn *conn)
        if (conn->nopin_timer_flags & ISCSI_TF_RUNNING)
                return;
 
-       init_timer(&conn->nopin_timer);
-       conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ);
-       conn->nopin_timer.data = (unsigned long)conn;
-       conn->nopin_timer.function = iscsit_handle_nopin_timeout;
        conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
        conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
-       add_timer(&conn->nopin_timer);
+       mod_timer(&conn->nopin_timer, jiffies + na->nopin_timeout * HZ);
 
        pr_debug("Started NOPIN Timer on CID: %d at %u second"
                " interval\n", conn->cid, na->nopin_timeout);
@@ -1043,13 +1036,9 @@ void iscsit_start_nopin_timer(struct iscsi_conn *conn)
                return;
        }
 
-       init_timer(&conn->nopin_timer);
-       conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ);
-       conn->nopin_timer.data = (unsigned long)conn;
-       conn->nopin_timer.function = iscsit_handle_nopin_timeout;
        conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
        conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
-       add_timer(&conn->nopin_timer);
+       mod_timer(&conn->nopin_timer, jiffies + na->nopin_timeout * HZ);
 
        pr_debug("Started NOPIN Timer on CID: %d at %u second"
                        " interval\n", conn->cid, na->nopin_timeout);
index 5e053d61c0c52f1ccd04358ca44d6f54edb649bc..d66dfc2126247c814ee554c8632f2fa7f126bfd3 100644 (file)
@@ -48,9 +48,11 @@ extern struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *,
 extern void iscsit_check_conn_usage_count(struct iscsi_conn *);
 extern void iscsit_dec_conn_usage_count(struct iscsi_conn *);
 extern void iscsit_inc_conn_usage_count(struct iscsi_conn *);
+extern void iscsit_handle_nopin_response_timeout(struct timer_list *t);
 extern void iscsit_mod_nopin_response_timer(struct iscsi_conn *);
 extern void iscsit_start_nopin_response_timer(struct iscsi_conn *);
 extern void iscsit_stop_nopin_response_timer(struct iscsi_conn *);
+extern void iscsit_handle_nopin_timeout(struct timer_list *t);
 extern void __iscsit_start_nopin_timer(struct iscsi_conn *);
 extern void iscsit_start_nopin_timer(struct iscsi_conn *);
 extern void iscsit_stop_nopin_timer(struct iscsi_conn *);
index 942d094269fba5db66ff7e791dcfaab1c6acec15..9469695f5871aea064bea2e4b4f65e32742c3cb4 100644 (file)
@@ -985,7 +985,7 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
        mb = udev->mb_addr;
        tcmu_flush_dcache_range(mb, sizeof(*mb));
 
-       while (udev->cmdr_last_cleaned != ACCESS_ONCE(mb->cmd_tail)) {
+       while (udev->cmdr_last_cleaned != READ_ONCE(mb->cmd_tail)) {
 
                struct tcmu_cmd_entry *entry = (void *) mb + CMDR_OFF + udev->cmdr_last_cleaned;
                struct tcmu_cmd *cmd;
index d272bc4e7fb5699aafabea9483cf6252d7d4fd40..dac8a1a8e4acdffd9fde5d68fd55dbe06506d82a 100644 (file)
@@ -283,7 +283,7 @@ static void cyz_poll(unsigned long);
 /* The Cyclades-Z polling cycle is defined by this variable */
 static long cyz_polling_cycle = CZ_DEF_POLL;
 
-static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
+static DEFINE_TIMER(cyz_timerlist, cyz_poll);
 
 #else                          /* CONFIG_CYZ_INTR */
 static void cyz_rx_restart(unsigned long);
index 61ecdd6b2fc24479bdbfcd3a24f810604908d29b..40af32108ff5e7d753a3eef3a3115bb3c6ea6dd7 100644 (file)
@@ -177,7 +177,7 @@ static struct tty_driver *isicom_normal;
 static void isicom_tx(unsigned long _data);
 static void isicom_start(struct tty_struct *tty);
 
-static DEFINE_TIMER(tx, isicom_tx, 0, 0);
+static DEFINE_TIMER(tx, isicom_tx);
 
 /*   baud index mappings from linux defns to isi */
 
index 7f3d4cb0341be03fdb3e67f06097a495cd2971b5..93d37655d928ec94ed3dd8e9ec7e92de32692aff 100644 (file)
@@ -428,7 +428,7 @@ static const struct tty_port_operations moxa_port_ops = {
 };
 
 static struct tty_driver *moxaDriver;
-static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
+static DEFINE_TIMER(moxaTimer, moxa_poll);
 
 /*
  * HW init
index 20d79a6007d50bcb9457890df30c1d341899485d..aa695fda1084e557bec716cbcd9c4c4947911025 100644 (file)
@@ -111,7 +111,7 @@ static struct r_port *rp_table[MAX_RP_PORTS];              /*  The main repository of
 static unsigned int xmit_flags[NUM_BOARDS];           /*  Bit significant, indicates port had data to transmit. */
                                                       /*  eg.  Bit 0 indicates port 0 has xmit data, ...        */
 static atomic_t rp_num_ports_open;                    /*  Number of serial ports open                           */
-static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0);
+static DEFINE_TIMER(rocket_timer, rp_do_poll);
 
 static unsigned long board1;                          /* ISA addresses, retrieved from rocketport.conf          */
 static unsigned long board2;
index f4166263bb3aaf383b0b64c28b929e749e6607da..f974d6340d0449bce837d9b6e90677fcb064f22d 100644 (file)
@@ -250,7 +250,7 @@ static void kd_nosound(unsigned long ignored)
        input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
 }
 
-static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
+static DEFINE_TIMER(kd_mksound_timer, kd_nosound);
 
 void kd_mksound(unsigned int hz, unsigned int ticks)
 {
index 2ebaba16f7858ec2ac0b0395af2c16d5d98a8273..602d716309521ca744b90e91e0a45c820581c88f 100644 (file)
@@ -228,7 +228,7 @@ static int scrollback_delta;
  */
 int (*console_blank_hook)(int);
 
-static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
+static DEFINE_TIMER(console_timer, blank_screen_t);
 static int blank_state;
 static int blank_timer_expired;
 enum {
index 3e865dbf878c74b2e904925798cd603e5cd0e979..fbaa2a90d25dc2ee4847baa582879940925f188e 100644 (file)
@@ -483,7 +483,7 @@ static ssize_t wdm_read
        if (rv < 0)
                return -ERESTARTSYS;
 
-       cntr = ACCESS_ONCE(desc->length);
+       cntr = READ_ONCE(desc->length);
        if (cntr == 0) {
                desc->read = 0;
 retry:
index e9326f31db8d4367cb80e813954573c983a49a08..4ae667d8c238549d85372aacbdda8d9e188176c2 100644 (file)
@@ -150,7 +150,7 @@ static int usbfs_increase_memory_usage(u64 amount)
 {
        u64 lim;
 
-       lim = ACCESS_ONCE(usbfs_memory_mb);
+       lim = READ_ONCE(usbfs_memory_mb);
        lim <<= 20;
 
        atomic64_add(amount, &usbfs_memory_usage);
index d930bfda40101457dad980ec432c0b73d7193981..58d59c5f859258ba73349d6695e0c0d069b0d66c 100644 (file)
@@ -973,7 +973,7 @@ static ssize_t interface_show(struct device *dev, struct device_attribute *attr,
        char *string;
 
        intf = to_usb_interface(dev);
-       string = ACCESS_ONCE(intf->cur_altsetting->string);
+       string = READ_ONCE(intf->cur_altsetting->string);
        if (!string)
                return 0;
        return sprintf(buf, "%s\n", string);
@@ -989,7 +989,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
 
        intf = to_usb_interface(dev);
        udev = interface_to_usbdev(intf);
-       alt = ACCESS_ONCE(intf->cur_altsetting);
+       alt = READ_ONCE(intf->cur_altsetting);
 
        return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
                        "ic%02Xisc%02Xip%02Xin%02X\n",
index 1f9941145746ee4d8b8130d4721e2fb2720fae54..0b59fa50aa301f84cd8ab9b56eb57f52832ad84d 100644 (file)
@@ -1261,7 +1261,7 @@ static int gr_handle_in_ep(struct gr_ep *ep)
        if (!req->last_desc)
                return 0;
 
-       if (ACCESS_ONCE(req->last_desc->ctrl) & GR_DESC_IN_CTRL_EN)
+       if (READ_ONCE(req->last_desc->ctrl) & GR_DESC_IN_CTRL_EN)
                return 0; /* Not put in hardware buffers yet */
 
        if (gr_read32(&ep->regs->epstat) & (GR_EPSTAT_B1 | GR_EPSTAT_B0))
@@ -1290,7 +1290,7 @@ static int gr_handle_out_ep(struct gr_ep *ep)
        if (!req->curr_desc)
                return 0;
 
-       ctrl = ACCESS_ONCE(req->curr_desc->ctrl);
+       ctrl = READ_ONCE(req->curr_desc->ctrl);
        if (ctrl & GR_DESC_OUT_CTRL_EN)
                return 0; /* Not received yet */
 
index 44924824fa414a28dfbf10a715b658e6b493a462..c86f89babd579391197b4518131c198b028e4682 100644 (file)
@@ -785,7 +785,7 @@ static void io_watchdog_func(unsigned long _ohci)
                }
 
                /* find the last TD processed by the controller. */
-               head = hc32_to_cpu(ohci, ACCESS_ONCE(ed->hwHeadP)) & TD_MASK;
+               head = hc32_to_cpu(ohci, READ_ONCE(ed->hwHeadP)) & TD_MASK;
                td_start = td;
                td_next = list_prepare_entry(td, &ed->td_list, td_list);
                list_for_each_entry_continue(td_next, &ed->td_list, td_list) {
index d97f0d9b3ce6ce0ec29ad1d79531082c0e392d9f..f1cc47292a59e9a3887ec7338dbdabf327773d1b 100644 (file)
@@ -187,7 +187,7 @@ struct uhci_qh {
  * We need a special accessor for the element pointer because it is
  * subject to asynchronous updates by the controller.
  */
-#define qh_element(qh)         ACCESS_ONCE((qh)->element)
+#define qh_element(qh)         READ_ONCE((qh)->element)
 
 #define LINK_TO_QH(uhci, qh)   (UHCI_PTR_QH((uhci)) | \
                                cpu_to_hc32((uhci), (qh)->dma_handle))
@@ -275,7 +275,7 @@ struct uhci_td {
  * subject to asynchronous updates by the controller.
  */
 #define td_status(uhci, td)            hc32_to_cpu((uhci), \
-                                               ACCESS_ONCE((td)->status))
+                                               READ_ONCE((td)->status))
 
 #define LINK_TO_TD(uhci, td)           (cpu_to_hc32((uhci), (td)->dma_handle))
 
index b3fc602b2e247ea150a49c13323ae66cde2b6b4b..5ad74750e8a4b858d77b98c9962f91dcccca78f8 100644 (file)
@@ -576,11 +576,16 @@ alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe)
        return sg;
 }
 
-static void sg_timeout(unsigned long _req)
+struct sg_timeout {
+       struct timer_list timer;
+       struct usb_sg_request *req;
+};
+
+static void sg_timeout(struct timer_list *t)
 {
-       struct usb_sg_request   *req = (struct usb_sg_request *) _req;
+       struct sg_timeout *timeout = from_timer(timeout, t, timer);
 
-       usb_sg_cancel(req);
+       usb_sg_cancel(timeout->req);
 }
 
 static int perform_sglist(
@@ -594,9 +599,11 @@ static int perform_sglist(
 {
        struct usb_device       *udev = testdev_to_usbdev(tdev);
        int                     retval = 0;
-       struct timer_list       sg_timer;
+       struct sg_timeout       timeout = {
+               .req = req,
+       };
 
-       setup_timer_on_stack(&sg_timer, sg_timeout, (unsigned long) req);
+       timer_setup_on_stack(&timeout.timer, sg_timeout, 0);
 
        while (retval == 0 && iterations-- > 0) {
                retval = usb_sg_init(req, udev, pipe,
@@ -607,13 +614,14 @@ static int perform_sglist(
 
                if (retval)
                        break;
-               mod_timer(&sg_timer, jiffies +
+               mod_timer(&timeout.timer, jiffies +
                                msecs_to_jiffies(SIMPLE_IO_TIMEOUT));
                usb_sg_wait(req);
-               if (!del_timer_sync(&sg_timer))
+               if (!del_timer_sync(&timeout.timer))
                        retval = -ETIMEDOUT;
                else
                        retval = req->status;
+               destroy_timer_on_stack(&timeout.timer);
 
                /* FIXME check resulting data pattern */
 
index f5a86f651f38e12874069281735169a1be26bede..2bc3705a99bd2f1a670e96c9f1175795b961c922 100644 (file)
@@ -665,7 +665,7 @@ static int vfio_dev_viable(struct device *dev, void *data)
 {
        struct vfio_group *group = data;
        struct vfio_device *device;
-       struct device_driver *drv = ACCESS_ONCE(dev->driver);
+       struct device_driver *drv = READ_ONCE(dev->driver);
        struct vfio_unbound_dev *unbound;
        int ret = -EINVAL;
 
index 046f6d280af5771f68e3aff5c58af4dfa00ea7a1..35e929f132e8f80453322b864288fc42d7406457 100644 (file)
@@ -929,7 +929,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                        continue;
                }
 
-               tpg = ACCESS_ONCE(vs_tpg[*target]);
+               tpg = READ_ONCE(vs_tpg[*target]);
                if (unlikely(!tpg)) {
                        /* Target does not exist, fail the request */
                        vhost_scsi_send_bad_target(vs, vq, head, out);
index 665e0e7dfe1e2e2e03eb371bc377f58b6f9f5236..18e896eeca62352f3c5e2c73479aab506c064958 100644 (file)
@@ -71,7 +71,7 @@ MODULE_PARM_DESC(use_gpio,
                "Use the gpio watchdog (required by old cobalt boards).");
 
 static void wdt_timer_ping(unsigned long);
-static DEFINE_TIMER(timer, wdt_timer_ping, 0, 1);
+static DEFINE_TIMER(timer, wdt_timer_ping);
 static unsigned long next_heartbeat;
 static unsigned long wdt_is_open;
 static char wdt_expect_close;
@@ -87,7 +87,7 @@ MODULE_PARM_DESC(nowayout,
  *     Whack the dog
  */
 
-static void wdt_timer_ping(unsigned long data)
+static void wdt_timer_ping(unsigned long unused)
 {
        /* If we got a heartbeat pulse within the WDT_US_INTERVAL
         * we agree to ping the WDT
index 3d43775548e59cda1966146897daa4b6d396b471..aee0b25cf10d9afd48604b943fa17d97a6fe6927 100644 (file)
@@ -230,9 +230,9 @@ static void cpwd_resetbrokentimer(struct cpwd *p, int index)
  * interrupts within the PLD so me must continually
  * reset the timers ad infinitum.
  */
-static void cpwd_brokentimer(unsigned long data)
+static void cpwd_brokentimer(struct timer_list *unused)
 {
-       struct cpwd *p = (struct cpwd *) data;
+       struct cpwd *p = cpwd_device;
        int id, tripped = 0;
 
        /* kill a running timer instance, in case we
@@ -275,7 +275,7 @@ static void cpwd_stoptimer(struct cpwd *p, int index)
 
                if (p->broken) {
                        p->devs[index].runstatus |= WD_STAT_BSTOP;
-                       cpwd_brokentimer((unsigned long) p);
+                       cpwd_brokentimer(NULL);
                }
        }
 }
@@ -608,7 +608,7 @@ static int cpwd_probe(struct platform_device *op)
        }
 
        if (p->broken) {
-               setup_timer(&cpwd_timer, cpwd_brokentimer, (unsigned long)p);
+               timer_setup(&cpwd_timer, cpwd_brokentimer, 0);
                cpwd_timer.expires      = WD_BTIMEOUT;
 
                pr_info("PLD defect workaround enabled for model %s\n",
index 3b8bb59adf027bddf5fde1013c3621f4b480e9a3..b4221f43cd947f625d8124062cb05ccbed875ef8 100644 (file)
@@ -78,10 +78,10 @@ static int lpc18xx_wdt_feed(struct watchdog_device *wdt_dev)
        return 0;
 }
 
-static void lpc18xx_wdt_timer_feed(unsigned long data)
+static void lpc18xx_wdt_timer_feed(struct timer_list *t)
 {
-       struct watchdog_device *wdt_dev = (struct watchdog_device *)data;
-       struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev);
+       struct lpc18xx_wdt_dev *lpc18xx_wdt = from_timer(lpc18xx_wdt, t, timer);
+       struct watchdog_device *wdt_dev = &lpc18xx_wdt->wdt_dev;
 
        lpc18xx_wdt_feed(wdt_dev);
 
@@ -96,7 +96,9 @@ static void lpc18xx_wdt_timer_feed(unsigned long data)
  */
 static int lpc18xx_wdt_stop(struct watchdog_device *wdt_dev)
 {
-       lpc18xx_wdt_timer_feed((unsigned long)wdt_dev);
+       struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev);
+
+       lpc18xx_wdt_timer_feed(&lpc18xx_wdt->timer);
 
        return 0;
 }
@@ -267,8 +269,7 @@ static int lpc18xx_wdt_probe(struct platform_device *pdev)
 
        __lpc18xx_wdt_set_timeout(lpc18xx_wdt);
 
-       setup_timer(&lpc18xx_wdt->timer, lpc18xx_wdt_timer_feed,
-                   (unsigned long)&lpc18xx_wdt->wdt_dev);
+       timer_setup(&lpc18xx_wdt->timer, lpc18xx_wdt_timer_feed, 0);
 
        watchdog_set_nowayout(&lpc18xx_wdt->wdt_dev, nowayout);
        watchdog_set_restart_priority(&lpc18xx_wdt->wdt_dev, 128);
index 9826b59ef73471c1e450e564176c2e49c4fcb283..8a616a57bb90441cc946c2d4d25c71dd5ae8f544 100644 (file)
@@ -127,7 +127,7 @@ static int zf_action = GEN_RESET;
 static unsigned long zf_is_open;
 static char zf_expect_close;
 static DEFINE_SPINLOCK(zf_port_lock);
-static DEFINE_TIMER(zf_timer, zf_ping, 0, 0);
+static DEFINE_TIMER(zf_timer, zf_ping);
 static unsigned long next_heartbeat;
 
 
index be86ea359eee1c1ffefd1cbae6f6e12f0059f273..c9e38096ea91fff0bcfed82f8d8058ff0bb7be17 100644 (file)
@@ -105,7 +105,7 @@ static unsigned long mixcomwd_opened; /* long req'd for setbit --RR */
 
 static int watchdog_port;
 static int mixcomwd_timer_alive;
-static DEFINE_TIMER(mixcomwd_timer, mixcomwd_timerfun, 0, 0);
+static DEFINE_TIMER(mixcomwd_timer, mixcomwd_timerfun);
 static char expect_close;
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
index 2eef58a0cf059837c5055d386bede89e21247c7f..8d589939bc8447b7cb116ba8b3ff70bdb8f207b6 100644 (file)
@@ -113,7 +113,7 @@ MODULE_PARM_DESC(nowayout,
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
 static void wdt_timer_ping(unsigned long);
-static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
+static DEFINE_TIMER(timer, wdt_timer_ping);
 static unsigned long next_heartbeat;
 static unsigned long wdt_is_open;
 static char wdt_expect_close;
index 1cfd3f6a13d5f428adebe5a7b3e030b155f06a44..3e9bbaa37bf46ac872b51da65fc4ed31ee1b9f2e 100644 (file)
@@ -124,7 +124,7 @@ MODULE_PARM_DESC(nowayout,
 static __u16 __iomem *wdtmrctl;
 
 static void wdt_timer_ping(unsigned long);
-static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
+static DEFINE_TIMER(timer, wdt_timer_ping);
 static unsigned long next_heartbeat;
 static unsigned long wdt_is_open;
 static char wdt_expect_close;
index 5f9cbc37520d2e4fd029ba02e594e9ac024c7e6f..ad3c3be13b40981d5a4ddecbccfbbfb262071e71 100644 (file)
@@ -68,7 +68,7 @@ static struct resource wdt_res;
 static void __iomem *wdt_mem;
 static unsigned int mmio;
 static void wdt_timer_tick(unsigned long data);
-static DEFINE_TIMER(timer, wdt_timer_tick, 0, 0);
+static DEFINE_TIMER(timer, wdt_timer_tick);
                                        /* The timer that pings the watchdog */
 static unsigned long next_heartbeat;   /* the next_heartbeat for the timer */
 
index f0483c75ed324b63cf3d63f33a2367325b1c7869..ba6b680af1000ebe795c0522691675494b28795a 100644 (file)
@@ -98,7 +98,7 @@ MODULE_PARM_DESC(nowayout,
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
 static void wdt_timer_ping(unsigned long);
-static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
+static DEFINE_TIMER(timer, wdt_timer_ping);
 static unsigned long next_heartbeat;
 static unsigned long wdt_is_open;
 static char wdt_expect_close;
index 2c6a9114d332c74a85e2d679b9c2672a7447e188..a8721d71818635a771eeb25d438c6da51943ee3b 100644 (file)
@@ -305,7 +305,7 @@ struct deferred_entry {
 };
 static LIST_HEAD(deferred_list);
 static void gnttab_handle_deferred(unsigned long);
-static DEFINE_TIMER(deferred_timer, gnttab_handle_deferred, 0, 0);
+static DEFINE_TIMER(deferred_timer, gnttab_handle_deferred);
 
 static void gnttab_handle_deferred(unsigned long unused)
 {
index 5a2487217072d18b1b5a25b6961e6cdd938375fc..e6de7715228c92995906c4afa9712d9137161a81 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -576,7 +576,7 @@ static int kiocb_cancel(struct aio_kiocb *kiocb)
         * actually has a cancel function, hence the cmpxchg()
         */
 
-       cancel = ACCESS_ONCE(kiocb->ki_cancel);
+       cancel = READ_ONCE(kiocb->ki_cancel);
        do {
                if (!cancel || cancel == KIOCB_CANCELLED)
                        return -EINVAL;
index 170df856bdb99715b126b2d129ff19ea95d46ad8..32ce01f0f95f3edfd65ee64cd1a90c421553e56f 100644 (file)
@@ -1692,7 +1692,8 @@ static struct buffer_head *create_page_buffers(struct page *page, struct inode *
        BUG_ON(!PageLocked(page));
 
        if (!page_has_buffers(page))
-               create_empty_buffers(page, 1 << ACCESS_ONCE(inode->i_blkbits), b_state);
+               create_empty_buffers(page, 1 << READ_ONCE(inode->i_blkbits),
+                                    b_state);
        return page_buffers(page);
 }
 
index a38630214058214dec6c30eca64f74f3f7f693df..577dfaf0367f66e137442b3932210d806d832da3 100644 (file)
@@ -374,7 +374,7 @@ void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
        struct fscrypt_info *prev;
 
        if (ci == NULL)
-               ci = ACCESS_ONCE(inode->i_crypt_info);
+               ci = READ_ONCE(inode->i_crypt_info);
        if (ci == NULL)
                return;
 
index f90141387f01ea4ed61bae215e137042527182c5..bcc9f6981569c4bb7e3dc1a5515a558aec23f0b8 100644 (file)
@@ -231,7 +231,7 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c
 {
        /*
         * Be careful about RCU walk racing with rename:
-        * use 'lockless_dereference' to fetch the name pointer.
+        * use 'READ_ONCE' to fetch the name pointer.
         *
         * NOTE! Even if a rename will mean that the length
         * was not loaded atomically, we don't care. The
@@ -245,7 +245,7 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c
         * early because the data cannot match (there can
         * be no NUL in the ct/tcount data)
         */
-       const unsigned char *cs = lockless_dereference(dentry->d_name.name);
+       const unsigned char *cs = READ_ONCE(dentry->d_name.name);
 
        return dentry_string_cmp(cs, ct, tcount);
 }
@@ -630,7 +630,7 @@ static inline struct dentry *lock_parent(struct dentry *dentry)
        rcu_read_lock();
        spin_unlock(&dentry->d_lock);
 again:
-       parent = ACCESS_ONCE(dentry->d_parent);
+       parent = READ_ONCE(dentry->d_parent);
        spin_lock(&parent->d_lock);
        /*
         * We can't blindly lock dentry until we are sure
@@ -721,7 +721,7 @@ static inline bool fast_dput(struct dentry *dentry)
         * around with a zero refcount.
         */
        smp_rmb();
-       d_flags = ACCESS_ONCE(dentry->d_flags);
+       d_flags = READ_ONCE(dentry->d_flags);
        d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST | DCACHE_DISCONNECTED;
 
        /* Nothing to do? Dropping the reference was all we needed? */
@@ -850,11 +850,11 @@ struct dentry *dget_parent(struct dentry *dentry)
         * locking.
         */
        rcu_read_lock();
-       ret = ACCESS_ONCE(dentry->d_parent);
+       ret = READ_ONCE(dentry->d_parent);
        gotref = lockref_get_not_zero(&ret->d_lockref);
        rcu_read_unlock();
        if (likely(gotref)) {
-               if (likely(ret == ACCESS_ONCE(dentry->d_parent)))
+               if (likely(ret == READ_ONCE(dentry->d_parent)))
                        return ret;
                dput(ret);
        }
@@ -3040,7 +3040,7 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen)
  * @buflen: allocated length of the buffer
  * @name:   name string and length qstr structure
  *
- * With RCU path tracing, it may race with d_move(). Use ACCESS_ONCE() to
+ * With RCU path tracing, it may race with d_move(). Use READ_ONCE() to
  * make sure that either the old or the new name pointer and length are
  * fetched. However, there may be mismatch between length and pointer.
  * The length cannot be trusted, we need to copy it byte-by-byte until
@@ -3054,8 +3054,8 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen)
  */
 static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
 {
-       const char *dname = ACCESS_ONCE(name->name);
-       u32 dlen = ACCESS_ONCE(name->len);
+       const char *dname = READ_ONCE(name->name);
+       u32 dlen = READ_ONCE(name->len);
        char *p;
 
        smp_read_barrier_depends();
@@ -3120,7 +3120,7 @@ restart:
                struct dentry * parent;
 
                if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
-                       struct mount *parent = ACCESS_ONCE(mnt->mnt_parent);
+                       struct mount *parent = READ_ONCE(mnt->mnt_parent);
                        /* Escaped? */
                        if (dentry != vfsmnt->mnt_root) {
                                bptr = *buffer;
@@ -3130,7 +3130,7 @@ restart:
                        }
                        /* Global root? */
                        if (mnt != parent) {
-                               dentry = ACCESS_ONCE(mnt->mnt_mountpoint);
+                               dentry = READ_ONCE(mnt->mnt_mountpoint);
                                mnt = parent;
                                vfsmnt = &mnt->mnt;
                                continue;
index b53e66d9abd7030f6b05a6dac4847928c24bf1a0..98fe1325da9d07e52135eb728c3d0dd381d35649 100644 (file)
@@ -1152,7 +1152,7 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
                      get_block_t get_block, dio_iodone_t end_io,
                      dio_submit_t submit_io, int flags)
 {
-       unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits);
+       unsigned i_blkbits = READ_ONCE(inode->i_blkbits);
        unsigned blkbits = i_blkbits;
        unsigned blocksize_mask = (1 << blkbits) - 1;
        ssize_t retval = -EINVAL;
index 3e14ba25f678bf8869e005a34dc9742e117e90df..1d6243d9f2b653e679165099be9332776805b8bd 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1911,7 +1911,7 @@ void set_dumpable(struct mm_struct *mm, int value)
                return;
 
        do {
-               old = ACCESS_ONCE(mm->flags);
+               old = READ_ONCE(mm->flags);
                new = (old & ~MMF_DUMPABLE_MASK) | value;
        } while (cmpxchg(&mm->flags, old, new) != old);
 }
index 8d78ffd7b399d430f05fdb8b72b68dfa1bda3bcb..30f47d0f74a00985149ee8123f34531643232711 100644 (file)
@@ -725,7 +725,7 @@ static void send_sigio_to_task(struct task_struct *p,
         * F_SETSIG can change ->signum lockless in parallel, make
         * sure we read it once and use the same value throughout.
         */
-       int signum = ACCESS_ONCE(fown->signum);
+       int signum = READ_ONCE(fown->signum);
 
        if (!sigio_perm(p, fown, signum))
                return;
index 61517f57f8ef744e9915c33659cfba96c0a1f767..49e1f2f1a4cbefe0906224433d03ee5c36e7a9c1 100644 (file)
@@ -201,11 +201,11 @@ static void __fput(struct file *file)
        eventpoll_release(file);
        locks_remove_file(file);
 
+       ima_file_free(file);
        if (unlikely(file->f_flags & FASYNC)) {
                if (file->f_op->fasync)
                        file->f_op->fasync(-1, file, 0);
        }
-       ima_file_free(file);
        if (file->f_op->release)
                file->f_op->release(inode, file);
        security_file_free(file);
index 0d285fd5b44ab6d16d2377f3a19ef7fb6cc06384..a6497cf8ae53aa2bc7dcc2996887fcb92f1e9820 100644 (file)
@@ -79,7 +79,7 @@ void mnt_pin_kill(struct mount *m)
        while (1) {
                struct hlist_node *p;
                rcu_read_lock();
-               p = ACCESS_ONCE(m->mnt_pins.first);
+               p = READ_ONCE(m->mnt_pins.first);
                if (!p) {
                        rcu_read_unlock();
                        break;
@@ -93,7 +93,7 @@ void group_pin_kill(struct hlist_head *p)
        while (1) {
                struct hlist_node *q;
                rcu_read_lock();
-               q = ACCESS_ONCE(p->first);
+               q = READ_ONCE(p->first);
                if (!q) {
                        rcu_read_unlock();
                        break;
index 13c65dd2d37d1ab1af358f82b42c43ba8c2cc2de..a42d89371748e51140c26a57cc4fa7dd28e4196b 100644 (file)
@@ -33,7 +33,7 @@ static struct fuse_dev *fuse_get_dev(struct file *file)
         * Lockless access is OK, because file->private data is set
         * once during mount and is valid until the file is released.
         */
-       return ACCESS_ONCE(file->private_data);
+       return READ_ONCE(file->private_data);
 }
 
 static void fuse_request_init(struct fuse_req *req, struct page **pages,
index d1e35b53bb23b80db7077500f63eeec9bce6bb28..fd401028a309e2d260ace4aaba996b8838b13fb1 100644 (file)
@@ -2090,7 +2090,7 @@ void inode_set_flags(struct inode *inode, unsigned int flags,
 
        WARN_ON_ONCE(flags & ~mask);
        do {
-               old_flags = ACCESS_ONCE(inode->i_flags);
+               old_flags = READ_ONCE(inode->i_flags);
                new_flags = (old_flags & ~mask) | flags;
        } while (unlikely(cmpxchg(&inode->i_flags, old_flags,
                                  new_flags) != old_flags));
index ed8b9488a890c2b936e249ab16e6a44a292a9521..5424b10cfdc4657dfa7f487f06d98094e7e58158 100644 (file)
@@ -1210,7 +1210,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
        /* Given that we're not holding a lock here, we retain the value in a
         * local variable for each dentry as we look at it so that we don't see
         * the components of that value change under us */
-       while (managed = ACCESS_ONCE(path->dentry->d_flags),
+       while (managed = READ_ONCE(path->dentry->d_flags),
               managed &= DCACHE_MANAGED_DENTRY,
               unlikely(managed != 0)) {
                /* Allow the filesystem to manage the transit without i_mutex
@@ -1395,7 +1395,7 @@ int follow_down(struct path *path)
        unsigned managed;
        int ret;
 
-       while (managed = ACCESS_ONCE(path->dentry->d_flags),
+       while (managed = READ_ONCE(path->dentry->d_flags),
               unlikely(managed & DCACHE_MANAGED_DENTRY)) {
                /* Allow the filesystem to manage the transit without i_mutex
                 * being held.
index d18deb4c410b24ed276c9b60c869f4c06b6ec20f..e158ec6b527b2d72341e096f76e628b5e61ea4cf 100644 (file)
@@ -353,7 +353,7 @@ int __mnt_want_write(struct vfsmount *m)
         * incremented count after it has set MNT_WRITE_HOLD.
         */
        smp_mb();
-       while (ACCESS_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD)
+       while (READ_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD)
                cpu_relax();
        /*
         * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will
index b5ec1d980dc933bfe0434201d7350def1371b6d1..0c57c5c5d40a1ce21c6537162d21ed0ad9b9867a 100644 (file)
@@ -120,10 +120,6 @@ static inline int ncp_case_sensitive(const struct inode *i)
 /*
  * Note: leave the hash unchanged if the directory
  * is case-sensitive.
- *
- * Accessing the parent inode can be racy under RCU pathwalking.
- * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
- * the callers will handle races.
  */
 static int 
 ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
@@ -148,11 +144,6 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
        return 0;
 }
 
-/*
- * Accessing the parent inode can be racy under RCU pathwalking.
- * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
- * the callers will handle races.
- */
 static int
 ncp_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
index 6d0f14c8609971378ee75104380873a6da67a4be..129f1937fa2c11527633c98a8840c2aae011fa0e 100644 (file)
@@ -618,7 +618,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
        server->tx.creq         = NULL;
        server->rcv.creq        = NULL;
 
-       init_timer(&server->timeout_tm);
+       timer_setup(&server->timeout_tm, ncpdgram_timeout_call, 0);
 #undef NCP_PACKET_SIZE
 #define NCP_PACKET_SIZE 131072
        error = -ENOMEM;
@@ -650,8 +650,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
        } else {
                INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
                INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
-               server->timeout_tm.data = (unsigned long)server;
-               server->timeout_tm.function = ncpdgram_timeout_call;
        }
        release_sock(sock->sk);
 
index 89031d7e3ae1966625a8970a9890cfe26dfc481d..f06cde4adf7167a35c30b2c37fad0066b55910e3 100644 (file)
@@ -150,7 +150,7 @@ extern void ncp_tcp_rcv_proc(struct work_struct *work);
 extern void ncp_tcp_tx_proc(struct work_struct *work);
 extern void ncpdgram_rcv_proc(struct work_struct *work);
 extern void ncpdgram_timeout_proc(struct work_struct *work);
-extern void ncpdgram_timeout_call(unsigned long server);
+extern void ncpdgram_timeout_call(struct timer_list *t);
 extern void ncp_tcp_data_ready(struct sock* sk);
 extern void ncp_tcp_write_space(struct sock* sk);
 extern void ncp_tcp_error_report(struct sock* sk);
index 7dd7170d6cdf2904086792650ca258736cfd1db8..efb176b1751a551bd636c58b277370b51cbfa0ca 100644 (file)
@@ -117,10 +117,10 @@ void ncp_tcp_write_space(struct sock *sk)
                schedule_work(&server->tx.tq);
 }
 
-void ncpdgram_timeout_call(unsigned long v)
+void ncpdgram_timeout_call(struct timer_list *t)
 {
-       struct ncp_server *server = (void*)v;
-       
+       struct ncp_server *server = from_timer(server, t, timeout_tm);
+
        schedule_work(&server->timeout_tq);
 }
 
index 5ceaeb1f6fb69d8ce15e932ff278a70837a48a30..f439f1c450086fa7349790989cf1823683204e77 100644 (file)
@@ -1081,7 +1081,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
        int error;
 
        if (flags & LOOKUP_RCU) {
-               parent = ACCESS_ONCE(dentry->d_parent);
+               parent = READ_ONCE(dentry->d_parent);
                dir = d_inode_rcu(parent);
                if (!dir)
                        return -ECHILD;
@@ -1168,7 +1168,7 @@ out_set_verifier:
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
  out_valid:
        if (flags & LOOKUP_RCU) {
-               if (parent != ACCESS_ONCE(dentry->d_parent))
+               if (parent != READ_ONCE(dentry->d_parent))
                        return -ECHILD;
        } else
                dput(parent);
@@ -1582,7 +1582,7 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
                struct inode *dir;
 
                if (flags & LOOKUP_RCU) {
-                       parent = ACCESS_ONCE(dentry->d_parent);
+                       parent = READ_ONCE(dentry->d_parent);
                        dir = d_inode_rcu(parent);
                        if (!dir)
                                return -ECHILD;
@@ -1596,7 +1596,7 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
                        ret = -ECHILD;
                if (!(flags & LOOKUP_RCU))
                        dput(parent);
-               else if (parent != ACCESS_ONCE(dentry->d_parent))
+               else if (parent != READ_ONCE(dentry->d_parent))
                        return -ECHILD;
                goto out;
        }
index 25d9b5adcd429071537c5edf3185b58a6ab9cd60..36b49bd09264a5bd92df902a1de7d10771d4b770 100644 (file)
@@ -77,5 +77,5 @@ static inline struct ovl_inode *OVL_I(struct inode *inode)
 
 static inline struct dentry *ovl_upperdentry_dereference(struct ovl_inode *oi)
 {
-       return lockless_dereference(oi->__upperdentry);
+       return READ_ONCE(oi->__upperdentry);
 }
index 698b74dd750ee6a9fb2586d0f8d42853111e6bd1..c310e3ff7f3f7d55979d60ef776c0740243f39b6 100644 (file)
@@ -754,7 +754,7 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
        if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
                struct inode *inode = file_inode(file);
 
-               realfile = lockless_dereference(od->upperfile);
+               realfile = READ_ONCE(od->upperfile);
                if (!realfile) {
                        struct path upperpath;
 
index 9390032a11e13d559b0fbc9accbee25bdff38b30..6f6fc1672ad1af5f942165de0c3ac42c08f390cc 100644 (file)
@@ -138,7 +138,7 @@ static const char * const task_state_array[] = {
 static inline const char *get_task_state(struct task_struct *tsk)
 {
        BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) != ARRAY_SIZE(task_state_array));
-       return task_state_array[__get_task_state(tsk)];
+       return task_state_array[task_state_index(tsk)];
 }
 
 static inline int get_task_umask(struct task_struct *tsk)
@@ -454,7 +454,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                cutime = sig->cutime;
                cstime = sig->cstime;
                cgtime = sig->cgtime;
-               rsslim = ACCESS_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur);
+               rsslim = READ_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur);
 
                /* add up live thread stats at the group level */
                if (whole) {
index 7626ee11b06c67edac5d9c021516ff6ea3390b98..7b635d17321377e4868554a6ad338a1bd413b3cc 100644 (file)
@@ -28,7 +28,7 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
 
        poll_wait(file, &p->ns->poll, wait);
 
-       event = ACCESS_ONCE(ns->event);
+       event = READ_ONCE(ns->event);
        if (m->poll_event != event) {
                m->poll_event = event;
                res |= POLLERR | POLLPRI;
index 2b21d180157c16a823f2f21d41e31d820bf77232..086e491faf04b655e4fdf2903b105a984e788f04 100644 (file)
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
 static int pstore_new_entry;
 
 static void pstore_timefunc(unsigned long);
-static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0);
+static DEFINE_TIMER(pstore_timer, pstore_timefunc);
 
 static void pstore_dowork(struct work_struct *);
 static DECLARE_WORK(pstore_work, pstore_dowork);
@@ -482,10 +482,7 @@ void pstore_record_init(struct pstore_record *record,
        record->psi = psinfo;
 
        /* Report zeroed timestamp if called before timekeeping has resumed. */
-       if (__getnstimeofday(&record->time)) {
-               record->time.tv_sec = 0;
-               record->time.tv_nsec = 0;
-       }
+       record->time = ns_to_timespec(ktime_get_real_fast_ns());
 }
 
 /*
index d336db65a33eaa4124a741e89fbbbee6b849850f..1b83b0ad183b656b06597dc65ab7d42883cc116e 100644 (file)
@@ -37,13 +37,12 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
        if (res)
                goto out;
 
-       if (shared) {
-               inode_lock_shared(inode);
-       } else {
+       if (shared)
+               res = down_read_killable(&inode->i_rwsem);
+       else
                res = down_write_killable(&inode->i_rwsem);
-               if (res)
-                       goto out;
-       }
+       if (res)
+               goto out;
 
        res = -ENOENT;
        if (!IS_DEADDIR(inode)) {
index f3084cce0ea6be94ad047a1bf07cdcf1cb3cf0f4..39e2dc01ac12c31a2d4629ddabdda2984319dd49 100644 (file)
@@ -253,7 +253,7 @@ EXPORT_SYMBOL(add_to_pipe);
  */
 int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
 {
-       unsigned int buffers = ACCESS_ONCE(pipe->buffers);
+       unsigned int buffers = READ_ONCE(pipe->buffers);
 
        spd->nr_pages_max = buffers;
        if (buffers <= PIPE_DEF_BUFFERS)
index 1c713fd5b3e67966c3d998979d2c30eb8e14ba07..f46d133c094998c48eada7a4e2bd8f5a69239ffa 100644 (file)
@@ -381,7 +381,7 @@ int handle_userfault(struct vm_fault *vmf, unsigned long reason)
         * in __get_user_pages if userfaultfd_release waits on the
         * caller of handle_userfault to release the mmap_sem.
         */
-       if (unlikely(ACCESS_ONCE(ctx->released))) {
+       if (unlikely(READ_ONCE(ctx->released))) {
                /*
                 * Don't return VM_FAULT_SIGBUS in this case, so a non
                 * cooperative manager can close the uffd after the
@@ -477,7 +477,7 @@ int handle_userfault(struct vm_fault *vmf, unsigned long reason)
                                                       vmf->flags, reason);
        up_read(&mm->mmap_sem);
 
-       if (likely(must_wait && !ACCESS_ONCE(ctx->released) &&
+       if (likely(must_wait && !READ_ONCE(ctx->released) &&
                   (return_to_userland ? !signal_pending(current) :
                    !fatal_signal_pending(current)))) {
                wake_up_poll(&ctx->fd_wqh, POLLIN);
@@ -586,7 +586,7 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx,
                set_current_state(TASK_KILLABLE);
                if (ewq->msg.event == 0)
                        break;
-               if (ACCESS_ONCE(ctx->released) ||
+               if (READ_ONCE(ctx->released) ||
                    fatal_signal_pending(current)) {
                        /*
                         * &ewq->wq may be queued in fork_event, but
@@ -833,7 +833,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
        struct userfaultfd_wake_range range = { .len = 0, };
        unsigned long new_flags;
 
-       ACCESS_ONCE(ctx->released) = true;
+       WRITE_ONCE(ctx->released, true);
 
        if (!mmget_not_zero(mm))
                goto wakeup;
index 51bf7b827387198d3bbc9f6db146abfcd3056a0c..129975970d993dd81e28abf049eb05e4b1cc6649 100644 (file)
@@ -592,9 +592,9 @@ xlog_valid_lsn(
         * a transiently forward state. Instead, we can see the LSN in a
         * transiently behind state if we happen to race with a cycle wrap.
         */
-       cur_cycle = ACCESS_ONCE(log->l_curr_cycle);
+       cur_cycle = READ_ONCE(log->l_curr_cycle);
        smp_rmb();
-       cur_block = ACCESS_ONCE(log->l_curr_block);
+       cur_block = READ_ONCE(log->l_curr_block);
 
        if ((CYCLE_LSN(lsn) > cur_cycle) ||
            (CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block)) {
index ad54610ea6cd4520812357633d8e461c6f49e744..17d61b1f2511ad71881b6ff4a182c10dcdf5191a 100644 (file)
@@ -126,8 +126,12 @@ struct acpi_exception_info {
 #define AE_NOT_CONFIGURED               EXCEP_ENV (0x001C)
 #define AE_ACCESS                       EXCEP_ENV (0x001D)
 #define AE_IO_ERROR                     EXCEP_ENV (0x001E)
+#define AE_NUMERIC_OVERFLOW             EXCEP_ENV (0x001F)
+#define AE_HEX_OVERFLOW                 EXCEP_ENV (0x0020)
+#define AE_DECIMAL_OVERFLOW             EXCEP_ENV (0x0021)
+#define AE_OCTAL_OVERFLOW               EXCEP_ENV (0x0022)
 
-#define AE_CODE_ENV_MAX                 0x001E
+#define AE_CODE_ENV_MAX                 0x0022
 
 /*
  * Programmer exceptions
@@ -263,7 +267,15 @@ static const struct acpi_exception_info acpi_gbl_exception_names_env[] = {
        EXCEP_TXT("AE_NOT_CONFIGURED",
                  "The interface is not part of the current subsystem configuration"),
        EXCEP_TXT("AE_ACCESS", "Permission denied for the requested operation"),
-       EXCEP_TXT("AE_IO_ERROR", "An I/O error occurred")
+       EXCEP_TXT("AE_IO_ERROR", "An I/O error occurred"),
+       EXCEP_TXT("AE_NUMERIC_OVERFLOW",
+                 "Overflow during string-to-integer conversion"),
+       EXCEP_TXT("AE_HEX_OVERFLOW",
+                 "Overflow during ASCII hex-to-binary conversion"),
+       EXCEP_TXT("AE_DECIMAL_OVERFLOW",
+                 "Overflow during ASCII decimal-to-binary conversion"),
+       EXCEP_TXT("AE_OCTAL_OVERFLOW",
+                 "Overflow during ASCII octal-to-binary conversion")
 };
 
 static const struct acpi_exception_info acpi_gbl_exception_names_pgm[] = {
index c66eb8ffa454b2d19532c9e45867d19f0480851f..d5c0f5153c4e58f332841974dacae402ef14a3e8 100644 (file)
@@ -287,6 +287,8 @@ acpi_status acpi_os_write_port(acpi_io_address address, u32 value, u32 width);
 /*
  * Platform and hardware-independent physical memory interfaces
  */
+int acpi_os_read_iomem(void __iomem *virt_addr, u64 *value, u32 width);
+
 #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_read_memory
 acpi_status
 acpi_os_read_memory(acpi_physical_address address, u64 *value, u32 width);
index 53c5e2f7bcecd82f824d021de2d31d67e9206c71..e1dd1a8d42b60eb155796819b9518c34855cbfa5 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20170728
+#define ACPI_CA_VERSION                 0x20170831
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
index 6b8714a428b6d78832b2a876d62482de97c07ad5..7a89e6de94da938e450aa10623e76a86dbe6602d 100644 (file)
@@ -69,6 +69,7 @@
 #define ACPI_SIG_HEST           "HEST" /* Hardware Error Source Table */
 #define ACPI_SIG_MADT           "APIC" /* Multiple APIC Description Table */
 #define ACPI_SIG_MSCT           "MSCT" /* Maximum System Characteristics Table */
+#define ACPI_SIG_PDTT           "PDTT" /* Processor Debug Trigger Table */
 #define ACPI_SIG_PPTT           "PPTT" /* Processor Properties Topology Table */
 #define ACPI_SIG_SBST           "SBST" /* Smart Battery Specification Table */
 #define ACPI_SIG_SLIT           "SLIT" /* System Locality Distance Information Table */
@@ -1280,6 +1281,35 @@ struct acpi_nfit_flush_address {
        u64 hint_address[1];    /* Variable length */
 };
 
+/*******************************************************************************
+ *
+ * PDTT - Processor Debug Trigger Table (ACPI 6.2)
+ *        Version 0
+ *
+ ******************************************************************************/
+
+struct acpi_table_pdtt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 trigger_count;
+       u8 reserved[3];
+       u32 array_offset;
+};
+
+/*
+ * PDTT Communication Channel Identifier Structure.
+ * The number of these structures is defined by trigger_count above,
+ * starting at array_offset.
+ */
+struct acpi_pdtt_channel {
+       u16 sub_channel_id;
+};
+
+/* Mask and Flags for above */
+
+#define ACPI_PDTT_SUBCHANNEL_ID_MASK        0x00FF
+#define ACPI_PDTT_RUNTIME_TRIGGER           (1<<8)
+#define ACPI_PPTT_WAIT_COMPLETION           (1<<9)
+
 /*******************************************************************************
  *
  * PPTT - Processor Properties Topology Table (ACPI 6.2)
index 1797e81a320408e79c24ab09c1802f6b86f28a12..680f80960c3dcf36f6dac83c4061cce7f5103f1b 100644 (file)
@@ -51,7 +51,6 @@ int erst_clear(u64 record_id);
 
 int arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr, void *data);
 void arch_apei_report_mem_error(int sev, struct cper_sec_mem_err *mem_err);
-void arch_apei_flush_tlb_one(unsigned long addr);
 
 #endif
 #endif
index 8caa79c617035e60a41ee850150d2b472f35df5a..cd6ef45e614ea8131b8c0e1c50518d67b36a0d4e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mailbox_controller.h>
 #include <linux/mailbox_client.h>
 
+#define MAX_PCC_SUBSPACES      256
 #ifdef CONFIG_PCC
 extern struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
                                                  int subspace_id);
index 49be4bba1e9641de9713ebc06532e581f934e40b..34a028a7bcc53c095a2028f2d0cee89cd3835292 100644 (file)
@@ -244,4 +244,7 @@ static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
 #define atomic_long_inc_not_zero(l) \
        ATOMIC_LONG_PFX(_inc_not_zero)((ATOMIC_LONG_PFX(_t) *)(l))
 
+#define atomic_long_cond_read_acquire(v, c) \
+       ATOMIC_LONG_PFX(_cond_read_acquire)((ATOMIC_LONG_PFX(_t) *)(v), (c))
+
 #endif  /*  _ASM_GENERIC_ATOMIC_LONG_H  */
index d2013064dc69719cf7111f8c045c02580e51006e..dc9726fdac8f3398e4c7af310a6c00fb06c630a8 100644 (file)
 
 #if BITS_PER_LONG == 64
 
+/**
+ * do_div - returns 2 values: calculate remainder and update new dividend
+ * @n: pointer to uint64_t dividend (will be updated)
+ * @base: uint32_t divisor
+ *
+ * Summary:
+ * ``uint32_t remainder = *n % base;``
+ * ``*n = *n / base;``
+ *
+ * Return: (uint32_t)remainder
+ *
+ * NOTE: macro parameter @n is evaluated multiple times,
+ * beware of side effects!
+ */
 # define do_div(n,base) ({                                     \
        uint32_t __base = (base);                               \
        uint32_t __rem;                                         \
index 7d026bf277131f7bc4c79529cc26488e3a8281ee..0f7062bd55e5875ea107852d403088164a4ab165 100644 (file)
 
 /*
  * Writer states & reader shift and bias.
- *
- *       | +0 | +1 | +2 | +3 |
- *   ----+----+----+----+----+
- *    LE | 78 | 56 | 34 | 12 | 0x12345678
- *   ----+----+----+----+----+
- *       | wr |      rd      |
- *       +----+----+----+----+
- *
- *   ----+----+----+----+----+
- *    BE | 12 | 34 | 56 | 78 | 0x12345678
- *   ----+----+----+----+----+
- *       |      rd      | wr |
- *       +----+----+----+----+
  */
-#define        _QW_WAITING     1               /* A writer is waiting     */
-#define        _QW_LOCKED      0xff            /* A writer holds the lock */
-#define        _QW_WMASK       0xff            /* Writer mask             */
-#define        _QR_SHIFT       8               /* Reader count shift      */
+#define        _QW_WAITING     0x100           /* A writer is waiting     */
+#define        _QW_LOCKED      0x0ff           /* A writer holds the lock */
+#define        _QW_WMASK       0x1ff           /* Writer mask             */
+#define        _QR_SHIFT       9               /* Reader count shift      */
 #define _QR_BIAS       (1U << _QR_SHIFT)
 
 /*
  * External function declarations
  */
-extern void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts);
+extern void queued_read_lock_slowpath(struct qrwlock *lock);
 extern void queued_write_lock_slowpath(struct qrwlock *lock);
 
-/**
- * queued_read_can_lock- would read_trylock() succeed?
- * @lock: Pointer to queue rwlock structure
- */
-static inline int queued_read_can_lock(struct qrwlock *lock)
-{
-       return !(atomic_read(&lock->cnts) & _QW_WMASK);
-}
-
-/**
- * queued_write_can_lock- would write_trylock() succeed?
- * @lock: Pointer to queue rwlock structure
- */
-static inline int queued_write_can_lock(struct qrwlock *lock)
-{
-       return !atomic_read(&lock->cnts);
-}
-
 /**
  * queued_read_trylock - try to acquire read lock of a queue rwlock
  * @lock : Pointer to queue rwlock structure
@@ -118,7 +87,7 @@ static inline void queued_read_lock(struct qrwlock *lock)
                return;
 
        /* The slowpath will decrement the reader count, if necessary. */
-       queued_read_lock_slowpath(lock, cnts);
+       queued_read_lock_slowpath(lock);
 }
 
 /**
@@ -146,31 +115,19 @@ static inline void queued_read_unlock(struct qrwlock *lock)
        (void)atomic_sub_return_release(_QR_BIAS, &lock->cnts);
 }
 
-/**
- * __qrwlock_write_byte - retrieve the write byte address of a queue rwlock
- * @lock : Pointer to queue rwlock structure
- * Return: the write byte address of a queue rwlock
- */
-static inline u8 *__qrwlock_write_byte(struct qrwlock *lock)
-{
-       return (u8 *)lock + 3 * IS_BUILTIN(CONFIG_CPU_BIG_ENDIAN);
-}
-
 /**
  * queued_write_unlock - release write lock of a queue rwlock
  * @lock : Pointer to queue rwlock structure
  */
 static inline void queued_write_unlock(struct qrwlock *lock)
 {
-       smp_store_release(__qrwlock_write_byte(lock), 0);
+       smp_store_release(&lock->wlocked, 0);
 }
 
 /*
  * Remapping rwlock architecture specific functions to the corresponding
  * queue rwlock functions.
  */
-#define arch_read_can_lock(l)  queued_read_can_lock(l)
-#define arch_write_can_lock(l) queued_write_can_lock(l)
 #define arch_read_lock(l)      queued_read_lock(l)
 #define arch_write_lock(l)     queued_write_lock(l)
 #define arch_read_trylock(l)   queued_read_trylock(l)
index d93573eff16294aa1a9efa0a79a1f428ddd08c23..137ecdd16daa01c9ced213a9ee38de7b9f16181a 100644 (file)
  */
 
 typedef struct qrwlock {
-       atomic_t                cnts;
+       union {
+               atomic_t cnts;
+               struct {
+#ifdef __LITTLE_ENDIAN
+                       u8 wlocked;     /* Locked for write? */
+                       u8 __lstate[3];
+#else
+                       u8 __lstate[3];
+                       u8 wlocked;     /* Locked for write? */
+#endif
+               };
+       };
        arch_spinlock_t         wait_lock;
 } arch_rwlock_t;
 
 #define        __ARCH_RW_LOCK_UNLOCKED {               \
-       .cnts = ATOMIC_INIT(0),                 \
+       { .cnts = ATOMIC_INIT(0), },            \
        .wait_lock = __ARCH_SPIN_LOCK_UNLOCKED, \
 }
 
index 66260777d64470a2ce016b4bb94ed660ab5fa6a0..b37b4ad7eb946633aa520db7b1e0f97fe46562b3 100644 (file)
@@ -121,6 +121,5 @@ static __always_inline bool virt_spin_lock(struct qspinlock *lock)
 #define arch_spin_lock(l)              queued_spin_lock(l)
 #define arch_spin_trylock(l)           queued_spin_trylock(l)
 #define arch_spin_unlock(l)            queued_spin_unlock(l)
-#define arch_spin_lock_flags(l, f)     queued_spin_lock(l)
 
 #endif /* __ASM_GENERIC_QSPINLOCK_H */
index bdbe43bac2307f5cdd617ebad8c0ae5d0842a37d..93e67a055a4d85ca82436f71ed160d971e33e46e 100644 (file)
@@ -38,6 +38,16 @@ static inline void __down_read(struct rw_semaphore *sem)
                rwsem_down_read_failed(sem);
 }
 
+static inline int __down_read_killable(struct rw_semaphore *sem)
+{
+       if (unlikely(atomic_long_inc_return_acquire(&sem->count) <= 0)) {
+               if (IS_ERR(rwsem_down_read_failed_killable(sem)))
+                       return -EINTR;
+       }
+
+       return 0;
+}
+
 static inline int __down_read_trylock(struct rw_semaphore *sem)
 {
        long tmp;
index 8acfc1e099e11079cde2ed23d028bd6d5fb79bc6..bdcd1caae0923db6e2bd6a964b6e9b00cad3c5ef 100644 (file)
 #define TEXT_TEXT                                                      \
                ALIGN_FUNCTION();                                       \
                *(.text.hot TEXT_MAIN .text.fixup .text.unlikely)       \
+               *(.text..refcount)                                      \
                *(.ref.text)                                            \
        MEM_KEEP(init.text)                                             \
        MEM_KEEP(exit.text)                                             \
 #define BUG_TABLE
 #endif
 
-#ifdef CONFIG_ORC_UNWINDER
+#ifdef CONFIG_UNWINDER_ORC
 #define ORC_UNWIND_TABLE                                               \
        . = ALIGN(4);                                                   \
        .orc_unwind_ip : AT(ADDR(.orc_unwind_ip) - LOAD_OFFSET) {       \
 #define INIT_RAM_FS
 #endif
 
+/*
+ * Memory encryption operates on a page basis. Since we need to clear
+ * the memory encryption mask for this section, it needs to be aligned
+ * on a page boundary and be a page-size multiple in length.
+ *
+ * Note: We use a separate section so that only this section gets
+ * decrypted to avoid exposing more than we wish.
+ */
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+#define PERCPU_DECRYPTED_SECTION                                       \
+       . = ALIGN(PAGE_SIZE);                                           \
+       *(.data..percpu..decrypted)                                     \
+       . = ALIGN(PAGE_SIZE);
+#else
+#define PERCPU_DECRYPTED_SECTION
+#endif
+
+
 /*
  * Default discarded sections.
  *
        . = ALIGN(cacheline);                                           \
        *(.data..percpu)                                                \
        *(.data..percpu..shared_aligned)                                \
+       PERCPU_DECRYPTED_SECTION                                        \
        VMLINUX_SYMBOL(__per_cpu_end) = .;
 
 /**
index 502af53ec0124e1c878ffa297f188c67a79c8d0e..dc1ebfeeb5ecc10e248f57084f80c72d32c6c14a 100644 (file)
@@ -864,21 +864,16 @@ static inline void arch_reserve_mem_area(acpi_physical_address addr,
 #endif
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_PM)
-int acpi_dev_runtime_suspend(struct device *dev);
-int acpi_dev_runtime_resume(struct device *dev);
+int acpi_dev_suspend(struct device *dev, bool wakeup);
+int acpi_dev_resume(struct device *dev);
 int acpi_subsys_runtime_suspend(struct device *dev);
 int acpi_subsys_runtime_resume(struct device *dev);
-struct acpi_device *acpi_dev_pm_get_node(struct device *dev);
 int acpi_dev_pm_attach(struct device *dev, bool power_on);
 #else
 static inline int acpi_dev_runtime_suspend(struct device *dev) { return 0; }
 static inline int acpi_dev_runtime_resume(struct device *dev) { return 0; }
 static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; }
 static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; }
-static inline struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
-{
-       return NULL;
-}
 static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
 {
        return -ENODEV;
@@ -887,22 +882,30 @@ static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_PM_SLEEP)
 int acpi_dev_suspend_late(struct device *dev);
-int acpi_dev_resume_early(struct device *dev);
 int acpi_subsys_prepare(struct device *dev);
 void acpi_subsys_complete(struct device *dev);
 int acpi_subsys_suspend_late(struct device *dev);
+int acpi_subsys_suspend_noirq(struct device *dev);
+int acpi_subsys_resume_noirq(struct device *dev);
 int acpi_subsys_resume_early(struct device *dev);
 int acpi_subsys_suspend(struct device *dev);
 int acpi_subsys_freeze(struct device *dev);
+int acpi_subsys_freeze_late(struct device *dev);
+int acpi_subsys_freeze_noirq(struct device *dev);
+int acpi_subsys_thaw_noirq(struct device *dev);
 #else
-static inline int acpi_dev_suspend_late(struct device *dev) { return 0; }
 static inline int acpi_dev_resume_early(struct device *dev) { return 0; }
 static inline int acpi_subsys_prepare(struct device *dev) { return 0; }
 static inline void acpi_subsys_complete(struct device *dev) {}
 static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; }
+static inline int acpi_subsys_suspend_noirq(struct device *dev) { return 0; }
+static inline int acpi_subsys_resume_noirq(struct device *dev) { return 0; }
 static inline int acpi_subsys_resume_early(struct device *dev) { return 0; }
 static inline int acpi_subsys_suspend(struct device *dev) { return 0; }
 static inline int acpi_subsys_freeze(struct device *dev) { return 0; }
+static inline int acpi_subsys_freeze_late(struct device *dev) { return 0; }
+static inline int acpi_subsys_freeze_noirq(struct device *dev) { return 0; }
+static inline int acpi_subsys_thaw_noirq(struct device *dev) { return 0; }
 #endif
 
 #ifdef CONFIG_ACPI
@@ -1254,4 +1257,13 @@ int acpi_irq_get(acpi_handle handle, unsigned int index, struct resource *res)
 }
 #endif
 
+#ifdef CONFIG_ACPI_LPIT
+int lpit_read_residency_count_address(u64 *address);
+#else
+static inline int lpit_read_residency_count_address(u64 *address)
+{
+       return -EINVAL;
+}
+#endif
+
 #endif /*_LINUX_ACPI_H*/
index d4fcb0efb896c3e4a40cb527c4da531bc58b3831..304511267c823d0fb398839a977d5b31f1f037e6 100644 (file)
@@ -6,15 +6,30 @@
 #define _LINUX_ARCH_TOPOLOGY_H_
 
 #include <linux/types.h>
+#include <linux/percpu.h>
 
 void topology_normalize_cpu_scale(void);
 
 struct device_node;
 bool topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu);
 
+DECLARE_PER_CPU(unsigned long, cpu_scale);
+
 struct sched_domain;
-unsigned long topology_get_cpu_scale(struct sched_domain *sd, int cpu);
+static inline
+unsigned long topology_get_cpu_scale(struct sched_domain *sd, int cpu)
+{
+       return per_cpu(cpu_scale, cpu);
+}
 
 void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity);
 
+DECLARE_PER_CPU(unsigned long, freq_scale);
+
+static inline
+unsigned long topology_get_freq_scale(struct sched_domain *sd, int cpu)
+{
+       return per_cpu(freq_scale, cpu);
+}
+
 #endif /* _LINUX_ARCH_TOPOLOGY_H_ */
index cd18203d6ff3278e477e24001fe2af058c5b00b0..8b276fd9a127317e5ff0d83082eecc9cfa68dd38 100644 (file)
@@ -654,6 +654,8 @@ static inline int atomic_dec_if_positive(atomic_t *v)
 }
 #endif
 
+#define atomic_cond_read_acquire(v, c) smp_cond_load_acquire(&(v)->counter, (c))
+
 #ifdef CONFIG_GENERIC_ATOMIC64
 #include <asm-generic/atomic64.h>
 #endif
@@ -1073,6 +1075,8 @@ static inline long long atomic64_fetch_andnot_release(long long i, atomic64_t *v
 }
 #endif
 
+#define atomic64_cond_read_acquire(v, c)       smp_cond_load_acquire(&(v)->counter, (c))
+
 #include <asm-generic/atomic-long.h>
 
 #endif /* _LINUX_ATOMIC_H */
index 1b6f5560c264d0fd0557800e1e66ba4722c4b758..a1a8f09631ce0de1652a944dd24fd754b906f40f 100644 (file)
@@ -2,6 +2,10 @@
 #ifndef _LINUX_AVERAGE_H
 #define _LINUX_AVERAGE_H
 
+#include <linux/bug.h>
+#include <linux/compiler.h>
+#include <linux/log2.h>
+
 /*
  * Exponentially weighted moving average (EWMA)
  *
@@ -49,7 +53,7 @@
        static inline void ewma_##name##_add(struct ewma_##name *e,     \
                                             unsigned long val)         \
        {                                                               \
-               unsigned long internal = ACCESS_ONCE(e->internal);      \
+               unsigned long internal = READ_ONCE(e->internal);        \
                unsigned long weight_rcp = ilog2(_weight_rcp);          \
                unsigned long precision = _precision;                   \
                                                                        \
                BUILD_BUG_ON((_precision) > 30);                        \
                BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp);               \
                                                                        \
-               ACCESS_ONCE(e->internal) = internal ?                   \
+               WRITE_ONCE(e->internal, internal ?                      \
                        (((internal << weight_rcp) - internal) +        \
                                (val << precision)) >> weight_rcp :     \
-                       (val << precision)                            \
+                       (val << precision));                            \
        }
 
 #endif /* _LINUX_AVERAGE_H */
index 19748a5b0e778d5ad7948a3ffd560d92917fa5f2..3489253e38fc3ec54dc45304273feb5210fc3f34 100644 (file)
  * See lib/bitmap.c for more details.
  */
 
-/*
+/**
+ * DOC: bitmap overview
+ *
  * The available bitmap operations and their rough meaning in the
  * case that the bitmap is a single unsigned long are thus:
  *
  * Note that nbits should be always a compile time evaluable constant.
  * Otherwise many inlines will generate horrible code.
  *
- * bitmap_zero(dst, nbits)                     *dst = 0UL
- * bitmap_fill(dst, nbits)                     *dst = ~0UL
- * bitmap_copy(dst, src, nbits)                        *dst = *src
- * bitmap_and(dst, src1, src2, nbits)          *dst = *src1 & *src2
- * bitmap_or(dst, src1, src2, nbits)           *dst = *src1 | *src2
- * bitmap_xor(dst, src1, src2, nbits)          *dst = *src1 ^ *src2
- * bitmap_andnot(dst, src1, src2, nbits)       *dst = *src1 & ~(*src2)
- * bitmap_complement(dst, src, nbits)          *dst = ~(*src)
- * bitmap_equal(src1, src2, nbits)             Are *src1 and *src2 equal?
- * bitmap_intersects(src1, src2, nbits)        Do *src1 and *src2 overlap?
- * bitmap_subset(src1, src2, nbits)            Is *src1 a subset of *src2?
- * bitmap_empty(src, nbits)                    Are all bits zero in *src?
- * bitmap_full(src, nbits)                     Are all bits set in *src?
- * bitmap_weight(src, nbits)                   Hamming Weight: number set bits
- * bitmap_set(dst, pos, nbits)                 Set specified bit area
- * bitmap_clear(dst, pos, nbits)               Clear specified bit area
- * bitmap_find_next_zero_area(buf, len, pos, n, mask)  Find bit free area
- * bitmap_find_next_zero_area_off(buf, len, pos, n, mask)      as above
- * bitmap_shift_right(dst, src, n, nbits)      *dst = *src >> n
- * bitmap_shift_left(dst, src, n, nbits)       *dst = *src << n
- * bitmap_remap(dst, src, old, new, nbits)     *dst = map(old, new)(src)
- * bitmap_bitremap(oldbit, old, new, nbits)    newbit = map(old, new)(oldbit)
- * bitmap_onto(dst, orig, relmap, nbits)       *dst = orig relative to relmap
- * bitmap_fold(dst, orig, sz, nbits)           dst bits = orig bits mod sz
- * bitmap_parse(buf, buflen, dst, nbits)       Parse bitmap dst from kernel buf
- * bitmap_parse_user(ubuf, ulen, dst, nbits)   Parse bitmap dst from user buf
- * bitmap_parselist(buf, dst, nbits)           Parse bitmap dst from kernel buf
- * bitmap_parselist_user(buf, dst, nbits)      Parse bitmap dst from user buf
- * bitmap_find_free_region(bitmap, bits, order)        Find and allocate bit region
- * bitmap_release_region(bitmap, pos, order)   Free specified bit region
- * bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
- * bitmap_from_u32array(dst, nbits, buf, nwords) *dst = *buf (nwords 32b words)
- * bitmap_to_u32array(buf, nwords, src, nbits) *buf = *dst (nwords 32b words)
+ * ::
+ *
+ *  bitmap_zero(dst, nbits)                     *dst = 0UL
+ *  bitmap_fill(dst, nbits)                     *dst = ~0UL
+ *  bitmap_copy(dst, src, nbits)                *dst = *src
+ *  bitmap_and(dst, src1, src2, nbits)          *dst = *src1 & *src2
+ *  bitmap_or(dst, src1, src2, nbits)           *dst = *src1 | *src2
+ *  bitmap_xor(dst, src1, src2, nbits)          *dst = *src1 ^ *src2
+ *  bitmap_andnot(dst, src1, src2, nbits)       *dst = *src1 & ~(*src2)
+ *  bitmap_complement(dst, src, nbits)          *dst = ~(*src)
+ *  bitmap_equal(src1, src2, nbits)             Are *src1 and *src2 equal?
+ *  bitmap_intersects(src1, src2, nbits)        Do *src1 and *src2 overlap?
+ *  bitmap_subset(src1, src2, nbits)            Is *src1 a subset of *src2?
+ *  bitmap_empty(src, nbits)                    Are all bits zero in *src?
+ *  bitmap_full(src, nbits)                     Are all bits set in *src?
+ *  bitmap_weight(src, nbits)                   Hamming Weight: number set bits
+ *  bitmap_set(dst, pos, nbits)                 Set specified bit area
+ *  bitmap_clear(dst, pos, nbits)               Clear specified bit area
+ *  bitmap_find_next_zero_area(buf, len, pos, n, mask)  Find bit free area
+ *  bitmap_find_next_zero_area_off(buf, len, pos, n, mask)  as above
+ *  bitmap_shift_right(dst, src, n, nbits)      *dst = *src >> n
+ *  bitmap_shift_left(dst, src, n, nbits)       *dst = *src << n
+ *  bitmap_remap(dst, src, old, new, nbits)     *dst = map(old, new)(src)
+ *  bitmap_bitremap(oldbit, old, new, nbits)    newbit = map(old, new)(oldbit)
+ *  bitmap_onto(dst, orig, relmap, nbits)       *dst = orig relative to relmap
+ *  bitmap_fold(dst, orig, sz, nbits)           dst bits = orig bits mod sz
+ *  bitmap_parse(buf, buflen, dst, nbits)       Parse bitmap dst from kernel buf
+ *  bitmap_parse_user(ubuf, ulen, dst, nbits)   Parse bitmap dst from user buf
+ *  bitmap_parselist(buf, dst, nbits)           Parse bitmap dst from kernel buf
+ *  bitmap_parselist_user(buf, dst, nbits)      Parse bitmap dst from user buf
+ *  bitmap_find_free_region(bitmap, bits, order)  Find and allocate bit region
+ *  bitmap_release_region(bitmap, pos, order)   Free specified bit region
+ *  bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
+ *  bitmap_from_u32array(dst, nbits, buf, nwords)  *dst = *buf (nwords 32b words)
+ *  bitmap_to_u32array(buf, nwords, src, nbits) *buf = *dst (nwords 32b words)
+ *
  */
 
-/*
- * Also the following operations in asm/bitops.h apply to bitmaps.
+/**
+ * DOC: bitmap bitops
+ *
+ * Also the following operations in asm/bitops.h apply to bitmaps.::
+ *
+ *  set_bit(bit, addr)                  *addr |= bit
+ *  clear_bit(bit, addr)                *addr &= ~bit
+ *  change_bit(bit, addr)               *addr ^= bit
+ *  test_bit(bit, addr)                 Is bit set in *addr?
+ *  test_and_set_bit(bit, addr)         Set bit and return old value
+ *  test_and_clear_bit(bit, addr)       Clear bit and return old value
+ *  test_and_change_bit(bit, addr)      Change bit and return old value
+ *  find_first_zero_bit(addr, nbits)    Position first zero bit in *addr
+ *  find_first_bit(addr, nbits)         Position first set bit in *addr
+ *  find_next_zero_bit(addr, nbits, bit)  Position next zero bit in *addr >= bit
+ *  find_next_bit(addr, nbits, bit)     Position next set bit in *addr >= bit
  *
- * set_bit(bit, addr)                  *addr |= bit
- * clear_bit(bit, addr)                        *addr &= ~bit
- * change_bit(bit, addr)               *addr ^= bit
- * test_bit(bit, addr)                 Is bit set in *addr?
- * test_and_set_bit(bit, addr)         Set bit and return old value
- * test_and_clear_bit(bit, addr)       Clear bit and return old value
- * test_and_change_bit(bit, addr)      Change bit and return old value
- * find_first_zero_bit(addr, nbits)    Position first zero bit in *addr
- * find_first_bit(addr, nbits)         Position first set bit in *addr
- * find_next_zero_bit(addr, nbits, bit)        Position next zero bit in *addr >= bit
- * find_next_bit(addr, nbits, bit)     Position next set bit in *addr >= bit
  */
 
-/*
+/**
+ * DOC: declare bitmap
  * The DECLARE_BITMAP(name,bits) macro, in linux/types.h, can be used
  * to declare an array named 'name' of just enough unsigned longs to
  * contain all bit positions from 0 to 'bits' - 1.
@@ -361,8 +370,9 @@ static inline int bitmap_parse(const char *buf, unsigned int buflen,
        return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits);
 }
 
-/*
+/**
  * BITMAP_FROM_U64() - Represent u64 value in the format suitable for bitmap.
+ * @n: u64 value
  *
  * Linux bitmaps are internally arrays of unsigned longs, i.e. 32-bit
  * integers in 32-bit environment, and 64-bit integers in 64-bit one.
@@ -393,14 +403,14 @@ static inline int bitmap_parse(const char *buf, unsigned int buflen,
                                ((unsigned long) ((u64)(n) >> 32))
 #endif
 
-/*
+/**
  * bitmap_from_u64 - Check and swap words within u64.
  *  @mask: source bitmap
  *  @dst:  destination bitmap
  *
- * In 32-bit Big Endian kernel, when using (u32 *)(&val)[*]
+ * In 32-bit Big Endian kernel, when using ``(u32 *)(&val)[*]``
  * to read u64 mask, we will get the wrong word.
- * That is "(u32 *)(&val)[0]" gets the upper 32 bits,
+ * That is ``(u32 *)(&val)[0]`` gets the upper 32 bits,
  * but we expect the lower 32-bits of u64.
  */
 static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
index d03c5dd6185daafd871e8ad8e685fa1c0af5cd8e..c537ac7435ad147e44165b7cceedde925677c50b 100644 (file)
@@ -237,7 +237,7 @@ static inline unsigned long __ffs64(u64 word)
        typeof(*ptr) old, new;                                  \
                                                                \
        do {                                                    \
-               old = ACCESS_ONCE(*ptr);                        \
+               old = READ_ONCE(*ptr);                  \
                new = (old & ~mask) | bits;                     \
        } while (cmpxchg(ptr, old, new) != old);                \
                                                                \
@@ -252,7 +252,7 @@ static inline unsigned long __ffs64(u64 word)
        typeof(*ptr) old, new;                                  \
                                                                \
        do {                                                    \
-               old = ACCESS_ONCE(*ptr);                        \
+               old = READ_ONCE(*ptr);                  \
                new = old & ~clear;                             \
        } while (!(old & test) &&                               \
                 cmpxchg(ptr, old, new) != old);                \
index 54dfef70a072744981e77f2621f8c01309c38970..a06583e41f80520a1425e4231d4e201b8d0a12a7 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __LINUX_COMPILER_H
+#ifndef __LINUX_COMPILER_TYPES_H
 #error "Please don't include <linux/compiler-clang.h> directly, include <linux/compiler.h> instead."
 #endif
 
index bb78e5bdff26334376eb54a4b142845bbbaf8c46..2272ded07496d6044ebe43e930047237bb5f254e 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __LINUX_COMPILER_H
+#ifndef __LINUX_COMPILER_TYPES_H
 #error "Please don't include <linux/compiler-gcc.h> directly, include <linux/compiler.h> instead."
 #endif
 
index 523d1b74550f20e39c86f3042982185e3dfeb7bd..bfa08160db3a46c5bb798b63650717815d08158b 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __LINUX_COMPILER_H
+#ifndef __LINUX_COMPILER_TYPES_H
 #error "Please don't include <linux/compiler-intel.h> directly, include <linux/compiler.h> instead."
 #endif
 
index 202710420d6deba1bba8107616359ae069ffd5e7..3672353a0acda884be51fd3debba26ea50f43b09 100644 (file)
 #ifndef __LINUX_COMPILER_H
 #define __LINUX_COMPILER_H
 
-#ifndef __ASSEMBLY__
+#include <linux/compiler_types.h>
 
-#ifdef __CHECKER__
-# define __user                __attribute__((noderef, address_space(1)))
-# define __kernel      __attribute__((address_space(0)))
-# define __safe                __attribute__((safe))
-# define __force       __attribute__((force))
-# define __nocast      __attribute__((nocast))
-# define __iomem       __attribute__((noderef, address_space(2)))
-# define __must_hold(x)        __attribute__((context(x,1,1)))
-# define __acquires(x) __attribute__((context(x,0,1)))
-# define __releases(x) __attribute__((context(x,1,0)))
-# define __acquire(x)  __context__(x,1)
-# define __release(x)  __context__(x,-1)
-# define __cond_lock(x,c)      ((c) ? ({ __acquire(x); 1; }) : 0)
-# define __percpu      __attribute__((noderef, address_space(3)))
-# define __rcu         __attribute__((noderef, address_space(4)))
-# define __private     __attribute__((noderef))
-extern void __chk_user_ptr(const volatile void __user *);
-extern void __chk_io_ptr(const volatile void __iomem *);
-# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member))
-#else /* __CHECKER__ */
-# ifdef STRUCTLEAK_PLUGIN
-#  define __user __attribute__((user))
-# else
-#  define __user
-# endif
-# define __kernel
-# define __safe
-# define __force
-# define __nocast
-# define __iomem
-# define __chk_user_ptr(x) (void)0
-# define __chk_io_ptr(x) (void)0
-# define __builtin_warning(x, y...) (1)
-# define __must_hold(x)
-# define __acquires(x)
-# define __releases(x)
-# define __acquire(x) (void)0
-# define __release(x) (void)0
-# define __cond_lock(x,c) (c)
-# define __percpu
-# define __rcu
-# define __private
-# define ACCESS_PRIVATE(p, member) ((p)->member)
-#endif /* __CHECKER__ */
-
-/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
-#define ___PASTE(a,b) a##b
-#define __PASTE(a,b) ___PASTE(a,b)
+#ifndef __ASSEMBLY__
 
 #ifdef __KERNEL__
 
-#ifdef __GNUC__
-#include <linux/compiler-gcc.h>
-#endif
-
-#if defined(CC_USING_HOTPATCH) && !defined(__CHECKER__)
-#define notrace __attribute__((hotpatch(0,0)))
-#else
-#define notrace __attribute__((no_instrument_function))
-#endif
-
-/* Intel compiler defines __GNUC__. So we will overwrite implementations
- * coming from above header files here
- */
-#ifdef __INTEL_COMPILER
-# include <linux/compiler-intel.h>
-#endif
-
-/* Clang compiler defines __GNUC__. So we will overwrite implementations
- * coming from above header files here
- */
-#ifdef __clang__
-#include <linux/compiler-clang.h>
-#endif
-
-/*
- * Generic compiler-dependent macros required for kernel
- * build go below this comment. Actual compiler/compiler version
- * specific implementations come from the above header files
- */
-
-struct ftrace_branch_data {
-       const char *func;
-       const char *file;
-       unsigned line;
-       union {
-               struct {
-                       unsigned long correct;
-                       unsigned long incorrect;
-               };
-               struct {
-                       unsigned long miss;
-                       unsigned long hit;
-               };
-               unsigned long miss_hit[2];
-       };
-};
-
-struct ftrace_likely_data {
-       struct ftrace_branch_data       data;
-       unsigned long                   constant;
-};
-
 /*
  * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code
  * to disable branch tracing on a per file basis.
@@ -333,6 +234,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
  * with an explicit memory barrier or atomic instruction that provides the
  * required ordering.
  */
+#include <asm/barrier.h>
 
 #define __READ_ONCE(x, check)                                          \
 ({                                                                     \
@@ -341,6 +243,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
                __read_once_size(&(x), __u.__c, sizeof(x));             \
        else                                                            \
                __read_once_size_nocheck(&(x), __u.__c, sizeof(x));     \
+       smp_read_barrier_depends(); /* Enforce dependency ordering from x */ \
        __u.__val;                                                      \
 })
 #define READ_ONCE(x) __READ_ONCE(x, 1)
@@ -363,167 +266,6 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef __KERNEL__
-/*
- * Allow us to mark functions as 'deprecated' and have gcc emit a nice
- * warning for each use, in hopes of speeding the functions removal.
- * Usage is:
- *             int __deprecated foo(void)
- */
-#ifndef __deprecated
-# define __deprecated          /* unimplemented */
-#endif
-
-#ifdef MODULE
-#define __deprecated_for_modules __deprecated
-#else
-#define __deprecated_for_modules
-#endif
-
-#ifndef __must_check
-#define __must_check
-#endif
-
-#ifndef CONFIG_ENABLE_MUST_CHECK
-#undef __must_check
-#define __must_check
-#endif
-#ifndef CONFIG_ENABLE_WARN_DEPRECATED
-#undef __deprecated
-#undef __deprecated_for_modules
-#define __deprecated
-#define __deprecated_for_modules
-#endif
-
-#ifndef __malloc
-#define __malloc
-#endif
-
-/*
- * Allow us to avoid 'defined but not used' warnings on functions and data,
- * as well as force them to be emitted to the assembly file.
- *
- * As of gcc 3.4, static functions that are not marked with attribute((used))
- * may be elided from the assembly file.  As of gcc 3.4, static data not so
- * marked will not be elided, but this may change in a future gcc version.
- *
- * NOTE: Because distributions shipped with a backported unit-at-a-time
- * compiler in gcc 3.3, we must define __used to be __attribute__((used))
- * for gcc >=3.3 instead of 3.4.
- *
- * In prior versions of gcc, such functions and data would be emitted, but
- * would be warned about except with attribute((unused)).
- *
- * Mark functions that are referenced only in inline assembly as __used so
- * the code is emitted even though it appears to be unreferenced.
- */
-#ifndef __used
-# define __used                        /* unimplemented */
-#endif
-
-#ifndef __maybe_unused
-# define __maybe_unused                /* unimplemented */
-#endif
-
-#ifndef __always_unused
-# define __always_unused       /* unimplemented */
-#endif
-
-#ifndef noinline
-#define noinline
-#endif
-
-/*
- * Rather then using noinline to prevent stack consumption, use
- * noinline_for_stack instead.  For documentation reasons.
- */
-#define noinline_for_stack noinline
-
-#ifndef __always_inline
-#define __always_inline inline
-#endif
-
-#endif /* __KERNEL__ */
-
-/*
- * From the GCC manual:
- *
- * Many functions do not examine any values except their arguments,
- * and have no effects except the return value.  Basically this is
- * just slightly more strict class than the `pure' attribute above,
- * since function is not allowed to read global memory.
- *
- * Note that a function that has pointer arguments and examines the
- * data pointed to must _not_ be declared `const'.  Likewise, a
- * function that calls a non-`const' function usually must not be
- * `const'.  It does not make sense for a `const' function to return
- * `void'.
- */
-#ifndef __attribute_const__
-# define __attribute_const__   /* unimplemented */
-#endif
-
-#ifndef __designated_init
-# define __designated_init
-#endif
-
-#ifndef __latent_entropy
-# define __latent_entropy
-#endif
-
-#ifndef __randomize_layout
-# define __randomize_layout __designated_init
-#endif
-
-#ifndef __no_randomize_layout
-# define __no_randomize_layout
-#endif
-
-#ifndef randomized_struct_fields_start
-# define randomized_struct_fields_start
-# define randomized_struct_fields_end
-#endif
-
-/*
- * Tell gcc if a function is cold. The compiler will assume any path
- * directly leading to the call is unlikely.
- */
-
-#ifndef __cold
-#define __cold
-#endif
-
-/* Simple shorthand for a section definition */
-#ifndef __section
-# define __section(S) __attribute__ ((__section__(#S)))
-#endif
-
-#ifndef __visible
-#define __visible
-#endif
-
-#ifndef __nostackprotector
-# define __nostackprotector
-#endif
-
-/*
- * Assume alignment of return value.
- */
-#ifndef __assume_aligned
-#define __assume_aligned(a, ...)
-#endif
-
-
-/* Are two types/vars the same type (ignoring qualifiers)? */
-#ifndef __same_type
-# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
-#endif
-
-/* Is this type a native word size -- useful for atomic operations */
-#ifndef __native_word
-# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
-#endif
-
 /* Compile time object size, -1 for unknown */
 #ifndef __compiletime_object_size
 # define __compiletime_object_size(obj) -1
@@ -605,24 +347,4 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
        (volatile typeof(x) *)&(x); })
 #define ACCESS_ONCE(x) (*__ACCESS_ONCE(x))
 
-/**
- * lockless_dereference() - safely load a pointer for later dereference
- * @p: The pointer to load
- *
- * Similar to rcu_dereference(), but for situations where the pointed-to
- * object's lifetime is managed by something other than RCU.  That
- * "something other" might be reference counting or simple immortality.
- *
- * The seemingly unused variable ___typecheck_p validates that @p is
- * indeed a pointer type by using a pointer to typeof(*p) as the type.
- * Taking a pointer to typeof(*p) again is needed in case p is void *.
- */
-#define lockless_dereference(p) \
-({ \
-       typeof(p) _________p1 = READ_ONCE(p); \
-       typeof(*(p)) *___typecheck_p __maybe_unused; \
-       smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
-       (_________p1); \
-})
-
 #endif /* __LINUX_COMPILER_H */
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
new file mode 100644 (file)
index 0000000..6b79a9b
--- /dev/null
@@ -0,0 +1,274 @@
+#ifndef __LINUX_COMPILER_TYPES_H
+#define __LINUX_COMPILER_TYPES_H
+
+#ifndef __ASSEMBLY__
+
+#ifdef __CHECKER__
+# define __user                __attribute__((noderef, address_space(1)))
+# define __kernel      __attribute__((address_space(0)))
+# define __safe                __attribute__((safe))
+# define __force       __attribute__((force))
+# define __nocast      __attribute__((nocast))
+# define __iomem       __attribute__((noderef, address_space(2)))
+# define __must_hold(x)        __attribute__((context(x,1,1)))
+# define __acquires(x) __attribute__((context(x,0,1)))
+# define __releases(x) __attribute__((context(x,1,0)))
+# define __acquire(x)  __context__(x,1)
+# define __release(x)  __context__(x,-1)
+# define __cond_lock(x,c)      ((c) ? ({ __acquire(x); 1; }) : 0)
+# define __percpu      __attribute__((noderef, address_space(3)))
+# define __rcu         __attribute__((noderef, address_space(4)))
+# define __private     __attribute__((noderef))
+extern void __chk_user_ptr(const volatile void __user *);
+extern void __chk_io_ptr(const volatile void __iomem *);
+# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member))
+#else /* __CHECKER__ */
+# ifdef STRUCTLEAK_PLUGIN
+#  define __user __attribute__((user))
+# else
+#  define __user
+# endif
+# define __kernel
+# define __safe
+# define __force
+# define __nocast
+# define __iomem
+# define __chk_user_ptr(x) (void)0
+# define __chk_io_ptr(x) (void)0
+# define __builtin_warning(x, y...) (1)
+# define __must_hold(x)
+# define __acquires(x)
+# define __releases(x)
+# define __acquire(x) (void)0
+# define __release(x) (void)0
+# define __cond_lock(x,c) (c)
+# define __percpu
+# define __rcu
+# define __private
+# define ACCESS_PRIVATE(p, member) ((p)->member)
+#endif /* __CHECKER__ */
+
+/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
+#define ___PASTE(a,b) a##b
+#define __PASTE(a,b) ___PASTE(a,b)
+
+#ifdef __KERNEL__
+
+#ifdef __GNUC__
+#include <linux/compiler-gcc.h>
+#endif
+
+#if defined(CC_USING_HOTPATCH) && !defined(__CHECKER__)
+#define notrace __attribute__((hotpatch(0,0)))
+#else
+#define notrace __attribute__((no_instrument_function))
+#endif
+
+/* Intel compiler defines __GNUC__. So we will overwrite implementations
+ * coming from above header files here
+ */
+#ifdef __INTEL_COMPILER
+# include <linux/compiler-intel.h>
+#endif
+
+/* Clang compiler defines __GNUC__. So we will overwrite implementations
+ * coming from above header files here
+ */
+#ifdef __clang__
+#include <linux/compiler-clang.h>
+#endif
+
+/*
+ * Generic compiler-dependent macros required for kernel
+ * build go below this comment. Actual compiler/compiler version
+ * specific implementations come from the above header files
+ */
+
+struct ftrace_branch_data {
+       const char *func;
+       const char *file;
+       unsigned line;
+       union {
+               struct {
+                       unsigned long correct;
+                       unsigned long incorrect;
+               };
+               struct {
+                       unsigned long miss;
+                       unsigned long hit;
+               };
+               unsigned long miss_hit[2];
+       };
+};
+
+struct ftrace_likely_data {
+       struct ftrace_branch_data       data;
+       unsigned long                   constant;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASSEMBLY__ */
+
+#ifdef __KERNEL__
+/*
+ * Allow us to mark functions as 'deprecated' and have gcc emit a nice
+ * warning for each use, in hopes of speeding the functions removal.
+ * Usage is:
+ *             int __deprecated foo(void)
+ */
+#ifndef __deprecated
+# define __deprecated          /* unimplemented */
+#endif
+
+#ifdef MODULE
+#define __deprecated_for_modules __deprecated
+#else
+#define __deprecated_for_modules
+#endif
+
+#ifndef __must_check
+#define __must_check
+#endif
+
+#ifndef CONFIG_ENABLE_MUST_CHECK
+#undef __must_check
+#define __must_check
+#endif
+#ifndef CONFIG_ENABLE_WARN_DEPRECATED
+#undef __deprecated
+#undef __deprecated_for_modules
+#define __deprecated
+#define __deprecated_for_modules
+#endif
+
+#ifndef __malloc
+#define __malloc
+#endif
+
+/*
+ * Allow us to avoid 'defined but not used' warnings on functions and data,
+ * as well as force them to be emitted to the assembly file.
+ *
+ * As of gcc 3.4, static functions that are not marked with attribute((used))
+ * may be elided from the assembly file.  As of gcc 3.4, static data not so
+ * marked will not be elided, but this may change in a future gcc version.
+ *
+ * NOTE: Because distributions shipped with a backported unit-at-a-time
+ * compiler in gcc 3.3, we must define __used to be __attribute__((used))
+ * for gcc >=3.3 instead of 3.4.
+ *
+ * In prior versions of gcc, such functions and data would be emitted, but
+ * would be warned about except with attribute((unused)).
+ *
+ * Mark functions that are referenced only in inline assembly as __used so
+ * the code is emitted even though it appears to be unreferenced.
+ */
+#ifndef __used
+# define __used                        /* unimplemented */
+#endif
+
+#ifndef __maybe_unused
+# define __maybe_unused                /* unimplemented */
+#endif
+
+#ifndef __always_unused
+# define __always_unused       /* unimplemented */
+#endif
+
+#ifndef noinline
+#define noinline
+#endif
+
+/*
+ * Rather then using noinline to prevent stack consumption, use
+ * noinline_for_stack instead.  For documentation reasons.
+ */
+#define noinline_for_stack noinline
+
+#ifndef __always_inline
+#define __always_inline inline
+#endif
+
+#endif /* __KERNEL__ */
+
+/*
+ * From the GCC manual:
+ *
+ * Many functions do not examine any values except their arguments,
+ * and have no effects except the return value.  Basically this is
+ * just slightly more strict class than the `pure' attribute above,
+ * since function is not allowed to read global memory.
+ *
+ * Note that a function that has pointer arguments and examines the
+ * data pointed to must _not_ be declared `const'.  Likewise, a
+ * function that calls a non-`const' function usually must not be
+ * `const'.  It does not make sense for a `const' function to return
+ * `void'.
+ */
+#ifndef __attribute_const__
+# define __attribute_const__   /* unimplemented */
+#endif
+
+#ifndef __designated_init
+# define __designated_init
+#endif
+
+#ifndef __latent_entropy
+# define __latent_entropy
+#endif
+
+#ifndef __randomize_layout
+# define __randomize_layout __designated_init
+#endif
+
+#ifndef __no_randomize_layout
+# define __no_randomize_layout
+#endif
+
+#ifndef randomized_struct_fields_start
+# define randomized_struct_fields_start
+# define randomized_struct_fields_end
+#endif
+
+/*
+ * Tell gcc if a function is cold. The compiler will assume any path
+ * directly leading to the call is unlikely.
+ */
+
+#ifndef __cold
+#define __cold
+#endif
+
+/* Simple shorthand for a section definition */
+#ifndef __section
+# define __section(S) __attribute__ ((__section__(#S)))
+#endif
+
+#ifndef __visible
+#define __visible
+#endif
+
+#ifndef __nostackprotector
+# define __nostackprotector
+#endif
+
+/*
+ * Assume alignment of return value.
+ */
+#ifndef __assume_aligned
+#define __assume_aligned(a, ...)
+#endif
+
+
+/* Are two types/vars the same type (ignoring qualifiers)? */
+#ifndef __same_type
+# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+#endif
+
+/* Is this type a native word size -- useful for atomic operations */
+#ifndef __native_word
+# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
+#endif
+
+#endif /* __LINUX_COMPILER_TYPES_H */
index 7828451e161aed19181a3b6cd6e210e6468cb190..0662a417febe34fb9e638857f13a6d52fcaf0d49 100644 (file)
@@ -50,15 +50,23 @@ static inline void complete_release_commit(struct completion *x)
        lock_commit_crosslock((struct lockdep_map *)&x->map);
 }
 
+#define init_completion_map(x, m)                                      \
+do {                                                                   \
+       lockdep_init_map_crosslock((struct lockdep_map *)&(x)->map,     \
+                       (m)->name, (m)->key, 0);                                \
+       __init_completion(x);                                           \
+} while (0)
+
 #define init_completion(x)                                             \
 do {                                                                   \
        static struct lock_class_key __key;                             \
        lockdep_init_map_crosslock((struct lockdep_map *)&(x)->map,     \
-                       "(complete)" #x,                                \
+                       "(completion)" #x,                              \
                        &__key, 0);                                     \
        __init_completion(x);                                           \
 } while (0)
 #else
+#define init_completion_map(x, m) __init_completion(x)
 #define init_completion(x) __init_completion(x)
 static inline void complete_acquire(struct completion *x) {}
 static inline void complete_release(struct completion *x) {}
@@ -68,12 +76,15 @@ static inline void complete_release_commit(struct completion *x) {}
 #ifdef CONFIG_LOCKDEP_COMPLETIONS
 #define COMPLETION_INITIALIZER(work) \
        { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait), \
-       STATIC_CROSS_LOCKDEP_MAP_INIT("(complete)" #work, &(work)) }
+       STATIC_CROSS_LOCKDEP_MAP_INIT("(completion)" #work, &(work)) }
 #else
 #define COMPLETION_INITIALIZER(work) \
        { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
 #endif
 
+#define COMPLETION_INITIALIZER_ONSTACK_MAP(work, map) \
+       (*({ init_completion_map(&(work), &(map)); &(work); }))
+
 #define COMPLETION_INITIALIZER_ONSTACK(work) \
        (*({ init_completion(&work); &work; }))
 
@@ -103,8 +114,11 @@ static inline void complete_release_commit(struct completion *x) {}
 #ifdef CONFIG_LOCKDEP
 # define DECLARE_COMPLETION_ONSTACK(work) \
        struct completion work = COMPLETION_INITIALIZER_ONSTACK(work)
+# define DECLARE_COMPLETION_ONSTACK_MAP(work, map) \
+       struct completion work = COMPLETION_INITIALIZER_ONSTACK_MAP(work, map)
 #else
 # define DECLARE_COMPLETION_ONSTACK(work) DECLARE_COMPLETION(work)
+# define DECLARE_COMPLETION_ONSTACK_MAP(work, map) DECLARE_COMPLETION(work)
 #endif
 
 /**
index 938ea8ae0ba422925b06d9e0c677eda4dba76eb4..a04ef7c15c6a9dd504a288e23d7da3d6322459e2 100644 (file)
@@ -56,27 +56,17 @@ extern void unregister_cpu(struct cpu *cpu);
 extern ssize_t arch_cpu_probe(const char *, size_t);
 extern ssize_t arch_cpu_release(const char *, size_t);
 #endif
-struct notifier_block;
-
-#define CPU_ONLINE             0x0002 /* CPU (unsigned)v is up */
-#define CPU_UP_PREPARE         0x0003 /* CPU (unsigned)v coming up */
-#define CPU_DEAD               0x0007 /* CPU (unsigned)v dead */
-#define CPU_POST_DEAD          0x0009 /* CPU (unsigned)v dead, cpu_hotplug
-                                       * lock is dropped */
-#define CPU_BROKEN             0x000B /* CPU (unsigned)v did not die properly,
-                                       * perhaps due to preemption. */
-
-/* Used for CPU hotplug events occurring while tasks are frozen due to a suspend
- * operation in progress
+
+/*
+ * These states are not related to the core CPU hotplug mechanism. They are
+ * used by various (sub)architectures to track internal state
  */
-#define CPU_TASKS_FROZEN       0x0010
-
-#define CPU_ONLINE_FROZEN      (CPU_ONLINE | CPU_TASKS_FROZEN)
-#define CPU_UP_PREPARE_FROZEN  (CPU_UP_PREPARE | CPU_TASKS_FROZEN)
-#define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN)
-#define CPU_DOWN_PREPARE_FROZEN        (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN)
-#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN)
-#define CPU_DEAD_FROZEN                (CPU_DEAD | CPU_TASKS_FROZEN)
+#define CPU_ONLINE             0x0002 /* CPU is up */
+#define CPU_UP_PREPARE         0x0003 /* CPU coming up */
+#define CPU_DEAD               0x0007 /* CPU dead */
+#define CPU_DEAD_FROZEN                0x0008 /* CPU timed out on unplug */
+#define CPU_POST_DEAD          0x0009 /* CPU successfully unplugged */
+#define CPU_BROKEN             0x000B /* CPU did not die properly */
 
 #ifdef CONFIG_SMP
 extern bool cpuhp_tasks_frozen;
index 537ff842ff733290252c795b2a8261b82944fd94..28734ee185a7d4baf3517550a44560621be08a51 100644 (file)
@@ -919,6 +919,9 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy)
 
 extern unsigned int arch_freq_get_on_cpu(int cpu);
 
+extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
+                               unsigned long max_freq);
+
 /* the following are really really optional */
 extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
 extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
index 2477a5cb5bd54a95423b46ddb39e3555ed7b8802..ec32c4c5eb30b405fd3b551933f83343e735292e 100644 (file)
@@ -99,6 +99,7 @@ enum cpuhp_state {
        CPUHP_AP_IRQ_HIP04_STARTING,
        CPUHP_AP_IRQ_ARMADA_XP_STARTING,
        CPUHP_AP_IRQ_BCM2836_STARTING,
+       CPUHP_AP_IRQ_MIPS_GIC_STARTING,
        CPUHP_AP_ARM_MVEBU_COHERENCY,
        CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
        CPUHP_AP_PERF_X86_STARTING,
index 8d3125c493b2322478ccca401d932797dec34850..75b5651944378eccca4fbe999444cfe923e58ff8 100644 (file)
@@ -131,6 +131,11 @@ static inline unsigned int cpumask_first(const struct cpumask *srcp)
        return 0;
 }
 
+static inline unsigned int cpumask_last(const struct cpumask *srcp)
+{
+       return 0;
+}
+
 /* Valid inputs for n are -1 and 0. */
 static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
 {
@@ -179,6 +184,17 @@ static inline unsigned int cpumask_first(const struct cpumask *srcp)
        return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits);
 }
 
+/**
+ * cpumask_last - get the last CPU in a cpumask
+ * @srcp:      - the cpumask pointer
+ *
+ * Returns     >= nr_cpumask_bits if no CPUs set.
+ */
+static inline unsigned int cpumask_last(const struct cpumask *srcp)
+{
+       return find_last_bit(cpumask_bits(srcp), nr_cpumask_bits);
+}
+
 unsigned int cpumask_next(int n, const struct cpumask *srcp);
 
 /**
index f05a659cdf348a0f2efa2f11b1a932a8f3181482..65cd8ab60b7a902bb1f1d36073170fe1040a13dc 100644 (file)
@@ -520,7 +520,7 @@ static inline struct inode *d_inode(const struct dentry *dentry)
 }
 
 /**
- * d_inode_rcu - Get the actual inode of this dentry with ACCESS_ONCE()
+ * d_inode_rcu - Get the actual inode of this dentry with READ_ONCE()
  * @dentry: The dentry to query
  *
  * This is the helper normal filesystems should use to get at their own inodes
@@ -528,7 +528,7 @@ static inline struct inode *d_inode(const struct dentry *dentry)
  */
 static inline struct inode *d_inode_rcu(const struct dentry *dentry)
 {
-       return ACCESS_ONCE(dentry->d_inode);
+       return READ_ONCE(dentry->d_inode);
 }
 
 /**
index 597294e0cc409cf0bbfeb13aefeb13dccc08d3ea..3aae5b3af87cf0436d855ff4a355fa1c9b534ce4 100644 (file)
 
 #define DEVFREQ_NAME_LEN 16
 
+/* DEVFREQ governor name */
+#define DEVFREQ_GOV_SIMPLE_ONDEMAND    "simple_ondemand"
+#define DEVFREQ_GOV_PERFORMANCE                "performance"
+#define DEVFREQ_GOV_POWERSAVE          "powersave"
+#define DEVFREQ_GOV_USERSPACE          "userspace"
+#define DEVFREQ_GOV_PASSIVE            "passive"
+
 /* DEVFREQ notifier interface */
 #define DEVFREQ_TRANSITION_NOTIFIER    (0)
 
@@ -84,8 +91,9 @@ struct devfreq_dev_status {
  *                     from devfreq_remove_device() call. If the user
  *                     has registered devfreq->nb at a notifier-head,
  *                     this is the time to unregister it.
- * @freq_table:        Optional list of frequencies to support statistics.
- * @max_state: The size of freq_table.
+ * @freq_table:                Optional list of frequencies to support statistics
+ *                     and freq_table must be generated in ascending order.
+ * @max_state:         The size of freq_table.
  */
 struct devfreq_dev_profile {
        unsigned long initial_freq;
@@ -120,6 +128,8 @@ struct devfreq_dev_profile {
  *             touch this.
  * @min_freq:  Limit minimum frequency requested by user (0: none)
  * @max_freq:  Limit maximum frequency requested by user (0: none)
+ * @scaling_min_freq:  Limit minimum frequency requested by OPP interface
+ * @scaling_max_freq:  Limit maximum frequency requested by OPP interface
  * @stop_polling:       devfreq polling status of a device.
  * @total_trans:       Number of devfreq transitions
  * @trans_table:       Statistics of devfreq transitions
@@ -153,6 +163,8 @@ struct devfreq {
 
        unsigned long min_freq;
        unsigned long max_freq;
+       unsigned long scaling_min_freq;
+       unsigned long scaling_max_freq;
        bool stop_polling;
 
        /* information for device frequency transition */
index 66fe271c2544d5cf861e1e5c58e23a0793ba1ed6..fb9451599aca948082a7a194556a7f5272f05115 100644 (file)
@@ -370,9 +370,6 @@ int subsys_virtual_register(struct bus_type *subsys,
  * @devnode:   Callback to provide the devtmpfs.
  * @class_release: Called to release this class.
  * @dev_release: Called to release the device.
- * @suspend:   Used to put the device to sleep mode, usually to a low power
- *             state.
- * @resume:    Used to bring the device from the sleep mode.
  * @shutdown_pre: Called at shut-down time before driver shutdown.
  * @ns_type:   Callbacks so sysfs can detemine namespaces.
  * @namespace: Namespace of the device belongs to this class.
@@ -400,8 +397,6 @@ struct class {
        void (*class_release)(struct class *class);
        void (*dev_release)(struct device *dev);
 
-       int (*suspend)(struct device *dev, pm_message_t state);
-       int (*resume)(struct device *dev);
        int (*shutdown_pre)(struct device *dev);
 
        const struct kobj_ns_type_operations *ns_type;
@@ -1075,6 +1070,16 @@ static inline void dev_pm_syscore_device(struct device *dev, bool val)
 #endif
 }
 
+static inline void dev_pm_set_driver_flags(struct device *dev, u32 flags)
+{
+       dev->power.driver_flags = flags;
+}
+
+static inline bool dev_pm_test_driver_flags(struct device *dev, u32 flags)
+{
+       return !!(dev->power.driver_flags & flags);
+}
+
 static inline void device_lock(struct device *dev)
 {
        mutex_lock(&dev->mutex);
index 34c0a5464c743c57f651c4563e465659a56a4534..023eae69398c4c393ea18f698b4957c7ee7fbaf1 100644 (file)
@@ -89,7 +89,7 @@ static inline void dql_queued(struct dql *dql, unsigned int count)
 /* Returns how many objects can be queued, < 0 indicates over limit. */
 static inline int dql_avail(const struct dql *dql)
 {
-       return ACCESS_ONCE(dql->adj_limit) - ACCESS_ONCE(dql->num_queued);
+       return READ_ONCE(dql->adj_limit) - READ_ONCE(dql->num_queued);
 }
 
 /* Record number of completed objects and recalculate the limit. */
index 3995df1d068f66b6c1574312b8740d35e2ad0de5..21f5aa0b217f3c0ce3c04a7d459f7a2e44e93076 100644 (file)
@@ -182,7 +182,7 @@ static inline void freezable_schedule_unsafe(void)
 }
 
 /*
- * Like freezable_schedule_timeout(), but should not block the freezer.  Do not
+ * Like schedule_timeout(), but should not block the freezer.  Do not
  * call this with locks held.
  */
 static inline long freezable_schedule_timeout(long timeout)
index 885266aae2d7d57615db4125884abb813066590f..e1f75a3b4af5be684d694a3c10439ed12ff69c26 100644 (file)
@@ -2793,6 +2793,7 @@ extern int do_pipe_flags(int *, int);
        id(KEXEC_IMAGE, kexec-image)            \
        id(KEXEC_INITRAMFS, kexec-initramfs)    \
        id(POLICY, security-policy)             \
+       id(X509_CERTIFICATE, x509-certificate)  \
        id(MAX_ID, )
 
 #define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
index b96dd4e1e6630997cbcea3f58c5dc34f0a1ed674..ecc2928e8046673b1933b8f85d01b83785176f6d 100644 (file)
@@ -31,7 +31,7 @@ extern wait_queue_head_t genl_sk_destructing_waitq;
  * @p: The pointer to read, prior to dereferencing
  *
  * Return the value of the specified RCU-protected pointer, but omit
- * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because
+ * both the smp_read_barrier_depends() and the READ_ONCE(), because
  * caller holds genl mutex.
  */
 #define genl_dereference(p)                                    \
index 44790523057f0380b1254458a20ca658f17a3305..eaefb7a62f83707a9493f664c232f3514d2db880 100644 (file)
@@ -207,6 +207,7 @@ struct gendisk {
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
        int node_id;
        struct badblocks *bb;
+       struct lockdep_map lockdep_map;
 };
 
 static inline struct gendisk *part_to_disk(struct hd_struct *part)
@@ -591,8 +592,7 @@ extern void __delete_partition(struct percpu_ref *);
 extern void delete_partition(struct gendisk *, int);
 extern void printk_all_partitions(void);
 
-extern struct gendisk *alloc_disk_node(int minors, int node_id);
-extern struct gendisk *alloc_disk(int minors);
+extern struct gendisk *__alloc_disk_node(int minors, int node_id);
 extern struct kobject *get_disk(struct gendisk *disk);
 extern void put_disk(struct gendisk *disk);
 extern void blk_register_region(dev_t devt, unsigned long range,
@@ -616,6 +616,24 @@ extern ssize_t part_fail_store(struct device *dev,
                               const char *buf, size_t count);
 #endif /* CONFIG_FAIL_MAKE_REQUEST */
 
+#define alloc_disk_node(minors, node_id)                               \
+({                                                                     \
+       static struct lock_class_key __key;                             \
+       const char *__name;                                             \
+       struct gendisk *__disk;                                         \
+                                                                       \
+       __name = "(gendisk_completion)"#minors"("#node_id")";           \
+                                                                       \
+       __disk = __alloc_disk_node(minors, node_id);                    \
+                                                                       \
+       if (__disk)                                                     \
+               lockdep_init_map(&__disk->lockdep_map, __name, &__key, 0); \
+                                                                       \
+       __disk;                                                         \
+})
+
+#define alloc_disk(minors) alloc_disk_node(minors, NUMA_NO_NODE)
+
 static inline int hd_ref_init(struct hd_struct *part)
 {
        if (percpu_ref_init(&part->ref, __delete_partition, 0,
diff --git a/include/linux/gpio-fan.h b/include/linux/gpio-fan.h
deleted file mode 100644 (file)
index 0966591..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * include/linux/gpio-fan.h
- *
- * Platform data structure for GPIO fan driver
- *
- * 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.
- */
-
-#ifndef __LINUX_GPIO_FAN_H
-#define __LINUX_GPIO_FAN_H
-
-struct gpio_fan_alarm {
-       unsigned        gpio;
-       unsigned        active_low;
-};
-
-struct gpio_fan_speed {
-       int rpm;
-       int ctrl_val;
-};
-
-struct gpio_fan_platform_data {
-       int                     num_ctrl;
-       unsigned                *ctrl;  /* fan control GPIOs. */
-       struct gpio_fan_alarm   *alarm; /* fan alarm GPIO. */
-       /*
-        * Speed conversion array: rpm from/to GPIO bit field.
-        * This array _must_ be sorted in ascending rpm order.
-        */
-       int                     num_speed;
-       struct gpio_fan_speed   *speed;
-};
-
-#endif /* __LINUX_GPIO_FAN_H */
index 87067d23a48b898a2d9e60c51ee4a5d2196f6c62..a8a126259bc4c8e8590e5ef29793787de92f8d8c 100644 (file)
@@ -222,7 +222,7 @@ extern struct page *huge_zero_page;
 
 static inline bool is_huge_zero_page(struct page *page)
 {
-       return ACCESS_ONCE(huge_zero_page) == page;
+       return READ_ONCE(huge_zero_page) == page;
 }
 
 static inline bool is_huge_zero_pmd(pmd_t pmd)
index b4054fd5b6f66fc5695585b0f38b121462d02620..b19563f9a8ebb9c58e115b79fecde5a0167ba0e0 100644 (file)
@@ -7,8 +7,12 @@
  *             Juergen Gross <jgross@suse.com>
  */
 
-#ifdef CONFIG_HYPERVISOR_GUEST
-#include <asm/hypervisor.h>
+#ifdef CONFIG_X86
+#include <asm/x86_init.h>
+static inline void hypervisor_pin_vcpu(int cpu)
+{
+       x86_platform.hyper.pin_vcpu(cpu);
+}
 #else
 static inline void hypervisor_pin_vcpu(int cpu)
 {
index 70db3af045417d7077fa2aa2fce15990f7b08547..771989d25ef882fd91cec3744e605eea1e96cbd5 100644 (file)
@@ -1212,7 +1212,7 @@ extern int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout);
 
 extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
 
-extern void ide_timer_expiry(unsigned long);
+extern void ide_timer_expiry(struct timer_list *t);
 extern irqreturn_t ide_intr(int irq, void *dev_id);
 extern void do_ide_request(struct request_queue *);
 extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq);
index 30294603526f91060c6ab776c09c03ee156b9b55..d95cae09dea0873a0cb119e63f5c3d6d7c73d823 100644 (file)
@@ -247,7 +247,7 @@ static inline struct team_port *team_get_port_by_index(struct team *team,
 
 static inline int team_num_to_port_index(struct team *team, unsigned int num)
 {
-       int en_port_count = ACCESS_ONCE(team->en_port_count);
+       int en_port_count = READ_ONCE(team->en_port_count);
 
        if (unlikely(!en_port_count))
                return 0;
index 83c8d6530f0f54ac308bd34424795a05e7d48df4..93b4183cf53d4ed45491edf144eec30a5ea8015e 100644 (file)
@@ -271,11 +271,14 @@ extern int
 walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
                void *arg, int (*func)(unsigned long, unsigned long, void *));
 extern int
+walk_mem_res(u64 start, u64 end, void *arg,
+            int (*func)(struct resource *, void *));
+extern int
 walk_system_ram_res(u64 start, u64 end, void *arg,
-                   int (*func)(u64, u64, void *));
+                   int (*func)(struct resource *, void *));
 extern int
 walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, u64 end,
-                   void *arg, int (*func)(u64, u64, void *));
+                   void *arg, int (*func)(struct resource *, void *));
 
 /* True if any part of r1 overlaps r2 */
 static inline bool resource_overlaps(struct resource *r1, struct resource *r2)
index 2cdd7480989962c69d8e7946ac8cf0cb76aa53e5..627efac73e6dce046d6c4d5bdab683ae13bbed5f 100644 (file)
@@ -3,6 +3,7 @@
 #define IOPRIO_H
 
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/iocontext.h>
 
 /*
@@ -63,7 +64,7 @@ static inline int task_nice_ioclass(struct task_struct *task)
 {
        if (task->policy == SCHED_IDLE)
                return IOPRIO_CLASS_IDLE;
-       else if (task->policy == SCHED_FIFO || task->policy == SCHED_RR)
+       else if (task_is_realtime(task))
                return IOPRIO_CLASS_RT;
        else
                return IOPRIO_CLASS_BE;
index 4536286cc4d24bcbb64dcc6a4db6a47f399f82d5..b01d06db9101ae73b08952ba6e11abf86c1bbb6d 100644 (file)
@@ -1114,6 +1114,28 @@ static inline u32 irq_reg_readl(struct irq_chip_generic *gc,
                return readl(gc->reg_base + reg_offset);
 }
 
+struct irq_matrix;
+struct irq_matrix *irq_alloc_matrix(unsigned int matrix_bits,
+                                   unsigned int alloc_start,
+                                   unsigned int alloc_end);
+void irq_matrix_online(struct irq_matrix *m);
+void irq_matrix_offline(struct irq_matrix *m);
+void irq_matrix_assign_system(struct irq_matrix *m, unsigned int bit, bool replace);
+int irq_matrix_reserve_managed(struct irq_matrix *m, const struct cpumask *msk);
+void irq_matrix_remove_managed(struct irq_matrix *m, const struct cpumask *msk);
+int irq_matrix_alloc_managed(struct irq_matrix *m, unsigned int cpu);
+void irq_matrix_reserve(struct irq_matrix *m);
+void irq_matrix_remove_reserved(struct irq_matrix *m);
+int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk,
+                    bool reserved, unsigned int *mapped_cpu);
+void irq_matrix_free(struct irq_matrix *m, unsigned int cpu,
+                    unsigned int bit, bool managed);
+void irq_matrix_assign(struct irq_matrix *m, unsigned int bit);
+unsigned int irq_matrix_available(struct irq_matrix *m, bool cpudown);
+unsigned int irq_matrix_allocated(struct irq_matrix *m);
+unsigned int irq_matrix_reserved(struct irq_matrix *m);
+void irq_matrix_debug_show(struct seq_file *sf, struct irq_matrix *m, int ind);
+
 /* Contrary to Linux irqs, for hardware irqs the irq number 0 is valid */
 #define INVALID_HWIRQ  (~0UL)
 irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu);
index 9270d73ea6821cbf027709596e5dd80b86bbfa29..0e81035b678f00817969cfae6c4ab6469da66a1d 100644 (file)
@@ -34,10 +34,7 @@ void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
 #define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { .func = (_f), }
 
 bool irq_work_queue(struct irq_work *work);
-
-#ifdef CONFIG_SMP
 bool irq_work_queue_on(struct irq_work *work, int cpu);
-#endif
 
 void irq_work_tick(void);
 void irq_work_sync(struct irq_work *work);
index 14b74f22d43c147f2bc8eec9ef82e2a1461a6643..c00c4c33e432e0bd7e6a1ddf2775e5a45b24fa4f 100644 (file)
@@ -68,6 +68,7 @@
 #define GICD_CTLR_ENABLE_SS_G1         (1U << 1)
 #define GICD_CTLR_ENABLE_SS_G0         (1U << 0)
 
+#define GICD_TYPER_RSS                 (1U << 26)
 #define GICD_TYPER_LPIS                        (1U << 17)
 #define GICD_TYPER_MBIS                        (1U << 16)
 
 #define ICC_CTLR_EL1_SEIS_MASK         (0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
 #define ICC_CTLR_EL1_A3V_SHIFT         15
 #define ICC_CTLR_EL1_A3V_MASK          (0x1 << ICC_CTLR_EL1_A3V_SHIFT)
+#define ICC_CTLR_EL1_RSS               (0x1 << 18)
 #define ICC_PMR_EL1_SHIFT              0
 #define ICC_PMR_EL1_MASK               (0xff << ICC_PMR_EL1_SHIFT)
 #define ICC_BPR0_EL1_SHIFT             0
 #define ICC_SGI1R_AFFINITY_2_SHIFT     32
 #define ICC_SGI1R_AFFINITY_2_MASK      (0xffULL << ICC_SGI1R_AFFINITY_2_SHIFT)
 #define ICC_SGI1R_IRQ_ROUTING_MODE_BIT 40
+#define ICC_SGI1R_RS_SHIFT             44
+#define ICC_SGI1R_RS_MASK              (0xfULL << ICC_SGI1R_RS_SHIFT)
 #define ICC_SGI1R_AFFINITY_3_SHIFT     48
 #define ICC_SGI1R_AFFINITY_3_MASK      (0xffULL << ICC_SGI1R_AFFINITY_3_SHIFT)
 
index 58a4d89aa82c022644ac371bdfa64ecedcd5ee26..447da8ca2156221749876d53c84430c62e729980 100644 (file)
 
 struct its_vpe;
 
+/*
+ * Maximum number of ITTs when GITS_TYPER.VMOVP == 0, using the
+ * ITSList mechanism to perform inter-ITS synchronization.
+ */
+#define GICv4_ITS_LIST_MAX             16
+
 /* Embedded in kvm.arch */
 struct its_vm {
        struct fwnode_handle    *fwnode;
@@ -30,6 +36,7 @@ struct its_vm {
        irq_hw_number_t         db_lpi_base;
        unsigned long           *db_bitmap;
        int                     nr_db_lpis;
+       u32                     vlpi_count[GICv4_ITS_LIST_MAX];
 };
 
 /* Embedded in kvm_vcpu.arch */
@@ -64,12 +71,14 @@ struct its_vpe {
  * @vm:                Pointer to the GICv4 notion of a VM
  * @vpe:       Pointer to the GICv4 notion of a virtual CPU (VPE)
  * @vintid:    Virtual LPI number
+ * @properties:        Priority and enable bits (as written in the prop table)
  * @db_enabled:        Is the VPE doorbell to be generated?
  */
 struct its_vlpi_map {
        struct its_vm           *vm;
        struct its_vpe          *vpe;
        u32                     vintid;
+       u8                      properties;
        bool                    db_enabled;
 };
 
index 2e3d1afeb67435734f1eda025abac349bef1c488..f19ccee7749f4305d814fc3564d12b631f065d70 100644 (file)
@@ -18,8 +18,6 @@
 #ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H
 #define __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H
 
-void omap3_init_irq(void);
-
 int omap_irq_pending(void);
 void omap_intc_save_context(void);
 void omap_intc_restore_context(void);
index b6084898d33017e01edaef49893169a26c9c0164..60e3100b0809a372258b6acc045d14d6cc86a8eb 100644 (file)
@@ -94,6 +94,7 @@ struct irq_desc {
 #endif
 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
        struct dentry           *debugfs_file;
+       const char              *dev_name;
 #endif
 #ifdef CONFIG_SPARSE_IRQ
        struct rcu_head         rcu;
index b1037dfc47e40eff76735022b7582024b6d89290..a34355d195463f93d3235283978633bf60f0b59d 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/types.h>
 #include <linux/irqhandler.h>
 #include <linux/of.h>
+#include <linux/mutex.h>
 #include <linux/radix-tree.h>
 
 struct device_node;
@@ -41,6 +42,7 @@ struct of_device_id;
 struct irq_chip;
 struct irq_data;
 struct cpumask;
+struct seq_file;
 
 /* Number of irqs reserved for a legacy isa controller */
 #define NUM_ISA_INTERRUPTS     16
@@ -105,18 +107,21 @@ struct irq_domain_ops {
        int (*xlate)(struct irq_domain *d, struct device_node *node,
                     const u32 *intspec, unsigned int intsize,
                     unsigned long *out_hwirq, unsigned int *out_type);
-
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
        /* extended V2 interfaces to support hierarchy irq_domains */
        int (*alloc)(struct irq_domain *d, unsigned int virq,
                     unsigned int nr_irqs, void *arg);
        void (*free)(struct irq_domain *d, unsigned int virq,
                     unsigned int nr_irqs);
-       void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+       int (*activate)(struct irq_domain *d, struct irq_data *irqd, bool early);
        void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
        int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
                         unsigned long *out_hwirq, unsigned int *out_type);
 #endif
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+       void (*debug_show)(struct seq_file *m, struct irq_domain *d,
+                          struct irq_data *irqd, int ind);
+#endif
 };
 
 extern struct irq_domain_ops irq_generic_chip_ops;
@@ -134,8 +139,8 @@ struct irq_domain_chip_generic;
  * @mapcount: The number of mapped interrupts
  *
  * Optional elements
- * @of_node: Pointer to device tree nodes associated with the irq_domain. Used
- *           when decoding device tree interrupt specifiers.
+ * @fwnode: Pointer to firmware node associated with the irq_domain. Pretty easy
+ *          to swap it for the of_node via the irq_domain_get_of_node accessor
  * @gc: Pointer to a list of generic chips. There is a helper function for
  *      setting up one or more generic chips for interrupt controllers
  *      drivers using the generic chip library which uses this pointer.
@@ -173,6 +178,7 @@ struct irq_domain {
        unsigned int revmap_direct_max_irq;
        unsigned int revmap_size;
        struct radix_tree_root revmap_tree;
+       struct mutex revmap_tree_mutex;
        unsigned int linear_revmap[];
 };
 
@@ -438,7 +444,7 @@ extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
                                   unsigned int nr_irqs, int node, void *arg,
                                   bool realloc, const struct cpumask *affinity);
 extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
-extern void irq_domain_activate_irq(struct irq_data *irq_data);
+extern int irq_domain_activate_irq(struct irq_data *irq_data, bool early);
 extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
 
 static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
@@ -508,8 +514,6 @@ static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
 extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain);
 
 #else  /* CONFIG_IRQ_DOMAIN_HIERARCHY */
-static inline void irq_domain_activate_irq(struct irq_data *data) { }
-static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
 static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
                        unsigned int nr_irqs, int node, void *arg)
 {
@@ -558,8 +562,6 @@ irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain)
 
 #else /* CONFIG_IRQ_DOMAIN */
 static inline void irq_dispose_mapping(unsigned int virq) { }
-static inline void irq_domain_activate_irq(struct irq_data *data) { }
-static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
 static inline struct irq_domain *irq_find_matching_fwnode(
        struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token)
 {
index 3b7675bcca645397d664ef24d6ed5449ff9f3fc4..c7b368c734af342da6a3e397c995b6859691f032 100644 (file)
@@ -82,9 +82,9 @@
 
 extern bool static_key_initialized;
 
-#define STATIC_KEY_CHECK_USE() WARN(!static_key_initialized,                 \
-                                   "%s used before call to jump_label_init", \
-                                   __func__)
+#define STATIC_KEY_CHECK_USE(key) WARN(!static_key_initialized,                      \
+                                   "%s(): static key '%pS' used before call to jump_label_init()", \
+                                   __func__, (key))
 
 #ifdef HAVE_JUMP_LABEL
 
@@ -212,13 +212,13 @@ static __always_inline bool static_key_true(struct static_key *key)
 
 static inline void static_key_slow_inc(struct static_key *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
        atomic_inc(&key->enabled);
 }
 
 static inline void static_key_slow_dec(struct static_key *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
        atomic_dec(&key->enabled);
 }
 
@@ -237,7 +237,7 @@ static inline int jump_label_apply_nops(struct module *mod)
 
 static inline void static_key_enable(struct static_key *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
 
        if (atomic_read(&key->enabled) != 0) {
                WARN_ON_ONCE(atomic_read(&key->enabled) != 1);
@@ -248,7 +248,7 @@ static inline void static_key_enable(struct static_key *key)
 
 static inline void static_key_disable(struct static_key *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
 
        if (atomic_read(&key->enabled) != 1) {
                WARN_ON_ONCE(atomic_read(&key->enabled) != 0);
index fc13ff289903700cb569f1bbfa5912e69b796455..baa8eabbaa56b7ef2c8367ee7a5c407b27cb18c8 100644 (file)
@@ -25,18 +25,18 @@ struct static_key_deferred {
 };
 static inline void static_key_slow_dec_deferred(struct static_key_deferred *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
        static_key_slow_dec(&key->key);
 }
 static inline void static_key_deferred_flush(struct static_key_deferred *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
 }
 static inline void
 jump_label_rate_limit(struct static_key_deferred *key,
                unsigned long rl)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
 }
 #endif /* HAVE_JUMP_LABEL */
 #endif /* _LINUX_JUMP_LABEL_RATELIMIT_H */
index 11dd93e4258027cac8968074a5725aeafc7ae814..708f337d780be3ee4c628fe0422e3a6752d0fb33 100644 (file)
 #define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
                         2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1)
 
+#ifndef CONFIG_64BIT
+# define KALLSYM_FMT "%08lx"
+#else
+# define KALLSYM_FMT "%016lx"
+#endif
+
 struct module;
 
 #ifdef CONFIG_KALLSYMS
@@ -46,6 +52,9 @@ extern void __print_symbol(const char *fmt, unsigned long address);
 int lookup_symbol_name(unsigned long addr, char *symname);
 int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
 
+/* How and when do we show kallsyms values? */
+extern int kallsyms_show_value(void);
+
 #else /* !CONFIG_KALLSYMS */
 
 static inline unsigned long kallsyms_lookup_name(const char *name)
@@ -104,6 +113,11 @@ static inline int lookup_symbol_attrs(unsigned long addr, unsigned long *size, u
        return -ERANGE;
 }
 
+static inline int kallsyms_show_value(void)
+{
+       return false;
+}
+
 /* Stupid that this does nothing, but I didn't create this mess. */
 #define __print_symbol(fmt, addr)
 #endif /*CONFIG_KALLSYMS*/
index 1c08c925cefbb748e0255486e30be309d70c497f..f16f6ceb387591abca37812cfe7aa4f2fc328eca 100644 (file)
@@ -160,7 +160,7 @@ struct kexec_buf {
 };
 
 int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,
-                              int (*func)(u64, u64, void *));
+                              int (*func)(struct resource *, void *));
 extern int kexec_add_buffer(struct kexec_buf *kbuf);
 int kexec_locate_mem_hole(struct kexec_buf *kbuf);
 #endif /* CONFIG_KEXEC_FILE */
index bd2684700b74cd5c97ada00a53fbea3242a15397..9440a2fc88937d463aa2990e345a08b156dd873b 100644 (file)
@@ -391,10 +391,6 @@ int register_kprobes(struct kprobe **kps, int num);
 void unregister_kprobes(struct kprobe **kps, int num);
 int setjmp_pre_handler(struct kprobe *, struct pt_regs *);
 int longjmp_break_handler(struct kprobe *, struct pt_regs *);
-int register_jprobe(struct jprobe *p);
-void unregister_jprobe(struct jprobe *p);
-int register_jprobes(struct jprobe **jps, int num);
-void unregister_jprobes(struct jprobe **jps, int num);
 void jprobe_return(void);
 unsigned long arch_deref_entry_point(void *);
 
@@ -443,20 +439,6 @@ static inline void unregister_kprobe(struct kprobe *p)
 static inline void unregister_kprobes(struct kprobe **kps, int num)
 {
 }
-static inline int register_jprobe(struct jprobe *p)
-{
-       return -ENOSYS;
-}
-static inline int register_jprobes(struct jprobe **jps, int num)
-{
-       return -ENOSYS;
-}
-static inline void unregister_jprobe(struct jprobe *p)
-{
-}
-static inline void unregister_jprobes(struct jprobe **jps, int num)
-{
-}
 static inline void jprobe_return(void)
 {
 }
@@ -486,6 +468,20 @@ static inline int enable_kprobe(struct kprobe *kp)
        return -ENOSYS;
 }
 #endif /* CONFIG_KPROBES */
+static inline int register_jprobe(struct jprobe *p)
+{
+       return -ENOSYS;
+}
+static inline int register_jprobes(struct jprobe **jps, int num)
+{
+       return -ENOSYS;
+}
+static inline void unregister_jprobe(struct jprobe *p)
+{
+}
+static inline void unregister_jprobes(struct jprobe **jps, int num)
+{
+}
 static inline int disable_kretprobe(struct kretprobe *rp)
 {
        return disable_kprobe(&rp->kp);
@@ -496,11 +492,11 @@ static inline int enable_kretprobe(struct kretprobe *rp)
 }
 static inline int disable_jprobe(struct jprobe *jp)
 {
-       return disable_kprobe(&jp->kp);
+       return -ENOSYS;
 }
 static inline int enable_jprobe(struct jprobe *jp)
 {
-       return enable_kprobe(&jp->kp);
+       return -ENOSYS;
 }
 
 #ifndef CONFIG_KPROBES
index 4e26609c77d4136cd0ecb096ac3616cebf4e0a6e..86d53a3cb497ff0d587952f4b9073da2f71e98a2 100644 (file)
@@ -76,7 +76,7 @@ extern int tsk_fork_get_node(struct task_struct *tsk);
  */
 struct kthread_work;
 typedef void (*kthread_work_func_t)(struct kthread_work *work);
-void kthread_delayed_work_timer_fn(unsigned long __data);
+void kthread_delayed_work_timer_fn(struct timer_list *t);
 
 enum {
        KTW_FREEZABLE           = 1 << 0,       /* freeze during suspend */
@@ -117,8 +117,8 @@ struct kthread_delayed_work {
 
 #define KTHREAD_DELAYED_WORK_INIT(dwork, fn) {                         \
        .work = KTHREAD_WORK_INIT((dwork).work, (fn)),                  \
-       .timer = __TIMER_INITIALIZER(kthread_delayed_work_timer_fn,     \
-                                    0, (unsigned long)&(dwork),        \
+       .timer = __TIMER_INITIALIZER((TIMER_FUNC_TYPE)kthread_delayed_work_timer_fn,\
+                                    (TIMER_DATA_TYPE)&(dwork.timer),   \
                                     TIMER_IRQSAFE),                    \
        }
 
@@ -165,8 +165,8 @@ extern void __kthread_init_worker(struct kthread_worker *worker,
        do {                                                            \
                kthread_init_work(&(dwork)->work, (fn));                \
                __setup_timer(&(dwork)->timer,                          \
-                             kthread_delayed_work_timer_fn,            \
-                             (unsigned long)(dwork),                   \
+                             (TIMER_FUNC_TYPE)kthread_delayed_work_timer_fn,\
+                             (TIMER_DATA_TYPE)&(dwork)->timer,         \
                              TIMER_IRQSAFE);                           \
        } while (0)
 
index 0c8bd45c820615eeaa3d50370f598c7f567ce51d..5b9fddbaac4166b11121f75a3f3b4db7af1aac4c 100644 (file)
@@ -270,5 +270,6 @@ static inline ktime_t ms_to_ktime(u64 ms)
 }
 
 # include <linux/timekeeping.h>
+# include <linux/timekeeping32.h>
 
 #endif
index 2e6f90bd52aa6254a1291abe7082269bdf3003b1..f68db9e450eb3f7ed00e30855a3b183c42d41b7f 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef _LINUX_LINKAGE_H
 #define _LINUX_LINKAGE_H
 
-#include <linux/compiler.h>
+#include <linux/compiler_types.h>
 #include <linux/stringify.h>
 #include <linux/export.h>
 #include <asm/linkage.h>
index 1957635e6d5f7b677896c50921627aff79445cfb..85abc2915e8d5d545e7d499ea57099201c57b21d 100644 (file)
@@ -198,7 +198,7 @@ static inline void init_llist_head(struct llist_head *list)
  */
 static inline bool llist_empty(const struct llist_head *head)
 {
-       return ACCESS_ONCE(head->first) == NULL;
+       return READ_ONCE(head->first) == NULL;
 }
 
 static inline struct llist_node *llist_next(struct llist_node *node)
index f301d31b473c789b9f51038b9d9ac2dddace38f5..a842551fe0449a38df5510a39d3fdc4760caa0ee 100644 (file)
@@ -528,6 +528,11 @@ static inline void lockdep_on(void)
  */
 struct lock_class_key { };
 
+/*
+ * The lockdep_map takes no space if lockdep is disabled:
+ */
+struct lockdep_map { };
+
 #define lockdep_depth(tsk)     (0)
 
 #define lockdep_is_held_type(l, r)             (1)
@@ -720,9 +725,24 @@ do {                                                                       \
        lock_acquire(&(lock)->dep_map, 0, 0, 1, 1, NULL, _THIS_IP_);    \
        lock_release(&(lock)->dep_map, 0, _THIS_IP_);                   \
 } while (0)
+
+#define lockdep_assert_irqs_enabled()  do {                            \
+               WARN_ONCE(debug_locks && !current->lockdep_recursion && \
+                         !current->hardirqs_enabled,                   \
+                         "IRQs not enabled as expected\n");            \
+       } while (0)
+
+#define lockdep_assert_irqs_disabled() do {                            \
+               WARN_ONCE(debug_locks && !current->lockdep_recursion && \
+                         current->hardirqs_enabled,                    \
+                         "IRQs not disabled as expected\n");           \
+       } while (0)
+
 #else
 # define might_lock(lock) do { } while (0)
 # define might_lock_read(lock) do { } while (0)
+# define lockdep_assert_irqs_enabled() do { } while (0)
+# define lockdep_assert_irqs_disabled() do { } while (0)
 #endif
 
 #ifdef CONFIG_LOCKDEP
index c373295f359fa582859962bbf3295dbd936111ad..41a1ae01099397dc0e6553bbb60155df33448ef4 100644 (file)
@@ -37,19 +37,23 @@ int __ilog2_u64(u64 n)
 }
 #endif
 
-/*
- *  Determine whether some value is a power of two, where zero is
+/**
+ * is_power_of_2() - check if a value is a power of two
+ * @n: the value to check
+ *
+ * Determine whether some value is a power of two, where zero is
  * *not* considered a power of two.
+ * Return: true if @n is a power of 2, otherwise false.
  */
-
 static inline __attribute__((const))
 bool is_power_of_2(unsigned long n)
 {
        return (n != 0 && ((n & (n - 1)) == 0));
 }
 
-/*
- * round up to nearest power of two
+/**
+ * __roundup_pow_of_two() - round up to nearest power of two
+ * @n: value to round up
  */
 static inline __attribute__((const))
 unsigned long __roundup_pow_of_two(unsigned long n)
@@ -57,8 +61,9 @@ unsigned long __roundup_pow_of_two(unsigned long n)
        return 1UL << fls_long(n - 1);
 }
 
-/*
- * round down to nearest power of two
+/**
+ * __rounddown_pow_of_two() - round down to nearest power of two
+ * @n: value to round down
  */
 static inline __attribute__((const))
 unsigned long __rounddown_pow_of_two(unsigned long n)
@@ -67,12 +72,12 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
 }
 
 /**
- * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
- * @n - parameter
+ * ilog2 - log base 2 of 32-bit or a 64-bit unsigned value
+ * @n: parameter
  *
  * constant-capable log of base 2 calculation
  * - this can be used to initialise global variables from constant data, hence
- *   the massive ternary operator construction
+ * the massive ternary operator construction
  *
  * selects the appropriately-sized optimised version depending on sizeof(n)
  */
@@ -150,7 +155,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
 
 /**
  * roundup_pow_of_two - round the given value up to nearest power of two
- * @n - parameter
+ * @n: parameter
  *
  * round the given value up to the nearest power of two
  * - the result is undefined when n == 0
@@ -167,7 +172,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
 
 /**
  * rounddown_pow_of_two - round the given value down to nearest power of two
- * @n - parameter
+ * @n: parameter
  *
  * round the given value down to the nearest power of two
  * - the result is undefined when n == 0
@@ -180,6 +185,12 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
        __rounddown_pow_of_two(n)               \
  )
 
+static inline __attribute_const__
+int __order_base_2(unsigned long n)
+{
+       return n > 1 ? ilog2(n - 1) + 1 : 0;
+}
+
 /**
  * order_base_2 - calculate the (rounded up) base 2 order of the argument
  * @n: parameter
@@ -193,13 +204,6 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
  *  ob2(5) = 3
  *  ... and so on.
  */
-
-static inline __attribute_const__
-int __order_base_2(unsigned long n)
-{
-       return n > 1 ? ilog2(n - 1) + 1 : 0;
-}
-
 #define order_base_2(n)                                \
 (                                              \
        __builtin_constant_p(n) ? (             \
index 082de345b73ce0c02d5a3466336bb97bd408894f..837f2f2d1d341ff56549d6b134149e1e92a49a69 100644 (file)
 
 /**
  * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
+ * @remainder: pointer to unsigned 32bit remainder
+ *
+ * Return: sets ``*remainder``, then returns dividend / divisor
  *
  * This is commonly provided by 32bit archs to provide an optimized 64bit
  * divide.
@@ -24,6 +29,11 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
 
 /**
  * div_s64_rem - signed 64bit divide with 32bit divisor with remainder
+ * @dividend: signed 64bit dividend
+ * @divisor: signed 32bit divisor
+ * @remainder: pointer to signed 32bit remainder
+ *
+ * Return: sets ``*remainder``, then returns dividend / divisor
  */
 static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
 {
@@ -33,6 +43,11 @@ static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
 
 /**
  * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 64bit divisor
+ * @remainder: pointer to unsigned 64bit remainder
+ *
+ * Return: sets ``*remainder``, then returns dividend / divisor
  */
 static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
 {
@@ -42,6 +57,10 @@ static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
 
 /**
  * div64_u64 - unsigned 64bit divide with 64bit divisor
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 64bit divisor
+ *
+ * Return: dividend / divisor
  */
 static inline u64 div64_u64(u64 dividend, u64 divisor)
 {
@@ -50,6 +69,10 @@ static inline u64 div64_u64(u64 dividend, u64 divisor)
 
 /**
  * div64_s64 - signed 64bit divide with 64bit divisor
+ * @dividend: signed 64bit dividend
+ * @divisor: signed 64bit divisor
+ *
+ * Return: dividend / divisor
  */
 static inline s64 div64_s64(s64 dividend, s64 divisor)
 {
@@ -89,6 +112,8 @@ extern s64 div64_s64(s64 dividend, s64 divisor);
 
 /**
  * div_u64 - unsigned 64bit divide with 32bit divisor
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
  *
  * This is the most common 64bit divide and should be used if possible,
  * as many 32bit archs can optimize this variant better than a full 64bit
@@ -104,6 +129,8 @@ static inline u64 div_u64(u64 dividend, u32 divisor)
 
 /**
  * div_s64 - signed 64bit divide with 32bit divisor
+ * @dividend: signed 64bit dividend
+ * @divisor: signed 32bit divisor
  */
 #ifndef div_s64
 static inline s64 div_s64(s64 dividend, s32 divisor)
index 265a9cd21cb418e4aae78bf6bc476ec463933670..b310a9c181131e095d7db49e7a628a889f072945 100644 (file)
 
 #define sme_me_mask    0ULL
 
+static inline bool sme_active(void) { return false; }
+static inline bool sev_active(void) { return false; }
+
 #endif /* CONFIG_ARCH_HAS_MEM_ENCRYPT */
 
-static inline bool sme_active(void)
+static inline bool mem_encrypt_active(void)
 {
-       return !!sme_me_mask;
+       return sme_me_mask;
 }
 
 static inline u64 sme_get_me_mask(void)
index e9c908c4fba8a22418f6884081af5661b9144a56..78dc85365c4f8309ea1bd5b50bb1d6bc4ab9984a 100644 (file)
@@ -131,6 +131,9 @@ enum axp20x_variants {
 #define AXP803_DCDC6_V_OUT             0x25
 #define AXP803_DCDC_FREQ_CTRL          0x3b
 
+/* Other DCDC regulator control registers are the same as AXP803 */
+#define AXP813_DCDC7_V_OUT             0x26
+
 /* Interrupt */
 #define AXP152_IRQ1_EN                 0x40
 #define AXP152_IRQ2_EN                 0x41
index 116816fb9110d20c0e86720a63a2a71b8c7615bf..7815d8db7eca5a6b8f3b4fc7411f200d55b0e19c 100644 (file)
 #define DCM_DRP_RD_DATA_H              0xFC29
 #define SD_VPCLK0_CTL                  0xFC2A
 #define SD_VPCLK1_CTL                  0xFC2B
+#define   PHASE_SELECT_MASK            0x1F
 #define SD_DCMPS0_CTL                  0xFC2C
 #define SD_DCMPS1_CTL                  0xFC2D
 #define SD_VPTX_CTL                    SD_VPCLK0_CTL
index bccd2d68b1e306c741ef295f9fe73d2d9e830086..f069c518c0ed64346c7abf2f8bc534ce5acba60e 100644 (file)
@@ -245,24 +245,6 @@ enum tps65218_irqs {
        TPS65218_INVALID4_IRQ,
 };
 
-/**
- * struct tps_info - packages regulator constraints
- * @id:                        Id of the regulator
- * @name:              Voltage regulator name
- * @min_uV:            minimum micro volts
- * @max_uV:            minimum micro volts
- * @strobe:            sequencing strobe value for the regulator
- *
- * This data is used to check the regualtor voltage limits while setting.
- */
-struct tps_info {
-       int id;
-       const char *name;
-       int min_uV;
-       int max_uV;
-       int strobe;
-};
-
 /**
  * struct tps65218 - tps65218 sub-driver chip access routines
  *
@@ -280,7 +262,6 @@ struct tps65218 {
        u32 irq_mask;
        struct regmap_irq_chip_data *irq_data;
        struct regulator_desc desc[TPS65218_NUM_REGULATOR];
-       struct tps_info *info[TPS65218_NUM_REGULATOR];
        struct regmap *regmap;
        u8 *strobes;
 };
index 43edf659453b2692a618d3d093d1f00262a6e715..91b46f99b4d2189291ddc47ba47690ba79db6251 100644 (file)
@@ -2496,7 +2496,7 @@ void vmemmap_populate_print_last(void);
 void vmemmap_free(unsigned long start, unsigned long end);
 #endif
 void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
-                                 unsigned long size);
+                                 unsigned long nr_pages);
 
 enum mf_flags {
        MF_COUNT_INCREASED = 1 << 0,
index 9a43763a68adb3e998ec942300688f99e065489b..e7743eca1021969642c1bb04e2c41676c427d013 100644 (file)
@@ -255,6 +255,10 @@ struct mmc_supply {
        struct regulator *vqmmc;        /* Optional Vccq supply */
 };
 
+struct mmc_ctx {
+       struct task_struct *task;
+};
+
 struct mmc_host {
        struct device           *parent;
        struct device           class_dev;
@@ -350,6 +354,8 @@ struct mmc_host {
 #define MMC_CAP2_CQE           (1 << 23)       /* Has eMMC command queue engine */
 #define MMC_CAP2_CQE_DCMD      (1 << 24)       /* CQE can issue a direct command */
 
+       int                     fixed_drv_type; /* fixed driver type for non-removable media */
+
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
        /* host specific block data */
@@ -388,8 +394,9 @@ struct mmc_host {
        struct mmc_card         *card;          /* device attached to this host */
 
        wait_queue_head_t       wq;
-       struct task_struct      *claimer;       /* task that has host claimed */
+       struct mmc_ctx          *claimer;       /* context that has host claimed */
        int                     claim_cnt;      /* "claim" nesting count */
+       struct mmc_ctx          default_ctx;    /* default context */
 
        struct delayed_work     detect;
        int                     detect_change;  /* card detect flag */
@@ -469,6 +476,8 @@ void mmc_detect_change(struct mmc_host *, unsigned long delay);
 void mmc_request_done(struct mmc_host *, struct mmc_request *);
 void mmc_command_done(struct mmc_host *host, struct mmc_request *mrq);
 
+void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq);
+
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
        host->ops->enable_sdio_irq(host, 0);
index 36f986d4a59a3424f2e979a7a319088accc5e681..1d42872d22f36c8dfb1f9a67d7881820d2521e14 100644 (file)
@@ -15,7 +15,4 @@ struct sdhci_pci_data {
 
 extern struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev,
                                int slotno);
-
-extern int sdhci_pci_spt_drive_strength;
-
 #endif
index c9c4a81b976711531125939340086e79a7de3ba1..a507f43ad221d72d3b899a3ff464be0cc084aa10 100644 (file)
@@ -1151,13 +1151,17 @@ struct mem_section {
 #define SECTION_ROOT_MASK      (SECTIONS_PER_ROOT - 1)
 
 #ifdef CONFIG_SPARSEMEM_EXTREME
-extern struct mem_section *mem_section[NR_SECTION_ROOTS];
+extern struct mem_section **mem_section;
 #else
 extern struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT];
 #endif
 
 static inline struct mem_section *__nr_to_section(unsigned long nr)
 {
+#ifdef CONFIG_SPARSEMEM_EXTREME
+       if (!mem_section)
+               return NULL;
+#endif
        if (!mem_section[SECTION_NR_TO_ROOT(nr)])
                return NULL;
        return &mem_section[SECTION_NR_TO_ROOT(nr)][nr & SECTION_ROOT_MASK];
index fe5aa3736707294a5a4b6f20ea83be79d91dc9c0..c69b49abe8775417587387a8d7def5497e476fc8 100644 (file)
@@ -639,6 +639,8 @@ static inline bool is_livepatch_module(struct module *mod)
 }
 #endif /* CONFIG_LIVEPATCH */
 
+bool is_module_sig_enforced(void);
+
 #else /* !CONFIG_MODULES... */
 
 static inline struct module *__module_address(unsigned long addr)
@@ -753,6 +755,11 @@ static inline bool module_requested_async_probing(struct module *module)
        return false;
 }
 
+static inline bool is_module_sig_enforced(void)
+{
+       return false;
+}
+
 #endif /* CONFIG_MODULES */
 
 #ifdef CONFIG_SYSFS
index cdd069cf9ed83acc413be8a534a04da08c290cf6..1f1bbb5b46794af1efc19fb73897c1b3e000bdd2 100644 (file)
@@ -284,6 +284,11 @@ enum {
        MSI_FLAG_PCI_MSIX               = (1 << 3),
        /* Needs early activate, required for PCI */
        MSI_FLAG_ACTIVATE_EARLY         = (1 << 4),
+       /*
+        * Must reactivate when irq is started even when
+        * MSI_FLAG_ACTIVATE_EARLY has been set.
+        */
+       MSI_FLAG_MUST_REACTIVATE        = (1 << 5),
 };
 
 int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
index 414a5e769fde98ba36f0bbe0b90505ffac2445ee..495ba4dd9da5bf419b140d540db6e6cefb30dfd4 100644 (file)
@@ -67,7 +67,7 @@ static inline bool lockdep_nfnl_is_held(__u8 subsys_id)
  * @ss: The nfnetlink subsystem ID
  *
  * Return the value of the specified RCU-protected pointer, but omit
- * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because
+ * both the smp_read_barrier_depends() and the READ_ONCE(), because
  * caller holds the NFNL subsystem mutex.
  */
 #define nfnl_dereference(p, ss)                                        \
index 58e3c64c6b4926b5f8734db2f2589780e66d3bc4..397607a0c0ebef2969a3c4ea81893be860c8aacc 100644 (file)
@@ -225,6 +225,7 @@ struct parport {
        struct pardevice *waittail;
 
        struct list_head list;
+       struct timer_list timer;
        unsigned int flags;
 
        void *sysctl_table;
index d16a7c037ec0bca6176aaf0212d73af45387c7e3..e920a2527797e0bbd4ff67d7903dae7a0cc8d64b 100644 (file)
@@ -206,13 +206,8 @@ enum pci_dev_flags {
        PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT = (__force pci_dev_flags_t) (1 << 9),
        /* Do not use FLR even if device advertises PCI_AF_CAP */
        PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
-       /*
-        * Resume before calling the driver's system suspend hooks, disabling
-        * the direct_complete optimization.
-        */
-       PCI_DEV_FLAGS_NEEDS_RESUME = (__force pci_dev_flags_t) (1 << 11),
        /* Don't use Relaxed Ordering for TLPs directed at this device */
-       PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 12),
+       PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
 };
 
 enum pci_irq_reroute_variant {
index 8f16299ca0683f426e9a1dfb21ab68b244655166..2d2096ba1cfeca2672b8c368cb49975985d67363 100644 (file)
 #define DEFINE_PER_CPU_READ_MOSTLY(type, name)                         \
        DEFINE_PER_CPU_SECTION(type, name, "..read_mostly")
 
+/*
+ * Declaration/definition used for per-CPU variables that should be accessed
+ * as decrypted when memory encryption is enabled in the guest.
+ */
+#if defined(CONFIG_VIRTUALIZATION) && defined(CONFIG_AMD_MEM_ENCRYPT)
+
+#define DECLARE_PER_CPU_DECRYPTED(type, name)                          \
+       DECLARE_PER_CPU_SECTION(type, name, "..decrypted")
+
+#define DEFINE_PER_CPU_DECRYPTED(type, name)                           \
+       DEFINE_PER_CPU_SECTION(type, name, "..decrypted")
+#else
+#define DEFINE_PER_CPU_DECRYPTED(type, name)   DEFINE_PER_CPU(type, name)
+#endif
+
 /*
  * Intermodule exports for per-CPU variables.  sparse forgets about
  * address space across EXPORT_SYMBOL(), change EXPORT_SYMBOL() to
index 8e22f24ded6a3ad0e2accd96fe781be16c1987e4..874b71a700586340439e34ea73a0dc5d14695bba 100644 (file)
@@ -485,9 +485,9 @@ struct perf_addr_filters_head {
 };
 
 /**
- * enum perf_event_active_state - the states of a event
+ * enum perf_event_state - the states of a event
  */
-enum perf_event_active_state {
+enum perf_event_state {
        PERF_EVENT_STATE_DEAD           = -4,
        PERF_EVENT_STATE_EXIT           = -3,
        PERF_EVENT_STATE_ERROR          = -2,
@@ -578,7 +578,7 @@ struct perf_event {
        struct pmu                      *pmu;
        void                            *pmu_private;
 
-       enum perf_event_active_state    state;
+       enum perf_event_state           state;
        unsigned int                    attach_state;
        local64_t                       count;
        atomic64_t                      child_count;
@@ -588,26 +588,10 @@ struct perf_event {
         * has been enabled (i.e. eligible to run, and the task has
         * been scheduled in, if this is a per-task event)
         * and running (scheduled onto the CPU), respectively.
-        *
-        * They are computed from tstamp_enabled, tstamp_running and
-        * tstamp_stopped when the event is in INACTIVE or ACTIVE state.
         */
        u64                             total_time_enabled;
        u64                             total_time_running;
-
-       /*
-        * These are timestamps used for computing total_time_enabled
-        * and total_time_running when the event is in INACTIVE or
-        * ACTIVE state, measured in nanoseconds from an arbitrary point
-        * in time.
-        * tstamp_enabled: the notional time when the event was enabled
-        * tstamp_running: the notional time when the event was scheduled on
-        * tstamp_stopped: in INACTIVE state, the notional time when the
-        *      event was scheduled off.
-        */
-       u64                             tstamp_enabled;
-       u64                             tstamp_running;
-       u64                             tstamp_stopped;
+       u64                             tstamp;
 
        /*
         * timestamp shadows the actual context timing but it can
@@ -699,7 +683,6 @@ struct perf_event {
 
 #ifdef CONFIG_CGROUP_PERF
        struct perf_cgroup              *cgrp; /* cgroup event is attach to */
-       int                             cgrp_defer_enabled;
 #endif
 
        struct list_head                sb_list;
@@ -806,6 +789,7 @@ struct perf_output_handle {
 struct bpf_perf_event_data_kern {
        struct pt_regs *regs;
        struct perf_sample_data *data;
+       struct perf_event *event;
 };
 
 #ifdef CONFIG_CGROUP_PERF
@@ -884,7 +868,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr,
                                void *context);
 extern void perf_pmu_migrate_context(struct pmu *pmu,
                                int src_cpu, int dst_cpu);
-int perf_event_read_local(struct perf_event *event, u64 *value);
+int perf_event_read_local(struct perf_event *event, u64 *value,
+                         u64 *enabled, u64 *running);
 extern u64 perf_event_read_value(struct perf_event *event,
                                 u64 *enabled, u64 *running);
 
@@ -1286,7 +1271,8 @@ static inline const struct perf_event_attr *perf_event_attrs(struct perf_event *
 {
        return ERR_PTR(-EINVAL);
 }
-static inline int perf_event_read_local(struct perf_event *event, u64 *value)
+static inline int perf_event_read_local(struct perf_event *event, u64 *value,
+                                       u64 *enabled, u64 *running)
 {
        return -EINVAL;
 }
diff --git a/include/linux/platform_data/sht15.h b/include/linux/platform_data/sht15.h
deleted file mode 100644 (file)
index 12289c1..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * sht15.h - support for the SHT15 Temperature and Humidity Sensor
- *
- * Copyright (c) 2009 Jonathan Cameron
- *
- * Copyright (c) 2007 Wouter Horre
- *
- * 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.
- *
- * For further information, see the Documentation/hwmon/sht15 file.
- */
-
-#ifndef _PDATA_SHT15_H
-#define _PDATA_SHT15_H
-
-/**
- * struct sht15_platform_data - sht15 connectivity info
- * @gpio_data:         no. of gpio to which bidirectional data line is
- *                     connected.
- * @gpio_sck:          no. of gpio to which the data clock is connected.
- * @supply_mv:         supply voltage in mv. Overridden by regulator if
- *                     available.
- * @checksum:          flag to indicate the checksum should be validated.
- * @no_otp_reload:     flag to indicate no reload from OTP.
- * @low_resolution:    flag to indicate the temp/humidity resolution to use.
- */
-struct sht15_platform_data {
-       int gpio_data;
-       int gpio_sck;
-       int supply_mv;
-       bool checksum;
-       bool no_otp_reload;
-       bool low_resolution;
-};
-
-#endif /* _PDATA_SHT15_H */
index 47ded8aa8a5d5a0b9ec83e0d362c037a26b03b1d..65d39115f06d8780399e469ed44fc1c90f074e69 100644 (file)
@@ -550,6 +550,33 @@ struct pm_subsys_data {
 #endif
 };
 
+/*
+ * Driver flags to control system suspend/resume behavior.
+ *
+ * These flags can be set by device drivers at the probe time.  They need not be
+ * cleared by the drivers as the driver core will take care of that.
+ *
+ * NEVER_SKIP: Do not skip system suspend/resume callbacks for the device.
+ * SMART_PREPARE: Check the return value of the driver's ->prepare callback.
+ * SMART_SUSPEND: No need to resume the device from runtime suspend.
+ *
+ * Setting SMART_PREPARE instructs bus types and PM domains which may want
+ * system suspend/resume callbacks to be skipped for the device to return 0 from
+ * their ->prepare callbacks if the driver's ->prepare callback returns 0 (in
+ * other words, the system suspend/resume callbacks can only be skipped for the
+ * device if its driver doesn't object against that).  This flag has no effect
+ * if NEVER_SKIP is set.
+ *
+ * Setting SMART_SUSPEND instructs bus types and PM domains which may want to
+ * runtime resume the device upfront during system suspend that doing so is not
+ * necessary from the driver's perspective.  It also may cause them to skip
+ * invocations of the ->suspend_late and ->suspend_noirq callbacks provided by
+ * the driver if they decide to leave the device in runtime suspend.
+ */
+#define DPM_FLAG_NEVER_SKIP    BIT(0)
+#define DPM_FLAG_SMART_PREPARE BIT(1)
+#define DPM_FLAG_SMART_SUSPEND BIT(2)
+
 struct dev_pm_info {
        pm_message_t            power_state;
        unsigned int            can_wakeup:1;
@@ -561,6 +588,7 @@ struct dev_pm_info {
        bool                    is_late_suspended:1;
        bool                    early_init:1;   /* Owned by the PM core */
        bool                    direct_complete:1;      /* Owned by the PM core */
+       u32                     driver_flags;
        spinlock_t              lock;
 #ifdef CONFIG_PM_SLEEP
        struct list_head        entry;
@@ -736,7 +764,8 @@ extern int pm_generic_poweroff_noirq(struct device *dev);
 extern int pm_generic_poweroff_late(struct device *dev);
 extern int pm_generic_poweroff(struct device *dev);
 extern void pm_generic_complete(struct device *dev);
-extern void pm_complete_with_resume_check(struct device *dev);
+
+extern bool dev_pm_smart_suspend_and_suspended(struct device *dev);
 
 #else /* !CONFIG_PM_SLEEP */
 
index 84f423d5633ee996e7eb5dd87ed8d3024f41b886..04dbef9847d3ad3b5619b12a6d2fdab209e725c8 100644 (file)
 #include <linux/spinlock.h>
 
 /* Defines used for the flags field in the struct generic_pm_domain */
-#define GENPD_FLAG_PM_CLK      (1U << 0) /* PM domain uses PM clk */
-#define GENPD_FLAG_IRQ_SAFE    (1U << 1) /* PM domain operates in atomic */
-#define GENPD_FLAG_ALWAYS_ON   (1U << 2) /* PM domain is always powered on */
+#define GENPD_FLAG_PM_CLK       (1U << 0) /* PM domain uses PM clk */
+#define GENPD_FLAG_IRQ_SAFE     (1U << 1) /* PM domain operates in atomic */
+#define GENPD_FLAG_ALWAYS_ON    (1U << 2) /* PM domain is always powered on */
+#define GENPD_FLAG_ACTIVE_WAKEUP (1U << 3) /* Keep devices active if wakeup */
 
 enum gpd_status {
        GPD_STATE_ACTIVE = 0,   /* PM domain is active */
@@ -35,7 +36,6 @@ struct dev_power_governor {
 struct gpd_dev_ops {
        int (*start)(struct device *dev);
        int (*stop)(struct device *dev);
-       bool (*active_wakeup)(struct device *dev);
 };
 
 struct genpd_power_state {
@@ -64,8 +64,11 @@ struct generic_pm_domain {
        unsigned int device_count;      /* Number of devices */
        unsigned int suspended_count;   /* System suspend device counter */
        unsigned int prepared_count;    /* Suspend counter of prepared devices */
+       unsigned int performance_state; /* Aggregated max performance state */
        int (*power_off)(struct generic_pm_domain *domain);
        int (*power_on)(struct generic_pm_domain *domain);
+       int (*set_performance_state)(struct generic_pm_domain *genpd,
+                                    unsigned int state);
        struct gpd_dev_ops dev_ops;
        s64 max_off_time_ns;    /* Maximum allowed "suspended" time. */
        bool max_off_time_changed;
@@ -121,6 +124,7 @@ struct generic_pm_domain_data {
        struct pm_domain_data base;
        struct gpd_timing_data td;
        struct notifier_block nb;
+       unsigned int performance_state;
        void *data;
 };
 
@@ -148,6 +152,8 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 extern int pm_genpd_init(struct generic_pm_domain *genpd,
                         struct dev_power_governor *gov, bool is_off);
 extern int pm_genpd_remove(struct generic_pm_domain *genpd);
+extern int dev_pm_genpd_set_performance_state(struct device *dev,
+                                             unsigned int state);
 
 extern struct dev_power_governor simple_qos_governor;
 extern struct dev_power_governor pm_domain_always_on_gov;
@@ -188,6 +194,12 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
        return -ENOTSUPP;
 }
 
+static inline int dev_pm_genpd_set_performance_state(struct device *dev,
+                                                    unsigned int state)
+{
+       return -ENOTSUPP;
+}
+
 #define simple_qos_governor            (*(struct dev_power_governor *)(NULL))
 #define pm_domain_always_on_gov                (*(struct dev_power_governor *)(NULL))
 #endif
index 51ec727b48249db35c72c8652117fcddcc8feea8..6c2d2e88f0666b51038d45d3da0894fc9e7bb2ae 100644 (file)
@@ -124,7 +124,9 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table);
 struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name);
 void dev_pm_opp_put_clkname(struct opp_table *opp_table);
 struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
-void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table);
+void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table);
+struct opp_table *dev_pm_opp_register_get_pstate_helper(struct device *dev, int (*get_pstate)(struct device *dev, unsigned long rate));
+void dev_pm_opp_unregister_get_pstate_helper(struct opp_table *opp_table);
 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
 int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
 int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
@@ -243,7 +245,15 @@ static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device
        return ERR_PTR(-ENOTSUPP);
 }
 
-static inline void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table) {}
+static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {}
+
+static inline struct opp_table *dev_pm_opp_register_get_pstate_helper(struct device *dev,
+               int (*get_pstate)(struct device *dev, unsigned long rate))
+{
+       return ERR_PTR(-ENOTSUPP);
+}
+
+static inline void dev_pm_opp_unregister_get_pstate_helper(struct opp_table *opp_table) {}
 
 static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
 {
index 2a3acf4dba9ab73cad5b54fc8ebfbfb8d711dd87..6ea1ae373d77c2efdc1369fe8391009a57a8054c 100644 (file)
@@ -28,19 +28,21 @@ enum pm_qos_flags_status {
        PM_QOS_FLAGS_ALL,
 };
 
-#define PM_QOS_DEFAULT_VALUE -1
+#define PM_QOS_DEFAULT_VALUE   (-1)
+#define PM_QOS_LATENCY_ANY     S32_MAX
+#define PM_QOS_LATENCY_ANY_NS  ((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
 
 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE        0
 #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE  0
-#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE    0
+#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE    PM_QOS_LATENCY_ANY
+#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_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
-#define PM_QOS_LATENCY_ANY                     ((s32)(~(__u32)0 >> 1))
 
 #define PM_QOS_FLAG_NO_POWER_OFF       (1 << 0)
-#define PM_QOS_FLAG_REMOTE_WAKEUP      (1 << 1)
 
 struct pm_qos_request {
        struct plist_node node;
@@ -175,7 +177,8 @@ static inline s32 dev_pm_qos_requested_flags(struct device *dev)
 static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
 {
        return IS_ERR_OR_NULL(dev->power.qos) ?
-               0 : pm_qos_read_value(&dev->power.qos->resume_latency);
+               PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
+               pm_qos_read_value(&dev->power.qos->resume_latency);
 }
 #else
 static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
@@ -185,9 +188,9 @@ 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 0; }
+                       { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline s32 dev_pm_qos_read_value(struct device *dev)
-                       { return 0; }
+                       { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
 static inline int dev_pm_qos_add_request(struct device *dev,
                                         struct dev_pm_qos_request *req,
                                         enum dev_pm_qos_req_type type,
@@ -233,9 +236,15 @@ static inline int dev_pm_qos_expose_latency_tolerance(struct device *dev)
                        { return 0; }
 static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
 
-static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
+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) { return 0; }
+static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
+{
+       return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+}
 #endif
 
 #endif
index 2efb08a60e638f3b0c043ce6485c54ebc031d5e9..f0fc4700b6ff53adfb8584162ae0bb3c522237a2 100644 (file)
@@ -105,7 +105,7 @@ static inline bool pm_runtime_callbacks_present(struct device *dev)
 
 static inline void pm_runtime_mark_last_busy(struct device *dev)
 {
-       ACCESS_ONCE(dev->power.last_busy) = jiffies;
+       WRITE_ONCE(dev->power.last_busy, jiffies);
 }
 
 static inline bool pm_runtime_is_irq_safe(struct device *dev)
index 335926039adcfda6f9a8af97a15f9c7802d63b4a..905bba92f01598ae535b2d2cd737d1a78e739476 100644 (file)
@@ -189,7 +189,6 @@ extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 
 extern int printk_delay_msec;
 extern int dmesg_restrict;
-extern int kptr_restrict;
 
 extern int
 devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, void __user *buf,
@@ -280,6 +279,8 @@ static inline void printk_safe_flush_on_panic(void)
 }
 #endif
 
+extern int kptr_restrict;
+
 extern asmlinkage void dump_stack(void) __cold;
 
 #ifndef pr_fmt
index c2cdd45a880aa00229c0f7c5807305804cfd7823..127f534fec94aadfdc322a562b03f0860d3ccfa3 100644 (file)
@@ -275,7 +275,7 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
  * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
  */
 #define list_entry_rcu(ptr, type, member) \
-       container_of(lockless_dereference(ptr), type, member)
+       container_of(READ_ONCE(ptr), type, member)
 
 /*
  * Where are list_empty_rcu() and list_first_entry_rcu()?
@@ -368,7 +368,7 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
  * example is when items are added to the list, but never deleted.
  */
 #define list_entry_lockless(ptr, type, member) \
-       container_of((typeof(ptr))lockless_dereference(ptr), type, member)
+       container_of((typeof(ptr))READ_ONCE(ptr), type, member)
 
 /**
  * list_for_each_entry_lockless - iterate over rcu list of given type
index 1a9f70d44af954ffe790dcb75872704beab152b2..a6ddc42f87a5786d08dda84f023f1ed879a74f22 100644 (file)
@@ -346,7 +346,7 @@ static inline void rcu_preempt_sleep_check(void) { }
 #define __rcu_dereference_check(p, c, space) \
 ({ \
        /* Dependency order vs. p above. */ \
-       typeof(*p) *________p1 = (typeof(*p) *__force)lockless_dereference(p); \
+       typeof(*p) *________p1 = (typeof(*p) *__force)READ_ONCE(p); \
        RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_check() usage"); \
        rcu_dereference_sparse(p, space); \
        ((typeof(*p) __force __kernel *)(________p1)); \
@@ -360,7 +360,7 @@ static inline void rcu_preempt_sleep_check(void) { }
 #define rcu_dereference_raw(p) \
 ({ \
        /* Dependency order vs. p above. */ \
-       typeof(p) ________p1 = lockless_dereference(p); \
+       typeof(p) ________p1 = READ_ONCE(p); \
        ((typeof(*p) __force __kernel *)(________p1)); \
 })
 
index 978abfbac61783091046d63dbe23aedd2ad82b3c..15eddc1353bae3a272f6bbae881abe97981c0a6b 100644 (file)
@@ -120,21 +120,65 @@ struct reg_sequence {
  */
 #define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_us) \
 ({ \
-       ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
+       u64 __timeout_us = (timeout_us); \
+       unsigned long __sleep_us = (sleep_us); \
+       ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
+       int __ret; \
+       might_sleep_if(__sleep_us); \
+       for (;;) { \
+               __ret = regmap_read((map), (addr), &(val)); \
+               if (__ret) \
+                       break; \
+               if (cond) \
+                       break; \
+               if ((__timeout_us) && \
+                   ktime_compare(ktime_get(), __timeout) > 0) { \
+                       __ret = regmap_read((map), (addr), &(val)); \
+                       break; \
+               } \
+               if (__sleep_us) \
+                       usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
+       } \
+       __ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
+/**
+ * regmap_field_read_poll_timeout - Poll until a condition is met or timeout
+ *
+ * @field: Regmap field to read from
+ * @val: Unsigned integer variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in us (0
+ *            tight-loops).  Should be less than ~20ms since usleep_range
+ *            is used (see Documentation/timers/timers-howto.txt).
+ * @timeout_us: Timeout in us, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_field_read
+ * error return value in case of a error read. In the two former cases,
+ * the last read value at @addr is stored in @val. Must not be called
+ * from atomic context if sleep_us or timeout_us are used.
+ *
+ * This is modelled after the readx_poll_timeout macros in linux/iopoll.h.
+ */
+#define regmap_field_read_poll_timeout(field, val, cond, sleep_us, timeout_us) \
+({ \
+       u64 __timeout_us = (timeout_us); \
+       unsigned long __sleep_us = (sleep_us); \
+       ktime_t timeout = ktime_add_us(ktime_get(), __timeout_us); \
        int pollret; \
-       might_sleep_if(sleep_us); \
+       might_sleep_if(__sleep_us); \
        for (;;) { \
-               pollret = regmap_read((map), (addr), &(val)); \
+               pollret = regmap_field_read((field), &(val)); \
                if (pollret) \
                        break; \
                if (cond) \
                        break; \
-               if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
-                       pollret = regmap_read((map), (addr), &(val)); \
+               if (__timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
+                       pollret = regmap_field_read((field), &(val)); \
                        break; \
                } \
-               if (sleep_us) \
-                       usleep_range((sleep_us >> 2) + 1, sleep_us); \
+               if (__sleep_us) \
+                       usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
        } \
        pollret ?: ((cond) ? 0 : -ETIMEDOUT); \
 })
@@ -273,6 +317,9 @@ typedef void (*regmap_unlock)(void *);
  *
  * @ranges: Array of configuration entries for virtual address ranges.
  * @num_ranges: Number of range configuration entries.
+ * @hwlock_id: Specify the hardware spinlock id.
+ * @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE,
+ *              HWLOCK_IRQ or 0.
  */
 struct regmap_config {
        const char *name;
@@ -317,6 +364,9 @@ struct regmap_config {
 
        const struct regmap_range_cfg *ranges;
        unsigned int num_ranges;
+
+       unsigned int hwlock_id;
+       unsigned int hwlock_mode;
 };
 
 /**
index 80cb40b7c88d44e966f07db9aa67f1b98c9fe43f..f2fd2d3bf58f7755afbbfb4faabffaa46bd90841 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * da9211.h - Regulator device driver for DA9211/DA9212
- * /DA9213/DA9214/DA9215
+ * /DA9213/DA9223/DA9214/DA9224/DA9215/DA9225
  * Copyright (C) 2015  Dialog Semiconductor Ltd.
  *
  * This program is free software; you can redistribute it and/or
@@ -25,8 +25,11 @@ enum da9211_chip_id {
        DA9211,
        DA9212,
        DA9213,
+       DA9223,
        DA9214,
+       DA9224,
        DA9215,
+       DA9225,
 };
 
 struct da9211_pdata {
index f6d7ee98d93c3afb7c8b205a75361bd101a56600..41319a2e409b459d553cc6add16218eea75c1cca 100644 (file)
@@ -136,6 +136,14 @@ struct rtc_device {
        /* Some hardware can't support UIE mode */
        int uie_unsupported;
 
+       /* Number of nsec it takes to set the RTC clock. This influences when
+        * the set ops are called. An offset:
+        *   - of 0.5 s will call RTC set for wall clock time 10.0 s at 9.5 s
+        *   - of 1.5 s will call RTC set for wall clock time 10.0 s at 8.5 s
+        *   - of -0.5 s will call RTC set for wall clock time 10.0 s at 10.5 s
+        */
+       long set_offset_nsec;
+
        bool registered;
 
        struct nvmem_config *nvmem_config;
@@ -173,7 +181,7 @@ extern void devm_rtc_device_unregister(struct device *dev,
 
 extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
 extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
-extern int rtc_set_ntp_time(struct timespec64 now);
+extern int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec);
 int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
 extern int rtc_read_alarm(struct rtc_device *rtc,
                        struct rtc_wkalrm *alrm);
@@ -222,6 +230,39 @@ static inline bool is_leap_year(unsigned int year)
        return (!(year % 4) && (year % 100)) || !(year % 400);
 }
 
+/* Determine if we can call to driver to set the time. Drivers can only be
+ * called to set a second aligned time value, and the field set_offset_nsec
+ * specifies how far away from the second aligned time to call the driver.
+ *
+ * This also computes 'to_set' which is the time we are trying to set, and has
+ * a zero in tv_nsecs, such that:
+ *    to_set - set_delay_nsec == now +/- FUZZ
+ *
+ */
+static inline bool rtc_tv_nsec_ok(s64 set_offset_nsec,
+                                 struct timespec64 *to_set,
+                                 const struct timespec64 *now)
+{
+       /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */
+       const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5;
+       struct timespec64 delay = {.tv_sec = 0,
+                                  .tv_nsec = set_offset_nsec};
+
+       *to_set = timespec64_add(*now, delay);
+
+       if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) {
+               to_set->tv_nsec = 0;
+               return true;
+       }
+
+       if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) {
+               to_set->tv_sec++;
+               to_set->tv_nsec = 0;
+               return true;
+       }
+       return false;
+}
+
 #define rtc_register_device(device) \
        __rtc_register_device(THIS_MODULE, device)
 
index ff3dd2ec44b478eb0a3c42977190588c3c138295..54bcd970bfd3c9586ac2be2d836ebe72f18261bf 100644 (file)
@@ -68,7 +68,7 @@ static inline bool lockdep_rtnl_is_held(void)
  * @p: The pointer to read, prior to dereferencing
  *
  * Return the value of the specified RCU-protected pointer, but omit
- * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because
+ * both the smp_read_barrier_depends() and the READ_ONCE(), because
  * caller holds RTNL.
  */
 #define rtnl_dereference(p)                                    \
index bc2994ed66e1c0e915ab7b9dbae61a470b282e50..3dcd617e65ae902316399b0717f0dc0e834b355c 100644 (file)
@@ -38,6 +38,15 @@ do {                                                         \
  extern int do_raw_write_trylock(rwlock_t *lock);
  extern void do_raw_write_unlock(rwlock_t *lock) __releases(lock);
 #else
+
+#ifndef arch_read_lock_flags
+# define arch_read_lock_flags(lock, flags)     arch_read_lock(lock)
+#endif
+
+#ifndef arch_write_lock_flags
+# define arch_write_lock_flags(lock, flags)    arch_write_lock(lock)
+#endif
+
 # define do_raw_read_lock(rwlock)      do {__acquire(lock); arch_read_lock(&(rwlock)->raw_lock); } while (0)
 # define do_raw_read_lock_flags(lock, flags) \
                do {__acquire(lock); arch_read_lock_flags(&(lock)->raw_lock, *(flags)); } while (0)
@@ -50,9 +59,6 @@ do {                                                          \
 # define do_raw_write_unlock(rwlock)   do {arch_write_unlock(&(rwlock)->raw_lock); __release(lock); } while (0)
 #endif
 
-#define read_can_lock(rwlock)          arch_read_can_lock(&(rwlock)->raw_lock)
-#define write_can_lock(rwlock)         arch_write_can_lock(&(rwlock)->raw_lock)
-
 /*
  * Define the various rw_lock methods.  Note we define these
  * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various
index 5b9b84b204070f8e6780e3836ea3c9efdc4a1e61..86ebb4bf9c6ee3e21be256cb7cdc4574dff8aed2 100644 (file)
@@ -211,7 +211,7 @@ static inline void __raw_write_lock(rwlock_t *lock)
        LOCK_CONTENDED(lock, do_raw_write_trylock, do_raw_write_lock);
 }
 
-#endif /* CONFIG_PREEMPT */
+#endif /* !CONFIG_GENERIC_LOCKBREAK || CONFIG_DEBUG_LOCK_ALLOC */
 
 static inline void __raw_write_unlock(rwlock_t *lock)
 {
index dfa34d8034399c80eef05c707e36f839510dec92..56707d5ff6adddce20b7ae417d91abfd9c393744 100644 (file)
@@ -112,6 +112,7 @@ static inline int rwsem_is_contended(struct rw_semaphore *sem)
  * lock for reading
  */
 extern void down_read(struct rw_semaphore *sem);
+extern int __must_check down_read_killable(struct rw_semaphore *sem);
 
 /*
  * trylock for reading -- returns 1 if successful, 0 if contention
index fdf74f27acf1e9801051c5b6c22f1ec5008b9f42..a5dc7c98b0a2e5d54814a2cd6d3ecc2ffd6f4ea1 100644 (file)
@@ -166,8 +166,6 @@ struct task_group;
 /* Task command name length: */
 #define TASK_COMM_LEN                  16
 
-extern cpumask_var_t                   cpu_isolated_map;
-
 extern void scheduler_tick(void);
 
 #define        MAX_SCHEDULE_TIMEOUT            LONG_MAX
@@ -332,9 +330,11 @@ struct load_weight {
 struct sched_avg {
        u64                             last_update_time;
        u64                             load_sum;
+       u64                             runnable_load_sum;
        u32                             util_sum;
        u32                             period_contrib;
        unsigned long                   load_avg;
+       unsigned long                   runnable_load_avg;
        unsigned long                   util_avg;
 };
 
@@ -377,6 +377,7 @@ struct sched_statistics {
 struct sched_entity {
        /* For load-balancing: */
        struct load_weight              load;
+       unsigned long                   runnable_weight;
        struct rb_node                  run_node;
        struct list_head                group_node;
        unsigned int                    on_rq;
@@ -472,10 +473,10 @@ struct sched_dl_entity {
         * conditions between the inactive timer handler and the wakeup
         * code.
         */
-       int                             dl_throttled;
-       int                             dl_boosted;
-       int                             dl_yielded;
-       int                             dl_non_contending;
+       int                             dl_throttled      : 1;
+       int                             dl_boosted        : 1;
+       int                             dl_yielded        : 1;
+       int                             dl_non_contending : 1;
 
        /*
         * Bandwidth enforcement timer. Each -deadline task has its
@@ -1246,7 +1247,7 @@ static inline pid_t task_pgrp_nr(struct task_struct *tsk)
 #define TASK_REPORT_IDLE       (TASK_REPORT + 1)
 #define TASK_REPORT_MAX                (TASK_REPORT_IDLE << 1)
 
-static inline unsigned int __get_task_state(struct task_struct *tsk)
+static inline unsigned int task_state_index(struct task_struct *tsk)
 {
        unsigned int tsk_state = READ_ONCE(tsk->state);
        unsigned int state = (tsk_state | tsk->exit_state) & TASK_REPORT;
@@ -1259,7 +1260,7 @@ static inline unsigned int __get_task_state(struct task_struct *tsk)
        return fls(state);
 }
 
-static inline char __task_state_to_char(unsigned int state)
+static inline char task_index_to_char(unsigned int state)
 {
        static const char state_char[] = "RSDTtXZPI";
 
@@ -1270,7 +1271,7 @@ static inline char __task_state_to_char(unsigned int state)
 
 static inline char task_state_to_char(struct task_struct *tsk)
 {
-       return __task_state_to_char(__get_task_state(tsk));
+       return task_index_to_char(task_state_index(tsk));
 }
 
 /**
diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
new file mode 100644 (file)
index 0000000..d849431
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _LINUX_SCHED_ISOLATION_H
+#define _LINUX_SCHED_ISOLATION_H
+
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/tick.h>
+
+enum hk_flags {
+       HK_FLAG_TIMER           = 1,
+       HK_FLAG_RCU             = (1 << 1),
+       HK_FLAG_MISC            = (1 << 2),
+       HK_FLAG_SCHED           = (1 << 3),
+       HK_FLAG_TICK            = (1 << 4),
+       HK_FLAG_DOMAIN          = (1 << 5),
+};
+
+#ifdef CONFIG_CPU_ISOLATION
+DECLARE_STATIC_KEY_FALSE(housekeeping_overriden);
+extern int housekeeping_any_cpu(enum hk_flags flags);
+extern const struct cpumask *housekeeping_cpumask(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);
+
+#else
+
+static inline int housekeeping_any_cpu(enum hk_flags flags)
+{
+       return smp_processor_id();
+}
+
+static inline const struct cpumask *housekeeping_cpumask(enum hk_flags flags)
+{
+       return cpu_possible_mask;
+}
+
+static inline void housekeeping_affine(struct task_struct *t,
+                                      enum hk_flags flags) { }
+static inline void housekeeping_init(void) { }
+#endif /* CONFIG_CPU_ISOLATION */
+
+static inline bool housekeeping_cpu(int cpu, enum hk_flags flags)
+{
+#ifdef CONFIG_CPU_ISOLATION
+       if (static_branch_unlikely(&housekeeping_overriden))
+               return housekeeping_test_cpu(cpu, flags);
+#endif
+       return true;
+}
+
+#endif /* _LINUX_SCHED_ISOLATION_H */
index db865ed25ef310e8c5109129a64631d17fdb099b..e5af028c08b4945a2572e5f797ed33d46e4b0123 100644 (file)
@@ -18,6 +18,17 @@ static inline int rt_task(struct task_struct *p)
        return rt_prio(p->prio);
 }
 
+static inline bool task_is_realtime(struct task_struct *tsk)
+{
+       int policy = tsk->policy;
+
+       if (policy == SCHED_FIFO || policy == SCHED_RR)
+               return true;
+       if (policy == SCHED_DEADLINE)
+               return true;
+       return false;
+}
+
 #ifdef CONFIG_RT_MUTEXES
 /*
  * Must hold either p->pi_lock or task_rq(p)->lock.
index d6a18a3839cc281c6c7c61f4e7cb4281a5087c66..1c1a1512ec553fdbda5e7651d349737495411e2c 100644 (file)
@@ -38,9 +38,9 @@ extern unsigned int sysctl_numa_balancing_scan_period_max;
 extern unsigned int sysctl_numa_balancing_scan_size;
 
 #ifdef CONFIG_SCHED_DEBUG
-extern unsigned int sysctl_sched_migration_cost;
-extern unsigned int sysctl_sched_nr_migrate;
-extern unsigned int sysctl_sched_time_avg;
+extern __read_mostly unsigned int sysctl_sched_migration_cost;
+extern __read_mostly unsigned int sysctl_sched_nr_migrate;
+extern __read_mostly unsigned int sysctl_sched_time_avg;
 
 int sched_proc_update_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *length,
index 72299ef00061db1ce70d34b96ae1639ecde08837..d448a4804aeabbbb44179d5e47e9f806733d3e66 100644 (file)
@@ -3770,6 +3770,13 @@ static inline void nf_reset_trace(struct sk_buff *skb)
 #endif
 }
 
+static inline void ipvs_reset(struct sk_buff *skb)
+{
+#if IS_ENABLED(CONFIG_IP_VS)
+       skb->ipvs_property = 0;
+#endif
+}
+
 /* Note: This doesn't put any conntrack and bridge info in dst. */
 static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src,
                             bool copy)
diff --git a/include/linux/spi/spi-fsl-dspi.h b/include/linux/spi/spi-fsl-dspi.h
new file mode 100644 (file)
index 0000000..74c9bae
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Freescale DSPI controller driver
+ *
+ * Copyright (c) 2017 Angelo Dureghello <angelo@sysam.it>
+ *
+ * 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.
+ */
+
+#ifndef SPI_FSL_DSPI_HEADER_H
+#define SPI_FSL_DSPI_HEADER_H
+
+/**
+ * struct fsl_dspi_platform_data - platform data for the Freescale DSPI driver
+ * @bus_num: board specific identifier for this DSPI driver.
+ * @cs_num: number of chip selects supported by this DSPI driver.
+ */
+struct fsl_dspi_platform_data {
+       u32 cs_num;
+       u32 bus_num;
+       u32 sck_cs_delay;
+       u32 cs_sck_delay;
+};
+
+#endif /* SPI_FSL_DSPI_HEADER_H */
index 341e1a12bfc78c99c62e21857c2f9e304800db52..a39186194cd6782ac0b6705f02af6179a86f7813 100644 (file)
@@ -166,6 +166,10 @@ static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
        arch_spin_lock(&lock->raw_lock);
 }
 
+#ifndef arch_spin_lock_flags
+#define arch_spin_lock_flags(lock, flags)      arch_spin_lock(lock)
+#endif
+
 static inline void
 do_raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long *flags) __acquires(lock)
 {
@@ -279,12 +283,6 @@ static inline void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock)
        1 : ({ local_irq_restore(flags); 0; }); \
 })
 
-/**
- * raw_spin_can_lock - would raw_spin_trylock() succeed?
- * @lock: the spinlock in question.
- */
-#define raw_spin_can_lock(lock)        (!raw_spin_is_locked(lock))
-
 /* Include rwlock functions */
 #include <linux/rwlock.h>
 
@@ -397,11 +395,6 @@ static __always_inline int spin_is_contended(spinlock_t *lock)
        return raw_spin_is_contended(&lock->rlock);
 }
 
-static __always_inline int spin_can_lock(spinlock_t *lock)
-{
-       return raw_spin_can_lock(&lock->rlock);
-}
-
 #define assert_spin_locked(lock)       assert_raw_spin_locked(&(lock)->rlock)
 
 /*
index 612fb530af41b40f2e164cfe5f302a3cc48a3cf7..0ac9112c1bbe3287658057098c37a67bc818c559 100644 (file)
@@ -32,14 +32,6 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
        barrier();
 }
 
-static inline void
-arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags)
-{
-       local_irq_save(flags);
-       lock->slock = 0;
-       barrier();
-}
-
 static inline int arch_spin_trylock(arch_spinlock_t *lock)
 {
        char oldval = lock->slock;
@@ -77,7 +69,4 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 #define arch_spin_is_contended(lock)   (((void)(lock), 0))
 
-#define arch_read_can_lock(lock)       (((void)(lock), 1))
-#define arch_write_can_lock(lock)      (((void)(lock), 1))
-
 #endif /* __LINUX_SPINLOCK_UP_H */
index 74f91eefeccfed728e38f0c4c9859fdf001224fa..b769ecfcc3bd41aad6fd339ba824c6bb622ac24d 100644 (file)
@@ -213,6 +213,11 @@ static inline struct ctl_table_header *register_sysctl_paths(
        return NULL;
 }
 
+static inline struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
+{
+       return NULL;
+}
+
 static inline void unregister_sysctl_table(struct ctl_table_header * table)
 {
 }
index cf413b344ddb7912864a12bbb67387fad9367c25..f442d1a42025925eb4446c6678e3a059a8cfbb39 100644 (file)
@@ -138,7 +138,6 @@ static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; }
 #ifdef CONFIG_NO_HZ_FULL
 extern bool tick_nohz_full_running;
 extern cpumask_var_t tick_nohz_full_mask;
-extern cpumask_var_t housekeeping_mask;
 
 static inline bool tick_nohz_full_enabled(void)
 {
@@ -162,11 +161,6 @@ static inline void tick_nohz_full_add_cpus_to(struct cpumask *mask)
                cpumask_or(mask, mask, tick_nohz_full_mask);
 }
 
-static inline int housekeeping_any_cpu(void)
-{
-       return cpumask_any_and(housekeeping_mask, cpu_online_mask);
-}
-
 extern void tick_nohz_dep_set(enum tick_dep_bits bit);
 extern void tick_nohz_dep_clear(enum tick_dep_bits bit);
 extern void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit);
@@ -235,11 +229,8 @@ static inline void tick_dep_clear_signal(struct signal_struct *signal,
 
 extern void tick_nohz_full_kick_cpu(int cpu);
 extern void __tick_nohz_task_switch(void);
+extern void __init tick_nohz_full_setup(cpumask_var_t cpumask);
 #else
-static inline int housekeeping_any_cpu(void)
-{
-       return smp_processor_id();
-}
 static inline bool tick_nohz_full_enabled(void) { return false; }
 static inline bool tick_nohz_full_cpu(int cpu) { return false; }
 static inline void tick_nohz_full_add_cpus_to(struct cpumask *mask) { }
@@ -259,35 +250,9 @@ static inline void tick_dep_clear_signal(struct signal_struct *signal,
 
 static inline void tick_nohz_full_kick_cpu(int cpu) { }
 static inline void __tick_nohz_task_switch(void) { }
+static inline void tick_nohz_full_setup(cpumask_var_t cpumask) { }
 #endif
 
-static inline const struct cpumask *housekeeping_cpumask(void)
-{
-#ifdef CONFIG_NO_HZ_FULL
-       if (tick_nohz_full_enabled())
-               return housekeeping_mask;
-#endif
-       return cpu_possible_mask;
-}
-
-static inline bool is_housekeeping_cpu(int cpu)
-{
-#ifdef CONFIG_NO_HZ_FULL
-       if (tick_nohz_full_enabled())
-               return cpumask_test_cpu(cpu, housekeeping_mask);
-#endif
-       return true;
-}
-
-static inline void housekeeping_affine(struct task_struct *t)
-{
-#ifdef CONFIG_NO_HZ_FULL
-       if (tick_nohz_full_enabled())
-               set_cpus_allowed_ptr(t, housekeeping_mask);
-
-#endif
-}
-
 static inline void tick_nohz_task_switch(void)
 {
        if (tick_nohz_full_enabled())
index 87c36cf1cec2cada829e3b04c3531b84aff3a423..4b62a2c0a66129c7615fd60e36852be02a642a14 100644 (file)
@@ -18,149 +18,10 @@ int get_itimerspec64(struct itimerspec64 *it,
 int put_itimerspec64(const struct itimerspec64 *it,
                        struct itimerspec __user *uit);
 
-#define TIME_T_MAX     (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
-
-static inline int timespec_equal(const struct timespec *a,
-                                 const struct timespec *b)
-{
-       return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
-}
-
-/*
- * lhs < rhs:  return <0
- * lhs == rhs: return 0
- * lhs > rhs:  return >0
- */
-static inline int timespec_compare(const struct timespec *lhs, const struct timespec *rhs)
-{
-       if (lhs->tv_sec < rhs->tv_sec)
-               return -1;
-       if (lhs->tv_sec > rhs->tv_sec)
-               return 1;
-       return lhs->tv_nsec - rhs->tv_nsec;
-}
-
-static inline int timeval_compare(const struct timeval *lhs, const struct timeval *rhs)
-{
-       if (lhs->tv_sec < rhs->tv_sec)
-               return -1;
-       if (lhs->tv_sec > rhs->tv_sec)
-               return 1;
-       return lhs->tv_usec - rhs->tv_usec;
-}
-
 extern time64_t mktime64(const unsigned int year, const unsigned int mon,
                        const unsigned int day, const unsigned int hour,
                        const unsigned int min, const unsigned int sec);
 
-/**
- * Deprecated. Use mktime64().
- */
-static inline unsigned long mktime(const unsigned int year,
-                       const unsigned int mon, const unsigned int day,
-                       const unsigned int hour, const unsigned int min,
-                       const unsigned int sec)
-{
-       return mktime64(year, mon, day, hour, min, sec);
-}
-
-extern void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec);
-
-/*
- * timespec_add_safe assumes both values are positive and checks
- * for overflow. It will return TIME_T_MAX if the reutrn would be
- * smaller then either of the arguments.
- */
-extern struct timespec timespec_add_safe(const struct timespec lhs,
-                                        const struct timespec rhs);
-
-
-static inline struct timespec timespec_add(struct timespec lhs,
-                                               struct timespec rhs)
-{
-       struct timespec ts_delta;
-       set_normalized_timespec(&ts_delta, lhs.tv_sec + rhs.tv_sec,
-                               lhs.tv_nsec + rhs.tv_nsec);
-       return ts_delta;
-}
-
-/*
- * sub = lhs - rhs, in normalized form
- */
-static inline struct timespec timespec_sub(struct timespec lhs,
-                                               struct timespec rhs)
-{
-       struct timespec ts_delta;
-       set_normalized_timespec(&ts_delta, lhs.tv_sec - rhs.tv_sec,
-                               lhs.tv_nsec - rhs.tv_nsec);
-       return ts_delta;
-}
-
-/*
- * Returns true if the timespec is norm, false if denorm:
- */
-static inline bool timespec_valid(const struct timespec *ts)
-{
-       /* Dates before 1970 are bogus */
-       if (ts->tv_sec < 0)
-               return false;
-       /* Can't have more nanoseconds then a second */
-       if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
-               return false;
-       return true;
-}
-
-static inline bool timespec_valid_strict(const struct timespec *ts)
-{
-       if (!timespec_valid(ts))
-               return false;
-       /* Disallow values that could overflow ktime_t */
-       if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX)
-               return false;
-       return true;
-}
-
-static inline bool timeval_valid(const struct timeval *tv)
-{
-       /* Dates before 1970 are bogus */
-       if (tv->tv_sec < 0)
-               return false;
-
-       /* Can't have more microseconds then a second */
-       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
-               return false;
-
-       return true;
-}
-
-extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
-
-/*
- * Validates if a timespec/timeval used to inject a time offset is valid.
- * Offsets can be postive or negative. The value of the timeval/timespec
- * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
- * always be non-negative.
- */
-static inline bool timeval_inject_offset_valid(const struct timeval *tv)
-{
-       /* We don't check the tv_sec as it can be positive or negative */
-
-       /* Can't have more microseconds then a second */
-       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
-               return false;
-       return true;
-}
-
-static inline bool timespec_inject_offset_valid(const struct timespec *ts)
-{
-       /* We don't check the tv_sec as it can be positive or negative */
-
-       /* Can't have more nanoseconds then a second */
-       if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
-               return false;
-       return true;
-}
-
 /* Some architectures do not supply their own clocksource.
  * This is mainly the case in architectures that get their
  * inter-tick times by reading the counter on their interval
@@ -209,73 +70,7 @@ struct tm {
 
 void time64_to_tm(time64_t totalsecs, int offset, struct tm *result);
 
-/**
- * time_to_tm - converts the calendar time to local broken-down time
- *
- * @totalsecs  the number of seconds elapsed since 00:00:00 on January 1, 1970,
- *             Coordinated Universal Time (UTC).
- * @offset     offset seconds adding to totalsecs.
- * @result     pointer to struct tm variable to receive broken-down time
- */
-static inline void time_to_tm(time_t totalsecs, int offset, struct tm *result)
-{
-       time64_to_tm(totalsecs, offset, result);
-}
-
-/**
- * timespec_to_ns - Convert timespec to nanoseconds
- * @ts:                pointer to the timespec variable to be converted
- *
- * Returns the scalar nanosecond representation of the timespec
- * parameter.
- */
-static inline s64 timespec_to_ns(const struct timespec *ts)
-{
-       return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
-}
-
-/**
- * timeval_to_ns - Convert timeval to nanoseconds
- * @ts:                pointer to the timeval variable to be converted
- *
- * Returns the scalar nanosecond representation of the timeval
- * parameter.
- */
-static inline s64 timeval_to_ns(const struct timeval *tv)
-{
-       return ((s64) tv->tv_sec * NSEC_PER_SEC) +
-               tv->tv_usec * NSEC_PER_USEC;
-}
-
-/**
- * ns_to_timespec - Convert nanoseconds to timespec
- * @nsec:      the nanoseconds value to be converted
- *
- * Returns the timespec representation of the nsec parameter.
- */
-extern struct timespec ns_to_timespec(const s64 nsec);
-
-/**
- * ns_to_timeval - Convert nanoseconds to timeval
- * @nsec:      the nanoseconds value to be converted
- *
- * Returns the timeval representation of the nsec parameter.
- */
-extern struct timeval ns_to_timeval(const s64 nsec);
-
-/**
- * timespec_add_ns - Adds nanoseconds to a timespec
- * @a:         pointer to timespec to be incremented
- * @ns:                unsigned nanoseconds value to be added
- *
- * This must always be inlined because its used from the x86-64 vdso,
- * which cannot call other kernel functions.
- */
-static __always_inline void timespec_add_ns(struct timespec *a, u64 ns)
-{
-       a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns);
-       a->tv_nsec = ns;
-}
+# include <linux/time32.h>
 
 static inline bool itimerspec64_valid(const struct itimerspec64 *its)
 {
diff --git a/include/linux/time32.h b/include/linux/time32.h
new file mode 100644 (file)
index 0000000..65b1de2
--- /dev/null
@@ -0,0 +1,221 @@
+#ifndef _LINUX_TIME32_H
+#define _LINUX_TIME32_H
+/*
+ * These are all interfaces based on the old time_t definition
+ * that overflows in 2038 on 32-bit architectures. New code
+ * should use the replacements based on time64_t and timespec64.
+ *
+ * Any interfaces in here that become unused as we migrate
+ * code to time64_t should get removed.
+ */
+
+#include <linux/time64.h>
+
+#define TIME_T_MAX     (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
+
+#if __BITS_PER_LONG == 64
+
+/* timespec64 is defined as timespec here */
+static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64)
+{
+       return ts64;
+}
+
+static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
+{
+       return ts;
+}
+
+# define timespec_equal                        timespec64_equal
+# define timespec_compare              timespec64_compare
+# define set_normalized_timespec       set_normalized_timespec64
+# define timespec_add                  timespec64_add
+# define timespec_sub                  timespec64_sub
+# define timespec_valid                        timespec64_valid
+# define timespec_valid_strict         timespec64_valid_strict
+# define timespec_to_ns                        timespec64_to_ns
+# define ns_to_timespec                        ns_to_timespec64
+# define timespec_add_ns               timespec64_add_ns
+
+#else
+static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64)
+{
+       struct timespec ret;
+
+       ret.tv_sec = (time_t)ts64.tv_sec;
+       ret.tv_nsec = ts64.tv_nsec;
+       return ret;
+}
+
+static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
+{
+       struct timespec64 ret;
+
+       ret.tv_sec = ts.tv_sec;
+       ret.tv_nsec = ts.tv_nsec;
+       return ret;
+}
+
+static inline int timespec_equal(const struct timespec *a,
+                                const struct timespec *b)
+{
+       return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
+}
+
+/*
+ * lhs < rhs:  return <0
+ * lhs == rhs: return 0
+ * lhs > rhs:  return >0
+ */
+static inline int timespec_compare(const struct timespec *lhs, const struct timespec *rhs)
+{
+       if (lhs->tv_sec < rhs->tv_sec)
+               return -1;
+       if (lhs->tv_sec > rhs->tv_sec)
+               return 1;
+       return lhs->tv_nsec - rhs->tv_nsec;
+}
+
+extern void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec);
+
+static inline struct timespec timespec_add(struct timespec lhs,
+                                               struct timespec rhs)
+{
+       struct timespec ts_delta;
+
+       set_normalized_timespec(&ts_delta, lhs.tv_sec + rhs.tv_sec,
+                               lhs.tv_nsec + rhs.tv_nsec);
+       return ts_delta;
+}
+
+/*
+ * sub = lhs - rhs, in normalized form
+ */
+static inline struct timespec timespec_sub(struct timespec lhs,
+                                               struct timespec rhs)
+{
+       struct timespec ts_delta;
+
+       set_normalized_timespec(&ts_delta, lhs.tv_sec - rhs.tv_sec,
+                               lhs.tv_nsec - rhs.tv_nsec);
+       return ts_delta;
+}
+
+/*
+ * Returns true if the timespec is norm, false if denorm:
+ */
+static inline bool timespec_valid(const struct timespec *ts)
+{
+       /* Dates before 1970 are bogus */
+       if (ts->tv_sec < 0)
+               return false;
+       /* Can't have more nanoseconds then a second */
+       if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
+               return false;
+       return true;
+}
+
+static inline bool timespec_valid_strict(const struct timespec *ts)
+{
+       if (!timespec_valid(ts))
+               return false;
+       /* Disallow values that could overflow ktime_t */
+       if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX)
+               return false;
+       return true;
+}
+
+/**
+ * timespec_to_ns - Convert timespec to nanoseconds
+ * @ts:                pointer to the timespec variable to be converted
+ *
+ * Returns the scalar nanosecond representation of the timespec
+ * parameter.
+ */
+static inline s64 timespec_to_ns(const struct timespec *ts)
+{
+       return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
+}
+
+/**
+ * ns_to_timespec - Convert nanoseconds to timespec
+ * @nsec:      the nanoseconds value to be converted
+ *
+ * Returns the timespec representation of the nsec parameter.
+ */
+extern struct timespec ns_to_timespec(const s64 nsec);
+
+/**
+ * timespec_add_ns - Adds nanoseconds to a timespec
+ * @a:         pointer to timespec to be incremented
+ * @ns:                unsigned nanoseconds value to be added
+ *
+ * This must always be inlined because its used from the x86-64 vdso,
+ * which cannot call other kernel functions.
+ */
+static __always_inline void timespec_add_ns(struct timespec *a, u64 ns)
+{
+       a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns);
+       a->tv_nsec = ns;
+}
+
+#endif
+
+/**
+ * time_to_tm - converts the calendar time to local broken-down time
+ *
+ * @totalsecs  the number of seconds elapsed since 00:00:00 on January 1, 1970,
+ *             Coordinated Universal Time (UTC).
+ * @offset     offset seconds adding to totalsecs.
+ * @result     pointer to struct tm variable to receive broken-down time
+ */
+static inline void time_to_tm(time_t totalsecs, int offset, struct tm *result)
+{
+       time64_to_tm(totalsecs, offset, result);
+}
+
+static inline unsigned long mktime(const unsigned int year,
+                       const unsigned int mon, const unsigned int day,
+                       const unsigned int hour, const unsigned int min,
+                       const unsigned int sec)
+{
+       return mktime64(year, mon, day, hour, min, sec);
+}
+
+static inline bool timeval_valid(const struct timeval *tv)
+{
+       /* Dates before 1970 are bogus */
+       if (tv->tv_sec < 0)
+               return false;
+
+       /* Can't have more microseconds then a second */
+       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+               return false;
+
+       return true;
+}
+
+extern struct timespec timespec_trunc(struct timespec t, unsigned int gran);
+
+/**
+ * timeval_to_ns - Convert timeval to nanoseconds
+ * @ts:                pointer to the timeval variable to be converted
+ *
+ * Returns the scalar nanosecond representation of the timeval
+ * parameter.
+ */
+static inline s64 timeval_to_ns(const struct timeval *tv)
+{
+       return ((s64) tv->tv_sec * NSEC_PER_SEC) +
+               tv->tv_usec * NSEC_PER_USEC;
+}
+
+/**
+ * ns_to_timeval - Convert nanoseconds to timeval
+ * @nsec:      the nanoseconds value to be converted
+ *
+ * Returns the timeval representation of the nsec parameter.
+ */
+extern struct timeval ns_to_timeval(const s64 nsec);
+
+#endif
index ad33260618f766e8c2814530dc177961c8be485e..93d39499838e06d168dbcefb970d23b047a288ad 100644 (file)
@@ -8,11 +8,8 @@
 typedef __s64 time64_t;
 typedef __u64 timeu64_t;
 
-/*
- * This wants to go into uapi/linux/time.h once we agreed about the
- * userspace interfaces.
- */
 #if __BITS_PER_LONG == 64
+/* this trick allows us to optimize out timespec64_to_timespec */
 # define timespec64 timespec
 #define itimerspec64 itimerspec
 #else
@@ -42,77 +39,6 @@ struct itimerspec64 {
 #define KTIME_MAX                      ((s64)~((u64)1 << 63))
 #define KTIME_SEC_MAX                  (KTIME_MAX / NSEC_PER_SEC)
 
-#if __BITS_PER_LONG == 64
-
-static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64)
-{
-       return ts64;
-}
-
-static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
-{
-       return ts;
-}
-
-static inline struct itimerspec itimerspec64_to_itimerspec(struct itimerspec64 *its64)
-{
-       return *its64;
-}
-
-static inline struct itimerspec64 itimerspec_to_itimerspec64(struct itimerspec *its)
-{
-       return *its;
-}
-
-# define timespec64_equal              timespec_equal
-# define timespec64_compare            timespec_compare
-# define set_normalized_timespec64     set_normalized_timespec
-# define timespec64_add                        timespec_add
-# define timespec64_sub                        timespec_sub
-# define timespec64_valid              timespec_valid
-# define timespec64_valid_strict       timespec_valid_strict
-# define timespec64_to_ns              timespec_to_ns
-# define ns_to_timespec64              ns_to_timespec
-# define timespec64_add_ns             timespec_add_ns
-
-#else
-
-static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64)
-{
-       struct timespec ret;
-
-       ret.tv_sec = (time_t)ts64.tv_sec;
-       ret.tv_nsec = ts64.tv_nsec;
-       return ret;
-}
-
-static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
-{
-       struct timespec64 ret;
-
-       ret.tv_sec = ts.tv_sec;
-       ret.tv_nsec = ts.tv_nsec;
-       return ret;
-}
-
-static inline struct itimerspec itimerspec64_to_itimerspec(struct itimerspec64 *its64)
-{
-       struct itimerspec ret;
-
-       ret.it_interval = timespec64_to_timespec(its64->it_interval);
-       ret.it_value = timespec64_to_timespec(its64->it_value);
-       return ret;
-}
-
-static inline struct itimerspec64 itimerspec_to_itimerspec64(struct itimerspec *its)
-{
-       struct itimerspec64 ret;
-
-       ret.it_interval = timespec_to_timespec64(its->it_interval);
-       ret.it_value = timespec_to_timespec64(its->it_value);
-       return ret;
-}
-
 static inline int timespec64_equal(const struct timespec64 *a,
                                   const struct timespec64 *b)
 {
@@ -214,8 +140,6 @@ static __always_inline void timespec64_add_ns(struct timespec64 *a, u64 ns)
        a->tv_nsec = ns;
 }
 
-#endif
-
 /*
  * timespec64_add_safe assumes both values are positive and checks for
  * overflow. It will return TIME64_MAX in case of overflow.
index 97154c61e5d2b3dc9e59f37abb187652f10bb8f7..7e9011101cb08f674a5c2ba698be5f67367a464c 100644 (file)
 /**
  * struct tk_read_base - base structure for timekeeping readout
  * @clock:     Current clocksource used for timekeeping.
- * @read:      Read function of @clock
  * @mask:      Bitmask for two's complement subtraction of non 64bit clocks
  * @cycle_last: @clock cycle value at last update
  * @mult:      (NTP adjusted) multiplier for scaled math conversion
  * @shift:     Shift value for scaled math conversion
  * @xtime_nsec: Shifted (fractional) nano seconds offset for readout
  * @base:      ktime_t (nanoseconds) base time for readout
+ * @base_real: Nanoseconds base value for clock REALTIME readout
  *
  * This struct has size 56 byte on 64 bit. Together with a seqcount it
  * occupies a single 64byte cache line.
  *
  * The struct is separate from struct timekeeper as it is also used
  * for a fast NMI safe accessors.
+ *
+ * @base_real is for the fast NMI safe accessor to allow reading clock
+ * realtime from any context.
  */
 struct tk_read_base {
        struct clocksource      *clock;
@@ -36,6 +39,7 @@ struct tk_read_base {
        u32                     shift;
        u64                     xtime_nsec;
        ktime_t                 base;
+       u64                     base_real;
 };
 
 /**
index 0021575fe871133da5d67e2a5f09c85d0196fccd..c198ab40c04fb37174e7dbd683abe82715dcfb16 100644 (file)
@@ -16,27 +16,16 @@ extern void xtime_update(unsigned long ticks);
 /*
  * Get and set timeofday
  */
-extern void do_gettimeofday(struct timeval *tv);
 extern int do_settimeofday64(const struct timespec64 *ts);
 extern int do_sys_settimeofday64(const struct timespec64 *tv,
                                 const struct timezone *tz);
 /*
  * Kernel time accessors
  */
-unsigned long get_seconds(void);
 struct timespec64 current_kernel_time64(void);
-/* does not take xtime_lock */
-struct timespec __current_kernel_time(void);
-
-static inline struct timespec current_kernel_time(void)
-{
-       struct timespec64 now = current_kernel_time64();
-
-       return timespec64_to_timespec(now);
-}
 
 /*
- * timespec based interfaces
+ * timespec64 based interfaces
  */
 struct timespec64 get_monotonic_coarse64(void);
 extern void getrawmonotonic64(struct timespec64 *ts);
@@ -48,116 +37,6 @@ extern int __getnstimeofday64(struct timespec64 *tv);
 extern void getnstimeofday64(struct timespec64 *tv);
 extern void getboottime64(struct timespec64 *ts);
 
-#if BITS_PER_LONG == 64
-/**
- * Deprecated. Use do_settimeofday64().
- */
-static inline int do_settimeofday(const struct timespec *ts)
-{
-       return do_settimeofday64(ts);
-}
-
-static inline int __getnstimeofday(struct timespec *ts)
-{
-       return __getnstimeofday64(ts);
-}
-
-static inline void getnstimeofday(struct timespec *ts)
-{
-       getnstimeofday64(ts);
-}
-
-static inline void ktime_get_ts(struct timespec *ts)
-{
-       ktime_get_ts64(ts);
-}
-
-static inline void ktime_get_real_ts(struct timespec *ts)
-{
-       getnstimeofday64(ts);
-}
-
-static inline void getrawmonotonic(struct timespec *ts)
-{
-       getrawmonotonic64(ts);
-}
-
-static inline struct timespec get_monotonic_coarse(void)
-{
-       return get_monotonic_coarse64();
-}
-
-static inline void getboottime(struct timespec *ts)
-{
-       return getboottime64(ts);
-}
-#else
-/**
- * Deprecated. Use do_settimeofday64().
- */
-static inline int do_settimeofday(const struct timespec *ts)
-{
-       struct timespec64 ts64;
-
-       ts64 = timespec_to_timespec64(*ts);
-       return do_settimeofday64(&ts64);
-}
-
-static inline int __getnstimeofday(struct timespec *ts)
-{
-       struct timespec64 ts64;
-       int ret = __getnstimeofday64(&ts64);
-
-       *ts = timespec64_to_timespec(ts64);
-       return ret;
-}
-
-static inline void getnstimeofday(struct timespec *ts)
-{
-       struct timespec64 ts64;
-
-       getnstimeofday64(&ts64);
-       *ts = timespec64_to_timespec(ts64);
-}
-
-static inline void ktime_get_ts(struct timespec *ts)
-{
-       struct timespec64 ts64;
-
-       ktime_get_ts64(&ts64);
-       *ts = timespec64_to_timespec(ts64);
-}
-
-static inline void ktime_get_real_ts(struct timespec *ts)
-{
-       struct timespec64 ts64;
-
-       getnstimeofday64(&ts64);
-       *ts = timespec64_to_timespec(ts64);
-}
-
-static inline void getrawmonotonic(struct timespec *ts)
-{
-       struct timespec64 ts64;
-
-       getrawmonotonic64(&ts64);
-       *ts = timespec64_to_timespec(ts64);
-}
-
-static inline struct timespec get_monotonic_coarse(void)
-{
-       return timespec64_to_timespec(get_monotonic_coarse64());
-}
-
-static inline void getboottime(struct timespec *ts)
-{
-       struct timespec64 ts64;
-
-       getboottime64(&ts64);
-       *ts = timespec64_to_timespec(ts64);
-}
-#endif
-
 #define ktime_get_real_ts64(ts)        getnstimeofday64(ts)
 
 /*
@@ -240,25 +119,16 @@ static inline u64 ktime_get_raw_ns(void)
 extern u64 ktime_get_mono_fast_ns(void);
 extern u64 ktime_get_raw_fast_ns(void);
 extern u64 ktime_get_boot_fast_ns(void);
+extern u64 ktime_get_real_fast_ns(void);
 
 /*
- * Timespec interfaces utilizing the ktime based ones
+ * timespec64 interfaces utilizing the ktime based ones
  */
-static inline void get_monotonic_boottime(struct timespec *ts)
-{
-       *ts = ktime_to_timespec(ktime_get_boottime());
-}
-
 static inline void get_monotonic_boottime64(struct timespec64 *ts)
 {
        *ts = ktime_to_timespec64(ktime_get_boottime());
 }
 
-static inline void timekeeping_clocktai(struct timespec *ts)
-{
-       *ts = ktime_to_timespec(ktime_get_clocktai());
-}
-
 static inline void timekeeping_clocktai64(struct timespec64 *ts)
 {
        *ts = ktime_to_timespec64(ktime_get_clocktai());
@@ -341,10 +211,8 @@ extern void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot);
  */
 extern int persistent_clock_is_local;
 
-extern void read_persistent_clock(struct timespec *ts);
 extern void read_persistent_clock64(struct timespec64 *ts);
 extern void read_boot_clock64(struct timespec64 *ts);
-extern int update_persistent_clock(struct timespec now);
 extern int update_persistent_clock64(struct timespec64 now);
 
 
diff --git a/include/linux/timekeeping32.h b/include/linux/timekeeping32.h
new file mode 100644 (file)
index 0000000..af4114d
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef _LINUX_TIMEKEEPING32_H
+#define _LINUX_TIMEKEEPING32_H
+/*
+ * These interfaces are all based on the old timespec type
+ * and should get replaced with the timespec64 based versions
+ * over time so we can remove the file here.
+ */
+
+extern void do_gettimeofday(struct timeval *tv);
+unsigned long get_seconds(void);
+
+/* does not take xtime_lock */
+struct timespec __current_kernel_time(void);
+
+static inline struct timespec current_kernel_time(void)
+{
+       struct timespec64 now = current_kernel_time64();
+
+       return timespec64_to_timespec(now);
+}
+
+#if BITS_PER_LONG == 64
+/**
+ * Deprecated. Use do_settimeofday64().
+ */
+static inline int do_settimeofday(const struct timespec *ts)
+{
+       return do_settimeofday64(ts);
+}
+
+static inline int __getnstimeofday(struct timespec *ts)
+{
+       return __getnstimeofday64(ts);
+}
+
+static inline void getnstimeofday(struct timespec *ts)
+{
+       getnstimeofday64(ts);
+}
+
+static inline void ktime_get_ts(struct timespec *ts)
+{
+       ktime_get_ts64(ts);
+}
+
+static inline void ktime_get_real_ts(struct timespec *ts)
+{
+       getnstimeofday64(ts);
+}
+
+static inline void getrawmonotonic(struct timespec *ts)
+{
+       getrawmonotonic64(ts);
+}
+
+static inline struct timespec get_monotonic_coarse(void)
+{
+       return get_monotonic_coarse64();
+}
+
+static inline void getboottime(struct timespec *ts)
+{
+       return getboottime64(ts);
+}
+#else
+/**
+ * Deprecated. Use do_settimeofday64().
+ */
+static inline int do_settimeofday(const struct timespec *ts)
+{
+       struct timespec64 ts64;
+
+       ts64 = timespec_to_timespec64(*ts);
+       return do_settimeofday64(&ts64);
+}
+
+static inline int __getnstimeofday(struct timespec *ts)
+{
+       struct timespec64 ts64;
+       int ret = __getnstimeofday64(&ts64);
+
+       *ts = timespec64_to_timespec(ts64);
+       return ret;
+}
+
+static inline void getnstimeofday(struct timespec *ts)
+{
+       struct timespec64 ts64;
+
+       getnstimeofday64(&ts64);
+       *ts = timespec64_to_timespec(ts64);
+}
+
+static inline void ktime_get_ts(struct timespec *ts)
+{
+       struct timespec64 ts64;
+
+       ktime_get_ts64(&ts64);
+       *ts = timespec64_to_timespec(ts64);
+}
+
+static inline void ktime_get_real_ts(struct timespec *ts)
+{
+       struct timespec64 ts64;
+
+       getnstimeofday64(&ts64);
+       *ts = timespec64_to_timespec(ts64);
+}
+
+static inline void getrawmonotonic(struct timespec *ts)
+{
+       struct timespec64 ts64;
+
+       getrawmonotonic64(&ts64);
+       *ts = timespec64_to_timespec(ts64);
+}
+
+static inline struct timespec get_monotonic_coarse(void)
+{
+       return timespec64_to_timespec(get_monotonic_coarse64());
+}
+
+static inline void getboottime(struct timespec *ts)
+{
+       struct timespec64 ts64;
+
+       getboottime64(&ts64);
+       *ts = timespec64_to_timespec(ts64);
+}
+#endif
+
+/*
+ * Timespec interfaces utilizing the ktime based ones
+ */
+static inline void get_monotonic_boottime(struct timespec *ts)
+{
+       *ts = ktime_to_timespec(ktime_get_boottime());
+}
+
+static inline void timekeeping_clocktai(struct timespec *ts)
+{
+       *ts = ktime_to_timespec(ktime_get_clocktai());
+}
+
+/*
+ * Persistent clock related interfaces
+ */
+extern void read_persistent_clock(struct timespec *ts);
+extern int update_persistent_clock(struct timespec now);
+
+#endif
index ac66f29c69169a24d010df022750b488878a85e0..bf781acfc6d820f555eefed29dbcdc7c8c4f7033 100644 (file)
@@ -64,31 +64,21 @@ struct timer_list {
 
 #define TIMER_TRACE_FLAGMASK   (TIMER_MIGRATING | TIMER_DEFERRABLE | TIMER_PINNED | TIMER_IRQSAFE)
 
-#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \
+#define TIMER_DATA_TYPE                unsigned long
+#define TIMER_FUNC_TYPE                void (*)(TIMER_DATA_TYPE)
+
+#define __TIMER_INITIALIZER(_function, _data, _flags) {                \
                .entry = { .next = TIMER_ENTRY_STATIC },        \
                .function = (_function),                        \
-               .expires = (_expires),                          \
                .data = (_data),                                \
                .flags = (_flags),                              \
                __TIMER_LOCKDEP_MAP_INITIALIZER(                \
                        __FILE__ ":" __stringify(__LINE__))     \
        }
 
-#define TIMER_INITIALIZER(_function, _expires, _data)          \
-       __TIMER_INITIALIZER((_function), (_expires), (_data), 0)
-
-#define TIMER_PINNED_INITIALIZER(_function, _expires, _data)   \
-       __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_PINNED)
-
-#define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data) \
-       __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE)
-
-#define TIMER_PINNED_DEFERRED_INITIALIZER(_function, _expires, _data)  \
-       __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE | TIMER_PINNED)
-
-#define DEFINE_TIMER(_name, _function, _expires, _data)                \
+#define DEFINE_TIMER(_name, _function)                         \
        struct timer_list _name =                               \
-               TIMER_INITIALIZER(_function, _expires, _data)
+               __TIMER_INITIALIZER((TIMER_FUNC_TYPE)_function, 0, 0)
 
 void init_timer_key(struct timer_list *timer, unsigned int flags,
                    const char *name, struct lock_class_key *key);
@@ -129,14 +119,6 @@ static inline void init_timer_on_stack_key(struct timer_list *timer,
 
 #define init_timer(timer)                                              \
        __init_timer((timer), 0)
-#define init_timer_pinned(timer)                                       \
-       __init_timer((timer), TIMER_PINNED)
-#define init_timer_deferrable(timer)                                   \
-       __init_timer((timer), TIMER_DEFERRABLE)
-#define init_timer_pinned_deferrable(timer)                            \
-       __init_timer((timer), TIMER_DEFERRABLE | TIMER_PINNED)
-#define init_timer_on_stack(timer)                                     \
-       __init_timer_on_stack((timer), 0)
 
 #define __setup_timer(_timer, _fn, _data, _flags)                      \
        do {                                                            \
@@ -169,9 +151,7 @@ static inline void init_timer_on_stack_key(struct timer_list *timer,
 #define setup_pinned_deferrable_timer_on_stack(timer, fn, data)                \
        __setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE | TIMER_PINNED)
 
-#define TIMER_DATA_TYPE                unsigned long
-#define TIMER_FUNC_TYPE                void (*)(TIMER_DATA_TYPE)
-
+#ifndef CONFIG_LOCKDEP
 static inline void timer_setup(struct timer_list *timer,
                               void (*callback)(struct timer_list *),
                               unsigned int flags)
@@ -180,6 +160,28 @@ static inline void timer_setup(struct timer_list *timer,
                      (TIMER_DATA_TYPE)timer, flags);
 }
 
+static inline void timer_setup_on_stack(struct timer_list *timer,
+                              void (*callback)(struct timer_list *),
+                              unsigned int flags)
+{
+       __setup_timer_on_stack(timer, (TIMER_FUNC_TYPE)callback,
+                              (TIMER_DATA_TYPE)timer, flags);
+}
+#else
+/*
+ * Under LOCKDEP, the timer lock_class_key (set up in __init_timer) needs
+ * to be tied to the caller's context, so an inline (above) won't work. We
+ * do want to keep the inline for argument type checking, though.
+ */
+# define timer_setup(timer, callback, flags)                           \
+               __setup_timer((timer), (TIMER_FUNC_TYPE)(callback),     \
+                             (TIMER_DATA_TYPE)(timer), (flags))
+# define timer_setup_on_stack(timer, callback, flags)                  \
+               __setup_timer_on_stack((timer),                         \
+                                      (TIMER_FUNC_TYPE)(callback),     \
+                                      (TIMER_DATA_TYPE)(timer), (flags))
+#endif
+
 #define from_timer(var, callback_timer, timer_fieldname) \
        container_of(callback_timer, typeof(*var), timer_fieldname)
 
@@ -202,6 +204,7 @@ extern void add_timer_on(struct timer_list *timer, int cpu);
 extern int del_timer(struct timer_list * timer);
 extern int mod_timer(struct timer_list *timer, unsigned long expires);
 extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
+extern int timer_reduce(struct timer_list *timer, unsigned long expires);
 
 /*
  * The jiffies value which is added to now, when there is no timer
index 0eae11fc7a23fee792e13b4b16e0bf110d491cd5..01a050fc6650ab055315d1dd00f5309bbe263450 100644 (file)
@@ -18,7 +18,7 @@ struct workqueue_struct;
 
 struct work_struct;
 typedef void (*work_func_t)(struct work_struct *work);
-void delayed_work_timer_fn(unsigned long __data);
+void delayed_work_timer_fn(struct timer_list *t);
 
 /*
  * The first word is the work queue pointer and the flags rolled into
@@ -176,8 +176,8 @@ struct execute_work {
 
 #define __DELAYED_WORK_INITIALIZER(n, f, tflags) {                     \
        .work = __WORK_INITIALIZER((n).work, (f)),                      \
-       .timer = __TIMER_INITIALIZER(delayed_work_timer_fn,             \
-                                    0, (unsigned long)&(n),            \
+       .timer = __TIMER_INITIALIZER((TIMER_FUNC_TYPE)delayed_work_timer_fn,\
+                                    (TIMER_DATA_TYPE)&(n.timer),       \
                                     (tflags) | TIMER_IRQSAFE),         \
        }
 
@@ -219,7 +219,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
                                                                        \
                __init_work((_work), _onstack);                         \
                (_work)->data = (atomic_long_t) WORK_DATA_INIT();       \
-               lockdep_init_map(&(_work)->lockdep_map, #_work, &__key, 0); \
+               lockdep_init_map(&(_work)->lockdep_map, "(work_completion)"#_work, &__key, 0); \
                INIT_LIST_HEAD(&(_work)->entry);                        \
                (_work)->func = (_func);                                \
        } while (0)
@@ -242,8 +242,9 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
 #define __INIT_DELAYED_WORK(_work, _func, _tflags)                     \
        do {                                                            \
                INIT_WORK(&(_work)->work, (_func));                     \
-               __setup_timer(&(_work)->timer, delayed_work_timer_fn,   \
-                             (unsigned long)(_work),                   \
+               __setup_timer(&(_work)->timer,                          \
+                             (TIMER_FUNC_TYPE)delayed_work_timer_fn,   \
+                             (TIMER_DATA_TYPE)&(_work)->timer,         \
                              (_tflags) | TIMER_IRQSAFE);               \
        } while (0)
 
@@ -251,8 +252,8 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
        do {                                                            \
                INIT_WORK_ONSTACK(&(_work)->work, (_func));             \
                __setup_timer_on_stack(&(_work)->timer,                 \
-                                      delayed_work_timer_fn,           \
-                                      (unsigned long)(_work),          \
+                                      (TIMER_FUNC_TYPE)delayed_work_timer_fn,\
+                                      (TIMER_DATA_TYPE)&(_work)->timer,\
                                       (_tflags) | TIMER_IRQSAFE);      \
        } while (0)
 
@@ -399,7 +400,7 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
        static struct lock_class_key __key;                             \
        const char *__lock_name;                                        \
                                                                        \
-       __lock_name = #fmt#args;                                        \
+       __lock_name = "(wq_completion)"#fmt#args;                       \
                                                                        \
        __alloc_workqueue_key((fmt), (flags), (max_active),             \
                              &__key, __lock_name, ##args);             \
index 1e6df0eb058f1eedd5b84a52457273b2020e1c80..a10a3b1813f36c18f698e609b8f09beaf43d8d1e 100644 (file)
@@ -14,7 +14,6 @@
 struct tcf_idrinfo {
        spinlock_t      lock;
        struct idr      action_idr;
-       struct net      *net;
 };
 
 struct tc_action_ops;
@@ -106,7 +105,7 @@ struct tc_action_net {
 
 static inline
 int tc_action_net_init(struct tc_action_net *tn,
-                      const struct tc_action_ops *ops, struct net *net)
+                      const struct tc_action_ops *ops)
 {
        int err = 0;
 
@@ -114,7 +113,6 @@ int tc_action_net_init(struct tc_action_net *tn,
        if (!tn->idrinfo)
                return -ENOMEM;
        tn->ops = ops;
-       tn->idrinfo->net = net;
        spin_lock_init(&tn->idrinfo->lock);
        idr_init(&tn->idrinfo->action_idr);
        return err;
index 5d08c1950e7d76891ab244958b70c9d8808d92cd..ff68cf288f9bf3a3ac18d696e215980e4fee54f5 100644 (file)
@@ -984,12 +984,12 @@ static inline int sysctl_sync_threshold(struct netns_ipvs *ipvs)
 
 static inline int sysctl_sync_period(struct netns_ipvs *ipvs)
 {
-       return ACCESS_ONCE(ipvs->sysctl_sync_threshold[1]);
+       return READ_ONCE(ipvs->sysctl_sync_threshold[1]);
 }
 
 static inline unsigned int sysctl_sync_refresh_period(struct netns_ipvs *ipvs)
 {
-       return ACCESS_ONCE(ipvs->sysctl_sync_refresh_period);
+       return READ_ONCE(ipvs->sysctl_sync_refresh_period);
 }
 
 static inline int sysctl_sync_retries(struct netns_ipvs *ipvs)
@@ -1014,7 +1014,7 @@ static inline int sysctl_sloppy_sctp(struct netns_ipvs *ipvs)
 
 static inline int sysctl_sync_ports(struct netns_ipvs *ipvs)
 {
-       return ACCESS_ONCE(ipvs->sysctl_sync_ports);
+       return READ_ONCE(ipvs->sysctl_sync_ports);
 }
 
 static inline int sysctl_sync_persist_mode(struct netns_ipvs *ipvs)
index 079c69cae2f6d723d306dfbde7fa21f71a131ace..470c1c71e7f4443e296f031e92d4743385a4610e 100644 (file)
@@ -1165,8 +1165,8 @@ static inline u8 nft_genmask_next(const struct net *net)
 
 static inline u8 nft_genmask_cur(const struct net *net)
 {
-       /* Use ACCESS_ONCE() to prevent refetching the value for atomicity */
-       return 1 << ACCESS_ONCE(net->nft.gencursor);
+       /* Use READ_ONCE() to prevent refetching the value for atomicity */
+       return 1 << READ_ONCE(net->nft.gencursor);
 }
 
 #define NFT_GENMASK_ANY                ((1 << 0) | (1 << 1))
index 70ca2437740e41284d7b40b5c202d85fc2e6668b..8826747ef83e616156092f311282c4785621d923 100644 (file)
@@ -94,6 +94,7 @@ struct tcf_exts {
        __u32   type; /* for backward compat(TCA_OLD_COMPAT) */
        int nr_actions;
        struct tc_action **actions;
+       struct net *net;
 #endif
        /* Map to export classifier specific extension TLV types to the
         * generic extensions API. Unsupported extensions must be set to 0.
@@ -107,6 +108,7 @@ static inline int tcf_exts_init(struct tcf_exts *exts, int action, int police)
 #ifdef CONFIG_NET_CLS_ACT
        exts->type = 0;
        exts->nr_actions = 0;
+       exts->net = NULL;
        exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *),
                                GFP_KERNEL);
        if (!exts->actions)
@@ -117,6 +119,28 @@ static inline int tcf_exts_init(struct tcf_exts *exts, int action, int police)
        return 0;
 }
 
+/* Return false if the netns is being destroyed in cleanup_net(). Callers
+ * need to do cleanup synchronously in this case, otherwise may race with
+ * tc_action_net_exit(). Return true for other cases.
+ */
+static inline bool tcf_exts_get_net(struct tcf_exts *exts)
+{
+#ifdef CONFIG_NET_CLS_ACT
+       exts->net = maybe_get_net(exts->net);
+       return exts->net != NULL;
+#else
+       return true;
+#endif
+}
+
+static inline void tcf_exts_put_net(struct tcf_exts *exts)
+{
+#ifdef CONFIG_NET_CLS_ACT
+       if (exts->net)
+               put_net(exts->net);
+#endif
+}
+
 static inline void tcf_exts_to_list(const struct tcf_exts *exts,
                                    struct list_head *actions)
 {
index 722d3264d3bf92b42077eafc25aeff6477df12a5..cb8a273732cf667d47a7f43e5770ada588ce9ab7 100644 (file)
@@ -382,7 +382,7 @@ static inline struct net_device *fcoe_get_netdev(const struct fc_lport *lport)
 
 void fcoe_clean_pending_queue(struct fc_lport *);
 void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb);
-void fcoe_queue_timer(ulong lport);
+void fcoe_queue_timer(struct timer_list *t);
 int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen,
                           struct fcoe_percpu_s *fps);
 
index 6c0dc6155ee757b5e066b075316dc899f6dddddc..388aaf72b48023506e5037f52fcfea915ff03de9 100644 (file)
@@ -629,6 +629,7 @@ struct sas_task_slow {
         */
        struct timer_list     timer;
        struct completion     completion;
+       struct sas_task       *task;
 };
 
 #define SAS_TASK_STATE_PENDING      1
index feb58d45556064881bcddd8a1b403da13c6af358..4b9ee3009aa09b46e749509f85cd0fcb60d49b8b 100644 (file)
@@ -49,7 +49,8 @@ typedef union snd_seq_timestamp snd_seq_timestamp_t;
 #define SNDRV_SEQ_DEFAULT_CLIENT_EVENTS        200
 
 /* max delivery path length */
-#define SNDRV_SEQ_MAX_HOPS             10
+/* NOTE: this shouldn't be greater than MAX_LOCKDEP_SUBCLASSES */
+#define SNDRV_SEQ_MAX_HOPS             8
 
 /* max size of event size */
 #define SNDRV_SEQ_MAX_EVENT_LEN                0x3fffffff
index c4d76ff056c6efd3431a4ed7aa3c6f6888c69e80..7ae226ab6990832d64c43935dded32463e739790 100644 (file)
@@ -90,6 +90,8 @@ struct snd_timer {
        struct list_head ack_list_head;
        struct list_head sack_list_head; /* slow ack list head */
        struct tasklet_struct task_queue;
+       int max_instances;      /* upper limit of timer instances */
+       int num_instances;      /* current number of timer instances */
 };
 
 struct snd_timer_instance {
diff --git a/include/trace/events/irq_matrix.h b/include/trace/events/irq_matrix.h
new file mode 100644 (file)
index 0000000..267d4cb
--- /dev/null
@@ -0,0 +1,201 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM irq_matrix
+
+#if !defined(_TRACE_IRQ_MATRIX_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_IRQ_MATRIX_H
+
+#include <linux/tracepoint.h>
+
+struct irq_matrix;
+struct cpumap;
+
+DECLARE_EVENT_CLASS(irq_matrix_global,
+
+       TP_PROTO(struct irq_matrix *matrix),
+
+       TP_ARGS(matrix),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   online_maps             )
+               __field(        unsigned int,   global_available        )
+               __field(        unsigned int,   global_reserved         )
+               __field(        unsigned int,   total_allocated         )
+       ),
+
+       TP_fast_assign(
+               __entry->online_maps            = matrix->online_maps;
+               __entry->global_available       = matrix->global_available;
+               __entry->global_reserved        = matrix->global_reserved;
+               __entry->total_allocated        = matrix->total_allocated;
+       ),
+
+       TP_printk("online_maps=%d global_avl=%u, global_rsvd=%u, total_alloc=%u",
+                 __entry->online_maps, __entry->global_available,
+                 __entry->global_reserved, __entry->total_allocated)
+);
+
+DECLARE_EVENT_CLASS(irq_matrix_global_update,
+
+       TP_PROTO(int bit, struct irq_matrix *matrix),
+
+       TP_ARGS(bit, matrix),
+
+       TP_STRUCT__entry(
+               __field(        int,            bit                     )
+               __field(        unsigned int,   online_maps             )
+               __field(        unsigned int,   global_available        )
+               __field(        unsigned int,   global_reserved         )
+               __field(        unsigned int,   total_allocated         )
+       ),
+
+       TP_fast_assign(
+               __entry->bit                    = bit;
+               __entry->online_maps            = matrix->online_maps;
+               __entry->global_available       = matrix->global_available;
+               __entry->global_reserved        = matrix->global_reserved;
+               __entry->total_allocated        = matrix->total_allocated;
+       ),
+
+       TP_printk("bit=%d online_maps=%d global_avl=%u, global_rsvd=%u, total_alloc=%u",
+                 __entry->bit, __entry->online_maps,
+                 __entry->global_available, __entry->global_reserved,
+                 __entry->total_allocated)
+);
+
+DECLARE_EVENT_CLASS(irq_matrix_cpu,
+
+       TP_PROTO(int bit, unsigned int cpu, struct irq_matrix *matrix,
+                struct cpumap *cmap),
+
+       TP_ARGS(bit, cpu, matrix, cmap),
+
+       TP_STRUCT__entry(
+               __field(        int,            bit                     )
+               __field(        unsigned int,   cpu                     )
+               __field(        bool,           online                  )
+               __field(        unsigned int,   available               )
+               __field(        unsigned int,   allocated               )
+               __field(        unsigned int,   managed                 )
+               __field(        unsigned int,   online_maps             )
+               __field(        unsigned int,   global_available        )
+               __field(        unsigned int,   global_reserved         )
+               __field(        unsigned int,   total_allocated         )
+       ),
+
+       TP_fast_assign(
+               __entry->bit                    = bit;
+               __entry->cpu                    = cpu;
+               __entry->online                 = cmap->online;
+               __entry->available              = cmap->available;
+               __entry->allocated              = cmap->allocated;
+               __entry->managed                = cmap->managed;
+               __entry->online_maps            = matrix->online_maps;
+               __entry->global_available       = matrix->global_available;
+               __entry->global_reserved        = matrix->global_reserved;
+               __entry->total_allocated        = matrix->total_allocated;
+       ),
+
+       TP_printk("bit=%d cpu=%u online=%d avl=%u alloc=%u managed=%u online_maps=%u global_avl=%u, global_rsvd=%u, total_alloc=%u",
+                 __entry->bit, __entry->cpu, __entry->online,
+                 __entry->available, __entry->allocated,
+                 __entry->managed, __entry->online_maps,
+                 __entry->global_available, __entry->global_reserved,
+                 __entry->total_allocated)
+);
+
+DEFINE_EVENT(irq_matrix_global, irq_matrix_online,
+
+       TP_PROTO(struct irq_matrix *matrix),
+
+       TP_ARGS(matrix)
+);
+
+DEFINE_EVENT(irq_matrix_global, irq_matrix_offline,
+
+       TP_PROTO(struct irq_matrix *matrix),
+
+       TP_ARGS(matrix)
+);
+
+DEFINE_EVENT(irq_matrix_global, irq_matrix_reserve,
+
+       TP_PROTO(struct irq_matrix *matrix),
+
+       TP_ARGS(matrix)
+);
+
+DEFINE_EVENT(irq_matrix_global, irq_matrix_remove_reserved,
+
+       TP_PROTO(struct irq_matrix *matrix),
+
+       TP_ARGS(matrix)
+);
+
+DEFINE_EVENT(irq_matrix_global_update, irq_matrix_assign_system,
+
+       TP_PROTO(int bit, struct irq_matrix *matrix),
+
+       TP_ARGS(bit, matrix)
+);
+
+DEFINE_EVENT(irq_matrix_cpu, irq_matrix_alloc_reserved,
+
+       TP_PROTO(int bit, unsigned int cpu,
+                struct irq_matrix *matrix, struct cpumap *cmap),
+
+       TP_ARGS(bit, cpu, matrix, cmap)
+);
+
+DEFINE_EVENT(irq_matrix_cpu, irq_matrix_reserve_managed,
+
+       TP_PROTO(int bit, unsigned int cpu,
+                struct irq_matrix *matrix, struct cpumap *cmap),
+
+       TP_ARGS(bit, cpu, matrix, cmap)
+);
+
+DEFINE_EVENT(irq_matrix_cpu, irq_matrix_remove_managed,
+
+       TP_PROTO(int bit, unsigned int cpu,
+                struct irq_matrix *matrix, struct cpumap *cmap),
+
+       TP_ARGS(bit, cpu, matrix, cmap)
+);
+
+DEFINE_EVENT(irq_matrix_cpu, irq_matrix_alloc_managed,
+
+       TP_PROTO(int bit, unsigned int cpu,
+                struct irq_matrix *matrix, struct cpumap *cmap),
+
+       TP_ARGS(bit, cpu, matrix, cmap)
+);
+
+DEFINE_EVENT(irq_matrix_cpu, irq_matrix_assign,
+
+       TP_PROTO(int bit, unsigned int cpu,
+                struct irq_matrix *matrix, struct cpumap *cmap),
+
+       TP_ARGS(bit, cpu, matrix, cmap)
+);
+
+DEFINE_EVENT(irq_matrix_cpu, irq_matrix_alloc,
+
+       TP_PROTO(int bit, unsigned int cpu,
+                struct irq_matrix *matrix, struct cpumap *cmap),
+
+       TP_ARGS(bit, cpu, matrix, cmap)
+);
+
+DEFINE_EVENT(irq_matrix_cpu, irq_matrix_free,
+
+       TP_PROTO(int bit, unsigned int cpu,
+                struct irq_matrix *matrix, struct cpumap *cmap),
+
+       TP_ARGS(bit, cpu, matrix, cmap)
+);
+
+
+#endif /*  _TRACE_IRQ_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index da10aa21bebc847bd1c71d1ffed177494bcb774e..306b31de519417790a50ab9dcb510faafd44cb30 100644 (file)
@@ -118,7 +118,7 @@ static inline long __trace_sched_switch_state(bool preempt, struct task_struct *
        if (preempt)
                return TASK_STATE_MAX;
 
-       return __get_task_state(p);
+       return task_state_index(p);
 }
 #endif /* CREATE_TRACE_POINTS */
 
index 6598fb76d2c27741d2c916f914b70c5f472911f9..9816590d3ad24b0d7037eb65f9b84c3c571c9b53 100644 (file)
@@ -829,6 +829,7 @@ struct drm_i915_gem_exec_fence {
 
 #define I915_EXEC_FENCE_WAIT            (1<<0)
 #define I915_EXEC_FENCE_SIGNAL          (1<<1)
+#define __I915_EXEC_FENCE_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SIGNAL << 1))
        __u32 flags;
 };
 
index c58627c0d6fb07843f8f50582708011b8f0b87d7..e09a4f963dc068b87bae5b828430e92113412da2 100644 (file)
@@ -412,6 +412,7 @@ typedef struct elf64_shdr {
 #define NT_S390_VXRS_HIGH      0x30a   /* s390 vector registers 16-31 */
 #define NT_S390_GS_CB  0x30b           /* s390 guarded storage registers */
 #define NT_S390_GS_BC  0x30c           /* s390 guarded storage broadcast control block */
+#define NT_S390_RI_CB  0x30d           /* s390 runtime instrumentation */
 #define NT_ARM_VFP     0x400           /* ARM VFP/NEON registers */
 #define NT_ARM_TLS     0x401           /* ARM TLS register */
 #define NT_ARM_HW_BREAK        0x402           /* ARM hardware breakpoint registers */
index f65b92e0e1f914fb84b7a4e67a47e5125afb80cc..ee8220f8dcf5f5e16662580cc5c35ac66c322048 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#include <linux/compiler.h>
+#include <linux/compiler_types.h>
 
 #ifndef __always_inline
 #define __always_inline inline
index a92be0f492a9bef04caf3bcc4108bb134c015474..c1395b5bd432a0e4fe9275b8d4eece00a52999c2 100644 (file)
@@ -66,6 +66,9 @@
 #define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
 #define XATTR_NAME_SMACKMMAP XATTR_SECURITY_PREFIX XATTR_SMACK_MMAP
 
+#define XATTR_APPARMOR_SUFFIX "apparmor"
+#define XATTR_NAME_APPARMOR XATTR_SECURITY_PREFIX XATTR_APPARMOR_SUFFIX
+
 #define XATTR_CAPS_SUFFIX "capability"
 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
 
index 3c1faaa2af4aad761c427a092c929aeb1acb05f6..c1fd2863d4baebda22b48005e681a6f84e365d4f 100644 (file)
@@ -472,6 +472,13 @@ config TASK_IO_ACCOUNTING
 
 endmenu # "CPU/Task time and stats accounting"
 
+config CPU_ISOLATION
+       bool "CPU isolation"
+       help
+         Make sure that CPUs running critical tasks are not disturbed by
+         any source of "noise" such as unbound workqueues, timers, kthreads...
+         Unbound jobs get offloaded to housekeeping CPUs.
+
 source "kernel/rcu/Kconfig"
 
 config BUILD_BIN2C
index 0ee9c6866ada1d9877c6afd50e23237eab6dfb4c..3bdd8da90f6921825d0f08174ea2a57013ea1d66 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/cgroup.h>
 #include <linux/efi.h>
 #include <linux/tick.h>
+#include <linux/sched/isolation.h>
 #include <linux/interrupt.h>
 #include <linux/taskstats_kern.h>
 #include <linux/delayacct.h>
@@ -606,6 +607,7 @@ asmlinkage __visible void __init start_kernel(void)
        early_irq_init();
        init_IRQ();
        tick_init();
+       housekeeping_init();
        rcu_init_nohz();
        init_timers();
        hrtimers_init();
@@ -664,12 +666,12 @@ asmlinkage __visible void __init start_kernel(void)
        debug_objects_mem_init();
        setup_per_cpu_pageset();
        numa_policy_init();
+       acpi_early_init();
        if (late_time_init)
                late_time_init();
        calibrate_delay();
        pidmap_init();
        anon_vma_init();
-       acpi_early_init();
 #ifdef CONFIG_X86
        if (efi_enabled(EFI_RUNTIME_SERVICES))
                efi_enter_virtual_mode();
index 6670fbd3e466d3003ae3c20d5f321b6e0abb2069..d15c0ee4d95504a88337498045a84f53a6ae0d15 100644 (file)
@@ -147,7 +147,7 @@ static struct bsd_acct_struct *acct_get(struct pid_namespace *ns)
 again:
        smp_rmb();
        rcu_read_lock();
-       res = to_acct(ACCESS_ONCE(ns->bacct));
+       res = to_acct(READ_ONCE(ns->bacct));
        if (!res) {
                rcu_read_unlock();
                return NULL;
@@ -159,7 +159,7 @@ again:
        }
        rcu_read_unlock();
        mutex_lock(&res->lock);
-       if (res != to_acct(ACCESS_ONCE(ns->bacct))) {
+       if (res != to_acct(READ_ONCE(ns->bacct))) {
                mutex_unlock(&res->lock);
                acct_put(res);
                goto again;
index e2636737b69bd8bdd1a690e5453616effb9800d5..c4b9ab01bba53715c42afd38004801ae69e7b7b7 100644 (file)
@@ -492,7 +492,7 @@ static void *perf_event_fd_array_get_ptr(struct bpf_map *map,
 
        ee = ERR_PTR(-EOPNOTSUPP);
        event = perf_file->private_data;
-       if (perf_event_read_local(event, &value) == -EOPNOTSUPP)
+       if (perf_event_read_local(event, &value, NULL, NULL) == -EOPNOTSUPP)
                goto err_out;
 
        ee = bpf_event_entry_gen(perf_file, map_file);
index 4657e2924ecb1a72281cc70e3c46f25a2f2ce962..f7efa7b4d825a350ca980fe325fdf7ce2db0178f 100644 (file)
@@ -57,7 +57,7 @@
 #include <linux/backing-dev.h>
 #include <linux/sort.h>
 #include <linux/oom.h>
-
+#include <linux/sched/isolation.h>
 #include <linux/uaccess.h>
 #include <linux/atomic.h>
 #include <linux/mutex.h>
@@ -656,7 +656,6 @@ static int generate_sched_domains(cpumask_var_t **domains,
        int csn;                /* how many cpuset ptrs in csa so far */
        int i, j, k;            /* indices for partition finding loops */
        cpumask_var_t *doms;    /* resulting partition; i.e. sched domains */
-       cpumask_var_t non_isolated_cpus;  /* load balanced CPUs */
        struct sched_domain_attr *dattr;  /* attributes for custom domains */
        int ndoms = 0;          /* number of sched domains in result */
        int nslot;              /* next empty doms[] struct cpumask slot */
@@ -666,10 +665,6 @@ static int generate_sched_domains(cpumask_var_t **domains,
        dattr = NULL;
        csa = NULL;
 
-       if (!alloc_cpumask_var(&non_isolated_cpus, GFP_KERNEL))
-               goto done;
-       cpumask_andnot(non_isolated_cpus, cpu_possible_mask, cpu_isolated_map);
-
        /* Special case for the 99% of systems with one, full, sched domain */
        if (is_sched_load_balance(&top_cpuset)) {
                ndoms = 1;
@@ -683,7 +678,7 @@ static int generate_sched_domains(cpumask_var_t **domains,
                        update_domain_attr_tree(dattr, &top_cpuset);
                }
                cpumask_and(doms[0], top_cpuset.effective_cpus,
-                                    non_isolated_cpus);
+                           housekeeping_cpumask(HK_FLAG_DOMAIN));
 
                goto done;
        }
@@ -707,7 +702,8 @@ static int generate_sched_domains(cpumask_var_t **domains,
                 */
                if (!cpumask_empty(cp->cpus_allowed) &&
                    !(is_sched_load_balance(cp) &&
-                     cpumask_intersects(cp->cpus_allowed, non_isolated_cpus)))
+                     cpumask_intersects(cp->cpus_allowed,
+                                        housekeeping_cpumask(HK_FLAG_DOMAIN))))
                        continue;
 
                if (is_sched_load_balance(cp))
@@ -789,7 +785,7 @@ restart:
 
                        if (apn == b->pn) {
                                cpumask_or(dp, dp, b->effective_cpus);
-                               cpumask_and(dp, dp, non_isolated_cpus);
+                               cpumask_and(dp, dp, housekeeping_cpumask(HK_FLAG_DOMAIN));
                                if (dattr)
                                        update_domain_attr_tree(dattr + nslot, b);
 
@@ -802,7 +798,6 @@ restart:
        BUG_ON(nslot != ndoms);
 
 done:
-       free_cpumask_var(non_isolated_cpus);
        kfree(csa);
 
        /*
index 10cdb9c26b5d12d41ddacda43e335a9d635c66a7..4c39c05e029a7f357cb872ffa982d6ca2381fddb 100644 (file)
@@ -209,7 +209,7 @@ static int event_function(void *info)
        struct perf_event_context *task_ctx = cpuctx->task_ctx;
        int ret = 0;
 
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        perf_ctx_lock(cpuctx, task_ctx);
        /*
@@ -306,7 +306,7 @@ static void event_function_local(struct perf_event *event, event_f func, void *d
        struct task_struct *task = READ_ONCE(ctx->task);
        struct perf_event_context *task_ctx = NULL;
 
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        if (task) {
                if (task == TASK_TOMBSTONE)
@@ -582,6 +582,88 @@ static inline u64 perf_event_clock(struct perf_event *event)
        return event->clock();
 }
 
+/*
+ * State based event timekeeping...
+ *
+ * The basic idea is to use event->state to determine which (if any) time
+ * fields to increment with the current delta. This means we only need to
+ * update timestamps when we change state or when they are explicitly requested
+ * (read).
+ *
+ * Event groups make things a little more complicated, but not terribly so. The
+ * rules for a group are that if the group leader is OFF the entire group is
+ * OFF, irrespecive of what the group member states are. This results in
+ * __perf_effective_state().
+ *
+ * A futher ramification is that when a group leader flips between OFF and
+ * !OFF, we need to update all group member times.
+ *
+ *
+ * NOTE: perf_event_time() is based on the (cgroup) context time, and thus we
+ * need to make sure the relevant context time is updated before we try and
+ * update our timestamps.
+ */
+
+static __always_inline enum perf_event_state
+__perf_effective_state(struct perf_event *event)
+{
+       struct perf_event *leader = event->group_leader;
+
+       if (leader->state <= PERF_EVENT_STATE_OFF)
+               return leader->state;
+
+       return event->state;
+}
+
+static __always_inline void
+__perf_update_times(struct perf_event *event, u64 now, u64 *enabled, u64 *running)
+{
+       enum perf_event_state state = __perf_effective_state(event);
+       u64 delta = now - event->tstamp;
+
+       *enabled = event->total_time_enabled;
+       if (state >= PERF_EVENT_STATE_INACTIVE)
+               *enabled += delta;
+
+       *running = event->total_time_running;
+       if (state >= PERF_EVENT_STATE_ACTIVE)
+               *running += delta;
+}
+
+static void perf_event_update_time(struct perf_event *event)
+{
+       u64 now = perf_event_time(event);
+
+       __perf_update_times(event, now, &event->total_time_enabled,
+                                       &event->total_time_running);
+       event->tstamp = now;
+}
+
+static void perf_event_update_sibling_time(struct perf_event *leader)
+{
+       struct perf_event *sibling;
+
+       list_for_each_entry(sibling, &leader->sibling_list, group_entry)
+               perf_event_update_time(sibling);
+}
+
+static void
+perf_event_set_state(struct perf_event *event, enum perf_event_state state)
+{
+       if (event->state == state)
+               return;
+
+       perf_event_update_time(event);
+       /*
+        * If a group leader gets enabled/disabled all its siblings
+        * are affected too.
+        */
+       if ((event->state < 0) ^ (state < 0))
+               perf_event_update_sibling_time(event);
+
+       WRITE_ONCE(event->state, state);
+}
+
 #ifdef CONFIG_CGROUP_PERF
 
 static inline bool
@@ -841,40 +923,6 @@ perf_cgroup_set_shadow_time(struct perf_event *event, u64 now)
        event->shadow_ctx_time = now - t->timestamp;
 }
 
-static inline void
-perf_cgroup_defer_enabled(struct perf_event *event)
-{
-       /*
-        * when the current task's perf cgroup does not match
-        * the event's, we need to remember to call the
-        * perf_mark_enable() function the first time a task with
-        * a matching perf cgroup is scheduled in.
-        */
-       if (is_cgroup_event(event) && !perf_cgroup_match(event))
-               event->cgrp_defer_enabled = 1;
-}
-
-static inline void
-perf_cgroup_mark_enabled(struct perf_event *event,
-                        struct perf_event_context *ctx)
-{
-       struct perf_event *sub;
-       u64 tstamp = perf_event_time(event);
-
-       if (!event->cgrp_defer_enabled)
-               return;
-
-       event->cgrp_defer_enabled = 0;
-
-       event->tstamp_enabled = tstamp - event->total_time_enabled;
-       list_for_each_entry(sub, &event->sibling_list, group_entry) {
-               if (sub->state >= PERF_EVENT_STATE_INACTIVE) {
-                       sub->tstamp_enabled = tstamp - sub->total_time_enabled;
-                       sub->cgrp_defer_enabled = 0;
-               }
-       }
-}
-
 /*
  * Update cpuctx->cgrp so that it is set when first cgroup event is added and
  * cleared when last cgroup event is removed.
@@ -974,17 +1022,6 @@ static inline u64 perf_cgroup_event_time(struct perf_event *event)
        return 0;
 }
 
-static inline void
-perf_cgroup_defer_enabled(struct perf_event *event)
-{
-}
-
-static inline void
-perf_cgroup_mark_enabled(struct perf_event *event,
-                        struct perf_event_context *ctx)
-{
-}
-
 static inline void
 list_update_cgroup_event(struct perf_event *event,
                         struct perf_event_context *ctx, bool add)
@@ -1006,7 +1043,7 @@ static enum hrtimer_restart perf_mux_hrtimer_handler(struct hrtimer *hr)
        struct perf_cpu_context *cpuctx;
        int rotations = 0;
 
-       WARN_ON(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        cpuctx = container_of(hr, struct perf_cpu_context, hrtimer);
        rotations = perf_rotate_context(cpuctx);
@@ -1093,7 +1130,7 @@ static void perf_event_ctx_activate(struct perf_event_context *ctx)
 {
        struct list_head *head = this_cpu_ptr(&active_ctx_list);
 
-       WARN_ON(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        WARN_ON(!list_empty(&ctx->active_ctx_list));
 
@@ -1102,7 +1139,7 @@ static void perf_event_ctx_activate(struct perf_event_context *ctx)
 
 static void perf_event_ctx_deactivate(struct perf_event_context *ctx)
 {
-       WARN_ON(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        WARN_ON(list_empty(&ctx->active_ctx_list));
 
@@ -1202,7 +1239,7 @@ perf_event_ctx_lock_nested(struct perf_event *event, int nesting)
 
 again:
        rcu_read_lock();
-       ctx = ACCESS_ONCE(event->ctx);
+       ctx = READ_ONCE(event->ctx);
        if (!atomic_inc_not_zero(&ctx->refcount)) {
                rcu_read_unlock();
                goto again;
@@ -1398,60 +1435,6 @@ static u64 perf_event_time(struct perf_event *event)
        return ctx ? ctx->time : 0;
 }
 
-/*
- * Update the total_time_enabled and total_time_running fields for a event.
- */
-static void update_event_times(struct perf_event *event)
-{
-       struct perf_event_context *ctx = event->ctx;
-       u64 run_end;
-
-       lockdep_assert_held(&ctx->lock);
-
-       if (event->state < PERF_EVENT_STATE_INACTIVE ||
-           event->group_leader->state < PERF_EVENT_STATE_INACTIVE)
-               return;
-
-       /*
-        * in cgroup mode, time_enabled represents
-        * the time the event was enabled AND active
-        * tasks were in the monitored cgroup. This is
-        * independent of the activity of the context as
-        * there may be a mix of cgroup and non-cgroup events.
-        *
-        * That is why we treat cgroup events differently
-        * here.
-        */
-       if (is_cgroup_event(event))
-               run_end = perf_cgroup_event_time(event);
-       else if (ctx->is_active)
-               run_end = ctx->time;
-       else
-               run_end = event->tstamp_stopped;
-
-       event->total_time_enabled = run_end - event->tstamp_enabled;
-
-       if (event->state == PERF_EVENT_STATE_INACTIVE)
-               run_end = event->tstamp_stopped;
-       else
-               run_end = perf_event_time(event);
-
-       event->total_time_running = run_end - event->tstamp_running;
-
-}
-
-/*
- * Update total_time_enabled and total_time_running for all events in a group.
- */
-static void update_group_times(struct perf_event *leader)
-{
-       struct perf_event *event;
-
-       update_event_times(leader);
-       list_for_each_entry(event, &leader->sibling_list, group_entry)
-               update_event_times(event);
-}
-
 static enum event_type_t get_event_type(struct perf_event *event)
 {
        struct perf_event_context *ctx = event->ctx;
@@ -1494,6 +1477,8 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
        WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT);
        event->attach_state |= PERF_ATTACH_CONTEXT;
 
+       event->tstamp = perf_event_time(event);
+
        /*
         * If we're a stand alone event or group leader, we go to the context
         * list, group events are kept attached to the group so that
@@ -1701,8 +1686,6 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
        if (event->group_leader == event)
                list_del_init(&event->group_entry);
 
-       update_group_times(event);
-
        /*
         * If event was in error state, then keep it
         * that way, otherwise bogus counts will be
@@ -1711,7 +1694,7 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
         * of the event
         */
        if (event->state > PERF_EVENT_STATE_OFF)
-               event->state = PERF_EVENT_STATE_OFF;
+               perf_event_set_state(event, PERF_EVENT_STATE_OFF);
 
        ctx->generation++;
 }
@@ -1810,38 +1793,24 @@ event_sched_out(struct perf_event *event,
                  struct perf_cpu_context *cpuctx,
                  struct perf_event_context *ctx)
 {
-       u64 tstamp = perf_event_time(event);
-       u64 delta;
+       enum perf_event_state state = PERF_EVENT_STATE_INACTIVE;
 
        WARN_ON_ONCE(event->ctx != ctx);
        lockdep_assert_held(&ctx->lock);
 
-       /*
-        * An event which could not be activated because of
-        * filter mismatch still needs to have its timings
-        * maintained, otherwise bogus information is return
-        * via read() for time_enabled, time_running:
-        */
-       if (event->state == PERF_EVENT_STATE_INACTIVE &&
-           !event_filter_match(event)) {
-               delta = tstamp - event->tstamp_stopped;
-               event->tstamp_running += delta;
-               event->tstamp_stopped = tstamp;
-       }
-
        if (event->state != PERF_EVENT_STATE_ACTIVE)
                return;
 
        perf_pmu_disable(event->pmu);
 
-       event->tstamp_stopped = tstamp;
        event->pmu->del(event, 0);
        event->oncpu = -1;
-       event->state = PERF_EVENT_STATE_INACTIVE;
+
        if (event->pending_disable) {
                event->pending_disable = 0;
-               event->state = PERF_EVENT_STATE_OFF;
+               state = PERF_EVENT_STATE_OFF;
        }
+       perf_event_set_state(event, state);
 
        if (!is_software_event(event))
                cpuctx->active_oncpu--;
@@ -1861,7 +1830,9 @@ group_sched_out(struct perf_event *group_event,
                struct perf_event_context *ctx)
 {
        struct perf_event *event;
-       int state = group_event->state;
+
+       if (group_event->state != PERF_EVENT_STATE_ACTIVE)
+               return;
 
        perf_pmu_disable(ctx->pmu);
 
@@ -1875,7 +1846,7 @@ group_sched_out(struct perf_event *group_event,
 
        perf_pmu_enable(ctx->pmu);
 
-       if (state == PERF_EVENT_STATE_ACTIVE && group_event->attr.exclusive)
+       if (group_event->attr.exclusive)
                cpuctx->exclusive = 0;
 }
 
@@ -1895,6 +1866,11 @@ __perf_remove_from_context(struct perf_event *event,
 {
        unsigned long flags = (unsigned long)info;
 
+       if (ctx->is_active & EVENT_TIME) {
+               update_context_time(ctx);
+               update_cgrp_time_from_cpuctx(cpuctx);
+       }
+
        event_sched_out(event, cpuctx, ctx);
        if (flags & DETACH_GROUP)
                perf_group_detach(event);
@@ -1957,14 +1933,17 @@ static void __perf_event_disable(struct perf_event *event,
        if (event->state < PERF_EVENT_STATE_INACTIVE)
                return;
 
-       update_context_time(ctx);
-       update_cgrp_time_from_event(event);
-       update_group_times(event);
+       if (ctx->is_active & EVENT_TIME) {
+               update_context_time(ctx);
+               update_cgrp_time_from_event(event);
+       }
+
        if (event == event->group_leader)
                group_sched_out(event, cpuctx, ctx);
        else
                event_sched_out(event, cpuctx, ctx);
-       event->state = PERF_EVENT_STATE_OFF;
+
+       perf_event_set_state(event, PERF_EVENT_STATE_OFF);
 }
 
 /*
@@ -2021,8 +2000,7 @@ void perf_event_disable_inatomic(struct perf_event *event)
 }
 
 static void perf_set_shadow_time(struct perf_event *event,
-                                struct perf_event_context *ctx,
-                                u64 tstamp)
+                                struct perf_event_context *ctx)
 {
        /*
         * use the correct time source for the time snapshot
@@ -2050,9 +2028,9 @@ static void perf_set_shadow_time(struct perf_event *event,
         * is cleaner and simpler to understand.
         */
        if (is_cgroup_event(event))
-               perf_cgroup_set_shadow_time(event, tstamp);
+               perf_cgroup_set_shadow_time(event, event->tstamp);
        else
-               event->shadow_ctx_time = tstamp - ctx->timestamp;
+               event->shadow_ctx_time = event->tstamp - ctx->timestamp;
 }
 
 #define MAX_INTERRUPTS (~0ULL)
@@ -2065,7 +2043,6 @@ event_sched_in(struct perf_event *event,
                 struct perf_cpu_context *cpuctx,
                 struct perf_event_context *ctx)
 {
-       u64 tstamp = perf_event_time(event);
        int ret = 0;
 
        lockdep_assert_held(&ctx->lock);
@@ -2075,11 +2052,12 @@ event_sched_in(struct perf_event *event,
 
        WRITE_ONCE(event->oncpu, smp_processor_id());
        /*
-        * Order event::oncpu write to happen before the ACTIVE state
-        * is visible.
+        * Order event::oncpu write to happen before the ACTIVE state is
+        * visible. This allows perf_event_{stop,read}() to observe the correct
+        * ->oncpu if it sees ACTIVE.
         */
        smp_wmb();
-       WRITE_ONCE(event->state, PERF_EVENT_STATE_ACTIVE);
+       perf_event_set_state(event, PERF_EVENT_STATE_ACTIVE);
 
        /*
         * Unthrottle events, since we scheduled we might have missed several
@@ -2091,26 +2069,19 @@ event_sched_in(struct perf_event *event,
                event->hw.interrupts = 0;
        }
 
-       /*
-        * The new state must be visible before we turn it on in the hardware:
-        */
-       smp_wmb();
-
        perf_pmu_disable(event->pmu);
 
-       perf_set_shadow_time(event, ctx, tstamp);
+       perf_set_shadow_time(event, ctx);
 
        perf_log_itrace_start(event);
 
        if (event->pmu->add(event, PERF_EF_START)) {
-               event->state = PERF_EVENT_STATE_INACTIVE;
+               perf_event_set_state(event, PERF_EVENT_STATE_INACTIVE);
                event->oncpu = -1;
                ret = -EAGAIN;
                goto out;
        }
 
-       event->tstamp_running += tstamp - event->tstamp_stopped;
-
        if (!is_software_event(event))
                cpuctx->active_oncpu++;
        if (!ctx->nr_active++)
@@ -2134,8 +2105,6 @@ group_sched_in(struct perf_event *group_event,
 {
        struct perf_event *event, *partial_group = NULL;
        struct pmu *pmu = ctx->pmu;
-       u64 now = ctx->time;
-       bool simulate = false;
 
        if (group_event->state == PERF_EVENT_STATE_OFF)
                return 0;
@@ -2165,27 +2134,13 @@ group_error:
        /*
         * Groups can be scheduled in as one unit only, so undo any
         * partial group before returning:
-        * The events up to the failed event are scheduled out normally,
-        * tstamp_stopped will be updated.
-        *
-        * The failed events and the remaining siblings need to have
-        * their timings updated as if they had gone thru event_sched_in()
-        * and event_sched_out(). This is required to get consistent timings
-        * across the group. This also takes care of the case where the group
-        * could never be scheduled by ensuring tstamp_stopped is set to mark
-        * the time the event was actually stopped, such that time delta
-        * calculation in update_event_times() is correct.
+        * The events up to the failed event are scheduled out normally.
         */
        list_for_each_entry(event, &group_event->sibling_list, group_entry) {
                if (event == partial_group)
-                       simulate = true;
+                       break;
 
-               if (simulate) {
-                       event->tstamp_running += now - event->tstamp_stopped;
-                       event->tstamp_stopped = now;
-               } else {
-                       event_sched_out(event, cpuctx, ctx);
-               }
+               event_sched_out(event, cpuctx, ctx);
        }
        event_sched_out(group_event, cpuctx, ctx);
 
@@ -2227,46 +2182,11 @@ static int group_can_go_on(struct perf_event *event,
        return can_add_hw;
 }
 
-/*
- * Complement to update_event_times(). This computes the tstamp_* values to
- * continue 'enabled' state from @now, and effectively discards the time
- * between the prior tstamp_stopped and now (as we were in the OFF state, or
- * just switched (context) time base).
- *
- * This further assumes '@event->state == INACTIVE' (we just came from OFF) and
- * cannot have been scheduled in yet. And going into INACTIVE state means
- * '@event->tstamp_stopped = @now'.
- *
- * Thus given the rules of update_event_times():
- *
- *   total_time_enabled = tstamp_stopped - tstamp_enabled
- *   total_time_running = tstamp_stopped - tstamp_running
- *
- * We can insert 'tstamp_stopped == now' and reverse them to compute new
- * tstamp_* values.
- */
-static void __perf_event_enable_time(struct perf_event *event, u64 now)
-{
-       WARN_ON_ONCE(event->state != PERF_EVENT_STATE_INACTIVE);
-
-       event->tstamp_stopped = now;
-       event->tstamp_enabled = now - event->total_time_enabled;
-       event->tstamp_running = now - event->total_time_running;
-}
-
 static void add_event_to_ctx(struct perf_event *event,
                               struct perf_event_context *ctx)
 {
-       u64 tstamp = perf_event_time(event);
-
        list_add_event(event, ctx);
        perf_group_attach(event);
-       /*
-        * We can be called with event->state == STATE_OFF when we create with
-        * .disabled = 1. In that case the IOC_ENABLE will call this function.
-        */
-       if (event->state == PERF_EVENT_STATE_INACTIVE)
-               __perf_event_enable_time(event, tstamp);
 }
 
 static void ctx_sched_out(struct perf_event_context *ctx,
@@ -2497,28 +2417,6 @@ again:
        raw_spin_unlock_irq(&ctx->lock);
 }
 
-/*
- * Put a event into inactive state and update time fields.
- * Enabling the leader of a group effectively enables all
- * the group members that aren't explicitly disabled, so we
- * have to update their ->tstamp_enabled also.
- * Note: this works for group members as well as group leaders
- * since the non-leader members' sibling_lists will be empty.
- */
-static void __perf_event_mark_enabled(struct perf_event *event)
-{
-       struct perf_event *sub;
-       u64 tstamp = perf_event_time(event);
-
-       event->state = PERF_EVENT_STATE_INACTIVE;
-       __perf_event_enable_time(event, tstamp);
-       list_for_each_entry(sub, &event->sibling_list, group_entry) {
-               /* XXX should not be > INACTIVE if event isn't */
-               if (sub->state >= PERF_EVENT_STATE_INACTIVE)
-                       __perf_event_enable_time(sub, tstamp);
-       }
-}
-
 /*
  * Cross CPU call to enable a performance event
  */
@@ -2537,14 +2435,12 @@ static void __perf_event_enable(struct perf_event *event,
        if (ctx->is_active)
                ctx_sched_out(ctx, cpuctx, EVENT_TIME);
 
-       __perf_event_mark_enabled(event);
+       perf_event_set_state(event, PERF_EVENT_STATE_INACTIVE);
 
        if (!ctx->is_active)
                return;
 
        if (!event_filter_match(event)) {
-               if (is_cgroup_event(event))
-                       perf_cgroup_defer_enabled(event);
                ctx_sched_in(ctx, cpuctx, EVENT_TIME, current);
                return;
        }
@@ -2864,18 +2760,10 @@ static void __perf_event_sync_stat(struct perf_event *event,
         * we know the event must be on the current CPU, therefore we
         * don't need to use it.
         */
-       switch (event->state) {
-       case PERF_EVENT_STATE_ACTIVE:
+       if (event->state == PERF_EVENT_STATE_ACTIVE)
                event->pmu->read(event);
-               /* fall-through */
-
-       case PERF_EVENT_STATE_INACTIVE:
-               update_event_times(event);
-               break;
 
-       default:
-               break;
-       }
+       perf_event_update_time(event);
 
        /*
         * In order to keep per-task stats reliable we need to flip the event
@@ -3112,10 +3000,6 @@ ctx_pinned_sched_in(struct perf_event_context *ctx,
                if (!event_filter_match(event))
                        continue;
 
-               /* may need to reset tstamp_enabled */
-               if (is_cgroup_event(event))
-                       perf_cgroup_mark_enabled(event, ctx);
-
                if (group_can_go_on(event, cpuctx, 1))
                        group_sched_in(event, cpuctx, ctx);
 
@@ -3123,10 +3007,8 @@ ctx_pinned_sched_in(struct perf_event_context *ctx,
                 * If this pinned group hasn't been scheduled,
                 * put it in error state.
                 */
-               if (event->state == PERF_EVENT_STATE_INACTIVE) {
-                       update_group_times(event);
-                       event->state = PERF_EVENT_STATE_ERROR;
-               }
+               if (event->state == PERF_EVENT_STATE_INACTIVE)
+                       perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
        }
 }
 
@@ -3148,10 +3030,6 @@ ctx_flexible_sched_in(struct perf_event_context *ctx,
                if (!event_filter_match(event))
                        continue;
 
-               /* may need to reset tstamp_enabled */
-               if (is_cgroup_event(event))
-                       perf_cgroup_mark_enabled(event, ctx);
-
                if (group_can_go_on(event, cpuctx, can_add_hw)) {
                        if (group_sched_in(event, cpuctx, ctx))
                                can_add_hw = 0;
@@ -3523,7 +3401,7 @@ void perf_event_task_tick(void)
        struct perf_event_context *ctx, *tmp;
        int throttled;
 
-       WARN_ON(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        __this_cpu_inc(perf_throttled_seq);
        throttled = __this_cpu_xchg(perf_throttled_count, 0);
@@ -3543,7 +3421,7 @@ static int event_enable_on_exec(struct perf_event *event,
        if (event->state >= PERF_EVENT_STATE_INACTIVE)
                return 0;
 
-       __perf_event_mark_enabled(event);
+       perf_event_set_state(event, PERF_EVENT_STATE_INACTIVE);
 
        return 1;
 }
@@ -3637,12 +3515,15 @@ static void __perf_event_read(void *info)
                return;
 
        raw_spin_lock(&ctx->lock);
-       if (ctx->is_active) {
+       if (ctx->is_active & EVENT_TIME) {
                update_context_time(ctx);
                update_cgrp_time_from_event(event);
        }
 
-       update_event_times(event);
+       perf_event_update_time(event);
+       if (data->group)
+               perf_event_update_sibling_time(event);
+
        if (event->state != PERF_EVENT_STATE_ACTIVE)
                goto unlock;
 
@@ -3657,7 +3538,6 @@ static void __perf_event_read(void *info)
        pmu->read(event);
 
        list_for_each_entry(sub, &event->sibling_list, group_entry) {
-               update_event_times(sub);
                if (sub->state == PERF_EVENT_STATE_ACTIVE) {
                        /*
                         * Use sibling's PMU rather than @event's since
@@ -3686,7 +3566,8 @@ static inline u64 perf_event_count(struct perf_event *event)
  *     will not be local and we cannot read them atomically
  *   - must not have a pmu::count method
  */
-int perf_event_read_local(struct perf_event *event, u64 *value)
+int perf_event_read_local(struct perf_event *event, u64 *value,
+                         u64 *enabled, u64 *running)
 {
        unsigned long flags;
        int ret = 0;
@@ -3720,6 +3601,7 @@ int perf_event_read_local(struct perf_event *event, u64 *value)
                goto out;
        }
 
+
        /*
         * If the event is currently on this CPU, its either a per-task event,
         * or local to this CPU. Furthermore it means its ACTIVE (otherwise
@@ -3729,6 +3611,16 @@ int perf_event_read_local(struct perf_event *event, u64 *value)
                event->pmu->read(event);
 
        *value = local64_read(&event->count);
+       if (enabled || running) {
+               u64 now = event->shadow_ctx_time + perf_clock();
+               u64 __enabled, __running;
+
+               __perf_update_times(event, now, &__enabled, &__running);
+               if (enabled)
+                       *enabled = __enabled;
+               if (running)
+                       *running = __running;
+       }
 out:
        local_irq_restore(flags);
 
@@ -3737,23 +3629,35 @@ out:
 
 static int perf_event_read(struct perf_event *event, bool group)
 {
+       enum perf_event_state state = READ_ONCE(event->state);
        int event_cpu, ret = 0;
 
        /*
         * If event is enabled and currently active on a CPU, update the
         * value in the event structure:
         */
-       if (event->state == PERF_EVENT_STATE_ACTIVE) {
-               struct perf_read_data data = {
-                       .event = event,
-                       .group = group,
-                       .ret = 0,
-               };
+again:
+       if (state == PERF_EVENT_STATE_ACTIVE) {
+               struct perf_read_data data;
+
+               /*
+                * Orders the ->state and ->oncpu loads such that if we see
+                * ACTIVE we must also see the right ->oncpu.
+                *
+                * Matches the smp_wmb() from event_sched_in().
+                */
+               smp_rmb();
 
                event_cpu = READ_ONCE(event->oncpu);
                if ((unsigned)event_cpu >= nr_cpu_ids)
                        return 0;
 
+               data = (struct perf_read_data){
+                       .event = event,
+                       .group = group,
+                       .ret = 0,
+               };
+
                preempt_disable();
                event_cpu = __perf_event_read_cpu(event, event_cpu);
 
@@ -3770,24 +3674,30 @@ static int perf_event_read(struct perf_event *event, bool group)
                (void)smp_call_function_single(event_cpu, __perf_event_read, &data, 1);
                preempt_enable();
                ret = data.ret;
-       } else if (event->state == PERF_EVENT_STATE_INACTIVE) {
+
+       } else if (state == PERF_EVENT_STATE_INACTIVE) {
                struct perf_event_context *ctx = event->ctx;
                unsigned long flags;
 
                raw_spin_lock_irqsave(&ctx->lock, flags);
+               state = event->state;
+               if (state != PERF_EVENT_STATE_INACTIVE) {
+                       raw_spin_unlock_irqrestore(&ctx->lock, flags);
+                       goto again;
+               }
+
                /*
-                * may read while context is not active
-                * (e.g., thread is blocked), in that case
-                * we cannot update context time
+                * May read while context is not active (e.g., thread is
+                * blocked), in that case we cannot update context time
                 */
-               if (ctx->is_active) {
+               if (ctx->is_active & EVENT_TIME) {
                        update_context_time(ctx);
                        update_cgrp_time_from_event(event);
                }
+
+               perf_event_update_time(event);
                if (group)
-                       update_group_times(event);
-               else
-                       update_event_times(event);
+                       perf_event_update_sibling_time(event);
                raw_spin_unlock_irqrestore(&ctx->lock, flags);
        }
 
@@ -4233,7 +4143,7 @@ static void perf_remove_from_owner(struct perf_event *event)
         * indeed free this event, otherwise we need to serialize on
         * owner->perf_event_mutex.
         */
-       owner = lockless_dereference(event->owner);
+       owner = READ_ONCE(event->owner);
        if (owner) {
                /*
                 * Since delayed_put_task_struct() also drops the last
@@ -4330,7 +4240,7 @@ again:
                 * Cannot change, child events are not migrated, see the
                 * comment with perf_event_ctx_lock_nested().
                 */
-               ctx = lockless_dereference(child->ctx);
+               ctx = READ_ONCE(child->ctx);
                /*
                 * Since child_mutex nests inside ctx::mutex, we must jump
                 * through hoops. We start by grabbing a reference on the ctx.
@@ -4390,7 +4300,7 @@ static int perf_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
+static u64 __perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
 {
        struct perf_event *child;
        u64 total = 0;
@@ -4418,6 +4328,18 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
 
        return total;
 }
+
+u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
+{
+       struct perf_event_context *ctx;
+       u64 count;
+
+       ctx = perf_event_ctx_lock(event);
+       count = __perf_event_read_value(event, enabled, running);
+       perf_event_ctx_unlock(event, ctx);
+
+       return count;
+}
 EXPORT_SYMBOL_GPL(perf_event_read_value);
 
 static int __perf_read_group_add(struct perf_event *leader,
@@ -4433,6 +4355,8 @@ static int __perf_read_group_add(struct perf_event *leader,
        if (ret)
                return ret;
 
+       raw_spin_lock_irqsave(&ctx->lock, flags);
+
        /*
         * Since we co-schedule groups, {enabled,running} times of siblings
         * will be identical to those of the leader, so we only publish one
@@ -4455,8 +4379,6 @@ static int __perf_read_group_add(struct perf_event *leader,
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(leader);
 
-       raw_spin_lock_irqsave(&ctx->lock, flags);
-
        list_for_each_entry(sub, &leader->sibling_list, group_entry) {
                values[n++] += perf_event_count(sub);
                if (read_format & PERF_FORMAT_ID)
@@ -4520,7 +4442,7 @@ static int perf_read_one(struct perf_event *event,
        u64 values[4];
        int n = 0;
 
-       values[n++] = perf_event_read_value(event, &enabled, &running);
+       values[n++] = __perf_event_read_value(event, &enabled, &running);
        if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
                values[n++] = enabled;
        if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
@@ -4899,8 +4821,7 @@ static void calc_timer_values(struct perf_event *event,
 
        *now = perf_clock();
        ctx_time = event->shadow_ctx_time + *now;
-       *enabled = ctx_time - event->tstamp_enabled;
-       *running = ctx_time - event->tstamp_running;
+       __perf_update_times(event, ctx_time, enabled, running);
 }
 
 static void perf_event_init_userpage(struct perf_event *event)
@@ -5304,8 +5225,8 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
                if (!rb)
                        goto aux_unlock;
 
-               aux_offset = ACCESS_ONCE(rb->user_page->aux_offset);
-               aux_size = ACCESS_ONCE(rb->user_page->aux_size);
+               aux_offset = READ_ONCE(rb->user_page->aux_offset);
+               aux_size = READ_ONCE(rb->user_page->aux_size);
 
                if (aux_offset < perf_data_size(rb) + PAGE_SIZE)
                        goto aux_unlock;
@@ -8074,6 +7995,7 @@ static void bpf_overflow_handler(struct perf_event *event,
        struct bpf_perf_event_data_kern ctx = {
                .data = data,
                .regs = regs,
+               .event = event,
        };
        int ret = 0;
 
@@ -9404,6 +9326,11 @@ static void account_event(struct perf_event *event)
                inc = true;
 
        if (inc) {
+               /*
+                * We need the mutex here because static_branch_enable()
+                * must complete *before* the perf_sched_count increment
+                * becomes visible.
+                */
                if (atomic_inc_not_zero(&perf_sched_count))
                        goto enabled;
 
@@ -10529,7 +10456,7 @@ perf_event_exit_event(struct perf_event *child_event,
        if (parent_event)
                perf_group_detach(child_event);
        list_del_event(child_event, child_ctx);
-       child_event->state = PERF_EVENT_STATE_EXIT; /* is_event_hup() */
+       perf_event_set_state(child_event, PERF_EVENT_STATE_EXIT); /* is_event_hup() */
        raw_spin_unlock_irq(&child_ctx->lock);
 
        /*
@@ -10767,7 +10694,7 @@ inherit_event(struct perf_event *parent_event,
              struct perf_event *group_leader,
              struct perf_event_context *child_ctx)
 {
-       enum perf_event_active_state parent_state = parent_event->state;
+       enum perf_event_state parent_state = parent_event->state;
        struct perf_event *child_event;
        unsigned long flags;
 
@@ -11103,6 +11030,7 @@ static void __perf_event_exit_context(void *__info)
        struct perf_event *event;
 
        raw_spin_lock(&ctx->lock);
+       ctx_sched_out(ctx, cpuctx, EVENT_TIME);
        list_for_each_entry(event, &ctx->event_list, event_entry)
                __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
        raw_spin_unlock(&ctx->lock);
index f684d8e5fa2be2fd10e4d5e2f1e65a5c2afeb629..f3e37971c842eb48878a6bfbd3dbc8f025697271 100644 (file)
@@ -381,7 +381,7 @@ void *perf_aux_output_begin(struct perf_output_handle *handle,
         * (B) <-> (C) ordering is still observed by the pmu driver.
         */
        if (!rb->aux_overwrite) {
-               aux_tail = ACCESS_ONCE(rb->user_page->aux_tail);
+               aux_tail = READ_ONCE(rb->user_page->aux_tail);
                handle->wakeup = rb->aux_wakeup + rb->aux_watermark;
                if (aux_head - aux_tail < perf_aux_size(rb))
                        handle->size = CIRC_SPACE(aux_head, aux_tail, perf_aux_size(rb));
index f6cad39f35dfbe441abc5fc740458a6574e7d529..6b4298a41167c7f3f7ea7be1d85af9a08d9d44cb 100644 (file)
@@ -1339,7 +1339,7 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
         * Ensure that EXIT_ZOMBIE -> EXIT_DEAD/EXIT_TRACE transition
         * can't confuse the checks below.
         */
-       int exit_state = ACCESS_ONCE(p->exit_state);
+       int exit_state = READ_ONCE(p->exit_state);
        int ret;
 
        if (unlikely(exit_state == EXIT_DEAD))
index 9aa1cc41ecf79c8c2cc5fb9dbd3fbd418025c0dd..a17fdb63dc3e470955dcfd5e5861920b9db2749f 100644 (file)
@@ -31,6 +31,8 @@
  * mutex protecting text section modification (dynamic code patching).
  * some users need to sleep (allocating memory...) while they hold this lock.
  *
+ * Note: Also protects SMP-alternatives modification on x86.
+ *
  * NOT exported to modules - patching kernel text is a really delicate matter.
  */
 DEFINE_MUTEX(text_mutex);
index a117adf7084b88fd8ad26897623d2a196813538c..89e3558664500101c41d464c1c8459f6ef42a5d3 100644 (file)
@@ -97,6 +97,12 @@ config HANDLE_DOMAIN_IRQ
 config IRQ_TIMINGS
        bool
 
+config GENERIC_IRQ_MATRIX_ALLOCATOR
+       bool
+
+config GENERIC_IRQ_RESERVATION_MODE
+       bool
+
 config IRQ_DOMAIN_DEBUG
        bool "Expose hardware/virtual IRQ mapping via debugfs"
        depends on IRQ_DOMAIN && DEBUG_FS
index ed15d142694b8e49e8f2c7f0d9ff3831eab054ef..ff6e352e3a6cbc7409f6170e1b0c8a66cefb3e61 100644 (file)
@@ -14,3 +14,4 @@ obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
 obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o
 obj-$(CONFIG_SMP) += affinity.o
 obj-$(CONFIG_GENERIC_IRQ_DEBUGFS) += debugfs.o
+obj-$(CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR) += matrix.o
index befa671fba644917c5b696d4ea5c5199bf6dc318..4e8089b319aedef183bef8e0131e0c5dafcb6d1b 100644 (file)
@@ -54,7 +54,7 @@ unsigned long probe_irq_on(void)
                        if (desc->irq_data.chip->irq_set_type)
                                desc->irq_data.chip->irq_set_type(&desc->irq_data,
                                                         IRQ_TYPE_PROBE);
-                       irq_startup(desc, IRQ_NORESEND, IRQ_START_FORCE);
+                       irq_activate_and_startup(desc, IRQ_NORESEND);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
index 5a2ef92c2782c59c177e1f6c2eb5b4b17fb75a49..043bfc35b3534e45b9e4ec90c230000ea04519d1 100644 (file)
@@ -207,20 +207,24 @@ __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
                 * Catch code which fiddles with enable_irq() on a managed
                 * and potentially shutdown IRQ. Chained interrupt
                 * installment or irq auto probing should not happen on
-                * managed irqs either. Emit a warning, break the affinity
-                * and start it up as a normal interrupt.
+                * managed irqs either.
                 */
                if (WARN_ON_ONCE(force))
-                       return IRQ_STARTUP_NORMAL;
+                       return IRQ_STARTUP_ABORT;
                /*
                 * The interrupt was requested, but there is no online CPU
                 * in it's affinity mask. Put it into managed shutdown
                 * state and let the cpu hotplug mechanism start it up once
                 * a CPU in the mask becomes available.
                 */
-               irqd_set_managed_shutdown(d);
                return IRQ_STARTUP_ABORT;
        }
+       /*
+        * Managed interrupts have reserved resources, so this should not
+        * happen.
+        */
+       if (WARN_ON(irq_domain_activate_irq(d, false)))
+               return IRQ_STARTUP_ABORT;
        return IRQ_STARTUP_MANAGED;
 }
 #else
@@ -236,7 +240,9 @@ static int __irq_startup(struct irq_desc *desc)
        struct irq_data *d = irq_desc_get_irq_data(desc);
        int ret = 0;
 
-       irq_domain_activate_irq(d);
+       /* Warn if this interrupt is not activated but try nevertheless */
+       WARN_ON_ONCE(!irqd_is_activated(d));
+
        if (d->chip->irq_startup) {
                ret = d->chip->irq_startup(d);
                irq_state_clr_disabled(desc);
@@ -269,6 +275,7 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force)
                        ret = __irq_startup(desc);
                        break;
                case IRQ_STARTUP_ABORT:
+                       irqd_set_managed_shutdown(d);
                        return 0;
                }
        }
@@ -278,6 +285,22 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force)
        return ret;
 }
 
+int irq_activate(struct irq_desc *desc)
+{
+       struct irq_data *d = irq_desc_get_irq_data(desc);
+
+       if (!irqd_affinity_is_managed(d))
+               return irq_domain_activate_irq(d, false);
+       return 0;
+}
+
+void irq_activate_and_startup(struct irq_desc *desc, bool resend)
+{
+       if (WARN_ON(irq_activate(desc)))
+               return;
+       irq_startup(desc, resend, IRQ_START_FORCE);
+}
+
 static void __irq_disable(struct irq_desc *desc, bool mask);
 
 void irq_shutdown(struct irq_desc *desc)
@@ -953,7 +976,7 @@ __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
                irq_settings_set_norequest(desc);
                irq_settings_set_nothread(desc);
                desc->action = &chained_action;
-               irq_startup(desc, IRQ_RESEND, IRQ_START_FORCE);
+               irq_activate_and_startup(desc, IRQ_RESEND);
        }
 }
 
index c3fdb36dec304956650082efc63bed95f37ff56c..7f608ac3965379fc112d85051fd80325b2ec84ce 100644 (file)
@@ -81,6 +81,8 @@ irq_debug_show_data(struct seq_file *m, struct irq_data *data, int ind)
                   data->domain ? data->domain->name : "");
        seq_printf(m, "%*shwirq:   0x%lx\n", ind + 1, "", data->hwirq);
        irq_debug_show_chip(m, data, ind + 1);
+       if (data->domain && data->domain->ops && data->domain->ops->debug_show)
+               data->domain->ops->debug_show(m, NULL, data, ind + 1);
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
        if (!data->parent_data)
                return;
@@ -149,6 +151,7 @@ static int irq_debug_show(struct seq_file *m, void *p)
        raw_spin_lock_irq(&desc->lock);
        data = irq_desc_get_irq_data(desc);
        seq_printf(m, "handler:  %pf\n", desc->handle_irq);
+       seq_printf(m, "device:   %s\n", desc->dev_name);
        seq_printf(m, "status:   0x%08x\n", desc->status_use_accessors);
        irq_debug_show_bits(m, 0, desc->status_use_accessors, irqdesc_states,
                            ARRAY_SIZE(irqdesc_states));
@@ -226,6 +229,15 @@ static const struct file_operations dfs_irq_ops = {
        .release        = single_release,
 };
 
+void irq_debugfs_copy_devname(int irq, struct device *dev)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       const char *name = dev_name(dev);
+
+       if (name)
+               desc->dev_name = kstrdup(name, GFP_KERNEL);
+}
+
 void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc)
 {
        char name [10];
index 44ed5f8c8759051896fcdae2a38ae6eb0c4edd83..07d08ca701ec4627b558d0435c54cf6de7e147d2 100644 (file)
@@ -75,6 +75,8 @@ extern void __enable_irq(struct irq_desc *desc);
 #define IRQ_START_FORCE        true
 #define IRQ_START_COND false
 
+extern int irq_activate(struct irq_desc *desc);
+extern void irq_activate_and_startup(struct irq_desc *desc, bool resend);
 extern int irq_startup(struct irq_desc *desc, bool resend, bool force);
 
 extern void irq_shutdown(struct irq_desc *desc);
@@ -437,6 +439,18 @@ static inline bool irq_fixup_move_pending(struct irq_desc *desc, bool fclear)
 }
 #endif /* !CONFIG_GENERIC_PENDING_IRQ */
 
+#if !defined(CONFIG_IRQ_DOMAIN) || !defined(CONFIG_IRQ_DOMAIN_HIERARCHY)
+static inline int irq_domain_activate_irq(struct irq_data *data, bool early)
+{
+       irqd_set_activated(data);
+       return 0;
+}
+static inline void irq_domain_deactivate_irq(struct irq_data *data)
+{
+       irqd_clr_activated(data);
+}
+#endif
+
 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
 #include <linux/debugfs.h>
 
@@ -444,7 +458,9 @@ void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc);
 static inline void irq_remove_debugfs_entry(struct irq_desc *desc)
 {
        debugfs_remove(desc->debugfs_file);
+       kfree(desc->dev_name);
 }
+void irq_debugfs_copy_devname(int irq, struct device *dev);
 # ifdef CONFIG_IRQ_DOMAIN
 void irq_domain_debugfs_init(struct dentry *root);
 # else
@@ -459,4 +475,7 @@ static inline void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *d)
 static inline void irq_remove_debugfs_entry(struct irq_desc *d)
 {
 }
+static inline void irq_debugfs_copy_devname(int irq, struct device *dev)
+{
+}
 #endif /* CONFIG_GENERIC_IRQ_DEBUGFS */
index 82afb7ed369f0df70bcd5d6fdc110addda5b842f..f2edcf85780dda0fc4c67ca3fcc39722fd0d2a18 100644 (file)
@@ -27,7 +27,7 @@ static struct lock_class_key irq_desc_lock_class;
 #if defined(CONFIG_SMP)
 static int __init irq_affinity_setup(char *str)
 {
-       zalloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
+       alloc_bootmem_cpumask_var(&irq_default_affinity);
        cpulist_parse(str, irq_default_affinity);
        /*
         * Set at least the boot cpu. We don't want to end up with
@@ -40,10 +40,8 @@ __setup("irqaffinity=", irq_affinity_setup);
 
 static void __init init_irq_default_affinity(void)
 {
-#ifdef CONFIG_CPUMASK_OFFSTACK
-       if (!irq_default_affinity)
+       if (!cpumask_available(irq_default_affinity))
                zalloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
-#endif
        if (cpumask_empty(irq_default_affinity))
                cpumask_setall(irq_default_affinity);
 }
@@ -448,7 +446,7 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node,
                }
        }
 
-       flags = affinity ? IRQD_AFFINITY_MANAGED : 0;
+       flags = affinity ? IRQD_AFFINITY_MANAGED | IRQD_MANAGED_SHUTDOWN : 0;
        mask = NULL;
 
        for (i = 0; i < cnt; i++) {
@@ -462,6 +460,7 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node,
                        goto err;
                irq_insert_desc(start + i, desc);
                irq_sysfs_add(start + i, desc);
+               irq_add_debugfs_entry(start + i, desc);
        }
        bitmap_set(allocated_irqs, start, cnt);
        return start;
index ac4644e92b499949b1a11652ddde3e3bccba8072..4f4f60015e8ab4196ef1df5107f04beda37d4c6c 100644 (file)
@@ -21,7 +21,6 @@
 static LIST_HEAD(irq_domain_list);
 static DEFINE_MUTEX(irq_domain_mutex);
 
-static DEFINE_MUTEX(revmap_trees_mutex);
 static struct irq_domain *irq_default_domain;
 
 static void irq_domain_check_hierarchy(struct irq_domain *domain);
@@ -211,6 +210,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
 
        /* Fill structure */
        INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
+       mutex_init(&domain->revmap_tree_mutex);
        domain->ops = ops;
        domain->host_data = host_data;
        domain->hwirq_max = hwirq_max;
@@ -462,9 +462,9 @@ static void irq_domain_clear_mapping(struct irq_domain *domain,
        if (hwirq < domain->revmap_size) {
                domain->linear_revmap[hwirq] = 0;
        } else {
-               mutex_lock(&revmap_trees_mutex);
+               mutex_lock(&domain->revmap_tree_mutex);
                radix_tree_delete(&domain->revmap_tree, hwirq);
-               mutex_unlock(&revmap_trees_mutex);
+               mutex_unlock(&domain->revmap_tree_mutex);
        }
 }
 
@@ -475,9 +475,9 @@ static void irq_domain_set_mapping(struct irq_domain *domain,
        if (hwirq < domain->revmap_size) {
                domain->linear_revmap[hwirq] = irq_data->irq;
        } else {
-               mutex_lock(&revmap_trees_mutex);
+               mutex_lock(&domain->revmap_tree_mutex);
                radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
-               mutex_unlock(&revmap_trees_mutex);
+               mutex_unlock(&domain->revmap_tree_mutex);
        }
 }
 
@@ -921,8 +921,7 @@ static void virq_debug_show_one(struct seq_file *m, struct irq_desc *desc)
                chip = irq_data_get_irq_chip(data);
                seq_printf(m, "%-15s  ", (chip && chip->name) ? chip->name : "none");
 
-               seq_printf(m, data ? "0x%p  " : "  %p  ",
-                          irq_data_get_irq_chip_data(data));
+               seq_printf(m, "0x%p  ", irq_data_get_irq_chip_data(data));
 
                seq_printf(m, "   %c    ", (desc->action && desc->action->handler) ? '*' : ' ');
                direct = (irq == hwirq) && (irq < domain->revmap_direct_max_irq);
@@ -1459,11 +1458,11 @@ static void irq_domain_fix_revmap(struct irq_data *d)
                return; /* Not using radix tree. */
 
        /* Fix up the revmap. */
-       mutex_lock(&revmap_trees_mutex);
+       mutex_lock(&d->domain->revmap_tree_mutex);
        slot = radix_tree_lookup_slot(&d->domain->revmap_tree, d->hwirq);
        if (slot)
                radix_tree_replace_slot(&d->domain->revmap_tree, slot, d);
-       mutex_unlock(&revmap_trees_mutex);
+       mutex_unlock(&d->domain->revmap_tree_mutex);
 }
 
 /**
@@ -1682,28 +1681,36 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain,
 }
 EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
 
-static void __irq_domain_activate_irq(struct irq_data *irq_data)
+static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
 {
        if (irq_data && irq_data->domain) {
                struct irq_domain *domain = irq_data->domain;
 
+               if (domain->ops->deactivate)
+                       domain->ops->deactivate(domain, irq_data);
                if (irq_data->parent_data)
-                       __irq_domain_activate_irq(irq_data->parent_data);
-               if (domain->ops->activate)
-                       domain->ops->activate(domain, irq_data);
+                       __irq_domain_deactivate_irq(irq_data->parent_data);
        }
 }
 
-static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
+static int __irq_domain_activate_irq(struct irq_data *irqd, bool early)
 {
-       if (irq_data && irq_data->domain) {
-               struct irq_domain *domain = irq_data->domain;
+       int ret = 0;
 
-               if (domain->ops->deactivate)
-                       domain->ops->deactivate(domain, irq_data);
-               if (irq_data->parent_data)
-                       __irq_domain_deactivate_irq(irq_data->parent_data);
+       if (irqd && irqd->domain) {
+               struct irq_domain *domain = irqd->domain;
+
+               if (irqd->parent_data)
+                       ret = __irq_domain_activate_irq(irqd->parent_data,
+                                                       early);
+               if (!ret && domain->ops->activate) {
+                       ret = domain->ops->activate(domain, irqd, early);
+                       /* Rollback in case of error */
+                       if (ret && irqd->parent_data)
+                               __irq_domain_deactivate_irq(irqd->parent_data);
+               }
        }
+       return ret;
 }
 
 /**
@@ -1714,12 +1721,15 @@ static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
  * This is the second step to call domain_ops->activate to program interrupt
  * controllers, so the interrupt could actually get delivered.
  */
-void irq_domain_activate_irq(struct irq_data *irq_data)
+int irq_domain_activate_irq(struct irq_data *irq_data, bool early)
 {
-       if (!irqd_is_activated(irq_data)) {
-               __irq_domain_activate_irq(irq_data);
+       int ret = 0;
+
+       if (!irqd_is_activated(irq_data))
+               ret = __irq_domain_activate_irq(irq_data, early);
+       if (!ret)
                irqd_set_activated(irq_data);
-       }
+       return ret;
 }
 
 /**
@@ -1810,6 +1820,8 @@ irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind)
                   d->revmap_size + d->revmap_direct_max_irq);
        seq_printf(m, "%*smapped: %u\n", ind + 1, "", d->mapcount);
        seq_printf(m, "%*sflags:  0x%08x\n", ind +1 , "", d->flags);
+       if (d->ops && d->ops->debug_show)
+               d->ops->debug_show(m, d, NULL, ind + 1);
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
        if (!d->parent)
                return;
index 4bff6a10ae8ec7efb76dd8e677e86016ca04355a..2ff1c0c82fc91a91e7a59edc1de72aab85d131c7 100644 (file)
@@ -398,7 +398,8 @@ int irq_select_affinity_usr(unsigned int irq)
 /**
  *     irq_set_vcpu_affinity - Set vcpu affinity for the interrupt
  *     @irq: interrupt number to set affinity
- *     @vcpu_info: vCPU specific data
+ *     @vcpu_info: vCPU specific data or pointer to a percpu array of vCPU
+ *                 specific data for percpu_devid interrupts
  *
  *     This function uses the vCPU specific data to set the vCPU
  *     affinity for an irq. The vCPU specific data is passed from
@@ -536,7 +537,7 @@ void __enable_irq(struct irq_desc *desc)
                 * time. If it was already started up, then irq_startup()
                 * will invoke irq_enable() under the hood.
                 */
-               irq_startup(desc, IRQ_RESEND, IRQ_START_COND);
+               irq_startup(desc, IRQ_RESEND, IRQ_START_FORCE);
                break;
        }
        default:
@@ -1305,7 +1306,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                 * thread_mask assigned. See the loop above which or's
                 * all existing action->thread_mask bits.
                 */
-               new->thread_mask = 1 << ffz(thread_mask);
+               new->thread_mask = 1UL << ffz(thread_mask);
 
        } else if (new->handler == irq_default_primary_handler &&
                   !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {
@@ -1342,6 +1343,21 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                                goto out_unlock;
                }
 
+               /*
+                * Activate the interrupt. That activation must happen
+                * independently of IRQ_NOAUTOEN. request_irq() can fail
+                * and the callers are supposed to handle
+                * that. enable_irq() of an interrupt requested with
+                * IRQ_NOAUTOEN is not supposed to fail. The activation
+                * keeps it in shutdown mode, it merily associates
+                * resources if necessary and if that's not possible it
+                * fails. Interrupts which are in managed shutdown mode
+                * will simply ignore that activation request.
+                */
+               ret = irq_activate(desc);
+               if (ret)
+                       goto out_unlock;
+
                desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
                                  IRQS_ONESHOT | IRQS_WAITING);
                irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
@@ -1417,7 +1433,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                wake_up_process(new->secondary->thread);
 
        register_irq_proc(irq, desc);
-       irq_add_debugfs_entry(irq, desc);
        new->dir = NULL;
        register_handler_proc(irq, new);
        return 0;
diff --git a/kernel/irq/matrix.c b/kernel/irq/matrix.c
new file mode 100644 (file)
index 0000000..a3cbbc8
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2017 Thomas Gleixner <tglx@linutronix.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
+#include <linux/bitmap.h>
+#include <linux/percpu.h>
+#include <linux/cpu.h>
+#include <linux/irq.h>
+
+#define IRQ_MATRIX_SIZE        (BITS_TO_LONGS(IRQ_MATRIX_BITS) * sizeof(unsigned long))
+
+struct cpumap {
+       unsigned int            available;
+       unsigned int            allocated;
+       unsigned int            managed;
+       bool                    online;
+       unsigned long           alloc_map[IRQ_MATRIX_SIZE];
+       unsigned long           managed_map[IRQ_MATRIX_SIZE];
+};
+
+struct irq_matrix {
+       unsigned int            matrix_bits;
+       unsigned int            alloc_start;
+       unsigned int            alloc_end;
+       unsigned int            alloc_size;
+       unsigned int            global_available;
+       unsigned int            global_reserved;
+       unsigned int            systembits_inalloc;
+       unsigned int            total_allocated;
+       unsigned int            online_maps;
+       struct cpumap __percpu  *maps;
+       unsigned long           scratch_map[IRQ_MATRIX_SIZE];
+       unsigned long           system_map[IRQ_MATRIX_SIZE];
+};
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/irq_matrix.h>
+
+/**
+ * irq_alloc_matrix - Allocate a irq_matrix structure and initialize it
+ * @matrix_bits:       Number of matrix bits must be <= IRQ_MATRIX_BITS
+ * @alloc_start:       From which bit the allocation search starts
+ * @alloc_end:         At which bit the allocation search ends, i.e first
+ *                     invalid bit
+ */
+__init struct irq_matrix *irq_alloc_matrix(unsigned int matrix_bits,
+                                          unsigned int alloc_start,
+                                          unsigned int alloc_end)
+{
+       struct irq_matrix *m;
+
+       if (matrix_bits > IRQ_MATRIX_BITS)
+               return NULL;
+
+       m = kzalloc(sizeof(*m), GFP_KERNEL);
+       if (!m)
+               return NULL;
+
+       m->matrix_bits = matrix_bits;
+       m->alloc_start = alloc_start;
+       m->alloc_end = alloc_end;
+       m->alloc_size = alloc_end - alloc_start;
+       m->maps = alloc_percpu(*m->maps);
+       if (!m->maps) {
+               kfree(m);
+               return NULL;
+       }
+       return m;
+}
+
+/**
+ * irq_matrix_online - Bring the local CPU matrix online
+ * @m:         Matrix pointer
+ */
+void irq_matrix_online(struct irq_matrix *m)
+{
+       struct cpumap *cm = this_cpu_ptr(m->maps);
+
+       BUG_ON(cm->online);
+
+       bitmap_zero(cm->alloc_map, m->matrix_bits);
+       cm->available = m->alloc_size - (cm->managed + m->systembits_inalloc);
+       cm->allocated = 0;
+       m->global_available += cm->available;
+       cm->online = true;
+       m->online_maps++;
+       trace_irq_matrix_online(m);
+}
+
+/**
+ * irq_matrix_offline - Bring the local CPU matrix offline
+ * @m:         Matrix pointer
+ */
+void irq_matrix_offline(struct irq_matrix *m)
+{
+       struct cpumap *cm = this_cpu_ptr(m->maps);
+
+       /* Update the global available size */
+       m->global_available -= cm->available;
+       cm->online = false;
+       m->online_maps--;
+       trace_irq_matrix_offline(m);
+}
+
+static unsigned int matrix_alloc_area(struct irq_matrix *m, struct cpumap *cm,
+                                     unsigned int num, bool managed)
+{
+       unsigned int area, start = m->alloc_start;
+       unsigned int end = m->alloc_end;
+
+       bitmap_or(m->scratch_map, cm->managed_map, m->system_map, end);
+       bitmap_or(m->scratch_map, m->scratch_map, cm->alloc_map, end);
+       area = bitmap_find_next_zero_area(m->scratch_map, end, start, num, 0);
+       if (area >= end)
+               return area;
+       if (managed)
+               bitmap_set(cm->managed_map, area, num);
+       else
+               bitmap_set(cm->alloc_map, area, num);
+       return area;
+}
+
+/**
+ * irq_matrix_assign_system - Assign system wide entry in the matrix
+ * @m:         Matrix pointer
+ * @bit:       Which bit to reserve
+ * @replace:   Replace an already allocated vector with a system
+ *             vector at the same bit position.
+ *
+ * The BUG_ON()s below are on purpose. If this goes wrong in the
+ * early boot process, then the chance to survive is about zero.
+ * If this happens when the system is life, it's not much better.
+ */
+void irq_matrix_assign_system(struct irq_matrix *m, unsigned int bit,
+                             bool replace)
+{
+       struct cpumap *cm = this_cpu_ptr(m->maps);
+
+       BUG_ON(bit > m->matrix_bits);
+       BUG_ON(m->online_maps > 1 || (m->online_maps && !replace));
+
+       set_bit(bit, m->system_map);
+       if (replace) {
+               BUG_ON(!test_and_clear_bit(bit, cm->alloc_map));
+               cm->allocated--;
+               m->total_allocated--;
+       }
+       if (bit >= m->alloc_start && bit < m->alloc_end)
+               m->systembits_inalloc++;
+
+       trace_irq_matrix_assign_system(bit, m);
+}
+
+/**
+ * irq_matrix_reserve_managed - Reserve a managed interrupt in a CPU map
+ * @m:         Matrix pointer
+ * @msk:       On which CPUs the bits should be reserved.
+ *
+ * Can be called for offline CPUs. Note, this will only reserve one bit
+ * on all CPUs in @msk, but it's not guaranteed that the bits are at the
+ * same offset on all CPUs
+ */
+int irq_matrix_reserve_managed(struct irq_matrix *m, const struct cpumask *msk)
+{
+       unsigned int cpu, failed_cpu;
+
+       for_each_cpu(cpu, msk) {
+               struct cpumap *cm = per_cpu_ptr(m->maps, cpu);
+               unsigned int bit;
+
+               bit = matrix_alloc_area(m, cm, 1, true);
+               if (bit >= m->alloc_end)
+                       goto cleanup;
+               cm->managed++;
+               if (cm->online) {
+                       cm->available--;
+                       m->global_available--;
+               }
+               trace_irq_matrix_reserve_managed(bit, cpu, m, cm);
+       }
+       return 0;
+cleanup:
+       failed_cpu = cpu;
+       for_each_cpu(cpu, msk) {
+               if (cpu == failed_cpu)
+                       break;
+               irq_matrix_remove_managed(m, cpumask_of(cpu));
+       }
+       return -ENOSPC;
+}
+
+/**
+ * irq_matrix_remove_managed - Remove managed interrupts in a CPU map
+ * @m:         Matrix pointer
+ * @msk:       On which CPUs the bits should be removed
+ *
+ * Can be called for offline CPUs
+ *
+ * This removes not allocated managed interrupts from the map. It does
+ * not matter which one because the managed interrupts free their
+ * allocation when they shut down. If not, the accounting is screwed,
+ * but all what can be done at this point is warn about it.
+ */
+void irq_matrix_remove_managed(struct irq_matrix *m, const struct cpumask *msk)
+{
+       unsigned int cpu;
+
+       for_each_cpu(cpu, msk) {
+               struct cpumap *cm = per_cpu_ptr(m->maps, cpu);
+               unsigned int bit, end = m->alloc_end;
+
+               if (WARN_ON_ONCE(!cm->managed))
+                       continue;
+
+               /* Get managed bit which are not allocated */
+               bitmap_andnot(m->scratch_map, cm->managed_map, cm->alloc_map, end);
+
+               bit = find_first_bit(m->scratch_map, end);
+               if (WARN_ON_ONCE(bit >= end))
+                       continue;
+
+               clear_bit(bit, cm->managed_map);
+
+               cm->managed--;
+               if (cm->online) {
+                       cm->available++;
+                       m->global_available++;
+               }
+               trace_irq_matrix_remove_managed(bit, cpu, m, cm);
+       }
+}
+
+/**
+ * irq_matrix_alloc_managed - Allocate a managed interrupt in a CPU map
+ * @m:         Matrix pointer
+ * @cpu:       On which CPU the interrupt should be allocated
+ */
+int irq_matrix_alloc_managed(struct irq_matrix *m, unsigned int cpu)
+{
+       struct cpumap *cm = per_cpu_ptr(m->maps, cpu);
+       unsigned int bit, end = m->alloc_end;
+
+       /* Get managed bit which are not allocated */
+       bitmap_andnot(m->scratch_map, cm->managed_map, cm->alloc_map, end);
+       bit = find_first_bit(m->scratch_map, end);
+       if (bit >= end)
+               return -ENOSPC;
+       set_bit(bit, cm->alloc_map);
+       cm->allocated++;
+       m->total_allocated++;
+       trace_irq_matrix_alloc_managed(bit, cpu, m, cm);
+       return bit;
+}
+
+/**
+ * irq_matrix_assign - Assign a preallocated interrupt in the local CPU map
+ * @m:         Matrix pointer
+ * @bit:       Which bit to mark
+ *
+ * This should only be used to mark preallocated vectors
+ */
+void irq_matrix_assign(struct irq_matrix *m, unsigned int bit)
+{
+       struct cpumap *cm = this_cpu_ptr(m->maps);
+
+       if (WARN_ON_ONCE(bit < m->alloc_start || bit >= m->alloc_end))
+               return;
+       if (WARN_ON_ONCE(test_and_set_bit(bit, cm->alloc_map)))
+               return;
+       cm->allocated++;
+       m->total_allocated++;
+       cm->available--;
+       m->global_available--;
+       trace_irq_matrix_assign(bit, smp_processor_id(), m, cm);
+}
+
+/**
+ * irq_matrix_reserve - Reserve interrupts
+ * @m:         Matrix pointer
+ *
+ * This is merily a book keeping call. It increments the number of globally
+ * reserved interrupt bits w/o actually allocating them. This allows to
+ * setup interrupt descriptors w/o assigning low level resources to it.
+ * The actual allocation happens when the interrupt gets activated.
+ */
+void irq_matrix_reserve(struct irq_matrix *m)
+{
+       if (m->global_reserved <= m->global_available &&
+           m->global_reserved + 1 > m->global_available)
+               pr_warn("Interrupt reservation exceeds available resources\n");
+
+       m->global_reserved++;
+       trace_irq_matrix_reserve(m);
+}
+
+/**
+ * irq_matrix_remove_reserved - Remove interrupt reservation
+ * @m:         Matrix pointer
+ *
+ * This is merily a book keeping call. It decrements the number of globally
+ * reserved interrupt bits. This is used to undo irq_matrix_reserve() when the
+ * interrupt was never in use and a real vector allocated, which undid the
+ * reservation.
+ */
+void irq_matrix_remove_reserved(struct irq_matrix *m)
+{
+       m->global_reserved--;
+       trace_irq_matrix_remove_reserved(m);
+}
+
+/**
+ * irq_matrix_alloc - Allocate a regular interrupt in a CPU map
+ * @m:         Matrix pointer
+ * @msk:       Which CPUs to search in
+ * @reserved:  Allocate previously reserved interrupts
+ * @mapped_cpu: Pointer to store the CPU for which the irq was allocated
+ */
+int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk,
+                    bool reserved, unsigned int *mapped_cpu)
+{
+       unsigned int cpu;
+
+       for_each_cpu(cpu, msk) {
+               struct cpumap *cm = per_cpu_ptr(m->maps, cpu);
+               unsigned int bit;
+
+               if (!cm->online)
+                       continue;
+
+               bit = matrix_alloc_area(m, cm, 1, false);
+               if (bit < m->alloc_end) {
+                       cm->allocated++;
+                       cm->available--;
+                       m->total_allocated++;
+                       m->global_available--;
+                       if (reserved)
+                               m->global_reserved--;
+                       *mapped_cpu = cpu;
+                       trace_irq_matrix_alloc(bit, cpu, m, cm);
+                       return bit;
+               }
+       }
+       return -ENOSPC;
+}
+
+/**
+ * irq_matrix_free - Free allocated interrupt in the matrix
+ * @m:         Matrix pointer
+ * @cpu:       Which CPU map needs be updated
+ * @bit:       The bit to remove
+ * @managed:   If true, the interrupt is managed and not accounted
+ *             as available.
+ */
+void irq_matrix_free(struct irq_matrix *m, unsigned int cpu,
+                    unsigned int bit, bool managed)
+{
+       struct cpumap *cm = per_cpu_ptr(m->maps, cpu);
+
+       if (WARN_ON_ONCE(bit < m->alloc_start || bit >= m->alloc_end))
+               return;
+
+       if (cm->online) {
+               clear_bit(bit, cm->alloc_map);
+               cm->allocated--;
+               m->total_allocated--;
+               if (!managed) {
+                       cm->available++;
+                       m->global_available++;
+               }
+       }
+       trace_irq_matrix_free(bit, cpu, m, cm);
+}
+
+/**
+ * irq_matrix_available - Get the number of globally available irqs
+ * @m:         Pointer to the matrix to query
+ * @cpudown:   If true, the local CPU is about to go down, adjust
+ *             the number of available irqs accordingly
+ */
+unsigned int irq_matrix_available(struct irq_matrix *m, bool cpudown)
+{
+       struct cpumap *cm = this_cpu_ptr(m->maps);
+
+       return m->global_available - cpudown ? cm->available : 0;
+}
+
+/**
+ * irq_matrix_reserved - Get the number of globally reserved irqs
+ * @m:         Pointer to the matrix to query
+ */
+unsigned int irq_matrix_reserved(struct irq_matrix *m)
+{
+       return m->global_reserved;
+}
+
+/**
+ * irq_matrix_allocated - Get the number of allocated irqs on the local cpu
+ * @m:         Pointer to the matrix to search
+ *
+ * This returns number of allocated irqs
+ */
+unsigned int irq_matrix_allocated(struct irq_matrix *m)
+{
+       struct cpumap *cm = this_cpu_ptr(m->maps);
+
+       return cm->allocated;
+}
+
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+/**
+ * irq_matrix_debug_show - Show detailed allocation information
+ * @sf:                Pointer to the seq_file to print to
+ * @m:         Pointer to the matrix allocator
+ * @ind:       Indentation for the print format
+ *
+ * Note, this is a lockless snapshot.
+ */
+void irq_matrix_debug_show(struct seq_file *sf, struct irq_matrix *m, int ind)
+{
+       unsigned int nsys = bitmap_weight(m->system_map, m->matrix_bits);
+       int cpu;
+
+       seq_printf(sf, "Online bitmaps:   %6u\n", m->online_maps);
+       seq_printf(sf, "Global available: %6u\n", m->global_available);
+       seq_printf(sf, "Global reserved:  %6u\n", m->global_reserved);
+       seq_printf(sf, "Total allocated:  %6u\n", m->total_allocated);
+       seq_printf(sf, "System: %u: %*pbl\n", nsys, m->matrix_bits,
+                  m->system_map);
+       seq_printf(sf, "%*s| CPU | avl | man | act | vectors\n", ind, " ");
+       cpus_read_lock();
+       for_each_online_cpu(cpu) {
+               struct cpumap *cm = per_cpu_ptr(m->maps, cpu);
+
+               seq_printf(sf, "%*s %4d  %4u  %4u  %4u  %*pbl\n", ind, " ",
+                          cpu, cm->available, cm->managed, cm->allocated,
+                          m->matrix_bits, cm->alloc_map);
+       }
+       cpus_read_unlock();
+}
+#endif
index 3fa4bd59f569865703bb9ab189d24401e99bbf38..edb987b2c58dc1553342b5a87c91335b42888e8b 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/msi.h>
 #include <linux/slab.h>
 
+#include "internals.h"
+
 /**
  * alloc_msi_entry - Allocate an initialize msi_entry
  * @dev:       Pointer to the device for which this is allocated
@@ -100,13 +102,14 @@ int msi_domain_set_affinity(struct irq_data *irq_data,
        return ret;
 }
 
-static void msi_domain_activate(struct irq_domain *domain,
-                               struct irq_data *irq_data)
+static int msi_domain_activate(struct irq_domain *domain,
+                              struct irq_data *irq_data, bool early)
 {
        struct msi_msg msg;
 
        BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
        irq_chip_write_msi_msg(irq_data, &msg);
+       return 0;
 }
 
 static void msi_domain_deactivate(struct irq_domain *domain,
@@ -373,8 +376,10 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
                        return ret;
                }
 
-               for (i = 0; i < desc->nvec_used; i++)
+               for (i = 0; i < desc->nvec_used; i++) {
                        irq_set_msi_desc_off(virq, i, desc);
+                       irq_debugfs_copy_devname(virq + i, dev);
+               }
        }
 
        if (ops->msi_finish)
@@ -396,11 +401,28 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
                        struct irq_data *irq_data;
 
                        irq_data = irq_domain_get_irq_data(domain, desc->irq);
-                       irq_domain_activate_irq(irq_data);
+                       ret = irq_domain_activate_irq(irq_data, true);
+                       if (ret)
+                               goto cleanup;
+                       if (info->flags & MSI_FLAG_MUST_REACTIVATE)
+                               irqd_clr_activated(irq_data);
                }
        }
-
        return 0;
+
+cleanup:
+       for_each_msi_entry(desc, dev) {
+               struct irq_data *irqd;
+
+               if (desc->irq == virq)
+                       break;
+
+               irqd = irq_domain_get_irq_data(domain, desc->irq);
+               if (irqd_is_activated(irqd))
+                       irq_domain_deactivate_irq(irqd);
+       }
+       msi_domain_free_irqs(domain, dev);
+       return ret;
 }
 
 /**
index c010cc0daf79a2d8c90048fc784ce1f8181651fe..e8f374971e37cb59a7c3c4e12f0bf2baa339ba33 100644 (file)
@@ -155,8 +155,9 @@ static ssize_t write_irq_affinity(int type, struct file *file,
                 */
                err = irq_select_affinity_usr(irq) ? -EINVAL : count;
        } else {
-               irq_set_affinity(irq, new_value);
-               err = count;
+               err = irq_set_affinity(irq, new_value);
+               if (!err)
+                       err = count;
        }
 
 free_cpumask:
index 987d7bca4864ffda66e6fa64d3213aed2082383e..1215229d1c1281b2363092b86d9246336ee636e0 100644 (file)
@@ -21,7 +21,7 @@ static int irqfixup __read_mostly;
 
 #define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10)
 static void poll_spurious_irqs(unsigned long dummy);
-static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs, 0, 0);
+static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs);
 static int irq_poll_cpu;
 static atomic_t irq_poll_active;
 
index c8c1d073fbf14958839760357f99142b9cf284a2..e0923fa4927acb0f40055bc8deeebb1c8716ded1 100644 (file)
@@ -264,7 +264,7 @@ u64 irq_timings_next_event(u64 now)
         * order to prevent the timings circular buffer to be updated
         * while we are reading it.
         */
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        /*
         * Number of elements in the circular buffer: If it happens it
index bcf107ce085450552c17d6b045816cd4656e97c0..40e9d739c169d15a361c8d6d11f674a20783cce8 100644 (file)
@@ -56,7 +56,6 @@ void __weak arch_irq_work_raise(void)
         */
 }
 
-#ifdef CONFIG_SMP
 /*
  * Enqueue the irq_work @work on @cpu unless it's already pending
  * somewhere.
@@ -68,6 +67,8 @@ bool irq_work_queue_on(struct irq_work *work, int cpu)
        /* All work should have been flushed before going offline */
        WARN_ON_ONCE(cpu_is_offline(cpu));
 
+#ifdef CONFIG_SMP
+
        /* Arch remote IPI send/receive backend aren't NMI safe */
        WARN_ON_ONCE(in_nmi());
 
@@ -78,10 +79,12 @@ bool irq_work_queue_on(struct irq_work *work, int cpu)
        if (llist_add(&work->llnode, &per_cpu(raised_list, cpu)))
                arch_send_call_function_single_ipi(cpu);
 
+#else /* #ifdef CONFIG_SMP */
+       irq_work_queue(work);
+#endif /* #else #ifdef CONFIG_SMP */
+
        return true;
 }
-EXPORT_SYMBOL_GPL(irq_work_queue_on);
-#endif
 
 /* Enqueue the irq work @work on the current CPU */
 bool irq_work_queue(struct irq_work *work)
@@ -128,9 +131,9 @@ bool irq_work_needs_cpu(void)
 
 static void irq_work_run_list(struct llist_head *list)
 {
-       unsigned long flags;
-       struct irq_work *work;
+       struct irq_work *work, *tmp;
        struct llist_node *llnode;
+       unsigned long flags;
 
        BUG_ON(!irqs_disabled());
 
@@ -138,11 +141,7 @@ static void irq_work_run_list(struct llist_head *list)
                return;
 
        llnode = llist_del_all(list);
-       while (llnode != NULL) {
-               work = llist_entry(llnode, struct irq_work, llnode);
-
-               llnode = llist_next(llnode);
-
+       llist_for_each_entry_safe(work, tmp, llnode, llnode) {
                /*
                 * Clear the PENDING bit, after this point the @work
                 * can be re-used.
@@ -188,7 +187,7 @@ void irq_work_tick(void)
  */
 void irq_work_sync(struct irq_work *work)
 {
-       WARN_ON_ONCE(irqs_disabled());
+       lockdep_assert_irqs_enabled();
 
        while (work->flags & IRQ_WORK_BUSY)
                cpu_relax();
index 0bf2e8f5244ae7ffbf7bc7660cca27cd79bb3e50..8ff4ca4665ff830014db9b9698726ac0b732da58 100644 (file)
@@ -83,7 +83,7 @@ static void static_key_slow_inc_cpuslocked(struct static_key *key)
 {
        int v, v1;
 
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
 
        /*
         * Careful if we get concurrent static_key_slow_inc() calls;
@@ -128,7 +128,7 @@ EXPORT_SYMBOL_GPL(static_key_slow_inc);
 
 void static_key_enable_cpuslocked(struct static_key *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
 
        if (atomic_read(&key->enabled) > 0) {
                WARN_ON_ONCE(atomic_read(&key->enabled) != 1);
@@ -158,7 +158,7 @@ EXPORT_SYMBOL_GPL(static_key_enable);
 
 void static_key_disable_cpuslocked(struct static_key *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
 
        if (atomic_read(&key->enabled) != 1) {
                WARN_ON_ONCE(atomic_read(&key->enabled) != 0);
@@ -224,21 +224,21 @@ static void jump_label_update_timeout(struct work_struct *work)
 
 void static_key_slow_dec(struct static_key *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
        __static_key_slow_dec(key, 0, NULL);
 }
 EXPORT_SYMBOL_GPL(static_key_slow_dec);
 
 void static_key_slow_dec_deferred(struct static_key_deferred *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
        __static_key_slow_dec(&key->key, key->timeout, &key->work);
 }
 EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred);
 
 void static_key_deferred_flush(struct static_key_deferred *key)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
        flush_delayed_work(&key->work);
 }
 EXPORT_SYMBOL_GPL(static_key_deferred_flush);
@@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(static_key_deferred_flush);
 void jump_label_rate_limit(struct static_key_deferred *key,
                unsigned long rl)
 {
-       STATIC_KEY_CHECK_USE();
+       STATIC_KEY_CHECK_USE(key);
        key->timeout = rl;
        INIT_DELAYED_WORK(&key->work, jump_label_update_timeout);
 }
index 127e7cfafa55207a3fb45e5dc158c7885b949b49..1e6ae66c6244329fa21f6190b1ab9d088493bfd5 100644 (file)
@@ -480,6 +480,7 @@ struct kallsym_iter {
        char name[KSYM_NAME_LEN];
        char module_name[MODULE_NAME_LEN];
        int exported;
+       int show_value;
 };
 
 static int get_ksymbol_mod(struct kallsym_iter *iter)
@@ -582,12 +583,15 @@ static void s_stop(struct seq_file *m, void *p)
 
 static int s_show(struct seq_file *m, void *p)
 {
+       unsigned long value;
        struct kallsym_iter *iter = m->private;
 
        /* Some debugging symbols have no name.  Ignore them. */
        if (!iter->name[0])
                return 0;
 
+       value = iter->show_value ? iter->value : 0;
+
        if (iter->module_name[0]) {
                char type;
 
@@ -597,10 +601,10 @@ static int s_show(struct seq_file *m, void *p)
                 */
                type = iter->exported ? toupper(iter->type) :
                                        tolower(iter->type);
-               seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
+               seq_printf(m, KALLSYM_FMT " %c %s\t[%s]\n", value,
                           type, iter->name, iter->module_name);
        } else
-               seq_printf(m, "%pK %c %s\n", (void *)iter->value,
+               seq_printf(m, KALLSYM_FMT " %c %s\n", value,
                           iter->type, iter->name);
        return 0;
 }
@@ -612,6 +616,40 @@ static const struct seq_operations kallsyms_op = {
        .show = s_show
 };
 
+static inline int kallsyms_for_perf(void)
+{
+#ifdef CONFIG_PERF_EVENTS
+       extern int sysctl_perf_event_paranoid;
+       if (sysctl_perf_event_paranoid <= 1)
+               return 1;
+#endif
+       return 0;
+}
+
+/*
+ * We show kallsyms information even to normal users if we've enabled
+ * kernel profiling and are explicitly not paranoid (so kptr_restrict
+ * is clear, and sysctl_perf_event_paranoid isn't set).
+ *
+ * Otherwise, require CAP_SYSLOG (assuming kptr_restrict isn't set to
+ * block even that).
+ */
+int kallsyms_show_value(void)
+{
+       switch (kptr_restrict) {
+       case 0:
+               if (kallsyms_for_perf())
+                       return 1;
+       /* fallthrough */
+       case 1:
+               if (has_capability_noaudit(current, CAP_SYSLOG))
+                       return 1;
+       /* fallthrough */
+       default:
+               return 0;
+       }
+}
+
 static int kallsyms_open(struct inode *inode, struct file *file)
 {
        /*
@@ -625,6 +663,7 @@ static int kallsyms_open(struct inode *inode, struct file *file)
                return -ENOMEM;
        reset_iter(iter, 0);
 
+       iter->show_value = kallsyms_show_value();
        return 0;
 }
 
index 9f48f441229720b0e02434b2375b61d9c62b7706..e5bcd94c1efb13db5daa12d7dd188279ea25c1a1 100644 (file)
@@ -406,9 +406,10 @@ static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
        return 1;
 }
 
-static int locate_mem_hole_callback(u64 start, u64 end, void *arg)
+static int locate_mem_hole_callback(struct resource *res, void *arg)
 {
        struct kexec_buf *kbuf = (struct kexec_buf *)arg;
+       u64 start = res->start, end = res->end;
        unsigned long sz = end - start + 1;
 
        /* Returning 0 will take to next memory range */
@@ -437,7 +438,7 @@ static int locate_mem_hole_callback(u64 start, u64 end, void *arg)
  * func returning non-zero, then zero will be returned.
  */
 int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,
-                              int (*func)(u64, u64, void *))
+                              int (*func)(struct resource *, void *))
 {
        if (kbuf->image->type == KEXEC_TYPE_CRASH)
                return walk_iomem_res_desc(crashk_res.desc,
index a1606a4224e14eef5f9e51d5826fa2c6ad75ab32..da2ccf14235814df4dc4b21509500d0d777cacb4 100644 (file)
@@ -117,7 +117,7 @@ enum kprobe_slot_state {
        SLOT_USED = 2,
 };
 
-static void *alloc_insn_page(void)
+void __weak *alloc_insn_page(void)
 {
        return module_alloc(PAGE_SIZE);
 }
@@ -573,13 +573,15 @@ static void kprobe_optimizer(struct work_struct *work)
        do_unoptimize_kprobes();
 
        /*
-        * Step 2: Wait for quiesence period to ensure all running interrupts
-        * are done. Because optprobe may modify multiple instructions
-        * there is a chance that Nth instruction is interrupted. In that
-        * case, running interrupt can return to 2nd-Nth byte of jump
-        * instruction. This wait is for avoiding it.
+        * Step 2: Wait for quiesence period to ensure all potentially
+        * preempted tasks to have normally scheduled. Because optprobe
+        * may modify multiple instructions, there is a chance that Nth
+        * instruction is preempted. In that case, such tasks can return
+        * to 2nd-Nth byte of jump instruction. This wait is for avoiding it.
+        * Note that on non-preemptive kernel, this is transparently converted
+        * to synchronoze_sched() to wait for all interrupts to have completed.
         */
-       synchronize_sched();
+       synchronize_rcu_tasks();
 
        /* Step 3: Optimize kprobes after quiesence period */
        do_optimize_kprobes();
@@ -1769,6 +1771,7 @@ unsigned long __weak arch_deref_entry_point(void *entry)
        return (unsigned long)entry;
 }
 
+#if 0
 int register_jprobes(struct jprobe **jps, int num)
 {
        int ret = 0, i;
@@ -1837,6 +1840,7 @@ void unregister_jprobes(struct jprobe **jps, int num)
        }
 }
 EXPORT_SYMBOL_GPL(unregister_jprobes);
+#endif
 
 #ifdef CONFIG_KRETPROBES
 /*
index 1c19edf824272db47a48730478af5f3b582bbf67..ba3992c8c3753bcc0785ecf998e457d21c013873 100644 (file)
@@ -798,15 +798,14 @@ EXPORT_SYMBOL_GPL(kthread_queue_work);
 /**
  * kthread_delayed_work_timer_fn - callback that queues the associated kthread
  *     delayed work when the timer expires.
- * @__data: pointer to the data associated with the timer
+ * @t: pointer to the expired timer
  *
  * The format of the function is defined by struct timer_list.
  * It should have been called from irqsafe timer with irq already off.
  */
-void kthread_delayed_work_timer_fn(unsigned long __data)
+void kthread_delayed_work_timer_fn(struct timer_list *t)
 {
-       struct kthread_delayed_work *dwork =
-               (struct kthread_delayed_work *)__data;
+       struct kthread_delayed_work *dwork = from_timer(dwork, t, timer);
        struct kthread_work *work = &dwork->work;
        struct kthread_worker *worker = work->worker;
 
@@ -837,8 +836,7 @@ void __kthread_queue_delayed_work(struct kthread_worker *worker,
        struct timer_list *timer = &dwork->timer;
        struct kthread_work *work = &dwork->work;
 
-       WARN_ON_ONCE(timer->function != kthread_delayed_work_timer_fn ||
-                    timer->data != (unsigned long)dwork);
+       WARN_ON_ONCE(timer->function != (TIMER_FUNC_TYPE)kthread_delayed_work_timer_fn);
 
        /*
         * If @delay is 0, queue @dwork->work immediately.  This is for
index e36e652d996fe682157c52768949f0b9c7f1e6d1..db933d063bfc50354a34f5013ca5619f1508ddf7 100644 (file)
@@ -76,6 +76,19 @@ module_param(lock_stat, int, 0644);
 #define lock_stat 0
 #endif
 
+#ifdef CONFIG_BOOTPARAM_LOCKDEP_CROSSRELEASE_FULLSTACK
+static int crossrelease_fullstack = 1;
+#else
+static int crossrelease_fullstack;
+#endif
+static int __init allow_crossrelease_fullstack(char *str)
+{
+       crossrelease_fullstack = 1;
+       return 0;
+}
+
+early_param("crossrelease_fullstack", allow_crossrelease_fullstack);
+
 /*
  * lockdep_lock: protects the lockdep graph, the hashes and the
  *               class/list/hash allocators.
@@ -4863,8 +4876,14 @@ static void add_xhlock(struct held_lock *hlock)
        xhlock->trace.nr_entries = 0;
        xhlock->trace.max_entries = MAX_XHLOCK_TRACE_ENTRIES;
        xhlock->trace.entries = xhlock->trace_entries;
-       xhlock->trace.skip = 3;
-       save_stack_trace(&xhlock->trace);
+
+       if (crossrelease_fullstack) {
+               xhlock->trace.skip = 3;
+               save_stack_trace(&xhlock->trace);
+       } else {
+               xhlock->trace.nr_entries = 1;
+               xhlock->trace.entries[0] = hlock->acquire_ip;
+       }
 }
 
 static inline int same_context_xhlock(struct hist_lock *xhlock)
index 2655f26ec882689f42d2ba7831209f166ce45869..c7471c3fb79898aa9c0176af57f72812564d2641 100644 (file)
 #include <linux/spinlock.h>
 #include <asm/qrwlock.h>
 
-/*
- * This internal data structure is used for optimizing access to some of
- * the subfields within the atomic_t cnts.
- */
-struct __qrwlock {
-       union {
-               atomic_t cnts;
-               struct {
-#ifdef __LITTLE_ENDIAN
-                       u8 wmode;       /* Writer mode   */
-                       u8 rcnts[3];    /* Reader counts */
-#else
-                       u8 rcnts[3];    /* Reader counts */
-                       u8 wmode;       /* Writer mode   */
-#endif
-               };
-       };
-       arch_spinlock_t lock;
-};
-
-/**
- * rspin_until_writer_unlock - inc reader count & spin until writer is gone
- * @lock  : Pointer to queue rwlock structure
- * @writer: Current queue rwlock writer status byte
- *
- * In interrupt context or at the head of the queue, the reader will just
- * increment the reader count & wait until the writer releases the lock.
- */
-static __always_inline void
-rspin_until_writer_unlock(struct qrwlock *lock, u32 cnts)
-{
-       while ((cnts & _QW_WMASK) == _QW_LOCKED) {
-               cpu_relax();
-               cnts = atomic_read_acquire(&lock->cnts);
-       }
-}
-
 /**
  * queued_read_lock_slowpath - acquire read lock of a queue rwlock
  * @lock: Pointer to queue rwlock structure
- * @cnts: Current qrwlock lock value
  */
-void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts)
+void queued_read_lock_slowpath(struct qrwlock *lock)
 {
        /*
         * Readers come here when they cannot get the lock without waiting
@@ -73,13 +35,11 @@ void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts)
        if (unlikely(in_interrupt())) {
                /*
                 * Readers in interrupt context will get the lock immediately
-                * if the writer is just waiting (not holding the lock yet).
-                * The rspin_until_writer_unlock() function returns immediately
-                * in this case. Otherwise, they will spin (with ACQUIRE
-                * semantics) until the lock is available without waiting in
-                * the queue.
+                * if the writer is just waiting (not holding the lock yet),
+                * so spin with ACQUIRE semantics until the lock is available
+                * without waiting in the queue.
                 */
-               rspin_until_writer_unlock(lock, cnts);
+               atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED));
                return;
        }
        atomic_sub(_QR_BIAS, &lock->cnts);
@@ -88,14 +48,14 @@ void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts)
         * Put the reader into the wait queue
         */
        arch_spin_lock(&lock->wait_lock);
+       atomic_add(_QR_BIAS, &lock->cnts);
 
        /*
         * The ACQUIRE semantics of the following spinning code ensure
         * that accesses can't leak upwards out of our subsequent critical
         * section in the case that the lock is currently held for write.
         */
-       cnts = atomic_fetch_add_acquire(_QR_BIAS, &lock->cnts);
-       rspin_until_writer_unlock(lock, cnts);
+       atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED));
 
        /*
         * Signal the next one in queue to become queue head
@@ -110,8 +70,6 @@ EXPORT_SYMBOL(queued_read_lock_slowpath);
  */
 void queued_write_lock_slowpath(struct qrwlock *lock)
 {
-       u32 cnts;
-
        /* Put the writer into the wait queue */
        arch_spin_lock(&lock->wait_lock);
 
@@ -120,30 +78,14 @@ void queued_write_lock_slowpath(struct qrwlock *lock)
            (atomic_cmpxchg_acquire(&lock->cnts, 0, _QW_LOCKED) == 0))
                goto unlock;
 
-       /*
-        * Set the waiting flag to notify readers that a writer is pending,
-        * or wait for a previous writer to go away.
-        */
-       for (;;) {
-               struct __qrwlock *l = (struct __qrwlock *)lock;
-
-               if (!READ_ONCE(l->wmode) &&
-                  (cmpxchg_relaxed(&l->wmode, 0, _QW_WAITING) == 0))
-                       break;
+       /* Set the waiting flag to notify readers that a writer is pending */
+       atomic_add(_QW_WAITING, &lock->cnts);
 
-               cpu_relax();
-       }
-
-       /* When no more readers, set the locked flag */
-       for (;;) {
-               cnts = atomic_read(&lock->cnts);
-               if ((cnts == _QW_WAITING) &&
-                   (atomic_cmpxchg_acquire(&lock->cnts, _QW_WAITING,
-                                           _QW_LOCKED) == _QW_WAITING))
-                       break;
-
-               cpu_relax();
-       }
+       /* When no more readers or writers, set the locked flag */
+       do {
+               atomic_cond_read_acquire(&lock->cnts, VAL == _QW_WAITING);
+       } while (atomic_cmpxchg_relaxed(&lock->cnts, _QW_WAITING,
+                                       _QW_LOCKED) != _QW_WAITING);
 unlock:
        arch_spin_unlock(&lock->wait_lock);
 }
index 15b6a39366c6210d3dc90440fb43b29f8d27a969..6ee477765e6c5cf8d0c2ed00dbd9fa20cdb4a1b4 100644 (file)
@@ -61,21 +61,50 @@ struct pv_node {
 #include "qspinlock_stat.h"
 
 /*
+ * Hybrid PV queued/unfair lock
+ *
  * By replacing the regular queued_spin_trylock() with the function below,
  * it will be called once when a lock waiter enter the PV slowpath before
- * being queued. By allowing one lock stealing attempt here when the pending
- * bit is off, it helps to reduce the performance impact of lock waiter
- * preemption without the drawback of lock starvation.
+ * being queued.
+ *
+ * The pending bit is set by the queue head vCPU of the MCS wait queue in
+ * pv_wait_head_or_lock() to signal that it is ready to spin on the lock.
+ * When that bit becomes visible to the incoming waiters, no lock stealing
+ * is allowed. The function will return immediately to make the waiters
+ * enter the MCS wait queue. So lock starvation shouldn't happen as long
+ * as the queued mode vCPUs are actively running to set the pending bit
+ * and hence disabling lock stealing.
+ *
+ * When the pending bit isn't set, the lock waiters will stay in the unfair
+ * mode spinning on the lock unless the MCS wait queue is empty. In this
+ * case, the lock waiters will enter the queued mode slowpath trying to
+ * become the queue head and set the pending bit.
+ *
+ * This hybrid PV queued/unfair lock combines the best attributes of a
+ * queued lock (no lock starvation) and an unfair lock (good performance
+ * on not heavily contended locks).
  */
-#define queued_spin_trylock(l) pv_queued_spin_steal_lock(l)
-static inline bool pv_queued_spin_steal_lock(struct qspinlock *lock)
+#define queued_spin_trylock(l) pv_hybrid_queued_unfair_trylock(l)
+static inline bool pv_hybrid_queued_unfair_trylock(struct qspinlock *lock)
 {
        struct __qspinlock *l = (void *)lock;
 
-       if (!(atomic_read(&lock->val) & _Q_LOCKED_PENDING_MASK) &&
-           (cmpxchg_acquire(&l->locked, 0, _Q_LOCKED_VAL) == 0)) {
-               qstat_inc(qstat_pv_lock_stealing, true);
-               return true;
+       /*
+        * Stay in unfair lock mode as long as queued mode waiters are
+        * present in the MCS wait queue but the pending bit isn't set.
+        */
+       for (;;) {
+               int val = atomic_read(&lock->val);
+
+               if (!(val & _Q_LOCKED_PENDING_MASK) &&
+                  (cmpxchg_acquire(&l->locked, 0, _Q_LOCKED_VAL) == 0)) {
+                       qstat_inc(qstat_pv_lock_stealing, true);
+                       return true;
+               }
+               if (!(val & _Q_TAIL_MASK) || (val & _Q_PENDING_MASK))
+                       break;
+
+               cpu_relax();
        }
 
        return false;
index a6c76a4832b40d60dacafaa33490c3a30eb77c70..f549c552dbf1e376a412efc1cb7a95a7029f2f7a 100644 (file)
@@ -29,6 +29,22 @@ void __sched down_read(struct rw_semaphore *sem)
 
 EXPORT_SYMBOL(down_read);
 
+int __sched down_read_killable(struct rw_semaphore *sem)
+{
+       might_sleep();
+       rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
+
+       if (LOCK_CONTENDED_RETURN(sem, __down_read_trylock, __down_read_killable)) {
+               rwsem_release(&sem->dep_map, 1, _RET_IP_);
+               return -EINTR;
+       }
+
+       rwsem_set_reader_owned(sem);
+       return 0;
+}
+
+EXPORT_SYMBOL(down_read_killable);
+
 /*
  * trylock for reading -- returns 1 if successful, 0 if contention
  */
index 6e40fdfba326b9e415dbea410eb7cb2166d51e45..1fd1a7543cdddf39197acaa3882a0f9de7ddb3ab 100644 (file)
 #if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC)
 /*
  * The __lock_function inlines are taken from
- * include/linux/spinlock_api_smp.h
+ * spinlock : include/linux/spinlock_api_smp.h
+ * rwlock   : include/linux/rwlock_api_smp.h
  */
 #else
-#define raw_read_can_lock(l)   read_can_lock(l)
-#define raw_write_can_lock(l)  write_can_lock(l)
 
 /*
  * Some architectures can relax in favour of the CPU owning the lock.
@@ -69,7 +68,7 @@ void __lockfunc __raw_##op##_lock(locktype##_t *lock)                 \
                                                                        \
                if (!(lock)->break_lock)                                \
                        (lock)->break_lock = 1;                         \
-               while (!raw_##op##_can_lock(lock) && (lock)->break_lock)\
+               while ((lock)->break_lock)                              \
                        arch_##op##_relax(&lock->raw_lock);             \
        }                                                               \
        (lock)->break_lock = 0;                                         \
@@ -89,7 +88,7 @@ unsigned long __lockfunc __raw_##op##_lock_irqsave(locktype##_t *lock)        \
                                                                        \
                if (!(lock)->break_lock)                                \
                        (lock)->break_lock = 1;                         \
-               while (!raw_##op##_can_lock(lock) && (lock)->break_lock)\
+               while ((lock)->break_lock)                              \
                        arch_##op##_relax(&lock->raw_lock);             \
        }                                                               \
        (lock)->break_lock = 0;                                         \
index de66ec82599289d786063457ef46a3619893bb03..32c2cdaccd93966cd0fda561511fe90674e45022 100644 (file)
@@ -278,6 +278,16 @@ static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
 module_param(sig_enforce, bool_enable_only, 0644);
 #endif /* !CONFIG_MODULE_SIG_FORCE */
 
+/*
+ * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
+ * on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
+ */
+bool is_module_sig_enforced(void)
+{
+       return sig_enforce;
+}
+EXPORT_SYMBOL(is_module_sig_enforced);
+
 /* Block module loading/unloading? */
 int modules_disabled = 0;
 core_param(nomodule, modules_disabled, bint, 0);
@@ -1516,7 +1526,7 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info)
                sattr->mattr.show = module_sect_show;
                sattr->mattr.store = NULL;
                sattr->mattr.attr.name = sattr->name;
-               sattr->mattr.attr.mode = S_IRUGO;
+               sattr->mattr.attr.mode = S_IRUSR;
                *(gattr++) = &(sattr++)->mattr.attr;
        }
        *gattr = NULL;
@@ -4147,6 +4157,7 @@ static int m_show(struct seq_file *m, void *p)
 {
        struct module *mod = list_entry(p, struct module, list);
        char buf[MODULE_FLAGS_BUF_SIZE];
+       unsigned long value;
 
        /* We always ignore unformed modules. */
        if (mod->state == MODULE_STATE_UNFORMED)
@@ -4162,7 +4173,8 @@ static int m_show(struct seq_file *m, void *p)
                   mod->state == MODULE_STATE_COMING ? "Loading" :
                   "Live");
        /* Used by oprofile and other similar tools. */
-       seq_printf(m, " 0x%pK", mod->core_layout.base);
+       value = m->private ? 0 : (unsigned long)mod->core_layout.base;
+       seq_printf(m, " 0x" KALLSYM_FMT, value);
 
        /* Taints info */
        if (mod->taints)
@@ -4184,9 +4196,23 @@ static const struct seq_operations modules_op = {
        .show   = m_show
 };
 
+/*
+ * This also sets the "private" pointer to non-NULL if the
+ * kernel pointers should be hidden (so you can just test
+ * "m->private" to see if you should keep the values private).
+ *
+ * We use the same logic as for /proc/kallsyms.
+ */
 static int modules_open(struct inode *inode, struct file *file)
 {
-       return seq_open(file, &modules_op);
+       int err = seq_open(file, &modules_op);
+
+       if (!err) {
+               struct seq_file *m = file->private_data;
+               m->private = kallsyms_show_value() ? NULL : (void *)8ul;
+       }
+
+       return 0;
 }
 
 static const struct file_operations proc_modules_operations = {
index e8517b63eb372eaa14b37bc32b616630e25766e1..e880ca22c5a589127b5c7f7023434e99e090972b 100644 (file)
@@ -259,20 +259,6 @@ config APM_EMULATION
          anything, try disabling/enabling this option (or disabling/enabling
          APM in your BIOS).
 
-config PM_OPP
-       bool
-       select SRCU
-       ---help---
-         SOCs have a standard set of tuples consisting of frequency and
-         voltage pairs that the device will support per voltage domain. This
-         is called Operating Performance Point or OPP. The actual definitions
-         of OPP varies over silicon within the same family of devices.
-
-         OPP layer organizes the data internally using device pointers
-         representing individual voltage domains and provides SOC
-         implementations a ready to use framework to manage OPPs.
-         For more information, read <file:Documentation/power/opp.txt>
-
 config PM_CLK
        def_bool y
        depends on PM && HAVE_CLK
index 97b0df71303ef7bbecf28d1479c3e198885b6199..9d7503910ce220302c29a9ea4f3ba0e2fab8ef26 100644 (file)
@@ -701,8 +701,8 @@ static int __init pm_qos_power_init(void)
        for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) {
                ret = register_pm_qos_misc(pm_qos_array[i], d);
                if (ret < 0) {
-                       printk(KERN_ERR "pm_qos_param: %s setup failed\n",
-                              pm_qos_array[i]->name);
+                       pr_err("%s: %s setup failed\n",
+                              __func__, pm_qos_array[i]->name);
                        return ret;
                }
        }
index 0972a8e09d082d99c7f197cbe6bd4fdb6475ba33..a917a301e201a38148d6aef8970af088c082e718 100644 (file)
@@ -10,6 +10,8 @@
  *
  */
 
+#define pr_fmt(fmt) "PM: " fmt
+
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/mm.h>
@@ -967,7 +969,7 @@ void __init __register_nosave_region(unsigned long start_pfn,
        region->end_pfn = end_pfn;
        list_add_tail(&region->list, &nosave_regions);
  Report:
-       printk(KERN_INFO "PM: Registered nosave memory: [mem %#010llx-%#010llx]\n",
+       pr_info("Registered nosave memory: [mem %#010llx-%#010llx]\n",
                (unsigned long long) start_pfn << PAGE_SHIFT,
                ((unsigned long long) end_pfn << PAGE_SHIFT) - 1);
 }
@@ -1039,7 +1041,7 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
        list_for_each_entry(region, &nosave_regions, list) {
                unsigned long pfn;
 
-               pr_debug("PM: Marking nosave pages: [mem %#010llx-%#010llx]\n",
+               pr_debug("Marking nosave pages: [mem %#010llx-%#010llx]\n",
                         (unsigned long long) region->start_pfn << PAGE_SHIFT,
                         ((unsigned long long) region->end_pfn << PAGE_SHIFT)
                                - 1);
@@ -1095,7 +1097,7 @@ int create_basic_memory_bitmaps(void)
        free_pages_map = bm2;
        mark_nosave_pages(forbidden_pages_map);
 
-       pr_debug("PM: Basic memory bitmaps created\n");
+       pr_debug("Basic memory bitmaps created\n");
 
        return 0;
 
@@ -1131,7 +1133,7 @@ void free_basic_memory_bitmaps(void)
        memory_bm_free(bm2, PG_UNSAFE_CLEAR);
        kfree(bm2);
 
-       pr_debug("PM: Basic memory bitmaps freed\n");
+       pr_debug("Basic memory bitmaps freed\n");
 }
 
 void clear_free_pages(void)
@@ -1152,7 +1154,7 @@ void clear_free_pages(void)
                pfn = memory_bm_next_pfn(bm);
        }
        memory_bm_position_reset(bm);
-       pr_info("PM: free pages cleared after restore\n");
+       pr_info("free pages cleared after restore\n");
 #endif /* PAGE_POISONING_ZERO */
 }
 
@@ -1690,7 +1692,7 @@ int hibernate_preallocate_memory(void)
        ktime_t start, stop;
        int error;
 
-       printk(KERN_INFO "PM: Preallocating image memory... ");
+       pr_info("Preallocating image memory... ");
        start = ktime_get();
 
        error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
@@ -1821,13 +1823,13 @@ int hibernate_preallocate_memory(void)
 
  out:
        stop = ktime_get();
-       printk(KERN_CONT "done (allocated %lu pages)\n", pages);
+       pr_cont("done (allocated %lu pages)\n", pages);
        swsusp_show_speed(start, stop, pages, "Allocated");
 
        return 0;
 
  err_out:
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
        swsusp_free();
        return -ENOMEM;
 }
@@ -1867,8 +1869,8 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
                        free += zone_page_state(zone, NR_FREE_PAGES);
 
        nr_pages += count_pages_for_highmem(nr_highmem);
-       pr_debug("PM: Normal pages needed: %u + %u, available pages: %u\n",
-               nr_pages, PAGES_FOR_IO, free);
+       pr_debug("Normal pages needed: %u + %u, available pages: %u\n",
+                nr_pages, PAGES_FOR_IO, free);
 
        return free > nr_pages + PAGES_FOR_IO;
 }
@@ -1961,20 +1963,20 @@ asmlinkage __visible int swsusp_save(void)
 {
        unsigned int nr_pages, nr_highmem;
 
-       printk(KERN_INFO "PM: Creating hibernation image:\n");
+       pr_info("Creating hibernation image:\n");
 
        drain_local_pages(NULL);
        nr_pages = count_data_pages();
        nr_highmem = count_highmem_pages();
-       printk(KERN_INFO "PM: Need to copy %u pages\n", nr_pages + nr_highmem);
+       pr_info("Need to copy %u pages\n", nr_pages + nr_highmem);
 
        if (!enough_free_mem(nr_pages, nr_highmem)) {
-               printk(KERN_ERR "PM: Not enough free memory\n");
+               pr_err("Not enough free memory\n");
                return -ENOMEM;
        }
 
        if (swsusp_alloc(&copy_bm, nr_pages, nr_highmem)) {
-               printk(KERN_ERR "PM: Memory allocation failed\n");
+               pr_err("Memory allocation failed\n");
                return -ENOMEM;
        }
 
@@ -1995,8 +1997,7 @@ asmlinkage __visible int swsusp_save(void)
        nr_copy_pages = nr_pages;
        nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
 
-       printk(KERN_INFO "PM: Hibernation image created (%d pages copied)\n",
-               nr_pages);
+       pr_info("Hibernation image created (%d pages copied)\n", nr_pages);
 
        return 0;
 }
@@ -2170,7 +2171,7 @@ static int check_header(struct swsusp_info *info)
        if (!reason && info->num_physpages != get_num_physpages())
                reason = "memory size";
        if (reason) {
-               printk(KERN_ERR "PM: Image mismatch: %s\n", reason);
+               pr_err("Image mismatch: %s\n", reason);
                return -EPERM;
        }
        return 0;
index ccd2d20e6b067f6a7c3bb83a5848e9c0b333fade..0685c44994314614780606c6f303e5035165a0af 100644 (file)
@@ -437,7 +437,6 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
                        error = suspend_ops->enter(state);
                        trace_suspend_resume(TPS("machine_suspend"),
                                state, false);
-                       events_check_enabled = false;
                } else if (*wakeup) {
                        error = -EBUSY;
                }
@@ -582,6 +581,7 @@ static int enter_state(suspend_state_t state)
        pm_restore_gfp_mask();
 
  Finish:
+       events_check_enabled = false;
        pm_pr_dbg("Finishing wakeup.\n");
        suspend_finish();
  Unlock:
index d7cdc426ee3809bbaafdfd9d5698f83db654e23a..293ead59ecccbab5c3013be15d5f4cbfbef2315f 100644 (file)
@@ -12,6 +12,8 @@
  *
  */
 
+#define pr_fmt(fmt) "PM: " fmt
+
 #include <linux/module.h>
 #include <linux/file.h>
 #include <linux/delay.h>
@@ -241,9 +243,9 @@ static void hib_end_io(struct bio *bio)
        struct page *page = bio->bi_io_vec[0].bv_page;
 
        if (bio->bi_status) {
-               printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n",
-                               MAJOR(bio_dev(bio)), MINOR(bio_dev(bio)),
-                               (unsigned long long)bio->bi_iter.bi_sector);
+               pr_alert("Read-error on swap-device (%u:%u:%Lu)\n",
+                        MAJOR(bio_dev(bio)), MINOR(bio_dev(bio)),
+                        (unsigned long long)bio->bi_iter.bi_sector);
        }
 
        if (bio_data_dir(bio) == WRITE)
@@ -273,8 +275,8 @@ static int hib_submit_io(int op, int op_flags, pgoff_t page_off, void *addr,
        bio_set_op_attrs(bio, op, op_flags);
 
        if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
-               printk(KERN_ERR "PM: Adding page to bio failed at %llu\n",
-                       (unsigned long long)bio->bi_iter.bi_sector);
+               pr_err("Adding page to bio failed at %llu\n",
+                      (unsigned long long)bio->bi_iter.bi_sector);
                bio_put(bio);
                return -EFAULT;
        }
@@ -319,7 +321,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
                error = hib_submit_io(REQ_OP_WRITE, REQ_SYNC,
                                      swsusp_resume_block, swsusp_header, NULL);
        } else {
-               printk(KERN_ERR "PM: Swap header not found!\n");
+               pr_err("Swap header not found!\n");
                error = -ENODEV;
        }
        return error;
@@ -413,8 +415,7 @@ static int get_swap_writer(struct swap_map_handle *handle)
        ret = swsusp_swap_check();
        if (ret) {
                if (ret != -ENOSPC)
-                       printk(KERN_ERR "PM: Cannot find swap device, try "
-                                       "swapon -a.\n");
+                       pr_err("Cannot find swap device, try swapon -a\n");
                return ret;
        }
        handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
@@ -491,9 +492,9 @@ static int swap_writer_finish(struct swap_map_handle *handle,
 {
        if (!error) {
                flush_swap_writer(handle);
-               printk(KERN_INFO "PM: S");
+               pr_info("S");
                error = mark_swapfiles(handle, flags);
-               printk("|\n");
+               pr_cont("|\n");
        }
 
        if (error)
@@ -542,7 +543,7 @@ static int save_image(struct swap_map_handle *handle,
 
        hib_init_batch(&hb);
 
-       printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n",
+       pr_info("Saving image data pages (%u pages)...\n",
                nr_to_write);
        m = nr_to_write / 10;
        if (!m)
@@ -557,8 +558,8 @@ static int save_image(struct swap_map_handle *handle,
                if (ret)
                        break;
                if (!(nr_pages % m))
-                       printk(KERN_INFO "PM: Image saving progress: %3d%%\n",
-                              nr_pages / m * 10);
+                       pr_info("Image saving progress: %3d%%\n",
+                               nr_pages / m * 10);
                nr_pages++;
        }
        err2 = hib_wait_io(&hb);
@@ -566,7 +567,7 @@ static int save_image(struct swap_map_handle *handle,
        if (!ret)
                ret = err2;
        if (!ret)
-               printk(KERN_INFO "PM: Image saving done.\n");
+               pr_info("Image saving done\n");
        swsusp_show_speed(start, stop, nr_to_write, "Wrote");
        return ret;
 }
@@ -692,14 +693,14 @@ static int save_image_lzo(struct swap_map_handle *handle,
 
        page = (void *)__get_free_page(__GFP_RECLAIM | __GFP_HIGH);
        if (!page) {
-               printk(KERN_ERR "PM: Failed to allocate LZO page\n");
+               pr_err("Failed to allocate LZO page\n");
                ret = -ENOMEM;
                goto out_clean;
        }
 
        data = vmalloc(sizeof(*data) * nr_threads);
        if (!data) {
-               printk(KERN_ERR "PM: Failed to allocate LZO data\n");
+               pr_err("Failed to allocate LZO data\n");
                ret = -ENOMEM;
                goto out_clean;
        }
@@ -708,7 +709,7 @@ static int save_image_lzo(struct swap_map_handle *handle,
 
        crc = kmalloc(sizeof(*crc), GFP_KERNEL);
        if (!crc) {
-               printk(KERN_ERR "PM: Failed to allocate crc\n");
+               pr_err("Failed to allocate crc\n");
                ret = -ENOMEM;
                goto out_clean;
        }
@@ -726,8 +727,7 @@ static int save_image_lzo(struct swap_map_handle *handle,
                                            "image_compress/%u", thr);
                if (IS_ERR(data[thr].thr)) {
                        data[thr].thr = NULL;
-                       printk(KERN_ERR
-                              "PM: Cannot start compression threads\n");
+                       pr_err("Cannot start compression threads\n");
                        ret = -ENOMEM;
                        goto out_clean;
                }
@@ -749,7 +749,7 @@ static int save_image_lzo(struct swap_map_handle *handle,
        crc->thr = kthread_run(crc32_threadfn, crc, "image_crc32");
        if (IS_ERR(crc->thr)) {
                crc->thr = NULL;
-               printk(KERN_ERR "PM: Cannot start CRC32 thread\n");
+               pr_err("Cannot start CRC32 thread\n");
                ret = -ENOMEM;
                goto out_clean;
        }
@@ -760,10 +760,9 @@ static int save_image_lzo(struct swap_map_handle *handle,
         */
        handle->reqd_free_pages = reqd_free_pages();
 
-       printk(KERN_INFO
-               "PM: Using %u thread(s) for compression.\n"
-               "PM: Compressing and saving image data (%u pages)...\n",
-               nr_threads, nr_to_write);
+       pr_info("Using %u thread(s) for compression\n", nr_threads);
+       pr_info("Compressing and saving image data (%u pages)...\n",
+               nr_to_write);
        m = nr_to_write / 10;
        if (!m)
                m = 1;
@@ -783,10 +782,8 @@ static int save_image_lzo(struct swap_map_handle *handle,
                                       data_of(*snapshot), PAGE_SIZE);
 
                                if (!(nr_pages % m))
-                                       printk(KERN_INFO
-                                              "PM: Image saving progress: "
-                                              "%3d%%\n",
-                                              nr_pages / m * 10);
+                                       pr_info("Image saving progress: %3d%%\n",
+                                               nr_pages / m * 10);
                                nr_pages++;
                        }
                        if (!off)
@@ -813,15 +810,14 @@ static int save_image_lzo(struct swap_map_handle *handle,
                        ret = data[thr].ret;
 
                        if (ret < 0) {
-                               printk(KERN_ERR "PM: LZO compression failed\n");
+                               pr_err("LZO compression failed\n");
                                goto out_finish;
                        }
 
                        if (unlikely(!data[thr].cmp_len ||
                                     data[thr].cmp_len >
                                     lzo1x_worst_compress(data[thr].unc_len))) {
-                               printk(KERN_ERR
-                                      "PM: Invalid LZO compressed length\n");
+                               pr_err("Invalid LZO compressed length\n");
                                ret = -1;
                                goto out_finish;
                        }
@@ -857,7 +853,7 @@ out_finish:
        if (!ret)
                ret = err2;
        if (!ret)
-               printk(KERN_INFO "PM: Image saving done.\n");
+               pr_info("Image saving done\n");
        swsusp_show_speed(start, stop, nr_to_write, "Wrote");
 out_clean:
        if (crc) {
@@ -888,7 +884,7 @@ static int enough_swap(unsigned int nr_pages, unsigned int flags)
        unsigned int free_swap = count_swap_pages(root_swap, 1);
        unsigned int required;
 
-       pr_debug("PM: Free swap pages: %u\n", free_swap);
+       pr_debug("Free swap pages: %u\n", free_swap);
 
        required = PAGES_FOR_IO + nr_pages;
        return free_swap > required;
@@ -915,12 +911,12 @@ int swsusp_write(unsigned int flags)
        pages = snapshot_get_image_size();
        error = get_swap_writer(&handle);
        if (error) {
-               printk(KERN_ERR "PM: Cannot get swap writer\n");
+               pr_err("Cannot get swap writer\n");
                return error;
        }
        if (flags & SF_NOCOMPRESS_MODE) {
                if (!enough_swap(pages, flags)) {
-                       printk(KERN_ERR "PM: Not enough free swap\n");
+                       pr_err("Not enough free swap\n");
                        error = -ENOSPC;
                        goto out_finish;
                }
@@ -1068,8 +1064,7 @@ static int load_image(struct swap_map_handle *handle,
        hib_init_batch(&hb);
 
        clean_pages_on_read = true;
-       printk(KERN_INFO "PM: Loading image data pages (%u pages)...\n",
-               nr_to_read);
+       pr_info("Loading image data pages (%u pages)...\n", nr_to_read);
        m = nr_to_read / 10;
        if (!m)
                m = 1;
@@ -1087,8 +1082,8 @@ static int load_image(struct swap_map_handle *handle,
                if (ret)
                        break;
                if (!(nr_pages % m))
-                       printk(KERN_INFO "PM: Image loading progress: %3d%%\n",
-                              nr_pages / m * 10);
+                       pr_info("Image loading progress: %3d%%\n",
+                               nr_pages / m * 10);
                nr_pages++;
        }
        err2 = hib_wait_io(&hb);
@@ -1096,7 +1091,7 @@ static int load_image(struct swap_map_handle *handle,
        if (!ret)
                ret = err2;
        if (!ret) {
-               printk(KERN_INFO "PM: Image loading done.\n");
+               pr_info("Image loading done\n");
                snapshot_write_finalize(snapshot);
                if (!snapshot_image_loaded(snapshot))
                        ret = -ENODATA;
@@ -1190,14 +1185,14 @@ static int load_image_lzo(struct swap_map_handle *handle,
 
        page = vmalloc(sizeof(*page) * LZO_MAX_RD_PAGES);
        if (!page) {
-               printk(KERN_ERR "PM: Failed to allocate LZO page\n");
+               pr_err("Failed to allocate LZO page\n");
                ret = -ENOMEM;
                goto out_clean;
        }
 
        data = vmalloc(sizeof(*data) * nr_threads);
        if (!data) {
-               printk(KERN_ERR "PM: Failed to allocate LZO data\n");
+               pr_err("Failed to allocate LZO data\n");
                ret = -ENOMEM;
                goto out_clean;
        }
@@ -1206,7 +1201,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
 
        crc = kmalloc(sizeof(*crc), GFP_KERNEL);
        if (!crc) {
-               printk(KERN_ERR "PM: Failed to allocate crc\n");
+               pr_err("Failed to allocate crc\n");
                ret = -ENOMEM;
                goto out_clean;
        }
@@ -1226,8 +1221,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
                                            "image_decompress/%u", thr);
                if (IS_ERR(data[thr].thr)) {
                        data[thr].thr = NULL;
-                       printk(KERN_ERR
-                              "PM: Cannot start decompression threads\n");
+                       pr_err("Cannot start decompression threads\n");
                        ret = -ENOMEM;
                        goto out_clean;
                }
@@ -1249,7 +1243,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
        crc->thr = kthread_run(crc32_threadfn, crc, "image_crc32");
        if (IS_ERR(crc->thr)) {
                crc->thr = NULL;
-               printk(KERN_ERR "PM: Cannot start CRC32 thread\n");
+               pr_err("Cannot start CRC32 thread\n");
                ret = -ENOMEM;
                goto out_clean;
        }
@@ -1274,8 +1268,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
                if (!page[i]) {
                        if (i < LZO_CMP_PAGES) {
                                ring_size = i;
-                               printk(KERN_ERR
-                                      "PM: Failed to allocate LZO pages\n");
+                               pr_err("Failed to allocate LZO pages\n");
                                ret = -ENOMEM;
                                goto out_clean;
                        } else {
@@ -1285,10 +1278,9 @@ static int load_image_lzo(struct swap_map_handle *handle,
        }
        want = ring_size = i;
 
-       printk(KERN_INFO
-               "PM: Using %u thread(s) for decompression.\n"
-               "PM: Loading and decompressing image data (%u pages)...\n",
-               nr_threads, nr_to_read);
+       pr_info("Using %u thread(s) for decompression\n", nr_threads);
+       pr_info("Loading and decompressing image data (%u pages)...\n",
+               nr_to_read);
        m = nr_to_read / 10;
        if (!m)
                m = 1;
@@ -1348,8 +1340,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
                        if (unlikely(!data[thr].cmp_len ||
                                     data[thr].cmp_len >
                                     lzo1x_worst_compress(LZO_UNC_SIZE))) {
-                               printk(KERN_ERR
-                                      "PM: Invalid LZO compressed length\n");
+                               pr_err("Invalid LZO compressed length\n");
                                ret = -1;
                                goto out_finish;
                        }
@@ -1400,16 +1391,14 @@ static int load_image_lzo(struct swap_map_handle *handle,
                        ret = data[thr].ret;
 
                        if (ret < 0) {
-                               printk(KERN_ERR
-                                      "PM: LZO decompression failed\n");
+                               pr_err("LZO decompression failed\n");
                                goto out_finish;
                        }
 
                        if (unlikely(!data[thr].unc_len ||
                                     data[thr].unc_len > LZO_UNC_SIZE ||
                                     data[thr].unc_len & (PAGE_SIZE - 1))) {
-                               printk(KERN_ERR
-                                      "PM: Invalid LZO uncompressed length\n");
+                               pr_err("Invalid LZO uncompressed length\n");
                                ret = -1;
                                goto out_finish;
                        }
@@ -1420,10 +1409,8 @@ static int load_image_lzo(struct swap_map_handle *handle,
                                       data[thr].unc + off, PAGE_SIZE);
 
                                if (!(nr_pages % m))
-                                       printk(KERN_INFO
-                                              "PM: Image loading progress: "
-                                              "%3d%%\n",
-                                              nr_pages / m * 10);
+                                       pr_info("Image loading progress: %3d%%\n",
+                                               nr_pages / m * 10);
                                nr_pages++;
 
                                ret = snapshot_write_next(snapshot);
@@ -1448,15 +1435,14 @@ out_finish:
        }
        stop = ktime_get();
        if (!ret) {
-               printk(KERN_INFO "PM: Image loading done.\n");
+               pr_info("Image loading done\n");
                snapshot_write_finalize(snapshot);
                if (!snapshot_image_loaded(snapshot))
                        ret = -ENODATA;
                if (!ret) {
                        if (swsusp_header->flags & SF_CRC32_MODE) {
                                if(handle->crc32 != swsusp_header->crc32) {
-                                       printk(KERN_ERR
-                                              "PM: Invalid image CRC32!\n");
+                                       pr_err("Invalid image CRC32!\n");
                                        ret = -ENODATA;
                                }
                        }
@@ -1513,9 +1499,9 @@ int swsusp_read(unsigned int *flags_p)
        swap_reader_finish(&handle);
 end:
        if (!error)
-               pr_debug("PM: Image successfully loaded\n");
+               pr_debug("Image successfully loaded\n");
        else
-               pr_debug("PM: Error %d resuming\n", error);
+               pr_debug("Error %d resuming\n", error);
        return error;
 }
 
@@ -1552,13 +1538,13 @@ put:
                if (error)
                        blkdev_put(hib_resume_bdev, FMODE_READ);
                else
-                       pr_debug("PM: Image signature found, resuming\n");
+                       pr_debug("Image signature found, resuming\n");
        } else {
                error = PTR_ERR(hib_resume_bdev);
        }
 
        if (error)
-               pr_debug("PM: Image not found (code %d)\n", error);
+               pr_debug("Image not found (code %d)\n", error);
 
        return error;
 }
@@ -1570,7 +1556,7 @@ put:
 void swsusp_close(fmode_t mode)
 {
        if (IS_ERR(hib_resume_bdev)) {
-               pr_debug("PM: Image device not initialised\n");
+               pr_debug("Image device not initialised\n");
                return;
        }
 
@@ -1594,7 +1580,7 @@ int swsusp_unmark(void)
                                        swsusp_resume_block,
                                        swsusp_header, NULL);
        } else {
-               printk(KERN_ERR "PM: Cannot find swsusp signature!\n");
+               pr_err("Cannot find swsusp signature!\n");
                error = -ENODEV;
        }
 
index e4b43fef89f5e12c5d4e0125d2500aff28bbde5f..59c471de342a05140c7c5271c6fa4ce16f364361 100644 (file)
@@ -203,6 +203,21 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head)
 extern int rcu_cpu_stall_suppress;
 int rcu_jiffies_till_stall_check(void);
 
+#define rcu_ftrace_dump_stall_suppress() \
+do { \
+       if (!rcu_cpu_stall_suppress) \
+               rcu_cpu_stall_suppress = 3; \
+} while (0)
+
+#define rcu_ftrace_dump_stall_unsuppress() \
+do { \
+       if (rcu_cpu_stall_suppress == 3) \
+               rcu_cpu_stall_suppress = 0; \
+} while (0)
+
+#else /* #endif #ifdef CONFIG_RCU_STALL_COMMON */
+#define rcu_ftrace_dump_stall_suppress()
+#define rcu_ftrace_dump_stall_unsuppress()
 #endif /* #ifdef CONFIG_RCU_STALL_COMMON */
 
 /*
@@ -220,8 +235,12 @@ do { \
        static atomic_t ___rfd_beenhere = ATOMIC_INIT(0); \
        \
        if (!atomic_read(&___rfd_beenhere) && \
-           !atomic_xchg(&___rfd_beenhere, 1)) \
+           !atomic_xchg(&___rfd_beenhere, 1)) { \
+               tracing_off(); \
+               rcu_ftrace_dump_stall_suppress(); \
                ftrace_dump(oops_dump_mode); \
+               rcu_ftrace_dump_stall_unsuppress(); \
+       } \
 } while (0)
 
 void rcu_early_boot_tests(void);
index 7649fcd2c4c7de0504c4113309f2aa8a9757adb3..88cba7c2956ce70395d2b30bba1b1bdb3088fdb3 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/rcupdate.h>
 
 #include "rcu_segcblist.h"
 
index 45f2ffbc1e78ed587d26d6764cb8d1aba0f6f2d8..74f6b0146b9878f3b9d42dd85b6bd1924be08387 100644 (file)
@@ -51,6 +51,7 @@
 #include <asm/byteorder.h>
 #include <linux/torture.h>
 #include <linux/vmalloc.h>
+#include <linux/sched/debug.h>
 
 #include "rcu.h"
 
@@ -89,6 +90,7 @@ torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
 torture_param(int, stall_cpu, 0, "Stall duration (s), zero to disable.");
 torture_param(int, stall_cpu_holdoff, 10,
             "Time to wait before starting stall (s).");
+torture_param(int, stall_cpu_irqsoff, 0, "Disable interrupts while stalling.");
 torture_param(int, stat_interval, 60,
             "Number of seconds between stats printk()s");
 torture_param(int, stutter, 5, "Number of seconds to run/halt test");
@@ -1076,7 +1078,7 @@ static void rcu_torture_timer_cb(struct rcu_head *rhp)
  * counter in the element should never be greater than 1, otherwise, the
  * RCU implementation is broken.
  */
-static void rcu_torture_timer(unsigned long unused)
+static void rcu_torture_timer(struct timer_list *unused)
 {
        int idx;
        unsigned long started;
@@ -1163,7 +1165,7 @@ rcu_torture_reader(void *arg)
        VERBOSE_TOROUT_STRING("rcu_torture_reader task started");
        set_user_nice(current, MAX_NICE);
        if (irqreader && cur_ops->irq_capable)
-               setup_timer_on_stack(&t, rcu_torture_timer, 0);
+               timer_setup_on_stack(&t, rcu_torture_timer, 0);
 
        do {
                if (irqreader && cur_ops->irq_capable) {
@@ -1239,6 +1241,7 @@ rcu_torture_stats_print(void)
        long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
        long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
        static unsigned long rtcv_snap = ULONG_MAX;
+       static bool splatted;
        struct task_struct *wtp;
 
        for_each_possible_cpu(cpu) {
@@ -1324,6 +1327,10 @@ rcu_torture_stats_print(void)
                         gpnum, completed, flags,
                         wtp == NULL ? ~0UL : wtp->state,
                         wtp == NULL ? -1 : (int)task_cpu(wtp));
+               if (!splatted && wtp) {
+                       sched_show_task(wtp);
+                       splatted = true;
+               }
                show_rcu_gp_kthreads();
                rcu_ftrace_dump(DUMP_ALL);
        }
@@ -1357,7 +1364,7 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
                 "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
                 "test_boost=%d/%d test_boost_interval=%d "
                 "test_boost_duration=%d shutdown_secs=%d "
-                "stall_cpu=%d stall_cpu_holdoff=%d "
+                "stall_cpu=%d stall_cpu_holdoff=%d stall_cpu_irqsoff=%d "
                 "n_barrier_cbs=%d "
                 "onoff_interval=%d onoff_holdoff=%d\n",
                 torture_type, tag, nrealreaders, nfakewriters,
@@ -1365,7 +1372,7 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
                 stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
                 test_boost, cur_ops->can_boost,
                 test_boost_interval, test_boost_duration, shutdown_secs,
-                stall_cpu, stall_cpu_holdoff,
+                stall_cpu, stall_cpu_holdoff, stall_cpu_irqsoff,
                 n_barrier_cbs,
                 onoff_interval, onoff_holdoff);
 }
@@ -1430,12 +1437,19 @@ static int rcu_torture_stall(void *args)
        if (!kthread_should_stop()) {
                stop_at = get_seconds() + stall_cpu;
                /* RCU CPU stall is expected behavior in following code. */
-               pr_alert("rcu_torture_stall start.\n");
                rcu_read_lock();
-               preempt_disable();
+               if (stall_cpu_irqsoff)
+                       local_irq_disable();
+               else
+                       preempt_disable();
+               pr_alert("rcu_torture_stall start on CPU %d.\n",
+                        smp_processor_id());
                while (ULONG_CMP_LT(get_seconds(), stop_at))
                        continue;  /* Induce RCU CPU stall warning. */
-               preempt_enable();
+               if (stall_cpu_irqsoff)
+                       local_irq_enable();
+               else
+                       preempt_enable();
                rcu_read_unlock();
                pr_alert("rcu_torture_stall end.\n");
        }
index 3e3650e94ae6b1dd26fea711a8961d627c16623b..f9c0ca2ccf0ca530ab8bb53ad54039c62c858a87 100644 (file)
@@ -534,8 +534,8 @@ module_param(rcu_kick_kthreads, bool, 0644);
  * How long the grace period must be before we start recruiting
  * quiescent-state help from rcu_note_context_switch().
  */
-static ulong jiffies_till_sched_qs = HZ / 20;
-module_param(jiffies_till_sched_qs, ulong, 0644);
+static ulong jiffies_till_sched_qs = HZ / 10;
+module_param(jiffies_till_sched_qs, ulong, 0444);
 
 static bool rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
                                  struct rcu_data *rdp);
@@ -734,7 +734,7 @@ static int rcu_future_needs_gp(struct rcu_state *rsp)
        int idx = (READ_ONCE(rnp->completed) + 1) & 0x1;
        int *fp = &rnp->need_future_gp[idx];
 
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_future_needs_gp() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        return READ_ONCE(*fp);
 }
 
@@ -746,7 +746,7 @@ static int rcu_future_needs_gp(struct rcu_state *rsp)
 static bool
 cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
 {
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "cpu_needs_another_gp() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        if (rcu_gp_in_progress(rsp))
                return false;  /* No, a grace period is already in progress. */
        if (rcu_future_needs_gp(rsp))
@@ -773,7 +773,7 @@ static void rcu_eqs_enter_common(bool user)
        struct rcu_data *rdp;
        struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
 
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_eqs_enter_common() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        trace_rcu_dyntick(TPS("Start"), rdtp->dynticks_nesting, 0);
        if (IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
            !user && !is_idle_task(current)) {
@@ -837,10 +837,13 @@ static void rcu_eqs_enter(bool user)
  * We crowbar the ->dynticks_nesting field to zero to allow for
  * the possibility of usermode upcalls having messed up our count
  * of interrupt nesting level during the prior busy period.
+ *
+ * If you add or remove a call to rcu_idle_enter(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_idle_enter(void)
 {
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_idle_enter() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        rcu_eqs_enter(false);
 }
 
@@ -852,10 +855,13 @@ void rcu_idle_enter(void)
  * is permitted between this call and rcu_user_exit(). This way the
  * CPU doesn't need to maintain the tick for RCU maintenance purposes
  * when the CPU runs in userspace.
+ *
+ * If you add or remove a call to rcu_user_enter(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_user_enter(void)
 {
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_user_enter() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        rcu_eqs_enter(true);
 }
 #endif /* CONFIG_NO_HZ_FULL */
@@ -875,12 +881,15 @@ void rcu_user_enter(void)
  * Use things like work queues to work around this limitation.
  *
  * You have been warned.
+ *
+ * If you add or remove a call to rcu_irq_exit(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_irq_exit(void)
 {
        struct rcu_dynticks *rdtp;
 
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_exit() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        rdtp = this_cpu_ptr(&rcu_dynticks);
 
        /* Page faults can happen in NMI handlers, so check... */
@@ -899,6 +908,9 @@ void rcu_irq_exit(void)
 
 /*
  * Wrapper for rcu_irq_exit() where interrupts are enabled.
+ *
+ * If you add or remove a call to rcu_irq_exit_irqson(), be sure to test
+ * with CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_irq_exit_irqson(void)
 {
@@ -947,7 +959,7 @@ static void rcu_eqs_exit(bool user)
        struct rcu_dynticks *rdtp;
        long long oldval;
 
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_eqs_exit() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        rdtp = this_cpu_ptr(&rcu_dynticks);
        oldval = rdtp->dynticks_nesting;
        WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && oldval < 0);
@@ -971,6 +983,9 @@ static void rcu_eqs_exit(bool user)
  * allow for the possibility of usermode upcalls messing up our count
  * of interrupt nesting level during the busy period that is just
  * now starting.
+ *
+ * If you add or remove a call to rcu_idle_exit(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_idle_exit(void)
 {
@@ -987,6 +1002,9 @@ void rcu_idle_exit(void)
  *
  * Exit RCU idle mode while entering the kernel because it can
  * run a RCU read side critical section anytime.
+ *
+ * If you add or remove a call to rcu_user_exit(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_user_exit(void)
 {
@@ -1012,13 +1030,16 @@ void rcu_user_exit(void)
  * Use things like work queues to work around this limitation.
  *
  * You have been warned.
+ *
+ * If you add or remove a call to rcu_irq_enter(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_irq_enter(void)
 {
        struct rcu_dynticks *rdtp;
        long long oldval;
 
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_enter() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        rdtp = this_cpu_ptr(&rcu_dynticks);
 
        /* Page faults can happen in NMI handlers, so check... */
@@ -1037,6 +1058,9 @@ void rcu_irq_enter(void)
 
 /*
  * Wrapper for rcu_irq_enter() where interrupts are enabled.
+ *
+ * If you add or remove a call to rcu_irq_enter_irqson(), be sure to test
+ * with CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_irq_enter_irqson(void)
 {
@@ -1055,6 +1079,9 @@ void rcu_irq_enter_irqson(void)
  * that the CPU is active.  This implementation permits nested NMIs, as
  * long as the nesting level does not overflow an int.  (You will probably
  * run out of stack space first.)
+ *
+ * If you add or remove a call to rcu_nmi_enter(), be sure to test
+ * with CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_nmi_enter(void)
 {
@@ -1087,6 +1114,9 @@ void rcu_nmi_enter(void)
  * RCU-idle period, update rdtp->dynticks and rdtp->dynticks_nmi_nesting
  * to let the RCU grace-period handling know that the CPU is back to
  * being RCU-idle.
+ *
+ * If you add or remove a call to rcu_nmi_exit(), be sure to test
+ * with CONFIG_RCU_EQS_DEBUG=y.
  */
 void rcu_nmi_exit(void)
 {
@@ -1206,6 +1236,22 @@ static int rcu_is_cpu_rrupt_from_idle(void)
        return __this_cpu_read(rcu_dynticks.dynticks_nesting) <= 1;
 }
 
+/*
+ * We are reporting a quiescent state on behalf of some other CPU, so
+ * it is our responsibility to check for and handle potential overflow
+ * of the rcu_node ->gpnum counter with respect to the rcu_data counters.
+ * After all, the CPU might be in deep idle state, and thus executing no
+ * code whatsoever.
+ */
+static void rcu_gpnum_ovf(struct rcu_node *rnp, struct rcu_data *rdp)
+{
+       lockdep_assert_held(&rnp->lock);
+       if (ULONG_CMP_LT(READ_ONCE(rdp->gpnum) + ULONG_MAX / 4, rnp->gpnum))
+               WRITE_ONCE(rdp->gpwrap, true);
+       if (ULONG_CMP_LT(rdp->rcu_iw_gpnum + ULONG_MAX / 4, rnp->gpnum))
+               rdp->rcu_iw_gpnum = rnp->gpnum + ULONG_MAX / 4;
+}
+
 /*
  * Snapshot the specified CPU's dynticks counter so that we can later
  * credit them with an implicit quiescent state.  Return 1 if this CPU
@@ -1216,14 +1262,33 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp)
        rdp->dynticks_snap = rcu_dynticks_snap(rdp->dynticks);
        if (rcu_dynticks_in_eqs(rdp->dynticks_snap)) {
                trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti"));
-               if (ULONG_CMP_LT(READ_ONCE(rdp->gpnum) + ULONG_MAX / 4,
-                                rdp->mynode->gpnum))
-                       WRITE_ONCE(rdp->gpwrap, true);
+               rcu_gpnum_ovf(rdp->mynode, rdp);
                return 1;
        }
        return 0;
 }
 
+/*
+ * Handler for the irq_work request posted when a grace period has
+ * gone on for too long, but not yet long enough for an RCU CPU
+ * stall warning.  Set state appropriately, but just complain if
+ * there is unexpected state on entry.
+ */
+static void rcu_iw_handler(struct irq_work *iwp)
+{
+       struct rcu_data *rdp;
+       struct rcu_node *rnp;
+
+       rdp = container_of(iwp, struct rcu_data, rcu_iw);
+       rnp = rdp->mynode;
+       raw_spin_lock_rcu_node(rnp);
+       if (!WARN_ON_ONCE(!rdp->rcu_iw_pending)) {
+               rdp->rcu_iw_gpnum = rnp->gpnum;
+               rdp->rcu_iw_pending = false;
+       }
+       raw_spin_unlock_rcu_node(rnp);
+}
+
 /*
  * Return true if the specified CPU has passed through a quiescent
  * state by virtue of being in or having passed through an dynticks
@@ -1235,8 +1300,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
        unsigned long jtsq;
        bool *rnhqp;
        bool *ruqp;
-       unsigned long rjtsc;
-       struct rcu_node *rnp;
+       struct rcu_node *rnp = rdp->mynode;
 
        /*
         * If the CPU passed through or entered a dynticks idle phase with
@@ -1249,34 +1313,25 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
        if (rcu_dynticks_in_eqs_since(rdp->dynticks, rdp->dynticks_snap)) {
                trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti"));
                rdp->dynticks_fqs++;
+               rcu_gpnum_ovf(rnp, rdp);
                return 1;
        }
 
-       /* Compute and saturate jiffies_till_sched_qs. */
-       jtsq = jiffies_till_sched_qs;
-       rjtsc = rcu_jiffies_till_stall_check();
-       if (jtsq > rjtsc / 2) {
-               WRITE_ONCE(jiffies_till_sched_qs, rjtsc);
-               jtsq = rjtsc / 2;
-       } else if (jtsq < 1) {
-               WRITE_ONCE(jiffies_till_sched_qs, 1);
-               jtsq = 1;
-       }
-
        /*
         * Has this CPU encountered a cond_resched_rcu_qs() since the
         * beginning of the grace period?  For this to be the case,
         * the CPU has to have noticed the current grace period.  This
         * might not be the case for nohz_full CPUs looping in the kernel.
         */
-       rnp = rdp->mynode;
+       jtsq = jiffies_till_sched_qs;
        ruqp = per_cpu_ptr(&rcu_dynticks.rcu_urgent_qs, rdp->cpu);
        if (time_after(jiffies, rdp->rsp->gp_start + jtsq) &&
            READ_ONCE(rdp->rcu_qs_ctr_snap) != per_cpu(rcu_dynticks.rcu_qs_ctr, rdp->cpu) &&
            READ_ONCE(rdp->gpnum) == rnp->gpnum && !rdp->gpwrap) {
                trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("rqc"));
+               rcu_gpnum_ovf(rnp, rdp);
                return 1;
-       } else {
+       } else if (time_after(jiffies, rdp->rsp->gp_start + jtsq)) {
                /* Load rcu_qs_ctr before store to rcu_urgent_qs. */
                smp_store_release(ruqp, true);
        }
@@ -1285,6 +1340,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
        if (!(rdp->grpmask & rcu_rnp_online_cpus(rnp))) {
                trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("ofl"));
                rdp->offline_fqs++;
+               rcu_gpnum_ovf(rnp, rdp);
                return 1;
        }
 
@@ -1304,10 +1360,6 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
         * updates are only once every few jiffies, the probability of
         * lossage (and thus of slight grace-period extension) is
         * quite low.
-        *
-        * Note that if the jiffies_till_sched_qs boot/sysfs parameter
-        * is set too high, we override with half of the RCU CPU stall
-        * warning delay.
         */
        rnhqp = &per_cpu(rcu_dynticks.rcu_need_heavy_qs, rdp->cpu);
        if (!READ_ONCE(*rnhqp) &&
@@ -1316,15 +1368,26 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
                WRITE_ONCE(*rnhqp, true);
                /* Store rcu_need_heavy_qs before rcu_urgent_qs. */
                smp_store_release(ruqp, true);
-               rdp->rsp->jiffies_resched += 5; /* Re-enable beating. */
+               rdp->rsp->jiffies_resched += jtsq; /* Re-enable beating. */
        }
 
        /*
-        * If more than halfway to RCU CPU stall-warning time, do
-        * a resched_cpu() to try to loosen things up a bit.
+        * If more than halfway to RCU CPU stall-warning time, do a
+        * resched_cpu() to try to loosen things up a bit.  Also check to
+        * see if the CPU is getting hammered with interrupts, but only
+        * once per grace period, just to keep the IPIs down to a dull roar.
         */
-       if (jiffies - rdp->rsp->gp_start > rcu_jiffies_till_stall_check() / 2)
+       if (jiffies - rdp->rsp->gp_start > rcu_jiffies_till_stall_check() / 2) {
                resched_cpu(rdp->cpu);
+               if (IS_ENABLED(CONFIG_IRQ_WORK) &&
+                   !rdp->rcu_iw_pending && rdp->rcu_iw_gpnum != rnp->gpnum &&
+                   (rnp->ffmask & rdp->grpmask)) {
+                       init_irq_work(&rdp->rcu_iw, rcu_iw_handler);
+                       rdp->rcu_iw_pending = true;
+                       rdp->rcu_iw_gpnum = rnp->gpnum;
+                       irq_work_queue_on(&rdp->rcu_iw, rdp->cpu);
+               }
+       }
 
        return 0;
 }
@@ -1513,6 +1576,7 @@ static void print_cpu_stall(struct rcu_state *rsp)
 {
        int cpu;
        unsigned long flags;
+       struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
        struct rcu_node *rnp = rcu_get_root(rsp);
        long totqlen = 0;
 
@@ -1528,7 +1592,9 @@ static void print_cpu_stall(struct rcu_state *rsp)
         */
        pr_err("INFO: %s self-detected stall on CPU", rsp->name);
        print_cpu_stall_info_begin();
+       raw_spin_lock_irqsave_rcu_node(rdp->mynode, flags);
        print_cpu_stall_info(rsp, smp_processor_id());
+       raw_spin_unlock_irqrestore_rcu_node(rdp->mynode, flags);
        print_cpu_stall_info_end();
        for_each_possible_cpu(cpu)
                totqlen += rcu_segcblist_n_cbs(&per_cpu_ptr(rsp->rda,
@@ -1922,6 +1988,7 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp,
                rdp->core_needs_qs = need_gp;
                zero_cpu_stall_ticks(rdp);
                WRITE_ONCE(rdp->gpwrap, false);
+               rcu_gpnum_ovf(rnp, rdp);
        }
        return ret;
 }
@@ -3702,6 +3769,8 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
        rdp->cpu_no_qs.b.norm = true;
        rdp->rcu_qs_ctr_snap = per_cpu(rcu_dynticks.rcu_qs_ctr, cpu);
        rdp->core_needs_qs = false;
+       rdp->rcu_iw_pending = false;
+       rdp->rcu_iw_gpnum = rnp->gpnum - 1;
        trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuonl"));
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
 }
@@ -3739,10 +3808,24 @@ static void rcutree_affinity_setting(unsigned int cpu, int outgoing)
  */
 int rcutree_online_cpu(unsigned int cpu)
 {
-       sync_sched_exp_online_cleanup(cpu);
-       rcutree_affinity_setting(cpu, -1);
+       unsigned long flags;
+       struct rcu_data *rdp;
+       struct rcu_node *rnp;
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp) {
+               rdp = per_cpu_ptr(rsp->rda, cpu);
+               rnp = rdp->mynode;
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
+               rnp->ffmask |= rdp->grpmask;
+               raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+       }
        if (IS_ENABLED(CONFIG_TREE_SRCU))
                srcu_online_cpu(cpu);
+       if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
+               return 0; /* Too early in boot for scheduler work. */
+       sync_sched_exp_online_cleanup(cpu);
+       rcutree_affinity_setting(cpu, -1);
        return 0;
 }
 
@@ -3752,6 +3835,19 @@ int rcutree_online_cpu(unsigned int cpu)
  */
 int rcutree_offline_cpu(unsigned int cpu)
 {
+       unsigned long flags;
+       struct rcu_data *rdp;
+       struct rcu_node *rnp;
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp) {
+               rdp = per_cpu_ptr(rsp->rda, cpu);
+               rnp = rdp->mynode;
+               raw_spin_lock_irqsave_rcu_node(rnp, flags);
+               rnp->ffmask &= ~rdp->grpmask;
+               raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+       }
+
        rcutree_affinity_setting(cpu, cpu);
        if (IS_ENABLED(CONFIG_TREE_SRCU))
                srcu_offline_cpu(cpu);
@@ -4200,8 +4296,7 @@ void __init rcu_init(void)
        for_each_online_cpu(cpu) {
                rcutree_prepare_cpu(cpu);
                rcu_cpu_starting(cpu);
-               if (IS_ENABLED(CONFIG_TREE_SRCU))
-                       srcu_online_cpu(cpu);
+               rcutree_online_cpu(cpu);
        }
 }
 
index 8e1f285f0a70ae53c4436e31df43d166109f6c67..46a5d1991450b58d520bb8296c122edb1c8b4f03 100644 (file)
@@ -103,6 +103,7 @@ struct rcu_node {
                                /* Online CPUs for next expedited GP. */
                                /*  Any CPU that has ever been online will */
                                /*  have its bit set. */
+       unsigned long ffmask;   /* Fully functional CPUs. */
        unsigned long grpmask;  /* Mask to apply to parent qsmask. */
                                /*  Only one bit will be set in this mask. */
        int     grplo;          /* lowest-numbered CPU or group here. */
@@ -285,6 +286,10 @@ struct rcu_data {
 
        /* 8) RCU CPU stall data. */
        unsigned int softirq_snap;      /* Snapshot of softirq activity. */
+       /* ->rcu_iw* fields protected by leaf rcu_node ->lock. */
+       struct irq_work rcu_iw;         /* Check for non-irq activity. */
+       bool rcu_iw_pending;            /* Is ->rcu_iw pending? */
+       unsigned long rcu_iw_gpnum;     /* ->gpnum associated with ->rcu_iw. */
 
        int cpu;
        struct rcu_state *rsp;
index e012b9be777e3ba00ccf2fe4d05df78b78abd8f5..db85ca3975f1863626ee2219afbb85f0244773d7 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/oom.h>
 #include <linux/sched/debug.h>
 #include <linux/smpboot.h>
+#include <linux/sched/isolation.h>
 #include <uapi/linux/sched/types.h>
 #include "../time/tick-internal.h"
 
@@ -54,6 +55,7 @@ DEFINE_PER_CPU(char, rcu_cpu_has_work);
  * This probably needs to be excluded from -rt builds.
  */
 #define rt_mutex_owner(a) ({ WARN_ON_ONCE(1); NULL; })
+#define rt_mutex_futex_unlock(x) WARN_ON_ONCE(1)
 
 #endif /* #else #ifdef CONFIG_RCU_BOOST */
 
@@ -325,7 +327,7 @@ static void rcu_preempt_note_context_switch(bool preempt)
        struct rcu_data *rdp;
        struct rcu_node *rnp;
 
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_preempt_note_context_switch() invoked with interrupts enabled!!!\n");
+       lockdep_assert_irqs_disabled();
        WARN_ON_ONCE(!preempt && t->rcu_read_lock_nesting > 0);
        if (t->rcu_read_lock_nesting > 0 &&
            !t->rcu_read_unlock_special.b.blocked) {
@@ -530,7 +532,7 @@ void rcu_read_unlock_special(struct task_struct *t)
 
                /* Unboost if we were boosted. */
                if (IS_ENABLED(CONFIG_RCU_BOOST) && drop_boost_mutex)
-                       rt_mutex_unlock(&rnp->boost_mtx);
+                       rt_mutex_futex_unlock(&rnp->boost_mtx);
 
                /*
                 * If this was the last task on the expedited lists,
@@ -911,8 +913,6 @@ void exit_rcu(void)
 
 #ifdef CONFIG_RCU_BOOST
 
-#include "../locking/rtmutex_common.h"
-
 static void rcu_wake_cond(struct task_struct *t, int status)
 {
        /*
@@ -1421,7 +1421,7 @@ int rcu_needs_cpu(u64 basemono, u64 *nextevt)
        struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
        unsigned long dj;
 
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_needs_cpu() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
 
        /* Snapshot to detect later posting of non-lazy callback. */
        rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
@@ -1470,7 +1470,7 @@ static void rcu_prepare_for_idle(void)
        struct rcu_state *rsp;
        int tne;
 
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_prepare_for_idle() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        if (rcu_is_nocb_cpu(smp_processor_id()))
                return;
 
@@ -1507,7 +1507,7 @@ static void rcu_prepare_for_idle(void)
        rdtp->last_accelerate = jiffies;
        for_each_rcu_flavor(rsp) {
                rdp = this_cpu_ptr(rsp->rda);
-               if (rcu_segcblist_pend_cbs(&rdp->cblist))
+               if (!rcu_segcblist_pend_cbs(&rdp->cblist))
                        continue;
                rnp = rdp->mynode;
                raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */
@@ -1525,7 +1525,7 @@ static void rcu_prepare_for_idle(void)
  */
 static void rcu_cleanup_after_idle(void)
 {
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_cleanup_after_idle() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        if (rcu_is_nocb_cpu(smp_processor_id()))
                return;
        if (rcu_try_advance_all_cbs())
@@ -1671,6 +1671,7 @@ static void print_cpu_stall_info_begin(void)
  */
 static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
 {
+       unsigned long delta;
        char fast_no_hz[72];
        struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_dynticks *rdtp = rdp->dynticks;
@@ -1685,11 +1686,15 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
                ticks_value = rsp->gpnum - rdp->gpnum;
        }
        print_cpu_stall_fast_no_hz(fast_no_hz, cpu);
-       pr_err("\t%d-%c%c%c: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u fqs=%ld %s\n",
+       delta = rdp->mynode->gpnum - rdp->rcu_iw_gpnum;
+       pr_err("\t%d-%c%c%c%c: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u fqs=%ld %s\n",
               cpu,
               "O."[!!cpu_online(cpu)],
               "o."[!!(rdp->grpmask & rdp->mynode->qsmaskinit)],
               "N."[!!(rdp->grpmask & rdp->mynode->qsmaskinitnext)],
+              !IS_ENABLED(CONFIG_IRQ_WORK) ? '?' :
+                       rdp->rcu_iw_pending ? (int)min(delta, 9UL) + '0' :
+                               "!."[!delta],
               ticks_value, ticks_title,
               rcu_dynticks_snap(rdtp) & 0xfff,
               rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting,
@@ -2012,7 +2017,7 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_data *my_rdp,
                                                     struct rcu_data *rdp,
                                                     unsigned long flags)
 {
-       RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_nocb_adopt_orphan_cbs() invoked with irqs enabled!!!");
+       lockdep_assert_irqs_disabled();
        if (!rcu_is_nocb_cpu(smp_processor_id()))
                return false; /* Not NOCBs CPU, caller must migrate CBs. */
        __call_rcu_nocb_enqueue(my_rdp, rcu_segcblist_head(&rdp->cblist),
@@ -2261,9 +2266,11 @@ static void do_nocb_deferred_wakeup_common(struct rcu_data *rdp)
 }
 
 /* Do a deferred wakeup of rcu_nocb_kthread() from a timer handler. */
-static void do_nocb_deferred_wakeup_timer(unsigned long x)
+static void do_nocb_deferred_wakeup_timer(struct timer_list *t)
 {
-       do_nocb_deferred_wakeup_common((struct rcu_data *)x);
+       struct rcu_data *rdp = from_timer(rdp, t, nocb_timer);
+
+       do_nocb_deferred_wakeup_common(rdp);
 }
 
 /*
@@ -2327,8 +2334,7 @@ static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
        init_swait_queue_head(&rdp->nocb_wq);
        rdp->nocb_follower_tail = &rdp->nocb_follower_head;
        raw_spin_lock_init(&rdp->nocb_lock);
-       setup_timer(&rdp->nocb_timer, do_nocb_deferred_wakeup_timer,
-                   (unsigned long)rdp);
+       timer_setup(&rdp->nocb_timer, do_nocb_deferred_wakeup_timer, 0);
 }
 
 /*
@@ -2583,7 +2589,7 @@ static void rcu_bind_gp_kthread(void)
 
        if (!tick_nohz_full_enabled())
                return;
-       housekeeping_affine(current);
+       housekeeping_affine(current, HK_FLAG_RCU);
 }
 
 /* Record the current task on dyntick-idle entry. */
index 5033b66d27530f30eea3625ac4e529f631aa0a41..fbd56d6e575b2b0eaa5a653c7919fe596ee1b8f5 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/kthread.h>
 #include <linux/tick.h>
 #include <linux/rcupdate_wait.h>
+#include <linux/sched/isolation.h>
 
 #define CREATE_TRACE_POINTS
 
@@ -494,6 +495,7 @@ EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read);
 #endif
 
 int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */
+EXPORT_SYMBOL_GPL(rcu_cpu_stall_suppress);
 static int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
 
 module_param(rcu_cpu_stall_suppress, int, 0644);
@@ -575,7 +577,6 @@ DEFINE_STATIC_SRCU(tasks_rcu_exit_srcu);
 static int rcu_task_stall_timeout __read_mostly = RCU_TASK_STALL_TIMEOUT;
 module_param(rcu_task_stall_timeout, int, 0644);
 
-static void rcu_spawn_tasks_kthread(void);
 static struct task_struct *rcu_tasks_kthread_ptr;
 
 /**
@@ -600,7 +601,6 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func)
 {
        unsigned long flags;
        bool needwake;
-       bool havetask = READ_ONCE(rcu_tasks_kthread_ptr);
 
        rhp->next = NULL;
        rhp->func = func;
@@ -610,11 +610,8 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func)
        rcu_tasks_cbs_tail = &rhp->next;
        raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags);
        /* We can't create the thread unless interrupts are enabled. */
-       if ((needwake && havetask) ||
-           (!havetask && !irqs_disabled_flags(flags))) {
-               rcu_spawn_tasks_kthread();
+       if (needwake && READ_ONCE(rcu_tasks_kthread_ptr))
                wake_up(&rcu_tasks_cbs_wq);
-       }
 }
 EXPORT_SYMBOL_GPL(call_rcu_tasks);
 
@@ -718,7 +715,7 @@ static int __noreturn rcu_tasks_kthread(void *arg)
        LIST_HEAD(rcu_tasks_holdouts);
 
        /* Run on housekeeping CPUs by default.  Sysadm can move if desired. */
-       housekeeping_affine(current);
+       housekeeping_affine(current, HK_FLAG_RCU);
 
        /*
         * Each pass through the following loop makes one check for
@@ -853,27 +850,18 @@ static int __noreturn rcu_tasks_kthread(void *arg)
        }
 }
 
-/* Spawn rcu_tasks_kthread() at first call to call_rcu_tasks(). */
-static void rcu_spawn_tasks_kthread(void)
+/* Spawn rcu_tasks_kthread() at core_initcall() time. */
+static int __init rcu_spawn_tasks_kthread(void)
 {
-       static DEFINE_MUTEX(rcu_tasks_kthread_mutex);
        struct task_struct *t;
 
-       if (READ_ONCE(rcu_tasks_kthread_ptr)) {
-               smp_mb(); /* Ensure caller sees full kthread. */
-               return;
-       }
-       mutex_lock(&rcu_tasks_kthread_mutex);
-       if (rcu_tasks_kthread_ptr) {
-               mutex_unlock(&rcu_tasks_kthread_mutex);
-               return;
-       }
        t = kthread_run(rcu_tasks_kthread, NULL, "rcu_tasks_kthread");
        BUG_ON(IS_ERR(t));
        smp_mb(); /* Ensure others see full kthread. */
        WRITE_ONCE(rcu_tasks_kthread_ptr, t);
-       mutex_unlock(&rcu_tasks_kthread_mutex);
+       return 0;
 }
+core_initcall(rcu_spawn_tasks_kthread);
 
 /* Do the srcu_read_lock() for the above synchronize_srcu().  */
 void exit_tasks_rcu_start(void)
index 9b5f04404152c296af3a96132f27cfc80ffa9af9..54ba6de3757c7ebdc83ad7f6c5b3d22b9d20f600 100644 (file)
@@ -397,9 +397,32 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc,
                res->start = p->start;
        if (res->end > p->end)
                res->end = p->end;
+       res->flags = p->flags;
+       res->desc = p->desc;
        return 0;
 }
 
+static int __walk_iomem_res_desc(struct resource *res, unsigned long desc,
+                                bool first_level_children_only,
+                                void *arg,
+                                int (*func)(struct resource *, void *))
+{
+       u64 orig_end = res->end;
+       int ret = -1;
+
+       while ((res->start < res->end) &&
+              !find_next_iomem_res(res, desc, first_level_children_only)) {
+               ret = (*func)(res, arg);
+               if (ret)
+                       break;
+
+               res->start = res->end + 1;
+               res->end = orig_end;
+       }
+
+       return ret;
+}
+
 /*
  * Walks through iomem resources and calls func() with matching resource
  * ranges. This walks through whole tree and not just first level children.
@@ -415,29 +438,15 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc,
  * <linux/ioport.h> and set it in 'desc' of a target resource entry.
  */
 int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start,
-               u64 end, void *arg, int (*func)(u64, u64, void *))
+               u64 end, void *arg, int (*func)(struct resource *, void *))
 {
        struct resource res;
-       u64 orig_end;
-       int ret = -1;
 
        res.start = start;
        res.end = end;
        res.flags = flags;
-       orig_end = res.end;
-
-       while ((res.start < res.end) &&
-               (!find_next_iomem_res(&res, desc, false))) {
-
-               ret = (*func)(res.start, res.end, arg);
-               if (ret)
-                       break;
-
-               res.start = res.end + 1;
-               res.end = orig_end;
-       }
 
-       return ret;
+       return __walk_iomem_res_desc(&res, desc, false, arg, func);
 }
 
 /*
@@ -448,25 +457,33 @@ int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start,
  * ranges.
  */
 int walk_system_ram_res(u64 start, u64 end, void *arg,
-                               int (*func)(u64, u64, void *))
+                               int (*func)(struct resource *, void *))
 {
        struct resource res;
-       u64 orig_end;
-       int ret = -1;
 
        res.start = start;
        res.end = end;
        res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
-       orig_end = res.end;
-       while ((res.start < res.end) &&
-               (!find_next_iomem_res(&res, IORES_DESC_NONE, true))) {
-               ret = (*func)(res.start, res.end, arg);
-               if (ret)
-                       break;
-               res.start = res.end + 1;
-               res.end = orig_end;
-       }
-       return ret;
+
+       return __walk_iomem_res_desc(&res, IORES_DESC_NONE, true,
+                                    arg, func);
+}
+
+/*
+ * This function calls the @func callback against all memory ranges, which
+ * are ranges marked as IORESOURCE_MEM and IORESOUCE_BUSY.
+ */
+int walk_mem_res(u64 start, u64 end, void *arg,
+                int (*func)(struct resource *, void *))
+{
+       struct resource res;
+
+       res.start = start;
+       res.end = end;
+       res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+
+       return __walk_iomem_res_desc(&res, IORES_DESC_NONE, true,
+                                    arg, func);
 }
 
 #if !defined(CONFIG_ARCH_HAS_WALK_MEMORY)
@@ -508,6 +525,7 @@ static int __is_ram(unsigned long pfn, unsigned long nr_pages, void *arg)
 {
        return 1;
 }
+
 /*
  * This generic page_is_ram() returns true if specified address is
  * registered as System RAM in iomem_resource list.
index a9ee16bbc6931a6e6cb8631f48bc6c19b39215b4..e2f9d4feff4015dd747a3dea06a345076b7709fd 100644 (file)
@@ -27,3 +27,4 @@ obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o
 obj-$(CONFIG_CPU_FREQ) += cpufreq.o
 obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
 obj-$(CONFIG_MEMBARRIER) += membarrier.o
+obj-$(CONFIG_CPU_ISOLATION) += isolation.o
index ca0f8fc945c6d0891ffc58f54d2c08c271c21c65..e086babe6c611b5abc75143b867ac2aca38c99b2 100644 (file)
@@ -388,7 +388,7 @@ void sched_clock_tick(void)
        if (unlikely(!sched_clock_running))
                return;
 
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        scd = this_scd();
        __scd_stamp(scd);
index d17c5da523a0bc817a6b32413ee7e0ba3e7a6b2e..5b82a00735325ba75ca9a93095953a28cc2b7257 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/profile.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/sched/isolation.h>
 
 #include <asm/switch_to.h>
 #include <asm/tlb.h>
 
 DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
 
+#if defined(CONFIG_SCHED_DEBUG) && defined(HAVE_JUMP_LABEL)
 /*
  * Debugging: various feature bits
+ *
+ * If SCHED_DEBUG is disabled, each compilation unit has its own copy of
+ * sysctl_sched_features, defined in sched.h, to allow constants propagation
+ * at compile time and compiler optimization based on features default.
  */
-
 #define SCHED_FEAT(name, enabled)      \
        (1UL << __SCHED_FEAT_##name) * enabled |
-
 const_debug unsigned int sysctl_sched_features =
 #include "features.h"
        0;
-
 #undef SCHED_FEAT
+#endif
 
 /*
  * Number of tasks to iterate in a single balance run.
@@ -83,9 +87,6 @@ __read_mostly int scheduler_running;
  */
 int sysctl_sched_rt_runtime = 950000;
 
-/* CPUs with isolated domains */
-cpumask_var_t cpu_isolated_map;
-
 /*
  * __task_rq_lock - lock the rq @p resides on.
  */
@@ -505,8 +506,7 @@ void resched_cpu(int cpu)
        struct rq *rq = cpu_rq(cpu);
        unsigned long flags;
 
-       if (!raw_spin_trylock_irqsave(&rq->lock, flags))
-               return;
+       raw_spin_lock_irqsave(&rq->lock, flags);
        resched_curr(rq);
        raw_spin_unlock_irqrestore(&rq->lock, flags);
 }
@@ -526,7 +526,7 @@ int get_nohz_timer_target(void)
        int i, cpu = smp_processor_id();
        struct sched_domain *sd;
 
-       if (!idle_cpu(cpu) && is_housekeeping_cpu(cpu))
+       if (!idle_cpu(cpu) && housekeeping_cpu(cpu, HK_FLAG_TIMER))
                return cpu;
 
        rcu_read_lock();
@@ -535,15 +535,15 @@ int get_nohz_timer_target(void)
                        if (cpu == i)
                                continue;
 
-                       if (!idle_cpu(i) && is_housekeeping_cpu(i)) {
+                       if (!idle_cpu(i) && housekeeping_cpu(i, HK_FLAG_TIMER)) {
                                cpu = i;
                                goto unlock;
                        }
                }
        }
 
-       if (!is_housekeeping_cpu(cpu))
-               cpu = housekeeping_any_cpu();
+       if (!housekeeping_cpu(cpu, HK_FLAG_TIMER))
+               cpu = housekeeping_any_cpu(HK_FLAG_TIMER);
 unlock:
        rcu_read_unlock();
        return cpu;
@@ -733,7 +733,7 @@ int tg_nop(struct task_group *tg, void *data)
 }
 #endif
 
-static void set_load_weight(struct task_struct *p)
+static void set_load_weight(struct task_struct *p, bool update_load)
 {
        int prio = p->static_prio - MAX_RT_PRIO;
        struct load_weight *load = &p->se.load;
@@ -747,8 +747,16 @@ static void set_load_weight(struct task_struct *p)
                return;
        }
 
-       load->weight = scale_load(sched_prio_to_weight[prio]);
-       load->inv_weight = sched_prio_to_wmult[prio];
+       /*
+        * SCHED_OTHER tasks have to update their load when changing their
+        * weight
+        */
+       if (update_load && p->sched_class == &fair_sched_class) {
+               reweight_task(p, prio);
+       } else {
+               load->weight = scale_load(sched_prio_to_weight[prio]);
+               load->inv_weight = sched_prio_to_wmult[prio];
+       }
 }
 
 static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
@@ -2358,7 +2366,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
                        p->static_prio = NICE_TO_PRIO(0);
 
                p->prio = p->normal_prio = __normal_prio(p);
-               set_load_weight(p);
+               set_load_weight(p, false);
 
                /*
                 * We don't need the reset flag anymore after the fork. It has
@@ -3805,7 +3813,7 @@ void set_user_nice(struct task_struct *p, long nice)
                put_prev_task(rq, p);
 
        p->static_prio = NICE_TO_PRIO(nice);
-       set_load_weight(p);
+       set_load_weight(p, true);
        old_prio = p->prio;
        p->prio = effective_prio(p);
        delta = p->prio - old_prio;
@@ -3962,7 +3970,7 @@ static void __setscheduler_params(struct task_struct *p,
         */
        p->rt_priority = attr->sched_priority;
        p->normal_prio = normal_prio(p);
-       set_load_weight(p);
+       set_load_weight(p, true);
 }
 
 /* Actually do priority change: must hold pi & rq lock. */
@@ -4842,6 +4850,7 @@ int __sched _cond_resched(void)
                preempt_schedule_common();
                return 1;
        }
+       rcu_all_qs();
        return 0;
 }
 EXPORT_SYMBOL(_cond_resched);
@@ -5165,6 +5174,7 @@ void sched_show_task(struct task_struct *p)
        show_stack(p, NULL);
        put_task_stack(p);
 }
+EXPORT_SYMBOL_GPL(sched_show_task);
 
 static inline bool
 state_filter_match(unsigned long state_filter, struct task_struct *p)
@@ -5726,10 +5736,6 @@ static inline void sched_init_smt(void) { }
 
 void __init sched_init_smp(void)
 {
-       cpumask_var_t non_isolated_cpus;
-
-       alloc_cpumask_var(&non_isolated_cpus, GFP_KERNEL);
-
        sched_init_numa();
 
        /*
@@ -5739,16 +5745,12 @@ void __init sched_init_smp(void)
         */
        mutex_lock(&sched_domains_mutex);
        sched_init_domains(cpu_active_mask);
-       cpumask_andnot(non_isolated_cpus, cpu_possible_mask, cpu_isolated_map);
-       if (cpumask_empty(non_isolated_cpus))
-               cpumask_set_cpu(smp_processor_id(), non_isolated_cpus);
        mutex_unlock(&sched_domains_mutex);
 
        /* Move init over to a non-isolated CPU */
-       if (set_cpus_allowed_ptr(current, non_isolated_cpus) < 0)
+       if (set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_FLAG_DOMAIN)) < 0)
                BUG();
        sched_init_granularity();
-       free_cpumask_var(non_isolated_cpus);
 
        init_sched_rt_class();
        init_sched_dl_class();
@@ -5933,7 +5935,7 @@ void __init sched_init(void)
                atomic_set(&rq->nr_iowait, 0);
        }
 
-       set_load_weight(&init_task);
+       set_load_weight(&init_task, false);
 
        /*
         * The boot idle thread does lazy MMU switching as well:
@@ -5952,9 +5954,6 @@ void __init sched_init(void)
        calc_load_update = jiffies + LOAD_FREQ;
 
 #ifdef CONFIG_SMP
-       /* May be allocated at isolcpus cmdline parse time */
-       if (cpu_isolated_map == NULL)
-               zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
        idle_thread_set_boot_cpu();
        set_cpu_rq_start_time(smp_processor_id());
 #endif
index 9209d83ecdcf1a52faa9eb3d7d741970b6631faf..2f52ec0f1539fce62a099d9fa559df334a19869c 100644 (file)
@@ -282,8 +282,12 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
                 * Do not reduce the frequency if the CPU has not been idle
                 * recently, as the reduction is likely to be premature then.
                 */
-               if (busy && next_f < sg_policy->next_freq)
+               if (busy && next_f < sg_policy->next_freq) {
                        next_f = sg_policy->next_freq;
+
+                       /* Reset cached freq as next_freq has changed */
+                       sg_policy->cached_raw_freq = 0;
+               }
        }
        sugov_update_commit(sg_policy, time, next_f);
 }
@@ -649,6 +653,7 @@ static int sugov_start(struct cpufreq_policy *policy)
                struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
 
                memset(sg_cpu, 0, sizeof(*sg_cpu));
+               sg_cpu->cpu = cpu;
                sg_cpu->sg_policy = sg_policy;
                sg_cpu->flags = SCHED_CPUFREQ_RT;
                sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
@@ -714,11 +719,6 @@ struct cpufreq_governor *cpufreq_default_governor(void)
 
 static int __init sugov_register(void)
 {
-       int cpu;
-
-       for_each_possible_cpu(cpu)
-               per_cpu(sugov_cpu, cpu).cpu = cpu;
-
        return cpufreq_register_governor(&schedutil_gov);
 }
 fs_initcall(sugov_register);
index 14d2dbf97c531db0dd0c1bba3113a35cbe8d3bd9..9be8b68a66da0cf5a334f2cd38d915b31a2a4b65 100644 (file)
@@ -259,8 +259,7 @@ static inline u64 account_other_time(u64 max)
 {
        u64 accounted;
 
-       /* Shall be converted to a lockdep-enabled lightweight check */
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        accounted = steal_account_process_time(max);
 
index 4ae5c1ea90e26bea2253124a8bc17cc3f84c1ce0..f349f7e98deca60b1b26ab10a0be36719866cd1e 100644 (file)
@@ -243,7 +243,7 @@ static void task_non_contending(struct task_struct *p)
                        if (p->state == TASK_DEAD)
                                sub_rq_bw(p->dl.dl_bw, &rq->dl);
                        raw_spin_lock(&dl_b->lock);
-                       __dl_clear(dl_b, p->dl.dl_bw, dl_bw_cpus(task_cpu(p)));
+                       __dl_sub(dl_b, p->dl.dl_bw, dl_bw_cpus(task_cpu(p)));
                        __dl_clear_params(p);
                        raw_spin_unlock(&dl_b->lock);
                }
@@ -1210,7 +1210,7 @@ static enum hrtimer_restart inactive_task_timer(struct hrtimer *timer)
                }
 
                raw_spin_lock(&dl_b->lock);
-               __dl_clear(dl_b, p->dl.dl_bw, dl_bw_cpus(task_cpu(p)));
+               __dl_sub(dl_b, p->dl.dl_bw, dl_bw_cpus(task_cpu(p)));
                raw_spin_unlock(&dl_b->lock);
                __dl_clear_params(p);
 
@@ -1365,6 +1365,10 @@ enqueue_dl_entity(struct sched_dl_entity *dl_se,
                update_dl_entity(dl_se, pi_se);
        } else if (flags & ENQUEUE_REPLENISH) {
                replenish_dl_entity(dl_se, pi_se);
+       } else if ((flags & ENQUEUE_RESTORE) &&
+                 dl_time_before(dl_se->deadline,
+                                rq_clock(rq_of_dl_rq(dl_rq_of_se(dl_se))))) {
+               setup_new_dl_entity(dl_se);
        }
 
        __enqueue_dl_entity(dl_se);
@@ -2167,7 +2171,7 @@ static void set_cpus_allowed_dl(struct task_struct *p,
                 * until we complete the update.
                 */
                raw_spin_lock(&src_dl_b->lock);
-               __dl_clear(src_dl_b, p->dl.dl_bw, dl_bw_cpus(task_cpu(p)));
+               __dl_sub(src_dl_b, p->dl.dl_bw, dl_bw_cpus(task_cpu(p)));
                raw_spin_unlock(&src_dl_b->lock);
        }
 
@@ -2256,13 +2260,6 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)
 
                return;
        }
-       /*
-        * If p is boosted we already updated its params in
-        * rt_mutex_setprio()->enqueue_task(..., ENQUEUE_REPLENISH),
-        * p's deadline being now already after rq_clock(rq).
-        */
-       if (dl_time_before(p->dl.deadline, rq_clock(rq)))
-               setup_new_dl_entity(&p->dl);
 
        if (rq->curr != p) {
 #ifdef CONFIG_SMP
@@ -2452,7 +2449,7 @@ int sched_dl_overflow(struct task_struct *p, int policy,
        if (dl_policy(policy) && !task_has_dl_policy(p) &&
            !__dl_overflow(dl_b, cpus, 0, new_bw)) {
                if (hrtimer_active(&p->dl.inactive_timer))
-                       __dl_clear(dl_b, p->dl.dl_bw, cpus);
+                       __dl_sub(dl_b, p->dl.dl_bw, cpus);
                __dl_add(dl_b, new_bw, cpus);
                err = 0;
        } else if (dl_policy(policy) && task_has_dl_policy(p) &&
@@ -2464,7 +2461,7 @@ int sched_dl_overflow(struct task_struct *p, int policy,
                 * But this would require to set the task's "inactive
                 * timer" when the task is not inactive.
                 */
-               __dl_clear(dl_b, p->dl.dl_bw, cpus);
+               __dl_sub(dl_b, p->dl.dl_bw, cpus);
                __dl_add(dl_b, new_bw, cpus);
                dl_change_utilization(p, new_bw);
                err = 0;
index 2f93e4a2d9f623915d0023f9b3a7d8b7d7b95cf7..1ca0130ed4f937d8b1abcc0e64fd14ebb3a3cfb7 100644 (file)
@@ -441,9 +441,11 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group
                P_SCHEDSTAT(se->statistics.wait_count);
        }
        P(se->load.weight);
+       P(se->runnable_weight);
 #ifdef CONFIG_SMP
        P(se->avg.load_avg);
        P(se->avg.util_avg);
+       P(se->avg.runnable_load_avg);
 #endif
 
 #undef PN_SCHEDSTAT
@@ -558,16 +560,19 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
        SEQ_printf(m, "  .%-30s: %d\n", "nr_running", cfs_rq->nr_running);
        SEQ_printf(m, "  .%-30s: %ld\n", "load", cfs_rq->load.weight);
 #ifdef CONFIG_SMP
+       SEQ_printf(m, "  .%-30s: %ld\n", "runnable_weight", cfs_rq->runnable_weight);
        SEQ_printf(m, "  .%-30s: %lu\n", "load_avg",
                        cfs_rq->avg.load_avg);
        SEQ_printf(m, "  .%-30s: %lu\n", "runnable_load_avg",
-                       cfs_rq->runnable_load_avg);
+                       cfs_rq->avg.runnable_load_avg);
        SEQ_printf(m, "  .%-30s: %lu\n", "util_avg",
                        cfs_rq->avg.util_avg);
-       SEQ_printf(m, "  .%-30s: %ld\n", "removed_load_avg",
-                       atomic_long_read(&cfs_rq->removed_load_avg));
-       SEQ_printf(m, "  .%-30s: %ld\n", "removed_util_avg",
-                       atomic_long_read(&cfs_rq->removed_util_avg));
+       SEQ_printf(m, "  .%-30s: %ld\n", "removed.load_avg",
+                       cfs_rq->removed.load_avg);
+       SEQ_printf(m, "  .%-30s: %ld\n", "removed.util_avg",
+                       cfs_rq->removed.util_avg);
+       SEQ_printf(m, "  .%-30s: %ld\n", "removed.runnable_sum",
+                       cfs_rq->removed.runnable_sum);
 #ifdef CONFIG_FAIR_GROUP_SCHED
        SEQ_printf(m, "  .%-30s: %lu\n", "tg_load_avg_contrib",
                        cfs_rq->tg_load_avg_contrib);
@@ -1004,10 +1009,13 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
                   "nr_involuntary_switches", (long long)p->nivcsw);
 
        P(se.load.weight);
+       P(se.runnable_weight);
 #ifdef CONFIG_SMP
        P(se.avg.load_sum);
+       P(se.avg.runnable_load_sum);
        P(se.avg.util_sum);
        P(se.avg.load_avg);
+       P(se.avg.runnable_load_avg);
        P(se.avg.util_avg);
        P(se.avg.last_update_time);
 #endif
index 5c09ddf8c8321ca1aa18a6ff7f78d3d2937ec92e..0989676c50e92df396e8a4ef6ccf3545a1e057fe 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/mempolicy.h>
 #include <linux/migrate.h>
 #include <linux/task_work.h>
+#include <linux/sched/isolation.h>
 
 #include <trace/events/sched.h>
 
@@ -717,13 +718,8 @@ void init_entity_runnable_average(struct sched_entity *se)
 {
        struct sched_avg *sa = &se->avg;
 
-       sa->last_update_time = 0;
-       /*
-        * sched_avg's period_contrib should be strictly less then 1024, so
-        * we give it 1023 to make sure it is almost a period (1024us), and
-        * will definitely be update (after enqueue).
-        */
-       sa->period_contrib = 1023;
+       memset(sa, 0, sizeof(*sa));
+
        /*
         * Tasks are intialized with full load to be seen as heavy tasks until
         * they get a chance to stabilize to their real load level.
@@ -731,13 +727,10 @@ void init_entity_runnable_average(struct sched_entity *se)
         * nothing has been attached to the task group yet.
         */
        if (entity_is_task(se))
-               sa->load_avg = scale_load_down(se->load.weight);
-       sa->load_sum = sa->load_avg * LOAD_AVG_MAX;
-       /*
-        * At this point, util_avg won't be used in select_task_rq_fair anyway
-        */
-       sa->util_avg = 0;
-       sa->util_sum = 0;
+               sa->runnable_load_avg = sa->load_avg = scale_load_down(se->load.weight);
+
+       se->runnable_weight = se->load.weight;
+
        /* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */
 }
 
@@ -785,7 +778,6 @@ void post_init_entity_util_avg(struct sched_entity *se)
                } else {
                        sa->util_avg = cap;
                }
-               sa->util_sum = sa->util_avg * LOAD_AVG_MAX;
        }
 
        if (entity_is_task(se)) {
@@ -2026,7 +2018,7 @@ static u64 numa_get_avg_runtime(struct task_struct *p, u64 *period)
                delta = runtime - p->last_sum_exec_runtime;
                *period = now - p->last_task_numa_placement;
        } else {
-               delta = p->se.avg.load_sum / p->se.load.weight;
+               delta = p->se.avg.load_sum;
                *period = LOAD_AVG_MAX;
        }
 
@@ -2693,18 +2685,226 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
        cfs_rq->nr_running--;
 }
 
+/*
+ * Signed add and clamp on underflow.
+ *
+ * Explicitly do a load-store to ensure the intermediate value never hits
+ * memory. This allows lockless observations without ever seeing the negative
+ * values.
+ */
+#define add_positive(_ptr, _val) do {                           \
+       typeof(_ptr) ptr = (_ptr);                              \
+       typeof(_val) val = (_val);                              \
+       typeof(*ptr) res, var = READ_ONCE(*ptr);                \
+                                                               \
+       res = var + val;                                        \
+                                                               \
+       if (val < 0 && res > var)                               \
+               res = 0;                                        \
+                                                               \
+       WRITE_ONCE(*ptr, res);                                  \
+} while (0)
+
+/*
+ * Unsigned subtract and clamp on underflow.
+ *
+ * Explicitly do a load-store to ensure the intermediate value never hits
+ * memory. This allows lockless observations without ever seeing the negative
+ * values.
+ */
+#define sub_positive(_ptr, _val) do {                          \
+       typeof(_ptr) ptr = (_ptr);                              \
+       typeof(*ptr) val = (_val);                              \
+       typeof(*ptr) res, var = READ_ONCE(*ptr);                \
+       res = var - val;                                        \
+       if (res > var)                                          \
+               res = 0;                                        \
+       WRITE_ONCE(*ptr, res);                                  \
+} while (0)
+
+#ifdef CONFIG_SMP
+/*
+ * XXX we want to get rid of these helpers and use the full load resolution.
+ */
+static inline long se_weight(struct sched_entity *se)
+{
+       return scale_load_down(se->load.weight);
+}
+
+static inline long se_runnable(struct sched_entity *se)
+{
+       return scale_load_down(se->runnable_weight);
+}
+
+static inline void
+enqueue_runnable_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       cfs_rq->runnable_weight += se->runnable_weight;
+
+       cfs_rq->avg.runnable_load_avg += se->avg.runnable_load_avg;
+       cfs_rq->avg.runnable_load_sum += se_runnable(se) * se->avg.runnable_load_sum;
+}
+
+static inline void
+dequeue_runnable_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       cfs_rq->runnable_weight -= se->runnable_weight;
+
+       sub_positive(&cfs_rq->avg.runnable_load_avg, se->avg.runnable_load_avg);
+       sub_positive(&cfs_rq->avg.runnable_load_sum,
+                    se_runnable(se) * se->avg.runnable_load_sum);
+}
+
+static inline void
+enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       cfs_rq->avg.load_avg += se->avg.load_avg;
+       cfs_rq->avg.load_sum += se_weight(se) * se->avg.load_sum;
+}
+
+static inline void
+dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+       sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg);
+       sub_positive(&cfs_rq->avg.load_sum, se_weight(se) * se->avg.load_sum);
+}
+#else
+static inline void
+enqueue_runnable_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
+static inline void
+dequeue_runnable_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
+static inline void
+enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
+static inline void
+dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
+#endif
+
+static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
+                           unsigned long weight, unsigned long runnable)
+{
+       if (se->on_rq) {
+               /* commit outstanding execution time */
+               if (cfs_rq->curr == se)
+                       update_curr(cfs_rq);
+               account_entity_dequeue(cfs_rq, se);
+               dequeue_runnable_load_avg(cfs_rq, se);
+       }
+       dequeue_load_avg(cfs_rq, se);
+
+       se->runnable_weight = runnable;
+       update_load_set(&se->load, weight);
+
+#ifdef CONFIG_SMP
+       do {
+               u32 divider = LOAD_AVG_MAX - 1024 + se->avg.period_contrib;
+
+               se->avg.load_avg = div_u64(se_weight(se) * se->avg.load_sum, divider);
+               se->avg.runnable_load_avg =
+                       div_u64(se_runnable(se) * se->avg.runnable_load_sum, divider);
+       } while (0);
+#endif
+
+       enqueue_load_avg(cfs_rq, se);
+       if (se->on_rq) {
+               account_entity_enqueue(cfs_rq, se);
+               enqueue_runnable_load_avg(cfs_rq, se);
+       }
+}
+
+void reweight_task(struct task_struct *p, int prio)
+{
+       struct sched_entity *se = &p->se;
+       struct cfs_rq *cfs_rq = cfs_rq_of(se);
+       struct load_weight *load = &se->load;
+       unsigned long weight = scale_load(sched_prio_to_weight[prio]);
+
+       reweight_entity(cfs_rq, se, weight, weight);
+       load->inv_weight = sched_prio_to_wmult[prio];
+}
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 # ifdef CONFIG_SMP
-static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
+/*
+ * All this does is approximate the hierarchical proportion which includes that
+ * global sum we all love to hate.
+ *
+ * That is, the weight of a group entity, is the proportional share of the
+ * group weight based on the group runqueue weights. That is:
+ *
+ *                     tg->weight * grq->load.weight
+ *   ge->load.weight = -----------------------------               (1)
+ *                       \Sum grq->load.weight
+ *
+ * Now, because computing that sum is prohibitively expensive to compute (been
+ * there, done that) we approximate it with this average stuff. The average
+ * moves slower and therefore the approximation is cheaper and more stable.
+ *
+ * So instead of the above, we substitute:
+ *
+ *   grq->load.weight -> grq->avg.load_avg                         (2)
+ *
+ * which yields the following:
+ *
+ *                     tg->weight * grq->avg.load_avg
+ *   ge->load.weight = ------------------------------              (3)
+ *                             tg->load_avg
+ *
+ * Where: tg->load_avg ~= \Sum grq->avg.load_avg
+ *
+ * That is shares_avg, and it is right (given the approximation (2)).
+ *
+ * The problem with it is that because the average is slow -- it was designed
+ * to be exactly that of course -- this leads to transients in boundary
+ * conditions. In specific, the case where the group was idle and we start the
+ * one task. It takes time for our CPU's grq->avg.load_avg to build up,
+ * yielding bad latency etc..
+ *
+ * Now, in that special case (1) reduces to:
+ *
+ *                     tg->weight * grq->load.weight
+ *   ge->load.weight = ----------------------------- = tg->weight   (4)
+ *                         grp->load.weight
+ *
+ * That is, the sum collapses because all other CPUs are idle; the UP scenario.
+ *
+ * So what we do is modify our approximation (3) to approach (4) in the (near)
+ * UP case, like:
+ *
+ *   ge->load.weight =
+ *
+ *              tg->weight * grq->load.weight
+ *     ---------------------------------------------------         (5)
+ *     tg->load_avg - grq->avg.load_avg + grq->load.weight
+ *
+ * But because grq->load.weight can drop to 0, resulting in a divide by zero,
+ * we need to use grq->avg.load_avg as its lower bound, which then gives:
+ *
+ *
+ *                     tg->weight * grq->load.weight
+ *   ge->load.weight = -----------------------------              (6)
+ *                             tg_load_avg'
+ *
+ * Where:
+ *
+ *   tg_load_avg' = tg->load_avg - grq->avg.load_avg +
+ *                  max(grq->load.weight, grq->avg.load_avg)
+ *
+ * And that is shares_weight and is icky. In the (near) UP case it approaches
+ * (4) while in the normal case it approaches (3). It consistently
+ * overestimates the ge->load.weight and therefore:
+ *
+ *   \Sum ge->load.weight >= tg->weight
+ *
+ * hence icky!
+ */
+static long calc_group_shares(struct cfs_rq *cfs_rq)
 {
-       long tg_weight, load, shares;
+       long tg_weight, tg_shares, load, shares;
+       struct task_group *tg = cfs_rq->tg;
 
-       /*
-        * This really should be: cfs_rq->avg.load_avg, but instead we use
-        * cfs_rq->load.weight, which is its upper bound. This helps ramp up
-        * the shares for small weight interactive tasks.
-        */
-       load = scale_load_down(cfs_rq->load.weight);
+       tg_shares = READ_ONCE(tg->shares);
+
+       load = max(scale_load_down(cfs_rq->load.weight), cfs_rq->avg.load_avg);
 
        tg_weight = atomic_long_read(&tg->load_avg);
 
@@ -2712,7 +2912,7 @@ static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
        tg_weight -= cfs_rq->tg_load_avg_contrib;
        tg_weight += load;
 
-       shares = (tg->shares * load);
+       shares = (tg_shares * load);
        if (tg_weight)
                shares /= tg_weight;
 
@@ -2728,63 +2928,86 @@ static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
         * case no task is runnable on a CPU MIN_SHARES=2 should be returned
         * instead of 0.
         */
-       if (shares < MIN_SHARES)
-               shares = MIN_SHARES;
-       if (shares > tg->shares)
-               shares = tg->shares;
-
-       return shares;
-}
-# else /* CONFIG_SMP */
-static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
-{
-       return tg->shares;
+       return clamp_t(long, shares, MIN_SHARES, tg_shares);
 }
-# endif /* CONFIG_SMP */
 
-static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
-                           unsigned long weight)
+/*
+ * This calculates the effective runnable weight for a group entity based on
+ * the group entity weight calculated above.
+ *
+ * Because of the above approximation (2), our group entity weight is
+ * an load_avg based ratio (3). This means that it includes blocked load and
+ * does not represent the runnable weight.
+ *
+ * Approximate the group entity's runnable weight per ratio from the group
+ * runqueue:
+ *
+ *                                          grq->avg.runnable_load_avg
+ *   ge->runnable_weight = ge->load.weight * -------------------------- (7)
+ *                                              grq->avg.load_avg
+ *
+ * However, analogous to above, since the avg numbers are slow, this leads to
+ * transients in the from-idle case. Instead we use:
+ *
+ *   ge->runnable_weight = ge->load.weight *
+ *
+ *             max(grq->avg.runnable_load_avg, grq->runnable_weight)
+ *             -----------------------------------------------------   (8)
+ *                   max(grq->avg.load_avg, grq->load.weight)
+ *
+ * Where these max() serve both to use the 'instant' values to fix the slow
+ * from-idle and avoid the /0 on to-idle, similar to (6).
+ */
+static long calc_group_runnable(struct cfs_rq *cfs_rq, long shares)
 {
-       if (se->on_rq) {
-               /* commit outstanding execution time */
-               if (cfs_rq->curr == se)
-                       update_curr(cfs_rq);
-               account_entity_dequeue(cfs_rq, se);
-       }
+       long runnable, load_avg;
 
-       update_load_set(&se->load, weight);
+       load_avg = max(cfs_rq->avg.load_avg,
+                      scale_load_down(cfs_rq->load.weight));
 
-       if (se->on_rq)
-               account_entity_enqueue(cfs_rq, se);
+       runnable = max(cfs_rq->avg.runnable_load_avg,
+                      scale_load_down(cfs_rq->runnable_weight));
+
+       runnable *= shares;
+       if (load_avg)
+               runnable /= load_avg;
+
+       return clamp_t(long, runnable, MIN_SHARES, shares);
 }
+# endif /* CONFIG_SMP */
 
 static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
 
-static void update_cfs_shares(struct sched_entity *se)
+/*
+ * Recomputes the group entity based on the current state of its group
+ * runqueue.
+ */
+static void update_cfs_group(struct sched_entity *se)
 {
-       struct cfs_rq *cfs_rq = group_cfs_rq(se);
-       struct task_group *tg;
-       long shares;
+       struct cfs_rq *gcfs_rq = group_cfs_rq(se);
+       long shares, runnable;
 
-       if (!cfs_rq)
+       if (!gcfs_rq)
                return;
 
-       if (throttled_hierarchy(cfs_rq))
+       if (throttled_hierarchy(gcfs_rq))
                return;
 
-       tg = cfs_rq->tg;
-
 #ifndef CONFIG_SMP
-       if (likely(se->load.weight == tg->shares))
+       runnable = shares = READ_ONCE(gcfs_rq->tg->shares);
+
+       if (likely(se->load.weight == shares))
                return;
+#else
+       shares   = calc_group_shares(gcfs_rq);
+       runnable = calc_group_runnable(gcfs_rq, shares);
 #endif
-       shares = calc_cfs_shares(cfs_rq, tg);
 
-       reweight_entity(cfs_rq_of(se), se, shares);
+       reweight_entity(cfs_rq_of(se), se, shares, runnable);
 }
 
 #else /* CONFIG_FAIR_GROUP_SCHED */
-static inline void update_cfs_shares(struct sched_entity *se)
+static inline void update_cfs_group(struct sched_entity *se)
 {
 }
 #endif /* CONFIG_FAIR_GROUP_SCHED */
@@ -2893,7 +3116,7 @@ static u32 __accumulate_pelt_segments(u64 periods, u32 d1, u32 d3)
  */
 static __always_inline u32
 accumulate_sum(u64 delta, int cpu, struct sched_avg *sa,
-              unsigned long weight, int running, struct cfs_rq *cfs_rq)
+              unsigned long load, unsigned long runnable, int running)
 {
        unsigned long scale_freq, scale_cpu;
        u32 contrib = (u32)delta; /* p == 0 -> delta < 1024 */
@@ -2910,10 +3133,8 @@ accumulate_sum(u64 delta, int cpu, struct sched_avg *sa,
         */
        if (periods) {
                sa->load_sum = decay_load(sa->load_sum, periods);
-               if (cfs_rq) {
-                       cfs_rq->runnable_load_sum =
-                               decay_load(cfs_rq->runnable_load_sum, periods);
-               }
+               sa->runnable_load_sum =
+                       decay_load(sa->runnable_load_sum, periods);
                sa->util_sum = decay_load((u64)(sa->util_sum), periods);
 
                /*
@@ -2926,11 +3147,10 @@ accumulate_sum(u64 delta, int cpu, struct sched_avg *sa,
        sa->period_contrib = delta;
 
        contrib = cap_scale(contrib, scale_freq);
-       if (weight) {
-               sa->load_sum += weight * contrib;
-               if (cfs_rq)
-                       cfs_rq->runnable_load_sum += weight * contrib;
-       }
+       if (load)
+               sa->load_sum += load * contrib;
+       if (runnable)
+               sa->runnable_load_sum += runnable * contrib;
        if (running)
                sa->util_sum += contrib * scale_cpu;
 
@@ -2966,8 +3186,8 @@ accumulate_sum(u64 delta, int cpu, struct sched_avg *sa,
  *            = u_0 + u_1*y + u_2*y^2 + ... [re-labeling u_i --> u_{i+1}]
  */
 static __always_inline int
-___update_load_avg(u64 now, int cpu, struct sched_avg *sa,
-                 unsigned long weight, int running, struct cfs_rq *cfs_rq)
+___update_load_sum(u64 now, int cpu, struct sched_avg *sa,
+                 unsigned long load, unsigned long runnable, int running)
 {
        u64 delta;
 
@@ -3000,8 +3220,8 @@ ___update_load_avg(u64 now, int cpu, struct sched_avg *sa,
         * this happens during idle_balance() which calls
         * update_blocked_averages()
         */
-       if (!weight)
-               running = 0;
+       if (!load)
+               runnable = running = 0;
 
        /*
         * Now we know we crossed measurement unit boundaries. The *_avg
@@ -3010,63 +3230,96 @@ ___update_load_avg(u64 now, int cpu, struct sched_avg *sa,
         * Step 1: accumulate *_sum since last_update_time. If we haven't
         * crossed period boundaries, finish.
         */
-       if (!accumulate_sum(delta, cpu, sa, weight, running, cfs_rq))
+       if (!accumulate_sum(delta, cpu, sa, load, runnable, running))
                return 0;
 
+       return 1;
+}
+
+static __always_inline void
+___update_load_avg(struct sched_avg *sa, unsigned long load, unsigned long runnable)
+{
+       u32 divider = LOAD_AVG_MAX - 1024 + sa->period_contrib;
+
        /*
         * Step 2: update *_avg.
         */
-       sa->load_avg = div_u64(sa->load_sum, LOAD_AVG_MAX - 1024 + sa->period_contrib);
-       if (cfs_rq) {
-               cfs_rq->runnable_load_avg =
-                       div_u64(cfs_rq->runnable_load_sum, LOAD_AVG_MAX - 1024 + sa->period_contrib);
-       }
-       sa->util_avg = sa->util_sum / (LOAD_AVG_MAX - 1024 + sa->period_contrib);
-
-       return 1;
+       sa->load_avg = div_u64(load * sa->load_sum, divider);
+       sa->runnable_load_avg = div_u64(runnable * sa->runnable_load_sum, divider);
+       sa->util_avg = sa->util_sum / divider;
 }
 
+/*
+ * sched_entity:
+ *
+ *   task:
+ *     se_runnable() == se_weight()
+ *
+ *   group: [ see update_cfs_group() ]
+ *     se_weight()   = tg->weight * grq->load_avg / tg->load_avg
+ *     se_runnable() = se_weight(se) * grq->runnable_load_avg / grq->load_avg
+ *
+ *   load_sum := runnable_sum
+ *   load_avg = se_weight(se) * runnable_avg
+ *
+ *   runnable_load_sum := runnable_sum
+ *   runnable_load_avg = se_runnable(se) * runnable_avg
+ *
+ * XXX collapse load_sum and runnable_load_sum
+ *
+ * cfq_rs:
+ *
+ *   load_sum = \Sum se_weight(se) * se->avg.load_sum
+ *   load_avg = \Sum se->avg.load_avg
+ *
+ *   runnable_load_sum = \Sum se_runnable(se) * se->avg.runnable_load_sum
+ *   runnable_load_avg = \Sum se->avg.runable_load_avg
+ */
+
 static int
 __update_load_avg_blocked_se(u64 now, int cpu, struct sched_entity *se)
 {
-       return ___update_load_avg(now, cpu, &se->avg, 0, 0, NULL);
+       if (entity_is_task(se))
+               se->runnable_weight = se->load.weight;
+
+       if (___update_load_sum(now, cpu, &se->avg, 0, 0, 0)) {
+               ___update_load_avg(&se->avg, se_weight(se), se_runnable(se));
+               return 1;
+       }
+
+       return 0;
 }
 
 static int
 __update_load_avg_se(u64 now, int cpu, struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       return ___update_load_avg(now, cpu, &se->avg,
-                                 se->on_rq * scale_load_down(se->load.weight),
-                                 cfs_rq->curr == se, NULL);
+       if (entity_is_task(se))
+               se->runnable_weight = se->load.weight;
+
+       if (___update_load_sum(now, cpu, &se->avg, !!se->on_rq, !!se->on_rq,
+                               cfs_rq->curr == se)) {
+
+               ___update_load_avg(&se->avg, se_weight(se), se_runnable(se));
+               return 1;
+       }
+
+       return 0;
 }
 
 static int
 __update_load_avg_cfs_rq(u64 now, int cpu, struct cfs_rq *cfs_rq)
 {
-       return ___update_load_avg(now, cpu, &cfs_rq->avg,
-                       scale_load_down(cfs_rq->load.weight),
-                       cfs_rq->curr != NULL, cfs_rq);
-}
+       if (___update_load_sum(now, cpu, &cfs_rq->avg,
+                               scale_load_down(cfs_rq->load.weight),
+                               scale_load_down(cfs_rq->runnable_weight),
+                               cfs_rq->curr != NULL)) {
 
-/*
- * Signed add and clamp on underflow.
- *
- * Explicitly do a load-store to ensure the intermediate value never hits
- * memory. This allows lockless observations without ever seeing the negative
- * values.
- */
-#define add_positive(_ptr, _val) do {                           \
-       typeof(_ptr) ptr = (_ptr);                              \
-       typeof(_val) val = (_val);                              \
-       typeof(*ptr) res, var = READ_ONCE(*ptr);                \
-                                                               \
-       res = var + val;                                        \
-                                                               \
-       if (val < 0 && res > var)                               \
-               res = 0;                                        \
-                                                               \
-       WRITE_ONCE(*ptr, res);                                  \
-} while (0)
+               ___update_load_avg(&cfs_rq->avg, 1, 1);
+               return 1;
+       }
+
+       return 0;
+}
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 /**
@@ -3149,11 +3402,77 @@ void set_task_rq_fair(struct sched_entity *se,
        se->avg.last_update_time = n_last_update_time;
 }
 
-/* Take into account change of utilization of a child task group */
+
+/*
+ * When on migration a sched_entity joins/leaves the PELT hierarchy, we need to
+ * propagate its contribution. The key to this propagation is the invariant
+ * that for each group:
+ *
+ *   ge->avg == grq->avg                                               (1)
+ *
+ * _IFF_ we look at the pure running and runnable sums. Because they
+ * represent the very same entity, just at different points in the hierarchy.
+ *
+ *
+ * Per the above update_tg_cfs_util() is trivial (and still 'wrong') and
+ * simply copies the running sum over.
+ *
+ * However, update_tg_cfs_runnable() is more complex. So we have:
+ *
+ *   ge->avg.load_avg = ge->load.weight * ge->avg.runnable_avg         (2)
+ *
+ * And since, like util, the runnable part should be directly transferable,
+ * the following would _appear_ to be the straight forward approach:
+ *
+ *   grq->avg.load_avg = grq->load.weight * grq->avg.running_avg       (3)
+ *
+ * And per (1) we have:
+ *
+ *   ge->avg.running_avg == grq->avg.running_avg
+ *
+ * Which gives:
+ *
+ *                      ge->load.weight * grq->avg.load_avg
+ *   ge->avg.load_avg = -----------------------------------            (4)
+ *                               grq->load.weight
+ *
+ * Except that is wrong!
+ *
+ * Because while for entities historical weight is not important and we
+ * really only care about our future and therefore can consider a pure
+ * runnable sum, runqueues can NOT do this.
+ *
+ * We specifically want runqueues to have a load_avg that includes
+ * historical weights. Those represent the blocked load, the load we expect
+ * to (shortly) return to us. This only works by keeping the weights as
+ * integral part of the sum. We therefore cannot decompose as per (3).
+ *
+ * OK, so what then?
+ *
+ *
+ * Another way to look at things is:
+ *
+ *   grq->avg.load_avg = \Sum se->avg.load_avg
+ *
+ * Therefore, per (2):
+ *
+ *   grq->avg.load_avg = \Sum se->load.weight * se->avg.runnable_avg
+ *
+ * And the very thing we're propagating is a change in that sum (someone
+ * joined/left). So we can easily know the runnable change, which would be, per
+ * (2) the already tracked se->load_avg divided by the corresponding
+ * se->weight.
+ *
+ * Basically (4) but in differential form:
+ *
+ *   d(runnable_avg) += se->avg.load_avg / se->load.weight
+ *                                                                (5)
+ *   ge->avg.load_avg += ge->load.weight * d(runnable_avg)
+ */
+
 static inline void
-update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se)
+update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
-       struct cfs_rq *gcfs_rq = group_cfs_rq(se);
        long delta = gcfs_rq->avg.util_avg - se->avg.util_avg;
 
        /* Nothing to update */
@@ -3169,102 +3488,65 @@ update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se)
        cfs_rq->avg.util_sum = cfs_rq->avg.util_avg * LOAD_AVG_MAX;
 }
 
-/* Take into account change of load of a child task group */
 static inline void
-update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se)
+update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
-       struct cfs_rq *gcfs_rq = group_cfs_rq(se);
-       long delta, load = gcfs_rq->avg.load_avg;
+       long runnable_sum = gcfs_rq->prop_runnable_sum;
+       long runnable_load_avg, load_avg;
+       s64 runnable_load_sum, load_sum;
 
-       /*
-        * If the load of group cfs_rq is null, the load of the
-        * sched_entity will also be null so we can skip the formula
-        */
-       if (load) {
-               long tg_load;
+       if (!runnable_sum)
+               return;
 
-               /* Get tg's load and ensure tg_load > 0 */
-               tg_load = atomic_long_read(&gcfs_rq->tg->load_avg) + 1;
+       gcfs_rq->prop_runnable_sum = 0;
 
-               /* Ensure tg_load >= load and updated with current load*/
-               tg_load -= gcfs_rq->tg_load_avg_contrib;
-               tg_load += load;
+       load_sum = (s64)se_weight(se) * runnable_sum;
+       load_avg = div_s64(load_sum, LOAD_AVG_MAX);
 
-               /*
-                * We need to compute a correction term in the case that the
-                * task group is consuming more CPU than a task of equal
-                * weight. A task with a weight equals to tg->shares will have
-                * a load less or equal to scale_load_down(tg->shares).
-                * Similarly, the sched_entities that represent the task group
-                * at parent level, can't have a load higher than
-                * scale_load_down(tg->shares). And the Sum of sched_entities'
-                * load must be <= scale_load_down(tg->shares).
-                */
-               if (tg_load > scale_load_down(gcfs_rq->tg->shares)) {
-                       /* scale gcfs_rq's load into tg's shares*/
-                       load *= scale_load_down(gcfs_rq->tg->shares);
-                       load /= tg_load;
-               }
-       }
+       add_positive(&se->avg.load_sum, runnable_sum);
+       add_positive(&se->avg.load_avg, load_avg);
 
-       delta = load - se->avg.load_avg;
+       add_positive(&cfs_rq->avg.load_avg, load_avg);
+       add_positive(&cfs_rq->avg.load_sum, load_sum);
 
-       /* Nothing to update */
-       if (!delta)
-               return;
-
-       /* Set new sched_entity's load */
-       se->avg.load_avg = load;
-       se->avg.load_sum = se->avg.load_avg * LOAD_AVG_MAX;
+       runnable_load_sum = (s64)se_runnable(se) * runnable_sum;
+       runnable_load_avg = div_s64(runnable_load_sum, LOAD_AVG_MAX);
 
-       /* Update parent cfs_rq load */
-       add_positive(&cfs_rq->avg.load_avg, delta);
-       cfs_rq->avg.load_sum = cfs_rq->avg.load_avg * LOAD_AVG_MAX;
+       add_positive(&se->avg.runnable_load_sum, runnable_sum);
+       add_positive(&se->avg.runnable_load_avg, runnable_load_avg);
 
-       /*
-        * If the sched_entity is already enqueued, we also have to update the
-        * runnable load avg.
-        */
        if (se->on_rq) {
-               /* Update parent cfs_rq runnable_load_avg */
-               add_positive(&cfs_rq->runnable_load_avg, delta);
-               cfs_rq->runnable_load_sum = cfs_rq->runnable_load_avg * LOAD_AVG_MAX;
+               add_positive(&cfs_rq->avg.runnable_load_avg, runnable_load_avg);
+               add_positive(&cfs_rq->avg.runnable_load_sum, runnable_load_sum);
        }
 }
 
-static inline void set_tg_cfs_propagate(struct cfs_rq *cfs_rq)
-{
-       cfs_rq->propagate_avg = 1;
-}
-
-static inline int test_and_clear_tg_cfs_propagate(struct sched_entity *se)
+static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum)
 {
-       struct cfs_rq *cfs_rq = group_cfs_rq(se);
-
-       if (!cfs_rq->propagate_avg)
-               return 0;
-
-       cfs_rq->propagate_avg = 0;
-       return 1;
+       cfs_rq->propagate = 1;
+       cfs_rq->prop_runnable_sum += runnable_sum;
 }
 
 /* Update task and its cfs_rq load average */
 static inline int propagate_entity_load_avg(struct sched_entity *se)
 {
-       struct cfs_rq *cfs_rq;
+       struct cfs_rq *cfs_rq, *gcfs_rq;
 
        if (entity_is_task(se))
                return 0;
 
-       if (!test_and_clear_tg_cfs_propagate(se))
+       gcfs_rq = group_cfs_rq(se);
+       if (!gcfs_rq->propagate)
                return 0;
 
+       gcfs_rq->propagate = 0;
+
        cfs_rq = cfs_rq_of(se);
 
-       set_tg_cfs_propagate(cfs_rq);
+       add_tg_cfs_propagate(cfs_rq, gcfs_rq->prop_runnable_sum);
 
-       update_tg_cfs_util(cfs_rq, se);
-       update_tg_cfs_load(cfs_rq, se);
+       update_tg_cfs_util(cfs_rq, se, gcfs_rq);
+       update_tg_cfs_runnable(cfs_rq, se, gcfs_rq);
 
        return 1;
 }
@@ -3288,7 +3570,7 @@ static inline bool skip_blocked_update(struct sched_entity *se)
         * If there is a pending propagation, we have to update the load and
         * the utilization of the sched_entity:
         */
-       if (gcfs_rq->propagate_avg)
+       if (gcfs_rq->propagate)
                return false;
 
        /*
@@ -3308,27 +3590,10 @@ static inline int propagate_entity_load_avg(struct sched_entity *se)
        return 0;
 }
 
-static inline void set_tg_cfs_propagate(struct cfs_rq *cfs_rq) {}
+static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum) {}
 
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
-/*
- * Unsigned subtract and clamp on underflow.
- *
- * Explicitly do a load-store to ensure the intermediate value never hits
- * memory. This allows lockless observations without ever seeing the negative
- * values.
- */
-#define sub_positive(_ptr, _val) do {                          \
-       typeof(_ptr) ptr = (_ptr);                              \
-       typeof(*ptr) val = (_val);                              \
-       typeof(*ptr) res, var = READ_ONCE(*ptr);                \
-       res = var - val;                                        \
-       if (res > var)                                          \
-               res = 0;                                        \
-       WRITE_ONCE(*ptr, res);                                  \
-} while (0)
-
 /**
  * update_cfs_rq_load_avg - update the cfs_rq's load/util averages
  * @now: current time, as per cfs_rq_clock_task()
@@ -3348,65 +3613,45 @@ static inline void set_tg_cfs_propagate(struct cfs_rq *cfs_rq) {}
 static inline int
 update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
 {
+       unsigned long removed_load = 0, removed_util = 0, removed_runnable_sum = 0;
        struct sched_avg *sa = &cfs_rq->avg;
-       int decayed, removed_load = 0, removed_util = 0;
+       int decayed = 0;
 
-       if (atomic_long_read(&cfs_rq->removed_load_avg)) {
-               s64 r = atomic_long_xchg(&cfs_rq->removed_load_avg, 0);
+       if (cfs_rq->removed.nr) {
+               unsigned long r;
+               u32 divider = LOAD_AVG_MAX - 1024 + sa->period_contrib;
+
+               raw_spin_lock(&cfs_rq->removed.lock);
+               swap(cfs_rq->removed.util_avg, removed_util);
+               swap(cfs_rq->removed.load_avg, removed_load);
+               swap(cfs_rq->removed.runnable_sum, removed_runnable_sum);
+               cfs_rq->removed.nr = 0;
+               raw_spin_unlock(&cfs_rq->removed.lock);
+
+               r = removed_load;
                sub_positive(&sa->load_avg, r);
-               sub_positive(&sa->load_sum, r * LOAD_AVG_MAX);
-               removed_load = 1;
-               set_tg_cfs_propagate(cfs_rq);
-       }
+               sub_positive(&sa->load_sum, r * divider);
 
-       if (atomic_long_read(&cfs_rq->removed_util_avg)) {
-               long r = atomic_long_xchg(&cfs_rq->removed_util_avg, 0);
+               r = removed_util;
                sub_positive(&sa->util_avg, r);
-               sub_positive(&sa->util_sum, r * LOAD_AVG_MAX);
-               removed_util = 1;
-               set_tg_cfs_propagate(cfs_rq);
+               sub_positive(&sa->util_sum, r * divider);
+
+               add_tg_cfs_propagate(cfs_rq, -(long)removed_runnable_sum);
+
+               decayed = 1;
        }
 
-       decayed = __update_load_avg_cfs_rq(now, cpu_of(rq_of(cfs_rq)), cfs_rq);
+       decayed |= __update_load_avg_cfs_rq(now, cpu_of(rq_of(cfs_rq)), cfs_rq);
 
 #ifndef CONFIG_64BIT
        smp_wmb();
        cfs_rq->load_last_update_time_copy = sa->last_update_time;
 #endif
 
-       if (decayed || removed_util)
+       if (decayed)
                cfs_rq_util_change(cfs_rq);
 
-       return decayed || removed_load;
-}
-
-/*
- * Optional action to be done while updating the load average
- */
-#define UPDATE_TG      0x1
-#define SKIP_AGE_LOAD  0x2
-
-/* Update task and its cfs_rq load average */
-static inline void update_load_avg(struct sched_entity *se, int flags)
-{
-       struct cfs_rq *cfs_rq = cfs_rq_of(se);
-       u64 now = cfs_rq_clock_task(cfs_rq);
-       struct rq *rq = rq_of(cfs_rq);
-       int cpu = cpu_of(rq);
-       int decayed;
-
-       /*
-        * Track task load average for carrying it to new CPU after migrated, and
-        * track group sched_entity load average for task_h_load calc in migration
-        */
-       if (se->avg.last_update_time && !(flags & SKIP_AGE_LOAD))
-               __update_load_avg_se(now, cpu, cfs_rq, se);
-
-       decayed  = update_cfs_rq_load_avg(now, cfs_rq);
-       decayed |= propagate_entity_load_avg(se);
-
-       if (decayed && (flags & UPDATE_TG))
-               update_tg_load_avg(cfs_rq, 0);
+       return decayed;
 }
 
 /**
@@ -3419,12 +3664,39 @@ static inline void update_load_avg(struct sched_entity *se, int flags)
  */
 static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
+       u32 divider = LOAD_AVG_MAX - 1024 + cfs_rq->avg.period_contrib;
+
+       /*
+        * When we attach the @se to the @cfs_rq, we must align the decay
+        * window because without that, really weird and wonderful things can
+        * happen.
+        *
+        * XXX illustrate
+        */
        se->avg.last_update_time = cfs_rq->avg.last_update_time;
-       cfs_rq->avg.load_avg += se->avg.load_avg;
-       cfs_rq->avg.load_sum += se->avg.load_sum;
+       se->avg.period_contrib = cfs_rq->avg.period_contrib;
+
+       /*
+        * Hell(o) Nasty stuff.. we need to recompute _sum based on the new
+        * period_contrib. This isn't strictly correct, but since we're
+        * entirely outside of the PELT hierarchy, nobody cares if we truncate
+        * _sum a little.
+        */
+       se->avg.util_sum = se->avg.util_avg * divider;
+
+       se->avg.load_sum = divider;
+       if (se_weight(se)) {
+               se->avg.load_sum =
+                       div_u64(se->avg.load_avg * se->avg.load_sum, se_weight(se));
+       }
+
+       se->avg.runnable_load_sum = se->avg.load_sum;
+
+       enqueue_load_avg(cfs_rq, se);
        cfs_rq->avg.util_avg += se->avg.util_avg;
        cfs_rq->avg.util_sum += se->avg.util_sum;
-       set_tg_cfs_propagate(cfs_rq);
+
+       add_tg_cfs_propagate(cfs_rq, se->avg.load_sum);
 
        cfs_rq_util_change(cfs_rq);
 }
@@ -3439,39 +3711,47 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
  */
 static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-
-       sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg);
-       sub_positive(&cfs_rq->avg.load_sum, se->avg.load_sum);
+       dequeue_load_avg(cfs_rq, se);
        sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg);
        sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum);
-       set_tg_cfs_propagate(cfs_rq);
+
+       add_tg_cfs_propagate(cfs_rq, -se->avg.load_sum);
 
        cfs_rq_util_change(cfs_rq);
 }
 
-/* Add the load generated by se into cfs_rq's load average */
-static inline void
-enqueue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
+/*
+ * Optional action to be done while updating the load average
+ */
+#define UPDATE_TG      0x1
+#define SKIP_AGE_LOAD  0x2
+#define DO_ATTACH      0x4
+
+/* Update task and its cfs_rq load average */
+static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 {
-       struct sched_avg *sa = &se->avg;
+       u64 now = cfs_rq_clock_task(cfs_rq);
+       struct rq *rq = rq_of(cfs_rq);
+       int cpu = cpu_of(rq);
+       int decayed;
+
+       /*
+        * Track task load average for carrying it to new CPU after migrated, and
+        * track group sched_entity load average for task_h_load calc in migration
+        */
+       if (se->avg.last_update_time && !(flags & SKIP_AGE_LOAD))
+               __update_load_avg_se(now, cpu, cfs_rq, se);
 
-       cfs_rq->runnable_load_avg += sa->load_avg;
-       cfs_rq->runnable_load_sum += sa->load_sum;
+       decayed  = update_cfs_rq_load_avg(now, cfs_rq);
+       decayed |= propagate_entity_load_avg(se);
+
+       if (!se->avg.last_update_time && (flags & DO_ATTACH)) {
 
-       if (!sa->last_update_time) {
                attach_entity_load_avg(cfs_rq, se);
                update_tg_load_avg(cfs_rq, 0);
-       }
-}
 
-/* Remove the runnable load generated by se from cfs_rq's runnable load average */
-static inline void
-dequeue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-       cfs_rq->runnable_load_avg =
-               max_t(long, cfs_rq->runnable_load_avg - se->avg.load_avg, 0);
-       cfs_rq->runnable_load_sum =
-               max_t(s64,  cfs_rq->runnable_load_sum - se->avg.load_sum, 0);
+       } else if (decayed && (flags & UPDATE_TG))
+               update_tg_load_avg(cfs_rq, 0);
 }
 
 #ifndef CONFIG_64BIT
@@ -3515,6 +3795,7 @@ void sync_entity_load_avg(struct sched_entity *se)
 void remove_entity_load_avg(struct sched_entity *se)
 {
        struct cfs_rq *cfs_rq = cfs_rq_of(se);
+       unsigned long flags;
 
        /*
         * tasks cannot exit without having gone through wake_up_new_task() ->
@@ -3527,13 +3808,18 @@ void remove_entity_load_avg(struct sched_entity *se)
         */
 
        sync_entity_load_avg(se);
-       atomic_long_add(se->avg.load_avg, &cfs_rq->removed_load_avg);
-       atomic_long_add(se->avg.util_avg, &cfs_rq->removed_util_avg);
+
+       raw_spin_lock_irqsave(&cfs_rq->removed.lock, flags);
+       ++cfs_rq->removed.nr;
+       cfs_rq->removed.util_avg        += se->avg.util_avg;
+       cfs_rq->removed.load_avg        += se->avg.load_avg;
+       cfs_rq->removed.runnable_sum    += se->avg.load_sum; /* == runnable_sum */
+       raw_spin_unlock_irqrestore(&cfs_rq->removed.lock, flags);
 }
 
 static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq)
 {
-       return cfs_rq->runnable_load_avg;
+       return cfs_rq->avg.runnable_load_avg;
 }
 
 static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq)
@@ -3553,16 +3839,13 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
 
 #define UPDATE_TG      0x0
 #define SKIP_AGE_LOAD  0x0
+#define DO_ATTACH      0x0
 
-static inline void update_load_avg(struct sched_entity *se, int not_used1)
+static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se, int not_used1)
 {
-       cfs_rq_util_change(cfs_rq_of(se));
+       cfs_rq_util_change(cfs_rq);
 }
 
-static inline void
-enqueue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) {}
-static inline void
-dequeue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) {}
 static inline void remove_entity_load_avg(struct sched_entity *se) {}
 
 static inline void
@@ -3707,9 +3990,9 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
         *     its group cfs_rq
         *   - Add its new weight to cfs_rq->load.weight
         */
-       update_load_avg(se, UPDATE_TG);
-       enqueue_entity_load_avg(cfs_rq, se);
-       update_cfs_shares(se);
+       update_load_avg(cfs_rq, se, UPDATE_TG | DO_ATTACH);
+       update_cfs_group(se);
+       enqueue_runnable_load_avg(cfs_rq, se);
        account_entity_enqueue(cfs_rq, se);
 
        if (flags & ENQUEUE_WAKEUP)
@@ -3791,8 +4074,8 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
         *   - For group entity, update its weight to reflect the new share
         *     of its group cfs_rq.
         */
-       update_load_avg(se, UPDATE_TG);
-       dequeue_entity_load_avg(cfs_rq, se);
+       update_load_avg(cfs_rq, se, UPDATE_TG);
+       dequeue_runnable_load_avg(cfs_rq, se);
 
        update_stats_dequeue(cfs_rq, se, flags);
 
@@ -3815,7 +4098,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
        /* return excess runtime on last dequeue */
        return_cfs_rq_runtime(cfs_rq);
 
-       update_cfs_shares(se);
+       update_cfs_group(se);
 
        /*
         * Now advance min_vruntime if @se was the entity holding it back,
@@ -3879,7 +4162,7 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
                 */
                update_stats_wait_end(cfs_rq, se);
                __dequeue_entity(cfs_rq, se);
-               update_load_avg(se, UPDATE_TG);
+               update_load_avg(cfs_rq, se, UPDATE_TG);
        }
 
        update_stats_curr_start(cfs_rq, se);
@@ -3981,7 +4264,7 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
                /* Put 'current' back into the tree. */
                __enqueue_entity(cfs_rq, prev);
                /* in !on_rq case, update occurred at dequeue */
-               update_load_avg(prev, 0);
+               update_load_avg(cfs_rq, prev, 0);
        }
        cfs_rq->curr = NULL;
 }
@@ -3997,8 +4280,8 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
        /*
         * Ensure that runnable average is periodically updated.
         */
-       update_load_avg(curr, UPDATE_TG);
-       update_cfs_shares(curr);
+       update_load_avg(cfs_rq, curr, UPDATE_TG);
+       update_cfs_group(curr);
 
 #ifdef CONFIG_SCHED_HRTICK
        /*
@@ -4915,8 +5198,8 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                if (cfs_rq_throttled(cfs_rq))
                        break;
 
-               update_load_avg(se, UPDATE_TG);
-               update_cfs_shares(se);
+               update_load_avg(cfs_rq, se, UPDATE_TG);
+               update_cfs_group(se);
        }
 
        if (!se)
@@ -4974,8 +5257,8 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                if (cfs_rq_throttled(cfs_rq))
                        break;
 
-               update_load_avg(se, UPDATE_TG);
-               update_cfs_shares(se);
+               update_load_avg(cfs_rq, se, UPDATE_TG);
+               update_cfs_group(se);
        }
 
        if (!se)
@@ -5449,6 +5732,8 @@ static unsigned long capacity_spare_wake(int cpu, struct task_struct *p)
 /*
  * find_idlest_group finds and returns the least busy CPU group within the
  * domain.
+ *
+ * Assumes p is allowed on at least one CPU in sd.
  */
 static struct sched_group *
 find_idlest_group(struct sched_domain *sd, struct task_struct *p,
@@ -5456,8 +5741,9 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p,
 {
        struct sched_group *idlest = NULL, *group = sd->groups;
        struct sched_group *most_spare_sg = NULL;
-       unsigned long min_runnable_load = ULONG_MAX, this_runnable_load = 0;
-       unsigned long min_avg_load = ULONG_MAX, this_avg_load = 0;
+       unsigned long min_runnable_load = ULONG_MAX;
+       unsigned long this_runnable_load = ULONG_MAX;
+       unsigned long min_avg_load = ULONG_MAX, this_avg_load = ULONG_MAX;
        unsigned long most_spare = 0, this_spare = 0;
        int load_idx = sd->forkexec_idx;
        int imbalance_scale = 100 + (sd->imbalance_pct-100)/2;
@@ -5578,10 +5864,10 @@ skip_spare:
 }
 
 /*
- * find_idlest_cpu - find the idlest cpu among the cpus in group.
+ * find_idlest_group_cpu - find the idlest cpu among the cpus in group.
  */
 static int
-find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
+find_idlest_group_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
 {
        unsigned long load, min_load = ULONG_MAX;
        unsigned int min_exit_latency = UINT_MAX;
@@ -5630,6 +5916,53 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
        return shallowest_idle_cpu != -1 ? shallowest_idle_cpu : least_loaded_cpu;
 }
 
+static inline int find_idlest_cpu(struct sched_domain *sd, struct task_struct *p,
+                                 int cpu, int prev_cpu, int sd_flag)
+{
+       int new_cpu = cpu;
+
+       if (!cpumask_intersects(sched_domain_span(sd), &p->cpus_allowed))
+               return prev_cpu;
+
+       while (sd) {
+               struct sched_group *group;
+               struct sched_domain *tmp;
+               int weight;
+
+               if (!(sd->flags & sd_flag)) {
+                       sd = sd->child;
+                       continue;
+               }
+
+               group = find_idlest_group(sd, p, cpu, sd_flag);
+               if (!group) {
+                       sd = sd->child;
+                       continue;
+               }
+
+               new_cpu = find_idlest_group_cpu(group, p, cpu);
+               if (new_cpu == cpu) {
+                       /* Now try balancing at a lower domain level of cpu */
+                       sd = sd->child;
+                       continue;
+               }
+
+               /* Now try balancing at a lower domain level of new_cpu */
+               cpu = new_cpu;
+               weight = sd->span_weight;
+               sd = NULL;
+               for_each_domain(cpu, tmp) {
+                       if (weight <= tmp->span_weight)
+                               break;
+                       if (tmp->flags & sd_flag)
+                               sd = tmp;
+               }
+               /* while loop will break here if sd == NULL */
+       }
+
+       return new_cpu;
+}
+
 #ifdef CONFIG_SCHED_SMT
 
 static inline void set_idle_cores(int cpu, int val)
@@ -5982,50 +6315,30 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
                        new_cpu = cpu;
        }
 
+       if (sd && !(sd_flag & SD_BALANCE_FORK)) {
+               /*
+                * We're going to need the task's util for capacity_spare_wake
+                * in find_idlest_group. Sync it up to prev_cpu's
+                * last_update_time.
+                */
+               sync_entity_load_avg(&p->se);
+       }
+
        if (!sd) {
- pick_cpu:
+pick_cpu:
                if (sd_flag & SD_BALANCE_WAKE) /* XXX always ? */
                        new_cpu = select_idle_sibling(p, prev_cpu, new_cpu);
 
-       } else while (sd) {
-               struct sched_group *group;
-               int weight;
-
-               if (!(sd->flags & sd_flag)) {
-                       sd = sd->child;
-                       continue;
-               }
-
-               group = find_idlest_group(sd, p, cpu, sd_flag);
-               if (!group) {
-                       sd = sd->child;
-                       continue;
-               }
-
-               new_cpu = find_idlest_cpu(group, p, cpu);
-               if (new_cpu == -1 || new_cpu == cpu) {
-                       /* Now try balancing at a lower domain level of cpu */
-                       sd = sd->child;
-                       continue;
-               }
-
-               /* Now try balancing at a lower domain level of new_cpu */
-               cpu = new_cpu;
-               weight = sd->span_weight;
-               sd = NULL;
-               for_each_domain(cpu, tmp) {
-                       if (weight <= tmp->span_weight)
-                               break;
-                       if (tmp->flags & sd_flag)
-                               sd = tmp;
-               }
-               /* while loop will break here if sd == NULL */
+       } else {
+               new_cpu = find_idlest_cpu(sd, p, cpu, prev_cpu, sd_flag);
        }
        rcu_read_unlock();
 
        return new_cpu;
 }
 
+static void detach_entity_cfs_rq(struct sched_entity *se);
+
 /*
  * Called immediately before a task is migrated to a new cpu; task_cpu(p) and
  * cfs_rq_of(p) references at time of call are still valid and identify the
@@ -6059,14 +6372,25 @@ static void migrate_task_rq_fair(struct task_struct *p)
                se->vruntime -= min_vruntime;
        }
 
-       /*
-        * We are supposed to update the task to "current" time, then its up to date
-        * and ready to go to new CPU/cfs_rq. But we have difficulty in getting
-        * what current time is, so simply throw away the out-of-date time. This
-        * will result in the wakee task is less decayed, but giving the wakee more
-        * load sounds not bad.
-        */
-       remove_entity_load_avg(&p->se);
+       if (p->on_rq == TASK_ON_RQ_MIGRATING) {
+               /*
+                * In case of TASK_ON_RQ_MIGRATING we in fact hold the 'old'
+                * rq->lock and can modify state directly.
+                */
+               lockdep_assert_held(&task_rq(p)->lock);
+               detach_entity_cfs_rq(&p->se);
+
+       } else {
+               /*
+                * We are supposed to update the task to "current" time, then
+                * its up to date and ready to go to new CPU/cfs_rq. But we
+                * have difficulty in getting what current time is, so simply
+                * throw away the out-of-date time. This will result in the
+                * wakee task is less decayed, but giving the wakee more load
+                * sounds not bad.
+                */
+               remove_entity_load_avg(&p->se);
+       }
 
        /* Tell new CPU we are migrated */
        p->se.avg.last_update_time = 0;
@@ -6334,10 +6658,7 @@ again:
                set_next_entity(cfs_rq, se);
        }
 
-       if (hrtick_enabled(rq))
-               hrtick_start_fair(rq, p);
-
-       return p;
+       goto done;
 simple:
 #endif
 
@@ -6351,6 +6672,16 @@ simple:
 
        p = task_of(se);
 
+done: __maybe_unused
+#ifdef CONFIG_SMP
+       /*
+        * Move the next running task to the front of
+        * the list, so our cfs_tasks list becomes MRU
+        * one.
+        */
+       list_move(&p->se.group_node, &rq->cfs_tasks);
+#endif
+
        if (hrtick_enabled(rq))
                hrtick_start_fair(rq, p);
 
@@ -6786,11 +7117,12 @@ static void detach_task(struct task_struct *p, struct lb_env *env)
  */
 static struct task_struct *detach_one_task(struct lb_env *env)
 {
-       struct task_struct *p, *n;
+       struct task_struct *p;
 
        lockdep_assert_held(&env->src_rq->lock);
 
-       list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) {
+       list_for_each_entry_reverse(p,
+                       &env->src_rq->cfs_tasks, se.group_node) {
                if (!can_migrate_task(p, env))
                        continue;
 
@@ -6836,7 +7168,7 @@ static int detach_tasks(struct lb_env *env)
                if (env->idle != CPU_NOT_IDLE && env->src_rq->nr_running <= 1)
                        break;
 
-               p = list_first_entry(tasks, struct task_struct, se.group_node);
+               p = list_last_entry(tasks, struct task_struct, se.group_node);
 
                env->loop++;
                /* We've more or less seen every task there is, call it quits */
@@ -6886,7 +7218,7 @@ static int detach_tasks(struct lb_env *env)
 
                continue;
 next:
-               list_move_tail(&p->se.group_node, tasks);
+               list_move(&p->se.group_node, tasks);
        }
 
        /*
@@ -6962,7 +7294,7 @@ static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
        if (cfs_rq->avg.util_sum)
                return false;
 
-       if (cfs_rq->runnable_load_sum)
+       if (cfs_rq->avg.runnable_load_sum)
                return false;
 
        return true;
@@ -6994,7 +7326,7 @@ static void update_blocked_averages(int cpu)
                /* Propagate pending load changes to the parent, if any: */
                se = cfs_rq->tg->se[cpu];
                if (se && !skip_blocked_update(se))
-                       update_load_avg(se, 0);
+                       update_load_avg(cfs_rq_of(se), se, 0);
 
                /*
                 * There can be a lot of idle CPU cgroups.  Don't let fully
@@ -7875,8 +8207,11 @@ static struct sched_group *find_busiest_group(struct lb_env *env)
        if (busiest->group_type == group_imbalanced)
                goto force_balance;
 
-       /* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
-       if (env->idle == CPU_NEWLY_IDLE && group_has_capacity(env, local) &&
+       /*
+        * When dst_cpu is idle, prevent SMP nice and/or asymmetric group
+        * capacities from resulting in underutilization due to avg_load.
+        */
+       if (env->idle != CPU_NOT_IDLE && group_has_capacity(env, local) &&
            busiest->group_no_capacity)
                goto force_balance;
 
@@ -8693,7 +9028,7 @@ void nohz_balance_enter_idle(int cpu)
                return;
 
        /* Spare idle load balancing on CPUs that don't want to be disturbed: */
-       if (!is_housekeeping_cpu(cpu))
+       if (!housekeeping_cpu(cpu, HK_FLAG_SCHED))
                return;
 
        if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))
@@ -9158,7 +9493,7 @@ static void propagate_entity_cfs_rq(struct sched_entity *se)
                if (cfs_rq_throttled(cfs_rq))
                        break;
 
-               update_load_avg(se, UPDATE_TG);
+               update_load_avg(cfs_rq, se, UPDATE_TG);
        }
 }
 #else
@@ -9170,7 +9505,7 @@ static void detach_entity_cfs_rq(struct sched_entity *se)
        struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
        /* Catch up with the cfs_rq and remove our load when we leave */
-       update_load_avg(se, 0);
+       update_load_avg(cfs_rq, se, 0);
        detach_entity_load_avg(cfs_rq, se);
        update_tg_load_avg(cfs_rq, false);
        propagate_entity_cfs_rq(se);
@@ -9189,7 +9524,7 @@ static void attach_entity_cfs_rq(struct sched_entity *se)
 #endif
 
        /* Synchronize entity with its cfs_rq */
-       update_load_avg(se, sched_feat(ATTACH_AGE_LOAD) ? 0 : SKIP_AGE_LOAD);
+       update_load_avg(cfs_rq, se, sched_feat(ATTACH_AGE_LOAD) ? 0 : SKIP_AGE_LOAD);
        attach_entity_load_avg(cfs_rq, se);
        update_tg_load_avg(cfs_rq, false);
        propagate_entity_cfs_rq(se);
@@ -9271,11 +9606,7 @@ void init_cfs_rq(struct cfs_rq *cfs_rq)
        cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime;
 #endif
 #ifdef CONFIG_SMP
-#ifdef CONFIG_FAIR_GROUP_SCHED
-       cfs_rq->propagate_avg = 0;
-#endif
-       atomic_long_set(&cfs_rq->removed_load_avg, 0);
-       atomic_long_set(&cfs_rq->removed_util_avg, 0);
+       raw_spin_lock_init(&cfs_rq->removed.lock);
 #endif
 }
 
@@ -9473,8 +9804,8 @@ int sched_group_set_shares(struct task_group *tg, unsigned long shares)
                rq_lock_irqsave(rq, &rf);
                update_rq_clock(rq);
                for_each_sched_entity(se) {
-                       update_load_avg(se, UPDATE_TG);
-                       update_cfs_shares(se);
+                       update_load_avg(cfs_rq_of(se), se, UPDATE_TG);
+                       update_cfs_group(se);
                }
                rq_unlock_irqrestore(rq, &rf);
        }
index 257f4f0b4532b0428a8ff3c72513b0a54cb0029d..7dae9eb8c0428343699c94b0b6444a9a90bcb0e3 100644 (file)
@@ -209,6 +209,7 @@ exit_idle:
  */
 static void do_idle(void)
 {
+       int cpu = smp_processor_id();
        /*
         * If the arch has a polling bit, we maintain an invariant:
         *
@@ -219,14 +220,13 @@ static void do_idle(void)
         */
 
        __current_set_polling();
-       quiet_vmstat();
        tick_nohz_idle_enter();
 
        while (!need_resched()) {
                check_pgt_cache();
                rmb();
 
-               if (cpu_is_offline(smp_processor_id())) {
+               if (cpu_is_offline(cpu)) {
                        cpuhp_report_idle_dead();
                        arch_cpu_idle_dead();
                }
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
new file mode 100644 (file)
index 0000000..b71b436
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *  Housekeeping management. Manage the targets for routine code that can run on
+ *  any CPU: unbound workqueues, timers, kthreads and any offloadable work.
+ *
+ * Copyright (C) 2017 Red Hat, Inc., Frederic Weisbecker
+ *
+ */
+
+#include <linux/sched/isolation.h>
+#include <linux/tick.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/static_key.h>
+#include <linux/ctype.h>
+
+DEFINE_STATIC_KEY_FALSE(housekeeping_overriden);
+EXPORT_SYMBOL_GPL(housekeeping_overriden);
+static cpumask_var_t housekeeping_mask;
+static unsigned int housekeeping_flags;
+
+int housekeeping_any_cpu(enum hk_flags flags)
+{
+       if (static_branch_unlikely(&housekeeping_overriden))
+               if (housekeeping_flags & flags)
+                       return cpumask_any_and(housekeeping_mask, cpu_online_mask);
+       return smp_processor_id();
+}
+EXPORT_SYMBOL_GPL(housekeeping_any_cpu);
+
+const struct cpumask *housekeeping_cpumask(enum hk_flags flags)
+{
+       if (static_branch_unlikely(&housekeeping_overriden))
+               if (housekeeping_flags & flags)
+                       return housekeeping_mask;
+       return cpu_possible_mask;
+}
+EXPORT_SYMBOL_GPL(housekeeping_cpumask);
+
+void housekeeping_affine(struct task_struct *t, enum hk_flags flags)
+{
+       if (static_branch_unlikely(&housekeeping_overriden))
+               if (housekeeping_flags & flags)
+                       set_cpus_allowed_ptr(t, housekeeping_mask);
+}
+EXPORT_SYMBOL_GPL(housekeeping_affine);
+
+bool housekeeping_test_cpu(int cpu, enum hk_flags flags)
+{
+       if (static_branch_unlikely(&housekeeping_overriden))
+               if (housekeeping_flags & flags)
+                       return cpumask_test_cpu(cpu, housekeeping_mask);
+       return true;
+}
+EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
+
+void __init housekeeping_init(void)
+{
+       if (!housekeeping_flags)
+               return;
+
+       static_branch_enable(&housekeeping_overriden);
+
+       /* We need at least one CPU to handle housekeeping work */
+       WARN_ON_ONCE(cpumask_empty(housekeeping_mask));
+}
+
+static int __init housekeeping_setup(char *str, enum hk_flags flags)
+{
+       cpumask_var_t non_housekeeping_mask;
+       int err;
+
+       alloc_bootmem_cpumask_var(&non_housekeeping_mask);
+       err = cpulist_parse(str, non_housekeeping_mask);
+       if (err < 0 || cpumask_last(non_housekeeping_mask) >= nr_cpu_ids) {
+               pr_warn("Housekeeping: nohz_full= or isolcpus= incorrect CPU range\n");
+               free_bootmem_cpumask_var(non_housekeeping_mask);
+               return 0;
+       }
+
+       if (!housekeeping_flags) {
+               alloc_bootmem_cpumask_var(&housekeeping_mask);
+               cpumask_andnot(housekeeping_mask,
+                              cpu_possible_mask, non_housekeeping_mask);
+               if (cpumask_empty(housekeeping_mask))
+                       cpumask_set_cpu(smp_processor_id(), housekeeping_mask);
+       } else {
+               cpumask_var_t tmp;
+
+               alloc_bootmem_cpumask_var(&tmp);
+               cpumask_andnot(tmp, cpu_possible_mask, non_housekeeping_mask);
+               if (!cpumask_equal(tmp, housekeeping_mask)) {
+                       pr_warn("Housekeeping: nohz_full= must match isolcpus=\n");
+                       free_bootmem_cpumask_var(tmp);
+                       free_bootmem_cpumask_var(non_housekeeping_mask);
+                       return 0;
+               }
+               free_bootmem_cpumask_var(tmp);
+       }
+
+       if ((flags & HK_FLAG_TICK) && !(housekeeping_flags & HK_FLAG_TICK)) {
+               if (IS_ENABLED(CONFIG_NO_HZ_FULL)) {
+                       tick_nohz_full_setup(non_housekeeping_mask);
+               } else {
+                       pr_warn("Housekeeping: nohz unsupported."
+                               " Build with CONFIG_NO_HZ_FULL\n");
+                       free_bootmem_cpumask_var(non_housekeeping_mask);
+                       return 0;
+               }
+       }
+
+       housekeeping_flags |= flags;
+
+       free_bootmem_cpumask_var(non_housekeeping_mask);
+
+       return 1;
+}
+
+static int __init housekeeping_nohz_full_setup(char *str)
+{
+       unsigned int flags;
+
+       flags = HK_FLAG_TICK | HK_FLAG_TIMER | HK_FLAG_RCU | HK_FLAG_MISC;
+
+       return housekeeping_setup(str, flags);
+}
+__setup("nohz_full=", housekeeping_nohz_full_setup);
+
+static int __init housekeeping_isolcpus_setup(char *str)
+{
+       unsigned int flags = 0;
+
+       while (isalpha(*str)) {
+               if (!strncmp(str, "nohz,", 5)) {
+                       str += 5;
+                       flags |= HK_FLAG_TICK;
+                       continue;
+               }
+
+               if (!strncmp(str, "domain,", 7)) {
+                       str += 7;
+                       flags |= HK_FLAG_DOMAIN;
+                       continue;
+               }
+
+               pr_warn("isolcpus: Error, unknown flag\n");
+               return 0;
+       }
+
+       /* Default behaviour for isolcpus without flags */
+       if (!flags)
+               flags |= HK_FLAG_DOMAIN;
+
+       return housekeeping_setup(str, flags);
+}
+__setup("isolcpus=", housekeeping_isolcpus_setup);
index 3c96c80e0992aff2c3dc0299f709ab16e75d5193..d8c43d73e078806ac468450732b76282fb13f798 100644 (file)
@@ -74,10 +74,6 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b)
        raw_spin_unlock(&rt_b->rt_runtime_lock);
 }
 
-#if defined(CONFIG_SMP) && defined(HAVE_RT_PUSH_IPI)
-static void push_irq_work_func(struct irq_work *work);
-#endif
-
 void init_rt_rq(struct rt_rq *rt_rq)
 {
        struct rt_prio_array *array;
@@ -97,13 +93,6 @@ void init_rt_rq(struct rt_rq *rt_rq)
        rt_rq->rt_nr_migratory = 0;
        rt_rq->overloaded = 0;
        plist_head_init(&rt_rq->pushable_tasks);
-
-#ifdef HAVE_RT_PUSH_IPI
-       rt_rq->push_flags = 0;
-       rt_rq->push_cpu = nr_cpu_ids;
-       raw_spin_lock_init(&rt_rq->push_lock);
-       init_irq_work(&rt_rq->push_work, push_irq_work_func);
-#endif
 #endif /* CONFIG_SMP */
        /* We start is dequeued state, because no RT tasks are queued */
        rt_rq->rt_queued = 0;
@@ -1876,241 +1865,166 @@ static void push_rt_tasks(struct rq *rq)
 }
 
 #ifdef HAVE_RT_PUSH_IPI
+
 /*
- * The search for the next cpu always starts at rq->cpu and ends
- * when we reach rq->cpu again. It will never return rq->cpu.
- * This returns the next cpu to check, or nr_cpu_ids if the loop
- * is complete.
+ * When a high priority task schedules out from a CPU and a lower priority
+ * task is scheduled in, a check is made to see if there's any RT tasks
+ * on other CPUs that are waiting to run because a higher priority RT task
+ * is currently running on its CPU. In this case, the CPU with multiple RT
+ * tasks queued on it (overloaded) needs to be notified that a CPU has opened
+ * up that may be able to run one of its non-running queued RT tasks.
+ *
+ * All CPUs with overloaded RT tasks need to be notified as there is currently
+ * no way to know which of these CPUs have the highest priority task waiting
+ * to run. Instead of trying to take a spinlock on each of these CPUs,
+ * which has shown to cause large latency when done on machines with many
+ * CPUs, sending an IPI to the CPUs to have them push off the overloaded
+ * RT tasks waiting to run.
+ *
+ * Just sending an IPI to each of the CPUs is also an issue, as on large
+ * count CPU machines, this can cause an IPI storm on a CPU, especially
+ * if its the only CPU with multiple RT tasks queued, and a large number
+ * of CPUs scheduling a lower priority task at the same time.
+ *
+ * Each root domain has its own irq work function that can iterate over
+ * all CPUs with RT overloaded tasks. Since all CPUs with overloaded RT
+ * tassk must be checked if there's one or many CPUs that are lowering
+ * their priority, there's a single irq work iterator that will try to
+ * push off RT tasks that are waiting to run.
+ *
+ * When a CPU schedules a lower priority task, it will kick off the
+ * irq work iterator that will jump to each CPU with overloaded RT tasks.
+ * As it only takes the first CPU that schedules a lower priority task
+ * to start the process, the rto_start variable is incremented and if
+ * the atomic result is one, then that CPU will try to take the rto_lock.
+ * This prevents high contention on the lock as the process handles all
+ * CPUs scheduling lower priority tasks.
+ *
+ * All CPUs that are scheduling a lower priority task will increment the
+ * rt_loop_next variable. This will make sure that the irq work iterator
+ * checks all RT overloaded CPUs whenever a CPU schedules a new lower
+ * priority task, even if the iterator is in the middle of a scan. Incrementing
+ * the rt_loop_next will cause the iterator to perform another scan.
  *
- * rq->rt.push_cpu holds the last cpu returned by this function,
- * or if this is the first instance, it must hold rq->cpu.
  */
 static int rto_next_cpu(struct rq *rq)
 {
-       int prev_cpu = rq->rt.push_cpu;
+       struct root_domain *rd = rq->rd;
+       int next;
        int cpu;
 
-       cpu = cpumask_next(prev_cpu, rq->rd->rto_mask);
-
        /*
-        * If the previous cpu is less than the rq's CPU, then it already
-        * passed the end of the mask, and has started from the beginning.
-        * We end if the next CPU is greater or equal to rq's CPU.
+        * When starting the IPI RT pushing, the rto_cpu is set to -1,
+        * rt_next_cpu() will simply return the first CPU found in
+        * the rto_mask.
+        *
+        * If rto_next_cpu() is called with rto_cpu is a valid cpu, it
+        * will return the next CPU found in the rto_mask.
+        *
+        * If there are no more CPUs left in the rto_mask, then a check is made
+        * against rto_loop and rto_loop_next. rto_loop is only updated with
+        * the rto_lock held, but any CPU may increment the rto_loop_next
+        * without any locking.
         */
-       if (prev_cpu < rq->cpu) {
-               if (cpu >= rq->cpu)
-                       return nr_cpu_ids;
+       for (;;) {
 
-       } else if (cpu >= nr_cpu_ids) {
-               /*
-                * We passed the end of the mask, start at the beginning.
-                * If the result is greater or equal to the rq's CPU, then
-                * the loop is finished.
-                */
-               cpu = cpumask_first(rq->rd->rto_mask);
-               if (cpu >= rq->cpu)
-                       return nr_cpu_ids;
-       }
-       rq->rt.push_cpu = cpu;
+               /* When rto_cpu is -1 this acts like cpumask_first() */
+               cpu = cpumask_next(rd->rto_cpu, rd->rto_mask);
 
-       /* Return cpu to let the caller know if the loop is finished or not */
-       return cpu;
-}
+               rd->rto_cpu = cpu;
 
-static int find_next_push_cpu(struct rq *rq)
-{
-       struct rq *next_rq;
-       int cpu;
+               if (cpu < nr_cpu_ids)
+                       return cpu;
 
-       while (1) {
-               cpu = rto_next_cpu(rq);
-               if (cpu >= nr_cpu_ids)
-                       break;
-               next_rq = cpu_rq(cpu);
+               rd->rto_cpu = -1;
+
+               /*
+                * ACQUIRE ensures we see the @rto_mask changes
+                * made prior to the @next value observed.
+                *
+                * Matches WMB in rt_set_overload().
+                */
+               next = atomic_read_acquire(&rd->rto_loop_next);
 
-               /* Make sure the next rq can push to this rq */
-               if (next_rq->rt.highest_prio.next < rq->rt.highest_prio.curr)
+               if (rd->rto_loop == next)
                        break;
+
+               rd->rto_loop = next;
        }
 
-       return cpu;
+       return -1;
 }
 
-#define RT_PUSH_IPI_EXECUTING          1
-#define RT_PUSH_IPI_RESTART            2
+static inline bool rto_start_trylock(atomic_t *v)
+{
+       return !atomic_cmpxchg_acquire(v, 0, 1);
+}
 
-/*
- * When a high priority task schedules out from a CPU and a lower priority
- * task is scheduled in, a check is made to see if there's any RT tasks
- * on other CPUs that are waiting to run because a higher priority RT task
- * is currently running on its CPU. In this case, the CPU with multiple RT
- * tasks queued on it (overloaded) needs to be notified that a CPU has opened
- * up that may be able to run one of its non-running queued RT tasks.
- *
- * On large CPU boxes, there's the case that several CPUs could schedule
- * a lower priority task at the same time, in which case it will look for
- * any overloaded CPUs that it could pull a task from. To do this, the runqueue
- * lock must be taken from that overloaded CPU. Having 10s of CPUs all fighting
- * for a single overloaded CPU's runqueue lock can produce a large latency.
- * (This has actually been observed on large boxes running cyclictest).
- * Instead of taking the runqueue lock of the overloaded CPU, each of the
- * CPUs that scheduled a lower priority task simply sends an IPI to the
- * overloaded CPU. An IPI is much cheaper than taking an runqueue lock with
- * lots of contention. The overloaded CPU will look to push its non-running
- * RT task off, and if it does, it can then ignore the other IPIs coming
- * in, and just pass those IPIs off to any other overloaded CPU.
- *
- * When a CPU schedules a lower priority task, it only sends an IPI to
- * the "next" CPU that has overloaded RT tasks. This prevents IPI storms,
- * as having 10 CPUs scheduling lower priority tasks and 10 CPUs with
- * RT overloaded tasks, would cause 100 IPIs to go out at once.
- *
- * The overloaded RT CPU, when receiving an IPI, will try to push off its
- * overloaded RT tasks and then send an IPI to the next CPU that has
- * overloaded RT tasks. This stops when all CPUs with overloaded RT tasks
- * have completed. Just because a CPU may have pushed off its own overloaded
- * RT task does not mean it should stop sending the IPI around to other
- * overloaded CPUs. There may be another RT task waiting to run on one of
- * those CPUs that are of higher priority than the one that was just
- * pushed.
- *
- * An optimization that could possibly be made is to make a CPU array similar
- * to the cpupri array mask of all running RT tasks, but for the overloaded
- * case, then the IPI could be sent to only the CPU with the highest priority
- * RT task waiting, and that CPU could send off further IPIs to the CPU with
- * the next highest waiting task. Since the overloaded case is much less likely
- * to happen, the complexity of this implementation may not be worth it.
- * Instead, just send an IPI around to all overloaded CPUs.
- *
- * The rq->rt.push_flags holds the status of the IPI that is going around.
- * A run queue can only send out a single IPI at a time. The possible flags
- * for rq->rt.push_flags are:
- *
- *    (None or zero):          No IPI is going around for the current rq
- *    RT_PUSH_IPI_EXECUTING:   An IPI for the rq is being passed around
- *    RT_PUSH_IPI_RESTART:     The priority of the running task for the rq
- *                             has changed, and the IPI should restart
- *                             circulating the overloaded CPUs again.
- *
- * rq->rt.push_cpu contains the CPU that is being sent the IPI. It is updated
- * before sending to the next CPU.
- *
- * Instead of having all CPUs that schedule a lower priority task send
- * an IPI to the same "first" CPU in the RT overload mask, they send it
- * to the next overloaded CPU after their own CPU. This helps distribute
- * the work when there's more than one overloaded CPU and multiple CPUs
- * scheduling in lower priority tasks.
- *
- * When a rq schedules a lower priority task than what was currently
- * running, the next CPU with overloaded RT tasks is examined first.
- * That is, if CPU 1 and 5 are overloaded, and CPU 3 schedules a lower
- * priority task, it will send an IPI first to CPU 5, then CPU 5 will
- * send to CPU 1 if it is still overloaded. CPU 1 will clear the
- * rq->rt.push_flags if RT_PUSH_IPI_RESTART is not set.
- *
- * The first CPU to notice IPI_RESTART is set, will clear that flag and then
- * send an IPI to the next overloaded CPU after the rq->cpu and not the next
- * CPU after push_cpu. That is, if CPU 1, 4 and 5 are overloaded when CPU 3
- * schedules a lower priority task, and the IPI_RESTART gets set while the
- * handling is being done on CPU 5, it will clear the flag and send it back to
- * CPU 4 instead of CPU 1.
- *
- * Note, the above logic can be disabled by turning off the sched_feature
- * RT_PUSH_IPI. Then the rq lock of the overloaded CPU will simply be
- * taken by the CPU requesting a pull and the waiting RT task will be pulled
- * by that CPU. This may be fine for machines with few CPUs.
- */
-static void tell_cpu_to_push(struct rq *rq)
+static inline void rto_start_unlock(atomic_t *v)
 {
-       int cpu;
+       atomic_set_release(v, 0);
+}
 
-       if (rq->rt.push_flags & RT_PUSH_IPI_EXECUTING) {
-               raw_spin_lock(&rq->rt.push_lock);
-               /* Make sure it's still executing */
-               if (rq->rt.push_flags & RT_PUSH_IPI_EXECUTING) {
-                       /*
-                        * Tell the IPI to restart the loop as things have
-                        * changed since it started.
-                        */
-                       rq->rt.push_flags |= RT_PUSH_IPI_RESTART;
-                       raw_spin_unlock(&rq->rt.push_lock);
-                       return;
-               }
-               raw_spin_unlock(&rq->rt.push_lock);
-       }
+static void tell_cpu_to_push(struct rq *rq)
+{
+       int cpu = -1;
 
-       /* When here, there's no IPI going around */
+       /* Keep the loop going if the IPI is currently active */
+       atomic_inc(&rq->rd->rto_loop_next);
 
-       rq->rt.push_cpu = rq->cpu;
-       cpu = find_next_push_cpu(rq);
-       if (cpu >= nr_cpu_ids)
+       /* Only one CPU can initiate a loop at a time */
+       if (!rto_start_trylock(&rq->rd->rto_loop_start))
                return;
 
-       rq->rt.push_flags = RT_PUSH_IPI_EXECUTING;
+       raw_spin_lock(&rq->rd->rto_lock);
+
+       /*
+        * The rto_cpu is updated under the lock, if it has a valid cpu
+        * then the IPI is still running and will continue due to the
+        * update to loop_next, and nothing needs to be done here.
+        * Otherwise it is finishing up and an ipi needs to be sent.
+        */
+       if (rq->rd->rto_cpu < 0)
+               cpu = rto_next_cpu(rq);
 
-       irq_work_queue_on(&rq->rt.push_work, cpu);
+       raw_spin_unlock(&rq->rd->rto_lock);
+
+       rto_start_unlock(&rq->rd->rto_loop_start);
+
+       if (cpu >= 0)
+               irq_work_queue_on(&rq->rd->rto_push_work, cpu);
 }
 
 /* Called from hardirq context */
-static void try_to_push_tasks(void *arg)
+void rto_push_irq_work_func(struct irq_work *work)
 {
-       struct rt_rq *rt_rq = arg;
-       struct rq *rq, *src_rq;
-       int this_cpu;
+       struct rq *rq;
        int cpu;
 
-       this_cpu = rt_rq->push_cpu;
+       rq = this_rq();
 
-       /* Paranoid check */
-       BUG_ON(this_cpu != smp_processor_id());
-
-       rq = cpu_rq(this_cpu);
-       src_rq = rq_of_rt_rq(rt_rq);
-
-again:
+       /*
+        * We do not need to grab the lock to check for has_pushable_tasks.
+        * When it gets updated, a check is made if a push is possible.
+        */
        if (has_pushable_tasks(rq)) {
                raw_spin_lock(&rq->lock);
-               push_rt_task(rq);
+               push_rt_tasks(rq);
                raw_spin_unlock(&rq->lock);
        }
 
-       /* Pass the IPI to the next rt overloaded queue */
-       raw_spin_lock(&rt_rq->push_lock);
-       /*
-        * If the source queue changed since the IPI went out,
-        * we need to restart the search from that CPU again.
-        */
-       if (rt_rq->push_flags & RT_PUSH_IPI_RESTART) {
-               rt_rq->push_flags &= ~RT_PUSH_IPI_RESTART;
-               rt_rq->push_cpu = src_rq->cpu;
-       }
+       raw_spin_lock(&rq->rd->rto_lock);
 
-       cpu = find_next_push_cpu(src_rq);
+       /* Pass the IPI to the next rt overloaded queue */
+       cpu = rto_next_cpu(rq);
 
-       if (cpu >= nr_cpu_ids)
-               rt_rq->push_flags &= ~RT_PUSH_IPI_EXECUTING;
-       raw_spin_unlock(&rt_rq->push_lock);
+       raw_spin_unlock(&rq->rd->rto_lock);
 
-       if (cpu >= nr_cpu_ids)
+       if (cpu < 0)
                return;
 
-       /*
-        * It is possible that a restart caused this CPU to be
-        * chosen again. Don't bother with an IPI, just see if we
-        * have more to push.
-        */
-       if (unlikely(cpu == rq->cpu))
-               goto again;
-
        /* Try the next RT overloaded CPU */
-       irq_work_queue_on(&rt_rq->push_work, cpu);
-}
-
-static void push_irq_work_func(struct irq_work *work)
-{
-       struct rt_rq *rt_rq = container_of(work, struct rt_rq, push_work);
-
-       try_to_push_tasks(rt_rq);
+       irq_work_queue_on(&rq->rd->rto_push_work, cpu);
 }
 #endif /* HAVE_RT_PUSH_IPI */
 
index 3b448ba82225dfb6f5ce7b221541aa2a6d6b3a6e..45ab0bf564e7abde39013518754e96c3e72f5c3e 100644 (file)
@@ -227,7 +227,7 @@ struct dl_bw {
 static inline void __dl_update(struct dl_bw *dl_b, s64 bw);
 
 static inline
-void __dl_clear(struct dl_bw *dl_b, u64 tsk_bw, int cpus)
+void __dl_sub(struct dl_bw *dl_b, u64 tsk_bw, int cpus)
 {
        dl_b->total_bw -= tsk_bw;
        __dl_update(dl_b, (s32)tsk_bw / cpus);
@@ -256,7 +256,6 @@ extern int sched_dl_overflow(struct task_struct *p, int policy,
 extern void __setparam_dl(struct task_struct *p, const struct sched_attr *attr);
 extern void __getparam_dl(struct task_struct *p, struct sched_attr *attr);
 extern bool __checkparam_dl(const struct sched_attr *attr);
-extern void __dl_clear_params(struct task_struct *p);
 extern bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr);
 extern int dl_task_can_attach(struct task_struct *p,
                              const struct cpumask *cs_cpus_allowed);
@@ -419,6 +418,7 @@ struct cfs_bandwidth { };
 /* CFS-related fields in a runqueue */
 struct cfs_rq {
        struct load_weight load;
+       unsigned long runnable_weight;
        unsigned int nr_running, h_nr_running;
 
        u64 exec_clock;
@@ -444,18 +444,22 @@ struct cfs_rq {
         * CFS load tracking
         */
        struct sched_avg avg;
-       u64 runnable_load_sum;
-       unsigned long runnable_load_avg;
-#ifdef CONFIG_FAIR_GROUP_SCHED
-       unsigned long tg_load_avg_contrib;
-       unsigned long propagate_avg;
-#endif
-       atomic_long_t removed_load_avg, removed_util_avg;
 #ifndef CONFIG_64BIT
        u64 load_last_update_time_copy;
 #endif
+       struct {
+               raw_spinlock_t  lock ____cacheline_aligned;
+               int             nr;
+               unsigned long   load_avg;
+               unsigned long   util_avg;
+               unsigned long   runnable_sum;
+       } removed;
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
+       unsigned long tg_load_avg_contrib;
+       long propagate;
+       long prop_runnable_sum;
+
        /*
         *   h_load = weight * f(tg)
         *
@@ -502,7 +506,7 @@ static inline int rt_bandwidth_enabled(void)
 }
 
 /* RT IPI pull logic requires IRQ_WORK */
-#ifdef CONFIG_IRQ_WORK
+#if defined(CONFIG_IRQ_WORK) && defined(CONFIG_SMP)
 # define HAVE_RT_PUSH_IPI
 #endif
 
@@ -524,12 +528,6 @@ struct rt_rq {
        unsigned long rt_nr_total;
        int overloaded;
        struct plist_head pushable_tasks;
-#ifdef HAVE_RT_PUSH_IPI
-       int push_flags;
-       int push_cpu;
-       struct irq_work push_work;
-       raw_spinlock_t push_lock;
-#endif
 #endif /* CONFIG_SMP */
        int rt_queued;
 
@@ -638,6 +636,19 @@ struct root_domain {
        struct dl_bw dl_bw;
        struct cpudl cpudl;
 
+#ifdef HAVE_RT_PUSH_IPI
+       /*
+        * For IPI pull requests, loop across the rto_mask.
+        */
+       struct irq_work rto_push_work;
+       raw_spinlock_t rto_lock;
+       /* These are only updated and read within rto_lock */
+       int rto_loop;
+       int rto_cpu;
+       /* These atomics are updated outside of a lock */
+       atomic_t rto_loop_next;
+       atomic_t rto_loop_start;
+#endif
        /*
         * The "RT overload" flag: it gets set if a CPU has more than
         * one runnable RT task.
@@ -655,6 +666,9 @@ extern void init_defrootdomain(void);
 extern int sched_init_domains(const struct cpumask *cpu_map);
 extern void rq_attach_root(struct rq *rq, struct root_domain *rd);
 
+#ifdef HAVE_RT_PUSH_IPI
+extern void rto_push_irq_work_func(struct irq_work *work);
+#endif
 #endif /* CONFIG_SMP */
 
 /*
@@ -1219,8 +1233,6 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
 # define const_debug const
 #endif
 
-extern const_debug unsigned int sysctl_sched_features;
-
 #define SCHED_FEAT(name, enabled)      \
        __SCHED_FEAT_##name ,
 
@@ -1232,6 +1244,13 @@ enum {
 #undef SCHED_FEAT
 
 #if defined(CONFIG_SCHED_DEBUG) && defined(HAVE_JUMP_LABEL)
+
+/*
+ * To support run-time toggling of sched features, all the translation units
+ * (but core.c) reference the sysctl_sched_features defined in core.c.
+ */
+extern const_debug unsigned int sysctl_sched_features;
+
 #define SCHED_FEAT(name, enabled)                                      \
 static __always_inline bool static_branch_##name(struct static_key *key) \
 {                                                                      \
@@ -1239,13 +1258,27 @@ static __always_inline bool static_branch_##name(struct static_key *key) \
 }
 
 #include "features.h"
-
 #undef SCHED_FEAT
 
 extern struct static_key sched_feat_keys[__SCHED_FEAT_NR];
 #define sched_feat(x) (static_branch_##x(&sched_feat_keys[__SCHED_FEAT_##x]))
+
 #else /* !(SCHED_DEBUG && HAVE_JUMP_LABEL) */
+
+/*
+ * Each translation unit has its own copy of sysctl_sched_features to allow
+ * constants propagation at compile time and compiler optimization based on
+ * features default.
+ */
+#define SCHED_FEAT(name, enabled)      \
+       (1UL << __SCHED_FEAT_##name) * enabled |
+static const_debug __maybe_unused unsigned int sysctl_sched_features =
+#include "features.h"
+       0;
+#undef SCHED_FEAT
+
 #define sched_feat(x) (sysctl_sched_features & (1UL << __SCHED_FEAT_##x))
+
 #endif /* SCHED_DEBUG && HAVE_JUMP_LABEL */
 
 extern struct static_key_false sched_numa_balancing;
@@ -1530,6 +1563,8 @@ extern void init_sched_dl_class(void);
 extern void init_sched_rt_class(void);
 extern void init_sched_fair_class(void);
 
+extern void reweight_task(struct task_struct *p, int prio);
+
 extern void resched_curr(struct rq *rq);
 extern void resched_cpu(int cpu);
 
index 6798276d29af2e72ecc91351b34c9adbf2985099..034cbed7f88b4f14dc44fb9565706436805c68b8 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include <linux/sched.h>
 #include <linux/mutex.h>
+#include <linux/sched/isolation.h>
 
 #include "sched.h"
 
@@ -269,6 +270,12 @@ static int init_rootdomain(struct root_domain *rd)
        if (!zalloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
                goto free_dlo_mask;
 
+#ifdef HAVE_RT_PUSH_IPI
+       rd->rto_cpu = -1;
+       raw_spin_lock_init(&rd->rto_lock);
+       init_irq_work(&rd->rto_push_work, rto_push_irq_work_func);
+#endif
+
        init_dl_bw(&rd->dl_bw);
        if (cpudl_init(&rd->cpudl) != 0)
                goto free_rto_mask;
@@ -464,21 +471,6 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu)
        update_top_cache_domain(cpu);
 }
 
-/* Setup the mask of CPUs configured for isolated domains */
-static int __init isolated_cpu_setup(char *str)
-{
-       int ret;
-
-       alloc_bootmem_cpumask_var(&cpu_isolated_map);
-       ret = cpulist_parse(str, cpu_isolated_map);
-       if (ret) {
-               pr_err("sched: Error, all isolcpus= values must be between 0 and %u\n", nr_cpu_ids);
-               return 0;
-       }
-       return 1;
-}
-__setup("isolcpus=", isolated_cpu_setup);
-
 struct s_data {
        struct sched_domain ** __percpu sd;
        struct root_domain      *rd;
@@ -1158,6 +1150,7 @@ sd_init(struct sched_domain_topology_level *tl,
                sd->smt_gain = 1178; /* ~15% */
 
        } else if (sd->flags & SD_SHARE_PKG_RESOURCES) {
+               sd->flags |= SD_PREFER_SIBLING;
                sd->imbalance_pct = 117;
                sd->cache_nice_tries = 1;
                sd->busy_idx = 2;
@@ -1332,6 +1325,10 @@ void sched_init_numa(void)
        if (!sched_domains_numa_distance)
                return;
 
+       /* Includes NUMA identity node at level 0. */
+       sched_domains_numa_distance[level++] = curr_distance;
+       sched_domains_numa_levels = level;
+
        /*
         * O(nr_nodes^2) deduplicating selection sort -- in order to find the
         * unique distances in the node_distance() table.
@@ -1379,8 +1376,7 @@ void sched_init_numa(void)
                return;
 
        /*
-        * 'level' contains the number of unique distances, excluding the
-        * identity distance node_distance(i,i).
+        * 'level' contains the number of unique distances
         *
         * The sched_domains_numa_distance[] array includes the actual distance
         * numbers.
@@ -1441,10 +1437,19 @@ void sched_init_numa(void)
        for (i = 0; sched_domain_topology[i].mask; i++)
                tl[i] = sched_domain_topology[i];
 
+       /*
+        * Add the NUMA identity distance, aka single NODE.
+        */
+       tl[i++] = (struct sched_domain_topology_level){
+               .mask = sd_numa_mask,
+               .numa_level = 0,
+               SD_INIT_NAME(NODE)
+       };
+
        /*
         * .. and append 'j' levels of NUMA goodness.
         */
-       for (j = 0; j < level; i++, j++) {
+       for (j = 1; j < level; i++, j++) {
                tl[i] = (struct sched_domain_topology_level){
                        .mask = sd_numa_mask,
                        .sd_flags = cpu_numa_flags,
@@ -1774,7 +1779,7 @@ int sched_init_domains(const struct cpumask *cpu_map)
        doms_cur = alloc_sched_domains(ndoms_cur);
        if (!doms_cur)
                doms_cur = &fallback_doms;
-       cpumask_andnot(doms_cur[0], cpu_map, cpu_isolated_map);
+       cpumask_and(doms_cur[0], cpu_map, housekeeping_cpumask(HK_FLAG_DOMAIN));
        err = build_sched_domains(doms_cur[0], NULL);
        register_sched_domain_sysctl();
 
@@ -1857,7 +1862,8 @@ void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
                doms_new = alloc_sched_domains(1);
                if (doms_new) {
                        n = 1;
-                       cpumask_andnot(doms_new[0], cpu_active_mask, cpu_isolated_map);
+                       cpumask_and(doms_new[0], cpu_active_mask,
+                                   housekeeping_cpumask(HK_FLAG_DOMAIN));
                }
        } else {
                n = ndoms_new;
@@ -1880,7 +1886,8 @@ match1:
        if (!doms_new) {
                n = 0;
                doms_new = &fallback_doms;
-               cpumask_andnot(doms_new[0], cpu_active_mask, cpu_isolated_map);
+               cpumask_and(doms_new[0], cpu_active_mask,
+                           housekeeping_cpumask(HK_FLAG_DOMAIN));
        }
 
        /* Build new domains: */
index 418a1c045933dc57e97de46efe1c71dcc5c879ca..5f0dfb2abb8d39542d72003f860e25eaff66c8f0 100644 (file)
@@ -190,7 +190,7 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd,
        u32 ret = SECCOMP_RET_ALLOW;
        /* Make sure cross-thread synced filter points somewhere sane. */
        struct seccomp_filter *f =
-                       lockless_dereference(current->seccomp.filter);
+                       READ_ONCE(current->seccomp.filter);
 
        /* Ensure unexpected behavior doesn't result in failing open. */
        if (unlikely(WARN_ON(f == NULL)))
index c94dd85c8d41798443a7080af55c24fe508815b3..084c8b3a26812d78e3eb2da63d46091e491a7e23 100644 (file)
@@ -213,7 +213,7 @@ static void flush_smp_call_function_queue(bool warn_cpu_offline)
        call_single_data_t *csd, *csd_next;
        static bool warned;
 
-       WARN_ON(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        head = this_cpu_ptr(&call_single_queue);
        entry = llist_del_all(head);
index 4e09821f9d9e8b5815037bd469110e2618abb7f6..662f7b1b7a78f6115a9f753e9ebba5a03774f426 100644 (file)
@@ -137,7 +137,7 @@ EXPORT_SYMBOL(__local_bh_disable_ip);
 
 static void __local_bh_enable(unsigned int cnt)
 {
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        if (softirq_count() == (cnt & SOFTIRQ_MASK))
                trace_softirqs_on(_RET_IP_);
@@ -158,7 +158,8 @@ EXPORT_SYMBOL(_local_bh_enable);
 
 void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
 {
-       WARN_ON_ONCE(in_irq() || irqs_disabled());
+       WARN_ON_ONCE(in_irq());
+       lockdep_assert_irqs_enabled();
 #ifdef CONFIG_TRACE_IRQFLAGS
        local_irq_disable();
 #endif
@@ -396,9 +397,8 @@ void irq_exit(void)
 #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
        local_irq_disable();
 #else
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 #endif
-
        account_irq_exit_time(current);
        preempt_count_sub(HARDIRQ_OFFSET);
        if (!in_interrupt() && local_softirq_pending())
@@ -488,7 +488,7 @@ EXPORT_SYMBOL(__tasklet_hi_schedule);
 
 void __tasklet_hi_schedule_first(struct tasklet_struct *t)
 {
-       BUG_ON(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        t->next = __this_cpu_read(tasklet_hi_vec.head);
        __this_cpu_write(tasklet_hi_vec.head, t);
index 5718b3ea202a3f5dd7186e6454f18fb6be392644..0fef395662a6ea6f38301e92f74d14f60b3f145d 100644 (file)
@@ -68,7 +68,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
         * we raced with task_work_run(), *pprev == NULL/exited.
         */
        raw_spin_lock_irqsave(&task->pi_lock, flags);
-       while ((work = lockless_dereference(*pprev))) {
+       while ((work = READ_ONCE(*pprev))) {
                if (work->func != func)
                        pprev = &work->next;
                else if (cmpxchg(pprev, work, work->next) == work)
index 0dbab6d1acb422368d8fc8c04a8eda94ba9342eb..dd53e354f630d9251de443d6a9cd6632c3646211 100644 (file)
@@ -22,7 +22,7 @@
 
 #define div_factor 3
 
-static u32 rand1, preh_val, posth_val, jph_val;
+static u32 rand1, preh_val, posth_val;
 static int errors, handler_errors, num_tests;
 static u32 (*target)(u32 value);
 static u32 (*target2)(u32 value);
@@ -34,6 +34,10 @@ static noinline u32 kprobe_target(u32 value)
 
 static int kp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
+       if (preemptible()) {
+               handler_errors++;
+               pr_err("pre-handler is preemptible\n");
+       }
        preh_val = (rand1 / div_factor);
        return 0;
 }
@@ -41,6 +45,10 @@ static int kp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 static void kp_post_handler(struct kprobe *p, struct pt_regs *regs,
                unsigned long flags)
 {
+       if (preemptible()) {
+               handler_errors++;
+               pr_err("post-handler is preemptible\n");
+       }
        if (preh_val != (rand1 / div_factor)) {
                handler_errors++;
                pr_err("incorrect value in post_handler\n");
@@ -154,8 +162,15 @@ static int test_kprobes(void)
 
 }
 
+#if 0
+static u32 jph_val;
+
 static u32 j_kprobe_target(u32 value)
 {
+       if (preemptible()) {
+               handler_errors++;
+               pr_err("jprobe-handler is preemptible\n");
+       }
        if (value != rand1) {
                handler_errors++;
                pr_err("incorrect value in jprobe handler\n");
@@ -227,11 +242,19 @@ static int test_jprobes(void)
 
        return 0;
 }
+#else
+#define test_jprobe() (0)
+#define test_jprobes() (0)
+#endif
 #ifdef CONFIG_KRETPROBES
 static u32 krph_val;
 
 static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
+       if (preemptible()) {
+               handler_errors++;
+               pr_err("kretprobe entry handler is preemptible\n");
+       }
        krph_val = (rand1 / div_factor);
        return 0;
 }
@@ -240,6 +263,10 @@ static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        unsigned long ret = regs_return_value(regs);
 
+       if (preemptible()) {
+               handler_errors++;
+               pr_err("kretprobe return handler is preemptible\n");
+       }
        if (ret != (rand1 / div_factor)) {
                handler_errors++;
                pr_err("incorrect value in kretprobe handler\n");
index ac09bc29eb08216a8588710d08515705a749fb19..d689a9557e170b9d89ddb7cb42e518a82d5851cb 100644 (file)
@@ -56,7 +56,7 @@ menu "Timers subsystem"
 
 # Core internal switch. Selected by NO_HZ_COMMON / HIGH_RES_TIMERS. This is
 # only related to the tick functionality. Oneshot clockevent devices
-# are supported independ of this.
+# are supported independent of this.
 config TICK_ONESHOT
        bool
 
index 4237e0744e26bd276de92ca083a44676c9ede240..16c027e9cc730a38d1bb97da89dd9f30c4557145 100644 (file)
@@ -280,17 +280,22 @@ static int clockevents_program_min_delta(struct clock_event_device *dev)
 static int clockevents_program_min_delta(struct clock_event_device *dev)
 {
        unsigned long long clc;
-       int64_t delta;
+       int64_t delta = 0;
+       int i;
 
-       delta = dev->min_delta_ns;
-       dev->next_event = ktime_add_ns(ktime_get(), delta);
+       for (i = 0; i < 10; i++) {
+               delta += dev->min_delta_ns;
+               dev->next_event = ktime_add_ns(ktime_get(), delta);
 
-       if (clockevent_state_shutdown(dev))
-               return 0;
+               if (clockevent_state_shutdown(dev))
+                       return 0;
 
-       dev->retries++;
-       clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
-       return dev->set_next_event((unsigned long) clc, dev);
+               dev->retries++;
+               clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
+               if (dev->set_next_event((unsigned long) clc, dev) == 0)
+                       return 0;
+       }
+       return -ETIME;
 }
 
 #endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */
index 88f75f92ef368c53ba8f2a1832068dbe9710cb49..d32520840fde9b1d0e63a4be7d96e092ddd06acf 100644 (file)
@@ -758,9 +758,7 @@ void clock_was_set(void)
  */
 void hrtimers_resume(void)
 {
-       WARN_ONCE(!irqs_disabled(),
-                 KERN_INFO "hrtimers_resume() called with IRQs enabled!");
-
+       lockdep_assert_irqs_disabled();
        /* Retrigger on the local CPU */
        retrigger_next_event(NULL);
        /* And schedule a retrigger for all others */
index 99e03bec68e4cbaa3ba103f3097eeb1e5d38e3ee..8d70da1b9a0d21bb8057eacd47362f45314c254a 100644 (file)
@@ -493,6 +493,67 @@ out:
        return leap;
 }
 
+static void sync_hw_clock(struct work_struct *work);
+static DECLARE_DELAYED_WORK(sync_work, sync_hw_clock);
+
+static void sched_sync_hw_clock(struct timespec64 now,
+                               unsigned long target_nsec, bool fail)
+
+{
+       struct timespec64 next;
+
+       getnstimeofday64(&next);
+       if (!fail)
+               next.tv_sec = 659;
+       else {
+               /*
+                * Try again as soon as possible. Delaying long periods
+                * decreases the accuracy of the work queue timer. Due to this
+                * the algorithm is very likely to require a short-sleep retry
+                * after the above long sleep to synchronize ts_nsec.
+                */
+               next.tv_sec = 0;
+       }
+
+       /* Compute the needed delay that will get to tv_nsec == target_nsec */
+       next.tv_nsec = target_nsec - next.tv_nsec;
+       if (next.tv_nsec <= 0)
+               next.tv_nsec += NSEC_PER_SEC;
+       if (next.tv_nsec >= NSEC_PER_SEC) {
+               next.tv_sec++;
+               next.tv_nsec -= NSEC_PER_SEC;
+       }
+
+       queue_delayed_work(system_power_efficient_wq, &sync_work,
+                          timespec64_to_jiffies(&next));
+}
+
+static void sync_rtc_clock(void)
+{
+       unsigned long target_nsec;
+       struct timespec64 adjust, now;
+       int rc;
+
+       if (!IS_ENABLED(CONFIG_RTC_SYSTOHC))
+               return;
+
+       getnstimeofday64(&now);
+
+       adjust = now;
+       if (persistent_clock_is_local)
+               adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
+
+       /*
+        * The current RTC in use will provide the target_nsec it wants to be
+        * called at, and does rtc_tv_nsec_ok internally.
+        */
+       rc = rtc_set_ntp_time(adjust, &target_nsec);
+       if (rc == -ENODEV)
+               return;
+
+       sched_sync_hw_clock(now, target_nsec, rc);
+}
+
 #ifdef CONFIG_GENERIC_CMOS_UPDATE
 int __weak update_persistent_clock(struct timespec now)
 {
@@ -508,76 +569,75 @@ int __weak update_persistent_clock64(struct timespec64 now64)
 }
 #endif
 
-#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
-static void sync_cmos_clock(struct work_struct *work);
-
-static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
-
-static void sync_cmos_clock(struct work_struct *work)
+static bool sync_cmos_clock(void)
 {
+       static bool no_cmos;
        struct timespec64 now;
-       struct timespec64 next;
-       int fail = 1;
+       struct timespec64 adjust;
+       int rc = -EPROTO;
+       long target_nsec = NSEC_PER_SEC / 2;
+
+       if (!IS_ENABLED(CONFIG_GENERIC_CMOS_UPDATE))
+               return false;
+
+       if (no_cmos)
+               return false;
 
        /*
-        * If we have an externally synchronized Linux clock, then update
-        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-        * called as close as possible to 500 ms before the new second starts.
-        * This code is run on a timer.  If the clock is set, that timer
-        * may not expire at the correct time.  Thus, we adjust...
-        * We want the clock to be within a couple of ticks from the target.
+        * Historically update_persistent_clock64() has followed x86
+        * semantics, which match the MC146818A/etc RTC. This RTC will store
+        * 'adjust' and then in .5s it will advance once second.
+        *
+        * Architectures are strongly encouraged to use rtclib and not
+        * implement this legacy API.
         */
-       if (!ntp_synced()) {
-               /*
-                * Not synced, exit, do not restart a timer (if one is
-                * running, let it run out).
-                */
-               return;
-       }
-
        getnstimeofday64(&now);
-       if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec * 5) {
-               struct timespec64 adjust = now;
-
-               fail = -ENODEV;
+       if (rtc_tv_nsec_ok(-1 * target_nsec, &adjust, &now)) {
                if (persistent_clock_is_local)
                        adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
-#ifdef CONFIG_GENERIC_CMOS_UPDATE
-               fail = update_persistent_clock64(adjust);
-#endif
-
-#ifdef CONFIG_RTC_SYSTOHC
-               if (fail == -ENODEV)
-                       fail = rtc_set_ntp_time(adjust);
-#endif
+               rc = update_persistent_clock64(adjust);
+               /*
+                * The machine does not support update_persistent_clock64 even
+                * though it defines CONFIG_GENERIC_CMOS_UPDATE.
+                */
+               if (rc == -ENODEV) {
+                       no_cmos = true;
+                       return false;
+               }
        }
 
-       next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2);
-       if (next.tv_nsec <= 0)
-               next.tv_nsec += NSEC_PER_SEC;
+       sched_sync_hw_clock(now, target_nsec, rc);
+       return true;
+}
 
-       if (!fail || fail == -ENODEV)
-               next.tv_sec = 659;
-       else
-               next.tv_sec = 0;
+/*
+ * If we have an externally synchronized Linux clock, then update RTC clock
+ * accordingly every ~11 minutes. Generally RTCs can only store second
+ * precision, but many RTCs will adjust the phase of their second tick to
+ * match the moment of update. This infrastructure arranges to call to the RTC
+ * set at the correct moment to phase synchronize the RTC second tick over
+ * with the kernel clock.
+ */
+static void sync_hw_clock(struct work_struct *work)
+{
+       if (!ntp_synced())
+               return;
 
-       if (next.tv_nsec >= NSEC_PER_SEC) {
-               next.tv_sec++;
-               next.tv_nsec -= NSEC_PER_SEC;
-       }
-       queue_delayed_work(system_power_efficient_wq,
-                          &sync_cmos_work, timespec64_to_jiffies(&next));
+       if (sync_cmos_clock())
+               return;
+
+       sync_rtc_clock();
 }
 
 void ntp_notify_cmos_timer(void)
 {
-       queue_delayed_work(system_power_efficient_wq, &sync_cmos_work, 0);
-}
-
-#else
-void ntp_notify_cmos_timer(void) { }
-#endif
+       if (!ntp_synced())
+               return;
 
+       if (IS_ENABLED(CONFIG_GENERIC_CMOS_UPDATE) ||
+           IS_ENABLED(CONFIG_RTC_SYSTOHC))
+               queue_delayed_work(system_power_efficient_wq, &sync_work, 0);
+}
 
 /*
  * Propagate a new txc->status value into the NTP state:
@@ -654,67 +714,6 @@ static inline void process_adjtimex_modes(struct timex *txc,
 }
 
 
-
-/**
- * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex
- */
-int ntp_validate_timex(struct timex *txc)
-{
-       if (txc->modes & ADJ_ADJTIME) {
-               /* singleshot must not be used with any other mode bits */
-               if (!(txc->modes & ADJ_OFFSET_SINGLESHOT))
-                       return -EINVAL;
-               if (!(txc->modes & ADJ_OFFSET_READONLY) &&
-                   !capable(CAP_SYS_TIME))
-                       return -EPERM;
-       } else {
-               /* In order to modify anything, you gotta be super-user! */
-                if (txc->modes && !capable(CAP_SYS_TIME))
-                       return -EPERM;
-               /*
-                * if the quartz is off by more than 10% then
-                * something is VERY wrong!
-                */
-               if (txc->modes & ADJ_TICK &&
-                   (txc->tick <  900000/USER_HZ ||
-                    txc->tick > 1100000/USER_HZ))
-                       return -EINVAL;
-       }
-
-       if (txc->modes & ADJ_SETOFFSET) {
-               /* In order to inject time, you gotta be super-user! */
-               if (!capable(CAP_SYS_TIME))
-                       return -EPERM;
-
-               if (txc->modes & ADJ_NANO) {
-                       struct timespec ts;
-
-                       ts.tv_sec = txc->time.tv_sec;
-                       ts.tv_nsec = txc->time.tv_usec;
-                       if (!timespec_inject_offset_valid(&ts))
-                               return -EINVAL;
-
-               } else {
-                       if (!timeval_inject_offset_valid(&txc->time))
-                               return -EINVAL;
-               }
-       }
-
-       /*
-        * Check for potential multiplication overflows that can
-        * only happen on 64-bit systems:
-        */
-       if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) {
-               if (LLONG_MIN / PPM_SCALE > txc->freq)
-                       return -EINVAL;
-               if (LLONG_MAX / PPM_SCALE < txc->freq)
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-
 /*
  * adjtimex mainly allows reading (and writing, if superuser) of
  * kernel time-keeping variables. used by xntpd.
index 0a53e6ea47b19ac52994222f376b51409f1b3bbb..909bd1f1bfb14dba87f6dc82fc85009108cabcdc 100644 (file)
@@ -8,7 +8,6 @@ extern void ntp_clear(void);
 extern u64 ntp_tick_length(void);
 extern ktime_t ntp_get_next_leap(void);
 extern int second_overflow(time64_t secs);
-extern int ntp_validate_timex(struct timex *);
 extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
 extern void __hardpps(const struct timespec64 *, const struct timespec64 *);
 #endif /* _LINUX_NTP_INTERNAL_H */
index 5b117110b55b59af25fd1ee1f0a81d9ead5dde87..1f27887aa19487e82950498485bc83a295098104 100644 (file)
@@ -603,7 +603,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
        /*
         * Disarm any old timer after extracting its expiry time.
         */
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        ret = 0;
        old_incr = timer->it.cpu.incr;
@@ -1034,7 +1034,7 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
        /*
         * Now re-arm for the new expiry time.
         */
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
        arm_timer(timer);
 unlock:
        unlock_task_sighand(p, &flags);
@@ -1125,7 +1125,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)
        struct k_itimer *timer, *next;
        unsigned long flags;
 
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        /*
         * The fast path checks that there are no expired thread or thread
index 06f34feb635ed4ddb4b736f6e9ece10f2686d4f6..b258bee13b021bcf72879a84a9d336cacf48e4ff 100644 (file)
@@ -117,8 +117,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
                const struct timespec __user *, rqtp,
                struct timespec __user *, rmtp)
 {
-       struct timespec64 t64;
-       struct timespec t;
+       struct timespec64 t;
 
        switch (which_clock) {
        case CLOCK_REALTIME:
@@ -129,16 +128,15 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
                return -EINVAL;
        }
 
-       if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
+       if (get_timespec64(&t, rqtp))
                return -EFAULT;
-       t64 = timespec_to_timespec64(t);
-       if (!timespec64_valid(&t64))
+       if (!timespec64_valid(&t))
                return -EINVAL;
        if (flags & TIMER_ABSTIME)
                rmtp = NULL;
        current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
        current->restart_block.nanosleep.rmtp = rmtp;
-       return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ?
+       return hrtimer_nanosleep(&t, flags & TIMER_ABSTIME ?
                                 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
                                 which_clock);
 }
@@ -203,8 +201,7 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
                       struct compat_timespec __user *, rqtp,
                       struct compat_timespec __user *, rmtp)
 {
-       struct timespec64 t64;
-       struct timespec t;
+       struct timespec64 t;
 
        switch (which_clock) {
        case CLOCK_REALTIME:
@@ -215,16 +212,15 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
                return -EINVAL;
        }
 
-       if (compat_get_timespec(&t, rqtp))
+       if (compat_get_timespec64(&t, rqtp))
                return -EFAULT;
-       t64 = timespec_to_timespec64(t);
-       if (!timespec64_valid(&t64))
+       if (!timespec64_valid(&t))
                return -EINVAL;
        if (flags & TIMER_ABSTIME)
                rmtp = NULL;
        current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
        current->restart_block.nanosleep.compat_rmtp = rmtp;
-       return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ?
+       return hrtimer_nanosleep(&t, flags & TIMER_ABSTIME ?
                                 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
                                 which_clock);
 }
index 6b009c2076718f284b455ea2b6c084b208a57e53..c1f518e7aa808a281b5dab69f3961a02b2c14315 100644 (file)
@@ -33,6 +33,7 @@ int tick_program_event(ktime_t expires, int force)
                 * We don't need the clock event device any more, stop it.
                 */
                clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT_STOPPED);
+               dev->next_event = KTIME_MAX;
                return 0;
        }
 
index c7a899c5ce643f04fcfa1bbeb9eb97c0d0984016..99578f06c8d4fe57cb15cdd44fd58865cae8d0f3 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/irq_work.h>
 #include <linux/posix-timers.h>
 #include <linux/context_tracking.h>
+#include <linux/mm.h>
 
 #include <asm/irq_regs.h>
 
@@ -165,7 +166,6 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
 
 #ifdef CONFIG_NO_HZ_FULL
 cpumask_var_t tick_nohz_full_mask;
-cpumask_var_t housekeeping_mask;
 bool tick_nohz_full_running;
 static atomic_t tick_dep_mask;
 
@@ -198,7 +198,7 @@ static bool check_tick_dependency(atomic_t *dep)
 
 static bool can_stop_full_tick(int cpu, struct tick_sched *ts)
 {
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        if (unlikely(!cpu_online(cpu)))
                return false;
@@ -385,20 +385,13 @@ out:
        local_irq_restore(flags);
 }
 
-/* Parse the boot-time nohz CPU list from the kernel parameters. */
-static int __init tick_nohz_full_setup(char *str)
+/* Get the boot-time nohz CPU list from the kernel parameters. */
+void __init tick_nohz_full_setup(cpumask_var_t cpumask)
 {
        alloc_bootmem_cpumask_var(&tick_nohz_full_mask);
-       if (cpulist_parse(str, tick_nohz_full_mask) < 0) {
-               pr_warn("NO_HZ: Incorrect nohz_full cpumask\n");
-               free_bootmem_cpumask_var(tick_nohz_full_mask);
-               return 1;
-       }
+       cpumask_copy(tick_nohz_full_mask, cpumask);
        tick_nohz_full_running = true;
-
-       return 1;
 }
-__setup("nohz_full=", tick_nohz_full_setup);
 
 static int tick_nohz_cpu_down(unsigned int cpu)
 {
@@ -437,13 +430,6 @@ void __init tick_nohz_init(void)
                        return;
        }
 
-       if (!alloc_cpumask_var(&housekeeping_mask, GFP_KERNEL)) {
-               WARN(1, "NO_HZ: Can't allocate not-full dynticks cpumask\n");
-               cpumask_clear(tick_nohz_full_mask);
-               tick_nohz_full_running = false;
-               return;
-       }
-
        /*
         * Full dynticks uses irq work to drive the tick rescheduling on safe
         * locking contexts. But then we need irq work to raise its own
@@ -452,7 +438,6 @@ void __init tick_nohz_init(void)
        if (!arch_irq_work_has_interrupt()) {
                pr_warn("NO_HZ: Can't run full dynticks because arch doesn't support irq work self-IPIs\n");
                cpumask_clear(tick_nohz_full_mask);
-               cpumask_copy(housekeeping_mask, cpu_possible_mask);
                tick_nohz_full_running = false;
                return;
        }
@@ -465,9 +450,6 @@ void __init tick_nohz_init(void)
                cpumask_clear_cpu(cpu, tick_nohz_full_mask);
        }
 
-       cpumask_andnot(housekeeping_mask,
-                      cpu_possible_mask, tick_nohz_full_mask);
-
        for_each_cpu(cpu, tick_nohz_full_mask)
                context_tracking_cpu_set(cpu);
 
@@ -477,12 +459,6 @@ void __init tick_nohz_init(void)
        WARN_ON(ret < 0);
        pr_info("NO_HZ: Full dynticks CPUs: %*pbl.\n",
                cpumask_pr_args(tick_nohz_full_mask));
-
-       /*
-        * We need at least one CPU to handle housekeeping work such
-        * as timekeeping, unbound timers, workqueues, ...
-        */
-       WARN_ON_ONCE(cpumask_empty(housekeeping_mask));
 }
 #endif
 
@@ -787,6 +763,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
        if (!ts->tick_stopped) {
                calc_load_nohz_start();
                cpu_load_update_nohz_start();
+               quiet_vmstat();
 
                ts->last_tick = hrtimer_get_expires(&ts->sched_timer);
                ts->tick_stopped = 1;
@@ -960,8 +937,7 @@ void tick_nohz_idle_enter(void)
 {
        struct tick_sched *ts;
 
-       WARN_ON_ONCE(irqs_disabled());
-
+       lockdep_assert_irqs_enabled();
        /*
         * Update the idle state in the scheduler domain hierarchy
         * when tick_nohz_stop_sched_tick() is called from the idle loop.
index 44a8c1402133be79d00fd6e66eb5825404277185..bd4e6c7dd6899d8320259856c8b99e5b98388fd1 100644 (file)
@@ -82,7 +82,7 @@ SYSCALL_DEFINE1(time, time_t __user *, tloc)
 
 SYSCALL_DEFINE1(stime, time_t __user *, tptr)
 {
-       struct timespec tv;
+       struct timespec64 tv;
        int err;
 
        if (get_user(tv.tv_sec, tptr))
@@ -90,11 +90,11 @@ SYSCALL_DEFINE1(stime, time_t __user *, tptr)
 
        tv.tv_nsec = 0;
 
-       err = security_settime(&tv, NULL);
+       err = security_settime64(&tv, NULL);
        if (err)
                return err;
 
-       do_settimeofday(&tv);
+       do_settimeofday64(&tv);
        return 0;
 }
 
@@ -122,7 +122,7 @@ COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc)
 
 COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr)
 {
-       struct timespec tv;
+       struct timespec64 tv;
        int err;
 
        if (get_user(tv.tv_sec, tptr))
@@ -130,11 +130,11 @@ COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr)
 
        tv.tv_nsec = 0;
 
-       err = security_settime(&tv, NULL);
+       err = security_settime64(&tv, NULL);
        if (err)
                return err;
 
-       do_settimeofday(&tv);
+       do_settimeofday64(&tv);
        return 0;
 }
 
@@ -157,40 +157,6 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
        return 0;
 }
 
-/*
- * Indicates if there is an offset between the system clock and the hardware
- * clock/persistent clock/rtc.
- */
-int persistent_clock_is_local;
-
-/*
- * Adjust the time obtained from the CMOS to be UTC time instead of
- * local time.
- *
- * This is ugly, but preferable to the alternatives.  Otherwise we
- * would either need to write a program to do it in /etc/rc (and risk
- * confusion if the program gets run more than once; it would also be
- * hard to make the program warp the clock precisely n hours)  or
- * compile in the timezone information into the kernel.  Bad, bad....
- *
- *                                             - TYT, 1992-01-01
- *
- * The best thing to do is to keep the CMOS clock in universal time (UTC)
- * as real UNIX machines always do it. This avoids all headaches about
- * daylight saving times and warping kernel clocks.
- */
-static inline void warp_clock(void)
-{
-       if (sys_tz.tz_minuteswest != 0) {
-               struct timespec adjust;
-
-               persistent_clock_is_local = 1;
-               adjust.tv_sec = sys_tz.tz_minuteswest * 60;
-               adjust.tv_nsec = 0;
-               timekeeping_inject_offset(&adjust);
-       }
-}
-
 /*
  * In case for some reason the CMOS clock has not already been running
  * in UTC, but in some local time: The first time we set the timezone,
@@ -224,7 +190,7 @@ int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz
                if (firsttime) {
                        firsttime = 0;
                        if (!tv)
-                               warp_clock();
+                               timekeeping_warp_clock();
                }
        }
        if (tv)
@@ -441,6 +407,7 @@ time64_t mktime64(const unsigned int year0, const unsigned int mon0,
 }
 EXPORT_SYMBOL(mktime64);
 
+#if __BITS_PER_LONG == 32
 /**
  * set_normalized_timespec - set timespec sec and nsec parts and normalize
  *
@@ -501,6 +468,7 @@ struct timespec ns_to_timespec(const s64 nsec)
        return ts;
 }
 EXPORT_SYMBOL(ns_to_timespec);
+#endif
 
 /**
  * ns_to_timeval - Convert nanoseconds to timeval
@@ -520,7 +488,6 @@ struct timeval ns_to_timeval(const s64 nsec)
 }
 EXPORT_SYMBOL(ns_to_timeval);
 
-#if BITS_PER_LONG == 32
 /**
  * set_normalized_timespec - set timespec sec and nsec parts and normalize
  *
@@ -581,7 +548,7 @@ struct timespec64 ns_to_timespec64(const s64 nsec)
        return ts;
 }
 EXPORT_SYMBOL(ns_to_timespec64);
-#endif
+
 /**
  * msecs_to_jiffies: - convert milliseconds to jiffies
  * @m: time in milliseconds
@@ -852,24 +819,6 @@ unsigned long nsecs_to_jiffies(u64 n)
 }
 EXPORT_SYMBOL_GPL(nsecs_to_jiffies);
 
-/*
- * Add two timespec values and do a safety check for overflow.
- * It's assumed that both values are valid (>= 0)
- */
-struct timespec timespec_add_safe(const struct timespec lhs,
-                                 const struct timespec rhs)
-{
-       struct timespec res;
-
-       set_normalized_timespec(&res, lhs.tv_sec + rhs.tv_sec,
-                               lhs.tv_nsec + rhs.tv_nsec);
-
-       if (res.tv_sec < lhs.tv_sec || res.tv_sec < rhs.tv_sec)
-               res.tv_sec = TIME_T_MAX;
-
-       return res;
-}
-
 /*
  * Add two timespec64 values and do a safety check for overflow.
  * It's assumed that both values are valid (>= 0).
index 2cafb49aa65e13b5b1d29223e8943d53386a795d..198afa78bf69e425b8cc1b0dfed538467df12bf7 100644 (file)
@@ -60,8 +60,27 @@ struct tk_fast {
        struct tk_read_base     base[2];
 };
 
-static struct tk_fast tk_fast_mono ____cacheline_aligned;
-static struct tk_fast tk_fast_raw  ____cacheline_aligned;
+/* Suspend-time cycles value for halted fast timekeeper. */
+static u64 cycles_at_suspend;
+
+static u64 dummy_clock_read(struct clocksource *cs)
+{
+       return cycles_at_suspend;
+}
+
+static struct clocksource dummy_clock = {
+       .read = dummy_clock_read,
+};
+
+static struct tk_fast tk_fast_mono ____cacheline_aligned = {
+       .base[0] = { .clock = &dummy_clock, },
+       .base[1] = { .clock = &dummy_clock, },
+};
+
+static struct tk_fast tk_fast_raw  ____cacheline_aligned = {
+       .base[0] = { .clock = &dummy_clock, },
+       .base[1] = { .clock = &dummy_clock, },
+};
 
 /* flag for if timekeeping is suspended */
 int __read_mostly timekeeping_suspended;
@@ -477,17 +496,39 @@ u64 notrace ktime_get_boot_fast_ns(void)
 }
 EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
 
-/* Suspend-time cycles value for halted fast timekeeper. */
-static u64 cycles_at_suspend;
 
-static u64 dummy_clock_read(struct clocksource *cs)
+/*
+ * See comment for __ktime_get_fast_ns() vs. timestamp ordering
+ */
+static __always_inline u64 __ktime_get_real_fast_ns(struct tk_fast *tkf)
 {
-       return cycles_at_suspend;
+       struct tk_read_base *tkr;
+       unsigned int seq;
+       u64 now;
+
+       do {
+               seq = raw_read_seqcount_latch(&tkf->seq);
+               tkr = tkf->base + (seq & 0x01);
+               now = ktime_to_ns(tkr->base_real);
+
+               now += timekeeping_delta_to_ns(tkr,
+                               clocksource_delta(
+                                       tk_clock_read(tkr),
+                                       tkr->cycle_last,
+                                       tkr->mask));
+       } while (read_seqcount_retry(&tkf->seq, seq));
+
+       return now;
 }
 
-static struct clocksource dummy_clock = {
-       .read = dummy_clock_read,
-};
+/**
+ * ktime_get_real_fast_ns: - NMI safe and fast access to clock realtime.
+ */
+u64 ktime_get_real_fast_ns(void)
+{
+       return __ktime_get_real_fast_ns(&tk_fast_mono);
+}
+EXPORT_SYMBOL_GPL(ktime_get_real_fast_ns);
 
 /**
  * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource.
@@ -507,6 +548,7 @@ static void halt_fast_timekeeper(struct timekeeper *tk)
        memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy));
        cycles_at_suspend = tk_clock_read(tkr);
        tkr_dummy.clock = &dummy_clock;
+       tkr_dummy.base_real = tkr->base + tk->offs_real;
        update_fast_timekeeper(&tkr_dummy, &tk_fast_mono);
 
        tkr = &tk->tkr_raw;
@@ -654,6 +696,7 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
        update_vsyscall(tk);
        update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET);
 
+       tk->tkr_mono.base_real = tk->tkr_mono.base + tk->offs_real;
        update_fast_timekeeper(&tk->tkr_mono, &tk_fast_mono);
        update_fast_timekeeper(&tk->tkr_raw,  &tk_fast_raw);
 
@@ -1264,33 +1307,31 @@ EXPORT_SYMBOL(do_settimeofday64);
  *
  * Adds or subtracts an offset value from the current time.
  */
-int timekeeping_inject_offset(struct timespec *ts)
+static int timekeeping_inject_offset(struct timespec64 *ts)
 {
        struct timekeeper *tk = &tk_core.timekeeper;
        unsigned long flags;
-       struct timespec64 ts64, tmp;
+       struct timespec64 tmp;
        int ret = 0;
 
-       if (!timespec_inject_offset_valid(ts))
+       if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
                return -EINVAL;
 
-       ts64 = timespec_to_timespec64(*ts);
-
        raw_spin_lock_irqsave(&timekeeper_lock, flags);
        write_seqcount_begin(&tk_core.seq);
 
        timekeeping_forward_now(tk);
 
        /* Make sure the proposed value is valid */
-       tmp = timespec64_add(tk_xtime(tk),  ts64);
-       if (timespec64_compare(&tk->wall_to_monotonic, &ts64) > 0 ||
+       tmp = timespec64_add(tk_xtime(tk), *ts);
+       if (timespec64_compare(&tk->wall_to_monotonic, ts) > 0 ||
            !timespec64_valid_strict(&tmp)) {
                ret = -EINVAL;
                goto error;
        }
 
-       tk_xtime_add(tk, &ts64);
-       tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts64));
+       tk_xtime_add(tk, ts);
+       tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, *ts));
 
 error: /* even if we error out, we forwarded the time, so call update */
        timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
@@ -1303,7 +1344,40 @@ error: /* even if we error out, we forwarded the time, so call update */
 
        return ret;
 }
-EXPORT_SYMBOL(timekeeping_inject_offset);
+
+/*
+ * Indicates if there is an offset between the system clock and the hardware
+ * clock/persistent clock/rtc.
+ */
+int persistent_clock_is_local;
+
+/*
+ * Adjust the time obtained from the CMOS to be UTC time instead of
+ * local time.
+ *
+ * This is ugly, but preferable to the alternatives.  Otherwise we
+ * would either need to write a program to do it in /etc/rc (and risk
+ * confusion if the program gets run more than once; it would also be
+ * hard to make the program warp the clock precisely n hours)  or
+ * compile in the timezone information into the kernel.  Bad, bad....
+ *
+ *                                             - TYT, 1992-01-01
+ *
+ * The best thing to do is to keep the CMOS clock in universal time (UTC)
+ * as real UNIX machines always do it. This avoids all headaches about
+ * daylight saving times and warping kernel clocks.
+ */
+void timekeeping_warp_clock(void)
+{
+       if (sys_tz.tz_minuteswest != 0) {
+               struct timespec64 adjust;
+
+               persistent_clock_is_local = 1;
+               adjust.tv_sec = sys_tz.tz_minuteswest * 60;
+               adjust.tv_nsec = 0;
+               timekeeping_inject_offset(&adjust);
+       }
+}
 
 /**
  * __timekeeping_set_tai_offset - Sets the TAI offset from UTC and monotonic
@@ -2247,6 +2321,72 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real,
        return base;
 }
 
+/**
+ * timekeeping_validate_timex - Ensures the timex is ok for use in do_adjtimex
+ */
+static int timekeeping_validate_timex(struct timex *txc)
+{
+       if (txc->modes & ADJ_ADJTIME) {
+               /* singleshot must not be used with any other mode bits */
+               if (!(txc->modes & ADJ_OFFSET_SINGLESHOT))
+                       return -EINVAL;
+               if (!(txc->modes & ADJ_OFFSET_READONLY) &&
+                   !capable(CAP_SYS_TIME))
+                       return -EPERM;
+       } else {
+               /* In order to modify anything, you gotta be super-user! */
+               if (txc->modes && !capable(CAP_SYS_TIME))
+                       return -EPERM;
+               /*
+                * if the quartz is off by more than 10% then
+                * something is VERY wrong!
+                */
+               if (txc->modes & ADJ_TICK &&
+                   (txc->tick <  900000/USER_HZ ||
+                    txc->tick > 1100000/USER_HZ))
+                       return -EINVAL;
+       }
+
+       if (txc->modes & ADJ_SETOFFSET) {
+               /* In order to inject time, you gotta be super-user! */
+               if (!capable(CAP_SYS_TIME))
+                       return -EPERM;
+
+               /*
+                * Validate if a timespec/timeval used to inject a time
+                * offset is valid.  Offsets can be postive or negative, so
+                * we don't check tv_sec. The value of the timeval/timespec
+                * is the sum of its fields,but *NOTE*:
+                * The field tv_usec/tv_nsec must always be non-negative and
+                * we can't have more nanoseconds/microseconds than a second.
+                */
+               if (txc->time.tv_usec < 0)
+                       return -EINVAL;
+
+               if (txc->modes & ADJ_NANO) {
+                       if (txc->time.tv_usec >= NSEC_PER_SEC)
+                               return -EINVAL;
+               } else {
+                       if (txc->time.tv_usec >= USEC_PER_SEC)
+                               return -EINVAL;
+               }
+       }
+
+       /*
+        * Check for potential multiplication overflows that can
+        * only happen on 64-bit systems:
+        */
+       if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) {
+               if (LLONG_MIN / PPM_SCALE > txc->freq)
+                       return -EINVAL;
+               if (LLONG_MAX / PPM_SCALE < txc->freq)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+
 /**
  * do_adjtimex() - Accessor function to NTP __do_adjtimex function
  */
@@ -2259,12 +2399,12 @@ int do_adjtimex(struct timex *txc)
        int ret;
 
        /* Validate the data before disabling interrupts */
-       ret = ntp_validate_timex(txc);
+       ret = timekeeping_validate_timex(txc);
        if (ret)
                return ret;
 
        if (txc->modes & ADJ_SETOFFSET) {
-               struct timespec delta;
+               struct timespec64 delta;
                delta.tv_sec  = txc->time.tv_sec;
                delta.tv_nsec = txc->time.tv_usec;
                if (!(txc->modes & ADJ_NANO))
index c9f9af33991498e29fbd49d677882f3ad9137cc7..7a9b4eb7a1d5bde85e7a7b1c7747602cdd605975 100644 (file)
@@ -11,7 +11,7 @@ extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq,
 
 extern int timekeeping_valid_for_hres(void);
 extern u64 timekeeping_max_deferment(void);
-extern int timekeeping_inject_offset(struct timespec *ts);
+extern void timekeeping_warp_clock(void);
 extern int timekeeping_suspend(void);
 extern void timekeeping_resume(void);
 
index f2674a056c268a58e0525194ea225fcd0bd9e1d5..af0b8bae45027042ff153172522b659fb605cf1d 100644 (file)
@@ -610,7 +610,7 @@ static bool timer_fixup_init(void *addr, enum debug_obj_state state)
 }
 
 /* Stub timer callback for improperly used timers. */
-static void stub_timer(unsigned long data)
+static void stub_timer(struct timer_list *unused)
 {
        WARN_ON(1);
 }
@@ -626,7 +626,7 @@ static bool timer_fixup_activate(void *addr, enum debug_obj_state state)
 
        switch (state) {
        case ODEBUG_STATE_NOTAVAILABLE:
-               setup_timer(timer, stub_timer, 0);
+               timer_setup(timer, stub_timer, 0);
                return true;
 
        case ODEBUG_STATE_ACTIVE:
@@ -665,7 +665,7 @@ static bool timer_fixup_assert_init(void *addr, enum debug_obj_state state)
 
        switch (state) {
        case ODEBUG_STATE_NOTAVAILABLE:
-               setup_timer(timer, stub_timer, 0);
+               timer_setup(timer, stub_timer, 0);
                return true;
        default:
                return false;
@@ -929,8 +929,11 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
        }
 }
 
+#define MOD_TIMER_PENDING_ONLY         0x01
+#define MOD_TIMER_REDUCE               0x02
+
 static inline int
-__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
+__mod_timer(struct timer_list *timer, unsigned long expires, unsigned int options)
 {
        struct timer_base *base, *new_base;
        unsigned int idx = UINT_MAX;
@@ -950,7 +953,11 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
                 * larger granularity than you would get from adding a new
                 * timer with this expiry.
                 */
-               if (timer->expires == expires)
+               long diff = timer->expires - expires;
+
+               if (!diff)
+                       return 1;
+               if (options & MOD_TIMER_REDUCE && diff <= 0)
                        return 1;
 
                /*
@@ -962,6 +969,12 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
                base = lock_timer_base(timer, &flags);
                forward_timer_base(base);
 
+               if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) &&
+                   time_before_eq(timer->expires, expires)) {
+                       ret = 1;
+                       goto out_unlock;
+               }
+
                clk = base->clk;
                idx = calc_wheel_index(expires, clk);
 
@@ -971,7 +984,10 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
                 * subsequent call will exit in the expires check above.
                 */
                if (idx == timer_get_idx(timer)) {
-                       timer->expires = expires;
+                       if (!(options & MOD_TIMER_REDUCE))
+                               timer->expires = expires;
+                       else if (time_after(timer->expires, expires))
+                               timer->expires = expires;
                        ret = 1;
                        goto out_unlock;
                }
@@ -981,7 +997,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
        }
 
        ret = detach_if_pending(timer, base, false);
-       if (!ret && pending_only)
+       if (!ret && (options & MOD_TIMER_PENDING_ONLY))
                goto out_unlock;
 
        debug_activate(timer, expires);
@@ -1042,7 +1058,7 @@ out_unlock:
  */
 int mod_timer_pending(struct timer_list *timer, unsigned long expires)
 {
-       return __mod_timer(timer, expires, true);
+       return __mod_timer(timer, expires, MOD_TIMER_PENDING_ONLY);
 }
 EXPORT_SYMBOL(mod_timer_pending);
 
@@ -1068,10 +1084,25 @@ EXPORT_SYMBOL(mod_timer_pending);
  */
 int mod_timer(struct timer_list *timer, unsigned long expires)
 {
-       return __mod_timer(timer, expires, false);
+       return __mod_timer(timer, expires, 0);
 }
 EXPORT_SYMBOL(mod_timer);
 
+/**
+ * timer_reduce - Modify a timer's timeout if it would reduce the timeout
+ * @timer:     The timer to be modified
+ * @expires:   New timeout in jiffies
+ *
+ * timer_reduce() is very similar to mod_timer(), except that it will only
+ * modify a running timer if that would reduce the expiration time (it will
+ * start a timer that isn't running).
+ */
+int timer_reduce(struct timer_list *timer, unsigned long expires)
+{
+       return __mod_timer(timer, expires, MOD_TIMER_REDUCE);
+}
+EXPORT_SYMBOL(timer_reduce);
+
 /**
  * add_timer - start a timer
  * @timer: the timer to be added
@@ -1560,8 +1591,11 @@ static int collect_expired_timers(struct timer_base *base,
                 * jiffies, otherwise forward to the next expiry time:
                 */
                if (time_after(next, jiffies)) {
-                       /* The call site will increment clock! */
-                       base->clk = jiffies - 1;
+                       /*
+                        * The call site will increment base->clk and then
+                        * terminate the expiry loop immediately.
+                        */
+                       base->clk = jiffies;
                        return 0;
                }
                base->clk = next;
@@ -1668,9 +1702,20 @@ void run_local_timers(void)
        raise_softirq(TIMER_SOFTIRQ);
 }
 
-static void process_timeout(unsigned long __data)
+/*
+ * Since schedule_timeout()'s timer is defined on the stack, it must store
+ * the target task on the stack as well.
+ */
+struct process_timer {
+       struct timer_list timer;
+       struct task_struct *task;
+};
+
+static void process_timeout(struct timer_list *t)
 {
-       wake_up_process((struct task_struct *)__data);
+       struct process_timer *timeout = from_timer(timeout, t, timer);
+
+       wake_up_process(timeout->task);
 }
 
 /**
@@ -1704,7 +1749,7 @@ static void process_timeout(unsigned long __data)
  */
 signed long __sched schedule_timeout(signed long timeout)
 {
-       struct timer_list timer;
+       struct process_timer timer;
        unsigned long expire;
 
        switch (timeout)
@@ -1738,13 +1783,14 @@ signed long __sched schedule_timeout(signed long timeout)
 
        expire = timeout + jiffies;
 
-       setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
-       __mod_timer(&timer, expire, false);
+       timer.task = current;
+       timer_setup_on_stack(&timer.timer, process_timeout, 0);
+       __mod_timer(&timer.timer, expire, 0);
        schedule();
-       del_singleshot_timer_sync(&timer);
+       del_singleshot_timer_sync(&timer.timer);
 
        /* Remove the timer from the object tracker */
-       destroy_timer_on_stack(&timer);
+       destroy_timer_on_stack(&timer.timer);
 
        timeout = expire - jiffies;
 
index dc498b605d5dd36137eaba7bd0ee93da72a36c33..95888ae6c2634b9e126000cbd009a7f5825b1309 100644 (file)
@@ -275,7 +275,7 @@ BPF_CALL_2(bpf_perf_event_read, struct bpf_map *, map, u64, flags)
        if (!ee)
                return -ENOENT;
 
-       err = perf_event_read_local(ee->event, &value);
+       err = perf_event_read_local(ee->event, &value, NULL, NULL);
        /*
         * this api is ugly since we miss [-22..-2] range of valid
         * counter values, but that's uapi
index 81279c6602ff1753d8c38c8def566c3576578962..845f3805c73d72cccaf844afcd5a5bc0f3337ebb 100644 (file)
@@ -2724,7 +2724,7 @@ rb_reserve_next_event(struct ring_buffer *buffer,
         * if it happened, we have to fail the write.
         */
        barrier();
-       if (unlikely(ACCESS_ONCE(cpu_buffer->buffer) != buffer)) {
+       if (unlikely(READ_ONCE(cpu_buffer->buffer) != buffer)) {
                local_dec(&cpu_buffer->committing);
                local_dec(&cpu_buffer->commits);
                return NULL;
index 401b0639116f216c78b3dad0ad663c9e74858d52..6b0b343a36a278be32a89e91e95066e84020c620 100644 (file)
@@ -1460,7 +1460,7 @@ extern struct trace_event_file *find_event_file(struct trace_array *tr,
 
 static inline void *event_file_data(struct file *filp)
 {
-       return ACCESS_ONCE(file_inode(filp)->i_private);
+       return READ_ONCE(file_inode(filp)->i_private);
 }
 
 extern struct mutex event_mutex;
index c738e764e2a55cfd3303a3262d748c94a917a86d..90db994ac9004d2fc7163eeb95b8c79e121e991a 100644 (file)
@@ -921,8 +921,8 @@ static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
 
        trace_assign_type(field, iter->ent);
 
-       T = __task_state_to_char(field->next_state);
-       S = __task_state_to_char(field->prev_state);
+       T = task_index_to_char(field->next_state);
+       S = task_index_to_char(field->prev_state);
        trace_find_cmdline(field->next_pid, comm);
        trace_seq_printf(&iter->seq,
                         " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
@@ -957,8 +957,8 @@ static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
        trace_assign_type(field, iter->ent);
 
        if (!S)
-               S = __task_state_to_char(field->prev_state);
-       T = __task_state_to_char(field->next_state);
+               S = task_index_to_char(field->prev_state);
+       T = task_index_to_char(field->next_state);
        trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n",
                         field->prev_pid,
                         field->prev_prio,
@@ -993,8 +993,8 @@ static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
        trace_assign_type(field, iter->ent);
 
        if (!S)
-               S = __task_state_to_char(field->prev_state);
-       T = __task_state_to_char(field->next_state);
+               S = task_index_to_char(field->prev_state);
+       T = task_index_to_char(field->next_state);
 
        SEQ_PUT_HEX_FIELD(s, field->prev_pid);
        SEQ_PUT_HEX_FIELD(s, field->prev_prio);
index 7d461dcd48318b8c2fd7898d4680f07a068d482d..a86b303e6c67dc7e1561636ddf52a9c8136fe65f 100644 (file)
@@ -398,10 +398,10 @@ tracing_sched_switch_trace(struct trace_array *tr,
        entry   = ring_buffer_event_data(event);
        entry->prev_pid                 = prev->pid;
        entry->prev_prio                = prev->prio;
-       entry->prev_state               = __get_task_state(prev);
+       entry->prev_state               = task_state_index(prev);
        entry->next_pid                 = next->pid;
        entry->next_prio                = next->prio;
-       entry->next_state               = __get_task_state(next);
+       entry->next_state               = task_state_index(next);
        entry->next_cpu = task_cpu(next);
 
        if (!call_filter_check_discard(call, entry, buffer, event))
@@ -426,10 +426,10 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
        entry   = ring_buffer_event_data(event);
        entry->prev_pid                 = curr->pid;
        entry->prev_prio                = curr->prio;
-       entry->prev_state               = __get_task_state(curr);
+       entry->prev_state               = task_state_index(curr);
        entry->next_pid                 = wakee->pid;
        entry->next_prio                = wakee->prio;
-       entry->next_state               = __get_task_state(wakee);
+       entry->next_state               = task_state_index(wakee);
        entry->next_cpu                 = task_cpu(wakee);
 
        if (!call_filter_check_discard(call, entry, buffer, event))
index 719a52a4064a0f6472ab7e662d00c47b6dd5993d..734accc02418930280a5248013fa6fbd4a5868e2 100644 (file)
@@ -78,7 +78,7 @@ check_stack(unsigned long ip, unsigned long *stack)
 {
        unsigned long this_size, flags; unsigned long *p, *top, *start;
        static int tracer_frame;
-       int frame_size = ACCESS_ONCE(tracer_frame);
+       int frame_size = READ_ONCE(tracer_frame);
        int i, x;
 
        this_size = ((unsigned long)stack) & (THREAD_SIZE-1);
index c490f1e4313b998a60686b98fbdf6b0167753e11..d32b45662fb66828cc907ea42ea4c9ede8a1ef0c 100644 (file)
@@ -894,7 +894,7 @@ static bool new_idmap_permitted(const struct file *file,
 int proc_setgroups_show(struct seq_file *seq, void *v)
 {
        struct user_namespace *ns = seq->private;
-       unsigned long userns_flags = ACCESS_ONCE(ns->flags);
+       unsigned long userns_flags = READ_ONCE(ns->flags);
 
        seq_printf(seq, "%s\n",
                   (userns_flags & USERNS_SETGROUPS_ALLOWED) ?
index c8e06703e44c2ce1604aab569d1a9cd4b7faf823..576d1804581150d1479730166910ff6fb0a89d2e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/workqueue.h>
 #include <linux/sched/clock.h>
 #include <linux/sched/debug.h>
+#include <linux/sched/isolation.h>
 
 #include <asm/irq_regs.h>
 #include <linux/kvm_para.h>
@@ -774,15 +775,11 @@ int proc_watchdog_cpumask(struct ctl_table *table, int write,
 
 void __init lockup_detector_init(void)
 {
-#ifdef CONFIG_NO_HZ_FULL
-       if (tick_nohz_full_enabled()) {
+       if (tick_nohz_full_enabled())
                pr_info("Disabling watchdog on nohz_full cores by default\n");
-               cpumask_copy(&watchdog_cpumask, housekeeping_mask);
-       } else
-               cpumask_copy(&watchdog_cpumask, cpu_possible_mask);
-#else
-       cpumask_copy(&watchdog_cpumask, cpu_possible_mask);
-#endif
+
+       cpumask_copy(&watchdog_cpumask,
+                    housekeeping_cpumask(HK_FLAG_TIMER));
 
        if (!watchdog_nmi_probe())
                nmi_watchdog_available = true;
index a2dccfe1acec34bbda97a292344b997055e56d9a..7368b57842ea349ca0c1183f6999ec7f16e6c647 100644 (file)
@@ -1376,7 +1376,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
         * queued or lose PENDING.  Grabbing PENDING and queueing should
         * happen with IRQ disabled.
         */
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        debug_work_activate(work);
 
@@ -1493,9 +1493,9 @@ bool queue_work_on(int cpu, struct workqueue_struct *wq,
 }
 EXPORT_SYMBOL(queue_work_on);
 
-void delayed_work_timer_fn(unsigned long __data)
+void delayed_work_timer_fn(struct timer_list *t)
 {
-       struct delayed_work *dwork = (struct delayed_work *)__data;
+       struct delayed_work *dwork = from_timer(dwork, t, timer);
 
        /* should have been called from irqsafe timer with irq already off */
        __queue_work(dwork->cpu, dwork->wq, &dwork->work);
@@ -1509,8 +1509,7 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq,
        struct work_struct *work = &dwork->work;
 
        WARN_ON_ONCE(!wq);
-       WARN_ON_ONCE(timer->function != delayed_work_timer_fn ||
-                    timer->data != (unsigned long)dwork);
+       WARN_ON_ONCE(timer->function != (TIMER_FUNC_TYPE)delayed_work_timer_fn);
        WARN_ON_ONCE(timer_pending(timer));
        WARN_ON_ONCE(!list_empty(&work->entry));
 
@@ -1833,9 +1832,9 @@ static void destroy_worker(struct worker *worker)
        wake_up_process(worker->task);
 }
 
-static void idle_worker_timeout(unsigned long __pool)
+static void idle_worker_timeout(struct timer_list *t)
 {
-       struct worker_pool *pool = (void *)__pool;
+       struct worker_pool *pool = from_timer(pool, t, idle_timer);
 
        spin_lock_irq(&pool->lock);
 
@@ -1881,9 +1880,9 @@ static void send_mayday(struct work_struct *work)
        }
 }
 
-static void pool_mayday_timeout(unsigned long __pool)
+static void pool_mayday_timeout(struct timer_list *t)
 {
-       struct worker_pool *pool = (void *)__pool;
+       struct worker_pool *pool = from_timer(pool, t, mayday_timer);
        struct work_struct *work;
 
        spin_lock_irq(&pool->lock);
@@ -2491,15 +2490,8 @@ static void insert_wq_barrier(struct pool_workqueue *pwq,
        INIT_WORK_ONSTACK(&barr->work, wq_barrier_func);
        __set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&barr->work));
 
-       /*
-        * Explicitly init the crosslock for wq_barrier::done, make its lock
-        * key a subkey of the corresponding work. As a result we won't
-        * build a dependency between wq_barrier::done and unrelated work.
-        */
-       lockdep_init_map_crosslock((struct lockdep_map *)&barr->done.map,
-                                  "(complete)wq_barr::done",
-                                  target->lockdep_map.key, 1);
-       __init_completion(&barr->done);
+       init_completion_map(&barr->done, &target->lockdep_map);
+
        barr->task = current;
 
        /*
@@ -2605,16 +2597,13 @@ void flush_workqueue(struct workqueue_struct *wq)
        struct wq_flusher this_flusher = {
                .list = LIST_HEAD_INIT(this_flusher.list),
                .flush_color = -1,
-               .done = COMPLETION_INITIALIZER_ONSTACK(this_flusher.done),
+               .done = COMPLETION_INITIALIZER_ONSTACK_MAP(this_flusher.done, wq->lockdep_map),
        };
        int next_color;
 
        if (WARN_ON(!wq_online))
                return;
 
-       lock_map_acquire(&wq->lockdep_map);
-       lock_map_release(&wq->lockdep_map);
-
        mutex_lock(&wq->mutex);
 
        /*
@@ -2877,9 +2866,6 @@ bool flush_work(struct work_struct *work)
        if (WARN_ON(!wq_online))
                return false;
 
-       lock_map_acquire(&work->lockdep_map);
-       lock_map_release(&work->lockdep_map);
-
        if (start_flush_work(work, &barr)) {
                wait_for_completion(&barr.done);
                destroy_work_on_stack(&barr.work);
@@ -3236,11 +3222,9 @@ static int init_worker_pool(struct worker_pool *pool)
        INIT_LIST_HEAD(&pool->idle_list);
        hash_init(pool->busy_hash);
 
-       setup_deferrable_timer(&pool->idle_timer, idle_worker_timeout,
-                              (unsigned long)pool);
+       timer_setup(&pool->idle_timer, idle_worker_timeout, TIMER_DEFERRABLE);
 
-       setup_timer(&pool->mayday_timer, pool_mayday_timeout,
-                   (unsigned long)pool);
+       timer_setup(&pool->mayday_timer, pool_mayday_timeout, 0);
 
        mutex_init(&pool->attach_mutex);
        INIT_LIST_HEAD(&pool->workers);
@@ -4640,7 +4624,7 @@ static void rebind_workers(struct worker_pool *pool)
                 * concurrency management.  Note that when or whether
                 * @worker clears REBOUND doesn't affect correctness.
                 *
-                * ACCESS_ONCE() is necessary because @worker->flags may be
+                * WRITE_ONCE() is necessary because @worker->flags may be
                 * tested without holding any lock in
                 * wq_worker_waking_up().  Without it, NOT_RUNNING test may
                 * fail incorrectly leading to premature concurrency
@@ -4649,7 +4633,7 @@ static void rebind_workers(struct worker_pool *pool)
                WARN_ON_ONCE(!(worker_flags & WORKER_UNBOUND));
                worker_flags |= WORKER_REBOUND;
                worker_flags &= ~WORKER_UNBOUND;
-               ACCESS_ONCE(worker->flags) = worker_flags;
+               WRITE_ONCE(worker->flags, worker_flags);
        }
 
        spin_unlock_irq(&pool->lock);
@@ -5383,11 +5367,8 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq)      { }
  */
 #ifdef CONFIG_WQ_WATCHDOG
 
-static void wq_watchdog_timer_fn(unsigned long data);
-
 static unsigned long wq_watchdog_thresh = 30;
-static struct timer_list wq_watchdog_timer =
-       TIMER_DEFERRED_INITIALIZER(wq_watchdog_timer_fn, 0, 0);
+static struct timer_list wq_watchdog_timer;
 
 static unsigned long wq_watchdog_touched = INITIAL_JIFFIES;
 static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES;
@@ -5401,7 +5382,7 @@ static void wq_watchdog_reset_touched(void)
                per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;
 }
 
-static void wq_watchdog_timer_fn(unsigned long data)
+static void wq_watchdog_timer_fn(struct timer_list *unused)
 {
        unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ;
        bool lockup_detected = false;
@@ -5503,6 +5484,7 @@ module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh,
 
 static void wq_watchdog_init(void)
 {
+       timer_setup(&wq_watchdog_timer, wq_watchdog_timer_fn, TIMER_DEFERRABLE);
        wq_watchdog_set_thresh(wq_watchdog_thresh);
 }
 
index efdd72e15794eb2fca6afbbe28612d1fdd3288d6..d390d1be37489f37bd8ac42826a12782a4ca99dc 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
+#include <linux/preempt.h>
 
 struct worker_pool;
 
@@ -60,7 +61,7 @@ struct worker {
  */
 static inline struct worker *current_wq_worker(void)
 {
-       if (current->flags & PF_WQ_WORKER)
+       if (in_task() && (current->flags & PF_WQ_WORKER))
                return kthread_data(current);
        return NULL;
 }
index dfdad67d8f6cce470171986addcad7b61c09f382..07ce7449765a499b99c4d1982c8b41f2e01e111e 100644 (file)
@@ -376,7 +376,7 @@ config STACK_VALIDATION
          that runtime stack traces are more reliable.
 
          This is also a prerequisite for generation of ORC unwind data, which
-         is needed for CONFIG_ORC_UNWINDER.
+         is needed for CONFIG_UNWINDER_ORC.
 
          For more information, see
          tools/objtool/Documentation/stack-validation.txt.
@@ -1092,8 +1092,8 @@ config PROVE_LOCKING
        select DEBUG_MUTEXES
        select DEBUG_RT_MUTEXES if RT_MUTEXES
        select DEBUG_LOCK_ALLOC
-       select LOCKDEP_CROSSRELEASE if BROKEN
-       select LOCKDEP_COMPLETIONS if BROKEN
+       select LOCKDEP_CROSSRELEASE
+       select LOCKDEP_COMPLETIONS
        select TRACE_IRQFLAGS
        default n
        help
@@ -1179,6 +1179,21 @@ config LOCKDEP_COMPLETIONS
         A deadlock caused by wait_for_completion() and complete() can be
         detected by lockdep using crossrelease feature.
 
+config BOOTPARAM_LOCKDEP_CROSSRELEASE_FULLSTACK
+       bool "Enable the boot parameter, crossrelease_fullstack"
+       depends on LOCKDEP_CROSSRELEASE
+       default n
+       help
+        The lockdep "cross-release" feature needs to record stack traces
+        (of calling functions) for all acquisitions, for eventual later
+        use during analysis. By default only a single caller is recorded,
+        because the unwind operation can be very expensive with deeper
+        stack chains.
+
+        However a boot parameter, crossrelease_fullstack, was
+        introduced since sometimes deeper traces are required for full
+        analysis. This option turns on the boot parameter.
+
 config DEBUG_LOCKDEP
        bool "Lock dependency engine debugging"
        depends on DEBUG_KERNEL && LOCKDEP
index fef5d2e114be1eef73b78653ce84a915da3e59d3..1ef0cec38d7879332966f8095d0bfdc0c7580230 100644 (file)
@@ -228,7 +228,7 @@ next_op:
                hdr = 2;
 
                /* Extract a tag from the data */
-               if (unlikely(dp >= datalen - 1))
+               if (unlikely(datalen - dp < 2))
                        goto data_overrun_error;
                tag = data[dp++];
                if (unlikely((tag & 0x1f) == ASN1_LONG_TAG))
@@ -274,7 +274,7 @@ next_op:
                                int n = len - 0x80;
                                if (unlikely(n > 2))
                                        goto length_too_long;
-                               if (unlikely(dp >= datalen - n))
+                               if (unlikely(n > datalen - dp))
                                        goto data_overrun_error;
                                hdr += n;
                                for (len = 0; n > 0; n--) {
index 4e53be8bc590dc2030a930aec5a2cac8c4fa6a30..b77d51da8c73def55d1aea5ca6c34161652981a0 100644 (file)
@@ -39,7 +39,7 @@ begin_node:
                /* Descend through a shortcut */
                shortcut = assoc_array_ptr_to_shortcut(cursor);
                smp_read_barrier_depends();
-               cursor = ACCESS_ONCE(shortcut->next_node);
+               cursor = READ_ONCE(shortcut->next_node);
        }
 
        node = assoc_array_ptr_to_node(cursor);
@@ -55,7 +55,7 @@ begin_node:
         */
        has_meta = 0;
        for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
-               ptr = ACCESS_ONCE(node->slots[slot]);
+               ptr = READ_ONCE(node->slots[slot]);
                has_meta |= (unsigned long)ptr;
                if (ptr && assoc_array_ptr_is_leaf(ptr)) {
                        /* We need a barrier between the read of the pointer
@@ -89,7 +89,7 @@ continue_node:
        smp_read_barrier_depends();
 
        for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
-               ptr = ACCESS_ONCE(node->slots[slot]);
+               ptr = READ_ONCE(node->slots[slot]);
                if (assoc_array_ptr_is_meta(ptr)) {
                        cursor = ptr;
                        goto begin_node;
@@ -98,7 +98,7 @@ continue_node:
 
 finished_node:
        /* Move up to the parent (may need to skip back over a shortcut) */
-       parent = ACCESS_ONCE(node->back_pointer);
+       parent = READ_ONCE(node->back_pointer);
        slot = node->parent_slot;
        if (parent == stop)
                return 0;
@@ -107,7 +107,7 @@ finished_node:
                shortcut = assoc_array_ptr_to_shortcut(parent);
                smp_read_barrier_depends();
                cursor = parent;
-               parent = ACCESS_ONCE(shortcut->back_pointer);
+               parent = READ_ONCE(shortcut->back_pointer);
                slot = shortcut->parent_slot;
                if (parent == stop)
                        return 0;
@@ -147,7 +147,7 @@ int assoc_array_iterate(const struct assoc_array *array,
                                        void *iterator_data),
                        void *iterator_data)
 {
-       struct assoc_array_ptr *root = ACCESS_ONCE(array->root);
+       struct assoc_array_ptr *root = READ_ONCE(array->root);
 
        if (!root)
                return 0;
@@ -194,7 +194,7 @@ assoc_array_walk(const struct assoc_array *array,
 
        pr_devel("-->%s()\n", __func__);
 
-       cursor = ACCESS_ONCE(array->root);
+       cursor = READ_ONCE(array->root);
        if (!cursor)
                return assoc_array_walk_tree_empty;
 
@@ -220,7 +220,7 @@ consider_node:
 
        slot = segments >> (level & ASSOC_ARRAY_KEY_CHUNK_MASK);
        slot &= ASSOC_ARRAY_FAN_MASK;
-       ptr = ACCESS_ONCE(node->slots[slot]);
+       ptr = READ_ONCE(node->slots[slot]);
 
        pr_devel("consider slot %x [ix=%d type=%lu]\n",
                 slot, level, (unsigned long)ptr & 3);
@@ -294,7 +294,7 @@ follow_shortcut:
        } while (sc_level < shortcut->skip_to_level);
 
        /* The shortcut matches the leaf's index to this point. */
-       cursor = ACCESS_ONCE(shortcut->next_node);
+       cursor = READ_ONCE(shortcut->next_node);
        if (((level ^ sc_level) & ~ASSOC_ARRAY_KEY_CHUNK_MASK) != 0) {
                level = sc_level;
                goto jumped;
@@ -337,7 +337,7 @@ void *assoc_array_find(const struct assoc_array *array,
         * the terminal node.
         */
        for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
-               ptr = ACCESS_ONCE(node->slots[slot]);
+               ptr = READ_ONCE(node->slots[slot]);
                if (ptr && assoc_array_ptr_is_leaf(ptr)) {
                        /* We need a barrier between the read of the pointer
                         * and dereferencing the pointer - but only if we are
index c82c61b66e166b521ff91d4e6055905d7431e6dc..d8f0c094b18eba130571a3e405796040750d9646 100644 (file)
@@ -18,7 +18,9 @@
 
 #include <asm/page.h>
 
-/*
+/**
+ * DOC: bitmap introduction
+ *
  * bitmaps provide an array of bits, implemented using an an
  * array of unsigned longs.  The number of valid bits in a
  * given bitmap does _not_ need to be an exact multiple of
index 6ddc92bc1460936f170e17e4f5b6fc633d11784a..2ef20fe84b69056b345467f1dd17b3d9c705c1b0 100644 (file)
@@ -225,7 +225,7 @@ static u32 __attribute_const__ gf2_multiply(u32 x, u32 y, u32 modulus)
 }
 
 /**
- * crc32_generic_shift - Append len 0 bytes to crc, in logarithmic time
+ * crc32_generic_shift - Append @len 0 bytes to crc, in logarithmic time
  * @crc: The original little-endian CRC (i.e. lsbit is x^31 coefficient)
  * @len: The number of bytes. @crc is multiplied by x^(8*@len)
  * @polynomial: The modulus used to reduce the result to 32 bits.
index cf6db46661bec611afe45220b584c339944dac2f..164ed9444cd3d83f3574212a404a6d62a7011586 100644 (file)
@@ -15,7 +15,7 @@ static const uint8_t crc4_tab[] = {
 
 /**
  * crc4 - calculate the 4-bit crc of a value.
- * @crc:  starting crc4
+ * @c:    starting crc4
  * @x:    value to checksum
  * @bits: number of bits in @x to checksum
  *
index 87b59cafdb8390e6cbcdd4815efd7301207b824b..595a5a75e3cd60c953f06a5f61c3a461db87f534 100644 (file)
 #include <linux/crc8.h>
 #include <linux/printk.h>
 
-/*
+/**
  * crc8_populate_msb - fill crc table for given polynomial in reverse bit order.
  *
- * table:      table to be filled.
- * polynomial: polynomial for which table is to be filled.
+ * @table:     table to be filled.
+ * @polynomial:        polynomial for which table is to be filled.
  */
 void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
 {
@@ -42,11 +42,11 @@ void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
 }
 EXPORT_SYMBOL(crc8_populate_msb);
 
-/*
+/**
  * crc8_populate_lsb - fill crc table for given polynomial in regular bit order.
  *
- * table:      table to be filled.
- * polynomial: polynomial for which table is to be filled.
+ * @table:     table to be filled.
+ * @polynomial:        polynomial for which table is to be filled.
  */
 void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
 {
@@ -63,13 +63,13 @@ void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
 }
 EXPORT_SYMBOL(crc8_populate_lsb);
 
-/*
+/**
  * crc8 - calculate a crc8 over the given input data.
  *
- * table: crc table used for calculation.
- * pdata: pointer to data buffer.
- * nbytes: number of bytes in data buffer.
- * crc:        previous returned crc8 value.
+ * @table: crc table used for calculation.
+ * @pdata: pointer to data buffer.
+ * @nbytes: number of bytes in data buffer.
+ * @crc: previous returned crc8 value.
  */
 u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc)
 {
index 58e2a404097e9f5a47269138dcb843d1a39084a8..01c8602bb6ffb9250e5a24b6c6866e47c440da51 100644 (file)
@@ -61,6 +61,12 @@ uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
 EXPORT_SYMBOL(__div64_32);
 #endif
 
+/**
+ * div_s64_rem - signed 64bit divide with 64bit divisor and remainder
+ * @dividend:  64bit dividend
+ * @divisor:   64bit divisor
+ * @remainder:  64bit remainder
+ */
 #ifndef div_s64_rem
 s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
 {
index 6a406fafb5d611771fd6db769efd584719a0ebc6..da4672a50a54a2046bb86479c57dc11552a1981c 100644 (file)
@@ -21,7 +21,7 @@ void dql_completed(struct dql *dql, unsigned int count)
        unsigned int ovlimit, completed, num_queued;
        bool all_prev_completed;
 
-       num_queued = ACCESS_ONCE(dql->num_queued);
+       num_queued = READ_ONCE(dql->num_queued);
 
        /* Can't complete more than what's in queue */
        BUG_ON(count > num_queued - dql->num_completed);
index 135ee6407a5e4f0a6f7fc8da85f38a74ea37ed38..227dea9244257b014c36c54fb0768a961a5f5dcb 100644 (file)
--- a/lib/gcd.c
+++ b/lib/gcd.c
 #if !defined(CONFIG_CPU_NO_EFFICIENT_FFS) && !defined(CPU_NO_EFFICIENT_FFS)
 
 /* If __ffs is available, the even/odd algorithm benchmarks slower. */
+
+/**
+ * gcd - calculate and return the greatest common divisor of 2 unsigned longs
+ * @a: first value
+ * @b: second value
+ */
 unsigned long gcd(unsigned long a, unsigned long b)
 {
        unsigned long r = a | b;
index ae5872b1df0c669fc8365ce1754d2a128651a890..7062e931a7bb4e8f2fb2937e065e6e062f049b2a 100644 (file)
@@ -41,7 +41,7 @@ bool llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
        struct llist_node *first;
 
        do {
-               new_last->next = first = ACCESS_ONCE(head->first);
+               new_last->next = first = READ_ONCE(head->first);
        } while (cmpxchg(&head->first, first, new_first) != first);
 
        return !first;
index 0a90cb0e0fb65f8480c398a7d2e0b42d1c6ef885..65cc018fef40d714272fb2e7948084e4082fe499 100644 (file)
@@ -215,7 +215,7 @@ core_initcall(prandom_init);
 
 static void __prandom_timer(unsigned long dontcare);
 
-static DEFINE_TIMER(seed_timer, __prandom_timer, 0, 0);
+static DEFINE_TIMER(seed_timer, __prandom_timer);
 
 static void __prandom_timer(unsigned long dontcare)
 {
index 8c6c83ef57a43336e0a33a52f691e3323eb8f3f4..cea19aaf303c9f3c558dd8246205ed39f38dcc46 100644 (file)
@@ -507,8 +507,9 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
        if (no_iotlb_memory)
                panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer");
 
-       if (sme_active())
-               pr_warn_once("SME is active and system is using DMA bounce buffers\n");
+       if (mem_encrypt_active())
+               pr_warn_once("%s is active and system is using DMA bounce buffers\n",
+                            sme_active() ? "SME" : "SEV");
 
        mask = dma_get_seg_boundary(hwdev);
 
index 86c3385b9eb393a54b09cddcfcccef3ec257f8d2..1746bae94d416f6ce3311c569e5d99080173f998 100644 (file)
@@ -620,8 +620,8 @@ char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_sp
 
        rcu_read_lock();
        for (i = 0; i < depth; i++, d = p) {
-               p = ACCESS_ONCE(d->d_parent);
-               array[i] = ACCESS_ONCE(d->d_name.name);
+               p = READ_ONCE(d->d_parent);
+               array[i] = READ_ONCE(d->d_name.name);
                if (p == d) {
                        if (i)
                                array[i] = "";
index b2b4d4263768d82d61b99d2a2125251345fa778c..dfcde13f289a76ddcb54919f900467aeab15609d 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1643,6 +1643,47 @@ static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end,
        return 1;
 }
 
+static void gup_pgd_range(unsigned long addr, unsigned long end,
+               int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pgd_t *pgdp;
+
+       pgdp = pgd_offset(current->mm, addr);
+       do {
+               pgd_t pgd = READ_ONCE(*pgdp);
+
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       return;
+               if (unlikely(pgd_huge(pgd))) {
+                       if (!gup_huge_pgd(pgd, pgdp, addr, next, write,
+                                         pages, nr))
+                               return;
+               } else if (unlikely(is_hugepd(__hugepd(pgd_val(pgd))))) {
+                       if (!gup_huge_pd(__hugepd(pgd_val(pgd)), addr,
+                                        PGDIR_SHIFT, next, write, pages, nr))
+                               return;
+               } else if (!gup_p4d_range(pgd, addr, next, write, pages, nr))
+                       return;
+       } while (pgdp++, addr = next, addr != end);
+}
+
+#ifndef gup_fast_permitted
+/*
+ * Check if it's allowed to use __get_user_pages_fast() for the range, or
+ * we need to fall back to the slow version:
+ */
+bool gup_fast_permitted(unsigned long start, int nr_pages, int write)
+{
+       unsigned long len, end;
+
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+       end = start + len;
+       return end >= start;
+}
+#endif
+
 /*
  * Like get_user_pages_fast() except it's IRQ-safe in that it won't fall back to
  * the regular GUP. It will only return non-negative values.
@@ -1650,10 +1691,8 @@ static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end,
 int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
                          struct page **pages)
 {
-       struct mm_struct *mm = current->mm;
        unsigned long addr, len, end;
-       unsigned long next, flags;
-       pgd_t *pgdp;
+       unsigned long flags;
        int nr = 0;
 
        start &= PAGE_MASK;
@@ -1677,45 +1716,15 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
         * block IPIs that come from THPs splitting.
         */
 
-       local_irq_save(flags);
-       pgdp = pgd_offset(mm, addr);
-       do {
-               pgd_t pgd = READ_ONCE(*pgdp);
-
-               next = pgd_addr_end(addr, end);
-               if (pgd_none(pgd))
-                       break;
-               if (unlikely(pgd_huge(pgd))) {
-                       if (!gup_huge_pgd(pgd, pgdp, addr, next, write,
-                                         pages, &nr))
-                               break;
-               } else if (unlikely(is_hugepd(__hugepd(pgd_val(pgd))))) {
-                       if (!gup_huge_pd(__hugepd(pgd_val(pgd)), addr,
-                                        PGDIR_SHIFT, next, write, pages, &nr))
-                               break;
-               } else if (!gup_p4d_range(pgd, addr, next, write, pages, &nr))
-                       break;
-       } while (pgdp++, addr = next, addr != end);
-       local_irq_restore(flags);
+       if (gup_fast_permitted(start, nr_pages, write)) {
+               local_irq_save(flags);
+               gup_pgd_range(addr, end, write, pages, &nr);
+               local_irq_restore(flags);
+       }
 
        return nr;
 }
 
-#ifndef gup_fast_permitted
-/*
- * Check if it's allowed to use __get_user_pages_fast() for the range, or
- * we need to fall back to the slow version:
- */
-bool gup_fast_permitted(unsigned long start, int nr_pages, int write)
-{
-       unsigned long len, end;
-
-       len = (unsigned long) nr_pages << PAGE_SHIFT;
-       end = start + len;
-       return end >= start;
-}
-#endif
-
 /**
  * get_user_pages_fast() - pin user pages in memory
  * @start:     starting user address
@@ -1735,12 +1744,22 @@ bool gup_fast_permitted(unsigned long start, int nr_pages, int write)
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                        struct page **pages)
 {
+       unsigned long addr, len, end;
        int nr = 0, ret = 0;
 
        start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+       end = start + len;
+
+       if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+                                       (void __user *)start, len)))
+               return 0;
 
        if (gup_fast_permitted(start, nr_pages, write)) {
-               nr = __get_user_pages_fast(start, nr_pages, write, pages);
+               local_irq_disable();
+               gup_pgd_range(addr, end, write, pages, &nr);
+               local_irq_enable();
                ret = nr;
        }
 
index 1981ed697dabb530b56c9e6b84d9f569428b101c..b521ed1170f967d37adac445eff57a394c7f0e4a 100644 (file)
@@ -2718,7 +2718,7 @@ static unsigned long deferred_split_count(struct shrinker *shrink,
                struct shrink_control *sc)
 {
        struct pglist_data *pgdata = NODE_DATA(sc->nid);
-       return ACCESS_ONCE(pgdata->split_queue_len);
+       return READ_ONCE(pgdata->split_queue_len);
 }
 
 static unsigned long deferred_split_scan(struct shrinker *shrink,
index a728bed16c206902de6498921a1d130d141ff7b7..cae514e7dcfccde030c46ea60923711efc4bbe3f 100644 (file)
@@ -3891,9 +3891,9 @@ static int handle_pte_fault(struct vm_fault *vmf)
                /*
                 * some architectures can have larger ptes than wordsize,
                 * e.g.ppc44x-defconfig has CONFIG_PTE_64BIT=y and
-                * CONFIG_32BIT=y, so READ_ONCE or ACCESS_ONCE cannot guarantee
-                * atomic accesses.  The code below just needs a consistent
-                * view for the ifs and we later double check anyway with the
+                * CONFIG_32BIT=y, so READ_ONCE cannot guarantee atomic
+                * accesses.  The code below just needs a consistent view
+                * for the ifs and we later double check anyway with the
                 * ptl lock held. So here a barrier will do.
                 */
                barrier();
index 028cdc7df67ec9e08a683ba27e64b17b19e7612e..86d7c7d860f92c3a46d505a4b327c76e34f5415a 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -259,7 +259,7 @@ cache_from_memcg_idx(struct kmem_cache *s, int idx)
         * memcg_caches issues a write barrier to match this (see
         * memcg_create_kmem_cache()).
         */
-       cachep = lockless_dereference(arr->entries[idx]);
+       cachep = READ_ONCE(arr->entries[idx]);
        rcu_read_unlock();
 
        return cachep;
index 4900707ae146cf73c1c9ca4d01bd63a9dfc27c8b..60805abf98af71e53775c00bd2a5975b7f13e6fa 100644 (file)
@@ -23,8 +23,7 @@
  * 1) mem_section      - memory sections, mem_map's for valid memory
  */
 #ifdef CONFIG_SPARSEMEM_EXTREME
-struct mem_section *mem_section[NR_SECTION_ROOTS]
-       ____cacheline_internodealigned_in_smp;
+struct mem_section **mem_section;
 #else
 struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]
        ____cacheline_internodealigned_in_smp;
@@ -101,7 +100,7 @@ static inline int sparse_index_init(unsigned long section_nr, int nid)
 int __section_nr(struct mem_section* ms)
 {
        unsigned long root_nr;
-       struct mem_section* root;
+       struct mem_section *root = NULL;
 
        for (root_nr = 0; root_nr < NR_SECTION_ROOTS; root_nr++) {
                root = __nr_to_section(root_nr * SECTIONS_PER_ROOT);
@@ -112,7 +111,7 @@ int __section_nr(struct mem_section* ms)
                     break;
        }
 
-       VM_BUG_ON(root_nr == NR_SECTION_ROOTS);
+       VM_BUG_ON(!root);
 
        return (root_nr * SECTIONS_PER_ROOT) + (ms - root);
 }
@@ -208,6 +207,16 @@ void __init memory_present(int nid, unsigned long start, unsigned long end)
 {
        unsigned long pfn;
 
+#ifdef CONFIG_SPARSEMEM_EXTREME
+       if (unlikely(!mem_section)) {
+               unsigned long size, align;
+
+               size = sizeof(struct mem_section) * NR_SECTION_ROOTS;
+               align = 1 << (INTERNODE_CACHE_SHIFT);
+               mem_section = memblock_virt_alloc(size, align);
+       }
+#endif
+
        start &= PAGE_SECTION_MASK;
        mminit_validate_memmodel_limits(&start, &end);
        for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) {
@@ -330,11 +339,17 @@ again:
 static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
 {
        unsigned long usemap_snr, pgdat_snr;
-       static unsigned long old_usemap_snr = NR_MEM_SECTIONS;
-       static unsigned long old_pgdat_snr = NR_MEM_SECTIONS;
+       static unsigned long old_usemap_snr;
+       static unsigned long old_pgdat_snr;
        struct pglist_data *pgdat = NODE_DATA(nid);
        int usemap_nid;
 
+       /* First call */
+       if (!old_usemap_snr) {
+               old_usemap_snr = NR_MEM_SECTIONS;
+               old_pgdat_snr = NR_MEM_SECTIONS;
+       }
+
        usemap_snr = pfn_to_section_nr(__pa(usemap) >> PAGE_SHIFT);
        pgdat_snr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT);
        if (usemap_snr == pgdat_snr)
index 9649579b5b9f38aff6ce7a990d2dc1ddb1d85e12..4a72ee4e2ae96b41faadb2959c968e0a757f3a0b 100644 (file)
@@ -376,6 +376,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        dev->name);
                vlan_vid_add(dev, htons(ETH_P_8021Q), 0);
        }
+       if (event == NETDEV_DOWN &&
+           (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
+               vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
 
        vlan_info = rtnl_dereference(dev->vlan_info);
        if (!vlan_info)
@@ -423,9 +426,6 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                struct net_device *tmp;
                LIST_HEAD(close_list);
 
-               if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
-                       vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
-
                /* Put all VLANs for this dev in the down state too.  */
                vlan_group_for_each_dev(grp, i, vlandev) {
                        flgs = vlandev->flags;
index 5677147209e8181ce2e9eff308bc0ed82b548e45..63138c8c2269cd190b9f8d50cf2d179ee63682f8 100644 (file)
@@ -121,7 +121,7 @@ static struct notifier_block mpoa_notifier = {
 
 struct mpoa_client *mpcs = NULL; /* FIXME */
 static struct atm_mpoa_qos *qos_head = NULL;
-static DEFINE_TIMER(mpc_timer, NULL, 0, 0);
+static DEFINE_TIMER(mpc_timer, NULL);
 
 
 static struct mpoa_client *find_mpc_by_itfnum(int itf)
index 11596a302a265212cb5dfe40f51b5b01fb20d0ce..61559ca3980b8d25d5faf6106d52717b16cc4cd3 100644 (file)
@@ -3725,7 +3725,7 @@ bool rps_may_expire_flow(struct net_device *dev, u16 rxq_index,
        flow_table = rcu_dereference(rxqueue->rps_flow_table);
        if (flow_table && flow_id <= flow_table->mask) {
                rflow = &flow_table->flows[flow_id];
-               cpu = ACCESS_ONCE(rflow->cpu);
+               cpu = READ_ONCE(rflow->cpu);
                if (rflow->filter == filter_id && cpu < nr_cpu_ids &&
                    ((int)(per_cpu(softnet_data, cpu).input_queue_head -
                           rflow->last_qtail) <
index 912731bed7b71b9208f3947b49c4b93922f7ab0d..57557a6a950cc9cdff959391576a03381d328c1a 100644 (file)
@@ -334,7 +334,7 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
        /* It is up to the caller to keep npinfo alive. */
        struct netpoll_info *npinfo;
 
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_irqs_disabled();
 
        npinfo = rcu_dereference_bh(np->dev->npinfo);
        if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
index 6e1e10ff433a5f4097d1d4b33848ab13d4e005c6..3b2034f6d49d20a0df890d02ea30ebd05cdb87b4 100644 (file)
@@ -3377,7 +3377,7 @@ static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
 
 static void pktgen_xmit(struct pktgen_dev *pkt_dev)
 {
-       unsigned int burst = ACCESS_ONCE(pkt_dev->burst);
+       unsigned int burst = READ_ONCE(pkt_dev->burst);
        struct net_device *odev = pkt_dev->odev;
        struct netdev_queue *txq;
        struct sk_buff *skb;
index 24656076906d2a0f3b70b030c977e854caba2487..e140ba49b30a4937ff5d8b073262838c62bc7f0a 100644 (file)
@@ -4864,6 +4864,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
        if (!xnet)
                return;
 
+       ipvs_reset(skb);
        skb_orphan(skb);
        skb->mark = 0;
 }
index 0bd3afd01dd2994bcbfc6d3a79a47cf8a25a7df0..6538632fbd0342d4fe22aca8dcd66401a150c7a4 100644 (file)
@@ -131,7 +131,7 @@ static struct dn_rt_hash_bucket *dn_rt_hash_table;
 static unsigned int dn_rt_hash_mask;
 
 static struct timer_list dn_route_timer;
-static DEFINE_TIMER(dn_rt_flush_timer, dn_run_flush, 0, 0);
+static DEFINE_TIMER(dn_rt_flush_timer, dn_run_flush);
 int decnet_dst_gc_interval = 2;
 
 static struct dst_ops dn_dst_ops = {
index e6c06aa349a6fd1930a6c343d4d643cccfa8cb92..1e2929f4290a0d3799b2d8583fe32a0d4dc96080 100644 (file)
@@ -133,6 +133,8 @@ static int dsa_switch_mdb_add(struct dsa_switch *ds,
                        if (err)
                                return err;
                }
+
+               return 0;
        }
 
        for_each_set_bit(port, group, ds->num_ports)
@@ -180,6 +182,8 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
                        if (err)
                                return err;
                }
+
+               return 0;
        }
 
        for_each_set_bit(port, members, ds->num_ports)
index af74d0433453d9751e1b6e26bcbe251d173bee4b..f9597ba2659986408b3d43c4821e0b7793fa6670 100644 (file)
@@ -164,7 +164,7 @@ static void inet_frag_worker(struct work_struct *work)
 
        local_bh_disable();
 
-       for (i = ACCESS_ONCE(f->next_bucket); budget; --budget) {
+       for (i = READ_ONCE(f->next_bucket); budget; --budget) {
                evicted += inet_evict_bucket(f, &f->hash[i]);
                i = (i + 1) & (INETFRAGS_HASHSZ - 1);
                if (evicted > INETFRAGS_EVICT_MAX)
index 3d9f1c2f81c58afb45a1445f6ed06a97203606a1..c0864562083b58e8a9143e051eb62a8a4e723d4a 100644 (file)
@@ -495,7 +495,7 @@ u32 ip_idents_reserve(u32 hash, int segs)
 {
        u32 *p_tstamp = ip_tstamps + hash % IP_IDENTS_SZ;
        atomic_t *p_id = ip_idents + hash % IP_IDENTS_SZ;
-       u32 old = ACCESS_ONCE(*p_tstamp);
+       u32 old = READ_ONCE(*p_tstamp);
        u32 now = (u32)jiffies;
        u32 new, delta = 0;
 
index 5a87a00641d3a82bfb78d4f3a2959fe8ea2e119c..887585045b271af66600f1814ac9d3a601f38773 100644 (file)
@@ -115,7 +115,7 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2;
 
 #define FLAG_ACKED             (FLAG_DATA_ACKED|FLAG_SYN_ACKED)
 #define FLAG_NOT_DUP           (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
-#define FLAG_CA_ALERT          (FLAG_DATA_SACKED|FLAG_ECE)
+#define FLAG_CA_ALERT          (FLAG_DATA_SACKED|FLAG_ECE|FLAG_DSACKING_ACK)
 #define FLAG_FORWARD_PROGRESS  (FLAG_ACKED|FLAG_DATA_SACKED)
 
 #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH)
@@ -816,12 +816,12 @@ static void tcp_update_pacing_rate(struct sock *sk)
        if (likely(tp->srtt_us))
                do_div(rate, tp->srtt_us);
 
-       /* ACCESS_ONCE() is needed because sch_fq fetches sk_pacing_rate
+       /* WRITE_ONCE() is needed because sch_fq fetches sk_pacing_rate
         * without any lock. We want to make sure compiler wont store
         * intermediate values in this location.
         */
-       ACCESS_ONCE(sk->sk_pacing_rate) = min_t(u64, rate,
-                                               sk->sk_max_pacing_rate);
+       WRITE_ONCE(sk->sk_pacing_rate, min_t(u64, rate,
+                                            sk->sk_max_pacing_rate));
 }
 
 /* Calculate rto without backoff.  This is the second half of Van Jacobson's
@@ -2615,7 +2615,6 @@ void tcp_simple_retransmit(struct sock *sk)
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
        unsigned int mss = tcp_current_mss(sk);
-       u32 prior_lost = tp->lost_out;
 
        tcp_for_write_queue(skb, sk) {
                if (skb == tcp_send_head(sk))
@@ -2632,7 +2631,7 @@ void tcp_simple_retransmit(struct sock *sk)
 
        tcp_clear_retrans_hints_partial(tp);
 
-       if (prior_lost == tp->lost_out)
+       if (!tp->lost_out)
                return;
 
        if (tcp_is_reno(tp))
index 11f69bbf93072b7b4dbc3a0485c9f9e0b9ba30b3..b6a2aa1dcf56cbaa029b0ec6c5e512e33c90fff9 100644 (file)
@@ -149,11 +149,19 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
         * is freed by GSO engine
         */
        if (copy_destructor) {
+               int delta;
+
                swap(gso_skb->sk, skb->sk);
                swap(gso_skb->destructor, skb->destructor);
                sum_truesize += skb->truesize;
-               refcount_add(sum_truesize - gso_skb->truesize,
-                          &skb->sk->sk_wmem_alloc);
+               delta = sum_truesize - gso_skb->truesize;
+               /* In some pathological cases, delta can be negative.
+                * We need to either use refcount_add() or refcount_sub_and_test()
+                */
+               if (likely(delta >= 0))
+                       refcount_add(delta, &skb->sk->sk_wmem_alloc);
+               else
+                       WARN_ON_ONCE(refcount_sub_and_test(-delta, &skb->sk->sk_wmem_alloc));
        }
 
        delta = htonl(oldlen + (skb_tail_pointer(skb) -
index 478909f4694d00076c96b7a3be1eda62b6be8bef..5a42e873d44a8f880d8999e911d64d6f388865fb 100644 (file)
@@ -1910,7 +1910,7 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb,
        if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len))
                goto send_now;
 
-       win_divisor = ACCESS_ONCE(sysctl_tcp_tso_win_divisor);
+       win_divisor = READ_ONCE(sysctl_tcp_tso_win_divisor);
        if (win_divisor) {
                u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
 
index ebfbccae62fde187ec5863670c03cd5b5c96258b..02ec9a3493033cf044b31724c340ce0cfa9add20 100644 (file)
@@ -1853,7 +1853,7 @@ static int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                 */
 
                /* if we're overly short, let UDP handle it */
-               encap_rcv = ACCESS_ONCE(up->encap_rcv);
+               encap_rcv = READ_ONCE(up->encap_rcv);
                if (encap_rcv) {
                        int ret;
 
@@ -2298,7 +2298,7 @@ void udp_destroy_sock(struct sock *sk)
        unlock_sock_fast(sk, slow);
        if (static_key_false(&udp_encap_needed) && up->encap_type) {
                void (*encap_destroy)(struct sock *sk);
-               encap_destroy = ACCESS_ONCE(up->encap_destroy);
+               encap_destroy = READ_ONCE(up->encap_destroy);
                if (encap_destroy)
                        encap_destroy(sk);
        }
index 15535ee327c5780e80feb050c2ab4e0d1cc3e99c..9f2e73c71768d917ff3ca0cb0e22aed28f710ce5 100644 (file)
@@ -47,7 +47,7 @@ static atomic_t fl_size = ATOMIC_INIT(0);
 static struct ip6_flowlabel __rcu *fl_ht[FL_HASH_MASK+1];
 
 static void ip6_fl_gc(unsigned long dummy);
-static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc, 0, 0);
+static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc);
 
 /* FL hash table lock: it protects only of GC */
 
index a1c24443cd9e01de9c6e2d5d68c0f8426e25ceec..dab94655415741873e869176d2f06520085d8729 100644 (file)
@@ -490,7 +490,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
        if (!t)
                goto out;
 
-       tproto = ACCESS_ONCE(t->parms.proto);
+       tproto = READ_ONCE(t->parms.proto);
        if (tproto != ipproto && tproto != 0)
                goto out;
 
@@ -899,7 +899,7 @@ static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto,
        t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
 
        if (t) {
-               u8 tproto = ACCESS_ONCE(t->parms.proto);
+               u8 tproto = READ_ONCE(t->parms.proto);
 
                if (tproto != ipproto && tproto != 0)
                        goto drop;
@@ -1233,7 +1233,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 
-       tproto = ACCESS_ONCE(t->parms.proto);
+       tproto = READ_ONCE(t->parms.proto);
        if (tproto != IPPROTO_IPIP && tproto != 0)
                return -1;
 
@@ -1303,7 +1303,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        u8 tproto;
        int err;
 
-       tproto = ACCESS_ONCE(t->parms.proto);
+       tproto = READ_ONCE(t->parms.proto);
        if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
            ip6_tnl_addr_conflict(t, ipv6h))
                return -1;
index 40d7234c27b991e54f5cfbacb5d7081e8277ae56..3f30fa313bf282d129668f6c0929a631edf0ca9d 100644 (file)
@@ -606,7 +606,7 @@ static int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                 */
 
                /* if we're overly short, let UDP handle it */
-               encap_rcv = ACCESS_ONCE(up->encap_rcv);
+               encap_rcv = READ_ONCE(up->encap_rcv);
                if (encap_rcv) {
                        int ret;
 
@@ -1432,7 +1432,7 @@ void udpv6_destroy_sock(struct sock *sk)
 
        if (static_key_false(&udpv6_encap_needed) && up->encap_type) {
                void (*encap_destroy)(struct sock *sk);
-               encap_destroy = ACCESS_ONCE(up->encap_destroy);
+               encap_destroy = READ_ONCE(up->encap_destroy);
                if (encap_destroy)
                        encap_destroy(sk);
        }
index 4d322c1b7233e5b546ff75a585a3603503e076bc..e4280b6568b4c820dda9b59fbac3bdf83409f5dc 100644 (file)
@@ -123,6 +123,7 @@ static int l2tp_ip_recv(struct sk_buff *skb)
        unsigned char *ptr, *optr;
        struct l2tp_session *session;
        struct l2tp_tunnel *tunnel = NULL;
+       struct iphdr *iph;
        int length;
 
        if (!pskb_may_pull(skb, 4))
@@ -178,24 +179,17 @@ pass_up:
                goto discard;
 
        tunnel_id = ntohl(*(__be32 *) &skb->data[4]);
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-       if (tunnel) {
-               sk = tunnel->sock;
-               sock_hold(sk);
-       } else {
-               struct iphdr *iph = (struct iphdr *) skb_network_header(skb);
-
-               read_lock_bh(&l2tp_ip_lock);
-               sk = __l2tp_ip_bind_lookup(net, iph->daddr, iph->saddr,
-                                          inet_iif(skb), tunnel_id);
-               if (!sk) {
-                       read_unlock_bh(&l2tp_ip_lock);
-                       goto discard;
-               }
+       iph = (struct iphdr *)skb_network_header(skb);
 
-               sock_hold(sk);
+       read_lock_bh(&l2tp_ip_lock);
+       sk = __l2tp_ip_bind_lookup(net, iph->daddr, iph->saddr, inet_iif(skb),
+                                  tunnel_id);
+       if (!sk) {
                read_unlock_bh(&l2tp_ip_lock);
+               goto discard;
        }
+       sock_hold(sk);
+       read_unlock_bh(&l2tp_ip_lock);
 
        if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_put;
index 88b397c30d86af8d6a22daeb466cedac36aac57e..8bcaa975b432e8600a60af6ec557dbe82e4cc898 100644 (file)
@@ -136,6 +136,7 @@ static int l2tp_ip6_recv(struct sk_buff *skb)
        unsigned char *ptr, *optr;
        struct l2tp_session *session;
        struct l2tp_tunnel *tunnel = NULL;
+       struct ipv6hdr *iph;
        int length;
 
        if (!pskb_may_pull(skb, 4))
@@ -192,24 +193,17 @@ pass_up:
                goto discard;
 
        tunnel_id = ntohl(*(__be32 *) &skb->data[4]);
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-       if (tunnel) {
-               sk = tunnel->sock;
-               sock_hold(sk);
-       } else {
-               struct ipv6hdr *iph = ipv6_hdr(skb);
-
-               read_lock_bh(&l2tp_ip6_lock);
-               sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, &iph->saddr,
-                                           inet6_iif(skb), tunnel_id);
-               if (!sk) {
-                       read_unlock_bh(&l2tp_ip6_lock);
-                       goto discard;
-               }
+       iph = ipv6_hdr(skb);
 
-               sock_hold(sk);
+       read_lock_bh(&l2tp_ip6_lock);
+       sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, &iph->saddr,
+                                   inet6_iif(skb), tunnel_id);
+       if (!sk) {
                read_unlock_bh(&l2tp_ip6_lock);
+               goto discard;
        }
+       sock_hold(sk);
+       read_unlock_bh(&l2tp_ip6_lock);
 
        if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_put;
index dd3e83328ad544d3183233da61fa40289975de51..82cb93f66b9bdd103b6900a5d1177751c5a01bc8 100644 (file)
@@ -193,7 +193,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
         */
        rcv = rcu_dereference(sap->rcv_func);
        dest = llc_pdu_type(skb);
-       sap_handler = dest ? ACCESS_ONCE(llc_type_handlers[dest - 1]) : NULL;
+       sap_handler = dest ? READ_ONCE(llc_type_handlers[dest - 1]) : NULL;
        if (unlikely(!sap_handler)) {
                if (rcv)
                        rcv(skb, dev, pt, orig_dev);
@@ -214,7 +214,7 @@ drop:
        kfree_skb(skb);
        goto out;
 handle_station:
-       sta_handler = ACCESS_ONCE(llc_station_handler);
+       sta_handler = READ_ONCE(llc_station_handler);
        if (!sta_handler)
                goto drop;
        sta_handler(skb);
index 69615016d5bf60cb89f46056f3faf7c6f2fd3ce4..214d2ba02877d2fcb45980786528a4e650c9644d 100644 (file)
@@ -2008,7 +2008,7 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
 
 static int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
 {
-       u16 rate = ACCESS_ONCE(sta_get_last_rx_stats(sta)->last_rate);
+       u16 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate);
 
        if (rate == STA_STATS_RATE_INVALID)
                return -EINVAL;
index 3d2ac71a83ec411294361037e7b1d77b6d4bb7e2..3a43b3470331bccc4b83a72e593ae3a3ac0c9f18 100644 (file)
@@ -104,7 +104,7 @@ static inline void ct_write_unlock_bh(unsigned int key)
        spin_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
 }
 
-static void ip_vs_conn_expire(unsigned long data);
+static void ip_vs_conn_expire(struct timer_list *t);
 
 /*
  *     Returns hash value for IPVS connection entry
@@ -457,7 +457,7 @@ EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto);
 static void __ip_vs_conn_put_notimer(struct ip_vs_conn *cp)
 {
        __ip_vs_conn_put(cp);
-       ip_vs_conn_expire((unsigned long)cp);
+       ip_vs_conn_expire(&cp->timer);
 }
 
 /*
@@ -817,9 +817,9 @@ static void ip_vs_conn_rcu_free(struct rcu_head *head)
        kmem_cache_free(ip_vs_conn_cachep, cp);
 }
 
-static void ip_vs_conn_expire(unsigned long data)
+static void ip_vs_conn_expire(struct timer_list *t)
 {
-       struct ip_vs_conn *cp = (struct ip_vs_conn *)data;
+       struct ip_vs_conn *cp = from_timer(cp, t, timer);
        struct netns_ipvs *ipvs = cp->ipvs;
 
        /*
@@ -909,7 +909,7 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
        }
 
        INIT_HLIST_NODE(&cp->c_list);
-       setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
+       timer_setup(&cp->timer, ip_vs_conn_expire, 0);
        cp->ipvs           = ipvs;
        cp->af             = p->af;
        cp->daf            = dest_af;
index 4f940d7eb2f7e4587b6543219e801f80a5a19b79..b47e266c6eca88d98df1e67efb28e1923f9497a5 100644 (file)
@@ -1146,9 +1146,9 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
        return 0;
 }
 
-static void ip_vs_dest_trash_expire(unsigned long data)
+static void ip_vs_dest_trash_expire(struct timer_list *t)
 {
-       struct netns_ipvs *ipvs = (struct netns_ipvs *)data;
+       struct netns_ipvs *ipvs = from_timer(ipvs, t, dest_trash_timer);
        struct ip_vs_dest *dest, *next;
        unsigned long now = jiffies;
 
@@ -4019,8 +4019,7 @@ int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
 
        INIT_LIST_HEAD(&ipvs->dest_trash);
        spin_lock_init(&ipvs->dest_trash_lock);
-       setup_timer(&ipvs->dest_trash_timer, ip_vs_dest_trash_expire,
-                   (unsigned long) ipvs);
+       timer_setup(&ipvs->dest_trash_timer, ip_vs_dest_trash_expire, 0);
        atomic_set(&ipvs->ftpsvc_counter, 0);
        atomic_set(&ipvs->nullsvc_counter, 0);
        atomic_set(&ipvs->conn_out_counter, 0);
index 457c6c193e1332ab803b6f381f1329f85f1ebdf6..489055091a9b3ba5ce9ba8b1d868dd9f79575f85 100644 (file)
@@ -97,12 +97,12 @@ static void ip_vs_read_cpu_stats(struct ip_vs_kstats *sum,
 }
 
 
-static void estimation_timer(unsigned long arg)
+static void estimation_timer(struct timer_list *t)
 {
        struct ip_vs_estimator *e;
        struct ip_vs_stats *s;
        u64 rate;
-       struct netns_ipvs *ipvs = (struct netns_ipvs *)arg;
+       struct netns_ipvs *ipvs = from_timer(ipvs, t, est_timer);
 
        spin_lock(&ipvs->est_lock);
        list_for_each_entry(e, &ipvs->est_list, list) {
@@ -192,7 +192,7 @@ int __net_init ip_vs_estimator_net_init(struct netns_ipvs *ipvs)
 {
        INIT_LIST_HEAD(&ipvs->est_list);
        spin_lock_init(&ipvs->est_lock);
-       setup_timer(&ipvs->est_timer, estimation_timer, (unsigned long)ipvs);
+       timer_setup(&ipvs->est_timer, estimation_timer, 0);
        mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
        return 0;
 }
index b6aa4a970c6e97678e8c88e8fe0e0e0b4e4d476d..d625179de485b0324d862f78cf6db7764609404e 100644 (file)
@@ -106,6 +106,7 @@ struct ip_vs_lblc_table {
        struct rcu_head         rcu_head;
        struct hlist_head       bucket[IP_VS_LBLC_TAB_SIZE];  /* hash bucket */
        struct timer_list       periodic_timer; /* collect stale entries */
+       struct ip_vs_service    *svc;           /* pointer back to service */
        atomic_t                entries;        /* number of entries */
        int                     max_size;       /* maximum size of entries */
        int                     rover;          /* rover for expire check */
@@ -294,10 +295,10 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
  *             of the table.
  *      The full expiration check is for this purpose now.
  */
-static void ip_vs_lblc_check_expire(unsigned long data)
+static void ip_vs_lblc_check_expire(struct timer_list *t)
 {
-       struct ip_vs_service *svc = (struct ip_vs_service *) data;
-       struct ip_vs_lblc_table *tbl = svc->sched_data;
+       struct ip_vs_lblc_table *tbl = from_timer(tbl, t, periodic_timer);
+       struct ip_vs_service *svc = tbl->svc;
        unsigned long now = jiffies;
        int goal;
        int i, j;
@@ -369,12 +370,12 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
        tbl->rover = 0;
        tbl->counter = 1;
        tbl->dead = 0;
+       tbl->svc = svc;
 
        /*
         *    Hook periodic timer for garbage collection
         */
-       setup_timer(&tbl->periodic_timer, ip_vs_lblc_check_expire,
-                       (unsigned long)svc);
+       timer_setup(&tbl->periodic_timer, ip_vs_lblc_check_expire, 0);
        mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL);
 
        return 0;
index c13ff575f9f73ab9fb53837ff1b01cd279156c9f..84c57b62a5887b433b672d0d71c681bbf9b11a59 100644 (file)
@@ -278,6 +278,7 @@ struct ip_vs_lblcr_table {
        atomic_t                entries;        /* number of entries */
        int                     max_size;       /* maximum size of entries */
        struct timer_list       periodic_timer; /* collect stale entries */
+       struct ip_vs_service    *svc;           /* pointer back to service */
        int                     rover;          /* rover for expire check */
        int                     counter;        /* counter for no expire */
        bool                    dead;
@@ -458,10 +459,10 @@ static inline void ip_vs_lblcr_full_check(struct ip_vs_service *svc)
  *             of the table.
  *      The full expiration check is for this purpose now.
  */
-static void ip_vs_lblcr_check_expire(unsigned long data)
+static void ip_vs_lblcr_check_expire(struct timer_list *t)
 {
-       struct ip_vs_service *svc = (struct ip_vs_service *) data;
-       struct ip_vs_lblcr_table *tbl = svc->sched_data;
+       struct ip_vs_lblcr_table *tbl = from_timer(tbl, t, periodic_timer);
+       struct ip_vs_service *svc = tbl->svc;
        unsigned long now = jiffies;
        int goal;
        int i, j;
@@ -532,12 +533,12 @@ static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc)
        tbl->rover = 0;
        tbl->counter = 1;
        tbl->dead = 0;
+       tbl->svc = svc;
 
        /*
         *    Hook periodic timer for garbage collection
         */
-       setup_timer(&tbl->periodic_timer, ip_vs_lblcr_check_expire,
-                       (unsigned long)svc);
+       timer_setup(&tbl->periodic_timer, ip_vs_lblcr_check_expire, 0);
        mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL);
 
        return 0;
index 13f7408755073b6f43e402975b8450e70ff32873..9ee71cb276d734795e16719347fbf2740ce0cfc4 100644 (file)
@@ -458,7 +458,7 @@ static inline bool in_persistence(struct ip_vs_conn *cp)
 static int ip_vs_sync_conn_needed(struct netns_ipvs *ipvs,
                                  struct ip_vs_conn *cp, int pkts)
 {
-       unsigned long orig = ACCESS_ONCE(cp->sync_endtime);
+       unsigned long orig = READ_ONCE(cp->sync_endtime);
        unsigned long now = jiffies;
        unsigned long n = (now + cp->timeout) & ~3UL;
        unsigned int sync_refresh_period;
index c9796629858f795629f0de0c60e0cd41acc85a80..a16356cacec3646a9b70a0d0b443db28a696a0a0 100644 (file)
@@ -401,7 +401,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 
        outdev = entry->state.out;
 
-       switch ((enum nfqnl_config_mode)ACCESS_ONCE(queue->copy_mode)) {
+       switch ((enum nfqnl_config_mode)READ_ONCE(queue->copy_mode)) {
        case NFQNL_COPY_META:
        case NFQNL_COPY_NONE:
                break;
@@ -412,7 +412,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
                    skb_checksum_help(entskb))
                        return NULL;
 
-               data_len = ACCESS_ONCE(queue->copy_range);
+               data_len = READ_ONCE(queue->copy_range);
                if (data_len > entskb->len)
                        data_len = entskb->len;
 
index d177dd0665043652c199605479959ea408145a4b..4d748975117dba1b3889e40f48a4229bcefe2459 100644 (file)
@@ -393,7 +393,7 @@ EXPORT_SYMBOL(netlbl_calipso_ops_register);
 
 static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)
 {
-       return ACCESS_ONCE(calipso_ops);
+       return READ_ONCE(calipso_ops);
 }
 
 /**
index 94d4e922af53c0fb5e1c34508dbad6a76f46d96f..989ae647825ef4568c0bd5717c8721e85cde46c6 100644 (file)
@@ -18,7 +18,7 @@
 static void nr_loopback_timer(unsigned long);
 
 static struct sk_buff_head loopback_queue;
-static DEFINE_TIMER(loopback_timer, nr_loopback_timer, 0, 0);
+static DEFINE_TIMER(loopback_timer, nr_loopback_timer);
 
 void __init nr_loopback_init(void)
 {
index c2f5c13550c052de0484582af9aabda3500cc030..78418f38464a4319f8ab6e3f4a2c3e745b698bd7 100644 (file)
@@ -1085,7 +1085,7 @@ static int __init qrtr_proto_init(void)
 
        return 0;
 }
-module_init(qrtr_proto_init);
+postcore_initcall(qrtr_proto_init);
 
 static void __exit qrtr_proto_fini(void)
 {
index 9722bf839d9dec7fc7c7bed5cca0818389b245ba..b4e421aa9727942e0cbe7ba40e11c3d19d937868 100644 (file)
@@ -410,14 +410,14 @@ void rds_ib_recv_refill(struct rds_connection *conn, int prefill, gfp_t gfp)
                        break;
                }
 
-               /* XXX when can this fail? */
-               ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, &failed_wr);
-               rdsdebug("recv %p ibinc %p page %p addr %lu ret %d\n", recv,
+               rdsdebug("recv %p ibinc %p page %p addr %lu\n", recv,
                         recv->r_ibinc, sg_page(&recv->r_frag->f_sg),
                         (long) ib_sg_dma_address(
                                ic->i_cm_id->device,
-                               &recv->r_frag->f_sg),
-                       ret);
+                               &recv->r_frag->f_sg));
+
+               /* XXX when can this fail? */
+               ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, &failed_wr);
                if (ret) {
                        rds_ib_conn_error(conn, "recv post on "
                               "%pI4 returned %d, disconnecting and "
index ca2ff0b3123f9d37e4b0549e55254bf46efb5e1a..8f2c635149561e741bda88163df063f8cc70f957 100644 (file)
@@ -78,7 +78,6 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
        spin_lock_bh(&idrinfo->lock);
        idr_remove_ext(&idrinfo->action_idr, p->tcfa_index);
        spin_unlock_bh(&idrinfo->lock);
-       put_net(idrinfo->net);
        gen_kill_estimator(&p->tcfa_rate_est);
        free_tcf(p);
 }
@@ -337,7 +336,6 @@ err3:
        p->idrinfo = idrinfo;
        p->ops = ops;
        INIT_LIST_HEAD(&p->list);
-       get_net(idrinfo->net);
        *a = p;
        return 0;
 }
index 9bce8cc84cbb9cd99fa1812ef0ac99a4405a995a..c0c707eb2c962520fbc6da655c8b4151bf8a4462 100644 (file)
@@ -398,7 +398,7 @@ static __net_init int bpf_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, bpf_net_id);
 
-       return tc_action_net_init(tn, &act_bpf_ops, net);
+       return tc_action_net_init(tn, &act_bpf_ops);
 }
 
 static void __net_exit bpf_exit_net(struct net *net)
index 34e52d01a5dde25ab4432979eaac01c730d733fd..10b7a8855a6c754640c66b21af3df1e4b17de63d 100644 (file)
@@ -206,7 +206,7 @@ static __net_init int connmark_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, connmark_net_id);
 
-       return tc_action_net_init(tn, &act_connmark_ops, net);
+       return tc_action_net_init(tn, &act_connmark_ops);
 }
 
 static void __net_exit connmark_exit_net(struct net *net)
index 35171df2ebef38776dfd2f9fe2603de86d341872..1c40caadcff959ba0c6cec6b8e32f7b459c42cfa 100644 (file)
@@ -626,7 +626,7 @@ static __net_init int csum_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, csum_net_id);
 
-       return tc_action_net_init(tn, &act_csum_ops, net);
+       return tc_action_net_init(tn, &act_csum_ops);
 }
 
 static void __net_exit csum_exit_net(struct net *net)
index ef7f7f39d26d27cff31f929f84dfed549ccb843d..e29a48ef7fc348aefdc720cf08d1509ac5b53559 100644 (file)
@@ -232,7 +232,7 @@ static __net_init int gact_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, gact_net_id);
 
-       return tc_action_net_init(tn, &act_gact_ops, net);
+       return tc_action_net_init(tn, &act_gact_ops);
 }
 
 static void __net_exit gact_exit_net(struct net *net)
index f65e4b5058e0803d4e2f9a67f2cb1f7978ffc656..8ccd35825b6b97f48311c1060f88a41a34f18f9a 100644 (file)
@@ -818,7 +818,7 @@ static __net_init int ife_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, ife_net_id);
 
-       return tc_action_net_init(tn, &act_ife_ops, net);
+       return tc_action_net_init(tn, &act_ife_ops);
 }
 
 static void __net_exit ife_exit_net(struct net *net)
index dbdf3b2470d53bebbd2f75f32889d4fda47e19fb..d9e399a7e3d59c8ec53e46e0862e2ca3c83988bc 100644 (file)
@@ -334,7 +334,7 @@ static __net_init int ipt_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, ipt_net_id);
 
-       return tc_action_net_init(tn, &act_ipt_ops, net);
+       return tc_action_net_init(tn, &act_ipt_ops);
 }
 
 static void __net_exit ipt_exit_net(struct net *net)
@@ -384,7 +384,7 @@ static __net_init int xt_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, xt_net_id);
 
-       return tc_action_net_init(tn, &act_xt_ops, net);
+       return tc_action_net_init(tn, &act_xt_ops);
 }
 
 static void __net_exit xt_exit_net(struct net *net)
index 84759cfd5a3398555cba7012d0cc949b7b7e6033..416627c66f081f26ff9284de86411c3e05390b8e 100644 (file)
@@ -343,7 +343,7 @@ static __net_init int mirred_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, mirred_net_id);
 
-       return tc_action_net_init(tn, &act_mirred_ops, net);
+       return tc_action_net_init(tn, &act_mirred_ops);
 }
 
 static void __net_exit mirred_exit_net(struct net *net)
index 7eeaaf9217b69faa356a091409bbaa2c70f95242..c365d01b99c8b7892c16e43742a88744d7d84e54 100644 (file)
@@ -307,7 +307,7 @@ static __net_init int nat_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, nat_net_id);
 
-       return tc_action_net_init(tn, &act_nat_ops, net);
+       return tc_action_net_init(tn, &act_nat_ops);
 }
 
 static void __net_exit nat_exit_net(struct net *net)
index b3d82c334a5f5285ad7309e5eb9b573e2f84e229..491fe5deb09ee7f38a6c0f892c43ffe0bce79fd1 100644 (file)
@@ -450,7 +450,7 @@ static __net_init int pedit_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, pedit_net_id);
 
-       return tc_action_net_init(tn, &act_pedit_ops, net);
+       return tc_action_net_init(tn, &act_pedit_ops);
 }
 
 static void __net_exit pedit_exit_net(struct net *net)
index 9ec42b26e4b97d298392e60ed7ca0a1eb427b6ea..3bb2ebf9e9aec2743033ecdc4f5763ce601bf653 100644 (file)
@@ -331,7 +331,7 @@ static __net_init int police_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, police_net_id);
 
-       return tc_action_net_init(tn, &act_police_ops, net);
+       return tc_action_net_init(tn, &act_police_ops);
 }
 
 static void __net_exit police_exit_net(struct net *net)
index e69a1e3a39bf700a5a729bd9234132397c7e55c7..8b5abcd2f32faeaa2a283bcc8fb388201f7a86e2 100644 (file)
@@ -240,7 +240,7 @@ static __net_init int sample_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, sample_net_id);
 
-       return tc_action_net_init(tn, &act_sample_ops, net);
+       return tc_action_net_init(tn, &act_sample_ops);
 }
 
 static void __net_exit sample_exit_net(struct net *net)
index a8d0ea95f89454826e9d782846543f054a0dc5e5..e7b57e5071a365743de9d2c5aaa22dca445fa0d9 100644 (file)
@@ -201,7 +201,7 @@ static __net_init int simp_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, simp_net_id);
 
-       return tc_action_net_init(tn, &act_simp_ops, net);
+       return tc_action_net_init(tn, &act_simp_ops);
 }
 
 static void __net_exit simp_exit_net(struct net *net)
index fbac62472e09cf72c5aac1731f9065843b48455e..59949d61f20da1031b8b47712f817c991c6bed60 100644 (file)
@@ -238,7 +238,7 @@ static __net_init int skbedit_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, skbedit_net_id);
 
-       return tc_action_net_init(tn, &act_skbedit_ops, net);
+       return tc_action_net_init(tn, &act_skbedit_ops);
 }
 
 static void __net_exit skbedit_exit_net(struct net *net)
index 8e12d8897d2ff6449a410e037652a1aa95c63d35..b642ad3d39dd414d392e492bae091995b01cbd77 100644 (file)
@@ -263,7 +263,7 @@ static __net_init int skbmod_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, skbmod_net_id);
 
-       return tc_action_net_init(tn, &act_skbmod_ops, net);
+       return tc_action_net_init(tn, &act_skbmod_ops);
 }
 
 static void __net_exit skbmod_exit_net(struct net *net)
index c33faa373cf2221c2798509a5f1f70c8bce69240..30c96274c63826520eec062a6a5609b141bab307 100644 (file)
@@ -322,7 +322,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 
-       return tc_action_net_init(tn, &act_tunnel_key_ops, net);
+       return tc_action_net_init(tn, &act_tunnel_key_ops);
 }
 
 static void __net_exit tunnel_key_exit_net(struct net *net)
index 115fc33cc6d8b321f9c02febf861b93fe9a85740..16eb067a8d8fa20c17894db8047571789c0b96e8 100644 (file)
@@ -269,7 +269,7 @@ static __net_init int vlan_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, vlan_net_id);
 
-       return tc_action_net_init(tn, &act_vlan_ops, net);
+       return tc_action_net_init(tn, &act_vlan_ops);
 }
 
 static void __net_exit vlan_exit_net(struct net *net)
index b2d31074548724a3b59defbcd827d6538ac9bea6..ecbb019efcbd310dd1caaaf336d2db2b523713dd 100644 (file)
@@ -927,6 +927,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
                                exts->actions[i++] = act;
                        exts->nr_actions = i;
                }
+               exts->net = net;
        }
 #else
        if ((exts->action && tb[exts->action]) ||
index f177649a24192a144f261d4e4a40b52ce7cdc91a..e43c56d5b96a2943d59733185b51b8bafe19f8fa 100644 (file)
@@ -85,16 +85,21 @@ static int basic_init(struct tcf_proto *tp)
        return 0;
 }
 
+static void __basic_delete_filter(struct basic_filter *f)
+{
+       tcf_exts_destroy(&f->exts);
+       tcf_em_tree_destroy(&f->ematches);
+       tcf_exts_put_net(&f->exts);
+       kfree(f);
+}
+
 static void basic_delete_filter_work(struct work_struct *work)
 {
        struct basic_filter *f = container_of(work, struct basic_filter, work);
 
        rtnl_lock();
-       tcf_exts_destroy(&f->exts);
-       tcf_em_tree_destroy(&f->ematches);
+       __basic_delete_filter(f);
        rtnl_unlock();
-
-       kfree(f);
 }
 
 static void basic_delete_filter(struct rcu_head *head)
@@ -113,7 +118,10 @@ static void basic_destroy(struct tcf_proto *tp)
        list_for_each_entry_safe(f, n, &head->flist, link) {
                list_del_rcu(&f->link);
                tcf_unbind_filter(tp, &f->res);
-               call_rcu(&f->rcu, basic_delete_filter);
+               if (tcf_exts_get_net(&f->exts))
+                       call_rcu(&f->rcu, basic_delete_filter);
+               else
+                       __basic_delete_filter(f);
        }
        kfree_rcu(head, rcu);
 }
@@ -125,6 +133,7 @@ static int basic_delete(struct tcf_proto *tp, void *arg, bool *last)
 
        list_del_rcu(&f->link);
        tcf_unbind_filter(tp, &f->res);
+       tcf_exts_get_net(&f->exts);
        call_rcu(&f->rcu, basic_delete_filter);
        *last = list_empty(&head->flist);
        return 0;
@@ -219,6 +228,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
        if (fold) {
                list_replace_rcu(&fold->link, &fnew->link);
                tcf_unbind_filter(tp, &fold->res);
+               tcf_exts_get_net(&fold->exts);
                call_rcu(&fold->rcu, basic_delete_filter);
        } else {
                list_add_rcu(&fnew->link, &head->flist);
index 037a3ae86829946135e2154bd83ddc722b61af17..990eb4d91d54255ace7eb400298eb433edd47cbe 100644 (file)
@@ -249,6 +249,7 @@ static int cls_bpf_init(struct tcf_proto *tp)
 static void __cls_bpf_delete_prog(struct cls_bpf_prog *prog)
 {
        tcf_exts_destroy(&prog->exts);
+       tcf_exts_put_net(&prog->exts);
 
        if (cls_bpf_is_ebpf(prog))
                bpf_prog_put(prog->filter);
@@ -282,7 +283,10 @@ static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog)
        cls_bpf_stop_offload(tp, prog);
        list_del_rcu(&prog->link);
        tcf_unbind_filter(tp, &prog->res);
-       call_rcu(&prog->rcu, cls_bpf_delete_prog_rcu);
+       if (tcf_exts_get_net(&prog->exts))
+               call_rcu(&prog->rcu, cls_bpf_delete_prog_rcu);
+       else
+               __cls_bpf_delete_prog(prog);
 }
 
 static int cls_bpf_delete(struct tcf_proto *tp, void *arg, bool *last)
@@ -516,6 +520,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
        if (oldprog) {
                list_replace_rcu(&oldprog->link, &prog->link);
                tcf_unbind_filter(tp, &oldprog->res);
+               tcf_exts_get_net(&oldprog->exts);
                call_rcu(&oldprog->rcu, cls_bpf_delete_prog_rcu);
        } else {
                list_add_rcu(&prog->link, &head->plist);
index a97e069bee89f0010daaa33c610cc1aea7b97811..309d5899265f8f7dea731a2a8569867fa5077e09 100644 (file)
@@ -60,15 +60,21 @@ static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = {
        [TCA_CGROUP_EMATCHES]   = { .type = NLA_NESTED },
 };
 
+static void __cls_cgroup_destroy(struct cls_cgroup_head *head)
+{
+       tcf_exts_destroy(&head->exts);
+       tcf_em_tree_destroy(&head->ematches);
+       tcf_exts_put_net(&head->exts);
+       kfree(head);
+}
+
 static void cls_cgroup_destroy_work(struct work_struct *work)
 {
        struct cls_cgroup_head *head = container_of(work,
                                                    struct cls_cgroup_head,
                                                    work);
        rtnl_lock();
-       tcf_exts_destroy(&head->exts);
-       tcf_em_tree_destroy(&head->ematches);
-       kfree(head);
+       __cls_cgroup_destroy(head);
        rtnl_unlock();
 }
 
@@ -124,8 +130,10 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
                goto errout;
 
        rcu_assign_pointer(tp->root, new);
-       if (head)
+       if (head) {
+               tcf_exts_get_net(&head->exts);
                call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
+       }
        return 0;
 errout:
        tcf_exts_destroy(&new->exts);
@@ -138,8 +146,12 @@ static void cls_cgroup_destroy(struct tcf_proto *tp)
        struct cls_cgroup_head *head = rtnl_dereference(tp->root);
 
        /* Head can still be NULL due to cls_cgroup_init(). */
-       if (head)
-               call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
+       if (head) {
+               if (tcf_exts_get_net(&head->exts))
+                       call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
+               else
+                       __cls_cgroup_destroy(head);
+       }
 }
 
 static int cls_cgroup_delete(struct tcf_proto *tp, void *arg, bool *last)
index 67f3a2af6aab1aadb5b492265d8469a37a1e8fd5..85f765cff6972357c835611a8a29464ce7a3970d 100644 (file)
@@ -372,15 +372,21 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
        [TCA_FLOW_PERTURB]      = { .type = NLA_U32 },
 };
 
-static void flow_destroy_filter_work(struct work_struct *work)
+static void __flow_destroy_filter(struct flow_filter *f)
 {
-       struct flow_filter *f = container_of(work, struct flow_filter, work);
-
-       rtnl_lock();
        del_timer_sync(&f->perturb_timer);
        tcf_exts_destroy(&f->exts);
        tcf_em_tree_destroy(&f->ematches);
+       tcf_exts_put_net(&f->exts);
        kfree(f);
+}
+
+static void flow_destroy_filter_work(struct work_struct *work)
+{
+       struct flow_filter *f = container_of(work, struct flow_filter, work);
+
+       rtnl_lock();
+       __flow_destroy_filter(f);
        rtnl_unlock();
 }
 
@@ -552,8 +558,10 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
 
        *arg = fnew;
 
-       if (fold)
+       if (fold) {
+               tcf_exts_get_net(&fold->exts);
                call_rcu(&fold->rcu, flow_destroy_filter);
+       }
        return 0;
 
 err2:
@@ -570,6 +578,7 @@ static int flow_delete(struct tcf_proto *tp, void *arg, bool *last)
        struct flow_filter *f = arg;
 
        list_del_rcu(&f->list);
+       tcf_exts_get_net(&f->exts);
        call_rcu(&f->rcu, flow_destroy_filter);
        *last = list_empty(&head->filters);
        return 0;
@@ -594,7 +603,10 @@ static void flow_destroy(struct tcf_proto *tp)
 
        list_for_each_entry_safe(f, next, &head->filters, list) {
                list_del_rcu(&f->list);
-               call_rcu(&f->rcu, flow_destroy_filter);
+               if (tcf_exts_get_net(&f->exts))
+                       call_rcu(&f->rcu, flow_destroy_filter);
+               else
+                       __flow_destroy_filter(f);
        }
        kfree_rcu(head, rcu);
 }
index 5b5722c8b32c1a276f7441fb67baa0d16ba24ff2..7a838d1c1c0059bddb3da24a59ad73689fec1877 100644 (file)
@@ -218,13 +218,19 @@ static int fl_init(struct tcf_proto *tp)
        return 0;
 }
 
+static void __fl_destroy_filter(struct cls_fl_filter *f)
+{
+       tcf_exts_destroy(&f->exts);
+       tcf_exts_put_net(&f->exts);
+       kfree(f);
+}
+
 static void fl_destroy_filter_work(struct work_struct *work)
 {
        struct cls_fl_filter *f = container_of(work, struct cls_fl_filter, work);
 
        rtnl_lock();
-       tcf_exts_destroy(&f->exts);
-       kfree(f);
+       __fl_destroy_filter(f);
        rtnl_unlock();
 }
 
@@ -318,7 +324,10 @@ static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
        if (!tc_skip_hw(f->flags))
                fl_hw_destroy_filter(tp, f);
        tcf_unbind_filter(tp, &f->res);
-       call_rcu(&f->rcu, fl_destroy_filter);
+       if (tcf_exts_get_net(&f->exts))
+               call_rcu(&f->rcu, fl_destroy_filter);
+       else
+               __fl_destroy_filter(f);
 }
 
 static void fl_destroy_sleepable(struct work_struct *work)
@@ -988,6 +997,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
                idr_replace_ext(&head->handle_idr, fnew, fnew->handle);
                list_replace_rcu(&fold->list, &fnew->list);
                tcf_unbind_filter(tp, &fold->res);
+               tcf_exts_get_net(&fold->exts);
                call_rcu(&fold->rcu, fl_destroy_filter);
        } else {
                list_add_tail_rcu(&fnew->list, &head->filters);
index 99183b8621ecb0543af91020167d13c193cad214..7f45e5ab8afcddcb95e4c9e4ead3ec5a9899d3ec 100644 (file)
@@ -122,13 +122,19 @@ static int fw_init(struct tcf_proto *tp)
        return 0;
 }
 
+static void __fw_delete_filter(struct fw_filter *f)
+{
+       tcf_exts_destroy(&f->exts);
+       tcf_exts_put_net(&f->exts);
+       kfree(f);
+}
+
 static void fw_delete_filter_work(struct work_struct *work)
 {
        struct fw_filter *f = container_of(work, struct fw_filter, work);
 
        rtnl_lock();
-       tcf_exts_destroy(&f->exts);
-       kfree(f);
+       __fw_delete_filter(f);
        rtnl_unlock();
 }
 
@@ -154,7 +160,10 @@ static void fw_destroy(struct tcf_proto *tp)
                        RCU_INIT_POINTER(head->ht[h],
                                         rtnl_dereference(f->next));
                        tcf_unbind_filter(tp, &f->res);
-                       call_rcu(&f->rcu, fw_delete_filter);
+                       if (tcf_exts_get_net(&f->exts))
+                               call_rcu(&f->rcu, fw_delete_filter);
+                       else
+                               __fw_delete_filter(f);
                }
        }
        kfree_rcu(head, rcu);
@@ -179,6 +188,7 @@ static int fw_delete(struct tcf_proto *tp, void *arg, bool *last)
                if (pfp == f) {
                        RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
                        tcf_unbind_filter(tp, &f->res);
+                       tcf_exts_get_net(&f->exts);
                        call_rcu(&f->rcu, fw_delete_filter);
                        ret = 0;
                        break;
@@ -299,6 +309,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
                RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next));
                rcu_assign_pointer(*fp, fnew);
                tcf_unbind_filter(tp, &f->res);
+               tcf_exts_get_net(&f->exts);
                call_rcu(&f->rcu, fw_delete_filter);
 
                *arg = fnew;
index c33f711b90198ab8b77bd314c289d09cbfe2d170..3684153cd8a9e1dfc680bcabf3c13e4fba2f507e 100644 (file)
@@ -44,13 +44,19 @@ static int mall_init(struct tcf_proto *tp)
        return 0;
 }
 
+static void __mall_destroy(struct cls_mall_head *head)
+{
+       tcf_exts_destroy(&head->exts);
+       tcf_exts_put_net(&head->exts);
+       kfree(head);
+}
+
 static void mall_destroy_work(struct work_struct *work)
 {
        struct cls_mall_head *head = container_of(work, struct cls_mall_head,
                                                  work);
        rtnl_lock();
-       tcf_exts_destroy(&head->exts);
-       kfree(head);
+       __mall_destroy(head);
        rtnl_unlock();
 }
 
@@ -109,7 +115,10 @@ static void mall_destroy(struct tcf_proto *tp)
        if (tc_should_offload(dev, head->flags))
                mall_destroy_hw_filter(tp, head, (unsigned long) head);
 
-       call_rcu(&head->rcu, mall_destroy_rcu);
+       if (tcf_exts_get_net(&head->exts))
+               call_rcu(&head->rcu, mall_destroy_rcu);
+       else
+               __mall_destroy(head);
 }
 
 static void *mall_get(struct tcf_proto *tp, u32 handle)
index 4b14ccd8b8f271aabecb97427fa3fa18f7484747..ac9a5b8825b9d572a0e60453fc6c68e82bdab320 100644 (file)
@@ -257,13 +257,19 @@ static int route4_init(struct tcf_proto *tp)
        return 0;
 }
 
+static void __route4_delete_filter(struct route4_filter *f)
+{
+       tcf_exts_destroy(&f->exts);
+       tcf_exts_put_net(&f->exts);
+       kfree(f);
+}
+
 static void route4_delete_filter_work(struct work_struct *work)
 {
        struct route4_filter *f = container_of(work, struct route4_filter, work);
 
        rtnl_lock();
-       tcf_exts_destroy(&f->exts);
-       kfree(f);
+       __route4_delete_filter(f);
        rtnl_unlock();
 }
 
@@ -297,7 +303,10 @@ static void route4_destroy(struct tcf_proto *tp)
                                        next = rtnl_dereference(f->next);
                                        RCU_INIT_POINTER(b->ht[h2], next);
                                        tcf_unbind_filter(tp, &f->res);
-                                       call_rcu(&f->rcu, route4_delete_filter);
+                                       if (tcf_exts_get_net(&f->exts))
+                                               call_rcu(&f->rcu, route4_delete_filter);
+                                       else
+                                               __route4_delete_filter(f);
                                }
                        }
                        RCU_INIT_POINTER(head->table[h1], NULL);
@@ -338,6 +347,7 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last)
 
                        /* Delete it */
                        tcf_unbind_filter(tp, &f->res);
+                       tcf_exts_get_net(&f->exts);
                        call_rcu(&f->rcu, route4_delete_filter);
 
                        /* Strip RTNL protected tree */
@@ -541,6 +551,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
        *arg = f;
        if (fold) {
                tcf_unbind_filter(tp, &fold->res);
+               tcf_exts_get_net(&fold->exts);
                call_rcu(&fold->rcu, route4_delete_filter);
        }
        return 0;
index bdbc541787f87d6bc0592122acef87a80b0b8d03..cf325625c99da83df0503a7a324d1b962540a34a 100644 (file)
@@ -285,13 +285,19 @@ static int rsvp_init(struct tcf_proto *tp)
        return -ENOBUFS;
 }
 
+static void __rsvp_delete_filter(struct rsvp_filter *f)
+{
+       tcf_exts_destroy(&f->exts);
+       tcf_exts_put_net(&f->exts);
+       kfree(f);
+}
+
 static void rsvp_delete_filter_work(struct work_struct *work)
 {
        struct rsvp_filter *f = container_of(work, struct rsvp_filter, work);
 
        rtnl_lock();
-       tcf_exts_destroy(&f->exts);
-       kfree(f);
+       __rsvp_delete_filter(f);
        rtnl_unlock();
 }
 
@@ -310,7 +316,10 @@ static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
         * grace period, since converted-to-rcu actions are relying on that
         * in cleanup() callback
         */
-       call_rcu(&f->rcu, rsvp_delete_filter_rcu);
+       if (tcf_exts_get_net(&f->exts))
+               call_rcu(&f->rcu, rsvp_delete_filter_rcu);
+       else
+               __rsvp_delete_filter(f);
 }
 
 static void rsvp_destroy(struct tcf_proto *tp)
index beaa95e09c25c26ba94155f03375d27156e9cbc4..a76937ee0b2dbf08f68574f727aa91d3a496fb4b 100644 (file)
@@ -139,13 +139,19 @@ static int tcindex_init(struct tcf_proto *tp)
        return 0;
 }
 
+static void __tcindex_destroy_rexts(struct tcindex_filter_result *r)
+{
+       tcf_exts_destroy(&r->exts);
+       tcf_exts_put_net(&r->exts);
+}
+
 static void tcindex_destroy_rexts_work(struct work_struct *work)
 {
        struct tcindex_filter_result *r;
 
        r = container_of(work, struct tcindex_filter_result, work);
        rtnl_lock();
-       tcf_exts_destroy(&r->exts);
+       __tcindex_destroy_rexts(r);
        rtnl_unlock();
 }
 
@@ -158,14 +164,20 @@ static void tcindex_destroy_rexts(struct rcu_head *head)
        tcf_queue_work(&r->work);
 }
 
+static void __tcindex_destroy_fexts(struct tcindex_filter *f)
+{
+       tcf_exts_destroy(&f->result.exts);
+       tcf_exts_put_net(&f->result.exts);
+       kfree(f);
+}
+
 static void tcindex_destroy_fexts_work(struct work_struct *work)
 {
        struct tcindex_filter *f = container_of(work, struct tcindex_filter,
                                                work);
 
        rtnl_lock();
-       tcf_exts_destroy(&f->result.exts);
-       kfree(f);
+       __tcindex_destroy_fexts(f);
        rtnl_unlock();
 }
 
@@ -210,10 +222,17 @@ found:
         * grace period, since converted-to-rcu actions are relying on that
         * in cleanup() callback
         */
-       if (f)
-               call_rcu(&f->rcu, tcindex_destroy_fexts);
-       else
-               call_rcu(&r->rcu, tcindex_destroy_rexts);
+       if (f) {
+               if (tcf_exts_get_net(&f->result.exts))
+                       call_rcu(&f->rcu, tcindex_destroy_fexts);
+               else
+                       __tcindex_destroy_fexts(f);
+       } else {
+               if (tcf_exts_get_net(&r->exts))
+                       call_rcu(&r->rcu, tcindex_destroy_rexts);
+               else
+                       __tcindex_destroy_rexts(r);
+       }
 
        *last = false;
        return 0;
index dadd1b3444970d1be4936e4f1a6cf8fd9a6d14a6..b58eccb21f039b676d051507ae971f6fc601654d 100644 (file)
@@ -399,6 +399,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n,
                           bool free_pf)
 {
        tcf_exts_destroy(&n->exts);
+       tcf_exts_put_net(&n->exts);
        if (n->ht_down)
                n->ht_down->refcnt--;
 #ifdef CONFIG_CLS_U32_PERF
@@ -476,6 +477,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
                                RCU_INIT_POINTER(*kp, key->next);
 
                                tcf_unbind_filter(tp, &key->res);
+                               tcf_exts_get_net(&key->exts);
                                call_rcu(&key->rcu, u32_delete_key_freepf_rcu);
                                return 0;
                        }
@@ -588,7 +590,10 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
                                         rtnl_dereference(n->next));
                        tcf_unbind_filter(tp, &n->res);
                        u32_remove_hw_knode(tp, n->handle);
-                       call_rcu(&n->rcu, u32_delete_key_freepf_rcu);
+                       if (tcf_exts_get_net(&n->exts))
+                               call_rcu(&n->rcu, u32_delete_key_freepf_rcu);
+                       else
+                               u32_destroy_key(n->tp, n, true);
                }
        }
 }
@@ -949,6 +954,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
 
                u32_replace_knode(tp, tp_c, new);
                tcf_unbind_filter(tp, &n->res);
+               tcf_exts_get_net(&n->exts);
                call_rcu(&n->rcu, u32_delete_key_rcu);
                return 0;
        }
index d396cb61a280d24b6c4bd4733885ff9693f1c673..eb866647a27ac3847f2a6eca3709945808dd70e6 100644 (file)
@@ -14201,7 +14201,7 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
-       u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
+       u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid);
 
        if (!nlportid)
                return false;
index 82d20ee34581bf8944e004f2b0df10b4bf4580ec..347ab31574d509ac9edd448bcbb7501a05f5ac2d 100644 (file)
@@ -266,8 +266,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                goto lock;
        }
 
-       daddr = (xfrm_address_t *)(skb_network_header(skb) +
-                                  XFRM_SPI_SKB_CB(skb)->daddroff);
        family = XFRM_SPI_SKB_CB(skb)->family;
 
        /* if tunnel is present override skb->mark value with tunnel i_key */
@@ -294,6 +292,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                goto drop;
        }
 
+       daddr = (xfrm_address_t *)(skb_network_header(skb) +
+                                  XFRM_SPI_SKB_CB(skb)->daddroff);
        do {
                if (skb->sp->len == XFRM_MAX_DEPTH) {
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
index 8cafb3c0a4ac501348c5227f1450b800fb834c0e..6eb228a70131069b74663d72c415daf83e83871b 100644 (file)
@@ -1361,36 +1361,29 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
        struct net *net = xp_net(policy);
        int nx;
        int i, error;
-       xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
-       xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
        xfrm_address_t tmp;
 
        for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
                struct xfrm_state *x;
-               xfrm_address_t *remote = daddr;
-               xfrm_address_t *local  = saddr;
+               xfrm_address_t *local;
+               xfrm_address_t *remote;
                struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
 
-               if (tmpl->mode == XFRM_MODE_TUNNEL ||
-                   tmpl->mode == XFRM_MODE_BEET) {
-                       remote = &tmpl->id.daddr;
-                       local = &tmpl->saddr;
-                       if (xfrm_addr_any(local, tmpl->encap_family)) {
-                               error = xfrm_get_saddr(net, fl->flowi_oif,
-                                                      &tmp, remote,
-                                                      tmpl->encap_family, 0);
-                               if (error)
-                                       goto fail;
-                               local = &tmp;
-                       }
+               remote = &tmpl->id.daddr;
+               local = &tmpl->saddr;
+               if (xfrm_addr_any(local, tmpl->encap_family)) {
+                       error = xfrm_get_saddr(net, fl->flowi_oif,
+                                              &tmp, remote,
+                                              tmpl->encap_family, 0);
+                       if (error)
+                               goto fail;
+                       local = &tmp;
                }
 
                x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
 
                if (x && x->km.state == XFRM_STATE_VALID) {
                        xfrm[nx++] = x;
-                       daddr = remote;
-                       saddr = local;
                        continue;
                }
                if (x) {
@@ -1787,19 +1780,23 @@ void xfrm_policy_cache_flush(void)
        put_online_cpus();
 }
 
-static bool xfrm_pol_dead(struct xfrm_dst *xdst)
+static bool xfrm_xdst_can_reuse(struct xfrm_dst *xdst,
+                               struct xfrm_state * const xfrm[],
+                               int num)
 {
-       unsigned int num_pols = xdst->num_pols;
-       unsigned int pol_dead = 0, i;
+       const struct dst_entry *dst = &xdst->u.dst;
+       int i;
 
-       for (i = 0; i < num_pols; i++)
-               pol_dead |= xdst->pols[i]->walk.dead;
+       if (xdst->num_xfrms != num)
+               return false;
 
-       /* Mark DST_OBSOLETE_DEAD to fail the next xfrm_dst_check() */
-       if (pol_dead)
-               xdst->u.dst.obsolete = DST_OBSOLETE_DEAD;
+       for (i = 0; i < num; i++) {
+               if (!dst || dst->xfrm != xfrm[i])
+                       return false;
+               dst = dst->child;
+       }
 
-       return pol_dead;
+       return xfrm_bundle_ok(xdst);
 }
 
 static struct xfrm_dst *
@@ -1813,26 +1810,28 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
        struct dst_entry *dst;
        int err;
 
+       /* Try to instantiate a bundle */
+       err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
+       if (err <= 0) {
+               if (err != 0 && err != -EAGAIN)
+                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
+               return ERR_PTR(err);
+       }
+
        xdst = this_cpu_read(xfrm_last_dst);
        if (xdst &&
            xdst->u.dst.dev == dst_orig->dev &&
            xdst->num_pols == num_pols &&
-           !xfrm_pol_dead(xdst) &&
            memcmp(xdst->pols, pols,
                   sizeof(struct xfrm_policy *) * num_pols) == 0 &&
-           xfrm_bundle_ok(xdst)) {
+           xfrm_xdst_can_reuse(xdst, xfrm, err)) {
                dst_hold(&xdst->u.dst);
+               while (err > 0)
+                       xfrm_state_put(xfrm[--err]);
                return xdst;
        }
 
        old = xdst;
-       /* Try to instantiate a bundle */
-       err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
-       if (err <= 0) {
-               if (err != 0 && err != -EAGAIN)
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
-               return ERR_PTR(err);
-       }
 
        dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig);
        if (IS_ERR(dst)) {
index d12cc944b69621e44b77a7a6f6abc8d3e6b76bb4..95cd06f4ec1ee47c017552bcf1b4f658e13c1112 100644 (file)
@@ -125,12 +125,12 @@ static int cn_test_want_notify(void)
 #endif
 
 static u32 cn_test_timer_counter;
-static void cn_test_timer_func(unsigned long __data)
+static void cn_test_timer_func(struct timer_list *unused)
 {
        struct cn_msg *m;
        char data[32];
 
-       pr_debug("%s: timer fired with data %lu\n", __func__, __data);
+       pr_debug("%s: timer fired\n", __func__);
 
        m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
        if (m) {
@@ -168,7 +168,7 @@ static int cn_test_init(void)
                goto err_out;
        }
 
-       setup_timer(&cn_test_timer, cn_test_timer_func, 0);
+       timer_setup(&cn_test_timer, cn_test_timer_func, 0);
        mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000));
 
        pr_info("initialized with id={%u.%u}\n",
index 68739bc4fc6a64f61df13004b0ed2d7963255279..880e54d2c082730a40f8441449edd62c7a5c162e 100644 (file)
@@ -1,5 +1,5 @@
 # builds the kprobes example kernel modules;
 # then to use one (as root):  insmod <module_name.ko>
 
-obj-$(CONFIG_SAMPLE_KPROBES) += kprobe_example.o jprobe_example.o
+obj-$(CONFIG_SAMPLE_KPROBES) += kprobe_example.o
 obj-$(CONFIG_SAMPLE_KRETPROBES) += kretprobe_example.o
diff --git a/samples/kprobes/jprobe_example.c b/samples/kprobes/jprobe_example.c
deleted file mode 100644 (file)
index e3c0a40..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Here's a sample kernel module showing the use of jprobes to dump
- * the arguments of _do_fork().
- *
- * For more information on theory of operation of jprobes, see
- * Documentation/kprobes.txt
- *
- * Build and insert the kernel module as done in the kprobe example.
- * You will see the trace data in /var/log/messages and on the
- * console whenever _do_fork() is invoked to create a new process.
- * (Some messages may be suppressed if syslogd is configured to
- * eliminate duplicate messages.)
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kprobes.h>
-
-/*
- * Jumper probe for _do_fork.
- * Mirror principle enables access to arguments of the probed routine
- * from the probe handler.
- */
-
-/* Proxy routine having the same arguments as actual _do_fork() routine */
-static long j_do_fork(unsigned long clone_flags, unsigned long stack_start,
-             unsigned long stack_size, int __user *parent_tidptr,
-             int __user *child_tidptr, unsigned long tls)
-{
-       pr_info("jprobe: clone_flags = 0x%lx, stack_start = 0x%lx "
-               "stack_size = 0x%lx\n", clone_flags, stack_start, stack_size);
-
-       /* Always end with a call to jprobe_return(). */
-       jprobe_return();
-       return 0;
-}
-
-static struct jprobe my_jprobe = {
-       .entry                  = j_do_fork,
-       .kp = {
-               .symbol_name    = "_do_fork",
-       },
-};
-
-static int __init jprobe_init(void)
-{
-       int ret;
-
-       ret = register_jprobe(&my_jprobe);
-       if (ret < 0) {
-               pr_err("register_jprobe failed, returned %d\n", ret);
-               return -1;
-       }
-       pr_info("Planted jprobe at %p, handler addr %p\n",
-              my_jprobe.kp.addr, my_jprobe.entry);
-       return 0;
-}
-
-static void __exit jprobe_exit(void)
-{
-       unregister_jprobe(&my_jprobe);
-       pr_info("jprobe at %p unregistered\n", my_jprobe.kp.addr);
-}
-
-module_init(jprobe_init)
-module_exit(jprobe_exit)
-MODULE_LICENSE("GPL");
index 88b3e2d227ae3bc1534fc8146fa66ac14887ecc1..67de3b774bc9024c93339b9e84a18835e9efabc3 100644 (file)
@@ -47,6 +47,10 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
                        " pstate = 0x%lx\n",
                p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate);
 #endif
+#ifdef CONFIG_S390
+       pr_info("<%s> pre_handler: p->addr, 0x%p, ip = 0x%lx, flags = 0x%lx\n",
+               p->symbol_name, p->addr, regs->psw.addr, regs->flags);
+#endif
 
        /* A dump_stack() here will give a stack backtrace */
        return 0;
@@ -76,6 +80,10 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs,
        pr_info("<%s> post_handler: p->addr = 0x%p, pstate = 0x%lx\n",
                p->symbol_name, p->addr, (long)regs->pstate);
 #endif
+#ifdef CONFIG_S390
+       pr_info("<%s> pre_handler: p->addr, 0x%p, flags = 0x%lx\n",
+               p->symbol_name, p->addr, regs->flags);
+#endif
 }
 
 /*
index 49db1def1721cdedc09b6a4e459b1cd41f82a749..f42ce551bb48f5cc8389272024fe913c1d78bfe5 100644 (file)
@@ -65,7 +65,7 @@ static struct mic_info mic_list;
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)        _ALIGN(addr, PAGE_SIZE)
 
-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+#define READ_ONCE(x) (*(volatile typeof(x) *)&(x))
 
 #define GSO_ENABLED            1
 #define MAX_GSO_SIZE           (64 * 1024)
@@ -382,7 +382,7 @@ disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy,
 
 static inline __u16 read_avail_idx(struct mic_vring *vr)
 {
-       return ACCESS_ONCE(vr->info->avail_idx);
+       return READ_ONCE(vr->info->avail_idx);
 }
 
 static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr,
@@ -523,7 +523,7 @@ spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr)
 {
        __u16 avail_idx = read_avail_idx(vr);
 
-       while (avail_idx == le16toh(ACCESS_ONCE(vr->vr.avail->idx))) {
+       while (avail_idx == le16toh(READ_ONCE(vr->vr.avail->idx))) {
 #ifdef DEBUG
                mpsslog("%s %s waiting for desc avail %d info_avail %d\n",
                        mic->name, __func__,
index bb831d49bcfd5edc41c30383ffab81ef9d51167b..e63af4e19382af618b365d5b9ebe50321d0b0407 100644 (file)
@@ -259,7 +259,7 @@ ifneq ($(SKIP_STACK_VALIDATION),1)
 
 __objtool_obj := $(objtree)/tools/objtool/objtool
 
-objtool_args = $(if $(CONFIG_ORC_UNWINDER),orc generate,check)
+objtool_args = $(if $(CONFIG_UNWINDER_ORC),orc generate,check)
 
 ifndef CONFIG_FRAME_POINTER
 objtool_args += --no-fp
diff --git a/scripts/documentation-file-ref-check b/scripts/documentation-file-ref-check
new file mode 100755 (executable)
index 0000000..bc16599
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+# Treewide grep for references to files under Documentation, and report
+# non-existing files in stderr.
+
+for f in $(git ls-files); do
+       for ref in $(grep -ho "Documentation/[A-Za-z0-9_.,~/*+-]*" "$f"); do
+               # presume trailing . and , are not part of the name
+               ref=${ref%%[.,]}
+
+               # use ls to handle wildcards
+               if ! ls $ref >/dev/null 2>&1; then
+                       echo "$f: $ref" >&2
+               fi
+       done
+done
diff --git a/scripts/find-unused-docs.sh b/scripts/find-unused-docs.sh
new file mode 100755 (executable)
index 0000000..3f46f89
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/bash
+# (c) 2017, Jonathan Corbet <corbet@lwn.net>
+#           sayli karnik <karniksayli1995@gmail.com>
+#
+# This script detects files with kernel-doc comments for exported functions
+# that are not included in documentation.
+#
+# usage: Run 'scripts/find-unused-docs.sh directory' from top level of kernel
+#       tree.
+#
+# example: $scripts/find-unused-docs.sh drivers/scsi
+#
+# Licensed under the terms of the GNU GPL License
+
+if ! [ -d "Documentation" ]; then
+       echo "Run from top level of kernel tree"
+       exit 1
+fi
+
+if [ "$#" -ne 1 ]; then
+       echo "Usage: scripts/find-unused-docs.sh directory"
+       exit 1
+fi
+
+if ! [ -d "$1" ]; then
+       echo "Directory $1 doesn't exist"
+       exit 1
+fi
+
+cd "$( dirname "${BASH_SOURCE[0]}" )"
+cd ..
+
+cd Documentation/
+
+echo "The following files contain kerneldoc comments for exported functions \
+that are not used in the formatted documentation"
+
+# FILES INCLUDED
+
+files_included=($(grep -rHR ".. kernel-doc" --include \*.rst | cut -d " " -f 3))
+
+declare -A FILES_INCLUDED
+
+for each in "${files_included[@]}"; do
+       FILES_INCLUDED[$each]="$each"
+       done
+
+cd ..
+
+# FILES NOT INCLUDED
+
+for file in `find $1 -name '*.c'`; do
+
+       if [[ ${FILES_INCLUDED[$file]+_} ]]; then
+       continue;
+       fi
+       str=$(scripts/kernel-doc -text -export "$file" 2>/dev/null)
+       if [[ -n "$str" ]]; then
+       echo "$file"
+       fi
+       done
+
index 4d1ea96e8794c19c99bae029f57377c076ea1f46..a18bca7209957302ebcbb4977f400b375b2ef274 100755 (executable)
@@ -34,7 +34,7 @@ do
        sed -r \
                -e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \
                -e 's/__attribute_const__([ \t]|$)/\1/g' \
-               -e 's@^#include <linux/compiler.h>@@' \
+               -e 's@^#include <linux/compiler(|_types).h>@@' \
                -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \
                -e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \
                -e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \
index 9d3eafea58f06a048f60291409e89ad5942d0a12..67d051edd6151b8f3264840349cd4f985d815c1d 100755 (executable)
@@ -2168,7 +2168,7 @@ sub dump_struct($$) {
     my $nested;
 
     if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
-       #my $decl_type = $1;
+       my $decl_type = $1;
        $declaration_name = $2;
        my $members = $3;
 
@@ -2194,7 +2194,7 @@ sub dump_struct($$) {
        $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
 
        create_parameterlist($members, ';', $file);
-       check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
+       check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual, $nested);
 
        output_declaration($declaration_name,
                           'struct',
@@ -2226,6 +2226,8 @@ sub dump_enum($$) {
     if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
        $declaration_name = $1;
        my $members = $2;
+       my %_members;
+
        $members =~ s/\s+$//;
 
        foreach my $arg (split ',', $members) {
@@ -2236,9 +2238,16 @@ sub dump_enum($$) {
                print STDERR "${file}:$.: warning: Enum value '$arg' ".
                    "not described in enum '$declaration_name'\n";
            }
-
+           $_members{$arg} = 1;
        }
 
+       while (my ($k, $v) = each %parameterdescs) {
+           if (!exists($_members{$k})) {
+            print STDERR "${file}:$.: warning: Excess enum value " .
+                         "'$k' description in '$declaration_name'\n";
+           }
+        }
+
        output_declaration($declaration_name,
                           'enum',
                           {'enum' => $declaration_name,
@@ -2506,7 +2515,7 @@ sub check_sections($$$$$$) {
                        } else {
                                if ($nested !~ m/\Q$sects[$sx]\E/) {
                                    print STDERR "${file}:$.: warning: " .
-                                       "Excess struct/union/enum/typedef member " .
+                                       "Excess $decl_type member " .
                                        "'$sects[$sx]' " .
                                        "description in '$decl_name'\n";
                                    ++$warnings;
diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl
new file mode 100755 (executable)
index 0000000..2977371
--- /dev/null
@@ -0,0 +1,305 @@
+#!/usr/bin/env perl
+#
+# (c) 2017 Tobin C. Harding <me@tobin.cc>
+# Licensed under the terms of the GNU GPL License version 2
+#
+# leaking_addresses.pl: Scan 64 bit kernel for potential leaking addresses.
+#  - Scans dmesg output.
+#  - Walks directory tree and parses each file (for each directory in @DIRS).
+#
+# You can configure the behaviour of the script;
+#
+#  - By adding paths, for directories you do not want to walk;
+#     absolute paths: @skip_walk_dirs_abs
+#     directory names: @skip_walk_dirs_any
+#
+#  - By adding paths, for files you do not want to parse;
+#     absolute paths: @skip_parse_files_abs
+#     file names: @skip_parse_files_any
+#
+# The use of @skip_xxx_xxx_any causes files to be skipped where ever they occur.
+# For example adding 'fd' to @skip_walk_dirs_any causes the fd/ directory to be
+# skipped for all PID sub-directories of /proc
+#
+# The same thing can be achieved by passing command line options to --dont-walk
+# and --dont-parse. If absolute paths are supplied to these options they are
+# appended to the @skip_xxx_xxx_abs arrays. If file names are supplied to these
+# options, they are appended to the @skip_xxx_xxx_any arrays.
+#
+# Use --debug to output path before parsing, this is useful to find files that
+# cause the script to choke.
+#
+# You may like to set kptr_restrict=2 before running script
+# (see Documentation/sysctl/kernel.txt).
+
+use warnings;
+use strict;
+use POSIX;
+use File::Basename;
+use File::Spec;
+use Cwd 'abs_path';
+use Term::ANSIColor qw(:constants);
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $P = $0;
+my $V = '0.01';
+
+# Directories to scan.
+my @DIRS = ('/proc', '/sys');
+
+# Command line options.
+my $help = 0;
+my $debug = 0;
+my @dont_walk = ();
+my @dont_parse = ();
+
+# Do not parse these files (absolute path).
+my @skip_parse_files_abs = ('/proc/kmsg',
+                           '/proc/kcore',
+                           '/proc/fs/ext4/sdb1/mb_groups',
+                           '/proc/1/fd/3',
+                           '/sys/kernel/debug/tracing/trace_pipe',
+                           '/sys/kernel/security/apparmor/revision');
+
+# Do not parse thes files under any subdirectory.
+my @skip_parse_files_any = ('0',
+                           '1',
+                           '2',
+                           'pagemap',
+                           'events',
+                           'access',
+                           'registers',
+                           'snapshot_raw',
+                           'trace_pipe_raw',
+                           'ptmx',
+                           'trace_pipe');
+
+# Do not walk these directories (absolute path).
+my @skip_walk_dirs_abs = ();
+
+# Do not walk these directories under any subdirectory.
+my @skip_walk_dirs_any = ('self',
+                         'thread-self',
+                         'cwd',
+                         'fd',
+                         'stderr',
+                         'stdin',
+                         'stdout');
+
+sub help
+{
+       my ($exitcode) = @_;
+
+       print << "EOM";
+Usage: $P [OPTIONS]
+Version: $V
+
+Options:
+
+       --dont-walk=<dir>      Don't walk tree starting at <dir>.
+       --dont-parse=<file>    Don't parse <file>.
+       -d, --debug                Display debugging output.
+       -h, --help, --version      Display this help and exit.
+
+If an absolute path is passed to --dont_XXX then this path is skipped. If a
+single filename is passed then this file/directory will be skipped when
+appearing under any subdirectory.
+
+Example:
+
+       # Just scan dmesg output.
+       scripts/leaking_addresses.pl --dont_walk_abs /proc --dont_walk_abs /sys
+
+Scans the running (64 bit) kernel for potential leaking addresses.
+
+EOM
+       exit($exitcode);
+}
+
+GetOptions(
+       'dont-walk=s'           => \@dont_walk,
+       'dont-parse=s'          => \@dont_parse,
+       'd|debug'               => \$debug,
+       'h|help'                => \$help,
+       'version'               => \$help
+) or help(1);
+
+help(0) if ($help);
+
+push_to_global();
+
+parse_dmesg();
+walk(@DIRS);
+
+exit 0;
+
+sub debug_arrays
+{
+       print 'dirs_any: ' . join(", ", @skip_walk_dirs_any) . "\n";
+       print 'dirs_abs: ' . join(", ", @skip_walk_dirs_abs) . "\n";
+       print 'parse_any: ' . join(", ", @skip_parse_files_any) . "\n";
+       print 'parse_abs: ' . join(", ", @skip_parse_files_abs) . "\n";
+}
+
+sub dprint
+{
+       printf(STDERR @_) if $debug;
+}
+
+sub push_in_abs_any
+{
+       my ($in, $abs, $any) = @_;
+
+       foreach my $path (@$in) {
+               if (File::Spec->file_name_is_absolute($path)) {
+                       push @$abs, $path;
+               } elsif (index($path,'/') == -1) {
+                       push @$any, $path;
+               } else {
+                       print 'path error: ' . $path;
+               }
+       }
+}
+
+# Push command line options to global arrays.
+sub push_to_global
+{
+       push_in_abs_any(\@dont_walk, \@skip_walk_dirs_abs, \@skip_walk_dirs_any);
+       push_in_abs_any(\@dont_parse, \@skip_parse_files_abs, \@skip_parse_files_any);
+}
+
+sub is_false_positive
+{
+        my ($match) = @_;
+
+        if ($match =~ '\b(0x)?(f|F){16}\b' or
+            $match =~ '\b(0x)?0{16}\b') {
+                return 1;
+        }
+
+        # vsyscall memory region, we should probably check against a range here.
+        if ($match =~ '\bf{10}600000\b' or
+            $match =~ '\bf{10}601000\b') {
+                return 1;
+        }
+
+        return 0;
+}
+
+# True if argument potentially contains a kernel address.
+sub may_leak_address
+{
+        my ($line) = @_;
+        my $address = '\b(0x)?ffff[[:xdigit:]]{12}\b';
+
+        # Signal masks.
+        if ($line =~ '^SigBlk:' or
+            $line =~ '^SigCgt:') {
+                return 0;
+        }
+
+        if ($line =~ '\bKEY=[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or
+            $line =~ '\b[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b') {
+               return 0;
+        }
+
+        while (/($address)/g) {
+                if (!is_false_positive($1)) {
+                        return 1;
+                }
+        }
+
+        return 0;
+}
+
+sub parse_dmesg
+{
+       open my $cmd, '-|', 'dmesg';
+       while (<$cmd>) {
+               if (may_leak_address($_)) {
+                       print 'dmesg: ' . $_;
+               }
+       }
+       close $cmd;
+}
+
+# True if we should skip this path.
+sub skip
+{
+       my ($path, $paths_abs, $paths_any) = @_;
+
+       foreach (@$paths_abs) {
+               return 1 if (/^$path$/);
+       }
+
+       my($filename, $dirs, $suffix) = fileparse($path);
+       foreach (@$paths_any) {
+               return 1 if (/^$filename$/);
+       }
+
+       return 0;
+}
+
+sub skip_parse
+{
+       my ($path) = @_;
+       return skip($path, \@skip_parse_files_abs, \@skip_parse_files_any);
+}
+
+sub parse_file
+{
+       my ($file) = @_;
+
+       if (! -R $file) {
+               return;
+       }
+
+       if (skip_parse($file)) {
+               dprint "skipping file: $file\n";
+               return;
+       }
+       dprint "parsing: $file\n";
+
+       open my $fh, "<", $file or return;
+       while ( <$fh> ) {
+               if (may_leak_address($_)) {
+                       print $file . ': ' . $_;
+               }
+       }
+       close $fh;
+}
+
+
+# True if we should skip walking this directory.
+sub skip_walk
+{
+       my ($path) = @_;
+       return skip($path, \@skip_walk_dirs_abs, \@skip_walk_dirs_any)
+}
+
+# Recursively walk directory tree.
+sub walk
+{
+       my @dirs = @_;
+       my %seen;
+
+       while (my $pwd = shift @dirs) {
+               next if (skip_walk($pwd));
+               next if (!opendir(DIR, $pwd));
+               my @files = readdir(DIR);
+               closedir(DIR);
+
+               foreach my $file (@files) {
+                       next if ($file eq '.' or $file eq '..');
+
+                       my $path = "$pwd/$file";
+                       next if (-l $path);
+
+                       if (-d $path) {
+                               push @dirs, $path;
+                       } else {
+                               parse_file($path);
+                       }
+               }
+       }
+}
index 98314b400a95cd819ad9352518440de1e48db581..f51cf977c65b22131ff1ac7aa568015771e94f65 100644 (file)
@@ -1963,7 +1963,7 @@ static void read_symbols(char *modname)
        }
 
        license = get_modinfo(info.modinfo, info.modinfo_len, "license");
-       if (info.modinfo && !license && !is_vmlinux(modname))
+       if (!license && !is_vmlinux(modname))
                warn("modpost: missing MODULE_LICENSE() in %s\n"
                     "see include/linux/module.h for "
                     "more information\n", modname);
index 436b3a7223571e6553564e0f2731f0af0aa9010e..f546707a2bbbe1c96a52c215baf492d70e23c00a 100644 (file)
 
 #include "match.h"
 
-/* Provide our own test for whether a write lock is held for asserts
- * this is because on none SMP systems write_can_lock will always
- * resolve to true, which is what you want for code making decisions
- * based on it, but wrong for asserts checking that the lock is held
- */
-#ifdef CONFIG_SMP
-#define write_is_locked(X) !write_can_lock(X)
-#else
-#define write_is_locked(X) (1)
-#endif /* CONFIG_SMP */
-
 /*
  * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
  * which is not related to profile accesses.
index 66fb9ede9447adc71e3fd27a0b90d306b095c0fe..7ca0032e7ba96ef374aefe98d47acb919f3f81d3 100644 (file)
@@ -128,7 +128,7 @@ static inline int map_signal_num(int sig)
                return SIGUNKNOWN;
        else if (sig >= SIGRTMIN)
                return sig - SIGRTMIN + 128;    /* rt sigs mapped to 128 */
-       else if (sig <= MAXMAPPED_SIG)
+       else if (sig < MAXMAPPED_SIG)
                return sig_map[sig];
        return SIGUNKNOWN;
 }
@@ -163,7 +163,7 @@ static void audit_signal_cb(struct audit_buffer *ab, void *va)
                        audit_signal_mask(ab, aad(sa)->denied);
                }
        }
-       if (aad(sa)->signal <= MAXMAPPED_SIG)
+       if (aad(sa)->signal < MAXMAPPED_SIG)
                audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]);
        else
                audit_log_format(ab, " signal=rtmin+%d",
index c5b99b954580c940d3cc3659a48c10b22752c1f0..ad28e03a6f30341ab013e23cc2641f144ab44ea1 100644 (file)
@@ -80,7 +80,7 @@ void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new)
 
        AA_BUG(!orig);
        AA_BUG(!new);
-       AA_BUG(!write_is_locked(&labels_set(orig)->lock));
+       lockdep_assert_held_exclusive(&labels_set(orig)->lock);
 
        tmp = rcu_dereference_protected(orig->proxy->label,
                                        &labels_ns(orig)->lock);
@@ -571,7 +571,7 @@ static bool __label_remove(struct aa_label *label, struct aa_label *new)
 
        AA_BUG(!ls);
        AA_BUG(!label);
-       AA_BUG(!write_is_locked(&ls->lock));
+       lockdep_assert_held_exclusive(&ls->lock);
 
        if (new)
                __aa_proxy_redirect(label, new);
@@ -608,7 +608,7 @@ static bool __label_replace(struct aa_label *old, struct aa_label *new)
        AA_BUG(!ls);
        AA_BUG(!old);
        AA_BUG(!new);
-       AA_BUG(!write_is_locked(&ls->lock));
+       lockdep_assert_held_exclusive(&ls->lock);
        AA_BUG(new->flags & FLAG_IN_TREE);
 
        if (!label_is_stale(old))
@@ -645,7 +645,7 @@ static struct aa_label *__label_insert(struct aa_labelset *ls,
        AA_BUG(!ls);
        AA_BUG(!label);
        AA_BUG(labels_set(label) != ls);
-       AA_BUG(!write_is_locked(&ls->lock));
+       lockdep_assert_held_exclusive(&ls->lock);
        AA_BUG(label->flags & FLAG_IN_TREE);
 
        /* Figure out where to put new node */
index fc46f5b85251049265a53929e37d5822240a64e3..4f8e0934095679f71e9674d4a567c6c1fe492f9e 100644 (file)
@@ -536,7 +536,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size)
 static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
                                          struct linux_binprm *bprm,
                                          bool *effective,
-                                         bool *has_cap)
+                                         bool *has_fcap)
 {
        struct cred *new = bprm->cred;
        unsigned i;
@@ -546,7 +546,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
                *effective = true;
 
        if (caps->magic_etc & VFS_CAP_REVISION_MASK)
-               *has_cap = true;
+               *has_fcap = true;
 
        CAP_FOR_EACH_U32(i) {
                __u32 permitted = caps->permitted.cap[i];
@@ -653,7 +653,7 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
  * its xattrs and, if present, apply them to the proposed credentials being
  * constructed by execve().
  */
-static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap)
+static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_fcap)
 {
        int rc = 0;
        struct cpu_vfs_cap_data vcaps;
@@ -684,7 +684,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c
                goto out;
        }
 
-       rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap);
+       rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_fcap);
        if (rc == -EINVAL)
                printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
                       __func__, rc, bprm->filename);
@@ -696,6 +696,115 @@ out:
        return rc;
 }
 
+static inline bool root_privileged(void) { return !issecure(SECURE_NOROOT); }
+
+static inline bool __is_real(kuid_t uid, struct cred *cred)
+{ return uid_eq(cred->uid, uid); }
+
+static inline bool __is_eff(kuid_t uid, struct cred *cred)
+{ return uid_eq(cred->euid, uid); }
+
+static inline bool __is_suid(kuid_t uid, struct cred *cred)
+{ return !__is_real(uid, cred) && __is_eff(uid, cred); }
+
+/*
+ * handle_privileged_root - Handle case of privileged root
+ * @bprm: The execution parameters, including the proposed creds
+ * @has_fcap: Are any file capabilities set?
+ * @effective: Do we have effective root privilege?
+ * @root_uid: This namespace' root UID WRT initial USER namespace
+ *
+ * Handle the case where root is privileged and hasn't been neutered by
+ * SECURE_NOROOT.  If file capabilities are set, they won't be combined with
+ * set UID root and nothing is changed.  If we are root, cap_permitted is
+ * updated.  If we have become set UID root, the effective bit is set.
+ */
+static void handle_privileged_root(struct linux_binprm *bprm, bool has_fcap,
+                                  bool *effective, kuid_t root_uid)
+{
+       const struct cred *old = current_cred();
+       struct cred *new = bprm->cred;
+
+       if (!root_privileged())
+               return;
+       /*
+        * If the legacy file capability is set, then don't set privs
+        * for a setuid root binary run by a non-root user.  Do set it
+        * for a root user just to cause least surprise to an admin.
+        */
+       if (has_fcap && __is_suid(root_uid, new)) {
+               warn_setuid_and_fcaps_mixed(bprm->filename);
+               return;
+       }
+       /*
+        * To support inheritance of root-permissions and suid-root
+        * executables under compatibility mode, we override the
+        * capability sets for the file.
+        */
+       if (__is_eff(root_uid, new) || __is_real(root_uid, new)) {
+               /* pP' = (cap_bset & ~0) | (pI & ~0) */
+               new->cap_permitted = cap_combine(old->cap_bset,
+                                                old->cap_inheritable);
+       }
+       /*
+        * If only the real uid is 0, we do not set the effective bit.
+        */
+       if (__is_eff(root_uid, new))
+               *effective = true;
+}
+
+#define __cap_gained(field, target, source) \
+       !cap_issubset(target->cap_##field, source->cap_##field)
+#define __cap_grew(target, source, cred) \
+       !cap_issubset(cred->cap_##target, cred->cap_##source)
+#define __cap_full(field, cred) \
+       cap_issubset(CAP_FULL_SET, cred->cap_##field)
+
+static inline bool __is_setuid(struct cred *new, const struct cred *old)
+{ return !uid_eq(new->euid, old->uid); }
+
+static inline bool __is_setgid(struct cred *new, const struct cred *old)
+{ return !gid_eq(new->egid, old->gid); }
+
+/*
+ * 1) Audit candidate if current->cap_effective is set
+ *
+ * We do not bother to audit if 3 things are true:
+ *   1) cap_effective has all caps
+ *   2) we became root *OR* are were already root
+ *   3) root is supposed to have all caps (SECURE_NOROOT)
+ * Since this is just a normal root execing a process.
+ *
+ * Number 1 above might fail if you don't have a full bset, but I think
+ * that is interesting information to audit.
+ *
+ * A number of other conditions require logging:
+ * 2) something prevented setuid root getting all caps
+ * 3) non-setuid root gets fcaps
+ * 4) non-setuid root gets ambient
+ */
+static inline bool nonroot_raised_pE(struct cred *new, const struct cred *old,
+                                    kuid_t root, bool has_fcap)
+{
+       bool ret = false;
+
+       if ((__cap_grew(effective, ambient, new) &&
+            !(__cap_full(effective, new) &&
+              (__is_eff(root, new) || __is_real(root, new)) &&
+              root_privileged())) ||
+           (root_privileged() &&
+            __is_suid(root, new) &&
+            !__cap_full(effective, new)) ||
+           (!__is_setuid(new, old) &&
+            ((has_fcap &&
+              __cap_gained(permitted, new, old)) ||
+             __cap_gained(ambient, new, old))))
+
+               ret = true;
+
+       return ret;
+}
+
 /**
  * cap_bprm_set_creds - Set up the proposed credentials for execve().
  * @bprm: The execution parameters, including the proposed creds
@@ -708,61 +817,33 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
 {
        const struct cred *old = current_cred();
        struct cred *new = bprm->cred;
-       bool effective, has_cap = false, is_setid;
+       bool effective = false, has_fcap = false, is_setid;
        int ret;
        kuid_t root_uid;
 
        if (WARN_ON(!cap_ambient_invariant_ok(old)))
                return -EPERM;
 
-       effective = false;
-       ret = get_file_caps(bprm, &effective, &has_cap);
+       ret = get_file_caps(bprm, &effective, &has_fcap);
        if (ret < 0)
                return ret;
 
        root_uid = make_kuid(new->user_ns, 0);
 
-       if (!issecure(SECURE_NOROOT)) {
-               /*
-                * If the legacy file capability is set, then don't set privs
-                * for a setuid root binary run by a non-root user.  Do set it
-                * for a root user just to cause least surprise to an admin.
-                */
-               if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) {
-                       warn_setuid_and_fcaps_mixed(bprm->filename);
-                       goto skip;
-               }
-               /*
-                * To support inheritance of root-permissions and suid-root
-                * executables under compatibility mode, we override the
-                * capability sets for the file.
-                *
-                * If only the real uid is 0, we do not set the effective bit.
-                */
-               if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) {
-                       /* pP' = (cap_bset & ~0) | (pI & ~0) */
-                       new->cap_permitted = cap_combine(old->cap_bset,
-                                                        old->cap_inheritable);
-               }
-               if (uid_eq(new->euid, root_uid))
-                       effective = true;
-       }
-skip:
+       handle_privileged_root(bprm, has_fcap, &effective, root_uid);
 
        /* if we have fs caps, clear dangerous personality flags */
-       if (!cap_issubset(new->cap_permitted, old->cap_permitted))
+       if (__cap_gained(permitted, new, old))
                bprm->per_clear |= PER_CLEAR_ON_SETID;
 
-
        /* Don't let someone trace a set[ug]id/setpcap binary with the revised
         * credentials unless they have the appropriate permit.
         *
         * In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
         */
-       is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid);
+       is_setid = __is_setuid(new, old) || __is_setgid(new, old);
 
-       if ((is_setid ||
-            !cap_issubset(new->cap_permitted, old->cap_permitted)) &&
+       if ((is_setid || __cap_gained(permitted, new, old)) &&
            ((bprm->unsafe & ~LSM_UNSAFE_PTRACE) ||
             !ptracer_capable(current, new->user_ns))) {
                /* downgrade; they get no more than they had, and maybe less */
@@ -779,7 +860,7 @@ skip:
        new->sgid = new->fsgid = new->egid;
 
        /* File caps or setid cancels ambient. */
-       if (has_cap || is_setid)
+       if (has_fcap || is_setid)
                cap_clear(new->cap_ambient);
 
        /*
@@ -800,26 +881,10 @@ skip:
        if (WARN_ON(!cap_ambient_invariant_ok(new)))
                return -EPERM;
 
-       /*
-        * Audit candidate if current->cap_effective is set
-        *
-        * We do not bother to audit if 3 things are true:
-        *   1) cap_effective has all caps
-        *   2) we are root
-        *   3) root is supposed to have all caps (SECURE_NOROOT)
-        * Since this is just a normal root execing a process.
-        *
-        * Number 1 above might fail if you don't have a full bset, but I think
-        * that is interesting information to audit.
-        */
-       if (!cap_issubset(new->cap_effective, new->cap_ambient)) {
-               if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
-                   !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
-                   issecure(SECURE_NOROOT)) {
-                       ret = audit_log_bprm_fcaps(bprm, new, old);
-                       if (ret < 0)
-                               return ret;
-               }
+       if (nonroot_raised_pE(new, old, root_uid, has_fcap)) {
+               ret = audit_log_bprm_fcaps(bprm, new, old);
+               if (ret < 0)
+                       return ret;
        }
 
        new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
@@ -829,13 +894,11 @@ skip:
 
        /* Check for privilege-elevated exec. */
        bprm->cap_elevated = 0;
-       if (is_setid) {
+       if (is_setid ||
+           (!__is_real(root_uid, new) &&
+            (effective ||
+             __cap_grew(permitted, ambient, new))))
                bprm->cap_elevated = 1;
-       } else if (!uid_eq(new->uid, root_uid)) {
-               if (effective ||
-                   !cap_issubset(new->cap_permitted, new->cap_ambient))
-                       bprm->cap_elevated = 1;
-       }
 
        return 0;
 }
index 06554c448dce886d3bd7a01a745a78ab5fd734e8..6f9e4ce568cd87fd8b529a2e8c08c615c6f790a5 100644 (file)
@@ -112,21 +112,25 @@ int __init integrity_init_keyring(const unsigned int id)
 int __init integrity_load_x509(const unsigned int id, const char *path)
 {
        key_ref_t key;
-       char *data;
+       void *data;
+       loff_t size;
        int rc;
 
        if (!keyring[id])
                return -EINVAL;
 
-       rc = integrity_read_file(path, &data);
-       if (rc < 0)
+       rc = kernel_read_file_from_path(path, &data, &size, 0,
+                                       READING_X509_CERTIFICATE);
+       if (rc < 0) {
+               pr_err("Unable to open file: %s (%d)", path, rc);
                return rc;
+       }
 
        key = key_create_or_update(make_key_ref(keyring[id], 1),
                                   "asymmetric",
                                   NULL,
                                   data,
-                                  rc,
+                                  size,
                                   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
                                    KEY_USR_VIEW | KEY_USR_READ),
                                   KEY_ALLOC_NOT_IN_QUOTA);
@@ -139,6 +143,6 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
                          key_ref_to_ptr(key)->description, path);
                key_ref_put(key);
        }
-       kfree(data);
+       vfree(data);
        return 0;
 }
index f5f12727771a0aba01442d7c242f95464658abce..241aca315b0c351d6897e4e6d9ee2261cbbb3bcb 100644 (file)
@@ -23,6 +23,9 @@
 
 #define EVM_INIT_HMAC  0x0001
 #define EVM_INIT_X509  0x0002
+#define EVM_SETUP       0x80000000 /* userland has signaled key load */
+
+#define EVM_INIT_MASK (EVM_INIT_HMAC | EVM_INIT_X509 | EVM_SETUP)
 
 extern int evm_initialized;
 extern char *evm_hmac;
index 1d32cd20009a3bd35cf77bc11027354c00eb8812..bcd64baf87881b4194cf9852c0167900d96ddddc 100644 (file)
@@ -80,7 +80,7 @@ static struct shash_desc *init_desc(char type)
 
        if (type == EVM_XATTR_HMAC) {
                if (!(evm_initialized & EVM_INIT_HMAC)) {
-                       pr_err("HMAC key is not set\n");
+                       pr_err_once("HMAC key is not set\n");
                        return ERR_PTR(-ENOKEY);
                }
                tfm = &hmac_tfm;
index 063d38aef64e71a00763997752f93983fa9702d6..9826c02e2db8f789eea2dc9d209db7e605839de0 100644 (file)
@@ -49,6 +49,9 @@ char *evm_config_xattrnames[] = {
        XATTR_NAME_SMACKMMAP,
 #endif
 #endif
+#ifdef CONFIG_SECURITY_APPARMOR
+       XATTR_NAME_APPARMOR,
+#endif
 #ifdef CONFIG_IMA_APPRAISE
        XATTR_NAME_IMA,
 #endif
index c8dccd54d5017da0de7a4f03708b5fabb49fe85e..319cf16d6603050f4ac6fef1f3e2aa31c7a941ce 100644 (file)
@@ -40,7 +40,7 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,
        if (*ppos != 0)
                return 0;
 
-       sprintf(temp, "%d", evm_initialized);
+       sprintf(temp, "%d", (evm_initialized & ~EVM_SETUP));
        rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
 
        return rc;
@@ -61,24 +61,29 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,
 static ssize_t evm_write_key(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
-       char temp[80];
-       int i;
+       int i, ret;
 
-       if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC))
+       if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP))
                return -EPERM;
 
-       if (count >= sizeof(temp) || count == 0)
-               return -EINVAL;
-
-       if (copy_from_user(temp, buf, count) != 0)
-               return -EFAULT;
+       ret = kstrtoint_from_user(buf, count, 0, &i);
 
-       temp[count] = '\0';
+       if (ret)
+               return ret;
 
-       if ((sscanf(temp, "%d", &i) != 1) || (i != 1))
+       /* Reject invalid values */
+       if (!i || (i & ~EVM_INIT_MASK) != 0)
                return -EINVAL;
 
-       evm_init_key();
+       if (i & EVM_INIT_HMAC) {
+               ret = evm_init_key();
+               if (ret != 0)
+                       return ret;
+               /* Forbid further writes after the symmetric key is loaded */
+               i |= EVM_SETUP;
+       }
+
+       evm_initialized |= i;
 
        return count;
 }
index 6fc888ca468e4f9cdd8938e535ebd4e2dbbe2044..c84e05866052a068e99b4f30236764e531c38896 100644 (file)
@@ -199,55 +199,6 @@ int integrity_kernel_read(struct file *file, loff_t offset,
        return ret;
 }
 
-/*
- * integrity_read_file - read entire file content into the buffer
- *
- * This is function opens a file, allocates the buffer of required
- * size, read entire file content to the buffer and closes the file
- *
- * It is used only by init code.
- *
- */
-int __init integrity_read_file(const char *path, char **data)
-{
-       struct file *file;
-       loff_t size;
-       char *buf;
-       int rc = -EINVAL;
-
-       if (!path || !*path)
-               return -EINVAL;
-
-       file = filp_open(path, O_RDONLY, 0);
-       if (IS_ERR(file)) {
-               rc = PTR_ERR(file);
-               pr_err("Unable to open file: %s (%d)", path, rc);
-               return rc;
-       }
-
-       size = i_size_read(file_inode(file));
-       if (size <= 0)
-               goto out;
-
-       buf = kmalloc(size, GFP_KERNEL);
-       if (!buf) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       rc = integrity_kernel_read(file, 0, buf, size);
-       if (rc == size) {
-               *data = buf;
-       } else {
-               kfree(buf);
-               if (rc >= 0)
-                       rc = -EIO;
-       }
-out:
-       fput(file);
-       return rc;
-}
-
 /*
  * integrity_load_keys - load integrity keys hook
  *
index c2edba8de35e4932a13e73ec55907f9987037dce..c7e8db0ea4c0e4bad275892f8c7b83c012ba8214 100644 (file)
@@ -199,42 +199,59 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
        struct inode *inode = file_inode(file);
        const char *filename = file->f_path.dentry->d_name.name;
        int result = 0;
+       int length;
+       void *tmpbuf;
+       u64 i_version;
        struct {
                struct ima_digest_data hdr;
                char digest[IMA_MAX_DIGEST_SIZE];
        } hash;
 
-       if (!(iint->flags & IMA_COLLECTED)) {
-               u64 i_version = file_inode(file)->i_version;
+       if (iint->flags & IMA_COLLECTED)
+               goto out;
 
-               if (file->f_flags & O_DIRECT) {
-                       audit_cause = "failed(directio)";
-                       result = -EACCES;
-                       goto out;
-               }
+       /*
+        * Dectecting file change is based on i_version. On filesystems
+        * which do not support i_version, support is limited to an initial
+        * measurement/appraisal/audit.
+        */
+       i_version = file_inode(file)->i_version;
+       hash.hdr.algo = algo;
 
-               hash.hdr.algo = algo;
-
-               result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
-                       ima_calc_buffer_hash(buf, size, &hash.hdr);
-               if (!result) {
-                       int length = sizeof(hash.hdr) + hash.hdr.length;
-                       void *tmpbuf = krealloc(iint->ima_hash, length,
-                                               GFP_NOFS);
-                       if (tmpbuf) {
-                               iint->ima_hash = tmpbuf;
-                               memcpy(iint->ima_hash, &hash, length);
-                               iint->version = i_version;
-                               iint->flags |= IMA_COLLECTED;
-                       } else
-                               result = -ENOMEM;
-               }
+       /* Initialize hash digest to 0's in case of failure */
+       memset(&hash.digest, 0, sizeof(hash.digest));
+
+       if (buf)
+               result = ima_calc_buffer_hash(buf, size, &hash.hdr);
+       else
+               result = ima_calc_file_hash(file, &hash.hdr);
+
+       if (result && result != -EBADF && result != -EINVAL)
+               goto out;
+
+       length = sizeof(hash.hdr) + hash.hdr.length;
+       tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
+       if (!tmpbuf) {
+               result = -ENOMEM;
+               goto out;
        }
+
+       iint->ima_hash = tmpbuf;
+       memcpy(iint->ima_hash, &hash, length);
+       iint->version = i_version;
+
+       /* Possibly temporary failure due to type of read (eg. O_DIRECT) */
+       if (!result)
+               iint->flags |= IMA_COLLECTED;
 out:
-       if (result)
+       if (result) {
+               if (file->f_flags & O_DIRECT)
+                       audit_cause = "failed(directio)";
+
                integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
                                    filename, "collect_data", audit_cause,
                                    result, 0);
+       }
        return result;
 }
 
@@ -278,7 +295,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
        }
 
        result = ima_store_template(entry, violation, inode, filename, pcr);
-       if (!result || result == -EEXIST) {
+       if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) {
                iint->flags |= IMA_MEASURED;
                iint->measured_pcrs |= (0x1 << pcr);
        }
index 809ba70fbbbfb3137339895db07301b39662d5a1..ec7dfa02c0519483818c40cce40ba0993fbd4712 100644 (file)
@@ -40,7 +40,7 @@ __setup("ima_appraise=", default_appraise_setup);
  */
 bool is_ima_appraise_enabled(void)
 {
-       return (ima_appraise & IMA_APPRAISE_ENFORCE) ? 1 : 0;
+       return ima_appraise & IMA_APPRAISE_ENFORCE;
 }
 
 /*
@@ -405,7 +405,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
                if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
                        return -EINVAL;
                ima_reset_appraise_flags(d_backing_inode(dentry),
-                        (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0);
+                       xvalue->type == EVM_IMA_XATTR_DIGSIG);
                result = 0;
        }
        return result;
index 802d5d20f36fe46ecb787163f4dafd532741c78b..a856d8c9c9f3af6601d211e5de36dde36b65b3b3 100644 (file)
@@ -441,6 +441,16 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
        loff_t i_size;
        int rc;
 
+       /*
+        * For consistency, fail file's opened with the O_DIRECT flag on
+        * filesystems mounted with/without DAX option.
+        */
+       if (file->f_flags & O_DIRECT) {
+               hash->length = hash_digest_size[ima_hash_algo];
+               hash->algo = ima_hash_algo;
+               return -EINVAL;
+       }
+
        i_size = i_size_read(file_inode(file));
 
        if (ima_ahash_minsize && i_size >= ima_ahash_minsize) {
index ad491c51e8339c8f497b218c7b007b7c12a98ce4..fa540c0469dac649ca7583834caacf7cc955b594 100644 (file)
@@ -32,7 +32,7 @@ bool ima_canonical_fmt;
 static int __init default_canonical_fmt_setup(char *str)
 {
 #ifdef __BIG_ENDIAN
-       ima_canonical_fmt = 1;
+       ima_canonical_fmt = true;
 #endif
        return 1;
 }
@@ -429,10 +429,10 @@ static int ima_release_policy(struct inode *inode, struct file *file)
        }
 
        ima_update_policy();
-#ifndef        CONFIG_IMA_WRITE_POLICY
+#if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
        securityfs_remove(ima_policy);
        ima_policy = NULL;
-#else
+#elif defined(CONFIG_IMA_WRITE_POLICY)
        clear_bit(IMA_FS_BUSY, &ima_fs_flags);
 #endif
        return 0;
index 2aebb7984437f10afe6e9aaa964a42be88f9295a..770654694efcb4d728dd6a0f23b2f8f21d6e90be 100644 (file)
@@ -51,6 +51,8 @@ static int __init hash_setup(char *str)
                        ima_hash_algo = HASH_ALGO_SHA1;
                else if (strncmp(str, "md5", 3) == 0)
                        ima_hash_algo = HASH_ALGO_MD5;
+               else
+                       return 1;
                goto out;
        }
 
@@ -60,6 +62,8 @@ static int __init hash_setup(char *str)
                        break;
                }
        }
+       if (i == HASH_ALGO__LAST)
+               return 1;
 out:
        hash_setup_done = 1;
        return 1;
@@ -235,11 +239,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
        hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
 
        rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
-       if (rc != 0) {
-               if (file->f_flags & O_DIRECT)
-                       rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
+       if (rc != 0 && rc != -EBADF && rc != -EINVAL)
                goto out_digsig;
-       }
 
        if (!pathbuf)   /* ima_rdwr_violation possibly pre-fetched */
                pathname = ima_d_path(&file->f_path, &pathbuf, filename);
@@ -247,12 +248,14 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
        if (action & IMA_MEASURE)
                ima_store_measurement(iint, file, pathname,
                                      xattr_value, xattr_len, pcr);
-       if (action & IMA_APPRAISE_SUBMASK)
+       if (rc == 0 && (action & IMA_APPRAISE_SUBMASK))
                rc = ima_appraise_measurement(func, iint, file, pathname,
                                              xattr_value, xattr_len, opened);
        if (action & IMA_AUDIT)
                ima_audit_measurement(iint, pathname);
 
+       if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO))
+               rc = 0;
 out_digsig:
        if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) &&
             !(iint->flags & IMA_NEW_FILE))
@@ -359,12 +362,12 @@ void ima_post_path_mknod(struct dentry *dentry)
  */
 int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
 {
+       bool sig_enforce = is_module_sig_enforced();
+
        if (!file && read_id == READING_MODULE) {
-#ifndef CONFIG_MODULE_SIG_FORCE
-               if ((ima_appraise & IMA_APPRAISE_MODULES) &&
+               if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES) &&
                    (ima_appraise & IMA_APPRAISE_ENFORCE))
                        return -EACCES; /* INTEGRITY_UNKNOWN */
-#endif
                return 0;       /* We rely on module signature checking */
        }
        return 0;
@@ -406,6 +409,10 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
        if (!file && read_id == READING_MODULE) /* MODULE_SIG_FORCE enabled */
                return 0;
 
+       /* permit signed certs */
+       if (!file && read_id == READING_X509_CERTIFICATE)
+               return 0;
+
        if (!file || !buf || size == 0) { /* should never happen */
                if (ima_appraise & IMA_APPRAISE_ENFORCE)
                        return -EACCES;
index 95209a5f8595aff48c253d509eb4c93c6f674ce7..ee4613fa58403dd8842fa60399845293e24253df 100644 (file)
@@ -196,9 +196,9 @@ static int __init policy_setup(char *str)
                if ((strcmp(p, "tcb") == 0) && !ima_policy)
                        ima_policy = DEFAULT_TCB;
                else if (strcmp(p, "appraise_tcb") == 0)
-                       ima_use_appraise_tcb = 1;
+                       ima_use_appraise_tcb = true;
                else if (strcmp(p, "secure_boot") == 0)
-                       ima_use_secure_boot = 1;
+                       ima_use_secure_boot = true;
        }
 
        return 1;
@@ -207,7 +207,7 @@ __setup("ima_policy=", policy_setup);
 
 static int __init default_appraise_policy_setup(char *str)
 {
-       ima_use_appraise_tcb = 1;
+       ima_use_appraise_tcb = true;
        return 1;
 }
 __setup("ima_appraise_tcb", default_appraise_policy_setup);
index a53e7e4ab06c74d4ca4c85836f1e0d2e809433a6..e1bf040fb110959bcc53a2be840ffd32a31d8c3d 100644 (file)
@@ -120,8 +120,6 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 int integrity_kernel_read(struct file *file, loff_t offset,
                          void *addr, unsigned long count);
 
-int __init integrity_read_file(const char *path, char **data);
-
 #define INTEGRITY_KEYRING_EVM          0
 #define INTEGRITY_KEYRING_IMA          1
 #define INTEGRITY_KEYRING_MODULE       2
index f01d48cb3de1aac09266b59bcfa732597c6534b4..afb3a9175d7686e2997f253d1ecad486fcd2badb 100644 (file)
@@ -30,7 +30,7 @@ DECLARE_WORK(key_gc_work, key_garbage_collector);
  * Reaper for links from keyrings to dead keys.
  */
 static void key_gc_timer_func(unsigned long);
-static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0);
+static DEFINE_TIMER(key_gc_timer, key_gc_timer_func);
 
 static time_t key_gc_next_run = LONG_MAX;
 static struct key_type *key_gc_dead_keytype;
index 286171a16ed255e20c396fca595600488c059c2d..14cc7940b36d2d0a960a3fff9a87a649a50dbc64 100644 (file)
@@ -4600,6 +4600,82 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
        return 0;
 }
 
+static int smack_inode_copy_up(struct dentry *dentry, struct cred **new)
+{
+
+       struct task_smack *tsp;
+       struct smack_known *skp;
+       struct inode_smack *isp;
+       struct cred *new_creds = *new;
+
+       if (new_creds == NULL) {
+               new_creds = prepare_creds();
+               if (new_creds == NULL)
+                       return -ENOMEM;
+       }
+
+       tsp = new_creds->security;
+
+       /*
+        * Get label from overlay inode and set it in create_sid
+        */
+       isp = d_inode(dentry->d_parent)->i_security;
+       skp = isp->smk_inode;
+       tsp->smk_task = skp;
+       *new = new_creds;
+       return 0;
+}
+
+static int smack_inode_copy_up_xattr(const char *name)
+{
+       /*
+        * Return 1 if this is the smack access Smack attribute.
+        */
+       if (strcmp(name, XATTR_NAME_SMACK) == 0)
+               return 1;
+
+       return -EOPNOTSUPP;
+}
+
+static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
+                                       struct qstr *name,
+                                       const struct cred *old,
+                                       struct cred *new)
+{
+       struct task_smack *otsp = old->security;
+       struct task_smack *ntsp = new->security;
+       struct inode_smack *isp;
+       int may;
+
+       /*
+        * Use the process credential unless all of
+        * the transmuting criteria are met
+        */
+       ntsp->smk_task = otsp->smk_task;
+
+       /*
+        * the attribute of the containing directory
+        */
+       isp = d_inode(dentry->d_parent)->i_security;
+
+       if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
+               rcu_read_lock();
+               may = smk_access_entry(otsp->smk_task->smk_known,
+                                      isp->smk_inode->smk_known,
+                                      &otsp->smk_task->smk_rules);
+               rcu_read_unlock();
+
+               /*
+                * If the directory is transmuting and the rule
+                * providing access is transmuting use the containing
+                * directory label instead of the process label.
+                */
+               if (may > 0 && (may & MAY_TRANSMUTE))
+                       ntsp->smk_task = isp->smk_inode;
+       }
+       return 0;
+}
+
 static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
        LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
@@ -4735,6 +4811,9 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
        LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
        LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),
+       LSM_HOOK_INIT(inode_copy_up, smack_inode_copy_up),
+       LSM_HOOK_INIT(inode_copy_up_xattr, smack_inode_copy_up_xattr),
+       LSM_HOOK_INIT(dentry_create_files_as, smack_dentry_create_files_as),
 };
 
 
index d330b060dcff2e7a02c56ca32a0d2973d68ea6e7..0f73fe30e37a571f9924ae484e2c27c495d3f614 100644 (file)
@@ -157,7 +157,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
        if (!buffer)
                return NULL;
 
-       tomoyo_convert_time(get_seconds(), &stamp);
+       tomoyo_convert_time(ktime_get_real_seconds(), &stamp);
 
        pos = snprintf(buffer, tomoyo_buffer_len - 1,
                       "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
index 21691b99e61f49f1495f0fb49ce15e7c368eeec4..25eed4b0b0e841040907ef9f0035fc99a128857a 100644 (file)
@@ -2257,7 +2257,7 @@ static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = {
 /* Timestamp counter for last updated. */
 static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT];
 /* Counter for number of updates. */
-static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT];
+static time64_t tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT];
 
 /**
  * tomoyo_update_stat - Update statistic counters.
@@ -2272,7 +2272,7 @@ void tomoyo_update_stat(const u8 index)
         * I don't use atomic operations because race condition is not fatal.
         */
        tomoyo_stat_updated[index]++;
-       tomoyo_stat_modified[index] = get_seconds();
+       tomoyo_stat_modified[index] = ktime_get_real_seconds();
 }
 
 /**
index e4097d7994b169746a934243f2db4a51c3ea4a98..7adccdd8e36d9b9117c9a8643495dcb2d880cc9a 100644 (file)
@@ -1037,7 +1037,7 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
                      bool (*check_entry) (struct tomoyo_request_info *,
                                           const struct tomoyo_acl_info *));
 void tomoyo_check_profile(void);
-void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp);
+void tomoyo_convert_time(time64_t time, struct tomoyo_time *stamp);
 void tomoyo_del_condition(struct list_head *element);
 void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
 void tomoyo_get_attributes(struct tomoyo_obj_info *obj);
index 580b318910f1484f6e3f7e7fdeefc5a5924d36ef..d3d9d9f1edb04a49abd4febc908d1fc294267d4f 100644 (file)
@@ -87,38 +87,17 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
  * @stamp: Pointer to "struct tomoyo_time".
  *
  * Returns nothing.
- *
- * This function does not handle Y2038 problem.
  */
-void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp)
+void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp)
 {
-       static const u16 tomoyo_eom[2][12] = {
-               { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
-               { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
-       };
-       u16 y;
-       u8 m;
-       bool r;
-       stamp->sec = time % 60;
-       time /= 60;
-       stamp->min = time % 60;
-       time /= 60;
-       stamp->hour = time % 24;
-       time /= 24;
-       for (y = 1970; ; y++) {
-               const unsigned short days = (y & 3) ? 365 : 366;
-               if (time < days)
-                       break;
-               time -= days;
-       }
-       r = (y & 3) == 0;
-       for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++)
-               ;
-       if (m)
-               time -= tomoyo_eom[r][m - 1];
-       stamp->year = y;
-       stamp->month = ++m;
-       stamp->day = ++time;
+       struct tm tm;
+       time64_to_tm(time64, 0, &tm);
+       stamp->sec = tm.tm_sec;
+       stamp->min = tm.tm_min;
+       stamp->hour = tm.tm_hour;
+       stamp->day = tm.tm_mday;
+       stamp->month = tm.tm_mon + 1;
+       stamp->year = tm.tm_year + 1900;
 }
 
 /**
index 1ac0c423903e7f3f41a2045fd20b9707df4ac00f..6e47b823bcaa3efd1ab9325117527a03f80c231f 100644 (file)
@@ -159,6 +159,7 @@ static int __init snd_hrtimer_init(void)
        timer->hw = hrtimer_hw;
        timer->hw.resolution = resolution;
        timer->hw.ticks = NANO_SEC / resolution;
+       timer->max_instances = 100; /* lower the limit */
 
        err = snd_timer_global_register(timer);
        if (err < 0) {
index aaff9ee326957b5a393495126e128b9f6b5efd98..b30b2139e3f033fd71e59fbe10cfa1e25340adc6 100644 (file)
@@ -612,9 +612,7 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
        if (!dp->timer->running)
                len = snd_seq_oss_timer_start(dp->timer);
        if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
-               if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
-                       snd_seq_oss_readq_puts(dp->readq, mdev->seq_device,
-                                              ev->data.ext.ptr, ev->data.ext.len);
+               snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev);
        } else {
                len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
                if (len > 0)
index 046cb586fb2f7271c88dc1e02354625d6dcca864..06b21226b4e7081ed6584a96cddbcd36af966a88 100644 (file)
@@ -117,6 +117,35 @@ snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, in
        return 0;
 }
 
+/*
+ * put MIDI sysex bytes; the event buffer may be chained, thus it has
+ * to be expanded via snd_seq_dump_var_event().
+ */
+struct readq_sysex_ctx {
+       struct seq_oss_readq *readq;
+       int dev;
+};
+
+static int readq_dump_sysex(void *ptr, void *buf, int count)
+{
+       struct readq_sysex_ctx *ctx = ptr;
+
+       return snd_seq_oss_readq_puts(ctx->readq, ctx->dev, buf, count);
+}
+
+int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
+                           struct snd_seq_event *ev)
+{
+       struct readq_sysex_ctx ctx = {
+               .readq = q,
+               .dev = dev
+       };
+
+       if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
+               return 0;
+       return snd_seq_dump_var_event(ev, readq_dump_sysex, &ctx);
+}
+
 /*
  * copy an event to input queue:
  * return zero if enqueued
index f1463f1f449e7e3863db3da0b71ad0ad6022db4b..8d033ca2d23f87788d1ce74d7b21af6ed0f1761a 100644 (file)
@@ -44,6 +44,8 @@ void snd_seq_oss_readq_delete(struct seq_oss_readq *q);
 void snd_seq_oss_readq_clear(struct seq_oss_readq *readq);
 unsigned int snd_seq_oss_readq_poll(struct seq_oss_readq *readq, struct file *file, poll_table *wait);
 int snd_seq_oss_readq_puts(struct seq_oss_readq *readq, int dev, unsigned char *data, int len);
+int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
+                           struct snd_seq_event *ev);
 int snd_seq_oss_readq_put_event(struct seq_oss_readq *readq, union evrec *ev);
 int snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *readq, unsigned long curt, int seq_mode);
 int snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec);
index 6cdd04a459626c86f185742d099ab16729b7d517..15e82a656d9622c5b0291dd0830813f77934393c 100644 (file)
@@ -180,7 +180,7 @@ static void snd_timer_request(struct snd_timer_id *tid)
  *
  * call this with register_mutex down.
  */
-static void snd_timer_check_slave(struct snd_timer_instance *slave)
+static int snd_timer_check_slave(struct snd_timer_instance *slave)
 {
        struct snd_timer *timer;
        struct snd_timer_instance *master;
@@ -190,16 +190,21 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
                list_for_each_entry(master, &timer->open_list_head, open_list) {
                        if (slave->slave_class == master->slave_class &&
                            slave->slave_id == master->slave_id) {
+                               if (master->timer->num_instances >=
+                                   master->timer->max_instances)
+                                       return -EBUSY;
                                list_move_tail(&slave->open_list,
                                               &master->slave_list_head);
+                               master->timer->num_instances++;
                                spin_lock_irq(&slave_active_lock);
                                slave->master = master;
                                slave->timer = master->timer;
                                spin_unlock_irq(&slave_active_lock);
-                               return;
+                               return 0;
                        }
                }
        }
+       return 0;
 }
 
 /*
@@ -208,7 +213,7 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
  *
  * call this with register_mutex down.
  */
-static void snd_timer_check_master(struct snd_timer_instance *master)
+static int snd_timer_check_master(struct snd_timer_instance *master)
 {
        struct snd_timer_instance *slave, *tmp;
 
@@ -216,7 +221,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
        list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
                if (slave->slave_class == master->slave_class &&
                    slave->slave_id == master->slave_id) {
+                       if (master->timer->num_instances >=
+                           master->timer->max_instances)
+                               return -EBUSY;
                        list_move_tail(&slave->open_list, &master->slave_list_head);
+                       master->timer->num_instances++;
                        spin_lock_irq(&slave_active_lock);
                        spin_lock(&master->timer->lock);
                        slave->master = master;
@@ -228,8 +237,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
                        spin_unlock_irq(&slave_active_lock);
                }
        }
+       return 0;
 }
 
+static int snd_timer_close_locked(struct snd_timer_instance *timeri);
+
 /*
  * open a timer instance
  * when opening a master, the slave id must be here given.
@@ -240,6 +252,7 @@ int snd_timer_open(struct snd_timer_instance **ti,
 {
        struct snd_timer *timer;
        struct snd_timer_instance *timeri = NULL;
+       int err;
 
        if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
                /* open a slave instance */
@@ -259,10 +272,14 @@ int snd_timer_open(struct snd_timer_instance **ti,
                timeri->slave_id = tid->device;
                timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
                list_add_tail(&timeri->open_list, &snd_timer_slave_list);
-               snd_timer_check_slave(timeri);
+               err = snd_timer_check_slave(timeri);
+               if (err < 0) {
+                       snd_timer_close_locked(timeri);
+                       timeri = NULL;
+               }
                mutex_unlock(&register_mutex);
                *ti = timeri;
-               return 0;
+               return err;
        }
 
        /* open a master instance */
@@ -288,6 +305,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
                        return -EBUSY;
                }
        }
+       if (timer->num_instances >= timer->max_instances) {
+               mutex_unlock(&register_mutex);
+               return -EBUSY;
+       }
        timeri = snd_timer_instance_new(owner, timer);
        if (!timeri) {
                mutex_unlock(&register_mutex);
@@ -314,25 +335,27 @@ int snd_timer_open(struct snd_timer_instance **ti,
        }
 
        list_add_tail(&timeri->open_list, &timer->open_list_head);
-       snd_timer_check_master(timeri);
+       timer->num_instances++;
+       err = snd_timer_check_master(timeri);
+       if (err < 0) {
+               snd_timer_close_locked(timeri);
+               timeri = NULL;
+       }
        mutex_unlock(&register_mutex);
        *ti = timeri;
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL(snd_timer_open);
 
 /*
  * close a timer instance
+ * call this with register_mutex down.
  */
-int snd_timer_close(struct snd_timer_instance *timeri)
+static int snd_timer_close_locked(struct snd_timer_instance *timeri)
 {
        struct snd_timer *timer = NULL;
        struct snd_timer_instance *slave, *tmp;
 
-       if (snd_BUG_ON(!timeri))
-               return -ENXIO;
-
-       mutex_lock(&register_mutex);
        list_del(&timeri->open_list);
 
        /* force to stop the timer */
@@ -340,6 +363,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
 
        timer = timeri->timer;
        if (timer) {
+               timer->num_instances--;
                /* wait, until the active callback is finished */
                spin_lock_irq(&timer->lock);
                while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
@@ -355,6 +379,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
                                         open_list) {
                        list_move_tail(&slave->open_list, &snd_timer_slave_list);
+                       timer->num_instances--;
                        slave->master = NULL;
                        slave->timer = NULL;
                        list_del_init(&slave->ack_list);
@@ -382,9 +407,24 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                module_put(timer->module);
        }
 
-       mutex_unlock(&register_mutex);
        return 0;
 }
+
+/*
+ * close a timer instance
+ */
+int snd_timer_close(struct snd_timer_instance *timeri)
+{
+       int err;
+
+       if (snd_BUG_ON(!timeri))
+               return -ENXIO;
+
+       mutex_lock(&register_mutex);
+       err = snd_timer_close_locked(timeri);
+       mutex_unlock(&register_mutex);
+       return err;
+}
 EXPORT_SYMBOL(snd_timer_close);
 
 unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
@@ -856,6 +896,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
        spin_lock_init(&timer->lock);
        tasklet_init(&timer->task_queue, snd_timer_tasklet,
                     (unsigned long)timer);
+       timer->max_instances = 1000; /* default limit per timer */
        if (card != NULL) {
                timer->module = card->module;
                err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);
index 23ccddb20de15f6498f3de67e1f683d8e22f963e..4210e5c6262eb9f19e4d08f6d195bca793f4c680 100644 (file)
@@ -247,7 +247,7 @@ void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
        struct amdtp_am824 *p = s->protocol;
 
        if (port < p->midi_ports)
-               ACCESS_ONCE(p->midi[port]) = midi;
+               WRITE_ONCE(p->midi[port], midi);
 }
 EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger);
 
@@ -336,7 +336,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffe
                                           unsigned int data_blocks, unsigned int *syt)
 {
        struct amdtp_am824 *p = s->protocol;
-       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
        unsigned int pcm_frames;
 
        if (pcm) {
@@ -357,7 +357,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffe
                                           unsigned int data_blocks, unsigned int *syt)
 {
        struct amdtp_am824 *p = s->protocol;
-       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
        unsigned int pcm_frames;
 
        if (pcm) {
index 3fc581a5ad6254b61b23f1b21a82ce6b0b3c622b..4a1dc145327b19f8f5dac1123ae0a20264d93506 100644 (file)
@@ -376,7 +376,7 @@ static void update_pcm_pointers(struct amdtp_stream *s,
        ptr = s->pcm_buffer_pointer + frames;
        if (ptr >= pcm->runtime->buffer_size)
                ptr -= pcm->runtime->buffer_size;
-       ACCESS_ONCE(s->pcm_buffer_pointer) = ptr;
+       WRITE_ONCE(s->pcm_buffer_pointer, ptr);
 
        s->pcm_period_pointer += frames;
        if (s->pcm_period_pointer >= pcm->runtime->period_size) {
@@ -388,7 +388,7 @@ static void update_pcm_pointers(struct amdtp_stream *s,
 static void pcm_period_tasklet(unsigned long data)
 {
        struct amdtp_stream *s = (void *)data;
-       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
 
        if (pcm)
                snd_pcm_period_elapsed(pcm);
@@ -453,7 +453,7 @@ static int handle_out_packet(struct amdtp_stream *s,
                s->data_block_counter =
                                (s->data_block_counter + data_blocks) & 0xff;
 
-       buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
+       buffer[0] = cpu_to_be32(READ_ONCE(s->source_node_id_field) |
                                (s->data_block_quadlets << CIP_DBS_SHIFT) |
                                ((s->sph << CIP_SPH_SHIFT) & CIP_SPH_MASK) |
                                s->data_block_counter);
@@ -472,7 +472,7 @@ static int handle_out_packet(struct amdtp_stream *s,
        if (queue_out_packet(s, payload_length) < 0)
                return -EIO;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm && pcm_frames > 0)
                update_pcm_pointers(s, pcm, pcm_frames);
 
@@ -504,7 +504,7 @@ static int handle_out_packet_without_header(struct amdtp_stream *s,
        if (queue_out_packet(s, payload_length) < 0)
                return -EIO;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm && pcm_frames > 0)
                update_pcm_pointers(s, pcm, pcm_frames);
 
@@ -621,7 +621,7 @@ end:
        if (queue_in_packet(s) < 0)
                return -EIO;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm && pcm_frames > 0)
                update_pcm_pointers(s, pcm, pcm_frames);
 
@@ -649,7 +649,7 @@ static int handle_in_packet_without_header(struct amdtp_stream *s,
        if (queue_in_packet(s) < 0)
                return -EIO;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm && pcm_frames > 0)
                update_pcm_pointers(s, pcm, pcm_frames);
 
@@ -947,7 +947,7 @@ unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s)
        if (!in_interrupt() && amdtp_stream_running(s))
                fw_iso_context_flush_completions(s->context);
 
-       return ACCESS_ONCE(s->pcm_buffer_pointer);
+       return READ_ONCE(s->pcm_buffer_pointer);
 }
 EXPORT_SYMBOL(amdtp_stream_pcm_pointer);
 
@@ -977,9 +977,8 @@ EXPORT_SYMBOL(amdtp_stream_pcm_ack);
 void amdtp_stream_update(struct amdtp_stream *s)
 {
        /* Precomputing. */
-       ACCESS_ONCE(s->source_node_id_field) =
-               (fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) &
-                                                               CIP_SID_MASK;
+       WRITE_ONCE(s->source_node_id_field,
+                   (fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) & CIP_SID_MASK);
 }
 EXPORT_SYMBOL(amdtp_stream_update);
 
@@ -1022,7 +1021,7 @@ void amdtp_stream_pcm_abort(struct amdtp_stream *s)
 {
        struct snd_pcm_substream *pcm;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm)
                snd_pcm_stop_xrun(pcm);
 }
index a608dae8334870ac2d83aae5ef5808a278a87bc9..e45de3eecfe39cb9b3b2f928f9a50307b05a3210 100644 (file)
@@ -221,7 +221,7 @@ static inline bool amdtp_stream_pcm_running(struct amdtp_stream *s)
 static inline void amdtp_stream_pcm_trigger(struct amdtp_stream *s,
                                            struct snd_pcm_substream *pcm)
 {
-       ACCESS_ONCE(s->pcm) = pcm;
+       WRITE_ONCE(s->pcm, pcm);
 }
 
 static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
index 1453c34ce99f0f25aa1f4cef7195dfb454456e87..4a884a33524809a23ba6a07e8319711f76771081 100644 (file)
@@ -327,7 +327,7 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port,
        struct amdtp_dot *p = s->protocol;
 
        if (port < MAX_MIDI_PORTS)
-               ACCESS_ONCE(p->midi[port]) = midi;
+               WRITE_ONCE(p->midi[port], midi);
 }
 
 static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
@@ -338,7 +338,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
        struct snd_pcm_substream *pcm;
        unsigned int pcm_frames;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm) {
                read_pcm_s32(s, pcm, buffer, data_blocks);
                pcm_frames = data_blocks;
@@ -359,7 +359,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
        struct snd_pcm_substream *pcm;
        unsigned int pcm_frames;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm) {
                write_pcm_s32(s, pcm, buffer, data_blocks);
                pcm_frames = data_blocks;
index 780da9deb2f01b75b6b6fe4c29d352a134f2103d..77c7598b61abeb9b9c0ea7629b15a56d39fd37b6 100644 (file)
@@ -108,7 +108,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
                                           unsigned int data_blocks,
                                           unsigned int *syt)
 {
-       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
        unsigned int pcm_frames;
 
        if (pcm) {
@@ -127,7 +127,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
                                           unsigned int data_blocks,
                                           unsigned int *syt)
 {
-       struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+       struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
        unsigned int pcm_frames;
 
        if (pcm) {
index 949ee56b4e0e91d4bd8390fe30d638787532fde5..6a49611ee46250a0534c4cd1455dc9a15972fc18 100644 (file)
@@ -22,7 +22,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
        ff->running_status[substream->number] = 0;
        ff->rx_midi_error[substream->number] = false;
 
-       ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = substream;
+       WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream);
 
        return 0;
 }
@@ -38,7 +38,7 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
        struct snd_ff *ff = substream->rmidi->private_data;
 
        cancel_work_sync(&ff->rx_midi_work[substream->number]);
-       ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = NULL;
+       WRITE_ONCE(ff->rx_midi_substreams[substream->number], NULL);
 
        return 0;
 }
@@ -52,10 +52,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
        spin_lock_irqsave(&ff->lock, flags);
 
        if (up)
-               ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) =
-                                                               substream;
+               WRITE_ONCE(ff->tx_midi_substreams[substream->number],
+                          substream);
        else
-               ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) = NULL;
+               WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL);
 
        spin_unlock_irqrestore(&ff->lock, flags);
 }
index dd6c8e839647f64d8eddc203b199e30014bc2738..332b29f8ed754da9c3a9d4c38807fe30935b2a18 100644 (file)
@@ -12,7 +12,7 @@ static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port,
                                     int rcode)
 {
        struct snd_rawmidi_substream *substream =
-                               ACCESS_ONCE(ff->rx_midi_substreams[port]);
+                               READ_ONCE(ff->rx_midi_substreams[port]);
 
        if (rcode_is_permanent_error(rcode)) {
                ff->rx_midi_error[port] = true;
@@ -60,7 +60,7 @@ static inline void fill_midi_buf(struct snd_ff *ff, unsigned int port,
 static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
 {
        struct snd_rawmidi_substream *substream =
-                       ACCESS_ONCE(ff->rx_midi_substreams[port]);
+                       READ_ONCE(ff->rx_midi_substreams[port]);
        u8 *buf = (u8 *)ff->msg_buf[port];
        int i, len;
 
@@ -159,7 +159,7 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request,
                 */
                index = (quad >> 8) & 0xff;
                if (index > 0) {
-                       substream = ACCESS_ONCE(ff->tx_midi_substreams[0]);
+                       substream = READ_ONCE(ff->tx_midi_substreams[0]);
                        if (substream != NULL) {
                                byte = quad & 0xff;
                                snd_rawmidi_receive(substream, &byte, 1);
@@ -169,7 +169,7 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request,
                /* Message in second port. */
                index = (quad >> 24) & 0xff;
                if (index > 0) {
-                       substream = ACCESS_ONCE(ff->tx_midi_substreams[1]);
+                       substream = READ_ONCE(ff->tx_midi_substreams[1]);
                        if (substream != NULL) {
                                byte = (quad >> 16) & 0xff;
                                snd_rawmidi_receive(substream, &byte, 1);
index 5826aa8362f10b319c5946054c73107fef5f963f..46092fa3ff9bf3632d41a67ce232766136b7f00f 100644 (file)
@@ -96,7 +96,7 @@ static void isight_update_pointers(struct isight *isight, unsigned int count)
        ptr += count;
        if (ptr >= runtime->buffer_size)
                ptr -= runtime->buffer_size;
-       ACCESS_ONCE(isight->buffer_pointer) = ptr;
+       WRITE_ONCE(isight->buffer_pointer, ptr);
 
        isight->period_counter += count;
        if (isight->period_counter >= runtime->period_size) {
@@ -111,7 +111,7 @@ static void isight_samples(struct isight *isight,
        struct snd_pcm_runtime *runtime;
        unsigned int count1;
 
-       if (!ACCESS_ONCE(isight->pcm_running))
+       if (!READ_ONCE(isight->pcm_running))
                return;
 
        runtime = isight->pcm->runtime;
@@ -131,7 +131,7 @@ static void isight_samples(struct isight *isight,
 
 static void isight_pcm_abort(struct isight *isight)
 {
-       if (ACCESS_ONCE(isight->pcm_active))
+       if (READ_ONCE(isight->pcm_active))
                snd_pcm_stop_xrun(isight->pcm);
 }
 
@@ -141,7 +141,7 @@ static void isight_dropped_samples(struct isight *isight, unsigned int total)
        u32 dropped;
        unsigned int count1;
 
-       if (!ACCESS_ONCE(isight->pcm_running))
+       if (!READ_ONCE(isight->pcm_running))
                return;
 
        runtime = isight->pcm->runtime;
@@ -293,7 +293,7 @@ static int isight_hw_params(struct snd_pcm_substream *substream,
        if (err < 0)
                return err;
 
-       ACCESS_ONCE(isight->pcm_active) = true;
+       WRITE_ONCE(isight->pcm_active, true);
 
        return 0;
 }
@@ -331,7 +331,7 @@ static int isight_hw_free(struct snd_pcm_substream *substream)
 {
        struct isight *isight = substream->private_data;
 
-       ACCESS_ONCE(isight->pcm_active) = false;
+       WRITE_ONCE(isight->pcm_active, false);
 
        mutex_lock(&isight->mutex);
        isight_stop_streaming(isight);
@@ -424,10 +424,10 @@ static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               ACCESS_ONCE(isight->pcm_running) = true;
+               WRITE_ONCE(isight->pcm_running, true);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               ACCESS_ONCE(isight->pcm_running) = false;
+               WRITE_ONCE(isight->pcm_running, false);
                break;
        default:
                return -EINVAL;
@@ -439,7 +439,7 @@ static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
 {
        struct isight *isight = substream->private_data;
 
-       return ACCESS_ONCE(isight->buffer_pointer);
+       return READ_ONCE(isight->buffer_pointer);
 }
 
 static int isight_create_pcm(struct isight *isight)
index 96f0091144bb2ad48cb7f1d12fc51db57e208e20..f0555a24d90ed1e6df27ea65b7eec57721c4751a 100644 (file)
@@ -310,7 +310,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
        if (p->midi_ports)
                read_midi_messages(s, buffer, data_blocks);
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (data_blocks > 0 && pcm)
                read_pcm_s32(s, pcm->runtime, buffer, data_blocks);
 
@@ -374,7 +374,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
        if (p->midi_ports)
                write_midi_messages(s, buffer, data_blocks);
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm)
                write_pcm_s32(s, pcm->runtime, buffer, data_blocks);
        else
index 02d5956658987424fdb9ca4ff8b79d68f0b47051..f33497cdc706e65584c2dfdecad43862b3906b27 100644 (file)
@@ -112,7 +112,7 @@ static void handle_hss(struct fw_card *card, struct fw_request *request,
        }
 
        if (length >= 1) {
-               stream = ACCESS_ONCE(scs->input);
+               stream = READ_ONCE(scs->input);
                if (stream)
                        midi_input_packet(scs, stream, data, length);
        }
@@ -183,7 +183,7 @@ static void scs_output_work(struct work_struct *work)
        if (scs->transaction_running)
                return;
 
-       stream = ACCESS_ONCE(scs->output);
+       stream = READ_ONCE(scs->output);
        if (!stream || scs->error) {
                scs->output_idle = true;
                wake_up(&scs->idle_wait);
@@ -291,9 +291,9 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up)
 
        if (up) {
                scs->input_escape_count = 0;
-               ACCESS_ONCE(scs->input) = stream;
+               WRITE_ONCE(scs->input, stream);
        } else {
-               ACCESS_ONCE(scs->input) = NULL;
+               WRITE_ONCE(scs->input, NULL);
        }
 }
 
@@ -319,10 +319,10 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up)
                scs->transaction_bytes = 0;
                scs->error = false;
 
-               ACCESS_ONCE(scs->output) = stream;
+               WRITE_ONCE(scs->output, stream);
                schedule_work(&scs->work);
        } else {
-               ACCESS_ONCE(scs->output) = NULL;
+               WRITE_ONCE(scs->output, NULL);
        }
 }
 static void midi_playback_drain(struct snd_rawmidi_substream *stream)
index 6aff1fc1c72d0c8e0a789d5c66d223627d5c3217..ab482423c16545d3161e04d7d8e78f614b3b70ea 100644 (file)
@@ -124,7 +124,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
 {
        struct snd_pcm_substream *pcm;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (data_blocks > 0 && pcm)
                read_pcm_s32(s, pcm, buffer, data_blocks);
 
@@ -143,7 +143,7 @@ static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
        /* This field is not used. */
        *syt = 0x0000;
 
-       pcm = ACCESS_ONCE(s->pcm);
+       pcm = READ_ONCE(s->pcm);
        if (pcm)
                write_pcm_s32(s, pcm, buffer, data_blocks);
        else
index 8967c52f503284a2d610352fcc7324a53a088b6d..2ad692dd4b137d0af15f8b74fcedb1aab2e80975 100644 (file)
@@ -148,7 +148,7 @@ static void async_midi_port_callback(struct fw_card *card, int rcode,
                                     void *callback_data)
 {
        struct snd_fw_async_midi_port *port = callback_data;
-       struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream);
+       struct snd_rawmidi_substream *substream = READ_ONCE(port->substream);
 
        /* This port is closed. */
        if (substream == NULL)
@@ -173,7 +173,7 @@ static void midi_port_work(struct work_struct *work)
 {
        struct snd_fw_async_midi_port *port =
                        container_of(work, struct snd_fw_async_midi_port, work);
-       struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream);
+       struct snd_rawmidi_substream *substream = READ_ONCE(port->substream);
        int generation;
 
        /* Under transacting or error state. */
@@ -282,7 +282,7 @@ static void handle_midi_tx(struct fw_card *card, struct fw_request *request,
                                bytes = 3;
                }
 
-               substream = ACCESS_ONCE(tscm->tx_midi_substreams[port]);
+               substream = READ_ONCE(tscm->tx_midi_substreams[port]);
                if (substream != NULL)
                        snd_rawmidi_receive(substream, b + 1, bytes);
        }
index 701c7625c9713aafa310e742cf5e87dfa4dc3247..1277df815d5bf26641c682fc408dab60c26c1b4e 100644 (file)
@@ -52,7 +52,7 @@ static struct midi_parms parms[MAX_MIDI_DEV];
 static void midi_poll(unsigned long dummy);
 
 
-static DEFINE_TIMER(poll_timer, midi_poll, 0, 0);
+static DEFINE_TIMER(poll_timer, midi_poll);
 
 static volatile int open_devs;
 static DEFINE_SPINLOCK(lock);
index b70c7c8f9c5d366dc41fce47e47c78339b8b1fd1..4391062e5cfdb813a0d2439b89067394f8c3fb3a 100644 (file)
@@ -662,7 +662,7 @@ static void do_sequencer_timer(unsigned long dummy)
 }
 
 
-static DEFINE_TIMER(seq_timer, do_sequencer_timer, 0, 0);
+static DEFINE_TIMER(seq_timer, do_sequencer_timer);
 
 void request_sound_timer(int count)
 {
index d17019d25b994526251a7fc8d9b088b0fecc109c..8a4b5625dba6d347711cd929664647f9fadaac01 100644 (file)
@@ -28,7 +28,7 @@ static unsigned long prev_event_time;
 
 static void     poll_def_tmr(unsigned long dummy);
 static DEFINE_SPINLOCK(lock);
-static DEFINE_TIMER(def_tmr, poll_def_tmr, 0, 0);
+static DEFINE_TIMER(def_tmr, poll_def_tmr);
 
 static unsigned long
 tmr2ticks(int tmr_value)
index eda32d7eddbdc89a9181e5e319cb1d65cf1d4b81..a9d3f756852505ebd26370f013c3f865393610d2 100644 (file)
@@ -78,7 +78,7 @@ static void (*midi_input_intr) (int dev, unsigned char data);
 static void poll_uart6850(unsigned long dummy);
 
 
-static DEFINE_TIMER(uart6850_timer, poll_uart6850, 0, 0);
+static DEFINE_TIMER(uart6850_timer, poll_uart6850);
 
 static void uart6850_input_loop(void)
 {
index 546d515f3c1fb810641375e5fcf548ef4e360807..dce0682c500191cddeeec4a4258a4d9f33796352 100644 (file)
@@ -6544,6 +6544,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x14, 0x90170110},
                {0x1b, 0x90a70130},
                {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0xb7a60130},
+               {0x13, 0xb8a61140},
+               {0x16, 0x90170110},
+               {0x21, 0x04211020}),
        SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
                {0x12, 0x90a60130},
                {0x14, 0x90170110},
index 8382ffa3bcaf8b446dd67197503f3c21cef307ba..2472144b329efed09b919ae05b65226cc0a01960 100644 (file)
@@ -165,7 +165,7 @@ static bool xtfpga_pcm_push_tx(struct xtfpga_i2s *i2s)
        tx_substream = rcu_dereference(i2s->tx_substream);
        tx_active = tx_substream && snd_pcm_running(tx_substream);
        if (tx_active) {
-               unsigned tx_ptr = ACCESS_ONCE(i2s->tx_ptr);
+               unsigned tx_ptr = READ_ONCE(i2s->tx_ptr);
                unsigned new_tx_ptr = i2s->tx_fn(i2s, tx_substream->runtime,
                                                 tx_ptr);
 
@@ -437,7 +437,7 @@ static int xtfpga_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ACCESS_ONCE(i2s->tx_ptr) = 0;
+               WRITE_ONCE(i2s->tx_ptr, 0);
                rcu_assign_pointer(i2s->tx_substream, substream);
                xtfpga_pcm_refill_fifo(i2s);
                break;
@@ -459,7 +459,7 @@ static snd_pcm_uframes_t xtfpga_pcm_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct xtfpga_i2s *i2s = runtime->private_data;
-       snd_pcm_uframes_t pos = ACCESS_ONCE(i2s->tx_ptr);
+       snd_pcm_uframes_t pos = READ_ONCE(i2s->tx_ptr);
 
        return pos < runtime->buffer_size ? pos : 0;
 }
index 7371e5b0603564e37190d074b5ae9506c80c3e32..fc579f33060145ec28be3e9b2526ab36af36cc1a 100644 (file)
@@ -108,7 +108,7 @@ static void bcd2000_midi_handle_input(struct bcd2000 *bcd2k,
        unsigned int payload_length, tocopy;
        struct snd_rawmidi_substream *midi_receive_substream;
 
-       midi_receive_substream = ACCESS_ONCE(bcd2k->midi_receive_substream);
+       midi_receive_substream = READ_ONCE(bcd2k->midi_receive_substream);
        if (!midi_receive_substream)
                return;
 
@@ -139,7 +139,7 @@ static void bcd2000_midi_send(struct bcd2000 *bcd2k)
 
        BUILD_BUG_ON(sizeof(device_cmd_prefix) >= BUFSIZE);
 
-       midi_out_substream = ACCESS_ONCE(bcd2k->midi_out_substream);
+       midi_out_substream = READ_ONCE(bcd2k->midi_out_substream);
        if (!midi_out_substream)
                return;
 
index 4f5f18f22974ef8e2e7b95e4c0ea261e7a04a388..20624320b753f4c892cb660b00d874eb1cca879e 100644 (file)
@@ -1375,6 +1375,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
                        case 0x199:
                                return SNDRV_PCM_FMTBIT_DSD_U32_LE;
                        case 0x19b:
+                       case 0x203:
                                return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                        default:
                                break;
index 7d8c3261a50d0d0d9ddc9c9c8cb26a632e524c3a..1f5e26aae9fc5fa898d496e3b0a1651627c61e0b 100644 (file)
@@ -25,7 +25,7 @@
  */
 static inline int atomic_read(const atomic_t *v)
 {
-       return ACCESS_ONCE((v)->counter);
+       return READ_ONCE((v)->counter);
 }
 
 /**
index 40b231fb95bd2848c11dba7f8d3a8e3632d9c284..4c1966f7c77a746c898838bc2556675fca21be44 100644 (file)
@@ -22,7 +22,7 @@
  */
 static inline int atomic_read(const atomic_t *v)
 {
-       return ACCESS_ONCE((v)->counter);
+       return READ_ONCE((v)->counter);
 }
 
 /**
index 4bf6777a8a035aab2c3008e1c953ed0aa406d960..9fdcd3eaac3b3b92ead5246b324aa42d68c6dbdb 100644 (file)
 # define POISON_POINTER_DELTA 0
 #endif
 
+#ifdef __cplusplus
+#define LIST_POISON1  NULL
+#define LIST_POISON2  NULL
+#else
 /*
  * These are non-NULL pointers that will result in page faults
  * under normal circumstances, used to verify that nobody uses
@@ -22,6 +26,7 @@
  */
 #define LIST_POISON1  ((void *) 0x100 + POISON_POINTER_DELTA)
 #define LIST_POISON2  ((void *) 0x200 + POISON_POINTER_DELTA)
+#endif
 
 /********** include/linux/timer.h **********/
 /*
index 6598fb76d2c27741d2c916f914b70c5f472911f9..9816590d3ad24b0d7037eb65f9b84c3c571c9b53 100644 (file)
@@ -829,6 +829,7 @@ struct drm_i915_gem_exec_fence {
 
 #define I915_EXEC_FENCE_WAIT            (1<<0)
 #define I915_EXEC_FENCE_SIGNAL          (1<<1)
+#define __I915_EXEC_FENCE_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SIGNAL << 1))
        __u32 flags;
 };
 
diff --git a/tools/include/uapi/linux/kcmp.h b/tools/include/uapi/linux/kcmp.h
new file mode 100644 (file)
index 0000000..481e103
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _UAPI_LINUX_KCMP_H
+#define _UAPI_LINUX_KCMP_H
+
+#include <linux/types.h>
+
+/* Comparison type */
+enum kcmp_type {
+       KCMP_FILE,
+       KCMP_VM,
+       KCMP_FILES,
+       KCMP_FS,
+       KCMP_SIGHAND,
+       KCMP_IO,
+       KCMP_SYSVSEM,
+       KCMP_EPOLL_TFD,
+
+       KCMP_TYPES,
+};
+
+/* Slot for KCMP_EPOLL_TFD */
+struct kcmp_epoll_slot {
+       __u32 efd;              /* epoll file descriptor */
+       __u32 tfd;              /* target file number */
+       __u32 toff;             /* target offset within same numbered sequence */
+};
+
+#endif /* _UAPI_LINUX_KCMP_H */
diff --git a/tools/include/uapi/linux/prctl.h b/tools/include/uapi/linux/prctl.h
new file mode 100644 (file)
index 0000000..a8d0759
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef _LINUX_PRCTL_H
+#define _LINUX_PRCTL_H
+
+#include <linux/types.h>
+
+/* Values to pass as first argument to prctl() */
+
+#define PR_SET_PDEATHSIG  1  /* Second arg is a signal */
+#define PR_GET_PDEATHSIG  2  /* Second arg is a ptr to return the signal */
+
+/* Get/set current->mm->dumpable */
+#define PR_GET_DUMPABLE   3
+#define PR_SET_DUMPABLE   4
+
+/* Get/set unaligned access control bits (if meaningful) */
+#define PR_GET_UNALIGN   5
+#define PR_SET_UNALIGN   6
+# define PR_UNALIGN_NOPRINT    1       /* silently fix up unaligned user accesses */
+# define PR_UNALIGN_SIGBUS     2       /* generate SIGBUS on unaligned user access */
+
+/* Get/set whether or not to drop capabilities on setuid() away from
+ * uid 0 (as per security/commoncap.c) */
+#define PR_GET_KEEPCAPS   7
+#define PR_SET_KEEPCAPS   8
+
+/* Get/set floating-point emulation control bits (if meaningful) */
+#define PR_GET_FPEMU  9
+#define PR_SET_FPEMU 10
+# define PR_FPEMU_NOPRINT      1       /* silently emulate fp operations accesses */
+# define PR_FPEMU_SIGFPE       2       /* don't emulate fp operations, send SIGFPE instead */
+
+/* Get/set floating-point exception mode (if meaningful) */
+#define PR_GET_FPEXC   11
+#define PR_SET_FPEXC   12
+# define PR_FP_EXC_SW_ENABLE   0x80    /* Use FPEXC for FP exception enables */
+# define PR_FP_EXC_DIV         0x010000        /* floating point divide by zero */
+# define PR_FP_EXC_OVF         0x020000        /* floating point overflow */
+# define PR_FP_EXC_UND         0x040000        /* floating point underflow */
+# define PR_FP_EXC_RES         0x080000        /* floating point inexact result */
+# define PR_FP_EXC_INV         0x100000        /* floating point invalid operation */
+# define PR_FP_EXC_DISABLED    0       /* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV    1       /* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC       2       /* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE     3       /* precise exception mode */
+
+/* Get/set whether we use statistical process timing or accurate timestamp
+ * based process timing */
+#define PR_GET_TIMING   13
+#define PR_SET_TIMING   14
+# define PR_TIMING_STATISTICAL  0       /* Normal, traditional,
+                                                   statistical process timing */
+# define PR_TIMING_TIMESTAMP    1       /* Accurate timestamp based
+                                                   process timing */
+
+#define PR_SET_NAME    15              /* Set process name */
+#define PR_GET_NAME    16              /* Get process name */
+
+/* Get/set process endian */
+#define PR_GET_ENDIAN  19
+#define PR_SET_ENDIAN  20
+# define PR_ENDIAN_BIG         0
+# define PR_ENDIAN_LITTLE      1       /* True little endian mode */
+# define PR_ENDIAN_PPC_LITTLE  2       /* "PowerPC" pseudo little endian */
+
+/* Get/set process seccomp mode */
+#define PR_GET_SECCOMP 21
+#define PR_SET_SECCOMP 22
+
+/* Get/set the capability bounding set (as per security/commoncap.c) */
+#define PR_CAPBSET_READ 23
+#define PR_CAPBSET_DROP 24
+
+/* Get/set the process' ability to use the timestamp counter instruction */
+#define PR_GET_TSC 25
+#define PR_SET_TSC 26
+# define PR_TSC_ENABLE         1       /* allow the use of the timestamp counter */
+# define PR_TSC_SIGSEGV                2       /* throw a SIGSEGV instead of reading the TSC */
+
+/* Get/set securebits (as per security/commoncap.c) */
+#define PR_GET_SECUREBITS 27
+#define PR_SET_SECUREBITS 28
+
+/*
+ * Get/set the timerslack as used by poll/select/nanosleep
+ * A value of 0 means "use default"
+ */
+#define PR_SET_TIMERSLACK 29
+#define PR_GET_TIMERSLACK 30
+
+#define PR_TASK_PERF_EVENTS_DISABLE            31
+#define PR_TASK_PERF_EVENTS_ENABLE             32
+
+/*
+ * Set early/late kill mode for hwpoison memory corruption.
+ * This influences when the process gets killed on a memory corruption.
+ */
+#define PR_MCE_KILL    33
+# define PR_MCE_KILL_CLEAR   0
+# define PR_MCE_KILL_SET     1
+
+# define PR_MCE_KILL_LATE    0
+# define PR_MCE_KILL_EARLY   1
+# define PR_MCE_KILL_DEFAULT 2
+
+#define PR_MCE_KILL_GET 34
+
+/*
+ * Tune up process memory map specifics.
+ */
+#define PR_SET_MM              35
+# define PR_SET_MM_START_CODE          1
+# define PR_SET_MM_END_CODE            2
+# define PR_SET_MM_START_DATA          3
+# define PR_SET_MM_END_DATA            4
+# define PR_SET_MM_START_STACK         5
+# define PR_SET_MM_START_BRK           6
+# define PR_SET_MM_BRK                 7
+# define PR_SET_MM_ARG_START           8
+# define PR_SET_MM_ARG_END             9
+# define PR_SET_MM_ENV_START           10
+# define PR_SET_MM_ENV_END             11
+# define PR_SET_MM_AUXV                        12
+# define PR_SET_MM_EXE_FILE            13
+# define PR_SET_MM_MAP                 14
+# define PR_SET_MM_MAP_SIZE            15
+
+/*
+ * This structure provides new memory descriptor
+ * map which mostly modifies /proc/pid/stat[m]
+ * output for a task. This mostly done in a
+ * sake of checkpoint/restore functionality.
+ */
+struct prctl_mm_map {
+       __u64   start_code;             /* code section bounds */
+       __u64   end_code;
+       __u64   start_data;             /* data section bounds */
+       __u64   end_data;
+       __u64   start_brk;              /* heap for brk() syscall */
+       __u64   brk;
+       __u64   start_stack;            /* stack starts at */
+       __u64   arg_start;              /* command line arguments bounds */
+       __u64   arg_end;
+       __u64   env_start;              /* environment variables bounds */
+       __u64   env_end;
+       __u64   *auxv;                  /* auxiliary vector */
+       __u32   auxv_size;              /* vector size */
+       __u32   exe_fd;                 /* /proc/$pid/exe link file */
+};
+
+/*
+ * Set specific pid that is allowed to ptrace the current task.
+ * A value of 0 mean "no process".
+ */
+#define PR_SET_PTRACER 0x59616d61
+# define PR_SET_PTRACER_ANY ((unsigned long)-1)
+
+#define PR_SET_CHILD_SUBREAPER 36
+#define PR_GET_CHILD_SUBREAPER 37
+
+/*
+ * If no_new_privs is set, then operations that grant new privileges (i.e.
+ * execve) will either fail or not grant them.  This affects suid/sgid,
+ * file capabilities, and LSMs.
+ *
+ * Operations that merely manipulate or drop existing privileges (setresuid,
+ * capset, etc.) will still work.  Drop those privileges if you want them gone.
+ *
+ * Changing LSM security domain is considered a new privilege.  So, for example,
+ * asking selinux for a specific new context (e.g. with runcon) will result
+ * in execve returning -EPERM.
+ *
+ * See Documentation/prctl/no_new_privs.txt for more details.
+ */
+#define PR_SET_NO_NEW_PRIVS    38
+#define PR_GET_NO_NEW_PRIVS    39
+
+#define PR_GET_TID_ADDRESS     40
+
+#define PR_SET_THP_DISABLE     41
+#define PR_GET_THP_DISABLE     42
+
+/*
+ * Tell the kernel to start/stop helping userspace manage bounds tables.
+ */
+#define PR_MPX_ENABLE_MANAGEMENT  43
+#define PR_MPX_DISABLE_MANAGEMENT 44
+
+#define PR_SET_FP_MODE         45
+#define PR_GET_FP_MODE         46
+# define PR_FP_MODE_FR         (1 << 0)        /* 64b FP registers */
+# define PR_FP_MODE_FRE                (1 << 1)        /* 32b compatibility */
+
+/* Control the ambient capability set */
+#define PR_CAP_AMBIENT                 47
+# define PR_CAP_AMBIENT_IS_SET         1
+# define PR_CAP_AMBIENT_RAISE          2
+# define PR_CAP_AMBIENT_LOWER          3
+# define PR_CAP_AMBIENT_CLEAR_ALL      4
+
+#endif /* _LINUX_PRCTL_H */
index c0e26ad1fa7e3dbd212b3a4fd02fbcc4d8afc74c..9b341584eb1b56b05761bea127ee6cf94eacc190 100644 (file)
@@ -1757,11 +1757,14 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
                if (insn->dead_end)
                        return 0;
 
-               insn = next_insn;
-               if (!insn) {
+               if (!next_insn) {
+                       if (state.cfa.base == CFI_UNDEFINED)
+                               return 0;
                        WARN("%s: unexpected end of section", sec->name);
                        return 1;
                }
+
+               insn = next_insn;
        }
 
        return 0;
index 31e0f91438400677d654f0d23ea1011dc69588ed..07f32991982840b74b6feaed10056c4a0127083c 100644 (file)
@@ -70,7 +70,7 @@ static void cmd_usage(void)
 
        printf("\n");
 
-       exit(1);
+       exit(129);
 }
 
 static void handle_options(int *argc, const char ***argv)
@@ -86,9 +86,7 @@ static void handle_options(int *argc, const char ***argv)
                        break;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
-                       fprintf(stderr, "\n Usage: %s\n",
-                               objtool_usage_string);
-                       exit(1);
+                       cmd_usage();
                }
 
                (*argv)++;
index f709de54707b714feff11e3e0e7f28cbb0c9fb8d..e2a897ae3596b763e66b41bb27e0ae03bb6ceffa 100644 (file)
@@ -8,7 +8,8 @@ perf-list - List all symbolic event types
 SYNOPSIS
 --------
 [verse]
-'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|sdt|event_glob]
+'perf list' [--no-desc] [--long-desc]
+            [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]
 
 DESCRIPTION
 -----------
@@ -47,6 +48,8 @@ counted. The following modifiers exist:
  P - use maximum detected precise level
  S - read sample value (PERF_SAMPLE_READ)
  D - pin the event to the PMU
+ W - group is weak and will fallback to non-group if not schedulable,
+     only supported in 'perf stat' for now.
 
 The 'p' modifier can be used for specifying how precise the instruction
 address should be. The 'p' modifier can be specified multiple times:
@@ -201,7 +204,7 @@ For example Intel Core CPUs typically have four generic performance counters
 for the core, plus three fixed counters for instructions, cycles and
 ref-cycles. Some special events have restrictions on which counter they
 can schedule, and may not support multiple instances in a single group.
-When too many events are specified in the group none of them will not
+When too many events are specified in the group some of them will not
 be measured.
 
 Globally pinned events can limit the number of counters available for
@@ -246,6 +249,10 @@ To limit the list use:
 
 . 'sdt' to list all Statically Defined Tracepoint events.
 
+. 'metric' to list metrics
+
+. 'metricgroup' to list metricgroups with metrics.
+
 . If none of the above is matched, it will apply the supplied glob to all
   events, printing the ones that match.
 
index 63526f4416ea4fb81292fafcfe6fdd55d9955639..5a626ef666c294368271670b30481db3352050b5 100644 (file)
@@ -377,6 +377,8 @@ symbolic names, e.g. on x86, ax, si. To list the available registers use
 --intr-regs=\?. To name registers, pass a comma separated list such as
 --intr-regs=ax,bx. The list of register is architecture dependent.
 
+--user-regs::
+Capture user registers at sample time. Same arguments as -I.
 
 --running-time::
 Record running and enabled time for read events (:S)
index 383a98d992ed5570564bf01f90cd9a2ba513e287..ddde2b54af572e2407c364cd6441aaba2742e43e 100644 (file)
@@ -434,7 +434,8 @@ include::itrace.txt[]
 
 --inline::
        If a callgraph address belongs to an inlined function, the inline stack
-       will be printed. Each entry is function name or file/line.
+       will be printed. Each entry is function name or file/line. Enabled by
+       default, disable with --no-inline.
 
 include::callchain-overhead-calculation.txt[]
 
index a092a2499e8f8f2003681369c140a19a84b9c401..55b67338548e1d116f8dc80555b30f9798c96bfc 100644 (file)
@@ -106,6 +106,14 @@ OPTIONS for 'perf sched timehist'
 --max-stack::
        Maximum number of functions to display in backtrace, default 5.
 
+-p=::
+--pid=::
+       Only show events for given process ID (comma separated list).
+
+-t=::
+--tid=::
+       Only show events for given thread ID (comma separated list).
+
 -s::
 --summary::
     Show only a summary of scheduling by thread with min, max, and average
index 18dfcfa384542c32d110fe5873c26571d4543019..2811fcf684cbffb0bec21941520910939b3a5164 100644 (file)
@@ -116,8 +116,8 @@ OPTIONS
 --fields::
         Comma separated list of fields to print. Options are:
         comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
-        srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff,
-        callindent, insn, insnlen, synth, phys_addr.
+        srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
+        brstackoff, callindent, insn, insnlen, synth, phys_addr.
         Field list can be prepended with the type, trace, sw or hw,
         to indicate to which event type the field list applies.
         e.g., -F sw:comm,tid,time,ip,sym  and -F trace:time,cpu,trace
@@ -325,9 +325,14 @@ include::itrace.txt[]
        Set the maximum number of program blocks to print with brstackasm for
        each sample.
 
+--per-event-dump::
+       Create per event files with a "perf.data.EVENT.dump" name instead of
+        printing to stdout, useful, for instance, for generating flamegraphs.
+
 --inline::
        If a callgraph address belongs to an inlined function, the inline stack
-       will be printed. Each entry has function name and file/line.
+       will be printed. Each entry has function name and file/line. Enabled by
+       default, disable with --no-inline.
 
 SEE ALSO
 --------
index c37d61682dfb1771b9b013d4669b59364f979656..823fce7674bb133e2bfd6a67e42c757e3f930db4 100644 (file)
@@ -199,6 +199,13 @@ Aggregate counts per processor socket for system-wide mode measurements.
 --per-core::
 Aggregate counts per physical processor for system-wide mode measurements.
 
+-M::
+--metrics::
+Print metrics or metricgroups specified in a comma separated list.
+For a group all metrics from the group are added.
+The events from the metrics are automatically measured.
+See perf list output for the possble metrics and metricgroups.
+
 -A::
 --no-aggr::
 Do not aggregate counts across all monitored CPUs.
index d864ea6fd367efb63e1a9411f6e74e8d42ab3428..4353262bc462b05cc3c4008c1a39e06ee76b758b 100644 (file)
@@ -240,6 +240,9 @@ Default is to monitor all CPUS.
 --force::
        Don't do ownership validation.
 
+--num-thread-synthesize::
+       The number of threads to run when synthesizing events for existing processes.
+       By default, the number of threads equals to the number of online CPUs.
 
 INTERACTIVE PROMPTING KEYS
 --------------------------
index 91ef44bfaf3e3891cfa22ec1b8f71ba5c2216b5a..68cf1360a3f3926e91d928eff8735c39e08bcae0 100644 (file)
@@ -173,7 +173,7 @@ AWK     = awk
 # non-config cases
 config := 1
 
-NON_CONFIG_TARGETS := clean TAGS tags cscope help install-doc install-man install-html install-info install-pdf doc man html info pdf
+NON_CONFIG_TARGETS := clean python-clean TAGS tags cscope help install-doc install-man install-html install-info install-pdf doc man html info pdf
 
 ifdef MAKECMDGOALS
 ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
@@ -420,6 +420,13 @@ sndrv_pcm_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh
 $(sndrv_pcm_ioctl_array): $(sndrv_pcm_hdr_dir)/asound.h $(sndrv_pcm_ioctl_tbl)
        $(Q)$(SHELL) '$(sndrv_pcm_ioctl_tbl)' $(sndrv_pcm_hdr_dir) > $@
 
+kcmp_type_array := $(beauty_outdir)/kcmp_type_array.c
+kcmp_hdr_dir := $(srctree)/tools/include/uapi/linux/
+kcmp_type_tbl := $(srctree)/tools/perf/trace/beauty/kcmp_type.sh
+
+$(kcmp_type_array): $(kcmp_hdr_dir)/kcmp.h $(kcmp_type_tbl)
+       $(Q)$(SHELL) '$(kcmp_type_tbl)' $(kcmp_hdr_dir) > $@
+
 kvm_ioctl_array := $(beauty_ioctl_outdir)/kvm_ioctl_array.c
 kvm_hdr_dir := $(srctree)/tools/include/uapi/linux
 kvm_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/kvm_ioctl.sh
@@ -441,6 +448,20 @@ perf_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/perf_ioctl.sh
 $(perf_ioctl_array): $(perf_hdr_dir)/perf_event.h $(perf_ioctl_tbl)
        $(Q)$(SHELL) '$(perf_ioctl_tbl)' $(perf_hdr_dir) > $@
 
+madvise_behavior_array := $(beauty_outdir)/madvise_behavior_array.c
+madvise_hdr_dir := $(srctree)/tools/include/uapi/asm-generic/
+madvise_behavior_tbl := $(srctree)/tools/perf/trace/beauty/madvise_behavior.sh
+
+$(madvise_behavior_array): $(madvise_hdr_dir)/mman-common.h $(madvise_behavior_tbl)
+       $(Q)$(SHELL) '$(madvise_behavior_tbl)' $(madvise_hdr_dir) > $@
+
+prctl_option_array := $(beauty_outdir)/prctl_option_array.c
+prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/
+prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh
+
+$(prctl_option_array): $(prctl_hdr_dir)/prctl.h $(prctl_option_tbl)
+       $(Q)$(SHELL) '$(prctl_option_tbl)' $(prctl_hdr_dir) > $@
+
 all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
 
 $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST)
@@ -539,9 +560,12 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
        $(pkey_alloc_access_rights_array) \
        $(sndrv_pcm_ioctl_array) \
        $(sndrv_ctl_ioctl_array) \
+       $(kcmp_type_array) \
        $(kvm_ioctl_array) \
        $(vhost_virtio_ioctl_array) \
-       $(perf_ioctl_array)
+       $(madvise_behavior_array) \
+       $(perf_ioctl_array) \
+       $(prctl_option_array)
 
 $(OUTPUT)%.o: %.c prepare FORCE
        $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
@@ -802,7 +826,10 @@ config-clean:
        $(call QUIET_CLEAN, config)
        $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null
 
-clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean fixdep-clean
+python-clean:
+       $(python-clean)
+
+clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean fixdep-clean python-clean
        $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
        $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
        $(Q)$(RM) $(OUTPUT).config-detected
@@ -811,15 +838,17 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
                $(OUTPUT)util/intel-pt-decoder/inat-tables.c \
                $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
                $(OUTPUT)pmu-events/pmu-events.c \
+               $(OUTPUT)$(madvise_behavior_array) \
                $(OUTPUT)$(drm_ioctl_array) \
                $(OUTPUT)$(pkey_alloc_access_rights_array) \
                $(OUTPUT)$(sndrv_ctl_ioctl_array) \
                $(OUTPUT)$(sndrv_pcm_ioctl_array) \
                $(OUTPUT)$(kvm_ioctl_array) \
+               $(OUTPUT)$(kcmp_type_array) \
                $(OUTPUT)$(vhost_virtio_ioctl_array) \
-               $(OUTPUT)$(perf_ioctl_array)
+               $(OUTPUT)$(perf_ioctl_array) \
+               $(OUTPUT)$(prctl_option_array)
        $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
-       $(python-clean)
 
 #
 # To provide FEATURE-DUMP into $(FEATURE_DUMP_COPY)
index b39b16395aac5c251c5ce9c4270258bd31564700..f64516d5b23eb6f8001d10ad21888929d4a068df 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
 #include <sys/types.h>
 #include <regex.h>
 
@@ -24,7 +25,7 @@ static struct ins_ops *arm__associate_instruction_ops(struct arch *arch, const c
        return ops;
 }
 
-static int arm__annotate_init(struct arch *arch)
+static int arm__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
 {
        struct arm_annotate *arm;
        int err;
index 9a3e0523e2c937e0f06110906d6a6d155797c631..6688977e4ac7745e77b1e08a9a4e4a5ded16557a 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
 #include <sys/types.h>
 #include <regex.h>
 
@@ -26,7 +27,7 @@ static struct ins_ops *arm64__associate_instruction_ops(struct arch *arch, const
        return ops;
 }
 
-static int arm64__annotate_init(struct arch *arch)
+static int arm64__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
 {
        struct arm64_annotate *arm;
        int err;
index b7bc04980fe870fed34cdb362d5d13f0fd1aa269..a3f423c27caea44e7706ff8e8d00c9e811fa2ef0 100644 (file)
@@ -1,4 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+
 static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name)
 {
        int i;
@@ -47,7 +49,7 @@ static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, con
        return ops;
 }
 
-static int powerpc__annotate_init(struct arch *arch)
+static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
 {
        if (!arch->initialized) {
                arch->initialized = true;
index c9a81673e8aa37b30cbaf35cd7c0d43b2e535992..e0e466c650dfad10c6a0d0187be4331d05dddde3 100644 (file)
@@ -1,4 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+
 static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *name)
 {
        struct ins_ops *ops = NULL;
@@ -20,7 +22,7 @@ static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *na
        return ops;
 }
 
-static int s390__annotate_init(struct arch *arch)
+static int s390__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
 {
        if (!arch->initialized) {
                arch->initialized = true;
index 4adfb4ce28645f545a689772125f7e67bc5aa5aa..5bd1ba8c02829e8f571e7d6453b6ea76165d8445 100644 (file)
@@ -123,3 +123,17 @@ static int x86__cpuid_parse(struct arch *arch, char *cpuid)
 
        return -1;
 }
+
+static int x86__annotate_init(struct arch *arch, char *cpuid)
+{
+       int err = 0;
+
+       if (arch->initialized)
+               return 0;
+
+       if (cpuid)
+               err = x86__cpuid_parse(arch, cpuid);
+
+       arch->initialized = true;
+       return err;
+}
index 9834fdc7c59e28ec943018fdf33a9b18527994fa..c1bd979b957be76a2ff55f45d0d4011c056e0de7 100644 (file)
@@ -9,7 +9,6 @@ struct test;
 int test__rdpmc(struct test *test __maybe_unused, int subtest);
 int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest);
 int test__insn_x86(struct test *test __maybe_unused, int subtest);
-int test__intel_cqm_count_nmi_context(struct test *test __maybe_unused, int subtest);
 
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 struct thread;
index cbb7e978166bcc67209f31a9600149c6a5fe30bc..8e2c5a38c3b90c18c2159b8f91e54500734cd9f3 100644 (file)
@@ -5,4 +5,3 @@ libperf-y += arch-tests.o
 libperf-y += rdpmc.o
 libperf-y += perf-time-to-tsc.o
 libperf-$(CONFIG_AUXTRACE) += insn-x86.o
-libperf-y += intel-cqm.o
index 34a078136a47c70877959141e5f131a7fdc56cae..cc1802ff54109ebccd23130fcc37f023d6e5ae9c 100644 (file)
@@ -24,10 +24,6 @@ struct test arch_tests[] = {
                .func = test__insn_x86,
        },
 #endif
-       {
-               .desc = "Intel cqm nmi context read",
-               .func = test__intel_cqm_count_nmi_context,
-       },
        {
                .func = NULL,
        },
index 3d32aa45016d9b6a5ef878c2168bc36573f48d77..f15731a3d438f4a642a3575193a94f1bb6148010 100644 (file)
@@ -357,7 +357,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
        }
 
        if (total_nr_samples == 0) {
-               ui__error("The %s file has no samples!\n", session->file->path);
+               ui__error("The %s file has no samples!\n", session->data->file.path);
                goto out;
        }
 
@@ -401,7 +401,7 @@ int cmd_annotate(int argc, const char **argv)
                        .ordering_requires_timestamps = true,
                },
        };
-       struct perf_data_file file = {
+       struct perf_data data = {
                .mode  = PERF_DATA_MODE_READ,
        };
        struct option options[] = {
@@ -411,7 +411,7 @@ int cmd_annotate(int argc, const char **argv)
                   "only consider symbols in these dsos"),
        OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
                    "symbol to annotate"),
-       OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
+       OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('q', "quiet", &quiet, "do now show any message"),
@@ -483,9 +483,9 @@ int cmd_annotate(int argc, const char **argv)
        if (quiet)
                perf_quiet_option();
 
-       file.path  = input_name;
+       data.file.path = input_name;
 
-       annotate.session = perf_session__new(&file, false, &annotate.tool);
+       annotate.session = perf_session__new(&data, false, &annotate.tool);
        if (annotate.session == NULL)
                return -1;
 
index 5f53a7ad5ef3e7981482ec34e0e8c3698aa8d2ab..3d354ba6e9c59884ebed61b2ba512b42e0d9359a 100644 (file)
@@ -312,7 +312,7 @@ int cmd_buildid_cache(int argc, const char **argv)
                   *kcore_filename = NULL;
        char sbuf[STRERR_BUFSIZE];
 
-       struct perf_data_file file = {
+       struct perf_data data = {
                .mode  = PERF_DATA_MODE_READ,
        };
        struct perf_session *session = NULL;
@@ -353,10 +353,10 @@ int cmd_buildid_cache(int argc, const char **argv)
                nsi = nsinfo__new(ns_id);
 
        if (missing_filename) {
-               file.path = missing_filename;
-               file.force = force;
+               data.file.path = missing_filename;
+               data.force     = force;
 
-               session = perf_session__new(&file, false, NULL);
+               session = perf_session__new(&data, false, NULL);
                if (session == NULL)
                        return -1;
        }
index ec2f327cd79d7bf1ed61f421aefe4932a7c7575a..78abbe8d9d5ff0a8c2c396619d1566f2c00def44 100644 (file)
@@ -51,10 +51,12 @@ static bool dso__skip_buildid(struct dso *dso, int with_hits)
 static int perf_session__list_build_ids(bool force, bool with_hits)
 {
        struct perf_session *session;
-       struct perf_data_file file = {
-               .path  = input_name,
-               .mode  = PERF_DATA_MODE_READ,
-               .force = force,
+       struct perf_data data = {
+               .file      = {
+                       .path = input_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = force,
        };
 
        symbol__elf_init();
@@ -64,7 +66,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
        if (filename__fprintf_build_id(input_name, stdout) > 0)
                goto out;
 
-       session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
+       session = perf_session__new(&data, false, &build_id__mark_dso_hit_ops);
        if (session == NULL)
                return -1;
 
@@ -72,7 +74,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
         * We take all buildids when the file contains AUX area tracing data
         * because we do not decode the trace because it would take too long.
         */
-       if (!perf_data_file__is_pipe(&file) &&
+       if (!perf_data__is_pipe(&data) &&
            perf_header__has_feat(&session->header, HEADER_AUXTRACE))
                with_hits = false;
 
@@ -80,7 +82,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
         * in pipe-mode, the only way to get the buildids is to parse
         * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
         */
-       if (with_hits || perf_data_file__is_pipe(&file))
+       if (with_hits || perf_data__is_pipe(&data))
                perf_session__process_events(session);
 
        perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
index fd32ad08c6d47d42f962f763877d7e0c4c1b7fa8..17855c4626a08b7d4add1b5c9922653a5be39ad4 100644 (file)
@@ -2524,7 +2524,7 @@ static int perf_c2c__report(int argc, const char **argv)
 {
        struct perf_session *session;
        struct ui_progress prog;
-       struct perf_data_file file = {
+       struct perf_data data = {
                .mode = PERF_DATA_MODE_READ,
        };
        char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
@@ -2573,8 +2573,8 @@ static int perf_c2c__report(int argc, const char **argv)
        if (!input_name || !strlen(input_name))
                input_name = "perf.data";
 
-       file.path  = input_name;
-       file.force = symbol_conf.force;
+       data.file.path = input_name;
+       data.force     = symbol_conf.force;
 
        err = setup_display(display);
        if (err)
@@ -2592,7 +2592,7 @@ static int perf_c2c__report(int argc, const char **argv)
                goto out;
        }
 
-       session = perf_session__new(&file, 0, &c2c.tool);
+       session = perf_session__new(&data, 0, &c2c.tool);
        if (session == NULL) {
                pr_debug("No memory for session\n");
                goto out;
@@ -2612,7 +2612,7 @@ static int perf_c2c__report(int argc, const char **argv)
                goto out_session;
 
        /* No pipe support at the moment. */
-       if (perf_data_file__is_pipe(session->file)) {
+       if (perf_data__is_pipe(session->data)) {
                pr_debug("No pipe support at the moment.\n");
                goto out_session;
        }
@@ -2733,6 +2733,7 @@ static int perf_c2c__record(int argc, const char **argv)
                if (!perf_mem_events[j].supported) {
                        pr_err("failed: event '%s' not supported\n",
                               perf_mem_events[j].name);
+                       free(rec_argv);
                        return -1;
                }
 
index abfa49eaf7fd1039ead9a753a0d8bb65d9dd0a90..514f70f95b5788164ef11eb138e52eb6a2669b7b 100644 (file)
@@ -35,8 +35,7 @@ static struct option config_options[] = {
        OPT_END()
 };
 
-static int set_config(struct perf_config_set *set, const char *file_name,
-                     const char *var, const char *value)
+static int set_config(struct perf_config_set *set, const char *file_name)
 {
        struct perf_config_section *section = NULL;
        struct perf_config_item *item = NULL;
@@ -50,7 +49,6 @@ static int set_config(struct perf_config_set *set, const char *file_name,
        if (!fp)
                return -1;
 
-       perf_config_set__collect(set, file_name, var, value);
        fprintf(fp, "%s\n", first_line);
 
        /* overwrite configvariables */
@@ -162,6 +160,7 @@ int cmd_config(int argc, const char **argv)
        struct perf_config_set *set;
        char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
        const char *config_filename;
+       bool changed = false;
 
        argc = parse_options(argc, argv, config_options, config_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
@@ -232,15 +231,26 @@ int cmd_config(int argc, const char **argv)
                                        goto out_err;
                                }
                        } else {
-                               if (set_config(set, config_filename, var, value) < 0) {
-                                       pr_err("Failed to set '%s=%s' on %s\n",
-                                              var, value, config_filename);
+                               if (perf_config_set__collect(set, config_filename,
+                                                            var, value) < 0) {
+                                       pr_err("Failed to add '%s=%s'\n",
+                                              var, value);
                                        free(arg);
                                        goto out_err;
                                }
+                               changed = true;
                        }
                        free(arg);
                }
+
+               if (!changed)
+                       break;
+
+               if (set_config(set, config_filename) < 0) {
+                       pr_err("Failed to set the configs on %s\n",
+                              config_filename);
+                       goto out_err;
+               }
        }
 
        ret = 0;
index 56223bdfa205dab7db28bd9dac9c2cd6e60ec7ae..d660cb7b222b23bfa6646dfd1fd04d75ca55d337 100644 (file)
@@ -48,7 +48,7 @@ struct diff_hpp_fmt {
 
 struct data__file {
        struct perf_session     *session;
-       struct perf_data_file   file;
+       struct perf_data         data;
        int                      idx;
        struct hists            *hists;
        struct diff_hpp_fmt      fmt[PERF_HPP_DIFF__MAX_INDEX];
@@ -708,7 +708,7 @@ static void data__fprintf(void)
 
        data__for_each_file(i, d)
                fprintf(stdout, "#  [%d] %s %s\n",
-                       d->idx, d->file.path,
+                       d->idx, d->data.file.path,
                        !d->idx ? "(Baseline)" : "");
 
        fprintf(stdout, "#\n");
@@ -777,16 +777,16 @@ static int __cmd_diff(void)
        int ret = -EINVAL, i;
 
        data__for_each_file(i, d) {
-               d->session = perf_session__new(&d->file, false, &tool);
+               d->session = perf_session__new(&d->data, false, &tool);
                if (!d->session) {
-                       pr_err("Failed to open %s\n", d->file.path);
+                       pr_err("Failed to open %s\n", d->data.file.path);
                        ret = -1;
                        goto out_delete;
                }
 
                ret = perf_session__process_events(d->session);
                if (ret) {
-                       pr_err("Failed to process %s\n", d->file.path);
+                       pr_err("Failed to process %s\n", d->data.file.path);
                        goto out_delete;
                }
 
@@ -1287,11 +1287,11 @@ static int data_init(int argc, const char **argv)
                return -ENOMEM;
 
        data__for_each_file(i, d) {
-               struct perf_data_file *file = &d->file;
+               struct perf_data *data = &d->data;
 
-               file->path  = use_default ? defaults[i] : argv[i];
-               file->mode  = PERF_DATA_MODE_READ,
-               file->force = force,
+               data->file.path = use_default ? defaults[i] : argv[i];
+               data->mode      = PERF_DATA_MODE_READ,
+               data->force     = force,
 
                d->idx  = i;
        }
index cdd145613f602980f040e4766ac6a08548c0f28e..e06e822ce6348768ee12ac45d70f39c9d9827a90 100644 (file)
@@ -22,14 +22,16 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
 {
        struct perf_session *session;
        struct perf_evsel *pos;
-       struct perf_data_file file = {
-               .path = file_name,
-               .mode = PERF_DATA_MODE_READ,
-               .force = details->force,
+       struct perf_data data = {
+               .file      = {
+                       .path = file_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = details->force,
        };
        bool has_tracepoint = false;
 
-       session = perf_session__new(&file, 0, NULL);
+       session = perf_session__new(&data, 0, NULL);
        if (session == NULL)
                return -1;
 
index 3e0e73b0dc67642514831962c0b887abea69d86b..16a28547ca86864ae0fb32c16dc003a3aff62684 100644 (file)
@@ -36,7 +36,7 @@ struct perf_inject {
        bool                    strip;
        bool                    jit_mode;
        const char              *input_name;
-       struct perf_data_file   output;
+       struct perf_data        output;
        u64                     bytes_written;
        u64                     aux_id;
        struct list_head        samples;
@@ -53,7 +53,7 @@ static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
 {
        ssize_t size;
 
-       size = perf_data_file__write(&inject->output, buf, sz);
+       size = perf_data__write(&inject->output, buf, sz);
        if (size < 0)
                return -errno;
 
@@ -146,7 +146,7 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
        if (!inject->output.is_pipe) {
                off_t offset;
 
-               offset = lseek(inject->output.fd, 0, SEEK_CUR);
+               offset = lseek(inject->output.file.fd, 0, SEEK_CUR);
                if (offset == -1)
                        return -errno;
                ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
@@ -155,11 +155,11 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
                        return ret;
        }
 
-       if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
+       if (perf_data__is_pipe(session->data) || !session->one_mmap) {
                ret = output_bytes(inject, event, event->header.size);
                if (ret < 0)
                        return ret;
-               ret = copy_bytes(inject, perf_data_file__fd(session->file),
+               ret = copy_bytes(inject, perf_data__fd(session->data),
                                 event->auxtrace.size);
        } else {
                ret = output_bytes(inject, event,
@@ -638,8 +638,8 @@ static int __cmd_inject(struct perf_inject *inject)
 {
        int ret = -EINVAL;
        struct perf_session *session = inject->session;
-       struct perf_data_file *file_out = &inject->output;
-       int fd = perf_data_file__fd(file_out);
+       struct perf_data *data_out = &inject->output;
+       int fd = perf_data__fd(data_out);
        u64 output_data_offset;
 
        signal(SIGINT, sig_handler);
@@ -694,14 +694,14 @@ static int __cmd_inject(struct perf_inject *inject)
        if (!inject->itrace_synth_opts.set)
                auxtrace_index__free(&session->auxtrace_index);
 
-       if (!file_out->is_pipe)
+       if (!data_out->is_pipe)
                lseek(fd, output_data_offset, SEEK_SET);
 
        ret = perf_session__process_events(session);
        if (ret)
                return ret;
 
-       if (!file_out->is_pipe) {
+       if (!data_out->is_pipe) {
                if (inject->build_ids)
                        perf_header__set_feat(&session->header,
                                              HEADER_BUILD_ID);
@@ -776,11 +776,13 @@ int cmd_inject(int argc, const char **argv)
                .input_name  = "-",
                .samples = LIST_HEAD_INIT(inject.samples),
                .output = {
-                       .path = "-",
-                       .mode = PERF_DATA_MODE_WRITE,
+                       .file      = {
+                               .path = "-",
+                       },
+                       .mode      = PERF_DATA_MODE_WRITE,
                },
        };
-       struct perf_data_file file = {
+       struct perf_data data = {
                .mode = PERF_DATA_MODE_READ,
        };
        int ret;
@@ -790,7 +792,7 @@ int cmd_inject(int argc, const char **argv)
                            "Inject build-ids into the output stream"),
                OPT_STRING('i', "input", &inject.input_name, "file",
                           "input file name"),
-               OPT_STRING('o', "output", &inject.output.path, "file",
+               OPT_STRING('o', "output", &inject.output.file.path, "file",
                           "output file name"),
                OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
                            "Merge sched-stat and sched-switch for getting events "
@@ -802,7 +804,7 @@ int cmd_inject(int argc, const char **argv)
                         "be more verbose (show build ids, etc)"),
                OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
                           "kallsyms pathname"),
-               OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
+               OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
                OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
                                    NULL, "opts", "Instruction Tracing options",
                                    itrace_parse_synth_opts),
@@ -830,15 +832,15 @@ int cmd_inject(int argc, const char **argv)
                return -1;
        }
 
-       if (perf_data_file__open(&inject.output)) {
+       if (perf_data__open(&inject.output)) {
                perror("failed to create output file");
                return -1;
        }
 
        inject.tool.ordered_events = inject.sched_stat;
 
-       file.path = inject.input_name;
-       inject.session = perf_session__new(&file, true, &inject.tool);
+       data.file.path = inject.input_name;
+       inject.session = perf_session__new(&data, true, &inject.tool);
        if (inject.session == NULL)
                return -1;
 
index 35d4b9c9a9e8ffd6e191807e66017b87faf3c2d4..557d391f564a1d22fe04a590698d53d72e33c3a9 100644 (file)
@@ -1894,7 +1894,7 @@ int cmd_kmem(int argc, const char **argv)
 {
        const char * const default_slab_sort = "frag,hit,bytes";
        const char * const default_page_sort = "bytes,hit";
-       struct perf_data_file file = {
+       struct perf_data data = {
                .mode = PERF_DATA_MODE_READ,
        };
        const struct option kmem_options[] = {
@@ -1910,7 +1910,7 @@ int cmd_kmem(int argc, const char **argv)
                     "page, order, migtype, gfp", parse_sort_opt),
        OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt),
        OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
-       OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
+       OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
        OPT_CALLBACK_NOOPT(0, "slab", NULL, NULL, "Analyze slab allocator",
                           parse_slab_opt),
        OPT_CALLBACK_NOOPT(0, "page", NULL, NULL, "Analyze page allocator",
@@ -1950,9 +1950,9 @@ int cmd_kmem(int argc, const char **argv)
                return __cmd_record(argc, argv);
        }
 
-       file.path = input_name;
+       data.file.path = input_name;
 
-       kmem_session = session = perf_session__new(&file, false, &perf_kmem);
+       kmem_session = session = perf_session__new(&data, false, &perf_kmem);
        if (session == NULL)
                return -1;
 
@@ -1984,7 +1984,8 @@ int cmd_kmem(int argc, const char **argv)
 
        if (perf_time__parse_str(&ptime, time_str) != 0) {
                pr_err("Invalid time string\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_delete;
        }
 
        if (!strcmp(argv[0], "stat")) {
index 5fb40368d5d12ff04e41abd36abbe9f5bc1f3045..0c36f2ac6a0e0419a61306be7161ea9462b3aead 100644 (file)
@@ -35,7 +35,6 @@
 #include <termios.h>
 #include <semaphore.h>
 #include <signal.h>
-#include <pthread.h>
 #include <math.h>
 
 static const char *get_filename_for_perf_kvm(void)
@@ -1069,10 +1068,12 @@ static int read_events(struct perf_kvm_stat *kvm)
                .namespaces             = perf_event__process_namespaces,
                .ordered_events         = true,
        };
-       struct perf_data_file file = {
-               .path = kvm->file_name,
-               .mode = PERF_DATA_MODE_READ,
-               .force = kvm->force,
+       struct perf_data file = {
+               .file      = {
+                       .path = kvm->file_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = kvm->force,
        };
 
        kvm->tool = eops;
@@ -1360,7 +1361,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
                "perf kvm stat live [<options>]",
                NULL
        };
-       struct perf_data_file file = {
+       struct perf_data data = {
                .mode = PERF_DATA_MODE_WRITE,
        };
 
@@ -1434,7 +1435,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        /*
         * perf session
         */
-       kvm->session = perf_session__new(&file, false, &kvm->tool);
+       kvm->session = perf_session__new(&data, false, &kvm->tool);
        if (kvm->session == NULL) {
                err = -1;
                goto out;
@@ -1443,7 +1444,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        perf_session__set_id_hdr_size(kvm->session);
        ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true);
        machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target,
-                                   kvm->evlist->threads, false, kvm->opts.proc_map_timeout);
+                                   kvm->evlist->threads, false,
+                                   kvm->opts.proc_map_timeout, 1);
        err = kvm_live_open_events(kvm);
        if (err)
                goto out;
index eeedbe433776781d3b17fe33c78fb3d716d69bf3..ead221e49f003e67d9681e102160e5f9e2e1dbb8 100644 (file)
@@ -16,6 +16,7 @@
 #include "util/cache.h"
 #include "util/pmu.h"
 #include "util/debug.h"
+#include "util/metricgroup.h"
 #include <subcmd/parse-options.h>
 
 static bool desc_flag = true;
@@ -80,6 +81,10 @@ int cmd_list(int argc, const char **argv)
                                                long_desc_flag, details_flag);
                else if (strcmp(argv[i], "sdt") == 0)
                        print_sdt_events(NULL, NULL, raw_dump);
+               else if (strcmp(argv[i], "metric") == 0)
+                       metricgroup__print(true, false, NULL, raw_dump);
+               else if (strcmp(argv[i], "metricgroup") == 0)
+                       metricgroup__print(false, true, NULL, raw_dump);
                else if ((sep = strchr(argv[i], ':')) != NULL) {
                        int sep_idx;
 
@@ -97,6 +102,7 @@ int cmd_list(int argc, const char **argv)
                        s[sep_idx] = '\0';
                        print_tracepoint_events(s, s + sep_idx + 1, raw_dump);
                        print_sdt_events(s, s + sep_idx + 1, raw_dump);
+                       metricgroup__print(true, true, s, raw_dump);
                        free(s);
                } else {
                        if (asprintf(&s, "*%s*", argv[i]) < 0) {
@@ -113,6 +119,7 @@ int cmd_list(int argc, const char **argv)
                                                details_flag);
                        print_tracepoint_events(NULL, s, raw_dump);
                        print_sdt_events(NULL, s, raw_dump);
+                       metricgroup__print(true, true, NULL, raw_dump);
                        free(s);
                }
        }
index fe69cd6b89e1ab8b66d074accf813ed2fc8aab1e..6e0189df2b3baf96a34ac3053098bc9b331d9a7e 100644 (file)
@@ -865,13 +865,15 @@ static int __cmd_report(bool display_info)
                .namespaces      = perf_event__process_namespaces,
                .ordered_events  = true,
        };
-       struct perf_data_file file = {
-               .path = input_name,
-               .mode = PERF_DATA_MODE_READ,
-               .force = force,
+       struct perf_data data = {
+               .file      = {
+                       .path = input_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = force,
        };
 
-       session = perf_session__new(&file, false, &eops);
+       session = perf_session__new(&data, false, &eops);
        if (!session) {
                pr_err("Initializing perf session failed\n");
                return -1;
index 4db960085273064d8ee0e1ceca7a1ac3929150c4..506564651cda983c4dd996f0acba0f8c1e66f9a1 100644 (file)
@@ -113,6 +113,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
                if (!perf_mem_events[j].supported) {
                        pr_err("failed: event '%s' not supported\n",
                               perf_mem_events__name(j));
+                       free(rec_argv);
                        return -1;
                }
 
@@ -236,13 +237,15 @@ static int process_sample_event(struct perf_tool *tool,
 
 static int report_raw_events(struct perf_mem *mem)
 {
-       struct perf_data_file file = {
-               .path = input_name,
-               .mode = PERF_DATA_MODE_READ,
-               .force = mem->force,
+       struct perf_data data = {
+               .file      = {
+                       .path = input_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = mem->force,
        };
        int ret;
-       struct perf_session *session = perf_session__new(&file, false,
+       struct perf_session *session = perf_session__new(&data, false,
                                                         &mem->tool);
 
        if (session == NULL)
index 0c95ffefb6ccdbbee39b49a60f0efd8b3977a234..3d7f33e19df28d90c7e33dcc37ea823197de6731 100644 (file)
@@ -67,7 +67,7 @@ struct record {
        struct perf_tool        tool;
        struct record_opts      opts;
        u64                     bytes_written;
-       struct perf_data_file   file;
+       struct perf_data        data;
        struct auxtrace_record  *itr;
        struct perf_evlist      *evlist;
        struct perf_session     *session;
@@ -108,7 +108,7 @@ static bool switch_output_time(struct record *rec)
 
 static int record__write(struct record *rec, void *bf, size_t size)
 {
-       if (perf_data_file__write(rec->session->file, bf, size) < 0) {
+       if (perf_data__write(rec->session->data, bf, size) < 0) {
                pr_err("failed to write perf data, error: %m\n");
                return -1;
        }
@@ -130,107 +130,12 @@ static int process_synthesized_event(struct perf_tool *tool,
        return record__write(rec, event, event->header.size);
 }
 
-static int
-backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end)
+static int record__pushfn(void *to, void *bf, size_t size)
 {
-       struct perf_event_header *pheader;
-       u64 evt_head = head;
-       int size = mask + 1;
-
-       pr_debug2("backward_rb_find_range: buf=%p, head=%"PRIx64"\n", buf, head);
-       pheader = (struct perf_event_header *)(buf + (head & mask));
-       *start = head;
-       while (true) {
-               if (evt_head - head >= (unsigned int)size) {
-                       pr_debug("Finished reading backward ring buffer: rewind\n");
-                       if (evt_head - head > (unsigned int)size)
-                               evt_head -= pheader->size;
-                       *end = evt_head;
-                       return 0;
-               }
-
-               pheader = (struct perf_event_header *)(buf + (evt_head & mask));
-
-               if (pheader->size == 0) {
-                       pr_debug("Finished reading backward ring buffer: get start\n");
-                       *end = evt_head;
-                       return 0;
-               }
-
-               evt_head += pheader->size;
-               pr_debug3("move evt_head: %"PRIx64"\n", evt_head);
-       }
-       WARN_ONCE(1, "Shouldn't get here\n");
-       return -1;
-}
-
-static int
-rb_find_range(void *data, int mask, u64 head, u64 old,
-             u64 *start, u64 *end, bool backward)
-{
-       if (!backward) {
-               *start = old;
-               *end = head;
-               return 0;
-       }
-
-       return backward_rb_find_range(data, mask, head, start, end);
-}
-
-static int
-record__mmap_read(struct record *rec, struct perf_mmap *md,
-                 bool overwrite, bool backward)
-{
-       u64 head = perf_mmap__read_head(md);
-       u64 old = md->prev;
-       u64 end = head, start = old;
-       unsigned char *data = md->base + page_size;
-       unsigned long size;
-       void *buf;
-       int rc = 0;
-
-       if (rb_find_range(data, md->mask, head,
-                         old, &start, &end, backward))
-               return -1;
-
-       if (start == end)
-               return 0;
+       struct record *rec = to;
 
        rec->samples++;
-
-       size = end - start;
-       if (size > (unsigned long)(md->mask) + 1) {
-               WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
-
-               md->prev = head;
-               perf_mmap__consume(md, overwrite || backward);
-               return 0;
-       }
-
-       if ((start & md->mask) + size != (end & md->mask)) {
-               buf = &data[start & md->mask];
-               size = md->mask + 1 - (start & md->mask);
-               start += size;
-
-               if (record__write(rec, buf, size) < 0) {
-                       rc = -1;
-                       goto out;
-               }
-       }
-
-       buf = &data[start & md->mask];
-       size = end - start;
-       start += size;
-
-       if (record__write(rec, buf, size) < 0) {
-               rc = -1;
-               goto out;
-       }
-
-       md->prev = head;
-       perf_mmap__consume(md, overwrite || backward);
-out:
-       return rc;
+       return record__write(rec, bf, size);
 }
 
 static volatile int done;
@@ -269,13 +174,13 @@ static int record__process_auxtrace(struct perf_tool *tool,
                                    size_t len1, void *data2, size_t len2)
 {
        struct record *rec = container_of(tool, struct record, tool);
-       struct perf_data_file *file = &rec->file;
+       struct perf_data *data = &rec->data;
        size_t padding;
        u8 pad[8] = {0};
 
-       if (!perf_data_file__is_pipe(file)) {
+       if (!perf_data__is_pipe(data)) {
                off_t file_offset;
-               int fd = perf_data_file__fd(file);
+               int fd = perf_data__fd(data);
                int err;
 
                file_offset = lseek(fd, 0, SEEK_CUR);
@@ -494,10 +399,10 @@ static int process_sample_event(struct perf_tool *tool,
 
 static int process_buildids(struct record *rec)
 {
-       struct perf_data_file *file  = &rec->file;
+       struct perf_data *data = &rec->data;
        struct perf_session *session = rec->session;
 
-       if (file->size == 0)
+       if (data->size == 0)
                return 0;
 
        /*
@@ -577,8 +482,7 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
                struct auxtrace_mmap *mm = &maps[i].auxtrace_mmap;
 
                if (maps[i].base) {
-                       if (record__mmap_read(rec, &maps[i],
-                                             evlist->overwrite, backward) != 0) {
+                       if (perf_mmap__push(&maps[i], evlist->overwrite, backward, rec, record__pushfn) != 0) {
                                rc = -1;
                                goto out;
                        }
@@ -641,14 +545,14 @@ static void record__init_features(struct record *rec)
 static void
 record__finish_output(struct record *rec)
 {
-       struct perf_data_file *file = &rec->file;
-       int fd = perf_data_file__fd(file);
+       struct perf_data *data = &rec->data;
+       int fd = perf_data__fd(data);
 
-       if (file->is_pipe)
+       if (data->is_pipe)
                return;
 
        rec->session->header.data_size += rec->bytes_written;
-       file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
+       data->size = lseek(perf_data__fd(data), 0, SEEK_CUR);
 
        if (!rec->no_buildid) {
                process_buildids(rec);
@@ -687,7 +591,7 @@ static int record__synthesize(struct record *rec, bool tail);
 static int
 record__switch_output(struct record *rec, bool at_exit)
 {
-       struct perf_data_file *file = &rec->file;
+       struct perf_data *data = &rec->data;
        int fd, err;
 
        /* Same Size:      "2015122520103046"*/
@@ -705,7 +609,7 @@ record__switch_output(struct record *rec, bool at_exit)
                return -EINVAL;
        }
 
-       fd = perf_data_file__switch(file, timestamp,
+       fd = perf_data__switch(data, timestamp,
                                    rec->session->header.data_offset,
                                    at_exit);
        if (fd >= 0 && !at_exit) {
@@ -715,7 +619,7 @@ record__switch_output(struct record *rec, bool at_exit)
 
        if (!quiet)
                fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
-                       file->path, timestamp);
+                       data->file.path, timestamp);
 
        /* Output tracking events */
        if (!at_exit) {
@@ -790,16 +694,16 @@ static int record__synthesize(struct record *rec, bool tail)
 {
        struct perf_session *session = rec->session;
        struct machine *machine = &session->machines.host;
-       struct perf_data_file *file = &rec->file;
+       struct perf_data *data = &rec->data;
        struct record_opts *opts = &rec->opts;
        struct perf_tool *tool = &rec->tool;
-       int fd = perf_data_file__fd(file);
+       int fd = perf_data__fd(data);
        int err = 0;
 
        if (rec->opts.tail_synthesize != tail)
                return 0;
 
-       if (file->is_pipe) {
+       if (data->is_pipe) {
                err = perf_event__synthesize_features(
                        tool, session, rec->evlist, process_synthesized_event);
                if (err < 0) {
@@ -864,7 +768,7 @@ static int record__synthesize(struct record *rec, bool tail)
 
        err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
                                            process_synthesized_event, opts->sample_address,
-                                           opts->proc_map_timeout);
+                                           opts->proc_map_timeout, 1);
 out:
        return err;
 }
@@ -878,7 +782,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        struct machine *machine;
        struct perf_tool *tool = &rec->tool;
        struct record_opts *opts = &rec->opts;
-       struct perf_data_file *file = &rec->file;
+       struct perf_data *data = &rec->data;
        struct perf_session *session;
        bool disabled = false, draining = false;
        int fd;
@@ -904,20 +808,20 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                signal(SIGUSR2, SIG_IGN);
        }
 
-       session = perf_session__new(file, false, tool);
+       session = perf_session__new(data, false, tool);
        if (session == NULL) {
                pr_err("Perf session creation failed.\n");
                return -1;
        }
 
-       fd = perf_data_file__fd(file);
+       fd = perf_data__fd(data);
        rec->session = session;
 
        record__init_features(rec);
 
        if (forks) {
                err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
-                                                   argv, file->is_pipe,
+                                                   argv, data->is_pipe,
                                                    workload_exec_failed_signal);
                if (err < 0) {
                        pr_err("Couldn't run the workload!\n");
@@ -953,7 +857,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        if (!rec->evlist->nr_groups)
                perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
 
-       if (file->is_pipe) {
+       if (data->is_pipe) {
                err = perf_header__write_pipe(fd);
                if (err < 0)
                        goto out_child;
@@ -1214,8 +1118,8 @@ out_child:
                        samples[0] = '\0';
 
                fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n",
-                       perf_data_file__size(file) / 1024.0 / 1024.0,
-                       file->path, postfix, samples);
+                       perf_data__size(data) / 1024.0 / 1024.0,
+                       data->file.path, postfix, samples);
        }
 
 out_delete_session:
@@ -1579,7 +1483,7 @@ static struct option __record_options[] = {
        OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
                    "list of cpus to monitor"),
        OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
-       OPT_STRING('o', "output", &record.file.path, "file",
+       OPT_STRING('o', "output", &record.data.file.path, "file",
                    "output file name"),
        OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
                        &record.opts.no_inherit_set,
@@ -1644,6 +1548,9 @@ static struct option __record_options[] = {
        OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register",
                    "sample selected machine registers on interrupt,"
                    " use -I ? to list register names", parse_regs),
+       OPT_CALLBACK_OPTARG(0, "user-regs", &record.opts.sample_user_regs, NULL, "any register",
+                   "sample selected machine registers on interrupt,"
+                   " use -I ? to list register names", parse_regs),
        OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
                    "Record running/enabled time of read (:S) events"),
        OPT_CALLBACK('k', "clockid", &record.opts,
index fae4b03407507a5291820ff45dac3ee6c03dfafb..1394cd8d96f7bb8d132e2a5cf892090690a19920 100644 (file)
@@ -258,7 +258,7 @@ static int report__setup_sample_type(struct report *rep)
 {
        struct perf_session *session = rep->session;
        u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
-       bool is_pipe = perf_data_file__is_pipe(session->file);
+       bool is_pipe = perf_data__is_pipe(session->data);
 
        if (session->itrace_synth_opts->callchain ||
            (!is_pipe &&
@@ -569,7 +569,7 @@ static int __cmd_report(struct report *rep)
        int ret;
        struct perf_session *session = rep->session;
        struct perf_evsel *pos;
-       struct perf_data_file *file = session->file;
+       struct perf_data *data = session->data;
 
        signal(SIGINT, sig_handler);
 
@@ -638,7 +638,7 @@ static int __cmd_report(struct report *rep)
                rep->nr_entries += evsel__hists(pos)->nr_entries;
 
        if (rep->nr_entries == 0) {
-               ui__error("The %s file has no samples!\n", file->path);
+               ui__error("The %s file has no samples!\n", data->file.path);
                return 0;
        }
 
@@ -880,7 +880,7 @@ int cmd_report(int argc, const char **argv)
                    "Show inline function"),
        OPT_END()
        };
-       struct perf_data_file file = {
+       struct perf_data data = {
                .mode  = PERF_DATA_MODE_READ,
        };
        int ret = hists__init();
@@ -941,11 +941,11 @@ int cmd_report(int argc, const char **argv)
                        input_name = "perf.data";
        }
 
-       file.path  = input_name;
-       file.force = symbol_conf.force;
+       data.file.path = input_name;
+       data.force     = symbol_conf.force;
 
 repeat:
-       session = perf_session__new(&file, false, &report.tool);
+       session = perf_session__new(&data, false, &report.tool);
        if (session == NULL)
                return -1;
 
index f380d91ee609779b9b8234a9316d72f98cb2d48b..83283fedb00f3e818236892040e3ea1da3028899 100644 (file)
@@ -1701,14 +1701,16 @@ static int perf_sched__read_events(struct perf_sched *sched)
                { "sched:sched_migrate_task", process_sched_migrate_task_event, },
        };
        struct perf_session *session;
-       struct perf_data_file file = {
-               .path = input_name,
-               .mode = PERF_DATA_MODE_READ,
-               .force = sched->force,
+       struct perf_data data = {
+               .file      = {
+                       .path = input_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = sched->force,
        };
        int rc = -1;
 
-       session = perf_session__new(&file, false, &sched->tool);
+       session = perf_session__new(&data, false, &sched->tool);
        if (session == NULL) {
                pr_debug("No Memory for session\n");
                return -1;
@@ -2903,10 +2905,12 @@ static int perf_sched__timehist(struct perf_sched *sched)
        const struct perf_evsel_str_handler migrate_handlers[] = {
                { "sched:sched_migrate_task", timehist_migrate_task_event, },
        };
-       struct perf_data_file file = {
-               .path = input_name,
-               .mode = PERF_DATA_MODE_READ,
-               .force = sched->force,
+       struct perf_data data = {
+               .file      = {
+                       .path = input_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = sched->force,
        };
 
        struct perf_session *session;
@@ -2931,7 +2935,7 @@ static int perf_sched__timehist(struct perf_sched *sched)
 
        symbol_conf.use_callchain = sched->show_callchain;
 
-       session = perf_session__new(&file, false, &sched->tool);
+       session = perf_session__new(&data, false, &sched->tool);
        if (session == NULL)
                return -ENOMEM;
 
@@ -3364,6 +3368,10 @@ int cmd_sched(int argc, const char **argv)
        OPT_STRING(0, "time", &sched.time_str, "str",
                   "Time span for analysis (start,stop)"),
        OPT_BOOLEAN(0, "state", &sched.show_state, "Show task state when sched-out"),
+       OPT_STRING('p', "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
+                  "analyze events only for given process id(s)"),
+       OPT_STRING('t', "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
+                  "analyze events only for given thread id(s)"),
        OPT_PARENT(sched_options)
        };
 
index 0fe02758de7dc47fd9497db1f2ccae95eed06409..68f36dc0344f2bb7d07a1bcdb05f8af4419d1d88 100644 (file)
@@ -89,6 +89,7 @@ enum perf_output_field {
        PERF_OUTPUT_BRSTACKOFF      = 1U << 24,
        PERF_OUTPUT_SYNTH           = 1U << 25,
        PERF_OUTPUT_PHYS_ADDR       = 1U << 26,
+       PERF_OUTPUT_UREGS           = 1U << 27,
 };
 
 struct output_option {
@@ -110,6 +111,7 @@ struct output_option {
        {.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
        {.str = "period", .field = PERF_OUTPUT_PERIOD},
        {.str = "iregs", .field = PERF_OUTPUT_IREGS},
+       {.str = "uregs", .field = PERF_OUTPUT_UREGS},
        {.str = "brstack", .field = PERF_OUTPUT_BRSTACK},
        {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM},
        {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC},
@@ -209,6 +211,51 @@ static struct {
        },
 };
 
+struct perf_evsel_script {
+       char *filename;
+       FILE *fp;
+       u64  samples;
+};
+
+static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel,
+                                                       struct perf_data *data)
+{
+       struct perf_evsel_script *es = malloc(sizeof(*es));
+
+       if (es != NULL) {
+               if (asprintf(&es->filename, "%s.%s.dump", data->file.path, perf_evsel__name(evsel)) < 0)
+                       goto out_free;
+               es->fp = fopen(es->filename, "w");
+               if (es->fp == NULL)
+                       goto out_free_filename;
+               es->samples = 0;
+       }
+
+       return es;
+out_free_filename:
+       zfree(&es->filename);
+out_free:
+       free(es);
+       return NULL;
+}
+
+static void perf_evsel_script__delete(struct perf_evsel_script *es)
+{
+       zfree(&es->filename);
+       fclose(es->fp);
+       es->fp = NULL;
+       free(es);
+}
+
+static int perf_evsel_script__fprintf(struct perf_evsel_script *es, FILE *fp)
+{
+       struct stat st;
+
+       fstat(fileno(es->fp), &st);
+       return fprintf(fp, "[ perf script: Wrote %.3f MB %s (%" PRIu64 " samples) ]\n",
+                      st.st_size / 1024.0 / 1024.0, es->filename, es->samples);
+}
+
 static inline int output_type(unsigned int type)
 {
        switch (type) {
@@ -386,6 +433,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
                                        PERF_OUTPUT_IREGS))
                return -EINVAL;
 
+       if (PRINT_FIELD(UREGS) &&
+               perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_USER, "UREGS",
+                                       PERF_OUTPUT_UREGS))
+               return -EINVAL;
+
        if (PRINT_FIELD(PHYS_ADDR) &&
                perf_evsel__check_stype(evsel, PERF_SAMPLE_PHYS_ADDR, "PHYS_ADDR",
                                        PERF_OUTPUT_PHYS_ADDR))
@@ -494,51 +546,76 @@ out:
        return 0;
 }
 
-static void print_sample_iregs(struct perf_sample *sample,
-                         struct perf_event_attr *attr)
+static int perf_sample__fprintf_iregs(struct perf_sample *sample,
+                                     struct perf_event_attr *attr, FILE *fp)
 {
        struct regs_dump *regs = &sample->intr_regs;
        uint64_t mask = attr->sample_regs_intr;
        unsigned i = 0, r;
+       int printed = 0;
 
        if (!regs)
-               return;
+               return 0;
 
        for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {
                u64 val = regs->regs[i++];
-               printf("%5s:0x%"PRIx64" ", perf_reg_name(r), val);
+               printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r), val);
        }
+
+       return printed;
 }
 
-static void print_sample_start(struct perf_sample *sample,
-                              struct thread *thread,
-                              struct perf_evsel *evsel)
+static int perf_sample__fprintf_uregs(struct perf_sample *sample,
+                                     struct perf_event_attr *attr, FILE *fp)
+{
+       struct regs_dump *regs = &sample->user_regs;
+       uint64_t mask = attr->sample_regs_user;
+       unsigned i = 0, r;
+       int printed = 0;
+
+       if (!regs || !regs->regs)
+               return 0;
+
+       printed += fprintf(fp, " ABI:%" PRIu64 " ", regs->abi);
+
+       for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {
+               u64 val = regs->regs[i++];
+               printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r), val);
+       }
+
+       return printed;
+}
+
+static int perf_sample__fprintf_start(struct perf_sample *sample,
+                                     struct thread *thread,
+                                     struct perf_evsel *evsel, FILE *fp)
 {
        struct perf_event_attr *attr = &evsel->attr;
        unsigned long secs;
        unsigned long long nsecs;
+       int printed = 0;
 
        if (PRINT_FIELD(COMM)) {
                if (latency_format)
-                       printf("%8.8s ", thread__comm_str(thread));
+                       printed += fprintf(fp, "%8.8s ", thread__comm_str(thread));
                else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
-                       printf("%s ", thread__comm_str(thread));
+                       printed += fprintf(fp, "%s ", thread__comm_str(thread));
                else
-                       printf("%16s ", thread__comm_str(thread));
+                       printed += fprintf(fp, "%16s ", thread__comm_str(thread));
        }
 
        if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
-               printf("%5d/%-5d ", sample->pid, sample->tid);
+               printed += fprintf(fp, "%5d/%-5d ", sample->pid, sample->tid);
        else if (PRINT_FIELD(PID))
-               printf("%5d ", sample->pid);
+               printed += fprintf(fp, "%5d ", sample->pid);
        else if (PRINT_FIELD(TID))
-               printf("%5d ", sample->tid);
+               printed += fprintf(fp, "%5d ", sample->tid);
 
        if (PRINT_FIELD(CPU)) {
                if (latency_format)
-                       printf("%3d ", sample->cpu);
+                       printed += fprintf(fp, "%3d ", sample->cpu);
                else
-                       printf("[%03d] ", sample->cpu);
+                       printed += fprintf(fp, "[%03d] ", sample->cpu);
        }
 
        if (PRINT_FIELD(TIME)) {
@@ -547,13 +624,15 @@ static void print_sample_start(struct perf_sample *sample,
                nsecs -= secs * NSEC_PER_SEC;
 
                if (nanosecs)
-                       printf("%5lu.%09llu: ", secs, nsecs);
+                       printed += fprintf(fp, "%5lu.%09llu: ", secs, nsecs);
                else {
                        char sample_time[32];
                        timestamp__scnprintf_usec(sample->time, sample_time, sizeof(sample_time));
-                       printf("%12s: ", sample_time);
+                       printed += fprintf(fp, "%12s: ", sample_time);
                }
        }
+
+       return printed;
 }
 
 static inline char
@@ -565,16 +644,17 @@ mispred_str(struct branch_entry *br)
        return br->flags.predicted ? 'P' : 'M';
 }
 
-static void print_sample_brstack(struct perf_sample *sample,
-                                struct thread *thread,
-                                struct perf_event_attr *attr)
+static int perf_sample__fprintf_brstack(struct perf_sample *sample,
+                                       struct thread *thread,
+                                       struct perf_event_attr *attr, FILE *fp)
 {
        struct branch_stack *br = sample->branch_stack;
        struct addr_location alf, alt;
        u64 i, from, to;
+       int printed = 0;
 
        if (!(br && br->nr))
-               return;
+               return 0;
 
        for (i = 0; i < br->nr; i++) {
                from = br->entries[i].from;
@@ -587,38 +667,41 @@ static void print_sample_brstack(struct perf_sample *sample,
                        thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
                }
 
-               printf(" 0x%"PRIx64, from);
+               printed += fprintf(fp, " 0x%"PRIx64, from);
                if (PRINT_FIELD(DSO)) {
-                       printf("(");
-                       map__fprintf_dsoname(alf.map, stdout);
-                       printf(")");
+                       printed += fprintf(fp, "(");
+                       printed += map__fprintf_dsoname(alf.map, fp);
+                       printed += fprintf(fp, ")");
                }
 
-               printf("/0x%"PRIx64, to);
+               printed += fprintf(fp, "/0x%"PRIx64, to);
                if (PRINT_FIELD(DSO)) {
-                       printf("(");
-                       map__fprintf_dsoname(alt.map, stdout);
-                       printf(")");
+                       printed += fprintf(fp, "(");
+                       printed += map__fprintf_dsoname(alt.map, fp);
+                       printed += fprintf(fp, ")");
                }
 
-               printf("/%c/%c/%c/%d ",
+               printed += fprintf(fp, "/%c/%c/%c/%d ",
                        mispred_str( br->entries + i),
                        br->entries[i].flags.in_tx? 'X' : '-',
                        br->entries[i].flags.abort? 'A' : '-',
                        br->entries[i].flags.cycles);
        }
+
+       return printed;
 }
 
-static void print_sample_brstacksym(struct perf_sample *sample,
-                                   struct thread *thread,
-                                   struct perf_event_attr *attr)
+static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
+                                          struct thread *thread,
+                                          struct perf_event_attr *attr, FILE *fp)
 {
        struct branch_stack *br = sample->branch_stack;
        struct addr_location alf, alt;
        u64 i, from, to;
+       int printed = 0;
 
        if (!(br && br->nr))
-               return;
+               return 0;
 
        for (i = 0; i < br->nr; i++) {
 
@@ -635,37 +718,40 @@ static void print_sample_brstacksym(struct perf_sample *sample,
                if (alt.map)
                        alt.sym = map__find_symbol(alt.map, alt.addr);
 
-               symbol__fprintf_symname_offs(alf.sym, &alf, stdout);
+               printed += symbol__fprintf_symname_offs(alf.sym, &alf, fp);
                if (PRINT_FIELD(DSO)) {
-                       printf("(");
-                       map__fprintf_dsoname(alf.map, stdout);
-                       printf(")");
+                       printed += fprintf(fp, "(");
+                       printed += map__fprintf_dsoname(alf.map, fp);
+                       printed += fprintf(fp, ")");
                }
-               putchar('/');
-               symbol__fprintf_symname_offs(alt.sym, &alt, stdout);
+               printed += fprintf(fp, "%c", '/');
+               printed += symbol__fprintf_symname_offs(alt.sym, &alt, fp);
                if (PRINT_FIELD(DSO)) {
-                       printf("(");
-                       map__fprintf_dsoname(alt.map, stdout);
-                       printf(")");
+                       printed += fprintf(fp, "(");
+                       printed += map__fprintf_dsoname(alt.map, fp);
+                       printed += fprintf(fp, ")");
                }
-               printf("/%c/%c/%c/%d ",
+               printed += fprintf(fp, "/%c/%c/%c/%d ",
                        mispred_str( br->entries + i),
                        br->entries[i].flags.in_tx? 'X' : '-',
                        br->entries[i].flags.abort? 'A' : '-',
                        br->entries[i].flags.cycles);
        }
+
+       return printed;
 }
 
-static void print_sample_brstackoff(struct perf_sample *sample,
-                                   struct thread *thread,
-                                   struct perf_event_attr *attr)
+static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
+                                          struct thread *thread,
+                                          struct perf_event_attr *attr, FILE *fp)
 {
        struct branch_stack *br = sample->branch_stack;
        struct addr_location alf, alt;
        u64 i, from, to;
+       int printed = 0;
 
        if (!(br && br->nr))
-               return;
+               return 0;
 
        for (i = 0; i < br->nr; i++) {
 
@@ -682,24 +768,26 @@ static void print_sample_brstackoff(struct perf_sample *sample,
                if (alt.map && !alt.map->dso->adjust_symbols)
                        to = map__map_ip(alt.map, to);
 
-               printf(" 0x%"PRIx64, from);
+               printed += fprintf(fp, " 0x%"PRIx64, from);
                if (PRINT_FIELD(DSO)) {
-                       printf("(");
-                       map__fprintf_dsoname(alf.map, stdout);
-                       printf(")");
+                       printed += fprintf(fp, "(");
+                       printed += map__fprintf_dsoname(alf.map, fp);
+                       printed += fprintf(fp, ")");
                }
-               printf("/0x%"PRIx64, to);
+               printed += fprintf(fp, "/0x%"PRIx64, to);
                if (PRINT_FIELD(DSO)) {
-                       printf("(");
-                       map__fprintf_dsoname(alt.map, stdout);
-                       printf(")");
+                       printed += fprintf(fp, "(");
+                       printed += map__fprintf_dsoname(alt.map, fp);
+                       printed += fprintf(fp, ")");
                }
-               printf("/%c/%c/%c/%d ",
+               printed += fprintf(fp, "/%c/%c/%c/%d ",
                        mispred_str(br->entries + i),
                        br->entries[i].flags.in_tx ? 'X' : '-',
                        br->entries[i].flags.abort ? 'A' : '-',
                        br->entries[i].flags.cycles);
        }
+
+       return printed;
 }
 #define MAXBB 16384UL
 
@@ -727,27 +815,26 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
         * but the exit is not. Let the caller patch it up.
         */
        if (kernel != machine__kernel_ip(machine, end)) {
-               printf("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n",
-                               start, end);
+               pr_debug("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n", start, end);
                return -ENXIO;
        }
 
        memset(&al, 0, sizeof(al));
        if (end - start > MAXBB - MAXINSN) {
                if (last)
-                       printf("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
+                       pr_debug("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
                else
-                       printf("\tblock %" PRIx64 "-%" PRIx64 " (%" PRIu64 ") too long to dump\n", start, end, end - start);
+                       pr_debug("\tblock %" PRIx64 "-%" PRIx64 " (%" PRIu64 ") too long to dump\n", start, end, end - start);
                return 0;
        }
 
        thread__find_addr_map(thread, *cpumode, MAP__FUNCTION, start, &al);
        if (!al.map || !al.map->dso) {
-               printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
+               pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
                return 0;
        }
        if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR) {
-               printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
+               pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
                return 0;
        }
 
@@ -760,36 +847,35 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
 
        *is64bit = al.map->dso->is_64_bit;
        if (len <= 0)
-               printf("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
+               pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
                        start, end);
        return len;
 }
 
-static void print_jump(uint64_t ip, struct branch_entry *en,
-                      struct perf_insn *x, u8 *inbuf, int len,
-                      int insn)
+static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
+                           struct perf_insn *x, u8 *inbuf, int len,
+                           int insn, FILE *fp)
 {
-       printf("\t%016" PRIx64 "\t%-30s\t#%s%s%s%s",
-              ip,
-              dump_insn(x, ip, inbuf, len, NULL),
-              en->flags.predicted ? " PRED" : "",
-              en->flags.mispred ? " MISPRED" : "",
-              en->flags.in_tx ? " INTX" : "",
-              en->flags.abort ? " ABORT" : "");
+       int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip,
+                             dump_insn(x, ip, inbuf, len, NULL),
+                             en->flags.predicted ? " PRED" : "",
+                             en->flags.mispred ? " MISPRED" : "",
+                             en->flags.in_tx ? " INTX" : "",
+                             en->flags.abort ? " ABORT" : "");
        if (en->flags.cycles) {
-               printf(" %d cycles", en->flags.cycles);
+               printed += fprintf(fp, " %d cycles", en->flags.cycles);
                if (insn)
-                       printf(" %.2f IPC", (float)insn / en->flags.cycles);
+                       printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles);
        }
-       putchar('\n');
+       return printed + fprintf(fp, "\n");
 }
 
-static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu,
-                        uint64_t addr, struct symbol **lastsym,
-                        struct perf_event_attr *attr)
+static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
+                          u8 cpumode, int cpu, struct symbol **lastsym,
+                          struct perf_event_attr *attr, FILE *fp)
 {
        struct addr_location al;
-       int off;
+       int off, printed = 0;
 
        memset(&al, 0, sizeof(al));
 
@@ -798,7 +884,7 @@ static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu,
                thread__find_addr_map(thread, cpumode, MAP__VARIABLE,
                                      addr, &al);
        if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end)
-               return;
+               return 0;
 
        al.cpu = cpu;
        al.sym = NULL;
@@ -806,37 +892,39 @@ static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu,
                al.sym = map__find_symbol(al.map, al.addr);
 
        if (!al.sym)
-               return;
+               return 0;
 
        if (al.addr < al.sym->end)
                off = al.addr - al.sym->start;
        else
                off = al.addr - al.map->start - al.sym->start;
-       printf("\t%s", al.sym->name);
+       printed += fprintf(fp, "\t%s", al.sym->name);
        if (off)
-               printf("%+d", off);
-       putchar(':');
+               printed += fprintf(fp, "%+d", off);
+       printed += fprintf(fp, ":");
        if (PRINT_FIELD(SRCLINE))
-               map__fprintf_srcline(al.map, al.addr, "\t", stdout);
-       putchar('\n');
+               printed += map__fprintf_srcline(al.map, al.addr, "\t", fp);
+       printed += fprintf(fp, "\n");
        *lastsym = al.sym;
+
+       return printed;
 }
 
-static void print_sample_brstackinsn(struct perf_sample *sample,
-                                    struct thread *thread,
-                                    struct perf_event_attr *attr,
-                                    struct machine *machine)
+static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
+                                           struct thread *thread,
+                                           struct perf_event_attr *attr,
+                                           struct machine *machine, FILE *fp)
 {
        struct branch_stack *br = sample->branch_stack;
        u64 start, end;
-       int i, insn, len, nr, ilen;
+       int i, insn, len, nr, ilen, printed = 0;
        struct perf_insn x;
        u8 buffer[MAXBB];
        unsigned off;
        struct symbol *lastsym = NULL;
 
        if (!(br && br->nr))
-               return;
+               return 0;
        nr = br->nr;
        if (max_blocks && nr > max_blocks + 1)
                nr = max_blocks + 1;
@@ -844,17 +932,17 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
        x.thread = thread;
        x.cpu = sample->cpu;
 
-       putchar('\n');
+       printed += fprintf(fp, "%c", '\n');
 
        /* Handle first from jump, of which we don't know the entry. */
        len = grab_bb(buffer, br->entries[nr-1].from,
                        br->entries[nr-1].from,
                        machine, thread, &x.is64bit, &x.cpumode, false);
        if (len > 0) {
-               print_ip_sym(thread, x.cpumode, x.cpu,
-                            br->entries[nr - 1].from, &lastsym, attr);
-               print_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
-                           &x, buffer, len, 0);
+               printed += ip__fprintf_sym(br->entries[nr - 1].from, thread,
+                                          x.cpumode, x.cpu, &lastsym, attr, fp);
+               printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
+                                           &x, buffer, len, 0, fp);
        }
 
        /* Print all blocks */
@@ -880,13 +968,13 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
                for (off = 0;; off += ilen) {
                        uint64_t ip = start + off;
 
-                       print_ip_sym(thread, x.cpumode, x.cpu, ip, &lastsym, attr);
+                       printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
                        if (ip == end) {
-                               print_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn);
+                               printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp);
                                break;
                        } else {
-                               printf("\t%016" PRIx64 "\t%s\n", ip,
-                                       dump_insn(&x, ip, buffer + off, len - off, &ilen));
+                               printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip,
+                                                  dump_insn(&x, ip, buffer + off, len - off, &ilen));
                                if (ilen == 0)
                                        break;
                                insn++;
@@ -899,9 +987,9 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
         * has not been executed yet.
         */
        if (br->entries[0].from == sample->ip)
-               return;
+               goto out;
        if (br->entries[0].flags.abort)
-               return;
+               goto out;
 
        /*
         * Print final block upto sample
@@ -909,58 +997,61 @@ static void print_sample_brstackinsn(struct perf_sample *sample,
        start = br->entries[0].to;
        end = sample->ip;
        len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true);
-       print_ip_sym(thread, x.cpumode, x.cpu, start, &lastsym, attr);
+       printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
        if (len <= 0) {
                /* Print at least last IP if basic block did not work */
                len = grab_bb(buffer, sample->ip, sample->ip,
                              machine, thread, &x.is64bit, &x.cpumode, false);
                if (len <= 0)
-                       return;
+                       goto out;
 
-               printf("\t%016" PRIx64 "\t%s\n", sample->ip,
+               printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip,
                        dump_insn(&x, sample->ip, buffer, len, NULL));
-               return;
+               goto out;
        }
        for (off = 0; off <= end - start; off += ilen) {
-               printf("\t%016" PRIx64 "\t%s\n", start + off,
-                       dump_insn(&x, start + off, buffer + off, len - off, &ilen));
+               printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", start + off,
+                                  dump_insn(&x, start + off, buffer + off, len - off, &ilen));
                if (ilen == 0)
                        break;
        }
+out:
+       return printed;
 }
 
-static void print_sample_addr(struct perf_sample *sample,
-                         struct thread *thread,
-                         struct perf_event_attr *attr)
+static int perf_sample__fprintf_addr(struct perf_sample *sample,
+                                    struct thread *thread,
+                                    struct perf_event_attr *attr, FILE *fp)
 {
        struct addr_location al;
-
-       printf("%16" PRIx64, sample->addr);
+       int printed = fprintf(fp, "%16" PRIx64, sample->addr);
 
        if (!sample_addr_correlates_sym(attr))
-               return;
+               goto out;
 
        thread__resolve(thread, &al, sample);
 
        if (PRINT_FIELD(SYM)) {
-               printf(" ");
+               printed += fprintf(fp, " ");
                if (PRINT_FIELD(SYMOFFSET))
-                       symbol__fprintf_symname_offs(al.sym, &al, stdout);
+                       printed += symbol__fprintf_symname_offs(al.sym, &al, fp);
                else
-                       symbol__fprintf_symname(al.sym, stdout);
+                       printed += symbol__fprintf_symname(al.sym, fp);
        }
 
        if (PRINT_FIELD(DSO)) {
-               printf(" (");
-               map__fprintf_dsoname(al.map, stdout);
-               printf(")");
+               printed += fprintf(fp, " (");
+               printed += map__fprintf_dsoname(al.map, fp);
+               printed += fprintf(fp, ")");
        }
+out:
+       return printed;
 }
 
-static void print_sample_callindent(struct perf_sample *sample,
-                                   struct perf_evsel *evsel,
-                                   struct thread *thread,
-                                   struct addr_location *al)
+static int perf_sample__fprintf_callindent(struct perf_sample *sample,
+                                          struct perf_evsel *evsel,
+                                          struct thread *thread,
+                                          struct addr_location *al, FILE *fp)
 {
        struct perf_event_attr *attr = &evsel->attr;
        size_t depth = thread_stack__depth(thread);
@@ -995,12 +1086,12 @@ static void print_sample_callindent(struct perf_sample *sample,
        }
 
        if (name)
-               len = printf("%*s%s", (int)depth * 4, "", name);
+               len = fprintf(fp, "%*s%s", (int)depth * 4, "", name);
        else if (ip)
-               len = printf("%*s%16" PRIx64, (int)depth * 4, "", ip);
+               len = fprintf(fp, "%*s%16" PRIx64, (int)depth * 4, "", ip);
 
        if (len < 0)
-               return;
+               return len;
 
        /*
         * Try to keep the output length from changing frequently so that the
@@ -1010,39 +1101,46 @@ static void print_sample_callindent(struct perf_sample *sample,
                spacing = round_up(len + 4, 32);
 
        if (len < spacing)
-               printf("%*s", spacing - len, "");
+               len += fprintf(fp, "%*s", spacing - len, "");
+
+       return len;
 }
 
-static void print_insn(struct perf_sample *sample,
-                      struct perf_event_attr *attr,
-                      struct thread *thread,
-                      struct machine *machine)
+static int perf_sample__fprintf_insn(struct perf_sample *sample,
+                                    struct perf_event_attr *attr,
+                                    struct thread *thread,
+                                    struct machine *machine, FILE *fp)
 {
+       int printed = 0;
+
        if (PRINT_FIELD(INSNLEN))
-               printf(" ilen: %d", sample->insn_len);
+               printed += fprintf(fp, " ilen: %d", sample->insn_len);
        if (PRINT_FIELD(INSN)) {
                int i;
 
-               printf(" insn:");
+               printed += fprintf(fp, " insn:");
                for (i = 0; i < sample->insn_len; i++)
-                       printf(" %02x", (unsigned char)sample->insn[i]);
+                       printed += fprintf(fp, " %02x", (unsigned char)sample->insn[i]);
        }
        if (PRINT_FIELD(BRSTACKINSN))
-               print_sample_brstackinsn(sample, thread, attr, machine);
+               printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp);
+
+       return printed;
 }
 
-static void print_sample_bts(struct perf_sample *sample,
-                            struct perf_evsel *evsel,
-                            struct thread *thread,
-                            struct addr_location *al,
-                            struct machine *machine)
+static int perf_sample__fprintf_bts(struct perf_sample *sample,
+                                   struct perf_evsel *evsel,
+                                   struct thread *thread,
+                                   struct addr_location *al,
+                                   struct machine *machine, FILE *fp)
 {
        struct perf_event_attr *attr = &evsel->attr;
        unsigned int type = output_type(attr->type);
        bool print_srcline_last = false;
+       int printed = 0;
 
        if (PRINT_FIELD(CALLINDENT))
-               print_sample_callindent(sample, evsel, thread, al);
+               printed += perf_sample__fprintf_callindent(sample, evsel, thread, al, fp);
 
        /* print branch_from information */
        if (PRINT_FIELD(IP)) {
@@ -1055,31 +1153,30 @@ static void print_sample_bts(struct perf_sample *sample,
                        cursor = &callchain_cursor;
 
                if (cursor == NULL) {
-                       putchar(' ');
+                       printed += fprintf(fp, " ");
                        if (print_opts & EVSEL__PRINT_SRCLINE) {
                                print_srcline_last = true;
                                print_opts &= ~EVSEL__PRINT_SRCLINE;
                        }
                } else
-                       putchar('\n');
+                       printed += fprintf(fp, "\n");
 
-               sample__fprintf_sym(sample, al, 0, print_opts, cursor, stdout);
+               printed += sample__fprintf_sym(sample, al, 0, print_opts, cursor, fp);
        }
 
        /* print branch_to information */
        if (PRINT_FIELD(ADDR) ||
            ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
             !output[type].user_set)) {
-               printf(" => ");
-               print_sample_addr(sample, thread, attr);
+               printed += fprintf(fp, " => ");
+               printed += perf_sample__fprintf_addr(sample, thread, attr, fp);
        }
 
        if (print_srcline_last)
-               map__fprintf_srcline(al->map, al->addr, "\n  ", stdout);
-
-       print_insn(sample, attr, thread, machine);
+               printed += map__fprintf_srcline(al->map, al->addr, "\n  ", fp);
 
-       printf("\n");
+       printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp);
+       return printed + fprintf(fp, "\n");
 }
 
 static struct {
@@ -1102,7 +1199,7 @@ static struct {
        {0, NULL}
 };
 
-static void print_sample_flags(u32 flags)
+static int perf_sample__fprintf_flags(u32 flags, FILE *fp)
 {
        const char *chars = PERF_IP_FLAG_CHARS;
        const int n = strlen(PERF_IP_FLAG_CHARS);
@@ -1129,9 +1226,9 @@ static void print_sample_flags(u32 flags)
        str[pos] = 0;
 
        if (name)
-               printf("  %-7s%4s ", name, in_tx ? "(x)" : "");
-       else
-               printf("  %-11s ", str);
+               return fprintf(fp, "  %-7s%4s ", name, in_tx ? "(x)" : "");
+
+       return fprintf(fp, "  %-11s ", str);
 }
 
 struct printer_data {
@@ -1140,40 +1237,40 @@ struct printer_data {
        bool is_printable;
 };
 
-static void
-print_sample_bpf_output_printer(enum binary_printer_ops op,
-                               unsigned int val,
-                               void *extra)
+static int sample__fprintf_bpf_output(enum binary_printer_ops op,
+                                     unsigned int val,
+                                     void *extra, FILE *fp)
 {
        unsigned char ch = (unsigned char)val;
        struct printer_data *printer_data = extra;
+       int printed = 0;
 
        switch (op) {
        case BINARY_PRINT_DATA_BEGIN:
-               printf("\n");
+               printed += fprintf(fp, "\n");
                break;
        case BINARY_PRINT_LINE_BEGIN:
-               printf("%17s", !printer_data->line_no ? "BPF output:" :
+               printed += fprintf(fp, "%17s", !printer_data->line_no ? "BPF output:" :
                                                        "           ");
                break;
        case BINARY_PRINT_ADDR:
-               printf(" %04x:", val);
+               printed += fprintf(fp, " %04x:", val);
                break;
        case BINARY_PRINT_NUM_DATA:
-               printf(" %02x", val);
+               printed += fprintf(fp, " %02x", val);
                break;
        case BINARY_PRINT_NUM_PAD:
-               printf("   ");
+               printed += fprintf(fp, "   ");
                break;
        case BINARY_PRINT_SEP:
-               printf("  ");
+               printed += fprintf(fp, "  ");
                break;
        case BINARY_PRINT_CHAR_DATA:
                if (printer_data->hit_nul && ch)
                        printer_data->is_printable = false;
 
                if (!isprint(ch)) {
-                       printf("%c", '.');
+                       printed += fprintf(fp, "%c", '.');
 
                        if (!printer_data->is_printable)
                                break;
@@ -1183,154 +1280,154 @@ print_sample_bpf_output_printer(enum binary_printer_ops op,
                        else
                                printer_data->is_printable = false;
                } else {
-                       printf("%c", ch);
+                       printed += fprintf(fp, "%c", ch);
                }
                break;
        case BINARY_PRINT_CHAR_PAD:
-               printf(" ");
+               printed += fprintf(fp, " ");
                break;
        case BINARY_PRINT_LINE_END:
-               printf("\n");
+               printed += fprintf(fp, "\n");
                printer_data->line_no++;
                break;
        case BINARY_PRINT_DATA_END:
        default:
                break;
        }
+
+       return printed;
 }
 
-static void print_sample_bpf_output(struct perf_sample *sample)
+static int perf_sample__fprintf_bpf_output(struct perf_sample *sample, FILE *fp)
 {
        unsigned int nr_bytes = sample->raw_size;
        struct printer_data printer_data = {0, false, true};
-
-       print_binary(sample->raw_data, nr_bytes, 8,
-                    print_sample_bpf_output_printer, &printer_data);
+       int printed = binary__fprintf(sample->raw_data, nr_bytes, 8,
+                                     sample__fprintf_bpf_output, &printer_data, fp);
 
        if (printer_data.is_printable && printer_data.hit_nul)
-               printf("%17s \"%s\"\n", "BPF string:",
-                      (char *)(sample->raw_data));
+               printed += fprintf(fp, "%17s \"%s\"\n", "BPF string:", (char *)(sample->raw_data));
+
+       return printed;
 }
 
-static void print_sample_spacing(int len, int spacing)
+static int perf_sample__fprintf_spacing(int len, int spacing, FILE *fp)
 {
        if (len > 0 && len < spacing)
-               printf("%*s", spacing - len, "");
+               return fprintf(fp, "%*s", spacing - len, "");
+
+       return 0;
 }
 
-static void print_sample_pt_spacing(int len)
+static int perf_sample__fprintf_pt_spacing(int len, FILE *fp)
 {
-       print_sample_spacing(len, 34);
+       return perf_sample__fprintf_spacing(len, 34, fp);
 }
 
-static void print_sample_synth_ptwrite(struct perf_sample *sample)
+static int perf_sample__fprintf_synth_ptwrite(struct perf_sample *sample, FILE *fp)
 {
        struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample);
        int len;
 
        if (perf_sample__bad_synth_size(sample, *data))
-               return;
+               return 0;
 
-       len = printf(" IP: %u payload: %#" PRIx64 " ",
+       len = fprintf(fp, " IP: %u payload: %#" PRIx64 " ",
                     data->ip, le64_to_cpu(data->payload));
-       print_sample_pt_spacing(len);
+       return len + perf_sample__fprintf_pt_spacing(len, fp);
 }
 
-static void print_sample_synth_mwait(struct perf_sample *sample)
+static int perf_sample__fprintf_synth_mwait(struct perf_sample *sample, FILE *fp)
 {
        struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample);
        int len;
 
        if (perf_sample__bad_synth_size(sample, *data))
-               return;
+               return 0;
 
-       len = printf(" hints: %#x extensions: %#x ",
-                    data->hints, data->extensions);
-       print_sample_pt_spacing(len);
+       len = fprintf(fp, " hints: %#x extensions: %#x ",
+                     data->hints, data->extensions);
+       return len + perf_sample__fprintf_pt_spacing(len, fp);
 }
 
-static void print_sample_synth_pwre(struct perf_sample *sample)
+static int perf_sample__fprintf_synth_pwre(struct perf_sample *sample, FILE *fp)
 {
        struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample);
        int len;
 
        if (perf_sample__bad_synth_size(sample, *data))
-               return;
+               return 0;
 
-       len = printf(" hw: %u cstate: %u sub-cstate: %u ",
-                    data->hw, data->cstate, data->subcstate);
-       print_sample_pt_spacing(len);
+       len = fprintf(fp, " hw: %u cstate: %u sub-cstate: %u ",
+                     data->hw, data->cstate, data->subcstate);
+       return len + perf_sample__fprintf_pt_spacing(len, fp);
 }
 
-static void print_sample_synth_exstop(struct perf_sample *sample)
+static int perf_sample__fprintf_synth_exstop(struct perf_sample *sample, FILE *fp)
 {
        struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample);
        int len;
 
        if (perf_sample__bad_synth_size(sample, *data))
-               return;
+               return 0;
 
-       len = printf(" IP: %u ", data->ip);
-       print_sample_pt_spacing(len);
+       len = fprintf(fp, " IP: %u ", data->ip);
+       return len + perf_sample__fprintf_pt_spacing(len, fp);
 }
 
-static void print_sample_synth_pwrx(struct perf_sample *sample)
+static int perf_sample__fprintf_synth_pwrx(struct perf_sample *sample, FILE *fp)
 {
        struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample);
        int len;
 
        if (perf_sample__bad_synth_size(sample, *data))
-               return;
+               return 0;
 
-       len = printf(" deepest cstate: %u last cstate: %u wake reason: %#x ",
+       len = fprintf(fp, " deepest cstate: %u last cstate: %u wake reason: %#x ",
                     data->deepest_cstate, data->last_cstate,
                     data->wake_reason);
-       print_sample_pt_spacing(len);
+       return len + perf_sample__fprintf_pt_spacing(len, fp);
 }
 
-static void print_sample_synth_cbr(struct perf_sample *sample)
+static int perf_sample__fprintf_synth_cbr(struct perf_sample *sample, FILE *fp)
 {
        struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample);
        unsigned int percent, freq;
        int len;
 
        if (perf_sample__bad_synth_size(sample, *data))
-               return;
+               return 0;
 
        freq = (le32_to_cpu(data->freq) + 500) / 1000;
-       len = printf(" cbr: %2u freq: %4u MHz ", data->cbr, freq);
+       len = fprintf(fp, " cbr: %2u freq: %4u MHz ", data->cbr, freq);
        if (data->max_nonturbo) {
                percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10;
-               len += printf("(%3u%%) ", percent);
+               len += fprintf(fp, "(%3u%%) ", percent);
        }
-       print_sample_pt_spacing(len);
+       return len + perf_sample__fprintf_pt_spacing(len, fp);
 }
 
-static void print_sample_synth(struct perf_sample *sample,
-                              struct perf_evsel *evsel)
+static int perf_sample__fprintf_synth(struct perf_sample *sample,
+                                     struct perf_evsel *evsel, FILE *fp)
 {
        switch (evsel->attr.config) {
        case PERF_SYNTH_INTEL_PTWRITE:
-               print_sample_synth_ptwrite(sample);
-               break;
+               return perf_sample__fprintf_synth_ptwrite(sample, fp);
        case PERF_SYNTH_INTEL_MWAIT:
-               print_sample_synth_mwait(sample);
-               break;
+               return perf_sample__fprintf_synth_mwait(sample, fp);
        case PERF_SYNTH_INTEL_PWRE:
-               print_sample_synth_pwre(sample);
-               break;
+               return perf_sample__fprintf_synth_pwre(sample, fp);
        case PERF_SYNTH_INTEL_EXSTOP:
-               print_sample_synth_exstop(sample);
-               break;
+               return perf_sample__fprintf_synth_exstop(sample, fp);
        case PERF_SYNTH_INTEL_PWRX:
-               print_sample_synth_pwrx(sample);
-               break;
+               return perf_sample__fprintf_synth_pwrx(sample, fp);
        case PERF_SYNTH_INTEL_CBR:
-               print_sample_synth_cbr(sample);
-               break;
+               return perf_sample__fprintf_synth_cbr(sample, fp);
        default:
                break;
        }
+
+       return 0;
 }
 
 struct perf_script {
@@ -1341,6 +1438,7 @@ struct perf_script {
        bool                    show_switch_events;
        bool                    show_namespace_events;
        bool                    allocated;
+       bool                    per_event_dump;
        struct cpu_map          *cpus;
        struct thread_map       *threads;
        int                     name_width;
@@ -1362,7 +1460,7 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist)
        return max;
 }
 
-static size_t data_src__printf(u64 data_src)
+static int data_src__fprintf(u64 data_src, FILE *fp)
 {
        struct mem_info mi = { .data_src.val = data_src };
        char decode[100];
@@ -1376,7 +1474,7 @@ static size_t data_src__printf(u64 data_src)
        if (maxlen < len)
                maxlen = len;
 
-       return printf("%-*s", maxlen, out);
+       return fprintf(fp, "%-*s", maxlen, out);
 }
 
 static void process_event(struct perf_script *script,
@@ -1387,14 +1485,18 @@ static void process_event(struct perf_script *script,
        struct thread *thread = al->thread;
        struct perf_event_attr *attr = &evsel->attr;
        unsigned int type = output_type(attr->type);
+       struct perf_evsel_script *es = evsel->priv;
+       FILE *fp = es->fp;
 
        if (output[type].fields == 0)
                return;
 
-       print_sample_start(sample, thread, evsel);
+       ++es->samples;
+
+       perf_sample__fprintf_start(sample, thread, evsel, fp);
 
        if (PRINT_FIELD(PERIOD))
-               printf("%10" PRIu64 " ", sample->period);
+               fprintf(fp, "%10" PRIu64 " ", sample->period);
 
        if (PRINT_FIELD(EVNAME)) {
                const char *evname = perf_evsel__name(evsel);
@@ -1402,33 +1504,33 @@ static void process_event(struct perf_script *script,
                if (!script->name_width)
                        script->name_width = perf_evlist__max_name_len(script->session->evlist);
 
-               printf("%*s: ", script->name_width,
-                      evname ? evname : "[unknown]");
+               fprintf(fp, "%*s: ", script->name_width, evname ?: "[unknown]");
        }
 
        if (print_flags)
-               print_sample_flags(sample->flags);
+               perf_sample__fprintf_flags(sample->flags, fp);
 
        if (is_bts_event(attr)) {
-               print_sample_bts(sample, evsel, thread, al, machine);
+               perf_sample__fprintf_bts(sample, evsel, thread, al, machine, fp);
                return;
        }
 
-       if (PRINT_FIELD(TRACE))
-               event_format__print(evsel->tp_format, sample->cpu,
-                                   sample->raw_data, sample->raw_size);
+       if (PRINT_FIELD(TRACE)) {
+               event_format__fprintf(evsel->tp_format, sample->cpu,
+                                     sample->raw_data, sample->raw_size, fp);
+       }
 
        if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH))
-               print_sample_synth(sample, evsel);
+               perf_sample__fprintf_synth(sample, evsel, fp);
 
        if (PRINT_FIELD(ADDR))
-               print_sample_addr(sample, thread, attr);
+               perf_sample__fprintf_addr(sample, thread, attr, fp);
 
        if (PRINT_FIELD(DATA_SRC))
-               data_src__printf(sample->data_src);
+               data_src__fprintf(sample->data_src, fp);
 
        if (PRINT_FIELD(WEIGHT))
-               printf("%16" PRIu64, sample->weight);
+               fprintf(fp, "%16" PRIu64, sample->weight);
 
        if (PRINT_FIELD(IP)) {
                struct callchain_cursor *cursor = NULL;
@@ -1438,27 +1540,30 @@ static void process_event(struct perf_script *script,
                                              sample, NULL, NULL, scripting_max_stack) == 0)
                        cursor = &callchain_cursor;
 
-               putchar(cursor ? '\n' : ' ');
-               sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout);
+               fputc(cursor ? '\n' : ' ', fp);
+               sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, fp);
        }
 
        if (PRINT_FIELD(IREGS))
-               print_sample_iregs(sample, attr);
+               perf_sample__fprintf_iregs(sample, attr, fp);
+
+       if (PRINT_FIELD(UREGS))
+               perf_sample__fprintf_uregs(sample, attr, fp);
 
        if (PRINT_FIELD(BRSTACK))
-               print_sample_brstack(sample, thread, attr);
+               perf_sample__fprintf_brstack(sample, thread, attr, fp);
        else if (PRINT_FIELD(BRSTACKSYM))
-               print_sample_brstacksym(sample, thread, attr);
+               perf_sample__fprintf_brstacksym(sample, thread, attr, fp);
        else if (PRINT_FIELD(BRSTACKOFF))
-               print_sample_brstackoff(sample, thread, attr);
+               perf_sample__fprintf_brstackoff(sample, thread, attr, fp);
 
        if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
-               print_sample_bpf_output(sample);
-       print_insn(sample, attr, thread, machine);
+               perf_sample__fprintf_bpf_output(sample, fp);
+       perf_sample__fprintf_insn(sample, attr, thread, machine, fp);
 
        if (PRINT_FIELD(PHYS_ADDR))
-               printf("%16" PRIx64, sample->phys_addr);
-       printf("\n");
+               fprintf(fp, "%16" PRIx64, sample->phys_addr);
+       fprintf(fp, "\n");
 }
 
 static struct scripting_ops    *scripting_ops;
@@ -1632,7 +1737,7 @@ static int process_comm_event(struct perf_tool *tool,
                sample->tid = event->comm.tid;
                sample->pid = event->comm.pid;
        }
-       print_sample_start(sample, thread, evsel);
+       perf_sample__fprintf_start(sample, thread, evsel, stdout);
        perf_event__fprintf(event, stdout);
        ret = 0;
 out:
@@ -1667,7 +1772,7 @@ static int process_namespaces_event(struct perf_tool *tool,
                sample->tid = event->namespaces.tid;
                sample->pid = event->namespaces.pid;
        }
-       print_sample_start(sample, thread, evsel);
+       perf_sample__fprintf_start(sample, thread, evsel, stdout);
        perf_event__fprintf(event, stdout);
        ret = 0;
 out:
@@ -1700,7 +1805,7 @@ static int process_fork_event(struct perf_tool *tool,
                sample->tid = event->fork.tid;
                sample->pid = event->fork.pid;
        }
-       print_sample_start(sample, thread, evsel);
+       perf_sample__fprintf_start(sample, thread, evsel, stdout);
        perf_event__fprintf(event, stdout);
        thread__put(thread);
 
@@ -1729,7 +1834,7 @@ static int process_exit_event(struct perf_tool *tool,
                sample->tid = event->fork.tid;
                sample->pid = event->fork.pid;
        }
-       print_sample_start(sample, thread, evsel);
+       perf_sample__fprintf_start(sample, thread, evsel, stdout);
        perf_event__fprintf(event, stdout);
 
        if (perf_event__process_exit(tool, event, sample, machine) < 0)
@@ -1764,7 +1869,7 @@ static int process_mmap_event(struct perf_tool *tool,
                sample->tid = event->mmap.tid;
                sample->pid = event->mmap.pid;
        }
-       print_sample_start(sample, thread, evsel);
+       perf_sample__fprintf_start(sample, thread, evsel, stdout);
        perf_event__fprintf(event, stdout);
        thread__put(thread);
        return 0;
@@ -1795,7 +1900,7 @@ static int process_mmap2_event(struct perf_tool *tool,
                sample->tid = event->mmap2.tid;
                sample->pid = event->mmap2.pid;
        }
-       print_sample_start(sample, thread, evsel);
+       perf_sample__fprintf_start(sample, thread, evsel, stdout);
        perf_event__fprintf(event, stdout);
        thread__put(thread);
        return 0;
@@ -1821,7 +1926,7 @@ static int process_switch_event(struct perf_tool *tool,
                return -1;
        }
 
-       print_sample_start(sample, thread, evsel);
+       perf_sample__fprintf_start(sample, thread, evsel, stdout);
        perf_event__fprintf(event, stdout);
        thread__put(thread);
        return 0;
@@ -1832,6 +1937,65 @@ static void sig_handler(int sig __maybe_unused)
        session_done = 1;
 }
 
+static void perf_script__fclose_per_event_dump(struct perf_script *script)
+{
+       struct perf_evlist *evlist = script->session->evlist;
+       struct perf_evsel *evsel;
+
+       evlist__for_each_entry(evlist, evsel) {
+               if (!evsel->priv)
+                       break;
+               perf_evsel_script__delete(evsel->priv);
+               evsel->priv = NULL;
+       }
+}
+
+static int perf_script__fopen_per_event_dump(struct perf_script *script)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each_entry(script->session->evlist, evsel) {
+               evsel->priv = perf_evsel_script__new(evsel, script->session->data);
+               if (evsel->priv == NULL)
+                       goto out_err_fclose;
+       }
+
+       return 0;
+
+out_err_fclose:
+       perf_script__fclose_per_event_dump(script);
+       return -1;
+}
+
+static int perf_script__setup_per_event_dump(struct perf_script *script)
+{
+       struct perf_evsel *evsel;
+       static struct perf_evsel_script es_stdout;
+
+       if (script->per_event_dump)
+               return perf_script__fopen_per_event_dump(script);
+
+       es_stdout.fp = stdout;
+
+       evlist__for_each_entry(script->session->evlist, evsel)
+               evsel->priv = &es_stdout;
+
+       return 0;
+}
+
+static void perf_script__exit_per_event_dump_stats(struct perf_script *script)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each_entry(script->session->evlist, evsel) {
+               struct perf_evsel_script *es = evsel->priv;
+
+               perf_evsel_script__fprintf(es, stdout);
+               perf_evsel_script__delete(es);
+               evsel->priv = NULL;
+       }
+}
+
 static int __cmd_script(struct perf_script *script)
 {
        int ret;
@@ -1853,8 +2017,16 @@ static int __cmd_script(struct perf_script *script)
        if (script->show_namespace_events)
                script->tool.namespaces = process_namespaces_event;
 
+       if (perf_script__setup_per_event_dump(script)) {
+               pr_err("Couldn't create the per event dump files\n");
+               return -1;
+       }
+
        ret = perf_session__process_events(script->session);
 
+       if (script->per_event_dump)
+               perf_script__exit_per_event_dump_stats(script);
+
        if (debug_mode)
                pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
 
@@ -2419,14 +2591,16 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
        char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
        DIR *scripts_dir, *lang_dir;
        struct perf_session *session;
-       struct perf_data_file file = {
-               .path = input_name,
-               .mode = PERF_DATA_MODE_READ,
+       struct perf_data data = {
+               .file      = {
+                       .path = input_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
        };
        char *temp;
        int i = 0;
 
-       session = perf_session__new(&file, false, NULL);
+       session = perf_session__new(&data, false, NULL);
        if (!session)
                return -1;
 
@@ -2704,7 +2878,7 @@ int cmd_script(int argc, const char **argv)
                        .ordering_requires_timestamps = true,
                },
        };
-       struct perf_data_file file = {
+       struct perf_data data = {
                .mode = PERF_DATA_MODE_READ,
        };
        const struct option options[] = {
@@ -2740,7 +2914,7 @@ int cmd_script(int argc, const char **argv)
                     "+field to add and -field to remove."
                     "Valid types: hw,sw,trace,raw,synth. "
                     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
-                    "addr,symoff,period,iregs,brstack,brstacksym,flags,"
+                    "addr,symoff,period,iregs,uregs,brstack,brstacksym,flags,"
                     "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr",
                     parse_output_fields),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
@@ -2772,6 +2946,8 @@ int cmd_script(int argc, const char **argv)
                    "Show context switch events (if recorded)"),
        OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events,
                    "Show namespace events (if recorded)"),
+       OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump,
+                   "Dump trace output to files named by the monitored events"),
        OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
        OPT_INTEGER(0, "max-blocks", &max_blocks,
                    "Maximum number of code blocks to dump with brstackinsn"),
@@ -2802,13 +2978,15 @@ int cmd_script(int argc, const char **argv)
                NULL
        };
 
+       perf_set_singlethreaded();
+
        setup_scripting();
 
        argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
 
-       file.path = input_name;
-       file.force = symbol_conf.force;
+       data.file.path = input_name;
+       data.force     = symbol_conf.force;
 
        if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
                rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
@@ -2975,7 +3153,7 @@ int cmd_script(int argc, const char **argv)
        if (!script_name)
                setup_pager();
 
-       session = perf_session__new(&file, false, &script.tool);
+       session = perf_session__new(&data, false, &script.tool);
        if (session == NULL)
                return -1;
 
@@ -3016,7 +3194,8 @@ int cmd_script(int argc, const char **argv)
                                         machine__resolve_kernel_addr,
                                         &session->machines.host) < 0) {
                pr_err("%s: failed to set libtraceevent function resolver\n", __func__);
-               return -1;
+               err = -1;
+               goto out_delete;
        }
 
        if (generate_script_lang) {
@@ -3030,7 +3209,7 @@ int cmd_script(int argc, const char **argv)
                        goto out_delete;
                }
 
-               input = open(file.path, O_RDONLY);      /* input_name */
+               input = open(data.file.path, O_RDONLY); /* input_name */
                if (input < 0) {
                        err = -errno;
                        perror("failed to open file");
@@ -3076,7 +3255,8 @@ int cmd_script(int argc, const char **argv)
        /* needs to be parsed after looking up reference time */
        if (perf_time__parse_str(&script.ptime, script.time_str) != 0) {
                pr_err("Invalid time string\n");
-               return -EINVAL;
+               err = -EINVAL;
+               goto out_delete;
        }
 
        err = __cmd_script(&script);
index 69523ed55894338cb202804db6ffbf202410b74f..59af5a8419e2be2c158753bf9d6a14ebd1089d76 100644 (file)
@@ -65,6 +65,7 @@
 #include "util/tool.h"
 #include "util/group.h"
 #include "util/string2.h"
+#include "util/metricgroup.h"
 #include "asm/bug.h"
 
 #include <linux/time64.h>
@@ -133,6 +134,8 @@ static const char *smi_cost_attrs = {
 
 static struct perf_evlist      *evsel_list;
 
+static struct rblist            metric_events;
+
 static struct target target = {
        .uid    = UINT_MAX,
 };
@@ -172,7 +175,7 @@ static int                  print_free_counters_hint;
 
 struct perf_stat {
        bool                     record;
-       struct perf_data_file    file;
+       struct perf_data         data;
        struct perf_session     *session;
        u64                      bytes_written;
        struct perf_tool         tool;
@@ -192,6 +195,11 @@ static struct perf_stat_config stat_config = {
        .scale          = true,
 };
 
+static bool is_duration_time(struct perf_evsel *evsel)
+{
+       return !strcmp(evsel->name, "duration_time");
+}
+
 static inline void diff_timespec(struct timespec *r, struct timespec *a,
                                 struct timespec *b)
 {
@@ -245,7 +253,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
         * by attr->sample_type != 0, and we can't run it on
         * stat sessions.
         */
-       if (!(STAT_RECORD && perf_stat.file.is_pipe))
+       if (!(STAT_RECORD && perf_stat.data.is_pipe))
                attr->sample_type = PERF_SAMPLE_IDENTIFIER;
 
        /*
@@ -287,7 +295,7 @@ static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
                                     struct perf_sample *sample __maybe_unused,
                                     struct machine *machine __maybe_unused)
 {
-       if (perf_data_file__write(&perf_stat.file, event, event->header.size) < 0) {
+       if (perf_data__write(&perf_stat.data, event, event->header.size) < 0) {
                pr_err("failed to write perf data, error: %m\n");
                return -1;
        }
@@ -407,6 +415,8 @@ static void process_interval(void)
                        pr_err("failed to write stat round event\n");
        }
 
+       init_stats(&walltime_nsecs_stats);
+       update_stats(&walltime_nsecs_stats, stat_config.interval * 1000000);
        print_counters(&rs, 0, NULL);
 }
 
@@ -582,6 +592,32 @@ static bool perf_evsel__should_store_id(struct perf_evsel *counter)
        return STAT_RECORD || counter->attr.read_format & PERF_FORMAT_ID;
 }
 
+static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel)
+{
+       struct perf_evsel *c2, *leader;
+       bool is_open = true;
+
+       leader = evsel->leader;
+       pr_debug("Weak group for %s/%d failed\n",
+                       leader->name, leader->nr_members);
+
+       /*
+        * for_each_group_member doesn't work here because it doesn't
+        * include the first entry.
+        */
+       evlist__for_each_entry(evsel_list, c2) {
+               if (c2 == evsel)
+                       is_open = false;
+               if (c2->leader == leader) {
+                       if (is_open)
+                               perf_evsel__close(c2);
+                       c2->leader = c2;
+                       c2->nr_members = 0;
+               }
+       }
+       return leader;
+}
+
 static int __run_perf_stat(int argc, const char **argv)
 {
        int interval = stat_config.interval;
@@ -592,7 +628,7 @@ static int __run_perf_stat(int argc, const char **argv)
        size_t l;
        int status = 0;
        const bool forks = (argc > 0);
-       bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false;
+       bool is_pipe = STAT_RECORD ? perf_stat.data.is_pipe : false;
        struct perf_evsel_config_term *err_term;
 
        if (interval) {
@@ -618,6 +654,15 @@ static int __run_perf_stat(int argc, const char **argv)
        evlist__for_each_entry(evsel_list, counter) {
 try_again:
                if (create_perf_stat_counter(counter) < 0) {
+
+                       /* Weak group failed. Reset the group. */
+                       if ((errno == EINVAL || errno == EBADF) &&
+                           counter->leader != counter &&
+                           counter->weak_group) {
+                               counter = perf_evsel__reset_weak_group(counter);
+                               goto try_again;
+                       }
+
                        /*
                         * PPC returns ENXIO for HW counters until 2.6.37
                         * (behavior changed with commit b0a873e).
@@ -674,10 +719,10 @@ try_again:
        }
 
        if (STAT_RECORD) {
-               int err, fd = perf_data_file__fd(&perf_stat.file);
+               int err, fd = perf_data__fd(&perf_stat.data);
 
                if (is_pipe) {
-                       err = perf_header__write_pipe(perf_data_file__fd(&perf_stat.file));
+                       err = perf_header__write_pipe(perf_data__fd(&perf_stat.data));
                } else {
                        err = perf_session__write_header(perf_stat.session, evsel_list,
                                                         fd, false);
@@ -800,7 +845,7 @@ static void print_noise(struct perf_evsel *evsel, double avg)
        if (run_count == 1)
                return;
 
-       ps = evsel->priv;
+       ps = evsel->stats;
        print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
 }
 
@@ -1199,7 +1244,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
 
        perf_stat__print_shadow_stats(counter, uval,
                                first_shadow_cpu(counter, id),
-                               &out);
+                               &out, &metric_events);
        if (!csv_output && !metric_only) {
                print_noise(counter, noise);
                print_running(run, ena);
@@ -1222,8 +1267,7 @@ static void aggr_update_shadow(void)
                                        continue;
                                val += perf_counts(counter->counts, cpu, 0)->val;
                        }
-                       val = val * counter->scale;
-                       perf_stat__update_shadow_stats(counter, &val,
+                       perf_stat__update_shadow_stats(counter, val,
                                                       first_shadow_cpu(counter, id));
                }
        }
@@ -1325,6 +1369,9 @@ static void print_aggr(char *prefix)
                ad.id = id = aggr_map->map[s];
                first = true;
                evlist__for_each_entry(evsel_list, counter) {
+                       if (is_duration_time(counter))
+                               continue;
+
                        ad.val = ad.ena = ad.run = 0;
                        ad.nr = 0;
                        if (!collect_data(counter, aggr_cb, &ad))
@@ -1384,7 +1431,7 @@ static void counter_aggr_cb(struct perf_evsel *counter, void *data,
                            bool first __maybe_unused)
 {
        struct caggr_data *cd = data;
-       struct perf_stat_evsel *ps = counter->priv;
+       struct perf_stat_evsel *ps = counter->stats;
 
        cd->avg += avg_stats(&ps->res_stats[0]);
        cd->avg_enabled += avg_stats(&ps->res_stats[1]);
@@ -1468,6 +1515,8 @@ static void print_no_aggr_metric(char *prefix)
                if (prefix)
                        fputs(prefix, stat_config.output);
                evlist__for_each_entry(evsel_list, counter) {
+                       if (is_duration_time(counter))
+                               continue;
                        if (first) {
                                aggr_printout(counter, cpu, 0);
                                first = false;
@@ -1522,6 +1571,8 @@ static void print_metric_headers(const char *prefix, bool no_indent)
 
        /* Print metrics headers only */
        evlist__for_each_entry(evsel_list, counter) {
+               if (is_duration_time(counter))
+                       continue;
                os.evsel = counter;
                out.ctx = &os;
                out.print_metric = print_metric_header;
@@ -1530,7 +1581,8 @@ static void print_metric_headers(const char *prefix, bool no_indent)
                os.evsel = counter;
                perf_stat__print_shadow_stats(counter, 0,
                                              0,
-                                             &out);
+                                             &out,
+                                             &metric_events);
        }
        fputc('\n', stat_config.output);
 }
@@ -1643,7 +1695,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
        char buf[64], *prefix = NULL;
 
        /* Do not print anything if we record to the pipe. */
-       if (STAT_RECORD && perf_stat.file.is_pipe)
+       if (STAT_RECORD && perf_stat.data.is_pipe)
                return;
 
        if (interval)
@@ -1668,12 +1720,18 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
                print_aggr(prefix);
                break;
        case AGGR_THREAD:
-               evlist__for_each_entry(evsel_list, counter)
+               evlist__for_each_entry(evsel_list, counter) {
+                       if (is_duration_time(counter))
+                               continue;
                        print_aggr_thread(counter, prefix);
+               }
                break;
        case AGGR_GLOBAL:
-               evlist__for_each_entry(evsel_list, counter)
+               evlist__for_each_entry(evsel_list, counter) {
+                       if (is_duration_time(counter))
+                               continue;
                        print_counter_aggr(counter, prefix);
+               }
                if (metric_only)
                        fputc('\n', stat_config.output);
                break;
@@ -1681,8 +1739,11 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
                if (metric_only)
                        print_no_aggr_metric(prefix);
                else {
-                       evlist__for_each_entry(evsel_list, counter)
+                       evlist__for_each_entry(evsel_list, counter) {
+                               if (is_duration_time(counter))
+                                       continue;
                                print_counter(counter, prefix);
+                       }
                }
                break;
        case AGGR_UNSET:
@@ -1754,6 +1815,13 @@ static int enable_metric_only(const struct option *opt __maybe_unused,
        return 0;
 }
 
+static int parse_metric_groups(const struct option *opt,
+                              const char *str,
+                              int unset __maybe_unused)
+{
+       return metricgroup__parse_groups(opt, str, &metric_events);
+}
+
 static const struct option stat_options[] = {
        OPT_BOOLEAN('T', "transaction", &transaction_run,
                    "hardware transaction statistics"),
@@ -1819,6 +1887,9 @@ static const struct option stat_options[] = {
                        "measure topdown level 1 statistics"),
        OPT_BOOLEAN(0, "smi-cost", &smi_cost,
                        "measure SMI cost"),
+       OPT_CALLBACK('M', "metrics", &evsel_list, "metric/metric group list",
+                    "monitor specified metrics or metric groups (separated by ,)",
+                    parse_metric_groups),
        OPT_END()
 };
 
@@ -2334,20 +2405,20 @@ static void init_features(struct perf_session *session)
 static int __cmd_record(int argc, const char **argv)
 {
        struct perf_session *session;
-       struct perf_data_file *file = &perf_stat.file;
+       struct perf_data *data = &perf_stat.data;
 
        argc = parse_options(argc, argv, stat_options, stat_record_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
 
        if (output_name)
-               file->path = output_name;
+               data->file.path = output_name;
 
        if (run_count != 1 || forever) {
                pr_err("Cannot use -r option with perf stat record.\n");
                return -1;
        }
 
-       session = perf_session__new(file, false, NULL);
+       session = perf_session__new(data, false, NULL);
        if (session == NULL) {
                pr_err("Perf session creation failed.\n");
                return -1;
@@ -2405,7 +2476,7 @@ int process_stat_config_event(struct perf_tool *tool,
        if (st->aggr_mode != AGGR_UNSET)
                stat_config.aggr_mode = st->aggr_mode;
 
-       if (perf_stat.file.is_pipe)
+       if (perf_stat.data.is_pipe)
                perf_stat_init_aggr_mode();
        else
                perf_stat_init_aggr_mode_file(st);
@@ -2513,10 +2584,10 @@ static int __cmd_report(int argc, const char **argv)
                        input_name = "perf.data";
        }
 
-       perf_stat.file.path = input_name;
-       perf_stat.file.mode = PERF_DATA_MODE_READ;
+       perf_stat.data.file.path = input_name;
+       perf_stat.data.mode      = PERF_DATA_MODE_READ;
 
-       session = perf_session__new(&perf_stat.file, false, &perf_stat.tool);
+       session = perf_session__new(&perf_stat.data, false, &perf_stat.tool);
        if (session == NULL)
                return -1;
 
@@ -2787,7 +2858,7 @@ int cmd_stat(int argc, const char **argv)
                 * records, but the need to suppress the kptr_restrict messages in older
                 * tools remain  -acme
                 */
-               int fd = perf_data_file__fd(&perf_stat.file);
+               int fd = perf_data__fd(&perf_stat.data);
                int err = perf_event__synthesize_kernel_mmap((void *)&perf_stat,
                                                             process_synthesized_event,
                                                             &perf_stat.session->machines.host);
@@ -2801,7 +2872,7 @@ int cmd_stat(int argc, const char **argv)
                                pr_err("failed to write stat round event\n");
                }
 
-               if (!perf_stat.file.is_pipe) {
+               if (!perf_stat.data.is_pipe) {
                        perf_stat.session->header.data_size += perf_stat.bytes_written;
                        perf_session__write_header(perf_stat.session, evsel_list, fd, true);
                }
index 4e2e61695986350a93b04b322712267068974e9e..813698a9b8c72d7188683dea53bf838a16c81c9d 100644 (file)
@@ -1601,13 +1601,15 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
                { "syscalls:sys_exit_pselect6",         process_exit_poll },
                { "syscalls:sys_exit_select",           process_exit_poll },
        };
-       struct perf_data_file file = {
-               .path = input_name,
-               .mode = PERF_DATA_MODE_READ,
-               .force = tchart->force,
+       struct perf_data data = {
+               .file      = {
+                       .path = input_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = tchart->force,
        };
 
-       struct perf_session *session = perf_session__new(&file, false,
+       struct perf_session *session = perf_session__new(&data, false,
                                                         &tchart->tool);
        int ret = -EINVAL;
 
@@ -1617,7 +1619,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
        symbol__init(&session->header.env);
 
        (void)perf_header__process_sections(&session->header,
-                                           perf_data_file__fd(session->file),
+                                           perf_data__fd(session->data),
                                            tchart,
                                            process_header);
 
@@ -1732,8 +1734,10 @@ static int timechart__io_record(int argc, const char **argv)
        if (rec_argv == NULL)
                return -ENOMEM;
 
-       if (asprintf(&filter, "common_pid != %d", getpid()) < 0)
+       if (asprintf(&filter, "common_pid != %d", getpid()) < 0) {
+               free(rec_argv);
                return -ENOMEM;
+       }
 
        p = rec_argv;
        for (i = 0; i < common_args_nr; i++)
index ee954bde7e3e800d308a41af7d70acc333802b67..477a8699f0b501e3c71a711fd6a5a336645a1c46 100644 (file)
@@ -958,8 +958,16 @@ static int __cmd_top(struct perf_top *top)
        if (perf_session__register_idle_thread(top->session) < 0)
                goto out_delete;
 
+       if (top->nr_threads_synthesize > 1)
+               perf_set_multithreaded();
+
        machine__synthesize_threads(&top->session->machines.host, &opts->target,
-                                   top->evlist->threads, false, opts->proc_map_timeout);
+                                   top->evlist->threads, false,
+                                   opts->proc_map_timeout,
+                                   top->nr_threads_synthesize);
+
+       if (top->nr_threads_synthesize > 1)
+               perf_set_singlethreaded();
 
        if (perf_hpp_list.socket) {
                ret = perf_env__read_cpu_topology_map(&perf_env);
@@ -1112,6 +1120,7 @@ int cmd_top(int argc, const char **argv)
                },
                .max_stack           = sysctl_perf_event_max_stack,
                .sym_pcnt_filter     = 5,
+               .nr_threads_synthesize = UINT_MAX,
        };
        struct record_opts *opts = &top.record_opts;
        struct target *target = &opts->target;
@@ -1221,6 +1230,8 @@ int cmd_top(int argc, const char **argv)
        OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy,
                    "Show entries in a hierarchy"),
        OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"),
+       OPT_UINTEGER(0, "num-thread-synthesize", &top.nr_threads_synthesize,
+                       "number of thread to run event synthesize"),
        OPT_END()
        };
        const char * const top_usage[] = {
index 771ddab94bb04746786c2b52389942f1455da48b..f2757d38c7d7054d4dcef7d7e90f25efc115a8f7 100644 (file)
@@ -578,7 +578,6 @@ static struct syscall_fmt {
 } syscall_fmts[] = {
        { .name     = "access",
          .arg = { [1] = { .scnprintf = SCA_ACCMODE,  /* mode */ }, }, },
-       { .name     = "arch_prctl", .alias = "prctl", },
        { .name     = "bpf",
          .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
        { .name     = "brk",        .hexret = true,
@@ -634,6 +633,12 @@ static struct syscall_fmt {
 #else
                   [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
 #endif
+       { .name     = "kcmp",       .nr_args = 5,
+         .arg = { [0] = { .name = "pid1",      .scnprintf = SCA_PID, },
+                  [1] = { .name = "pid2",      .scnprintf = SCA_PID, },
+                  [2] = { .name = "type",      .scnprintf = SCA_KCMP_TYPE, },
+                  [3] = { .name = "idx1",      .scnprintf = SCA_KCMP_IDX, },
+                  [4] = { .name = "idx2",      .scnprintf = SCA_KCMP_IDX, }, }, },
        { .name     = "keyctl",
          .arg = { [0] = STRARRAY(option, keyctl_options), }, },
        { .name     = "kill",
@@ -703,6 +708,10 @@ static struct syscall_fmt {
                   [3] = { .scnprintf = SCA_INT,        /* pkey */ }, }, },
        { .name     = "poll", .timeout = true, },
        { .name     = "ppoll", .timeout = true, },
+       { .name     = "prctl", .alias = "arch_prctl",
+         .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
+                  [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
+                  [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
        { .name     = "pread", .alias = "pread64", },
        { .name     = "preadv", .alias = "pread", },
        { .name     = "prlimit64",
@@ -985,6 +994,23 @@ size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
        return printed;
 }
 
+size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
+{
+        size_t printed = scnprintf(bf, size, "%d", fd);
+       struct thread *thread = machine__find_thread(trace->host, pid, pid);
+
+       if (thread) {
+               const char *path = thread__fd_path(thread, fd, trace);
+
+               if (path)
+                       printed += scnprintf(bf + printed, size - printed, "<%s>", path);
+
+               thread__put(thread);
+       }
+
+        return printed;
+}
+
 static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
                                              struct syscall_arg *arg)
 {
@@ -1131,13 +1157,21 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
 
        err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
                                            evlist->threads, trace__tool_process, false,
-                                           trace->opts.proc_map_timeout);
+                                           trace->opts.proc_map_timeout, 1);
        if (err)
                symbol__exit();
 
        return err;
 }
 
+static void trace__symbols__exit(struct trace *trace)
+{
+       machine__exit(trace->host);
+       trace->host = NULL;
+
+       symbol__exit();
+}
+
 static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
 {
        int idx;
@@ -1828,16 +1862,14 @@ out_dump:
        goto out_put;
 }
 
-static void bpf_output__printer(enum binary_printer_ops op,
-                               unsigned int val, void *extra)
+static int bpf_output__printer(enum binary_printer_ops op,
+                              unsigned int val, void *extra __maybe_unused, FILE *fp)
 {
-       FILE *output = extra;
        unsigned char ch = (unsigned char)val;
 
        switch (op) {
        case BINARY_PRINT_CHAR_DATA:
-               fprintf(output, "%c", isprint(ch) ? ch : '.');
-               break;
+               return fprintf(fp, "%c", isprint(ch) ? ch : '.');
        case BINARY_PRINT_DATA_BEGIN:
        case BINARY_PRINT_LINE_BEGIN:
        case BINARY_PRINT_ADDR:
@@ -1850,13 +1882,15 @@ static void bpf_output__printer(enum binary_printer_ops op,
        default:
                break;
        }
+
+       return 0;
 }
 
 static void bpf_output__fprintf(struct trace *trace,
                                struct perf_sample *sample)
 {
-       print_binary(sample->raw_data, sample->raw_size, 8,
-                    bpf_output__printer, trace->output);
+       binary__fprintf(sample->raw_data, sample->raw_size, 8,
+                       bpf_output__printer, NULL, trace->output);
 }
 
 static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
@@ -2078,6 +2112,7 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
                        rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
                else {
                        pr_err("Neither raw_syscalls nor syscalls events exist.\n");
+                       free(rec_argv);
                        return -1;
                }
        }
@@ -2481,6 +2516,8 @@ out_disable:
        }
 
 out_delete_evlist:
+       trace__symbols__exit(trace);
+
        perf_evlist__delete(evlist);
        trace->evlist = NULL;
        trace->live = false;
@@ -2528,10 +2565,12 @@ static int trace__replay(struct trace *trace)
        const struct perf_evsel_str_handler handlers[] = {
                { "probe:vfs_getname",       trace__vfs_getname, },
        };
-       struct perf_data_file file = {
-               .path  = input_name,
-               .mode  = PERF_DATA_MODE_READ,
-               .force = trace->force,
+       struct perf_data data = {
+               .file      = {
+                       .path = input_name,
+               },
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = trace->force,
        };
        struct perf_session *session;
        struct perf_evsel *evsel;
@@ -2554,7 +2593,7 @@ static int trace__replay(struct trace *trace)
        /* add tid to output */
        trace->multiple_threads = true;
 
-       session = perf_session__new(&file, false, &trace->tool);
+       session = perf_session__new(&data, false, &trace->tool);
        if (session == NULL)
                return -1;
 
@@ -2730,20 +2769,23 @@ DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_event
 
 static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
 {
-       DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
        size_t printed = trace__fprintf_threads_header(fp);
        struct rb_node *nd;
+       int i;
 
-       if (threads == NULL) {
-               fprintf(fp, "%s", "Error sorting output by nr_events!\n");
-               return 0;
-       }
+       for (i = 0; i < THREADS__TABLE_SIZE; i++) {
+               DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
 
-       resort_rb__for_each_entry(nd, threads)
-               printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
+               if (threads == NULL) {
+                       fprintf(fp, "%s", "Error sorting output by nr_events!\n");
+                       return 0;
+               }
 
-       resort_rb__delete(threads);
+               resort_rb__for_each_entry(nd, threads)
+                       printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
 
+               resort_rb__delete(threads);
+       }
        return printed;
 }
 
index 50cd6228f50637def472cf75ce37ed9bba759a10..77406d25e5218023bf15277f293338e4279fe144 100755 (executable)
@@ -5,8 +5,10 @@ HEADERS='
 include/uapi/drm/drm.h
 include/uapi/drm/i915_drm.h
 include/uapi/linux/fcntl.h
+include/uapi/linux/kcmp.h
 include/uapi/linux/kvm.h
 include/uapi/linux/perf_event.h
+include/uapi/linux/prctl.h
 include/uapi/linux/sched.h
 include/uapi/linux/stat.h
 include/uapi/linux/vhost.h
@@ -58,6 +60,11 @@ check () {
 }
 
 
+# Check if we have the kernel headers (tools/perf/../../include), else
+# we're probably on a detached tarball, so no point in trying to check
+# differences.
+test -d ../../include || exit 0
+
 # simple diff check
 for i in $HEADERS; do
   check $i -B
index f75f3dec748502e6edb1bfb3709e1a323119c0f6..2357f4ccc9c79d22d4f9d3ad152a2ec2e63482fe 100644 (file)
@@ -66,6 +66,7 @@ struct record_opts {
        unsigned int user_freq;
        u64          branch_stack;
        u64          sample_intr_regs;
+       u64          sample_user_regs;
        u64          default_interval;
        u64          user_interval;
        size_t       auxtrace_snapshot_size;
diff --git a/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json b/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json
new file mode 100644 (file)
index 0000000..00bfdb5
--- /dev/null
@@ -0,0 +1,164 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , IDQ.MITE_UOPS / ( (UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 16 * ( ICACHE.HIT + ICACHE.MISSES ) / 4.0 ) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_EXECUTED.THREAD / (( cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2) if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+        "MetricExpr": "2* (( RS_EVENTS.EMPTY_CYCLES - ICACHE.IFDATA_STALL  - (( 14 * ITLB_MISSES.STLB_HIT + cpu@ITLB_MISSES.WALK_DURATION\\,cmask\\=1@ + 7* ITLB_MISSES.WALK_COMPLETED )) ) / RS_EVENTS.EMPTY_END)",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_UOPS_RETIRED.L1_MISS + mem_load_uops_retired.hit_lfb )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / (( cpu@l1d_pend_miss.pending_cycles\\,any\\=1@ / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES)",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+        "MetricExpr": "( cpu@ITLB_MISSES.WALK_DURATION\\,cmask\\=1@ + cpu@DTLB_LOAD_MISSES.WALK_DURATION\\,cmask\\=1@ + cpu@DTLB_STORE_MISSES.WALK_DURATION\\,cmask\\=1@ + 7*(DTLB_STORE_MISSES.WALK_COMPLETED+DTLB_LOAD_MISSES.WALK_COMPLETED+ITLB_MISSES.WALK_COMPLETED)) / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "(( 1*( FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_ARITH_INST_RETIRED.SCALAR_DOUBLE ) + 2* FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4*( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE ) + 8* FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE )) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json b/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json
new file mode 100644 (file)
index 0000000..49c5f12
--- /dev/null
@@ -0,0 +1,164 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , IDQ.MITE_UOPS / ( UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY * 16 * ( ICACHE.HIT + ICACHE.MISSES ) / 4.0 ) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / INST_RETIRED.ANY / cycles",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / ( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_EXECUTED.THREAD / ( cpu@uops_executed.core\\,cmask\\=1@ / 2) if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+       "MetricExpr": "2* ( RS_EVENTS.EMPTY_CYCLES - ICACHE.IFDATA_STALL  - ( 14 * ITLB_MISSES.STLB_HIT + cpu@ITLB_MISSES.WALK_DURATION\\,cmask\\=1@ + 7* ITLB_MISSES.WALK_COMPLETED ) ) / RS_EVENTS.EMPTY_END",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_UOPS_RETIRED.L1_MISS + mem_load_uops_retired.hit_lfb )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( cpu@l1d_pend_miss.pending_cycles\\,any\\=1@ / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+       "MetricExpr": "( cpu@ITLB_MISSES.WALK_DURATION\\,cmask\\=1@ + cpu@DTLB_LOAD_MISSES.WALK_DURATION\\,cmask\\=1@ + cpu@DTLB_STORE_MISSES.WALK_DURATION\\,cmask\\=1@ + 7*(DTLB_STORE_MISSES.WALK_COMPLETED+DTLB_LOAD_MISSES.WALK_COMPLETED+ITLB_MISSES.WALK_COMPLETED)) / ( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "( 1*( FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_ARITH_INST_RETIRED.SCALAR_DOUBLE ) + 2* FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4*( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE ) + 8* FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE ) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json b/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json
new file mode 100644 (file)
index 0000000..5a7f1ec
--- /dev/null
@@ -0,0 +1,164 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , IDQ.MITE_UOPS / ( (UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 16 * ( ICACHE.HIT + ICACHE.MISSES ) / 4.0 ) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_EXECUTED.THREAD / (( cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2) if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+        "MetricExpr": "2* (( RS_EVENTS.EMPTY_CYCLES - ICACHE.IFDATA_STALL  - (( 14 * ITLB_MISSES.STLB_HIT + cpu@ITLB_MISSES.WALK_DURATION\\,cmask\\=1@ + 7* ITLB_MISSES.WALK_COMPLETED )) ) / RS_EVENTS.EMPTY_END)",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_UOPS_RETIRED.L1_MISS + mem_load_uops_retired.hit_lfb )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / (( cpu@l1d_pend_miss.pending_cycles\\,any\\=1@ / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES)",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+        "MetricExpr": "( ITLB_MISSES.WALK_DURATION + DTLB_LOAD_MISSES.WALK_DURATION + DTLB_STORE_MISSES.WALK_DURATION + 7*(DTLB_STORE_MISSES.WALK_COMPLETED+DTLB_LOAD_MISSES.WALK_COMPLETED+ITLB_MISSES.WALK_COMPLETED) ) / (2*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles))",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "(( 1*( FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_ARITH_INST_RETIRED.SCALAR_DOUBLE ) + 2* FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4*( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE ) + 8* FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE )) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/goldmontplus/cache.json b/tools/perf/pmu-events/arch/x86/goldmontplus/cache.json
new file mode 100644 (file)
index 0000000..b4791b4
--- /dev/null
@@ -0,0 +1,1453 @@
+[
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts memory requests originating from the core that miss in the L2 cache.",
+        "EventCode": "0x2E",
+        "Counter": "0,1,2,3",
+        "UMask": "0x41",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "LONGEST_LAT_CACHE.MISS",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "L2 cache request misses"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts memory requests originating from the core that reference a cache line in the L2 cache.",
+        "EventCode": "0x2E",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4f",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "LONGEST_LAT_CACHE.REFERENCE",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "L2 cache requests"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of demand and prefetch transactions that the L2 XQ rejects due to a full or near full condition which likely indicates back pressure from the intra-die interconnect (IDI) fabric. The XQ may reject transactions from the L2Q (non-cacheable requests), L2 misses and L2 write-back victims.",
+        "EventCode": "0x30",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "L2_REJECT_XQ.ALL",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Requests rejected by the XQ"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of demand and L1 prefetcher requests rejected by the L2Q due to a full or nearly full condition which likely indicates back pressure from L2Q. It also counts requests that would have gone directly to the XQ, but are rejected due to a full or nearly full condition, indicating back pressure from the IDI link. The L2Q may also reject transactions from a core to insure fairness between cores, or to delay a core's dirty eviction when the address conflicts with incoming external snoops.",
+        "EventCode": "0x31",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "CORE_REJECT_L2Q.ALL",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Requests rejected by the L2Q"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts when a modified (dirty) cache line is evicted from the data L1 cache and needs to be written back to memory.  No count will occur if the evicted line is clean, and hence does not require a writeback.",
+        "EventCode": "0x51",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DL1.REPLACEMENT",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "L1 Cache evictions for dirty data"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts cycles that fetch is stalled due to an outstanding ICache miss. That is, the decoder queue is able to accept bytes, but the fetch unit is unable to provide bytes due to an ICache miss.  Note: this event is not the same as the total number of cycles spent retrieving instruction cache lines from the memory hierarchy.",
+        "EventCode": "0x86",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "FETCH_STALL.ICACHE_FILL_PENDING_CYCLES",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Cycles code-fetch stalled due to an outstanding ICache miss."
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "EventCode": "0xB7",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts locked memory uops retired.  This includes regular locks and bus locks. (To specifically count bus locks only, see the Offcore response event.)  A locked access is one with a lock prefix, or an exchange to memory.  See the SDM for a complete description of which memory load accesses are locks.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x21",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.LOCK_LOADS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Locked load uops retired (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts load uops retired where the data requested spans a 64 byte cache line boundary.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x41",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.SPLIT_LOADS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Load uops retired that split a cache-line (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts store uops retired where the data requested spans a 64 byte cache line boundary.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x42",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.SPLIT_STORES",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Stores uops retired that split a cache-line (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts memory uops retired where the data requested spans a 64 byte cache line boundary.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x43",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.SPLIT",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Memory uops retired that split a cache-line (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts the number of load uops retired.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x81",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.ALL_LOADS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Load uops retired (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts the number of store uops retired.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x82",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.ALL_STORES",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Store uops retired (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts the number of memory uops retired that is either a loads or a store or both.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x83",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.ALL",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Memory uops retired (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts load uops retired that hit the L1 data cache.",
+        "EventCode": "0xD1",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_LOAD_UOPS_RETIRED.L1_HIT",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Load uops retired that hit L1 data cache (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts load uops retired that hit in the L2 cache.",
+        "EventCode": "0xD1",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_LOAD_UOPS_RETIRED.L2_HIT",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Load uops retired that hit L2 (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts load uops retired that miss the L1 data cache.",
+        "EventCode": "0xD1",
+        "Counter": "0,1,2,3",
+        "UMask": "0x8",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_LOAD_UOPS_RETIRED.L1_MISS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Load uops retired that missed L1 data cache (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts load uops retired that miss in the L2 cache.",
+        "EventCode": "0xD1",
+        "Counter": "0,1,2,3",
+        "UMask": "0x10",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_LOAD_UOPS_RETIRED.L2_MISS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Load uops retired that missed L2 (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts load uops retired where the cache line containing the data was in the modified state of another core or modules cache (HITM).  More specifically, this means that when the load address was checked by other caching agents (typically another processor) in the system, one of those caching agents indicated that they had a dirty copy of the data.  Loads that obtain a HITM response incur greater latency than most is typical for a load.  In addition, since HITM indicates that some other processor had this data in its cache, it implies that the data was shared between processors, or potentially was a lock or semaphore value.  This event is useful for locating sharing, false sharing, and contended locks.",
+        "EventCode": "0xD1",
+        "Counter": "0,1,2,3",
+        "UMask": "0x20",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_LOAD_UOPS_RETIRED.HITM",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Memory uop retired where cross core or cross module HITM occurred (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts memory load uops retired where the data is retrieved from the WCB (or fill buffer), indicating that the load found its data while that data was in the process of being brought into the L1 cache.  Typically a load will receive this indication when some other load or prefetch missed the L1 cache and was in the process of retrieving the cache line containing the data, but that process had not yet finished (and written the data back to the cache). For example, consider load X and Y, both referencing the same cache line that is not in the L1 cache.  If load X misses cache first, it obtains and WCB (or fill buffer) and begins the process of requesting the data.  When load Y requests the data, it will either hit the WCB, or the L1 cache, depending on exactly what time the request to Y occurs.",
+        "EventCode": "0xD1",
+        "Counter": "0,1,2,3",
+        "UMask": "0x40",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_LOAD_UOPS_RETIRED.WCB_HIT",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Loads retired that hit WCB (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts memory load uops retired where the data is retrieved from DRAM.  Event is counted at retirement, so the speculative loads are ignored.  A memory load can hit (or miss) the L1 cache, hit (or miss) the L2 cache, hit DRAM, hit in the WCB or receive a HITM response.",
+        "EventCode": "0xD1",
+        "Counter": "0,1,2,3",
+        "UMask": "0x80",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_LOAD_UOPS_RETIRED.DRAM_HIT",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Loads retired that came from DRAM (Precise event capable)"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand cacheable data reads of full cache lines have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010001",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand cacheable data reads of full cache lines have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand cacheable data reads of full cache lines hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040001",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand cacheable data reads of full cache lines hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand cacheable data reads of full cache lines true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000001",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand cacheable data reads of full cache lines true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand cacheable data reads of full cache lines miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000001",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand cacheable data reads of full cache lines miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand cacheable data reads of full cache lines outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000001",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_DATA_RD.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand cacheable data reads of full cache lines outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010002",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040002",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000002",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000002",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000002",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_RFO.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand reads for ownership (RFO) requests generated by a write to full data cache line outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010004",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040004",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000004",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000004",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000004",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.DEMAND_CODE_RD.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts demand instruction cacheline and I-side prefetch requests that miss the instruction cache outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010008",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.COREWB.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040008",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.COREWB.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000008",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.COREWB.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000008",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.COREWB.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000008",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.COREWB.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts the number of writeback transactions caused by L1 or L2 cache evictions outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_DATA_RD.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cacheline reads generated by hardware L2 cache prefetcher outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010020",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040020",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000020",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000020",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000020",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L2_RFO.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests generated by L2 prefetcher outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts bus lock and split lock requests have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010400",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.BUS_LOCKS.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts bus lock and split lock requests have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts bus lock and split lock requests hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040400",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.BUS_LOCKS.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts bus lock and split lock requests hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts bus lock and split lock requests true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000400",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.BUS_LOCKS.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts bus lock and split lock requests true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts bus lock and split lock requests miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000400",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.BUS_LOCKS.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts bus lock and split lock requests miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts bus lock and split lock requests outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000400",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.BUS_LOCKS.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts bus lock and split lock requests outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.FULL_STREAMING_STORES.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.FULL_STREAMING_STORES.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.FULL_STREAMING_STORES.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.FULL_STREAMING_STORES.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.FULL_STREAMING_STORES.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts full cache line data writes to uncacheable write combining (USWC) memory region and full cache-line non-temporal writes outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache lines requests by software prefetch instructions have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000011000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.SW_PREFETCH.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache lines requests by software prefetch instructions have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache lines requests by software prefetch instructions hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000041000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.SW_PREFETCH.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache lines requests by software prefetch instructions hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache lines requests by software prefetch instructions true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200001000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.SW_PREFETCH.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache lines requests by software prefetch instructions true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache lines requests by software prefetch instructions miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000001000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.SW_PREFETCH.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache lines requests by software prefetch instructions miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache lines requests by software prefetch instructions outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000001000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.SW_PREFETCH.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache lines requests by software prefetch instructions outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000012000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L1_DATA_RD.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000042000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L1_DATA_RD.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200002000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L1_DATA_RD.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000002000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L1_DATA_RD.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000002000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.PF_L1_DATA_RD.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data cache line reads generated by hardware L1 data cache prefetcher outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000014800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.STREAMING_STORES.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000044800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.STREAMING_STORES.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200004800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.STREAMING_STORES.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000004800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.STREAMING_STORES.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000004800",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.STREAMING_STORES.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts any data writes to uncacheable write combining (USWC) memory region  outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts requests to the uncore subsystem have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000018000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_REQUEST.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts requests to the uncore subsystem have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts requests to the uncore subsystem hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000048000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_REQUEST.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts requests to the uncore subsystem hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts requests to the uncore subsystem true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200008000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_REQUEST.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts requests to the uncore subsystem true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts requests to the uncore subsystem miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000008000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_REQUEST.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts requests to the uncore subsystem miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts requests to the uncore subsystem outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000008000",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_REQUEST.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts requests to the uncore subsystem outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads generated by L1 or L2 prefetchers have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000013010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_PF_DATA_RD.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads generated by L1 or L2 prefetchers have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads generated by L1 or L2 prefetchers hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000043010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_PF_DATA_RD.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads generated by L1 or L2 prefetchers hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads generated by L1 or L2 prefetchers true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200003010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_PF_DATA_RD.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads generated by L1 or L2 prefetchers true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads generated by L1 or L2 prefetchers miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000003010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_PF_DATA_RD.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads generated by L1 or L2 prefetchers miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads generated by L1 or L2 prefetchers outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000003010",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_PF_DATA_RD.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads generated by L1 or L2 prefetchers outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads (demand & prefetch) have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000013091",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_DATA_RD.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads (demand & prefetch) have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads (demand & prefetch) hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000043091",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_DATA_RD.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads (demand & prefetch) hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads (demand & prefetch) true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200003091",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_DATA_RD.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads (demand & prefetch) true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads (demand & prefetch) miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000003091",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_DATA_RD.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads (demand & prefetch) miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data reads (demand & prefetch) outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000003091",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_DATA_RD.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data reads (demand & prefetch) outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000010022",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_RFO.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0000040022",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_RFO.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x0200000022",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_RFO.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x1000000022",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_RFO.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x4000000022",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_RFO.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts reads for ownership (RFO) requests (demand & prefetch) outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) have any transaction responses from the uncore subsystem. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x00000132b7",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_READ.ANY_RESPONSE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) have any transaction responses from the uncore subsystem.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) hit the L2 cache. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x00000432b7",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_READ.L2_HIT",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) hit the L2 cache.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) true miss for the L2 cache with a snoop miss in the other processor module.  Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x02000032b7",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_READ.L2_MISS.SNOOP_MISS_OR_NO_SNOOP_NEEDED",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) true miss for the L2 cache with a snoop miss in the other processor module. ",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) miss the L2 cache with a snoop hit in the other processor module, data forwarding is required. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x10000032b7",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_READ.L2_MISS.HITM_OTHER_CORE",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6, 0x1a7",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) miss the L2 cache with a snoop hit in the other processor module, data forwarding is required.",
+        "Offcore": "1"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) outstanding, per cycle, from the time of the L2 miss to when any response is received. Requires MSR_OFFCORE_RESP[0,1] to specify request type and response. (duplicated for both MSRs)",
+        "EventCode": "0xB7",
+        "MSRValue": "0x40000032b7",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "OFFCORE_RESPONSE.ANY_READ.OUTSTANDING",
+        "PDIR_COUNTER": "na",
+        "MSRIndex": "0x1a6",
+        "SampleAfterValue": "100007",
+        "BriefDescription": "Counts data read, code read, and read for ownership (RFO) requests (demand & prefetch) outstanding, per cycle, from the time of the L2 miss to when any response is received.",
+        "Offcore": "1"
+    }
+]
\ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/goldmontplus/frontend.json b/tools/perf/pmu-events/arch/x86/goldmontplus/frontend.json
new file mode 100644 (file)
index 0000000..a787896
--- /dev/null
@@ -0,0 +1,62 @@
+[
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts requests to the Instruction Cache (ICache) for one or more bytes in an ICache Line and that cache line is in the ICache (hit).  The event strives to count on a cache line basis, so that multiple accesses which hit in a single cache line count as one ICACHE.HIT.  Specifically, the event counts when straight line code crosses the cache line boundary, or when a branch target is to a new line, and that cache line is in the ICache. This event counts differently than Intel processors based on Silvermont microarchitecture.",
+        "EventCode": "0x80",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ICACHE.HIT",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "References per ICache line that are available in the ICache (hit). This event counts differently than Intel processors based on Silvermont microarchitecture"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts requests to the Instruction Cache (ICache)  for one or more bytes in an ICache Line and that cache line is not in the ICache (miss).  The event strives to count on a cache line basis, so that multiple accesses which miss in a single cache line count as one ICACHE.MISS.  Specifically, the event counts when straight line code crosses the cache line boundary, or when a branch target is to a new line, and that cache line is not in the ICache. This event counts differently than Intel processors based on Silvermont microarchitecture.",
+        "EventCode": "0x80",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ICACHE.MISSES",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "References per ICache line that are not available in the ICache (miss). This event counts differently than Intel processors based on Silvermont microarchitecture"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts requests to the Instruction Cache (ICache) for one or more bytes in an ICache Line.  The event strives to count on a cache line basis, so that multiple fetches to a single cache line count as one ICACHE.ACCESS.  Specifically, the event counts when accesses from straight line code crosses the cache line boundary, or when a branch target is to a new line.\r\nThis event counts differently than Intel processors based on Silvermont microarchitecture.",
+        "EventCode": "0x80",
+        "Counter": "0,1,2,3",
+        "UMask": "0x3",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ICACHE.ACCESSES",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "References per ICache line. This event counts differently than Intel processors based on Silvermont microarchitecture"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of times the Microcode Sequencer (MS) starts a flow of uops from the MSROM. It does not count every time a uop is read from the MSROM.  The most common case that this counts is when a micro-coded instruction is encountered by the front end of the machine.  Other cases include when an instruction encounters a fault, trap, or microcode assist of any sort that initiates a flow of uops.  The event will count MS startups for uops that are speculative, and subsequently cleared by branch mispredict or a machine clear.",
+        "EventCode": "0xE7",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MS_DECODED.MS_ENTRY",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "MS decode starts"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of times the prediction (from the predecode cache) for instruction length is incorrect.",
+        "EventCode": "0xE9",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DECODE_RESTRICTION.PREDECODE_WRONG",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Decode restrictions due to predicting wrong instruction length"
+    }
+]
\ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/goldmontplus/memory.json b/tools/perf/pmu-events/arch/x86/goldmontplus/memory.json
new file mode 100644 (file)
index 0000000..91e0815
--- /dev/null
@@ -0,0 +1,38 @@
+[
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts when a memory load of a uop spans a page boundary (a split) is retired.",
+        "EventCode": "0x13",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MISALIGN_MEM_REF.LOAD_PAGE_SPLIT",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Load uops that split a page (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts when a memory store of a uop spans a page boundary (a split) is retired.",
+        "EventCode": "0x13",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MISALIGN_MEM_REF.STORE_PAGE_SPLIT",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Store uops that split a page (Precise event capable)"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts machine clears due to memory ordering issues.  This occurs when a snoop request happens and the machine is uncertain if memory ordering will be preserved - as another core is in the process of modifying the data.",
+        "EventCode": "0xC3",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MACHINE_CLEARS.MEMORY_ORDERING",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "20003",
+        "BriefDescription": "Machine clears due to memory ordering issue"
+    }
+]
\ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/goldmontplus/other.json b/tools/perf/pmu-events/arch/x86/goldmontplus/other.json
new file mode 100644 (file)
index 0000000..b860374
--- /dev/null
@@ -0,0 +1,98 @@
+[
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts cycles that fetch is stalled due to any reason. That is, the decoder queue is able to accept bytes, but the fetch unit is unable to provide bytes.  This will include cycles due to an ITLB miss, ICache miss and other events.",
+        "EventCode": "0x86",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "FETCH_STALL.ALL",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Cycles code-fetch stalled due to any reason."
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts cycles that fetch is stalled due to an outstanding ITLB miss. That is, the decoder queue is able to accept bytes, but the fetch unit is unable to provide bytes due to an ITLB miss.  Note: this event is not the same as page walk cycles to retrieve an instruction translation.",
+        "EventCode": "0x86",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "FETCH_STALL.ITLB_FILL_PENDING_CYCLES",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Cycles the code-fetch stalls and an ITLB miss is outstanding."
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of issue slots per core cycle that were not consumed by the backend due to either a full resource  in the backend (RESOURCE_FULL) or due to the processor recovering from some event (RECOVERY).",
+        "EventCode": "0xCA",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ISSUE_SLOTS_NOT_CONSUMED.ANY",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Unfilled issue slots per cycle"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of issue slots per core cycle that were not consumed because of a full resource in the backend.  Including but not limited to resources such as the Re-order Buffer (ROB), reservation stations (RS), load/store buffers, physical registers, or any other needed machine resource that is currently unavailable.   Note that uops must be available for consumption in order for this event to fire.  If a uop is not available (Instruction Queue is empty), this event will not count.",
+        "EventCode": "0xCA",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ISSUE_SLOTS_NOT_CONSUMED.RESOURCE_FULL",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Unfilled issue slots per cycle because of a full resource in the backend"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of issue slots per core cycle that were not consumed by the backend because allocation is stalled waiting for a mispredicted jump to retire or other branch-like conditions (e.g. the event is relevant during certain microcode flows).   Counts all issue slots blocked while within this window including slots where uops were not available in the Instruction Queue.",
+        "EventCode": "0xCA",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ISSUE_SLOTS_NOT_CONSUMED.RECOVERY",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Unfilled issue slots per cycle to recover"
+    },
+    {
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts hardware interrupts received by the processor.",
+        "EventCode": "0xCB",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "HW_INTERRUPTS.RECEIVED",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "203",
+        "BriefDescription": "Hardware interrupts received"
+    },
+    {
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts the number of core cycles during which interrupts are masked (disabled). Increments by 1 each core cycle that EFLAGS.IF is 0, regardless of whether interrupts are pending or not.",
+        "EventCode": "0xCB",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "HW_INTERRUPTS.MASKED",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Cycles hardware interrupts are masked"
+    },
+    {
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts core cycles during which there are pending interrupts, but interrupts are masked (EFLAGS.IF = 0).",
+        "EventCode": "0xCB",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "HW_INTERRUPTS.PENDING_AND_MASKED",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Cycles pending interrupts are masked"
+    }
+]
\ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/goldmontplus/pipeline.json b/tools/perf/pmu-events/arch/x86/goldmontplus/pipeline.json
new file mode 100644 (file)
index 0000000..ccf1aed
--- /dev/null
@@ -0,0 +1,544 @@
+[
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of instructions that retire execution. For instructions that consist of multiple uops, this event counts the retirement of the last uop of the instruction. The counter continues counting during hardware interrupts, traps, and inside interrupt handlers.  This event uses fixed counter 0.  You cannot collect a PEBs record for this event.",
+        "EventCode": "0x00",
+        "Counter": "Fixed counter 0",
+        "UMask": "0x1",
+        "PEBScounters": "32",
+        "EventName": "INST_RETIRED.ANY",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Instructions retired (Fixed event)"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of core cycles while the core is not in a halt state.  The core enters the halt state when it is running the HLT instruction. In mobile systems the core frequency may change from time to time. For this reason this event may have a changing ratio with regards to time.  This event uses fixed counter 1.  You cannot collect a PEBs record for this event.",
+        "EventCode": "0x00",
+        "Counter": "Fixed counter 1",
+        "UMask": "0x2",
+        "PEBScounters": "33",
+        "EventName": "CPU_CLK_UNHALTED.CORE",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Core cycles when core is not halted  (Fixed event)"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of reference cycles that the core is not in a halt state. The core enters the halt state when it is running the HLT instruction.  In mobile systems the core frequency may change from time.  This event is not affected by core frequency changes but counts as if the core is running at the maximum frequency all the time.  This event uses fixed counter 2.  You cannot collect a PEBs record for this event.",
+        "EventCode": "0x00",
+        "Counter": "Fixed counter 2",
+        "UMask": "0x3",
+        "PEBScounters": "34",
+        "EventName": "CPU_CLK_UNHALTED.REF_TSC",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Reference cycles when core is not halted  (Fixed event)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts a load blocked from using a store forward, but did not occur because the store data was not available at the right time.  The forward might occur subsequently when the data is available.",
+        "EventCode": "0x03",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "LD_BLOCKS.DATA_UNKNOWN",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Loads blocked due to store data not ready (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts a load blocked from using a store forward because of an address/size mismatch, only one of the loads blocked from each store will be counted.",
+        "EventCode": "0x03",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "LD_BLOCKS.STORE_FORWARD",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Loads blocked due to store forward restriction (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts loads that block because their address modulo 4K matches a pending store.",
+        "EventCode": "0x03",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "LD_BLOCKS.4K_ALIAS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Loads blocked because address has 4k partial address false dependence (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts loads blocked because they are unable to find their physical address in the micro TLB (UTLB).",
+        "EventCode": "0x03",
+        "Counter": "0,1,2,3",
+        "UMask": "0x8",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "LD_BLOCKS.UTLB_MISS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Loads blocked because address in not in the UTLB (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts anytime a load that retires is blocked for any reason.",
+        "EventCode": "0x03",
+        "Counter": "0,1,2,3",
+        "UMask": "0x10",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "LD_BLOCKS.ALL_BLOCK",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Loads blocked (Precise event capable)"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts uops issued by the front end and allocated into the back end of the machine.  This event counts uops that retire as well as uops that were speculatively executed but didn't retire. The sort of speculative uops that might be counted includes, but is not limited to those uops issued in the shadow of a miss-predicted branch, those uops that are inserted during an assist (such as for a denormal floating point result), and (previously allocated) uops that might be canceled during a machine clear.",
+        "EventCode": "0x0E",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "UOPS_ISSUED.ANY",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Uops issued to the back end per cycle"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Core cycles when core is not halted.  This event uses a (_P)rogrammable general purpose performance counter.",
+        "EventCode": "0x3C",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "CPU_CLK_UNHALTED.CORE_P",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Core cycles when core is not halted"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Reference cycles when core is not halted.  This event uses a (_P)rogrammable general purpose performance counter.",
+        "EventCode": "0x3C",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "CPU_CLK_UNHALTED.REF",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Reference cycles when core is not halted"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "This event used to measure front-end inefficiencies. I.e. when front-end of the machine is not delivering uops to the back-end and the back-end has is not stalled. This event can be used to identify if the machine is truly front-end bound.  When this event occurs, it is an indication that the front-end of the machine is operating at less than its theoretical peak performance. Background: We can think of the processor pipeline as being divided into 2 broader parts: Front-end and Back-end. Front-end is responsible for fetching the instruction, decoding into uops in machine understandable format and putting them into a uop queue to be consumed by back end. The back-end then takes these uops, allocates the required resources.  When all resources are ready, uops are executed. If the back-end is not ready to accept uops from the front-end, then we do not want to count these as front-end bottlenecks.  However, whenever we have bottlenecks in the back-end, we will have allocation unit stalls and eventually forcing the front-end to wait until the back-end is ready to receive more uops. This event counts only when back-end is requesting more uops and front-end is not able to provide them. When 3 uops are requested and no uops are delivered, the event counts 3. When 3 are requested, and only 1 is delivered, the event counts 2. When only 2 are delivered, the event counts 1. Alternatively stated, the event will not count if 3 uops are delivered, or if the back end is stalled and not requesting any uops at all.  Counts indicate missed opportunities for the front-end to deliver a uop to the back end. Some examples of conditions that cause front-end efficiencies are: ICache misses, ITLB misses, and decoder restrictions that limit the front-end bandwidth. Known Issues: Some uops require multiple allocation slots.  These uops will not be charged as a front end 'not delivered' opportunity, and will be regarded as a back end problem. For example, the INC instruction has one uop that requires 2 issue slots.  A stream of INC instructions will not count as UOPS_NOT_DELIVERED, even though only one instruction can be issued per clock.  The low uop issue rate for a stream of INC instructions is considered to be a back end issue.",
+        "EventCode": "0x9C",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "UOPS_NOT_DELIVERED.ANY",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Uops requested but not-delivered to the back-end per cycle"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of instructions that retire execution. For instructions that consist of multiple uops, this event counts the retirement of the last uop of the instruction. The event continues counting during hardware interrupts, traps, and inside interrupt handlers.  This is an architectural performance event.  This event uses a (_P)rogrammable general purpose performance counter. *This event is Precise Event capable:  The EventingRIP field in the PEBS record is precise to the address of the instruction which caused the event.  Note: Because PEBS records can be collected only on IA32_PMC0, only one event can use the PEBS facility at a time.",
+        "EventCode": "0xC0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "INST_RETIRED.ANY_P",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Instructions retired (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts INST_RETIRED.ANY using the Reduced Skid PEBS feature that reduces the shadow in which events aren't counted allowing for a more unbiased distribution of samples across instructions retired.",
+        "EventCode": "0xC0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "EventName": "INST_RETIRED.PREC_DIST",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Instructions retired - using Reduced Skid PEBS feature"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts uops which retired.",
+        "EventCode": "0xC2",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "UOPS_RETIRED.ANY",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Uops retired (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts uops retired that are from the complex flows issued by the micro-sequencer (MS).  Counts both the uops from a micro-coded instruction, and the uops that might be generated from a micro-coded assist.",
+        "EventCode": "0xC2",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "UOPS_RETIRED.MS",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "MS uops retired (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of floating point divide uops retired.",
+        "EventCode": "0xC2",
+        "Counter": "0,1,2,3",
+        "UMask": "0x8",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "UOPS_RETIRED.FPDIV",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Floating point divide uops retired (Precise Event Capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of integer divide uops retired.",
+        "EventCode": "0xC2",
+        "Counter": "0,1,2,3",
+        "UMask": "0x10",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "UOPS_RETIRED.IDIV",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Integer divide uops retired (Precise Event Capable)"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts machine clears for any reason.",
+        "EventCode": "0xC3",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MACHINE_CLEARS.ALL",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "20003",
+        "BriefDescription": "All machine clears"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of times that the processor detects that a program is writing to a code section and has to perform a machine clear because of that modification.  Self-modifying code (SMC) causes a severe penalty in all Intel architecture processors.",
+        "EventCode": "0xC3",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MACHINE_CLEARS.SMC",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "20003",
+        "BriefDescription": "Self-Modifying Code detected"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts machine clears due to floating point (FP) operations needing assists.  For instance, if the result was a floating point denormal, the hardware clears the pipeline and reissues uops to produce the correct IEEE compliant denormal result.",
+        "EventCode": "0xC3",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MACHINE_CLEARS.FP_ASSIST",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "20003",
+        "BriefDescription": "Machine clears due to FP assists"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts machine clears due to memory disambiguation.  Memory disambiguation happens when a load which has been issued conflicts with a previous unretired store in the pipeline whose address was not known at issue time, but is later resolved to be the same as the load address.",
+        "EventCode": "0xC3",
+        "Counter": "0,1,2,3",
+        "UMask": "0x8",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MACHINE_CLEARS.DISAMBIGUATION",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "20003",
+        "BriefDescription": "Machine clears due to memory disambiguation"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of times that the machines clears due to a page fault. Covers both I-side and D-side(Loads/Stores) page faults. A page fault occurs when either page is not present, or an access violation",
+        "EventCode": "0xC3",
+        "Counter": "0,1,2,3",
+        "UMask": "0x20",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MACHINE_CLEARS.PAGE_FAULT",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "20003",
+        "BriefDescription": "Machines clear due to a page fault"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts branch instructions retired for all branch types.  This is an architectural performance event.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.ALL_BRANCHES",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired branch instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts retired Jcc (Jump on Conditional Code/Jump if Condition is Met) branch instructions retired, including both when the branch was taken and when it was not taken.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0x7e",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.JCC",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired conditional branch instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts the number of taken branch instructions retired.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0x80",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.ALL_TAKEN_BRANCHES",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired taken branch instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts far branch instructions retired.  This includes far jump, far call and return, and Interrupt call and return.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0xbf",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.FAR_BRANCH",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired far branch instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts near indirect call or near indirect jmp branch instructions retired.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0xeb",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.NON_RETURN_IND",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired instructions of near indirect Jmp or call (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts near return branch instructions retired.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0xf7",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.RETURN",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired near return instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts near CALL branch instructions retired.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0xf9",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.CALL",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired near call instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts near indirect CALL branch instructions retired.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0xfb",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.IND_CALL",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired near indirect call instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts near relative CALL branch instructions retired.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0xfd",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.REL_CALL",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired near relative call instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts Jcc (Jump on Conditional Code/Jump if Condition is Met) branch instructions retired that were taken and does not count when the Jcc branch instruction were not taken.",
+        "EventCode": "0xC4",
+        "Counter": "0,1,2,3",
+        "UMask": "0xfe",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_INST_RETIRED.TAKEN_JCC",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired conditional branch instructions that were taken (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts mispredicted branch instructions retired including all branch types.",
+        "EventCode": "0xC5",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_MISP_RETIRED.ALL_BRANCHES",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired mispredicted branch instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts mispredicted retired Jcc (Jump on Conditional Code/Jump if Condition is Met) branch instructions retired, including both when the branch was supposed to be taken and when it was not supposed to be taken (but the processor predicted the opposite condition).",
+        "EventCode": "0xC5",
+        "Counter": "0,1,2,3",
+        "UMask": "0x7e",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_MISP_RETIRED.JCC",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired mispredicted conditional branch instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts mispredicted branch instructions retired that were near indirect call or near indirect jmp, where the target address taken was not what the processor predicted.",
+        "EventCode": "0xC5",
+        "Counter": "0,1,2,3",
+        "UMask": "0xeb",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_MISP_RETIRED.NON_RETURN_IND",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired mispredicted instructions of near indirect Jmp or near indirect call (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts mispredicted near RET branch instructions retired, where the return address taken was not what the processor predicted.",
+        "EventCode": "0xC5",
+        "Counter": "0,1,2,3",
+        "UMask": "0xf7",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_MISP_RETIRED.RETURN",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired mispredicted near return instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts mispredicted near indirect CALL branch instructions retired, where the target address taken was not what the processor predicted.",
+        "EventCode": "0xC5",
+        "Counter": "0,1,2,3",
+        "UMask": "0xfb",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_MISP_RETIRED.IND_CALL",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired mispredicted near indirect call instructions (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts mispredicted retired Jcc (Jump on Conditional Code/Jump if Condition is Met) branch instructions retired that were supposed to be taken but the processor predicted that it would not be taken.",
+        "EventCode": "0xC5",
+        "Counter": "0,1,2,3",
+        "UMask": "0xfe",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BR_MISP_RETIRED.TAKEN_JCC",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Retired mispredicted conditional branch instructions that were taken (Precise event capable)"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts core cycles if either divide unit is busy.",
+        "EventCode": "0xCD",
+        "Counter": "0,1,2,3",
+        "UMask": "0x0",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "CYCLES_DIV_BUSY.ALL",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Cycles a divider is busy"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts core cycles the integer divide unit is busy.",
+        "EventCode": "0xCD",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "CYCLES_DIV_BUSY.IDIV",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Cycles the integer divide unit is busy"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts core cycles the floating point divide unit is busy.",
+        "EventCode": "0xCD",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "CYCLES_DIV_BUSY.FPDIV",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Cycles the FP divide unit is busy"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of times a BACLEAR is signaled for any reason, including, but not limited to indirect branch/call,  Jcc (Jump on Conditional Code/Jump if Condition is Met) branch, unconditional branch/call, and returns.",
+        "EventCode": "0xE6",
+        "Counter": "0,1,2,3",
+        "UMask": "0x1",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BACLEARS.ALL",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "BACLEARs asserted for any branch type"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts BACLEARS on return instructions.",
+        "EventCode": "0xE6",
+        "Counter": "0,1,2,3",
+        "UMask": "0x8",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BACLEARS.RETURN",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "BACLEARs asserted for return branch"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts BACLEARS on Jcc (Jump on Conditional Code/Jump if Condition is Met) branches.",
+        "EventCode": "0xE6",
+        "Counter": "0,1,2,3",
+        "UMask": "0x10",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "BACLEARS.COND",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "BACLEARs asserted for conditional branch"
+    }
+]
\ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/goldmontplus/virtual-memory.json b/tools/perf/pmu-events/arch/x86/goldmontplus/virtual-memory.json
new file mode 100644 (file)
index 0000000..0b53a3b
--- /dev/null
@@ -0,0 +1,218 @@
+[
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to demand data loads (including SW prefetches) whose address translations missed in all TLB levels and were mapped to 4K pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x08",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_4K",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Page walk completed due to a demand load to a 4K page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to demand data loads (including SW prefetches) whose address translations missed in all TLB levels and were mapped to 2M or 4M pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x08",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_2M_4M",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Page walk completed due to a demand load to a 2M or 4M page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to demand data loads (including SW prefetches) whose address translations missed in all TLB levels and were mapped to 1GB pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x08",
+        "Counter": "0,1,2,3",
+        "UMask": "0x8",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DTLB_LOAD_MISSES.WALK_COMPLETED_1GB",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Page walk completed due to a demand load to a 1GB page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts once per cycle for each page walk occurring due to a load (demand data loads or SW prefetches). Includes cycles spent traversing the Extended Page Table (EPT). Average cycles per walk can be calculated by dividing by the number of walks.",
+        "EventCode": "0x08",
+        "Counter": "0,1,2,3",
+        "UMask": "0x10",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DTLB_LOAD_MISSES.WALK_PENDING",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Page walks outstanding due to a demand load every cycle."
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to demand data stores whose address translations missed in the TLB and were mapped to 4K pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x49",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_4K",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Page walk completed due to a demand data store to a 4K page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to demand data stores whose address translations missed in the TLB and were mapped to 2M or 4M pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x49",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_2M_4M",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Page walk completed due to a demand data store to a 2M or 4M page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to demand data stores whose address translations missed in the TLB and were mapped to 1GB pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x49",
+        "Counter": "0,1,2,3",
+        "UMask": "0x8",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DTLB_STORE_MISSES.WALK_COMPLETED_1GB",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Page walk completed due to a demand data store to a 1GB page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts once per cycle for each page walk occurring due to a demand data store. Includes cycles spent traversing the Extended Page Table (EPT). Average cycles per walk can be calculated by dividing by the number of walks.",
+        "EventCode": "0x49",
+        "Counter": "0,1,2,3",
+        "UMask": "0x10",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "DTLB_STORE_MISSES.WALK_PENDING",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Page walks outstanding due to a demand data store every cycle."
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts once per cycle for each page walk only while traversing the Extended Page Table (EPT), and does not count during the rest of the translation.  The EPT is used for translating Guest-Physical Addresses to Physical Addresses for Virtual Machine Monitors (VMMs).  Average cycles per walk can be calculated by dividing the count by number of walks.",
+        "EventCode": "0x4F",
+        "Counter": "0,1,2,3",
+        "UMask": "0x10",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "EPT.WALK_PENDING",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Page walks outstanding due to walking the EPT every cycle"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts the number of times the machine was unable to find a translation in the Instruction Translation Lookaside Buffer (ITLB) for a linear address of an instruction fetch.  It counts when new translation are filled into the ITLB.  The event is speculative in nature, but will not count translations (page walks) that are begun and not finished, or translations that are finished but not filled into the ITLB.",
+        "EventCode": "0x81",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ITLB.MISS",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "ITLB misses"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to instruction fetches whose address translations missed in the TLB and were mapped to 4K pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x85",
+        "Counter": "0,1,2,3",
+        "UMask": "0x2",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ITLB_MISSES.WALK_COMPLETED_4K",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Page walk completed due to an instruction fetch in a 4K page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to instruction fetches whose address translations missed in the TLB and were mapped to 2M or 4M pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x85",
+        "Counter": "0,1,2,3",
+        "UMask": "0x4",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ITLB_MISSES.WALK_COMPLETED_2M_4M",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Page walk completed due to an instruction fetch in a 2M or 4M page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts page walks completed due to instruction fetches whose address translations missed in the TLB and were mapped to 1GB pages.  The page walks can end with or without a page fault.",
+        "EventCode": "0x85",
+        "Counter": "0,1,2,3",
+        "UMask": "0x8",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ITLB_MISSES.WALK_COMPLETED_1GB",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "2000003",
+        "BriefDescription": "Page walk completed due to an instruction fetch in a 1GB page"
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts once per cycle for each page walk occurring due to an instruction fetch. Includes cycles spent traversing the Extended Page Table (EPT). Average cycles per walk can be calculated by dividing by the number of walks.",
+        "EventCode": "0x85",
+        "Counter": "0,1,2,3",
+        "UMask": "0x10",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "ITLB_MISSES.WALK_PENDING",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Page walks outstanding due to an instruction fetch every cycle."
+    },
+    {
+        "CollectPEBSRecord": "1",
+        "PublicDescription": "Counts STLB flushes.  The TLBs are flushed on instructions like INVLPG and MOV to CR3.",
+        "EventCode": "0xBD",
+        "Counter": "0,1,2,3",
+        "UMask": "0x20",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "TLB_FLUSHES.STLB_ANY",
+        "PDIR_COUNTER": "na",
+        "SampleAfterValue": "20003",
+        "BriefDescription": "STLB flushes"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts load uops retired that caused a DTLB miss.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x11",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.DTLB_MISS_LOADS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Load uops retired that missed the DTLB (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts store uops retired that caused a DTLB miss.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x12",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.DTLB_MISS_STORES",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Store uops retired that missed the DTLB (Precise event capable)"
+    },
+    {
+        "PEBS": "2",
+        "CollectPEBSRecord": "2",
+        "PublicDescription": "Counts uops retired that had a DTLB miss on load, store or either.  Note that when two distinct memory operations to the same page miss the DTLB, only one of them will be recorded as a DTLB miss.",
+        "EventCode": "0xD0",
+        "Counter": "0,1,2,3",
+        "UMask": "0x13",
+        "PEBScounters": "0,1,2,3",
+        "EventName": "MEM_UOPS_RETIRED.DTLB_MISS",
+        "SampleAfterValue": "200003",
+        "BriefDescription": "Memory uops retired that missed the DTLB (Precise event capable)"
+    }
+]
\ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json b/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json
new file mode 100644 (file)
index 0000000..5ab5c78
--- /dev/null
@@ -0,0 +1,158 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , IDQ.MITE_UOPS / ( (UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 16 * ( ICACHE.HIT + ICACHE.MISSES ) / 4.0 ) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "( UOPS_EXECUTED.CORE / 2 / (( cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2) if #SMT_on else cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@) ) if #SMT_on else UOPS_EXECUTED.CORE / (( cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2) if #SMT_on else cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+        "MetricExpr": "2* (( RS_EVENTS.EMPTY_CYCLES - ICACHE.IFDATA_STALL  - (( 14 * ITLB_MISSES.STLB_HIT + ITLB_MISSES.WALK_DURATION )) ) / RS_EVENTS.EMPTY_END)",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_UOPS_RETIRED.L1_MISS + mem_load_uops_retired.hit_lfb )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / (( cpu@l1d_pend_miss.pending_cycles\\,any\\=1@ / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES)",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+        "MetricExpr": "( ITLB_MISSES.WALK_DURATION + DTLB_LOAD_MISSES.WALK_DURATION + DTLB_STORE_MISSES.WALK_DURATION ) / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json b/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json
new file mode 100644 (file)
index 0000000..5ab5c78
--- /dev/null
@@ -0,0 +1,158 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , IDQ.MITE_UOPS / ( (UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 16 * ( ICACHE.HIT + ICACHE.MISSES ) / 4.0 ) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "( UOPS_EXECUTED.CORE / 2 / (( cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2) if #SMT_on else cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@) ) if #SMT_on else UOPS_EXECUTED.CORE / (( cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2) if #SMT_on else cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+        "MetricExpr": "2* (( RS_EVENTS.EMPTY_CYCLES - ICACHE.IFDATA_STALL  - (( 14 * ITLB_MISSES.STLB_HIT + ITLB_MISSES.WALK_DURATION )) ) / RS_EVENTS.EMPTY_END)",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_UOPS_RETIRED.L1_MISS + mem_load_uops_retired.hit_lfb )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / (( cpu@l1d_pend_miss.pending_cycles\\,any\\=1@ / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES)",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+        "MetricExpr": "( ITLB_MISSES.WALK_DURATION + DTLB_LOAD_MISSES.WALK_DURATION + DTLB_STORE_MISSES.WALK_DURATION ) / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json b/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json
new file mode 100644 (file)
index 0000000..7c26795
--- /dev/null
@@ -0,0 +1,164 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , UOPS_ISSUED.ANY / ( (UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 32 * ( ICACHE.HIT + ICACHE.MISSES ) / 4) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_EXECUTED.THREAD / (( cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2) if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+        "MetricExpr": "2* (( RS_EVENTS.EMPTY_CYCLES - ICACHE.IFETCH_STALL ) / RS_EVENTS.EMPTY_END)",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_UOPS_RETIRED.L1_MISS + mem_load_uops_retired.hit_lfb )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / (( cpu@l1d_pend_miss.pending_cycles\\,any\\=1@ / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES)",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+        "MetricExpr": "( ITLB_MISSES.WALK_DURATION + DTLB_LOAD_MISSES.WALK_DURATION + DTLB_STORE_MISSES.WALK_DURATION ) / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "(( 1*( FP_COMP_OPS_EXE.SSE_SCALAR_SINGLE + FP_COMP_OPS_EXE.SSE_SCALAR_DOUBLE ) + 2* FP_COMP_OPS_EXE.SSE_PACKED_DOUBLE + 4*( FP_COMP_OPS_EXE.SSE_PACKED_SINGLE + SIMD_FP_256.PACKED_DOUBLE ) + 8* SIMD_FP_256.PACKED_SINGLE )) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json b/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json
new file mode 100644 (file)
index 0000000..7c26795
--- /dev/null
@@ -0,0 +1,164 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , UOPS_ISSUED.ANY / ( (UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 32 * ( ICACHE.HIT + ICACHE.MISSES ) / 4) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_EXECUTED.THREAD / (( cpu@UOPS_EXECUTED.CORE\\,cmask\\=1@ / 2) if #SMT_on else UOPS_EXECUTED.CYCLES_GE_1_UOP_EXEC)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+        "MetricExpr": "2* (( RS_EVENTS.EMPTY_CYCLES - ICACHE.IFETCH_STALL ) / RS_EVENTS.EMPTY_END)",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_UOPS_RETIRED.L1_MISS + mem_load_uops_retired.hit_lfb )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / (( cpu@l1d_pend_miss.pending_cycles\\,any\\=1@ / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES)",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+        "MetricExpr": "( ITLB_MISSES.WALK_DURATION + DTLB_LOAD_MISSES.WALK_DURATION + DTLB_STORE_MISSES.WALK_DURATION ) / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "(( 1*( FP_COMP_OPS_EXE.SSE_SCALAR_SINGLE + FP_COMP_OPS_EXE.SSE_SCALAR_DOUBLE ) + 2* FP_COMP_OPS_EXE.SSE_PACKED_DOUBLE + 4*( FP_COMP_OPS_EXE.SSE_PACKED_SINGLE + SIMD_FP_256.PACKED_DOUBLE ) + 8* SIMD_FP_256.PACKED_SINGLE )) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json b/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json
new file mode 100644 (file)
index 0000000..fd7d7c4
--- /dev/null
@@ -0,0 +1,140 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , UOPS_ISSUED.ANY / ( (UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 32 * ( ICACHE.HIT + ICACHE.MISSES ) / 4) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_DISPATCHED.THREAD / (( cpu@UOPS_DISPATCHED.CORE\\,cmask\\=1@ / 2) if #SMT_on else cpu@UOPS_DISPATCHED.CORE\\,cmask\\=1@)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "(( 1*( FP_COMP_OPS_EXE.SSE_SCALAR_SINGLE + FP_COMP_OPS_EXE.SSE_SCALAR_DOUBLE ) + 2* FP_COMP_OPS_EXE.SSE_PACKED_DOUBLE + 4*( FP_COMP_OPS_EXE.SSE_PACKED_SINGLE + SIMD_FP_256.PACKED_DOUBLE ) + 8* SIMD_FP_256.PACKED_SINGLE )) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
index 4ea068366c3e8e7a9d88a518b8a26d8a39141b08..fe1a2c47cabf22d9dcbb28cc1718911dd1fb88cb 100644 (file)
@@ -9,6 +9,7 @@ GenuineIntel-6-27,v4,bonnell,core
 GenuineIntel-6-36,v4,bonnell,core
 GenuineIntel-6-35,v4,bonnell,core
 GenuineIntel-6-5C,v8,goldmont,core
+GenuineIntel-6-7A,v1,goldmontplus,core
 GenuineIntel-6-3C,v24,haswell,core
 GenuineIntel-6-45,v24,haswell,core
 GenuineIntel-6-46,v24,haswell,core
diff --git a/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json b/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json
new file mode 100644 (file)
index 0000000..fd7d7c4
--- /dev/null
@@ -0,0 +1,140 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , UOPS_ISSUED.ANY / ( (UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 32 * ( ICACHE.HIT + ICACHE.MISSES ) / 4) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_DISPATCHED.THREAD / (( cpu@UOPS_DISPATCHED.CORE\\,cmask\\=1@ / 2) if #SMT_on else cpu@UOPS_DISPATCHED.CORE\\,cmask\\=1@)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "(( 1*( FP_COMP_OPS_EXE.SSE_SCALAR_SINGLE + FP_COMP_OPS_EXE.SSE_SCALAR_DOUBLE ) + 2* FP_COMP_OPS_EXE.SSE_PACKED_DOUBLE + 4*( FP_COMP_OPS_EXE.SSE_PACKED_SINGLE + SIMD_FP_256.PACKED_DOUBLE ) + 8* SIMD_FP_256.PACKED_SINGLE )) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json b/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json
new file mode 100644 (file)
index 0000000..36c903f
--- /dev/null
@@ -0,0 +1,164 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , UOPS_ISSUED.ANY / ((UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 64 * ( ICACHE_64B.IFTAG_HIT + ICACHE_64B.IFTAG_MISS ) / 4.1) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_EXECUTED.THREAD / (( UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2) if #SMT_on else UOPS_EXECUTED.CORE_CYCLES_GE_1)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+        "MetricExpr": "2* (( RS_EVENTS.EMPTY_CYCLES - ICACHE_16B.IFDATA_STALL  - ICACHE_64B.IFTAG_STALL ) / RS_EVENTS.EMPTY_END)",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_RETIRED.L1_MISS_PS + MEM_LOAD_RETIRED.FB_HIT_PS )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / (( L1D_PEND_MISS.PENDING_CYCLES_ANY / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES)",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+        "MetricExpr": "( ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_PENDING + DTLB_STORE_MISSES.WALK_PENDING + EPT.WALK_PENDING ) / ( 2 * (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles) )",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "(( 1*( FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_ARITH_INST_RETIRED.SCALAR_DOUBLE ) + 2* FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4*( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE ) + 8* FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE )) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
diff --git a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json
new file mode 100644 (file)
index 0000000..36c903f
--- /dev/null
@@ -0,0 +1,164 @@
+[
+    {
+        "BriefDescription": "Instructions Per Cycle (per logical thread)",
+        "MetricExpr": "INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "IPC"
+    },
+    {
+        "BriefDescription": "Uops Per Instruction",
+        "MetricExpr": "UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY",
+        "MetricGroup": "Pipeline",
+        "MetricName": "UPI"
+    },
+    {
+        "BriefDescription": "Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions",
+        "MetricExpr": "min( 1 , UOPS_ISSUED.ANY / ((UOPS_RETIRED.RETIRE_SLOTS / INST_RETIRED.ANY) * 64 * ( ICACHE_64B.IFTAG_HIT + ICACHE_64B.IFTAG_MISS ) / 4.1) )",
+        "MetricGroup": "Frontend",
+        "MetricName": "IFetch_Line_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)",
+        "MetricExpr": "IDQ.DSB_UOPS / ( IDQ.DSB_UOPS + LSD.UOPS + IDQ.MITE_UOPS + IDQ.MS_UOPS )",
+        "MetricGroup": "DSB; Frontend_Bandwidth",
+        "MetricName": "DSB_Coverage"
+    },
+    {
+        "BriefDescription": "Cycles Per Instruction (threaded)",
+        "MetricExpr": "1 / (INST_RETIRED.ANY / cycles)",
+        "MetricGroup": "Pipeline;Summary",
+        "MetricName": "CPI"
+    },
+    {
+        "BriefDescription": "Per-thread actual clocks when the logical processor is active. This is called 'Clockticks' in VTune.",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "Summary",
+        "MetricName": "CLKS"
+    },
+    {
+        "BriefDescription": "Total issue-pipeline slots",
+        "MetricExpr": "4*(( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "TopDownL1",
+        "MetricName": "SLOTS"
+    },
+    {
+        "BriefDescription": "Total number of retired Instructions",
+        "MetricExpr": "INST_RETIRED.ANY",
+        "MetricGroup": "Summary",
+        "MetricName": "Instructions"
+    },
+    {
+        "BriefDescription": "Instructions Per Cycle (per physical core)",
+        "MetricExpr": "INST_RETIRED.ANY / (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles)",
+        "MetricGroup": "SMT",
+        "MetricName": "CoreIPC"
+    },
+    {
+        "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is at least 1 uop executed)",
+        "MetricExpr": "UOPS_EXECUTED.THREAD / (( UOPS_EXECUTED.CORE_CYCLES_GE_1 / 2) if #SMT_on else UOPS_EXECUTED.CORE_CYCLES_GE_1)",
+        "MetricGroup": "Pipeline;Ports_Utilization",
+        "MetricName": "ILP"
+    },
+    {
+        "BriefDescription": "Average Branch Address Clear Cost (fraction of cycles)",
+        "MetricExpr": "2* (( RS_EVENTS.EMPTY_CYCLES - ICACHE_16B.IFDATA_STALL  - ICACHE_64B.IFTAG_STALL ) / RS_EVENTS.EMPTY_END)",
+        "MetricGroup": "Unknown_Branches",
+        "MetricName": "BAClear_Cost"
+    },
+    {
+        "BriefDescription": "Core actual clocks when any thread is active on the physical core",
+        "MetricExpr": "( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else CPU_CLK_UNHALTED.THREAD",
+        "MetricGroup": "SMT",
+        "MetricName": "CORE_CLKS"
+    },
+    {
+        "BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_RETIRED.L1_MISS_PS + MEM_LOAD_RETIRED.FB_HIT_PS )",
+        "MetricGroup": "Memory_Bound;Memory_Lat",
+        "MetricName": "Load_Miss_Real_Latency"
+    },
+    {
+        "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)",
+        "MetricExpr": "L1D_PEND_MISS.PENDING / (( L1D_PEND_MISS.PENDING_CYCLES_ANY / 2) if #SMT_on else L1D_PEND_MISS.PENDING_CYCLES)",
+        "MetricGroup": "Memory_Bound;Memory_BW",
+        "MetricName": "MLP"
+    },
+    {
+        "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
+        "MetricExpr": "( ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_PENDING + DTLB_STORE_MISSES.WALK_PENDING + EPT.WALK_PENDING ) / ( 2 * (( CPU_CLK_UNHALTED.THREAD_ANY / 2 ) if #SMT_on else cycles) )",
+        "MetricGroup": "TLB",
+        "MetricName": "Page_Walks_Utilization"
+    },
+    {
+        "BriefDescription": "Average CPU Utilization",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / msr@tsc@",
+        "MetricGroup": "Summary",
+        "MetricName": "CPU_Utilization"
+    },
+    {
+        "BriefDescription": "Giga Floating Point Operations Per Second",
+        "MetricExpr": "(( 1*( FP_ARITH_INST_RETIRED.SCALAR_SINGLE + FP_ARITH_INST_RETIRED.SCALAR_DOUBLE ) + 2* FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4*( FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE + FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE ) + 8* FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE )) / 1000000000 / duration_time",
+        "MetricGroup": "FLOPS;Summary",
+        "MetricName": "GFLOPs"
+    },
+    {
+        "BriefDescription": "Average Frequency Utilization relative nominal frequency",
+        "MetricExpr": "CPU_CLK_UNHALTED.THREAD / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Power",
+        "MetricName": "Turbo_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles where both hardware threads were active",
+        "MetricExpr": "1 - CPU_CLK_THREAD_UNHALTED.ONE_THREAD_ACTIVE / ( CPU_CLK_THREAD_UNHALTED.REF_XCLK_ANY / 2 ) if #SMT_on else 0",
+        "MetricGroup": "SMT;Summary",
+        "MetricName": "SMT_2T_Utilization"
+    },
+    {
+        "BriefDescription": "Fraction of cycles spent in Kernel mode",
+        "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC",
+        "MetricGroup": "Summary",
+        "MetricName": "Kernel_Utilization"
+    },
+    {
+        "BriefDescription": "C3 residency percent per core",
+        "MetricExpr": "(cstate_core@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Core_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per core",
+        "MetricExpr": "(cstate_core@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Core_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per core",
+        "MetricExpr": "(cstate_core@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Core_Residency"
+    },
+    {
+        "BriefDescription": "C2 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C2_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C3 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c3\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C3_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C6 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C6_Pkg_Residency"
+    },
+    {
+        "BriefDescription": "C7 residency percent per package",
+        "MetricExpr": "(cstate_pkg@c7\\-residency@ / msr@tsc@) * 100",
+        "MetricGroup": "Power",
+        "MetricName": "C7_Pkg_Residency"
+    }
+]
index d51dc9ca8861ab194c1b15287e63cc93f4c19477..9eb7047bafe471277fa25cf9022057bddfcae31c 100644 (file)
@@ -292,7 +292,7 @@ static int print_events_table_entry(void *data, char *name, char *event,
                                    char *desc, char *long_desc,
                                    char *pmu, char *unit, char *perpkg,
                                    char *metric_expr,
-                                   char *metric_name)
+                                   char *metric_name, char *metric_group)
 {
        struct perf_entry_data *pd = data;
        FILE *outfp = pd->outfp;
@@ -304,8 +304,10 @@ static int print_events_table_entry(void *data, char *name, char *event,
         */
        fprintf(outfp, "{\n");
 
-       fprintf(outfp, "\t.name = \"%s\",\n", name);
-       fprintf(outfp, "\t.event = \"%s\",\n", event);
+       if (name)
+               fprintf(outfp, "\t.name = \"%s\",\n", name);
+       if (event)
+               fprintf(outfp, "\t.event = \"%s\",\n", event);
        fprintf(outfp, "\t.desc = \"%s\",\n", desc);
        fprintf(outfp, "\t.topic = \"%s\",\n", topic);
        if (long_desc && long_desc[0])
@@ -320,6 +322,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
                fprintf(outfp, "\t.metric_expr = \"%s\",\n", metric_expr);
        if (metric_name)
                fprintf(outfp, "\t.metric_name = \"%s\",\n", metric_name);
+       if (metric_group)
+               fprintf(outfp, "\t.metric_group = \"%s\",\n", metric_group);
        fprintf(outfp, "},\n");
 
        return 0;
@@ -357,6 +361,9 @@ static char *real_event(const char *name, char *event)
 {
        int i;
 
+       if (!name)
+               return NULL;
+
        for (i = 0; fixed[i].name; i++)
                if (!strcasecmp(name, fixed[i].name))
                        return (char *)fixed[i].event;
@@ -369,7 +376,7 @@ int json_events(const char *fn,
                      char *long_desc,
                      char *pmu, char *unit, char *perpkg,
                      char *metric_expr,
-                     char *metric_name),
+                     char *metric_name, char *metric_group),
          void *data)
 {
        int err = -EIO;
@@ -397,6 +404,7 @@ int json_events(const char *fn,
                char *unit = NULL;
                char *metric_expr = NULL;
                char *metric_name = NULL;
+               char *metric_group = NULL;
                unsigned long long eventcode = 0;
                struct msrmap *msr = NULL;
                jsmntok_t *msrval = NULL;
@@ -476,6 +484,8 @@ int json_events(const char *fn,
                                addfield(map, &perpkg, "", "", val);
                        } else if (json_streq(map, field, "MetricName")) {
                                addfield(map, &metric_name, "", "", val);
+                       } else if (json_streq(map, field, "MetricGroup")) {
+                               addfield(map, &metric_group, "", "", val);
                        } else if (json_streq(map, field, "MetricExpr")) {
                                addfield(map, &metric_expr, "", "", val);
                                for (s = metric_expr; *s; s++)
@@ -501,10 +511,11 @@ int json_events(const char *fn,
                        addfield(map, &event, ",", filter, NULL);
                if (msr != NULL)
                        addfield(map, &event, ",", msr->pname, msrval);
-               fixname(name);
+               if (name)
+                       fixname(name);
 
                err = func(data, name, real_event(name, event), desc, long_desc,
-                               pmu, unit, perpkg, metric_expr, metric_name);
+                          pmu, unit, perpkg, metric_expr, metric_name, metric_group);
                free(event);
                free(desc);
                free(name);
@@ -516,6 +527,7 @@ int json_events(const char *fn,
                free(unit);
                free(metric_expr);
                free(metric_name);
+               free(metric_group);
                if (err)
                        break;
                tok += j;
index d87efd2685b8cad889c6cd4f74ced45e19829c4b..4684c673c445798b956a1509b7a84735d89ceaf7 100644 (file)
@@ -7,7 +7,7 @@ int json_events(const char *fn,
                                char *long_desc,
                                char *pmu,
                                char *unit, char *perpkg, char *metric_expr,
-                               char *metric_name),
+                               char *metric_name, char *metric_group),
                void *data);
 char *get_cpu_str(void);
 
index e08789ddfe6cdbb883fa2821e1dfa7eb8c743903..92a4d15ee0b9d8ad8d2adb7fb6422fc98ebbfc5c 100644 (file)
@@ -16,6 +16,7 @@ struct pmu_event {
        const char *perpkg;
        const char *metric_expr;
        const char *metric_name;
+       const char *metric_group;
 };
 
 /*
index c180bbcdbef60239177384608cbf48ce33c270cf..0e1367f90af5355576a49e3693474f91686b5a7c 100644 (file)
@@ -167,7 +167,7 @@ static int run_dir(const char *d, const char *perf)
        snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s",
                 d, d, perf, vcnt, v);
 
-       return system(cmd);
+       return system(cmd) ? TEST_FAIL : TEST_OK;
 }
 
 int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused)
index 907b1b2f56ad45672d8d304075a68fad8b9bddaf..ff9b60b99f52a9bb834f85fc2e296a4d897bf9ae 100644 (file)
@@ -238,6 +238,7 @@ class Test(object):
         # events in result. Fail if there's not any.
         for exp_name, exp_event in expect.items():
             exp_list = []
+            res_event = {}
             log.debug("    matching [%s]" % exp_name)
             for res_name, res_event in result.items():
                 log.debug("      to [%s]" % res_name)
@@ -254,7 +255,10 @@ class Test(object):
                 if exp_event.optional():
                     log.debug("    %s does not match, but is optional" % exp_name)
                 else:
-                    exp_event.diff(res_event)
+                    if not res_event:
+                        log.debug("    res_event is empty");
+                    else:
+                        exp_event.diff(res_event)
                     raise Fail(self, 'match failure');
 
             match[exp_name] = exp_list
index 31e0b1da830b87f243509448f3c1e26f00c2c669..37940665f736c7850a61fcaa107a4bdd228a7668 100644 (file)
@@ -23,7 +23,7 @@ comm=1
 freq=1
 inherit_stat=0
 enable_on_exec=1
-task=0
+task=1
 watermark=0
 precise_ip=0|1|2|3
 mmap_data=0
index 6e7961f6f7a570ae7ddb6c06e5f3981ea558430b..618ba1c174741c46ea730297383d8a67574be252 100644 (file)
@@ -17,5 +17,6 @@ sample_type=327
 read_format=4
 mmap=0
 comm=0
+task=0
 enable_on_exec=0
 disabled=0
index ef59afd6d6356b62d51470c3232fcee68864013a..f906b793196fc7594a96f795617bdbb73ae42639 100644 (file)
@@ -23,7 +23,7 @@ sample_type=343
 
 # PERF_FORMAT_ID | PERF_FORMAT_GROUP
 read_format=12
-
+task=0
 mmap=0
 comm=0
 enable_on_exec=0
index 87a222d014d8392843bfc56afafb11fe015e9a78..48e8bd12fe4676f166cf74c512f1ec52d9ae93d6 100644 (file)
@@ -18,5 +18,6 @@ sample_type=327
 read_format=4
 mmap=0
 comm=0
+task=0
 enable_on_exec=0
 disabled=0
index 67717fe6a65d44e66cc5407dc3c709d32ae82d8e..a2c76d10b2bb2a1553320b8ea6714ae8ee6e5fa2 100644 (file)
@@ -7,3 +7,4 @@ ret     = 1
 # events are disabled by default when attached to cpu
 disabled=1
 enable_on_exec=0
+optional=1
index 74e17881f2ba55da4cef2cb402942c7a7fc76c89..69867d049fda926ff7b29682c468d42ffca55247 100644 (file)
@@ -4,3 +4,4 @@ args    = -e cycles kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-stat]
+optional=1
index e911dbd4eb47eb9b1be00e9d14bebab763efb5d0..d9e99b3f77e66e707cca6c8e115120b0105c84b3 100644 (file)
@@ -32,6 +32,7 @@ config=2
 fd=5
 type=0
 config=0
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
 [event6:base-stat]
@@ -52,15 +53,18 @@ optional=1
 fd=8
 type=0
 config=1
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
 [event9:base-stat]
 fd=9
 type=0
 config=4
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
 [event10:base-stat]
 fd=10
 type=0
 config=5
+optional=1
index b39270a08e740a58f5ae2e9fbfdcd5658942502a..8b04a055d1548d03a84c53ad719e249eeb807197 100644 (file)
@@ -33,6 +33,7 @@ config=2
 fd=5
 type=0
 config=0
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
 [event6:base-stat]
@@ -53,18 +54,21 @@ optional=1
 fd=8
 type=0
 config=1
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
 [event9:base-stat]
 fd=9
 type=0
 config=4
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
 [event10:base-stat]
 fd=10
 type=0
 config=5
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_L1D                <<  0  |
@@ -74,6 +78,7 @@ config=5
 fd=11
 type=3
 config=0
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_L1D                <<  0  |
@@ -83,6 +88,7 @@ config=0
 fd=12
 type=3
 config=65536
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_LL                 <<  0  |
@@ -92,6 +98,7 @@ config=65536
 fd=13
 type=3
 config=2
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_LL                 <<  0  |
@@ -101,3 +108,4 @@ config=2
 fd=14
 type=3
 config=65538
+optional=1
index 45f8e6ea34f817819d5fd71ae9b05e661425e8cb..4fca9f1bfbf8d36932b814d70750c6e826c9cc05 100644 (file)
@@ -33,6 +33,7 @@ config=2
 fd=5
 type=0
 config=0
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
 [event6:base-stat]
@@ -53,18 +54,21 @@ optional=1
 fd=8
 type=0
 config=1
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
 [event9:base-stat]
 fd=9
 type=0
 config=4
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
 [event10:base-stat]
 fd=10
 type=0
 config=5
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_L1D                <<  0  |
@@ -74,6 +78,7 @@ config=5
 fd=11
 type=3
 config=0
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_L1D                <<  0  |
@@ -83,6 +88,7 @@ config=0
 fd=12
 type=3
 config=65536
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_LL                 <<  0  |
@@ -92,6 +98,7 @@ config=65536
 fd=13
 type=3
 config=2
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_LL                 <<  0  |
@@ -101,6 +108,7 @@ config=2
 fd=14
 type=3
 config=65538
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_L1I                <<  0  |
@@ -120,6 +128,7 @@ optional=1
 fd=16
 type=3
 config=65537
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_DTLB               <<  0  |
@@ -129,6 +138,7 @@ config=65537
 fd=17
 type=3
 config=3
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_DTLB               <<  0  |
@@ -138,6 +148,7 @@ config=3
 fd=18
 type=3
 config=65539
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_ITLB               <<  0  |
@@ -147,6 +158,7 @@ config=65539
 fd=19
 type=3
 config=4
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_ITLB               <<  0  |
@@ -156,3 +168,4 @@ config=4
 fd=20
 type=3
 config=65540
+optional=1
index 30ae0fb7a3fdb12c549050c4985b70c8b885e4ea..4bb58e1c82a676c7b5b7c7ab411f6d93f424864e 100644 (file)
@@ -33,6 +33,7 @@ config=2
 fd=5
 type=0
 config=0
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
 [event6:base-stat]
@@ -53,18 +54,21 @@ optional=1
 fd=8
 type=0
 config=1
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
 [event9:base-stat]
 fd=9
 type=0
 config=4
+optional=1
 
 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
 [event10:base-stat]
 fd=10
 type=0
 config=5
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_L1D                <<  0  |
@@ -74,6 +78,7 @@ config=5
 fd=11
 type=3
 config=0
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_L1D                <<  0  |
@@ -83,6 +88,7 @@ config=0
 fd=12
 type=3
 config=65536
+optional=1
 
 # PERF_TYPE_HW_CACHE /
 #  PERF_COUNT_HW_CACHE_LL                 <<  0  |
@@ -92,6 +98,7 @@ config=65536
 fd=13
 type=3
 config=2
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_LL                 <<  0  |
@@ -101,6 +108,7 @@ config=2
 fd=14
 type=3
 config=65538
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_L1I                <<  0  |
@@ -120,6 +128,7 @@ optional=1
 fd=16
 type=3
 config=65537
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_DTLB               <<  0  |
@@ -129,6 +138,7 @@ config=65537
 fd=17
 type=3
 config=3
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_DTLB               <<  0  |
@@ -138,6 +148,7 @@ config=3
 fd=18
 type=3
 config=65539
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_ITLB               <<  0  |
@@ -147,6 +158,7 @@ config=65539
 fd=19
 type=3
 config=4
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_ITLB               <<  0  |
@@ -156,6 +168,7 @@ config=4
 fd=20
 type=3
 config=65540
+optional=1
 
 # PERF_TYPE_HW_CACHE,
 #  PERF_COUNT_HW_CACHE_L1D                <<  0  |
index fdc1596a88626c7630378aa1b46f702319a4a08e..e15d6946e9b3a72381a0f8d0d1b0e22a619ff4ac 100644 (file)
@@ -6,6 +6,7 @@ ret     = 1
 [event-1:base-stat]
 fd=1
 group_fd=-1
+read_format=3|15
 
 [event-2:base-stat]
 fd=2
@@ -13,3 +14,4 @@ group_fd=1
 config=1
 disabled=0
 enable_on_exec=0
+read_format=3|15
index 2a1f86e4a904c67f0d271fb729c7e4464efaae34..1746751123dcb2c473456dda415423b58ad48054 100644 (file)
@@ -6,6 +6,7 @@ ret     = 1
 [event-1:base-stat]
 fd=1
 group_fd=-1
+read_format=3|15
 
 [event-2:base-stat]
 fd=2
@@ -13,3 +14,4 @@ group_fd=1
 config=1
 disabled=0
 enable_on_exec=0
+read_format=3|15
index d54b2a1e3e2822263b4be5ca99558b17dd369018..924fbb9300d162599cb1e20a6e349afba55d7309 100644 (file)
@@ -5,3 +5,4 @@ ret     = 1
 
 [event:base-stat]
 inherit=0
+optional=1
index 53d06f37406a22526638b3a9e58643caca736fba..766573e236e4582a3b2df2031374ddd17058dcf2 100644 (file)
@@ -4,6 +4,7 @@
  *
  * Builtin regression testing command: ever growing number of sanity tests
  */
+#include <fcntl.h>
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
index 3c3f3e029e33bd77cb5b2d7284b6e3cb01735237..868d82b501f4241addc27a2a0aaa6fe11bd1fb6f 100644 (file)
@@ -132,7 +132,7 @@ static int synth_all(struct machine *machine)
 {
        return perf_event__synthesize_threads(NULL,
                                              perf_event__process,
-                                             machine, 0, 500);
+                                             machine, 0, 500, 1);
 }
 
 static int synth_process(struct machine *machine)
index a59db7c45a65b2258b90b446d65885fff53e7f6d..17cb1bb3448c842930df519d1bad7077777a098d 100644 (file)
@@ -30,12 +30,14 @@ static int get_temp(char *path)
 static int session_write_header(char *path)
 {
        struct perf_session *session;
-       struct perf_data_file file = {
-               .path = path,
-               .mode = PERF_DATA_MODE_WRITE,
+       struct perf_data data = {
+               .file      = {
+                       .path = path,
+               },
+               .mode      = PERF_DATA_MODE_WRITE,
        };
 
-       session = perf_session__new(&file, false, NULL);
+       session = perf_session__new(&data, false, NULL);
        TEST_ASSERT_VAL("can't get session", session);
 
        session->evlist = perf_evlist__new_default();
@@ -47,7 +49,7 @@ static int session_write_header(char *path)
        session->header.data_size += DATA_SIZE;
 
        TEST_ASSERT_VAL("failed to write header",
-                       !perf_session__write_header(session, session->evlist, file.fd, true));
+                       !perf_session__write_header(session, session->evlist, data.file.fd, true));
 
        perf_session__delete(session);
 
@@ -57,13 +59,15 @@ static int session_write_header(char *path)
 static int check_cpu_topology(char *path, struct cpu_map *map)
 {
        struct perf_session *session;
-       struct perf_data_file file = {
-               .path = path,
-               .mode = PERF_DATA_MODE_READ,
+       struct perf_data data = {
+               .file      = {
+                       .path = path,
+               },
+               .mode      = PERF_DATA_MODE_READ,
        };
        int i;
 
-       session = perf_session__new(&file, false, NULL);
+       session = perf_session__new(&data, false, NULL);
        TEST_ASSERT_VAL("can't get session", session);
 
        for (i = 0; i < session->header.env.nr_cpus_avail; i++) {
index 175d633c6b491e5beb5257c02bdd36894268b74b..066bbf0f4a744b6949d5bb5a5dd220602919b801 100644 (file)
@@ -3,5 +3,7 @@ libperf-y += fcntl.o
 ifeq ($(SRCARCH),$(filter $(SRCARCH),x86))
 libperf-y += ioctl.o
 endif
+libperf-y += kcmp.o
 libperf-y += pkey_alloc.o
+libperf-y += prctl.o
 libperf-y += statx.o
index d80655cd18815d1de61b52c143630a5c4e175173..a6dfd04beaee1124a851ba7d2be4dca4e14c189f 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <sys/types.h>
 
 struct strarray {
        int         offset;
@@ -27,6 +28,8 @@ size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const cha
 struct trace;
 struct thread;
 
+size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size);
+
 /**
  * @val: value of syscall argument being formatted
  * @args: All the args, use syscall_args__val(arg, nth) to access one
@@ -79,12 +82,27 @@ size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_ar
 size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg);
 #define SCA_IOCTL_CMD syscall_arg__scnprintf_ioctl_cmd
 
+size_t syscall_arg__scnprintf_kcmp_type(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_KCMP_TYPE syscall_arg__scnprintf_kcmp_type
+
+size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_KCMP_IDX syscall_arg__scnprintf_kcmp_idx
+
 size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg);
 #define SCA_PKEY_ALLOC_ACCESS_RIGHTS syscall_arg__scnprintf_pkey_alloc_access_rights
 
 size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, struct syscall_arg *arg);
 #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
 
+size_t syscall_arg__scnprintf_prctl_option(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_PRCTL_OPTION syscall_arg__scnprintf_prctl_option
+
+size_t syscall_arg__scnprintf_prctl_arg2(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_PRCTL_ARG2 syscall_arg__scnprintf_prctl_arg2
+
+size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_PRCTL_ARG3 syscall_arg__scnprintf_prctl_arg3
+
 size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg);
 #define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags
 
diff --git a/tools/perf/trace/beauty/kcmp.c b/tools/perf/trace/beauty/kcmp.c
new file mode 100644 (file)
index 0000000..f62040e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * trace/beauty/kcmp.c
+ *
+ *  Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include "trace/beauty/beauty.h"
+#include <linux/kernel.h>
+#include <sys/types.h>
+#include <machine.h>
+#include <uapi/linux/kcmp.h>
+
+#include "trace/beauty/generated/kcmp_type_array.c"
+
+size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg)
+{
+       unsigned long fd = arg->val;
+       int type = syscall_arg__val(arg, 2);
+       pid_t pid;
+
+       if (type != KCMP_FILE)
+               return syscall_arg__scnprintf_long(bf, size, arg);
+
+       pid = syscall_arg__val(arg, arg->idx == 3 ? 0 : 1); /* idx1 -> pid1, idx2 -> pid2 */
+       return pid__scnprintf_fd(arg->trace, pid, fd, bf, size);
+}
+
+static size_t kcmp__scnprintf_type(int type, char *bf, size_t size)
+{
+       static DEFINE_STRARRAY(kcmp_types);
+       return strarray__scnprintf(&strarray__kcmp_types, bf, size, "%d", type);
+}
+
+size_t syscall_arg__scnprintf_kcmp_type(char *bf, size_t size, struct syscall_arg *arg)
+{
+       unsigned long type = arg->val;
+
+       if (type != KCMP_FILE)
+               arg->mask |= (1 << 3) | (1 << 4); /* Ignore idx1 and idx2 */
+
+       return kcmp__scnprintf_type(type, bf, size);
+}
diff --git a/tools/perf/trace/beauty/kcmp_type.sh b/tools/perf/trace/beauty/kcmp_type.sh
new file mode 100755 (executable)
index 0000000..40d063b
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+header_dir=$1
+
+printf "static const char *kcmp_types[] = {\n"
+regex='^[[:space:]]+(KCMP_(\w+)),'
+egrep $regex ${header_dir}/kcmp.h | grep -v KCMP_TYPES, | \
+       sed -r "s/$regex/\1 \2/g" | \
+       xargs printf "\t[%s]\t= \"%s\",\n"
+printf "};\n"
diff --git a/tools/perf/trace/beauty/madvise_behavior.sh b/tools/perf/trace/beauty/madvise_behavior.sh
new file mode 100755 (executable)
index 0000000..60ef864
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+header_dir=$1
+
+printf "static const char *madvise_advices[] = {\n"
+regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MADV_([[:alnum:]_]+)[[:space:]]+([[:digit:]]+)[[:space:]]*.*'
+egrep $regex ${header_dir}/mman-common.h | \
+       sed -r "s/$regex/\2 \1/g"       | \
+       sort -n | xargs printf "\t[%s] = \"%s\",\n"
+printf "};\n"
index 51f1cea406f5c69521778bc5ab363bde7937cb8b..9e1668b2c5d7cf86f25a5fa6453026a6768d2950 100644 (file)
@@ -95,35 +95,21 @@ static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
 
 #define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
 
+static size_t madvise__scnprintf_behavior(int behavior, char *bf, size_t size)
+{
+#include "trace/beauty/generated/madvise_behavior_array.c"
+       static DEFINE_STRARRAY(madvise_advices);
+
+       if (behavior < strarray__madvise_advices.nr_entries && strarray__madvise_advices.entries[behavior] != NULL)
+               return scnprintf(bf, size, "MADV_%s", strarray__madvise_advices.entries[behavior]);
+
+       return scnprintf(bf, size, "%#", behavior);
+}
+
 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
                                                      struct syscall_arg *arg)
 {
-       int behavior = arg->val;
-
-       switch (behavior) {
-#define        P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
-       P_MADV_BHV(NORMAL);
-       P_MADV_BHV(RANDOM);
-       P_MADV_BHV(SEQUENTIAL);
-       P_MADV_BHV(WILLNEED);
-       P_MADV_BHV(DONTNEED);
-       P_MADV_BHV(FREE);
-       P_MADV_BHV(REMOVE);
-       P_MADV_BHV(DONTFORK);
-       P_MADV_BHV(DOFORK);
-       P_MADV_BHV(HWPOISON);
-       P_MADV_BHV(SOFT_OFFLINE);
-       P_MADV_BHV(MERGEABLE);
-       P_MADV_BHV(UNMERGEABLE);
-       P_MADV_BHV(HUGEPAGE);
-       P_MADV_BHV(NOHUGEPAGE);
-       P_MADV_BHV(DONTDUMP);
-       P_MADV_BHV(DODUMP);
-#undef P_MADV_BHV
-       default: break;
-       }
-
-       return scnprintf(bf, size, "%#x", behavior);
+       return madvise__scnprintf_behavior(arg->val, bf, size);
 }
 
 #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
diff --git a/tools/perf/trace/beauty/prctl.c b/tools/perf/trace/beauty/prctl.c
new file mode 100644 (file)
index 0000000..246130d
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * trace/beauty/prctl.c
+ *
+ *  Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include "trace/beauty/beauty.h"
+#include <linux/kernel.h>
+#include <uapi/linux/prctl.h>
+
+#include "trace/beauty/generated/prctl_option_array.c"
+
+static size_t prctl__scnprintf_option(int option, char *bf, size_t size)
+{
+       static DEFINE_STRARRAY(prctl_options);
+       return strarray__scnprintf(&strarray__prctl_options, bf, size, "%d", option);
+}
+
+static size_t prctl__scnprintf_set_mm(int option, char *bf, size_t size)
+{
+       static DEFINE_STRARRAY(prctl_set_mm_options);
+       return strarray__scnprintf(&strarray__prctl_set_mm_options, bf, size, "%d", option);
+}
+
+size_t syscall_arg__scnprintf_prctl_arg2(char *bf, size_t size, struct syscall_arg *arg)
+{
+       int option = syscall_arg__val(arg, 0);
+
+       if (option == PR_SET_MM)
+               return prctl__scnprintf_set_mm(arg->val, bf, size);
+       /*
+        * We still don't grab the contents of pointers on entry or exit,
+        * so just print them as hex numbers
+        */
+       if (option == PR_SET_NAME)
+               return syscall_arg__scnprintf_hex(bf, size, arg);
+
+       return syscall_arg__scnprintf_long(bf, size, arg);
+}
+
+size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg)
+{
+       int option = syscall_arg__val(arg, 0);
+
+       if (option == PR_SET_MM)
+               return syscall_arg__scnprintf_hex(bf, size, arg);
+
+       return syscall_arg__scnprintf_long(bf, size, arg);
+}
+
+size_t syscall_arg__scnprintf_prctl_option(char *bf, size_t size, struct syscall_arg *arg)
+{
+       unsigned long option = arg->val;
+       enum {
+                SPO_ARG2 = (1 << 1),
+                SPO_ARG3 = (1 << 2),
+                SPO_ARG4 = (1 << 3),
+                SPO_ARG5 = (1 << 4),
+                SPO_ARG6 = (1 << 5),
+        };
+       const u8 all_but2 = SPO_ARG3 | SPO_ARG4 | SPO_ARG5 | SPO_ARG6;
+       const u8 all = SPO_ARG2 | all_but2;
+       const u8 masks[] = {
+               [PR_GET_DUMPABLE]        = all,
+               [PR_SET_DUMPABLE]        = all_but2,
+               [PR_SET_NAME]            = all_but2,
+               [PR_GET_CHILD_SUBREAPER] = all_but2,
+               [PR_SET_CHILD_SUBREAPER] = all_but2,
+               [PR_GET_SECUREBITS]      = all,
+               [PR_SET_SECUREBITS]      = all_but2,
+               [PR_SET_MM]              = SPO_ARG4 | SPO_ARG5 | SPO_ARG6,
+               [PR_GET_PDEATHSIG]       = all,
+               [PR_SET_PDEATHSIG]       = all_but2,
+       };
+
+       if (option < ARRAY_SIZE(masks))
+               arg->mask |= masks[option];
+
+       return prctl__scnprintf_option(option, bf, size);
+}
diff --git a/tools/perf/trace/beauty/prctl_option.sh b/tools/perf/trace/beauty/prctl_option.sh
new file mode 100755 (executable)
index 0000000..0be4138
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+header_dir=$1
+
+printf "static const char *prctl_options[] = {\n"
+regex='^#define[[:space:]]+PR_([GS]ET\w+)[[:space:]]*([[:xdigit:]]+).*'
+egrep $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \
+       sed -r "s/$regex/\2 \1/g"       | \
+       sort -n | xargs printf "\t[%s] = \"%s\",\n"
+printf "};\n"
+
+printf "static const char *prctl_set_mm_options[] = {\n"
+regex='^#[[:space:]]+define[[:space:]]+PR_SET_MM_(\w+)[[:space:]]*([[:digit:]]+).*'
+egrep $regex ${header_dir}/prctl.h | \
+       sed -r "s/$regex/\2 \1/g"       | \
+       sort -n | xargs printf "\t[%s] = \"%s\",\n"
+printf "};\n"
index 628ad5f7eddb6a4295ba9370f987e9194dfe6bed..68146f4620a5730028c24c364001ce5e21766aad 100644 (file)
@@ -155,57 +155,9 @@ static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
        cl->unfolded = unfold ? cl->has_children : false;
 }
 
-static struct inline_node *inline_node__create(struct map *map, u64 ip)
-{
-       struct dso *dso;
-       struct inline_node *node;
-
-       if (map == NULL)
-               return NULL;
-
-       dso = map->dso;
-       if (dso == NULL)
-               return NULL;
-
-       node = dso__parse_addr_inlines(dso,
-                                      map__rip_2objdump(map, ip));
-
-       return node;
-}
-
-static int inline__count_rows(struct inline_node *node)
-{
-       struct inline_list *ilist;
-       int i = 0;
-
-       if (node == NULL)
-               return 0;
-
-       list_for_each_entry(ilist, &node->val, list) {
-               if ((ilist->filename != NULL) || (ilist->funcname != NULL))
-                       i++;
-       }
-
-       return i;
-}
-
-static int callchain_list__inline_rows(struct callchain_list *chain)
-{
-       struct inline_node *node;
-       int rows;
-
-       node = inline_node__create(chain->ms.map, chain->ip);
-       if (node == NULL)
-               return 0;
-
-       rows = inline__count_rows(node);
-       inline_node__delete(node);
-       return rows;
-}
-
 static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
 {
-       int n = 0, inline_rows;
+       int n = 0;
        struct rb_node *nd;
 
        for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
@@ -216,12 +168,6 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
                list_for_each_entry(chain, &child->val, list) {
                        ++n;
 
-                       if (symbol_conf.inline_name) {
-                               inline_rows =
-                                       callchain_list__inline_rows(chain);
-                               n += inline_rows;
-                       }
-
                        /* We need this because we may not have children */
                        folded_sign = callchain_list__folded(chain);
                        if (folded_sign == '+')
@@ -273,7 +219,7 @@ static int callchain_node__count_rows(struct callchain_node *node)
 {
        struct callchain_list *chain;
        bool unfolded = false;
-       int n = 0, inline_rows;
+       int n = 0;
 
        if (callchain_param.mode == CHAIN_FLAT)
                return callchain_node__count_flat_rows(node);
@@ -282,10 +228,6 @@ static int callchain_node__count_rows(struct callchain_node *node)
 
        list_for_each_entry(chain, &node->val, list) {
                ++n;
-               if (symbol_conf.inline_name) {
-                       inline_rows = callchain_list__inline_rows(chain);
-                       n += inline_rows;
-               }
 
                unfolded = chain->unfolded;
        }
@@ -433,19 +375,6 @@ static void hist_entry__init_have_children(struct hist_entry *he)
        he->init_have_children = true;
 }
 
-static void hist_entry_init_inline_node(struct hist_entry *he)
-{
-       if (he->inline_node)
-               return;
-
-       he->inline_node = inline_node__create(he->ms.map, he->ip);
-
-       if (he->inline_node == NULL)
-               return;
-
-       he->has_children = true;
-}
-
 static bool hist_browser__toggle_fold(struct hist_browser *browser)
 {
        struct hist_entry *he = browser->he_selection;
@@ -477,12 +406,8 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
 
                if (he->unfolded) {
                        if (he->leaf)
-                               if (he->inline_node)
-                                       he->nr_rows = inline__count_rows(
-                                                       he->inline_node);
-                               else
-                                       he->nr_rows = callchain__count_rows(
-                                                       &he->sorted_chain);
+                               he->nr_rows = callchain__count_rows(
+                                               &he->sorted_chain);
                        else
                                he->nr_rows = hierarchy_count_rows(browser, he, false);
 
@@ -842,71 +767,6 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u
 
 #define LEVEL_OFFSET_STEP 3
 
-static int hist_browser__show_inline(struct hist_browser *browser,
-                                    struct inline_node *node,
-                                    unsigned short row,
-                                    int offset)
-{
-       struct inline_list *ilist;
-       char buf[1024];
-       int color, width, first_row;
-
-       first_row = row;
-       width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
-       list_for_each_entry(ilist, &node->val, list) {
-               if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
-                       color = HE_COLORSET_NORMAL;
-                       if (ui_browser__is_current_entry(&browser->b, row))
-                               color = HE_COLORSET_SELECTED;
-
-                       if (callchain_param.key == CCKEY_ADDRESS ||
-                           callchain_param.key == CCKEY_SRCLINE) {
-                               if (ilist->filename != NULL)
-                                       scnprintf(buf, sizeof(buf),
-                                                 "%s:%d (inline)",
-                                                 ilist->filename,
-                                                 ilist->line_nr);
-                               else
-                                       scnprintf(buf, sizeof(buf), "??");
-                       } else if (ilist->funcname != NULL)
-                               scnprintf(buf, sizeof(buf), "%s (inline)",
-                                         ilist->funcname);
-                       else if (ilist->filename != NULL)
-                               scnprintf(buf, sizeof(buf),
-                                         "%s:%d (inline)",
-                                         ilist->filename,
-                                         ilist->line_nr);
-                       else
-                               scnprintf(buf, sizeof(buf), "??");
-
-                       ui_browser__set_color(&browser->b, color);
-                       hist_browser__gotorc(browser, row, 0);
-                       ui_browser__write_nstring(&browser->b, " ",
-                               LEVEL_OFFSET_STEP + offset);
-                       ui_browser__write_nstring(&browser->b, buf, width);
-                       row++;
-               }
-       }
-
-       return row - first_row;
-}
-
-static size_t show_inline_list(struct hist_browser *browser, struct map *map,
-                              u64 ip, int row, int offset)
-{
-       struct inline_node *node;
-       int ret;
-
-       node = inline_node__create(map, ip);
-       if (node == NULL)
-               return 0;
-
-       ret = hist_browser__show_inline(browser, node, row, offset);
-
-       inline_node__delete(node);
-       return ret;
-}
-
 static int hist_browser__show_callchain_list(struct hist_browser *browser,
                                             struct callchain_node *node,
                                             struct callchain_list *chain,
@@ -918,7 +778,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
        char bf[1024], *alloc_str;
        char buf[64], *alloc_str2;
        const char *str;
-       int inline_rows = 0, ret = 1;
+       int ret = 1;
 
        if (arg->row_offset != 0) {
                arg->row_offset--;
@@ -955,12 +815,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
        free(alloc_str);
        free(alloc_str2);
 
-       if (symbol_conf.inline_name) {
-               inline_rows = show_inline_list(browser, chain->ms.map,
-                                              chain->ip, row + 1, offset);
-       }
-
-       return ret + inline_rows;
+       return ret;
 }
 
 static bool check_percent_display(struct rb_node *node, u64 parent_total)
@@ -1384,12 +1239,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                folded_sign = hist_entry__folded(entry);
        }
 
-       if (symbol_conf.inline_name &&
-           (!entry->has_children)) {
-               hist_entry_init_inline_node(entry);
-               folded_sign = hist_entry__folded(entry);
-       }
-
        if (row_offset == 0) {
                struct hpp_arg arg = {
                        .b              = &browser->b,
@@ -1421,8 +1270,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                        }
 
                        if (first) {
-                               if (symbol_conf.use_callchain ||
-                                       symbol_conf.inline_name) {
+                               if (symbol_conf.use_callchain) {
                                        ui_browser__printf(&browser->b, "%c ", folded_sign);
                                        width -= 2;
                                }
@@ -1464,15 +1312,11 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                        .is_current_entry = current_entry,
                };
 
-               if (entry->inline_node)
-                       printed += hist_browser__show_inline(browser,
-                                       entry->inline_node, row, 0);
-               else
-                       printed += hist_browser__show_callchain(browser,
-                                       entry, 1, row,
-                                       hist_browser__show_callchain_entry,
-                                       &arg,
-                                       hist_browser__check_output_full);
+               printed += hist_browser__show_callchain(browser,
+                               entry, 1, row,
+                               hist_browser__show_callchain_entry,
+                               &arg,
+                               hist_browser__check_output_full);
        }
 
        return printed;
index b5a5df14d7020fc60960ed781bd8ee3173d2578a..bbfbc91a0fa4683c9294247051e4fad532115665 100644 (file)
@@ -28,13 +28,17 @@ void ui_progress__update(struct ui_progress *p, u64 adv)
        }
 }
 
-void ui_progress__init(struct ui_progress *p, u64 total, const char *title)
+void __ui_progress__init(struct ui_progress *p, u64 total,
+                        const char *title, bool size)
 {
        p->curr = 0;
        p->next = p->step = total / 16 ?: 1;
        p->total = total;
        p->title = title;
+       p->size  = size;
 
+       if (ui_progress__ops->init)
+               ui_progress__ops->init(p);
 }
 
 void ui_progress__finish(void)
index 594bbe6935ddb0cb0978286a33d37496b179c852..4f52c37b2f099a82195879e1d2fc2c43f6b14444 100644 (file)
@@ -9,12 +9,22 @@ void ui_progress__finish(void);
 struct ui_progress {
        const char *title;
        u64 curr, next, step, total;
+       bool size;
 };
 
-void ui_progress__init(struct ui_progress *p, u64 total, const char *title);
+void __ui_progress__init(struct ui_progress *p, u64 total,
+                        const char *title, bool size);
+
+#define ui_progress__init(p, total, title) \
+       __ui_progress__init(p, total, title, false)
+
+#define ui_progress__init_size(p, total, title) \
+       __ui_progress__init(p, total, title, true)
+
 void ui_progress__update(struct ui_progress *p, u64 adv);
 
 struct ui_progress_ops {
+       void (*init)(struct ui_progress *p);
        void (*update)(struct ui_progress *p);
        void (*finish)(void);
 };
index de2810ae16be270e4ee4578730147d6f8af91701..25dd1e0ecc58186b38723a24ed085e28c1afc2cb 100644 (file)
@@ -22,64 +22,6 @@ static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
        return ret;
 }
 
-static size_t inline__fprintf(struct map *map, u64 ip, int left_margin,
-                             int depth, int depth_mask, FILE *fp)
-{
-       struct dso *dso;
-       struct inline_node *node;
-       struct inline_list *ilist;
-       int ret = 0, i;
-
-       if (map == NULL)
-               return 0;
-
-       dso = map->dso;
-       if (dso == NULL)
-               return 0;
-
-       node = dso__parse_addr_inlines(dso,
-                                      map__rip_2objdump(map, ip));
-       if (node == NULL)
-               return 0;
-
-       list_for_each_entry(ilist, &node->val, list) {
-               if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
-                       ret += callchain__fprintf_left_margin(fp, left_margin);
-
-                       for (i = 0; i < depth; i++) {
-                               if (depth_mask & (1 << i))
-                                       ret += fprintf(fp, "|");
-                               else
-                                       ret += fprintf(fp, " ");
-                               ret += fprintf(fp, "          ");
-                       }
-
-                       if (callchain_param.key == CCKEY_ADDRESS ||
-                           callchain_param.key == CCKEY_SRCLINE) {
-                               if (ilist->filename != NULL)
-                                       ret += fprintf(fp, "%s:%d (inline)",
-                                                      ilist->filename,
-                                                      ilist->line_nr);
-                               else
-                                       ret += fprintf(fp, "??");
-                       } else if (ilist->funcname != NULL)
-                               ret += fprintf(fp, "%s (inline)",
-                                              ilist->funcname);
-                       else if (ilist->filename != NULL)
-                               ret += fprintf(fp, "%s:%d (inline)",
-                                              ilist->filename,
-                                              ilist->line_nr);
-                       else
-                               ret += fprintf(fp, "??");
-
-                       ret += fprintf(fp, "\n");
-               }
-       }
-
-       inline_node__delete(node);
-       return ret;
-}
-
 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
                                          int left_margin)
 {
@@ -138,9 +80,6 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
        fputc('\n', fp);
        free(alloc_str);
 
-       if (symbol_conf.inline_name)
-               ret += inline__fprintf(chain->ms.map, chain->ip,
-                                      left_margin, depth, depth_mask, fp);
        return ret;
 }
 
@@ -315,13 +254,6 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
 
                        if (++entries_printed == callchain_param.print_limit)
                                break;
-
-                       if (symbol_conf.inline_name)
-                               ret += inline__fprintf(chain->ms.map,
-                                                      chain->ip,
-                                                      left_margin,
-                                                      0, 0,
-                                                      fp);
                }
                root = &cnode->rb_root;
        }
@@ -601,7 +533,6 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
 {
        int ret;
        int callchain_ret = 0;
-       int inline_ret = 0;
        struct perf_hpp hpp = {
                .buf            = bf,
                .size           = size,
@@ -623,13 +554,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
                callchain_ret = hist_entry_callchain__fprintf(he, total_period,
                                                              0, fp);
 
-       if (callchain_ret == 0 && symbol_conf.inline_name) {
-               inline_ret = inline__fprintf(he->ms.map, he->ip, 0, 0, 0, fp);
-               ret += inline_ret;
-               if (inline_ret > 0)
-                       ret += fprintf(fp, "\n");
-       } else
-               ret += callchain_ret;
+       ret += callchain_ret;
 
        return ret;
 }
index 236bcb620ae49722286233d55ccbc8fa4af90f79..bc134b82829d64a55c61663bbfeadac09e14d6df 100644 (file)
@@ -1,13 +1,34 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
 #include "../cache.h"
 #include "../progress.h"
 #include "../libslang.h"
 #include "../ui.h"
 #include "tui.h"
+#include "units.h"
 #include "../browser.h"
 
+static void __tui_progress__init(struct ui_progress *p)
+{
+       p->next = p->step = p->total / (SLtt_Screen_Cols - 2) ?: 1;
+}
+
+static int get_title(struct ui_progress *p, char *buf, size_t size)
+{
+       char buf_cur[20];
+       char buf_tot[20];
+       int ret;
+
+       ret  = unit_number__scnprintf(buf_cur, sizeof(buf_cur), p->curr);
+       ret += unit_number__scnprintf(buf_tot, sizeof(buf_tot), p->total);
+
+       return ret + scnprintf(buf, size, "%s [%s/%s]",
+                              p->title, buf_cur, buf_tot);
+}
+
 static void tui_progress__update(struct ui_progress *p)
 {
+       char buf[100], *title = (char *) p->title;
        int bar, y;
        /*
         * FIXME: We should have a per UI backend way of showing progress,
@@ -19,13 +40,18 @@ static void tui_progress__update(struct ui_progress *p)
        if (p->total == 0)
                return;
 
+       if (p->size) {
+               get_title(p, buf, sizeof(buf));
+               title = buf;
+       }
+
        ui__refresh_dimensions(false);
        pthread_mutex_lock(&ui__lock);
        y = SLtt_Screen_Rows / 2 - 2;
        SLsmg_set_color(0);
        SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
        SLsmg_gotorc(y++, 1);
-       SLsmg_write_string((char *)p->title);
+       SLsmg_write_string(title);
        SLsmg_fill_region(y, 1, 1, SLtt_Screen_Cols - 2, ' ');
        SLsmg_set_color(HE_COLORSET_SELECTED);
        bar = ((SLtt_Screen_Cols - 2) * p->curr) / p->total;
@@ -50,8 +76,8 @@ static void tui_progress__finish(void)
        pthread_mutex_unlock(&ui__lock);
 }
 
-static struct ui_progress_ops tui_progress__ops =
-{
+static struct ui_progress_ops tui_progress__ops = {
+       .init   = __tui_progress__init,
        .update = tui_progress__update,
        .finish = tui_progress__finish,
 };
index 94518c1bf8b6c37896c8f90430c4056012f6b29e..a3de7916fe6311f0f4f64e2a4029b67a223adae8 100644 (file)
@@ -13,6 +13,7 @@ libperf-y += find_bit.o
 libperf-y += kallsyms.o
 libperf-y += levenshtein.o
 libperf-y += llvm-utils.o
+libperf-y += mmap.o
 libperf-y += memswap.o
 libperf-y += parse-events.o
 libperf-y += perf_regs.o
@@ -34,6 +35,7 @@ libperf-y += dso.o
 libperf-y += symbol.o
 libperf-y += symbol_fprintf.o
 libperf-y += color.o
+libperf-y += metricgroup.o
 libperf-y += header.o
 libperf-y += callchain.o
 libperf-y += values.o
@@ -78,6 +80,7 @@ libperf-y += data.o
 libperf-y += tsc.o
 libperf-y += cloexec.o
 libperf-y += call-path.o
+libperf-y += rwsem.o
 libperf-y += thread-stack.o
 libperf-$(CONFIG_AUXTRACE) += auxtrace.o
 libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
index aa66791b1bfcba473bf665f16da69e37092a63fd..da1c4c4a0dd842a279283f8b2b52bef10c5fda3d 100644 (file)
@@ -49,10 +49,9 @@ struct arch {
        void            *priv;
        unsigned int    model;
        unsigned int    family;
-       int             (*init)(struct arch *arch);
+       int             (*init)(struct arch *arch, char *cpuid);
        bool            (*ins_is_fused)(struct arch *arch, const char *ins1,
                                        const char *ins2);
-       int             (*cpuid_parse)(struct arch *arch, char *cpuid);
        struct          {
                char comment_char;
                char skip_functions_char;
@@ -132,10 +131,10 @@ static struct arch architectures[] = {
        },
        {
                .name = "x86",
+               .init = x86__annotate_init,
                .instructions = x86__instructions,
                .nr_instructions = ARRAY_SIZE(x86__instructions),
                .ins_is_fused = x86__ins_is_fused,
-               .cpuid_parse = x86__cpuid_parse,
                .objdump =  {
                        .comment_char = '#',
                },
@@ -1457,16 +1456,13 @@ int symbol__disassemble(struct symbol *sym, struct map *map,
                *parch = arch;
 
        if (arch->init) {
-               err = arch->init(arch);
+               err = arch->init(arch, cpuid);
                if (err) {
                        pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
                        return err;
                }
        }
 
-       if (arch->cpuid_parse && cpuid)
-               arch->cpuid_parse(arch, cpuid);
-
        pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
                 symfs_filename, sym->name, map->unmap_ip(map, sym->start),
                 map->unmap_ip(map, sym->end));
index 5547457566a7130d25e97d012811e6ac8775ecf0..a33491416400ed85b8814f2a134d59eeaf6b528c 100644 (file)
@@ -208,7 +208,7 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues,
 
 static void *auxtrace_copy_data(u64 size, struct perf_session *session)
 {
-       int fd = perf_data_file__fd(session->file);
+       int fd = perf_data__fd(session->data);
        void *p;
        ssize_t ret;
 
@@ -305,7 +305,7 @@ static int auxtrace_queues__add_event_buffer(struct auxtrace_queues *queues,
        if (session->one_mmap) {
                buffer->data = buffer->data_offset - session->one_mmap_offset +
                               session->one_mmap_addr;
-       } else if (perf_data_file__is_pipe(session->file)) {
+       } else if (perf_data__is_pipe(session->data)) {
                buffer->data = auxtrace_copy_data(buffer->size, session);
                if (!buffer->data)
                        return -ENOMEM;
index 33b5e6cdf38c8302727fe55446b8f24d8342084d..d19e11b68de728b95c2e427923475bdb3a877a26 100644 (file)
@@ -378,7 +378,7 @@ struct addr_filters {
 static inline u64 auxtrace_mmap__read_snapshot_head(struct auxtrace_mmap *mm)
 {
        struct perf_event_mmap_page *pc = mm->userpg;
-       u64 head = ACCESS_ONCE(pc->aux_head);
+       u64 head = READ_ONCE(pc->aux_head);
 
        /* Ensure all reads are done after we read the head */
        rmb();
@@ -389,7 +389,7 @@ static inline u64 auxtrace_mmap__read_head(struct auxtrace_mmap *mm)
 {
        struct perf_event_mmap_page *pc = mm->userpg;
 #if BITS_PER_LONG == 64 || !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
-       u64 head = ACCESS_ONCE(pc->aux_head);
+       u64 head = READ_ONCE(pc->aux_head);
 #else
        u64 head = __sync_val_compare_and_swap(&pc->aux_head, 0, 0);
 #endif
index 6031933d811c258f0c3d36c09389975985ff2e1c..082505d08d720b18cae0051591b087bb86e6e456 100644 (file)
@@ -567,6 +567,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
                call->ip = cursor_node->ip;
                call->ms.sym = cursor_node->sym;
                call->ms.map = map__get(cursor_node->map);
+               call->srcline = cursor_node->srcline;
 
                if (cursor_node->branch) {
                        call->branch_count = 1;
@@ -645,103 +646,120 @@ enum match_result {
        MATCH_GT,
 };
 
-static enum match_result match_chain_srcline(struct callchain_cursor_node *node,
-                                            struct callchain_list *cnode)
+static enum match_result match_chain_strings(const char *left,
+                                            const char *right)
 {
-       char *left = NULL;
-       char *right = NULL;
        enum match_result ret = MATCH_EQ;
        int cmp;
 
-       if (cnode->ms.map)
-               left = get_srcline(cnode->ms.map->dso,
-                                map__rip_2objdump(cnode->ms.map, cnode->ip),
-                                cnode->ms.sym, true, false);
-       if (node->map)
-               right = get_srcline(node->map->dso,
-                                 map__rip_2objdump(node->map, node->ip),
-                                 node->sym, true, false);
-
        if (left && right)
                cmp = strcmp(left, right);
        else if (!left && right)
                cmp = 1;
        else if (left && !right)
                cmp = -1;
-       else if (cnode->ip == node->ip)
-               cmp = 0;
        else
-               cmp = (cnode->ip < node->ip) ? -1 : 1;
+               return MATCH_ERROR;
 
        if (cmp != 0)
                ret = cmp < 0 ? MATCH_LT : MATCH_GT;
 
-       free_srcline(left);
-       free_srcline(right);
        return ret;
 }
 
+/*
+ * We need to always use relative addresses because we're aggregating
+ * callchains from multiple threads, i.e. different address spaces, so
+ * comparing absolute addresses make no sense as a symbol in a DSO may end up
+ * in a different address when used in a different binary or even the same
+ * binary but with some sort of address randomization technique, thus we need
+ * to compare just relative addresses. -acme
+ */
+static enum match_result match_chain_dso_addresses(struct map *left_map, u64 left_ip,
+                                                  struct map *right_map, u64 right_ip)
+{
+       struct dso *left_dso = left_map ? left_map->dso : NULL;
+       struct dso *right_dso = right_map ? right_map->dso : NULL;
+
+       if (left_dso != right_dso)
+               return left_dso < right_dso ? MATCH_LT : MATCH_GT;
+
+       if (left_ip != right_ip)
+               return left_ip < right_ip ? MATCH_LT : MATCH_GT;
+
+       return MATCH_EQ;
+}
+
 static enum match_result match_chain(struct callchain_cursor_node *node,
                                     struct callchain_list *cnode)
 {
-       struct symbol *sym = node->sym;
-       u64 left, right;
-       struct dso *left_dso = NULL;
-       struct dso *right_dso = NULL;
-
-       if (callchain_param.key == CCKEY_SRCLINE) {
-               enum match_result match = match_chain_srcline(node, cnode);
+       enum match_result match = MATCH_ERROR;
 
+       switch (callchain_param.key) {
+       case CCKEY_SRCLINE:
+               match = match_chain_strings(cnode->srcline, node->srcline);
                if (match != MATCH_ERROR)
-                       return match;
-       }
-
-       if (cnode->ms.sym && sym && callchain_param.key == CCKEY_FUNCTION) {
-               left = cnode->ms.sym->start;
-               right = sym->start;
-               left_dso = cnode->ms.map->dso;
-               right_dso = node->map->dso;
-       } else {
-               left = cnode->ip;
-               right = node->ip;
+                       break;
+               /* otherwise fall-back to symbol-based comparison below */
+               __fallthrough;
+       case CCKEY_FUNCTION:
+               if (node->sym && cnode->ms.sym) {
+                       /*
+                        * Compare inlined frames based on their symbol name
+                        * because different inlined frames will have the same
+                        * symbol start. Otherwise do a faster comparison based
+                        * on the symbol start address.
+                        */
+                       if (cnode->ms.sym->inlined || node->sym->inlined) {
+                               match = match_chain_strings(cnode->ms.sym->name,
+                                                           node->sym->name);
+                               if (match != MATCH_ERROR)
+                                       break;
+                       } else {
+                               match = match_chain_dso_addresses(cnode->ms.map, cnode->ms.sym->start,
+                                                                 node->map, node->sym->start);
+                               break;
+                       }
+               }
+               /* otherwise fall-back to IP-based comparison below */
+               __fallthrough;
+       case CCKEY_ADDRESS:
+       default:
+               match = match_chain_dso_addresses(cnode->ms.map, cnode->ip, node->map, node->ip);
+               break;
        }
 
-       if (left == right && left_dso == right_dso) {
-               if (node->branch) {
-                       cnode->branch_count++;
+       if (match == MATCH_EQ && node->branch) {
+               cnode->branch_count++;
 
-                       if (node->branch_from) {
-                               /*
-                                * It's "to" of a branch
-                                */
-                               cnode->brtype_stat.branch_to = true;
+               if (node->branch_from) {
+                       /*
+                        * It's "to" of a branch
+                        */
+                       cnode->brtype_stat.branch_to = true;
 
-                               if (node->branch_flags.predicted)
-                                       cnode->predicted_count++;
+                       if (node->branch_flags.predicted)
+                               cnode->predicted_count++;
 
-                               if (node->branch_flags.abort)
-                                       cnode->abort_count++;
+                       if (node->branch_flags.abort)
+                               cnode->abort_count++;
 
-                               branch_type_count(&cnode->brtype_stat,
-                                                 &node->branch_flags,
-                                                 node->branch_from,
-                                                 node->ip);
-                       } else {
-                               /*
-                                * It's "from" of a branch
-                                */
-                               cnode->brtype_stat.branch_to = false;
-                               cnode->cycles_count +=
-                                       node->branch_flags.cycles;
-                               cnode->iter_count += node->nr_loop_iter;
-                               cnode->iter_cycles += node->iter_cycles;
-                       }
+                       branch_type_count(&cnode->brtype_stat,
+                                         &node->branch_flags,
+                                         node->branch_from,
+                                         node->ip);
+               } else {
+                       /*
+                        * It's "from" of a branch
+                        */
+                       cnode->brtype_stat.branch_to = false;
+                       cnode->cycles_count += node->branch_flags.cycles;
+                       cnode->iter_count += node->nr_loop_iter;
+                       cnode->iter_cycles += node->iter_cycles;
                }
-
-               return MATCH_EQ;
        }
 
-       return left > right ? MATCH_GT : MATCH_LT;
+       return match;
 }
 
 /*
@@ -970,7 +988,7 @@ merge_chain_branch(struct callchain_cursor *cursor,
        list_for_each_entry_safe(list, next_list, &src->val, list) {
                callchain_cursor_append(cursor, list->ip,
                                        list->ms.map, list->ms.sym,
-                                       false, NULL, 0, 0, 0);
+                                       false, NULL, 0, 0, 0, list->srcline);
                list_del(&list->list);
                map__zput(list->ms.map);
                free(list);
@@ -1010,7 +1028,8 @@ int callchain_merge(struct callchain_cursor *cursor,
 int callchain_cursor_append(struct callchain_cursor *cursor,
                            u64 ip, struct map *map, struct symbol *sym,
                            bool branch, struct branch_flags *flags,
-                           int nr_loop_iter, u64 iter_cycles, u64 branch_from)
+                           int nr_loop_iter, u64 iter_cycles, u64 branch_from,
+                           const char *srcline)
 {
        struct callchain_cursor_node *node = *cursor->last;
 
@@ -1029,6 +1048,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
        node->branch = branch;
        node->nr_loop_iter = nr_loop_iter;
        node->iter_cycles = iter_cycles;
+       node->srcline = srcline;
 
        if (flags)
                memcpy(&node->branch_flags, flags,
@@ -1071,10 +1091,8 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
 {
        al->map = node->map;
        al->sym = node->sym;
-       if (node->map)
-               al->addr = node->map->map_ip(node->map, node->ip);
-       else
-               al->addr = node->ip;
+       al->srcline = node->srcline;
+       al->addr = node->ip;
 
        if (al->sym == NULL) {
                if (hide_unresolved)
@@ -1116,16 +1134,15 @@ char *callchain_list__sym_name(struct callchain_list *cl,
        int printed;
 
        if (cl->ms.sym) {
-               if (show_srcline && cl->ms.map && !cl->srcline)
-                       cl->srcline = get_srcline(cl->ms.map->dso,
-                                                 map__rip_2objdump(cl->ms.map,
-                                                                   cl->ip),
-                                                 cl->ms.sym, false, show_addr);
-               if (cl->srcline)
-                       printed = scnprintf(bf, bfsize, "%s %s",
-                                       cl->ms.sym->name, cl->srcline);
+               const char *inlined = cl->ms.sym->inlined ? " (inlined)" : "";
+
+               if (show_srcline && cl->srcline)
+                       printed = scnprintf(bf, bfsize, "%s %s%s",
+                                           cl->ms.sym->name, cl->srcline,
+                                           inlined);
                else
-                       printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
+                       printed = scnprintf(bf, bfsize, "%s%s",
+                                           cl->ms.sym->name, inlined);
        } else
                printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
 
@@ -1533,7 +1550,7 @@ int callchain_cursor__copy(struct callchain_cursor *dst,
                                             node->branch, &node->branch_flags,
                                             node->nr_loop_iter,
                                             node->iter_cycles,
-                                            node->branch_from);
+                                            node->branch_from, node->srcline);
                if (rc)
                        break;
 
index f967aa47d0a1d090420b1acd2e1814292a29f47f..b79ef2478a575fd206e52cf4860f49230ae64930 100644 (file)
@@ -122,7 +122,7 @@ struct callchain_list {
        u64                     iter_count;
        u64                     iter_cycles;
        struct branch_type_stat brtype_stat;
-       char                   *srcline;
+       const char              *srcline;
        struct list_head        list;
 };
 
@@ -136,6 +136,7 @@ struct callchain_cursor_node {
        u64                             ip;
        struct map                      *map;
        struct symbol                   *sym;
+       const char                      *srcline;
        bool                            branch;
        struct branch_flags             branch_flags;
        u64                             branch_from;
@@ -202,7 +203,8 @@ static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
 int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
                            struct map *map, struct symbol *sym,
                            bool branch, struct branch_flags *flags,
-                           int nr_loop_iter, u64 iter_cycles, u64 branch_from);
+                           int nr_loop_iter, u64 iter_cycles, u64 branch_from,
+                           const char *srcline);
 
 /* Close a cursor writing session. Initialize for the reader */
 static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
index 8808570f8e9c25244bbd5886d4d2afd51ad09cf7..7798a2cc8a867420a468ffc530b444a1fd26f1fe 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <linux/refcount.h>
+#include "rwsem.h"
 
 struct comm_str {
        char *str;
@@ -15,6 +16,7 @@ struct comm_str {
 
 /* Should perhaps be moved to struct machine */
 static struct rb_root comm_str_root;
+static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER,};
 
 static struct comm_str *comm_str__get(struct comm_str *cs)
 {
@@ -26,7 +28,9 @@ static struct comm_str *comm_str__get(struct comm_str *cs)
 static void comm_str__put(struct comm_str *cs)
 {
        if (cs && refcount_dec_and_test(&cs->refcnt)) {
+               down_write(&comm_str_lock);
                rb_erase(&cs->rb_node, &comm_str_root);
+               up_write(&comm_str_lock);
                zfree(&cs->str);
                free(cs);
        }
@@ -51,7 +55,8 @@ static struct comm_str *comm_str__alloc(const char *str)
        return cs;
 }
 
-static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
+static
+struct comm_str *__comm_str__findnew(const char *str, struct rb_root *root)
 {
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
@@ -82,6 +87,17 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
        return new;
 }
 
+static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
+{
+       struct comm_str *cs;
+
+       down_write(&comm_str_lock);
+       cs = __comm_str__findnew(str, root);
+       up_write(&comm_str_lock);
+
+       return cs;
+}
+
 struct comm *comm__new(const char *str, u64 timestamp, bool exec)
 {
        struct comm *comm = zalloc(sizeof(*comm));
index 4b893c622236294b7934db7b88c057c3a41788cd..84eb9393c7db1bf304b77d9984a11d5aea6a673d 100644 (file)
@@ -701,10 +701,7 @@ struct perf_config_set *perf_config_set__new(void)
 
        if (set) {
                INIT_LIST_HEAD(&set->sections);
-               if (perf_config_set__init(set) < 0) {
-                       perf_config_set__delete(set);
-                       set = NULL;
-               }
+               perf_config_set__init(set);
        }
 
        return set;
index 2346cecb8ea20c867520a9ca76a24b355c0fe7e3..5744c12641a53d341ef46d548a3498272841cf54 100644 (file)
@@ -1577,10 +1577,10 @@ int bt_convert__perf2ctf(const char *input, const char *path,
                         struct perf_data_convert_opts *opts)
 {
        struct perf_session *session;
-       struct perf_data_file file = {
-               .path = input,
-               .mode = PERF_DATA_MODE_READ,
-               .force = opts->force,
+       struct perf_data data = {
+               .file.path = input,
+               .mode      = PERF_DATA_MODE_READ,
+               .force     = opts->force,
        };
        struct convert c = {
                .tool = {
@@ -1619,7 +1619,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
 
        err = -1;
        /* perf.data session */
-       session = perf_session__new(&file, 0, &c.tool);
+       session = perf_session__new(&data, 0, &c.tool);
        if (!session)
                goto free_writer;
 
@@ -1650,7 +1650,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
 
        fprintf(stderr,
                "[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
-               file.path, path);
+               data.file.path, path);
 
        fprintf(stderr,
                "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples",
index 79192758bdb3de9d232de2f576edc8b0d6bcffde..48094fde0a682c623dfdef6831dc45f92d9cd6e9 100644 (file)
@@ -4,6 +4,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 
 #endif
 #endif
 
-static bool check_pipe(struct perf_data_file *file)
+static bool check_pipe(struct perf_data *data)
 {
        struct stat st;
        bool is_pipe = false;
-       int fd = perf_data_file__is_read(file) ?
+       int fd = perf_data__is_read(data) ?
                 STDIN_FILENO : STDOUT_FILENO;
 
-       if (!file->path) {
+       if (!data->file.path) {
                if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
                        is_pipe = true;
        } else {
-               if (!strcmp(file->path, "-"))
+               if (!strcmp(data->file.path, "-"))
                        is_pipe = true;
        }
 
        if (is_pipe)
-               file->fd = fd;
+               data->file.fd = fd;
 
-       return file->is_pipe = is_pipe;
+       return data->is_pipe = is_pipe;
 }
 
-static int check_backup(struct perf_data_file *file)
+static int check_backup(struct perf_data *data)
 {
        struct stat st;
 
-       if (!stat(file->path, &st) && st.st_size) {
+       if (!stat(data->file.path, &st) && st.st_size) {
                /* TODO check errors properly */
                char oldname[PATH_MAX];
                snprintf(oldname, sizeof(oldname), "%s.old",
-                        file->path);
+                        data->file.path);
                unlink(oldname);
-               rename(file->path, oldname);
+               rename(data->file.path, oldname);
        }
 
        return 0;
 }
 
-static int open_file_read(struct perf_data_file *file)
+static int open_file_read(struct perf_data *data)
 {
        struct stat st;
        int fd;
        char sbuf[STRERR_BUFSIZE];
 
-       fd = open(file->path, O_RDONLY);
+       fd = open(data->file.path, O_RDONLY);
        if (fd < 0) {
                int err = errno;
 
-               pr_err("failed to open %s: %s", file->path,
+               pr_err("failed to open %s: %s", data->file.path,
                        str_error_r(err, sbuf, sizeof(sbuf)));
-               if (err == ENOENT && !strcmp(file->path, "perf.data"))
+               if (err == ENOENT && !strcmp(data->file.path, "perf.data"))
                        pr_err("  (try 'perf record' first)");
                pr_err("\n");
                return -err;
@@ -79,19 +80,19 @@ static int open_file_read(struct perf_data_file *file)
        if (fstat(fd, &st) < 0)
                goto out_close;
 
-       if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
+       if (!data->force && st.st_uid && (st.st_uid != geteuid())) {
                pr_err("File %s not owned by current user or root (use -f to override)\n",
-                      file->path);
+                      data->file.path);
                goto out_close;
        }
 
        if (!st.st_size) {
-               pr_info("zero-sized file (%s), nothing to do!\n",
-                       file->path);
+               pr_info("zero-sized data (%s), nothing to do!\n",
+                       data->file.path);
                goto out_close;
        }
 
-       file->size = st.st_size;
+       data->size = st.st_size;
        return fd;
 
  out_close:
@@ -99,49 +100,49 @@ static int open_file_read(struct perf_data_file *file)
        return -1;
 }
 
-static int open_file_write(struct perf_data_file *file)
+static int open_file_write(struct perf_data *data)
 {
        int fd;
        char sbuf[STRERR_BUFSIZE];
 
-       if (check_backup(file))
+       if (check_backup(data))
                return -1;
 
-       fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
+       fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC,
                  S_IRUSR|S_IWUSR);
 
        if (fd < 0)
-               pr_err("failed to open %s : %s\n", file->path,
+               pr_err("failed to open %s : %s\n", data->file.path,
                        str_error_r(errno, sbuf, sizeof(sbuf)));
 
        return fd;
 }
 
-static int open_file(struct perf_data_file *file)
+static int open_file(struct perf_data *data)
 {
        int fd;
 
-       fd = perf_data_file__is_read(file) ?
-            open_file_read(file) : open_file_write(file);
+       fd = perf_data__is_read(data) ?
+            open_file_read(data) : open_file_write(data);
 
-       file->fd = fd;
+       data->file.fd = fd;
        return fd < 0 ? -1 : 0;
 }
 
-int perf_data_file__open(struct perf_data_file *file)
+int perf_data__open(struct perf_data *data)
 {
-       if (check_pipe(file))
+       if (check_pipe(data))
                return 0;
 
-       if (!file->path)
-               file->path = "perf.data";
+       if (!data->file.path)
+               data->file.path = "perf.data";
 
-       return open_file(file);
+       return open_file(data);
 }
 
-void perf_data_file__close(struct perf_data_file *file)
+void perf_data__close(struct perf_data *data)
 {
-       close(file->fd);
+       close(data->file.fd);
 }
 
 ssize_t perf_data_file__write(struct perf_data_file *file,
@@ -150,42 +151,48 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
        return writen(file->fd, buf, size);
 }
 
-int perf_data_file__switch(struct perf_data_file *file,
+ssize_t perf_data__write(struct perf_data *data,
+                             void *buf, size_t size)
+{
+       return perf_data_file__write(&data->file, buf, size);
+}
+
+int perf_data__switch(struct perf_data *data,
                           const char *postfix,
                           size_t pos, bool at_exit)
 {
        char *new_filepath;
        int ret;
 
-       if (check_pipe(file))
+       if (check_pipe(data))
                return -EINVAL;
-       if (perf_data_file__is_read(file))
+       if (perf_data__is_read(data))
                return -EINVAL;
 
-       if (asprintf(&new_filepath, "%s.%s", file->path, postfix) < 0)
+       if (asprintf(&new_filepath, "%s.%s", data->file.path, postfix) < 0)
                return -ENOMEM;
 
        /*
         * Only fire a warning, don't return error, continue fill
         * original file.
         */
-       if (rename(file->path, new_filepath))
-               pr_warning("Failed to rename %s to %s\n", file->path, new_filepath);
+       if (rename(data->file.path, new_filepath))
+               pr_warning("Failed to rename %s to %s\n", data->file.path, new_filepath);
 
        if (!at_exit) {
-               close(file->fd);
-               ret = perf_data_file__open(file);
+               close(data->file.fd);
+               ret = perf_data__open(data);
                if (ret < 0)
                        goto out;
 
-               if (lseek(file->fd, pos, SEEK_SET) == (off_t)-1) {
+               if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) {
                        ret = -errno;
                        pr_debug("Failed to lseek to %zu: %s",
                                 pos, strerror(errno));
                        goto out;
                }
        }
-       ret = file->fd;
+       ret = data->file.fd;
 out:
        free(new_filepath);
        return ret;
index 80241ba781010d996012674e15a693572daca96f..4828f7feea8949eb0e9a7d0464fad3997519c170 100644 (file)
@@ -10,51 +10,57 @@ enum perf_data_mode {
 };
 
 struct perf_data_file {
-       const char              *path;
-       int                      fd;
+       const char      *path;
+       int              fd;
+};
+
+struct perf_data {
+       struct perf_data_file    file;
        bool                     is_pipe;
        bool                     force;
        unsigned long            size;
        enum perf_data_mode      mode;
 };
 
-static inline bool perf_data_file__is_read(struct perf_data_file *file)
+static inline bool perf_data__is_read(struct perf_data *data)
 {
-       return file->mode == PERF_DATA_MODE_READ;
+       return data->mode == PERF_DATA_MODE_READ;
 }
 
-static inline bool perf_data_file__is_write(struct perf_data_file *file)
+static inline bool perf_data__is_write(struct perf_data *data)
 {
-       return file->mode == PERF_DATA_MODE_WRITE;
+       return data->mode == PERF_DATA_MODE_WRITE;
 }
 
-static inline int perf_data_file__is_pipe(struct perf_data_file *file)
+static inline int perf_data__is_pipe(struct perf_data *data)
 {
-       return file->is_pipe;
+       return data->is_pipe;
 }
 
-static inline int perf_data_file__fd(struct perf_data_file *file)
+static inline int perf_data__fd(struct perf_data *data)
 {
-       return file->fd;
+       return data->file.fd;
 }
 
-static inline unsigned long perf_data_file__size(struct perf_data_file *file)
+static inline unsigned long perf_data__size(struct perf_data *data)
 {
-       return file->size;
+       return data->size;
 }
 
-int perf_data_file__open(struct perf_data_file *file);
-void perf_data_file__close(struct perf_data_file *file);
+int perf_data__open(struct perf_data *data);
+void perf_data__close(struct perf_data *data);
+ssize_t perf_data__write(struct perf_data *data,
+                             void *buf, size_t size);
 ssize_t perf_data_file__write(struct perf_data_file *file,
                              void *buf, size_t size);
 /*
  * If at_exit is set, only rename current perf.data to
- * perf.data.<postfix>, continue write on original file.
+ * perf.data.<postfix>, continue write on original data.
  * Set at_exit when flushing the last output.
  *
  * Return value is fd of new output.
  */
-int perf_data_file__switch(struct perf_data_file *file,
+int perf_data__switch(struct perf_data *data,
                           const char *postfix,
                           size_t pos, bool at_exit);
 #endif /* __PERF_DATA_H */
index dc8b53b6950e3c89c0bdddb825a60d278a4fda7c..f3a71db83947355136204b9e2425af21d7af8902 100644 (file)
@@ -112,50 +112,53 @@ int dump_printf(const char *fmt, ...)
        return ret;
 }
 
-static void trace_event_printer(enum binary_printer_ops op,
-                               unsigned int val, void *extra)
+static int trace_event_printer(enum binary_printer_ops op,
+                              unsigned int val, void *extra, FILE *fp)
 {
        const char *color = PERF_COLOR_BLUE;
        union perf_event *event = (union perf_event *)extra;
        unsigned char ch = (unsigned char)val;
+       int printed = 0;
 
        switch (op) {
        case BINARY_PRINT_DATA_BEGIN:
-               printf(".");
-               color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n",
-                               event->header.size);
+               printed += fprintf(fp, ".");
+               printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",
+                                        event->header.size);
                break;
        case BINARY_PRINT_LINE_BEGIN:
-               printf(".");
+               printed += fprintf(fp, ".");
                break;
        case BINARY_PRINT_ADDR:
-               color_fprintf(stdout, color, "  %04x: ", val);
+               printed += color_fprintf(fp, color, "  %04x: ", val);
                break;
        case BINARY_PRINT_NUM_DATA:
-               color_fprintf(stdout, color, " %02x", val);
+               printed += color_fprintf(fp, color, " %02x", val);
                break;
        case BINARY_PRINT_NUM_PAD:
-               color_fprintf(stdout, color, "   ");
+               printed += color_fprintf(fp, color, "   ");
                break;
        case BINARY_PRINT_SEP:
-               color_fprintf(stdout, color, "  ");
+               printed += color_fprintf(fp, color, "  ");
                break;
        case BINARY_PRINT_CHAR_DATA:
-               color_fprintf(stdout, color, "%c",
+               printed += color_fprintf(fp, color, "%c",
                              isprint(ch) ? ch : '.');
                break;
        case BINARY_PRINT_CHAR_PAD:
-               color_fprintf(stdout, color, " ");
+               printed += color_fprintf(fp, color, " ");
                break;
        case BINARY_PRINT_LINE_END:
-               color_fprintf(stdout, color, "\n");
+               printed += color_fprintf(fp, color, "\n");
                break;
        case BINARY_PRINT_DATA_END:
-               printf("\n");
+               printed += fprintf(fp, "\n");
                break;
        default:
                break;
        }
+
+       return printed;
 }
 
 void trace_event(union perf_event *event)
index 00c98c968cb15f5d41dbec59295d231d73207ac0..d5b6f7f5baffff4f8bb34fe59d014ec8c4c8d014 100644 (file)
@@ -7,9 +7,11 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <errno.h>
+#include <fcntl.h>
 #include "compress.h"
 #include "path.h"
 #include "symbol.h"
+#include "srcline.h"
 #include "dso.h"
 #include "machine.h"
 #include "auxtrace.h"
@@ -1201,6 +1203,8 @@ struct dso *dso__new(const char *name)
                for (i = 0; i < MAP__NR_TYPES; ++i)
                        dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
                dso->data.cache = RB_ROOT;
+               dso->inlined_nodes = RB_ROOT;
+               dso->srclines = RB_ROOT;
                dso->data.fd = -1;
                dso->data.status = DSO_DATA_STATUS_UNKNOWN;
                dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
@@ -1232,6 +1236,10 @@ void dso__delete(struct dso *dso)
        if (!RB_EMPTY_NODE(&dso->rb_node))
                pr_err("DSO %s is still in rbtree when being deleted!\n",
                       dso->long_name);
+
+       /* free inlines first, as they reference symbols */
+       inlines__tree_delete(&dso->inlined_nodes);
+       srcline__tree_delete(&dso->srclines);
        for (i = 0; i < MAP__NR_TYPES; ++i)
                symbols__delete(&dso->symbols[i]);
 
@@ -1366,9 +1374,9 @@ void __dsos__add(struct dsos *dsos, struct dso *dso)
 
 void dsos__add(struct dsos *dsos, struct dso *dso)
 {
-       pthread_rwlock_wrlock(&dsos->lock);
+       down_write(&dsos->lock);
        __dsos__add(dsos, dso);
-       pthread_rwlock_unlock(&dsos->lock);
+       up_write(&dsos->lock);
 }
 
 struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
@@ -1387,9 +1395,9 @@ struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
 struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
 {
        struct dso *dso;
-       pthread_rwlock_rdlock(&dsos->lock);
+       down_read(&dsos->lock);
        dso = __dsos__find(dsos, name, cmp_short);
-       pthread_rwlock_unlock(&dsos->lock);
+       up_read(&dsos->lock);
        return dso;
 }
 
@@ -1416,9 +1424,9 @@ struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
 struct dso *dsos__findnew(struct dsos *dsos, const char *name)
 {
        struct dso *dso;
-       pthread_rwlock_wrlock(&dsos->lock);
+       down_write(&dsos->lock);
        dso = dso__get(__dsos__findnew(dsos, name));
-       pthread_rwlock_unlock(&dsos->lock);
+       up_write(&dsos->lock);
        return dso;
 }
 
index 926ff2e7f668d18dc734c03bb3e1b8296b848dcd..c229dbe0277a2a844fca644fe7c24590697b7bb3 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/rbtree.h>
 #include <sys/types.h>
 #include <stdbool.h>
-#include <pthread.h>
+#include "rwsem.h"
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include "map.h"
@@ -130,7 +130,7 @@ struct dso_cache {
 struct dsos {
        struct list_head head;
        struct rb_root   root;  /* rbtree root sorted by long name */
-       pthread_rwlock_t lock;
+       struct rw_semaphore lock;
 };
 
 struct auxtrace_cache;
@@ -142,6 +142,8 @@ struct dso {
        struct rb_root   *root;         /* root of rbtree that rb_node is in */
        struct rb_root   symbols[MAP__NR_TYPES];
        struct rb_root   symbol_names[MAP__NR_TYPES];
+       struct rb_root   inlined_nodes;
+       struct rb_root   srclines;
        struct {
                u64             addr;
                struct symbol   *symbol;
index fc690fecbfd66509083eeb1527ea7c00bf7c1777..97a8ef9980db7407a6760a0b22049ddba88b3d6c 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <dirent.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -678,21 +679,21 @@ out:
        return err;
 }
 
-int perf_event__synthesize_threads(struct perf_tool *tool,
-                                  perf_event__handler_t process,
-                                  struct machine *machine,
-                                  bool mmap_data,
-                                  unsigned int proc_map_timeout)
+static int __perf_event__synthesize_threads(struct perf_tool *tool,
+                                           perf_event__handler_t process,
+                                           struct machine *machine,
+                                           bool mmap_data,
+                                           unsigned int proc_map_timeout,
+                                           struct dirent **dirent,
+                                           int start,
+                                           int num)
 {
-       DIR *proc;
-       char proc_path[PATH_MAX];
-       struct dirent *dirent;
        union perf_event *comm_event, *mmap_event, *fork_event;
        union perf_event *namespaces_event;
        int err = -1;
-
-       if (machine__is_default_guest(machine))
-               return 0;
+       char *end;
+       pid_t pid;
+       int i;
 
        comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
        if (comm_event == NULL)
@@ -712,31 +713,25 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
        if (namespaces_event == NULL)
                goto out_free_fork;
 
-       snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
-       proc = opendir(proc_path);
-
-       if (proc == NULL)
-               goto out_free_namespaces;
-
-       while ((dirent = readdir(proc)) != NULL) {
-               char *end;
-               pid_t pid = strtol(dirent->d_name, &end, 10);
+       for (i = start; i < start + num; i++) {
+               if (!isdigit(dirent[i]->d_name[0]))
+                       continue;
 
-               if (*end) /* only interested in proper numerical dirents */
+               pid = (pid_t)strtol(dirent[i]->d_name, &end, 10);
+               /* only interested in proper numerical dirents */
+               if (*end)
                        continue;
                /*
-                * We may race with exiting thread, so don't stop just because
-                * one thread couldn't be synthesized.
-                */
+                * We may race with exiting thread, so don't stop just because
+                * one thread couldn't be synthesized.
+                */
                __event__synthesize_thread(comm_event, mmap_event, fork_event,
                                           namespaces_event, pid, 1, process,
                                           tool, machine, mmap_data,
                                           proc_map_timeout);
        }
-
        err = 0;
-       closedir(proc);
-out_free_namespaces:
+
        free(namespaces_event);
 out_free_fork:
        free(fork_event);
@@ -748,6 +743,118 @@ out:
        return err;
 }
 
+struct synthesize_threads_arg {
+       struct perf_tool *tool;
+       perf_event__handler_t process;
+       struct machine *machine;
+       bool mmap_data;
+       unsigned int proc_map_timeout;
+       struct dirent **dirent;
+       int num;
+       int start;
+};
+
+static void *synthesize_threads_worker(void *arg)
+{
+       struct synthesize_threads_arg *args = arg;
+
+       __perf_event__synthesize_threads(args->tool, args->process,
+                                        args->machine, args->mmap_data,
+                                        args->proc_map_timeout, args->dirent,
+                                        args->start, args->num);
+       return NULL;
+}
+
+int perf_event__synthesize_threads(struct perf_tool *tool,
+                                  perf_event__handler_t process,
+                                  struct machine *machine,
+                                  bool mmap_data,
+                                  unsigned int proc_map_timeout,
+                                  unsigned int nr_threads_synthesize)
+{
+       struct synthesize_threads_arg *args = NULL;
+       pthread_t *synthesize_threads = NULL;
+       char proc_path[PATH_MAX];
+       struct dirent **dirent;
+       int num_per_thread;
+       int m, n, i, j;
+       int thread_nr;
+       int base = 0;
+       int err = -1;
+
+
+       if (machine__is_default_guest(machine))
+               return 0;
+
+       snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
+       n = scandir(proc_path, &dirent, 0, alphasort);
+       if (n < 0)
+               return err;
+
+       if (nr_threads_synthesize == UINT_MAX)
+               thread_nr = sysconf(_SC_NPROCESSORS_ONLN);
+       else
+               thread_nr = nr_threads_synthesize;
+
+       if (thread_nr <= 1) {
+               err = __perf_event__synthesize_threads(tool, process,
+                                                      machine, mmap_data,
+                                                      proc_map_timeout,
+                                                      dirent, base, n);
+               goto free_dirent;
+       }
+       if (thread_nr > n)
+               thread_nr = n;
+
+       synthesize_threads = calloc(sizeof(pthread_t), thread_nr);
+       if (synthesize_threads == NULL)
+               goto free_dirent;
+
+       args = calloc(sizeof(*args), thread_nr);
+       if (args == NULL)
+               goto free_threads;
+
+       num_per_thread = n / thread_nr;
+       m = n % thread_nr;
+       for (i = 0; i < thread_nr; i++) {
+               args[i].tool = tool;
+               args[i].process = process;
+               args[i].machine = machine;
+               args[i].mmap_data = mmap_data;
+               args[i].proc_map_timeout = proc_map_timeout;
+               args[i].dirent = dirent;
+       }
+       for (i = 0; i < m; i++) {
+               args[i].num = num_per_thread + 1;
+               args[i].start = i * args[i].num;
+       }
+       if (i != 0)
+               base = args[i-1].start + args[i-1].num;
+       for (j = i; j < thread_nr; j++) {
+               args[j].num = num_per_thread;
+               args[j].start = base + (j - i) * args[i].num;
+       }
+
+       for (i = 0; i < thread_nr; i++) {
+               if (pthread_create(&synthesize_threads[i], NULL,
+                                  synthesize_threads_worker, &args[i]))
+                       goto out_join;
+       }
+       err = 0;
+out_join:
+       for (i = 0; i < thread_nr; i++)
+               pthread_join(synthesize_threads[i], NULL);
+       free(args);
+free_threads:
+       free(synthesize_threads);
+free_dirent:
+       for (i = 0; i < n; i++)
+               free(dirent[i]);
+       free(dirent);
+
+       return err;
+}
+
 struct process_symbol_args {
        const char *name;
        u64        start;
@@ -1498,6 +1605,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
        al->sym = NULL;
        al->cpu = sample->cpu;
        al->socket = -1;
+       al->srcline = NULL;
 
        if (al->cpu >= 0) {
                struct perf_env *env = machine->env;
index 5524ee69279c21d16d06d3dafb9d33d087045219..1ae95efbfb95d2c8a87dc807f5c5feb0f7f15abd 100644 (file)
@@ -681,7 +681,8 @@ int perf_event__synthesize_cpu_map(struct perf_tool *tool,
 int perf_event__synthesize_threads(struct perf_tool *tool,
                                   perf_event__handler_t process,
                                   struct machine *machine, bool mmap_data,
-                                  unsigned int proc_map_timeout);
+                                  unsigned int proc_map_timeout,
+                                  unsigned int nr_threads_synthesize);
 int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
                                       perf_event__handler_t process,
                                       struct machine *machine);
index 6a0d7ffbeba00e084054b4b8f7372c087c72510c..c6c891e154a63c67971c04512c0b576d5bf43087 100644 (file)
@@ -33,9 +33,6 @@
 #include <linux/log2.h>
 #include <linux/err.h>
 
-static void perf_mmap__munmap(struct perf_mmap *map);
-static void perf_mmap__put(struct perf_mmap *map);
-
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
 
@@ -704,129 +701,6 @@ static int perf_evlist__resume(struct perf_evlist *evlist)
        return perf_evlist__set_paused(evlist, false);
 }
 
-/* When check_messup is true, 'end' must points to a good entry */
-static union perf_event *
-perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start,
-               u64 end, u64 *prev)
-{
-       unsigned char *data = md->base + page_size;
-       union perf_event *event = NULL;
-       int diff = end - start;
-
-       if (check_messup) {
-               /*
-                * If we're further behind than half the buffer, there's a chance
-                * the writer will bite our tail and mess up the samples under us.
-                *
-                * If we somehow ended up ahead of the 'end', we got messed up.
-                *
-                * In either case, truncate and restart at 'end'.
-                */
-               if (diff > md->mask / 2 || diff < 0) {
-                       fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
-
-                       /*
-                        * 'end' points to a known good entry, start there.
-                        */
-                       start = end;
-                       diff = 0;
-               }
-       }
-
-       if (diff >= (int)sizeof(event->header)) {
-               size_t size;
-
-               event = (union perf_event *)&data[start & md->mask];
-               size = event->header.size;
-
-               if (size < sizeof(event->header) || diff < (int)size) {
-                       event = NULL;
-                       goto broken_event;
-               }
-
-               /*
-                * Event straddles the mmap boundary -- header should always
-                * be inside due to u64 alignment of output.
-                */
-               if ((start & md->mask) + size != ((start + size) & md->mask)) {
-                       unsigned int offset = start;
-                       unsigned int len = min(sizeof(*event), size), cpy;
-                       void *dst = md->event_copy;
-
-                       do {
-                               cpy = min(md->mask + 1 - (offset & md->mask), len);
-                               memcpy(dst, &data[offset & md->mask], cpy);
-                               offset += cpy;
-                               dst += cpy;
-                               len -= cpy;
-                       } while (len);
-
-                       event = (union perf_event *) md->event_copy;
-               }
-
-               start += size;
-       }
-
-broken_event:
-       if (prev)
-               *prev = start;
-
-       return event;
-}
-
-union perf_event *perf_mmap__read_forward(struct perf_mmap *md, bool check_messup)
-{
-       u64 head;
-       u64 old = md->prev;
-
-       /*
-        * Check if event was unmapped due to a POLLHUP/POLLERR.
-        */
-       if (!refcount_read(&md->refcnt))
-               return NULL;
-
-       head = perf_mmap__read_head(md);
-
-       return perf_mmap__read(md, check_messup, old, head, &md->prev);
-}
-
-union perf_event *
-perf_mmap__read_backward(struct perf_mmap *md)
-{
-       u64 head, end;
-       u64 start = md->prev;
-
-       /*
-        * Check if event was unmapped due to a POLLHUP/POLLERR.
-        */
-       if (!refcount_read(&md->refcnt))
-               return NULL;
-
-       head = perf_mmap__read_head(md);
-       if (!head)
-               return NULL;
-
-       /*
-        * 'head' pointer starts from 0. Kernel minus sizeof(record) form
-        * it each time when kernel writes to it, so in fact 'head' is
-        * negative. 'end' pointer is made manually by adding the size of
-        * the ring buffer to 'head' pointer, means the validate data can
-        * read is the whole ring buffer. If 'end' is positive, the ring
-        * buffer has not fully filled, so we must adjust 'end' to 0.
-        *
-        * However, since both 'head' and 'end' is unsigned, we can't
-        * simply compare 'end' against 0. Here we compare '-head' and
-        * the size of the ring buffer, where -head is the number of bytes
-        * kernel write to the ring buffer.
-        */
-       if (-head < (u64)(md->mask + 1))
-               end = 0;
-       else
-               end = head + md->mask + 1;
-
-       return perf_mmap__read(md, false, start, end, &md->prev);
-}
-
 union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int idx)
 {
        struct perf_mmap *md = &evlist->mmap[idx];
@@ -857,96 +731,16 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
        return perf_evlist__mmap_read_forward(evlist, idx);
 }
 
-void perf_mmap__read_catchup(struct perf_mmap *md)
-{
-       u64 head;
-
-       if (!refcount_read(&md->refcnt))
-               return;
-
-       head = perf_mmap__read_head(md);
-       md->prev = head;
-}
-
 void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx)
 {
        perf_mmap__read_catchup(&evlist->mmap[idx]);
 }
 
-static bool perf_mmap__empty(struct perf_mmap *md)
-{
-       return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base;
-}
-
-static void perf_mmap__get(struct perf_mmap *map)
-{
-       refcount_inc(&map->refcnt);
-}
-
-static void perf_mmap__put(struct perf_mmap *md)
-{
-       BUG_ON(md->base && refcount_read(&md->refcnt) == 0);
-
-       if (refcount_dec_and_test(&md->refcnt))
-               perf_mmap__munmap(md);
-}
-
-void perf_mmap__consume(struct perf_mmap *md, bool overwrite)
-{
-       if (!overwrite) {
-               u64 old = md->prev;
-
-               perf_mmap__write_tail(md, old);
-       }
-
-       if (refcount_read(&md->refcnt) == 1 && perf_mmap__empty(md))
-               perf_mmap__put(md);
-}
-
 void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
 {
        perf_mmap__consume(&evlist->mmap[idx], evlist->overwrite);
 }
 
-int __weak auxtrace_mmap__mmap(struct auxtrace_mmap *mm __maybe_unused,
-                              struct auxtrace_mmap_params *mp __maybe_unused,
-                              void *userpg __maybe_unused,
-                              int fd __maybe_unused)
-{
-       return 0;
-}
-
-void __weak auxtrace_mmap__munmap(struct auxtrace_mmap *mm __maybe_unused)
-{
-}
-
-void __weak auxtrace_mmap_params__init(
-                       struct auxtrace_mmap_params *mp __maybe_unused,
-                       off_t auxtrace_offset __maybe_unused,
-                       unsigned int auxtrace_pages __maybe_unused,
-                       bool auxtrace_overwrite __maybe_unused)
-{
-}
-
-void __weak auxtrace_mmap_params__set_idx(
-                       struct auxtrace_mmap_params *mp __maybe_unused,
-                       struct perf_evlist *evlist __maybe_unused,
-                       int idx __maybe_unused,
-                       bool per_cpu __maybe_unused)
-{
-}
-
-static void perf_mmap__munmap(struct perf_mmap *map)
-{
-       if (map->base != NULL) {
-               munmap(map->base, perf_mmap__mmap_len(map));
-               map->base = NULL;
-               map->fd = -1;
-               refcount_set(&map->refcnt, 0);
-       }
-       auxtrace_mmap__munmap(&map->auxtrace_mmap);
-}
-
 static void perf_evlist__munmap_nofree(struct perf_evlist *evlist)
 {
        int i;
@@ -995,48 +789,6 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist)
        return map;
 }
 
-struct mmap_params {
-       int prot;
-       int mask;
-       struct auxtrace_mmap_params auxtrace_mp;
-};
-
-static int perf_mmap__mmap(struct perf_mmap *map,
-                          struct mmap_params *mp, int fd)
-{
-       /*
-        * The last one will be done at perf_evlist__mmap_consume(), so that we
-        * make sure we don't prevent tools from consuming every last event in
-        * the ring buffer.
-        *
-        * I.e. we can get the POLLHUP meaning that the fd doesn't exist
-        * anymore, but the last events for it are still in the ring buffer,
-        * waiting to be consumed.
-        *
-        * Tools can chose to ignore this at their own discretion, but the
-        * evlist layer can't just drop it when filtering events in
-        * perf_evlist__filter_pollfd().
-        */
-       refcount_set(&map->refcnt, 2);
-       map->prev = 0;
-       map->mask = mp->mask;
-       map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot,
-                        MAP_SHARED, fd, 0);
-       if (map->base == MAP_FAILED) {
-               pr_debug2("failed to mmap perf event ring buffer, error %d\n",
-                         errno);
-               map->base = NULL;
-               return -1;
-       }
-       map->fd = fd;
-
-       if (auxtrace_mmap__mmap(&map->auxtrace_mmap,
-                               &mp->auxtrace_mp, map->base, fd))
-               return -1;
-
-       return 0;
-}
-
 static bool
 perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused,
                         struct perf_evsel *evsel)
index c1750a400bb768edcd3f802b3367e85ae10032eb..e72ae64c11acb5214d82996d9c21498b1d34547e 100644 (file)
@@ -7,12 +7,13 @@
 #include <linux/refcount.h>
 #include <linux/list.h>
 #include <api/fd/array.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include "../perf.h"
 #include "event.h"
 #include "evsel.h"
+#include "mmap.h"
 #include "util.h"
-#include "auxtrace.h"
 #include <signal.h>
 #include <unistd.h>
 
@@ -24,55 +25,6 @@ struct record_opts;
 #define PERF_EVLIST__HLIST_BITS 8
 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
 
-/**
- * struct perf_mmap - perf's ring buffer mmap details
- *
- * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this
- */
-struct perf_mmap {
-       void             *base;
-       int              mask;
-       int              fd;
-       refcount_t       refcnt;
-       u64              prev;
-       struct auxtrace_mmap auxtrace_mmap;
-       char             event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
-};
-
-static inline size_t
-perf_mmap__mmap_len(struct perf_mmap *map)
-{
-       return map->mask + 1 + page_size;
-}
-
-/*
- * State machine of bkw_mmap_state:
- *
- *                     .________________(forbid)_____________.
- *                     |                                     V
- * NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY
- *                     ^  ^              |   ^               |
- *                     |  |__(forbid)____/   |___(forbid)___/|
- *                     |                                     |
- *                      \_________________(3)_______________/
- *
- * NOTREADY     : Backward ring buffers are not ready
- * RUNNING      : Backward ring buffers are recording
- * DATA_PENDING : We are required to collect data from backward ring buffers
- * EMPTY        : We have collected data from backward ring buffers.
- *
- * (0): Setup backward ring buffer
- * (1): Pause ring buffers for reading
- * (2): Read from ring buffers
- * (3): Resume ring buffers for recording
- */
-enum bkw_mmap_state {
-       BKW_MMAP_NOTREADY,
-       BKW_MMAP_RUNNING,
-       BKW_MMAP_DATA_PENDING,
-       BKW_MMAP_EMPTY,
-};
-
 struct perf_evlist {
        struct list_head entries;
        struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
@@ -177,12 +129,6 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
 
 void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, enum bkw_mmap_state state);
 
-union perf_event *perf_mmap__read_forward(struct perf_mmap *map, bool check_messup);
-union perf_event *perf_mmap__read_backward(struct perf_mmap *map);
-
-void perf_mmap__read_catchup(struct perf_mmap *md);
-void perf_mmap__consume(struct perf_mmap *md, bool overwrite);
-
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx);
 
 union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist,
@@ -286,25 +232,6 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
 int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size);
 int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size);
 
-static inline u64 perf_mmap__read_head(struct perf_mmap *mm)
-{
-       struct perf_event_mmap_page *pc = mm->base;
-       u64 head = ACCESS_ONCE(pc->data_head);
-       rmb();
-       return head;
-}
-
-static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail)
-{
-       struct perf_event_mmap_page *pc = md->base;
-
-       /*
-        * ensure all reads are done before we write the tail out.
-        */
-       mb();
-       pc->data_tail = tail;
-}
-
 bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str);
 void perf_evlist__to_front(struct perf_evlist *evlist,
                           struct perf_evsel *move_evsel);
index 0dccdb89572cdb455724a6a48a86d96821fc53e2..f894893c203d13e00259d356414a8b781066fa5a 100644 (file)
@@ -683,7 +683,7 @@ void perf_evsel__config_callchain(struct perf_evsel *evsel,
                if (!function) {
                        perf_evsel__set_sample_bit(evsel, REGS_USER);
                        perf_evsel__set_sample_bit(evsel, STACK_USER);
-                       attr->sample_regs_user = PERF_REGS_MASK;
+                       attr->sample_regs_user |= PERF_REGS_MASK;
                        attr->sample_stack_user = param->dump_size;
                        attr->exclude_callchain_user = 1;
                } else {
@@ -936,6 +936,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
                perf_evsel__set_sample_bit(evsel, REGS_INTR);
        }
 
+       if (opts->sample_user_regs) {
+               attr->sample_regs_user |= opts->sample_user_regs;
+               perf_evsel__set_sample_bit(evsel, REGS_USER);
+       }
+
        if (target__has_cpu(&opts->target) || opts->sample_cpu)
                perf_evsel__set_sample_bit(evsel, CPU);
 
index b4df79d723297f4fbe2910efe26528bc1f0c0d06..9277df96ffdad90a4899e922b574156bb708ef86 100644 (file)
@@ -69,6 +69,8 @@ struct perf_evsel_config_term {
        } val;
 };
 
+struct perf_stat_evsel;
+
 /** struct perf_evsel - event selector
  *
  * @evlist - evlist this evsel is in, if it is in one.
@@ -102,6 +104,7 @@ struct perf_evsel {
        const char              *unit;
        struct event_format     *tp_format;
        off_t                   id_offset;
+       struct perf_stat_evsel  *stats;
        void                    *priv;
        u64                     db_id;
        struct cgroup_sel       *cgrp;
@@ -138,6 +141,7 @@ struct perf_evsel {
        const char *            metric_name;
        struct perf_evsel       **metric_events;
        bool                    collect_stat;
+       bool                    weak_group;
 };
 
 union u64_swap {
index 1fd7c2e46db265ddb39440fea5c6c0b6c37e891c..06dfb027879d018f6afb0a6404cac778ab96a7e3 100644 (file)
@@ -158,7 +158,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
                                }
                        }
 
-                       if (print_dso) {
+                       if (print_dso && (!node->sym || !node->sym->inlined)) {
                                printed += fprintf(fp, " (");
                                printed += map__fprintf_dsoname(node->map, fp);
                                printed += fprintf(fp, ")");
@@ -167,41 +167,12 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
                        if (print_srcline)
                                printed += map__fprintf_srcline(node->map, addr, "\n  ", fp);
 
+                       if (node->sym && node->sym->inlined)
+                               printed += fprintf(fp, " (inlined)");
+
                        if (!print_oneline)
                                printed += fprintf(fp, "\n");
 
-                       if (symbol_conf.inline_name && node->map) {
-                               struct inline_node *inode;
-
-                               addr = map__rip_2objdump(node->map, node->ip),
-                               inode = dso__parse_addr_inlines(node->map->dso, addr);
-
-                               if (inode) {
-                                       struct inline_list *ilist;
-
-                                       list_for_each_entry(ilist, &inode->val, list) {
-                                               if (print_arrow)
-                                                       printed += fprintf(fp, " <-");
-
-                                               /* IP is same, just skip it */
-                                               if (print_ip)
-                                                       printed += fprintf(fp, "%c%16s",
-                                                                          s, "");
-                                               if (print_sym)
-                                                       printed += fprintf(fp, " %s",
-                                                                          ilist->funcname);
-                                               if (print_srcline)
-                                                       printed += fprintf(fp, "\n  %s:%d",
-                                                                          ilist->filename,
-                                                                          ilist->line_nr);
-                                               if (!print_oneline)
-                                                       printed += fprintf(fp, "\n");
-                                       }
-
-                                       inline_node__delete(inode);
-                               }
-                       }
-
                        if (symbol_conf.bt_stop_list &&
                            node->sym &&
                            strlist__has_entry(symbol_conf.bt_stop_list,
index ba0cea8fef724f26499f8e14c74484d8bb9601a8..7c0e9d587bfaf06f1aa74219cb8a01723ea63f20 100644 (file)
@@ -1763,7 +1763,7 @@ process_event_desc(struct feat_fd *ff, void *data __maybe_unused)
 
        session = container_of(ff->ph, struct perf_session, header);
 
-       if (session->file->is_pipe) {
+       if (session->data->is_pipe) {
                /* Save events for reading later by print_event_desc,
                 * since they can't be read again in pipe mode. */
                ff->events = events;
@@ -1772,7 +1772,7 @@ process_event_desc(struct feat_fd *ff, void *data __maybe_unused)
        for (evsel = events; evsel->attr.size; evsel++)
                perf_evlist__set_event_name(session->evlist, evsel);
 
-       if (!session->file->is_pipe)
+       if (!session->data->is_pipe)
                free_event_desc(events);
 
        return 0;
@@ -2249,7 +2249,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
 {
        struct header_print_data hd;
        struct perf_header *header = &session->header;
-       int fd = perf_data_file__fd(session->file);
+       int fd = perf_data__fd(session->data);
        struct stat st;
        int ret, bit;
 
@@ -2265,7 +2265,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
        perf_header__process_sections(header, fd, &hd,
                                      perf_file_section__fprintf_info);
 
-       if (session->file->is_pipe)
+       if (session->data->is_pipe)
                return 0;
 
        fprintf(fp, "# missing features: ");
@@ -2758,7 +2758,7 @@ static int perf_header__read_pipe(struct perf_session *session)
        struct perf_pipe_file_header f_header;
 
        if (perf_file_header__read_pipe(&f_header, header,
-                                       perf_data_file__fd(session->file),
+                                       perf_data__fd(session->data),
                                        session->repipe) < 0) {
                pr_debug("incompatible file format\n");
                return -EINVAL;
@@ -2861,13 +2861,13 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
 
 int perf_session__read_header(struct perf_session *session)
 {
-       struct perf_data_file *file = session->file;
+       struct perf_data *data = session->data;
        struct perf_header *header = &session->header;
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
        u64                     f_id;
        int nr_attrs, nr_ids, i, j;
-       int fd = perf_data_file__fd(file);
+       int fd = perf_data__fd(data);
 
        session->evlist = perf_evlist__new();
        if (session->evlist == NULL)
@@ -2875,7 +2875,7 @@ int perf_session__read_header(struct perf_session *session)
 
        session->evlist->env = &header->env;
        session->machines.host.env = &header->env;
-       if (perf_data_file__is_pipe(file))
+       if (perf_data__is_pipe(data))
                return perf_header__read_pipe(session);
 
        if (perf_file_header__read(&f_header, header, fd) < 0)
@@ -2890,7 +2890,7 @@ int perf_session__read_header(struct perf_session *session)
        if (f_header.data.size == 0) {
                pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
                           "Was the 'perf record' command properly terminated?\n",
-                          file->path);
+                          data->file.path);
        }
 
        nr_attrs = f_header.attrs.size / f_header.attr_size;
@@ -3398,7 +3398,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
                                     struct perf_session *session)
 {
        ssize_t size_read, padding, size = event->tracing_data.size;
-       int fd = perf_data_file__fd(session->file);
+       int fd = perf_data__fd(session->data);
        off_t offset = lseek(fd, 0, SEEK_CUR);
        char buf[BUFSIZ];
 
index 097473600d943fc558140e3fde742636a2894d1d..b6140950301eec7b41c325fbe75f02bc8f2ecac6 100644 (file)
@@ -597,6 +597,7 @@ __hists__add_entry(struct hists *hists,
                        .map    = al->map,
                        .sym    = al->sym,
                },
+               .srcline = al->srcline ? strdup(al->srcline) : NULL,
                .socket  = al->socket,
                .cpu     = al->cpu,
                .cpumode = al->cpumode,
@@ -951,6 +952,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
                        .map = al->map,
                        .sym = al->sym,
                },
+               .srcline = al->srcline ? strdup(al->srcline) : NULL,
                .parent = iter->parent,
                .raw_data = sample->raw_data,
                .raw_size = sample->raw_size,
@@ -1142,11 +1144,6 @@ void hist_entry__delete(struct hist_entry *he)
                zfree(&he->mem_info);
        }
 
-       if (he->inline_node) {
-               inline_node__delete(he->inline_node);
-               he->inline_node = NULL;
-       }
-
        zfree(&he->stat_acc);
        free_srcline(he->srcline);
        if (he->srcfile && he->srcfile[0])
index 218ee2bac9a5c9ff8c1005508555755465c2b573..5325e65f97110d95ea55173045fbac22d239d0f1 100644 (file)
@@ -500,7 +500,7 @@ static int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp)
        }
 
        if (!buffer->data) {
-               int fd = perf_data_file__fd(btsq->bts->session->file);
+               int fd = perf_data__fd(btsq->bts->session->data);
 
                buffer->data = auxtrace_buffer__get_data(buffer, fd);
                if (!buffer->data) {
@@ -664,10 +664,10 @@ static int intel_bts_process_auxtrace_event(struct perf_session *session,
        if (!bts->data_queued) {
                struct auxtrace_buffer *buffer;
                off_t data_offset;
-               int fd = perf_data_file__fd(session->file);
+               int fd = perf_data__fd(session->data);
                int err;
 
-               if (perf_data_file__is_pipe(session->file)) {
+               if (perf_data__is_pipe(session->data)) {
                        data_offset = 0;
                } else {
                        data_offset = lseek(fd, 0, SEEK_CUR);
index b58f9fd1e2eefb7710b55111f87ff7559e0250a7..23f9ba676df0d8b8b3b7bfba0a12304526b733fe 100644 (file)
@@ -271,7 +271,7 @@ next:
        ptq->buffer = buffer;
 
        if (!buffer->data) {
-               int fd = perf_data_file__fd(ptq->pt->session->file);
+               int fd = perf_data__fd(ptq->pt->session->data);
 
                buffer->data = auxtrace_buffer__get_data(buffer, fd);
                if (!buffer->data)
@@ -2084,10 +2084,10 @@ static int intel_pt_process_auxtrace_event(struct perf_session *session,
        if (!pt->data_queued) {
                struct auxtrace_buffer *buffer;
                off_t data_offset;
-               int fd = perf_data_file__fd(session->file);
+               int fd = perf_data__fd(session->data);
                int err;
 
-               if (perf_data_file__is_pipe(session->file)) {
+               if (perf_data__is_pipe(session->data)) {
                        data_offset = 0;
                } else {
                        data_offset = lseek(fd, 0, SEEK_CUR);
index c2582fa9fe21bcca2125b62289c1f0d40e02d991..6817ffc2a059fb67c1793b836d665af8df8ab716 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <data.h>
 
-int jit_process(struct perf_session *session, struct perf_data_file *output,
+int jit_process(struct perf_session *session, struct perf_data *output,
                struct machine *machine, char *filename, pid_t pid, u64 *nbytes);
 
 int jit_inject_record(const char *filename);
index 36483db032e865728be003bfb2abea97c93b9114..a1863000e972dbca938ed0003fb3632bf25e35c0 100644 (file)
@@ -30,7 +30,7 @@
 #include "sane_ctype.h"
 
 struct jit_buf_desc {
-       struct perf_data_file *output;
+       struct perf_data *output;
        struct perf_session *session;
        struct machine *machine;
        union jr_entry   *entry;
@@ -61,8 +61,8 @@ struct debug_line_info {
 
 struct jit_tool {
        struct perf_tool tool;
-       struct perf_data_file   output;
-       struct perf_data_file   input;
+       struct perf_data        output;
+       struct perf_data        input;
        u64 bytes_written;
 };
 
@@ -357,7 +357,7 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
 {
        ssize_t size;
 
-       size = perf_data_file__write(jd->output, event, event->header.size);
+       size = perf_data__write(jd->output, event, event->header.size);
        if (size < 0)
                return -1;
 
@@ -752,7 +752,7 @@ jit_detect(char *mmap_name, pid_t pid)
 
 int
 jit_process(struct perf_session *session,
-           struct perf_data_file *output,
+           struct perf_data *output,
            struct machine *machine,
            char *filename,
            pid_t pid,
index bd5d5b5e2218c89e9ccc8cc216db41f8a88044d7..6a8d03c3d9b7095961b07a4d648eadc6f857e868 100644 (file)
@@ -31,7 +31,21 @@ static void dsos__init(struct dsos *dsos)
 {
        INIT_LIST_HEAD(&dsos->head);
        dsos->root = RB_ROOT;
-       pthread_rwlock_init(&dsos->lock, NULL);
+       init_rwsem(&dsos->lock);
+}
+
+static void machine__threads_init(struct machine *machine)
+{
+       int i;
+
+       for (i = 0; i < THREADS__TABLE_SIZE; i++) {
+               struct threads *threads = &machine->threads[i];
+               threads->entries = RB_ROOT;
+               init_rwsem(&threads->lock);
+               threads->nr = 0;
+               INIT_LIST_HEAD(&threads->dead);
+               threads->last_match = NULL;
+       }
 }
 
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
@@ -41,11 +55,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
        RB_CLEAR_NODE(&machine->rb_node);
        dsos__init(&machine->dsos);
 
-       machine->threads = RB_ROOT;
-       pthread_rwlock_init(&machine->threads_lock, NULL);
-       machine->nr_threads = 0;
-       INIT_LIST_HEAD(&machine->dead_threads);
-       machine->last_match = NULL;
+       machine__threads_init(machine);
 
        machine->vdso_info = NULL;
        machine->env = NULL;
@@ -121,7 +131,7 @@ static void dsos__purge(struct dsos *dsos)
 {
        struct dso *pos, *n;
 
-       pthread_rwlock_wrlock(&dsos->lock);
+       down_write(&dsos->lock);
 
        list_for_each_entry_safe(pos, n, &dsos->head, node) {
                RB_CLEAR_NODE(&pos->rb_node);
@@ -130,39 +140,49 @@ static void dsos__purge(struct dsos *dsos)
                dso__put(pos);
        }
 
-       pthread_rwlock_unlock(&dsos->lock);
+       up_write(&dsos->lock);
 }
 
 static void dsos__exit(struct dsos *dsos)
 {
        dsos__purge(dsos);
-       pthread_rwlock_destroy(&dsos->lock);
+       exit_rwsem(&dsos->lock);
 }
 
 void machine__delete_threads(struct machine *machine)
 {
        struct rb_node *nd;
+       int i;
 
-       pthread_rwlock_wrlock(&machine->threads_lock);
-       nd = rb_first(&machine->threads);
-       while (nd) {
-               struct thread *t = rb_entry(nd, struct thread, rb_node);
+       for (i = 0; i < THREADS__TABLE_SIZE; i++) {
+               struct threads *threads = &machine->threads[i];
+               down_write(&threads->lock);
+               nd = rb_first(&threads->entries);
+               while (nd) {
+                       struct thread *t = rb_entry(nd, struct thread, rb_node);
 
-               nd = rb_next(nd);
-               __machine__remove_thread(machine, t, false);
+                       nd = rb_next(nd);
+                       __machine__remove_thread(machine, t, false);
+               }
+               up_write(&threads->lock);
        }
-       pthread_rwlock_unlock(&machine->threads_lock);
 }
 
 void machine__exit(struct machine *machine)
 {
+       int i;
+
        machine__destroy_kernel_maps(machine);
        map_groups__exit(&machine->kmaps);
        dsos__exit(&machine->dsos);
        machine__exit_vdso(machine);
        zfree(&machine->root_dir);
        zfree(&machine->current_tid);
-       pthread_rwlock_destroy(&machine->threads_lock);
+
+       for (i = 0; i < THREADS__TABLE_SIZE; i++) {
+               struct threads *threads = &machine->threads[i];
+               exit_rwsem(&threads->lock);
+       }
 }
 
 void machine__delete(struct machine *machine)
@@ -380,10 +400,11 @@ out_err:
  * lookup/new thread inserted.
  */
 static struct thread *____machine__findnew_thread(struct machine *machine,
+                                                 struct threads *threads,
                                                  pid_t pid, pid_t tid,
                                                  bool create)
 {
-       struct rb_node **p = &machine->threads.rb_node;
+       struct rb_node **p = &threads->entries.rb_node;
        struct rb_node *parent = NULL;
        struct thread *th;
 
@@ -392,14 +413,14 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
         * so most of the time we dont have to look up
         * the full rbtree:
         */
-       th = machine->last_match;
+       th = threads->last_match;
        if (th != NULL) {
                if (th->tid == tid) {
                        machine__update_thread_pid(machine, th, pid);
                        return thread__get(th);
                }
 
-               machine->last_match = NULL;
+               threads->last_match = NULL;
        }
 
        while (*p != NULL) {
@@ -407,7 +428,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
                th = rb_entry(parent, struct thread, rb_node);
 
                if (th->tid == tid) {
-                       machine->last_match = th;
+                       threads->last_match = th;
                        machine__update_thread_pid(machine, th, pid);
                        return thread__get(th);
                }
@@ -424,7 +445,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
        th = thread__new(pid, tid);
        if (th != NULL) {
                rb_link_node(&th->rb_node, parent, p);
-               rb_insert_color(&th->rb_node, &machine->threads);
+               rb_insert_color(&th->rb_node, &threads->entries);
 
                /*
                 * We have to initialize map_groups separately
@@ -435,7 +456,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
                 * leader and that would screwed the rb tree.
                 */
                if (thread__init_map_groups(th, machine)) {
-                       rb_erase_init(&th->rb_node, &machine->threads);
+                       rb_erase_init(&th->rb_node, &threads->entries);
                        RB_CLEAR_NODE(&th->rb_node);
                        thread__put(th);
                        return NULL;
@@ -444,8 +465,8 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
                 * It is now in the rbtree, get a ref
                 */
                thread__get(th);
-               machine->last_match = th;
-               ++machine->nr_threads;
+               threads->last_match = th;
+               ++threads->nr;
        }
 
        return th;
@@ -453,27 +474,30 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
 
 struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid)
 {
-       return ____machine__findnew_thread(machine, pid, tid, true);
+       return ____machine__findnew_thread(machine, machine__threads(machine, tid), pid, tid, true);
 }
 
 struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
                                       pid_t tid)
 {
+       struct threads *threads = machine__threads(machine, tid);
        struct thread *th;
 
-       pthread_rwlock_wrlock(&machine->threads_lock);
+       down_write(&threads->lock);
        th = __machine__findnew_thread(machine, pid, tid);
-       pthread_rwlock_unlock(&machine->threads_lock);
+       up_write(&threads->lock);
        return th;
 }
 
 struct thread *machine__find_thread(struct machine *machine, pid_t pid,
                                    pid_t tid)
 {
+       struct threads *threads = machine__threads(machine, tid);
        struct thread *th;
-       pthread_rwlock_rdlock(&machine->threads_lock);
-       th =  ____machine__findnew_thread(machine, pid, tid, false);
-       pthread_rwlock_unlock(&machine->threads_lock);
+
+       down_read(&threads->lock);
+       th =  ____machine__findnew_thread(machine, threads, pid, tid, false);
+       up_read(&threads->lock);
        return th;
 }
 
@@ -565,7 +589,7 @@ static struct dso *machine__findnew_module_dso(struct machine *machine,
 {
        struct dso *dso;
 
-       pthread_rwlock_wrlock(&machine->dsos.lock);
+       down_write(&machine->dsos.lock);
 
        dso = __dsos__find(&machine->dsos, m->name, true);
        if (!dso) {
@@ -579,7 +603,7 @@ static struct dso *machine__findnew_module_dso(struct machine *machine,
 
        dso__get(dso);
 out_unlock:
-       pthread_rwlock_unlock(&machine->dsos.lock);
+       up_write(&machine->dsos.lock);
        return dso;
 }
 
@@ -720,21 +744,25 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
 
 size_t machine__fprintf(struct machine *machine, FILE *fp)
 {
-       size_t ret;
        struct rb_node *nd;
+       size_t ret;
+       int i;
 
-       pthread_rwlock_rdlock(&machine->threads_lock);
+       for (i = 0; i < THREADS__TABLE_SIZE; i++) {
+               struct threads *threads = &machine->threads[i];
 
-       ret = fprintf(fp, "Threads: %u\n", machine->nr_threads);
+               down_read(&threads->lock);
 
-       for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
-               struct thread *pos = rb_entry(nd, struct thread, rb_node);
+               ret = fprintf(fp, "Threads: %u\n", threads->nr);
 
-               ret += thread__fprintf(pos, fp);
-       }
+               for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
+                       struct thread *pos = rb_entry(nd, struct thread, rb_node);
 
-       pthread_rwlock_unlock(&machine->threads_lock);
+                       ret += thread__fprintf(pos, fp);
+               }
 
+               up_read(&threads->lock);
+       }
        return ret;
 }
 
@@ -1293,7 +1321,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
                struct dso *kernel = NULL;
                struct dso *dso;
 
-               pthread_rwlock_rdlock(&machine->dsos.lock);
+               down_read(&machine->dsos.lock);
 
                list_for_each_entry(dso, &machine->dsos.head, node) {
 
@@ -1323,7 +1351,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
                        break;
                }
 
-               pthread_rwlock_unlock(&machine->dsos.lock);
+               up_read(&machine->dsos.lock);
 
                if (kernel == NULL)
                        kernel = machine__findnew_dso(machine, kmmap_prefix);
@@ -1480,23 +1508,25 @@ out_problem:
 
 static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock)
 {
-       if (machine->last_match == th)
-               machine->last_match = NULL;
+       struct threads *threads = machine__threads(machine, th->tid);
+
+       if (threads->last_match == th)
+               threads->last_match = NULL;
 
        BUG_ON(refcount_read(&th->refcnt) == 0);
        if (lock)
-               pthread_rwlock_wrlock(&machine->threads_lock);
-       rb_erase_init(&th->rb_node, &machine->threads);
+               down_write(&threads->lock);
+       rb_erase_init(&th->rb_node, &threads->entries);
        RB_CLEAR_NODE(&th->rb_node);
-       --machine->nr_threads;
+       --threads->nr;
        /*
         * Move it first to the dead_threads list, then drop the reference,
         * if this is the last reference, then the thread__delete destructor
         * will be called and we will remove it from the dead_threads list.
         */
-       list_add_tail(&th->node, &machine->dead_threads);
+       list_add_tail(&th->node, &threads->dead);
        if (lock)
-               pthread_rwlock_unlock(&machine->threads_lock);
+               up_write(&threads->lock);
        thread__put(th);
 }
 
@@ -1680,6 +1710,26 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample,
        return mi;
 }
 
+static char *callchain_srcline(struct map *map, struct symbol *sym, u64 ip)
+{
+       char *srcline = NULL;
+
+       if (!map || callchain_param.key == CCKEY_FUNCTION)
+               return srcline;
+
+       srcline = srcline__tree_find(&map->dso->srclines, ip);
+       if (!srcline) {
+               bool show_sym = false;
+               bool show_addr = callchain_param.key == CCKEY_ADDRESS;
+
+               srcline = get_srcline(map->dso, map__rip_2objdump(map, ip),
+                                     sym, show_sym, show_addr);
+               srcline__tree_insert(&map->dso->srclines, ip, srcline);
+       }
+
+       return srcline;
+}
+
 struct iterations {
        int nr_loop_iter;
        u64 cycles;
@@ -1699,6 +1749,7 @@ static int add_callchain_ip(struct thread *thread,
        struct addr_location al;
        int nr_loop_iter = 0;
        u64 iter_cycles = 0;
+       const char *srcline = NULL;
 
        al.filtered = 0;
        al.sym = NULL;
@@ -1754,9 +1805,10 @@ static int add_callchain_ip(struct thread *thread,
                iter_cycles = iter->cycles;
        }
 
+       srcline = callchain_srcline(al.map, al.sym, al.addr);
        return callchain_cursor_append(cursor, al.addr, al.map, al.sym,
                                       branch, flags, nr_loop_iter,
-                                      iter_cycles, branch_from);
+                                      iter_cycles, branch_from, srcline);
 }
 
 struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
@@ -2069,15 +2121,54 @@ check_calls:
        return 0;
 }
 
+static int append_inlines(struct callchain_cursor *cursor,
+                         struct map *map, struct symbol *sym, u64 ip)
+{
+       struct inline_node *inline_node;
+       struct inline_list *ilist;
+       u64 addr;
+       int ret = 1;
+
+       if (!symbol_conf.inline_name || !map || !sym)
+               return ret;
+
+       addr = map__rip_2objdump(map, ip);
+
+       inline_node = inlines__tree_find(&map->dso->inlined_nodes, addr);
+       if (!inline_node) {
+               inline_node = dso__parse_addr_inlines(map->dso, addr, sym);
+               if (!inline_node)
+                       return ret;
+               inlines__tree_insert(&map->dso->inlined_nodes, inline_node);
+       }
+
+       list_for_each_entry(ilist, &inline_node->val, list) {
+               ret = callchain_cursor_append(cursor, ip, map,
+                                             ilist->symbol, false,
+                                             NULL, 0, 0, 0, ilist->srcline);
+
+               if (ret != 0)
+                       return ret;
+       }
+
+       return ret;
+}
+
 static int unwind_entry(struct unwind_entry *entry, void *arg)
 {
        struct callchain_cursor *cursor = arg;
+       const char *srcline = NULL;
 
        if (symbol_conf.hide_unresolved && entry->sym == NULL)
                return 0;
+
+       if (append_inlines(cursor, entry->map, entry->sym, entry->ip) == 0)
+               return 0;
+
+       srcline = callchain_srcline(entry->map, entry->sym, entry->ip);
        return callchain_cursor_append(cursor, entry->ip,
                                       entry->map, entry->sym,
-                                      false, NULL, 0, 0, 0);
+                                      false, NULL, 0, 0, 0, srcline);
 }
 
 static int thread__resolve_callchain_unwind(struct thread *thread,
@@ -2141,21 +2232,26 @@ int machine__for_each_thread(struct machine *machine,
                             int (*fn)(struct thread *thread, void *p),
                             void *priv)
 {
+       struct threads *threads;
        struct rb_node *nd;
        struct thread *thread;
        int rc = 0;
+       int i;
 
-       for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
-               thread = rb_entry(nd, struct thread, rb_node);
-               rc = fn(thread, priv);
-               if (rc != 0)
-                       return rc;
-       }
+       for (i = 0; i < THREADS__TABLE_SIZE; i++) {
+               threads = &machine->threads[i];
+               for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
+                       thread = rb_entry(nd, struct thread, rb_node);
+                       rc = fn(thread, priv);
+                       if (rc != 0)
+                               return rc;
+               }
 
-       list_for_each_entry(thread, &machine->dead_threads, node) {
-               rc = fn(thread, priv);
-               if (rc != 0)
-                       return rc;
+               list_for_each_entry(thread, &threads->dead, node) {
+                       rc = fn(thread, priv);
+                       if (rc != 0)
+                               return rc;
+               }
        }
        return rc;
 }
@@ -2184,12 +2280,16 @@ int machines__for_each_thread(struct machines *machines,
 int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
                                  struct target *target, struct thread_map *threads,
                                  perf_event__handler_t process, bool data_mmap,
-                                 unsigned int proc_map_timeout)
+                                 unsigned int proc_map_timeout,
+                                 unsigned int nr_threads_synthesize)
 {
        if (target__has_task(target))
                return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap, proc_map_timeout);
        else if (target__has_cpu(target))
-               return perf_event__synthesize_threads(tool, process, machine, data_mmap, proc_map_timeout);
+               return perf_event__synthesize_threads(tool, process,
+                                                     machine, data_mmap,
+                                                     proc_map_timeout,
+                                                     nr_threads_synthesize);
        /* command specified */
        return 0;
 }
index d551aa80a59bab2a3982e4268d005b173948a540..5ce860b64c74171ec47d61fe11ad18711f2c94b3 100644 (file)
@@ -7,6 +7,7 @@
 #include "map.h"
 #include "dso.h"
 #include "event.h"
+#include "rwsem.h"
 
 struct addr_location;
 struct branch_stack;
@@ -24,6 +25,17 @@ extern const char *ref_reloc_sym_names[];
 
 struct vdso_info;
 
+#define THREADS__TABLE_BITS    8
+#define THREADS__TABLE_SIZE    (1 << THREADS__TABLE_BITS)
+
+struct threads {
+       struct rb_root    entries;
+       struct rw_semaphore lock;
+       unsigned int      nr;
+       struct list_head  dead;
+       struct thread     *last_match;
+};
+
 struct machine {
        struct rb_node    rb_node;
        pid_t             pid;
@@ -31,11 +43,7 @@ struct machine {
        bool              comm_exec;
        bool              kptr_restrict_warned;
        char              *root_dir;
-       struct rb_root    threads;
-       pthread_rwlock_t  threads_lock;
-       unsigned int      nr_threads;
-       struct list_head  dead_threads;
-       struct thread     *last_match;
+       struct threads    threads[THREADS__TABLE_SIZE];
        struct vdso_info  *vdso_info;
        struct perf_env   *env;
        struct dsos       dsos;
@@ -49,6 +57,12 @@ struct machine {
        };
 };
 
+static inline struct threads *machine__threads(struct machine *machine, pid_t tid)
+{
+       /* Cast it to handle tid == -1 */
+       return &machine->threads[(unsigned int)tid % THREADS__TABLE_SIZE];
+}
+
 static inline
 struct map *__machine__kernel_map(struct machine *machine, enum map_type type)
 {
@@ -244,15 +258,18 @@ int machines__for_each_thread(struct machines *machines,
 int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
                                  struct target *target, struct thread_map *threads,
                                  perf_event__handler_t process, bool data_mmap,
-                                 unsigned int proc_map_timeout);
+                                 unsigned int proc_map_timeout,
+                                 unsigned int nr_threads_synthesize);
 static inline
 int machine__synthesize_threads(struct machine *machine, struct target *target,
                                struct thread_map *threads, bool data_mmap,
-                               unsigned int proc_map_timeout)
+                               unsigned int proc_map_timeout,
+                               unsigned int nr_threads_synthesize)
 {
        return __machine__synthesize_threads(machine, NULL, target, threads,
                                             perf_event__process, data_mmap,
-                                            proc_map_timeout);
+                                            proc_map_timeout,
+                                            nr_threads_synthesize);
 }
 
 pid_t machine__get_current_tid(struct machine *machine, int cpu);
index 4e7bd27501224a99bd80c6d95d5c676382451075..6d40efd74402732d6456bbd262a7b12dd12d613d 100644 (file)
@@ -489,7 +489,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
 static void maps__init(struct maps *maps)
 {
        maps->entries = RB_ROOT;
-       pthread_rwlock_init(&maps->lock, NULL);
+       init_rwsem(&maps->lock);
 }
 
 void map_groups__init(struct map_groups *mg, struct machine *machine)
@@ -518,9 +518,9 @@ static void __maps__purge(struct maps *maps)
 
 static void maps__exit(struct maps *maps)
 {
-       pthread_rwlock_wrlock(&maps->lock);
+       down_write(&maps->lock);
        __maps__purge(maps);
-       pthread_rwlock_unlock(&maps->lock);
+       up_write(&maps->lock);
 }
 
 void map_groups__exit(struct map_groups *mg)
@@ -587,7 +587,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
        struct symbol *sym;
        struct rb_node *nd;
 
-       pthread_rwlock_rdlock(&maps->lock);
+       down_read(&maps->lock);
 
        for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
                struct map *pos = rb_entry(nd, struct map, rb_node);
@@ -603,7 +603,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
 
        sym = NULL;
 out:
-       pthread_rwlock_unlock(&maps->lock);
+       up_read(&maps->lock);
        return sym;
 }
 
@@ -639,7 +639,7 @@ static size_t maps__fprintf(struct maps *maps, FILE *fp)
        size_t printed = 0;
        struct rb_node *nd;
 
-       pthread_rwlock_rdlock(&maps->lock);
+       down_read(&maps->lock);
 
        for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
                struct map *pos = rb_entry(nd, struct map, rb_node);
@@ -651,7 +651,7 @@ static size_t maps__fprintf(struct maps *maps, FILE *fp)
                }
        }
 
-       pthread_rwlock_unlock(&maps->lock);
+       up_read(&maps->lock);
 
        return printed;
 }
@@ -683,7 +683,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
        struct rb_node *next;
        int err = 0;
 
-       pthread_rwlock_wrlock(&maps->lock);
+       down_write(&maps->lock);
 
        root = &maps->entries;
        next = rb_first(root);
@@ -751,7 +751,7 @@ put_map:
 
        err = 0;
 out:
-       pthread_rwlock_unlock(&maps->lock);
+       up_write(&maps->lock);
        return err;
 }
 
@@ -772,7 +772,7 @@ int map_groups__clone(struct thread *thread,
        struct map *map;
        struct maps *maps = &parent->maps[type];
 
-       pthread_rwlock_rdlock(&maps->lock);
+       down_read(&maps->lock);
 
        for (map = maps__first(maps); map; map = map__next(map)) {
                struct map *new = map__clone(map);
@@ -789,7 +789,7 @@ int map_groups__clone(struct thread *thread,
 
        err = 0;
 out_unlock:
-       pthread_rwlock_unlock(&maps->lock);
+       up_read(&maps->lock);
        return err;
 }
 
@@ -816,9 +816,9 @@ static void __maps__insert(struct maps *maps, struct map *map)
 
 void maps__insert(struct maps *maps, struct map *map)
 {
-       pthread_rwlock_wrlock(&maps->lock);
+       down_write(&maps->lock);
        __maps__insert(maps, map);
-       pthread_rwlock_unlock(&maps->lock);
+       up_write(&maps->lock);
 }
 
 static void __maps__remove(struct maps *maps, struct map *map)
@@ -829,9 +829,9 @@ static void __maps__remove(struct maps *maps, struct map *map)
 
 void maps__remove(struct maps *maps, struct map *map)
 {
-       pthread_rwlock_wrlock(&maps->lock);
+       down_write(&maps->lock);
        __maps__remove(maps, map);
-       pthread_rwlock_unlock(&maps->lock);
+       up_write(&maps->lock);
 }
 
 struct map *maps__find(struct maps *maps, u64 ip)
@@ -839,7 +839,7 @@ struct map *maps__find(struct maps *maps, u64 ip)
        struct rb_node **p, *parent = NULL;
        struct map *m;
 
-       pthread_rwlock_rdlock(&maps->lock);
+       down_read(&maps->lock);
 
        p = &maps->entries.rb_node;
        while (*p != NULL) {
@@ -855,7 +855,7 @@ struct map *maps__find(struct maps *maps, u64 ip)
 
        m = NULL;
 out:
-       pthread_rwlock_unlock(&maps->lock);
+       up_read(&maps->lock);
        return m;
 }
 
index 1fb9b8589adc7537c74cd6422ea38c93649dc000..edeb7291c8e1ffdd0aedd2004957e72d4b2bf8ad 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <linux/types.h>
+#include "rwsem.h"
 
 enum map_type {
        MAP__FUNCTION = 0,
@@ -62,7 +63,7 @@ struct kmap {
 
 struct maps {
        struct rb_root   entries;
-       pthread_rwlock_t lock;
+       struct rw_semaphore lock;
 };
 
 struct map_groups {
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
new file mode 100644 (file)
index 0000000..0ddd9c1
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2017, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+/* Manage metrics and groups of metrics from JSON files */
+
+#include "metricgroup.h"
+#include "evlist.h"
+#include "strbuf.h"
+#include "pmu.h"
+#include "expr.h"
+#include "rblist.h"
+#include "pmu.h"
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include "pmu-events/pmu-events.h"
+#include "strbuf.h"
+#include "strlist.h"
+#include <assert.h>
+#include <ctype.h>
+
+struct metric_event *metricgroup__lookup(struct rblist *metric_events,
+                                        struct perf_evsel *evsel,
+                                        bool create)
+{
+       struct rb_node *nd;
+       struct metric_event me = {
+               .evsel = evsel
+       };
+       nd = rblist__find(metric_events, &me);
+       if (nd)
+               return container_of(nd, struct metric_event, nd);
+       if (create) {
+               rblist__add_node(metric_events, &me);
+               nd = rblist__find(metric_events, &me);
+               if (nd)
+                       return container_of(nd, struct metric_event, nd);
+       }
+       return NULL;
+}
+
+static int metric_event_cmp(struct rb_node *rb_node, const void *entry)
+{
+       struct metric_event *a = container_of(rb_node,
+                                             struct metric_event,
+                                             nd);
+       const struct metric_event *b = entry;
+
+       if (a->evsel == b->evsel)
+               return 0;
+       if ((char *)a->evsel < (char *)b->evsel)
+               return -1;
+       return +1;
+}
+
+static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused,
+                                       const void *entry)
+{
+       struct metric_event *me = malloc(sizeof(struct metric_event));
+
+       if (!me)
+               return NULL;
+       memcpy(me, entry, sizeof(struct metric_event));
+       me->evsel = ((struct metric_event *)entry)->evsel;
+       INIT_LIST_HEAD(&me->head);
+       return &me->nd;
+}
+
+static void metricgroup__rblist_init(struct rblist *metric_events)
+{
+       rblist__init(metric_events);
+       metric_events->node_cmp = metric_event_cmp;
+       metric_events->node_new = metric_event_new;
+}
+
+struct egroup {
+       struct list_head nd;
+       int idnum;
+       const char **ids;
+       const char *metric_name;
+       const char *metric_expr;
+};
+
+static struct perf_evsel *find_evsel(struct perf_evlist *perf_evlist,
+                                    const char **ids,
+                                    int idnum,
+                                    struct perf_evsel **metric_events)
+{
+       struct perf_evsel *ev, *start = NULL;
+       int ind = 0;
+
+       evlist__for_each_entry (perf_evlist, ev) {
+               if (!strcmp(ev->name, ids[ind])) {
+                       metric_events[ind] = ev;
+                       if (ind == 0)
+                               start = ev;
+                       if (++ind == idnum) {
+                               metric_events[ind] = NULL;
+                               return start;
+                       }
+               } else {
+                       ind = 0;
+                       start = NULL;
+               }
+       }
+       /*
+        * This can happen when an alias expands to multiple
+        * events, like for uncore events.
+        * We don't support this case for now.
+        */
+       return NULL;
+}
+
+static int metricgroup__setup_events(struct list_head *groups,
+                                    struct perf_evlist *perf_evlist,
+                                    struct rblist *metric_events_list)
+{
+       struct metric_event *me;
+       struct metric_expr *expr;
+       int i = 0;
+       int ret = 0;
+       struct egroup *eg;
+       struct perf_evsel *evsel;
+
+       list_for_each_entry (eg, groups, nd) {
+               struct perf_evsel **metric_events;
+
+               metric_events = calloc(sizeof(void *), eg->idnum + 1);
+               if (!metric_events) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               evsel = find_evsel(perf_evlist, eg->ids, eg->idnum,
+                                  metric_events);
+               if (!evsel) {
+                       pr_debug("Cannot resolve %s: %s\n",
+                                       eg->metric_name, eg->metric_expr);
+                       continue;
+               }
+               for (i = 0; i < eg->idnum; i++)
+                       metric_events[i]->collect_stat = true;
+               me = metricgroup__lookup(metric_events_list, evsel, true);
+               if (!me) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               expr = malloc(sizeof(struct metric_expr));
+               if (!expr) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               expr->metric_expr = eg->metric_expr;
+               expr->metric_name = eg->metric_name;
+               expr->metric_events = metric_events;
+               list_add(&expr->nd, &me->head);
+       }
+       return ret;
+}
+
+static bool match_metric(const char *n, const char *list)
+{
+       int len;
+       char *m;
+
+       if (!list)
+               return false;
+       if (!strcmp(list, "all"))
+               return true;
+       if (!n)
+               return !strcasecmp(list, "No_group");
+       len = strlen(list);
+       m = strcasestr(n, list);
+       if (!m)
+               return false;
+       if ((m == n || m[-1] == ';' || m[-1] == ' ') &&
+           (m[len] == 0 || m[len] == ';'))
+               return true;
+       return false;
+}
+
+struct mep {
+       struct rb_node nd;
+       const char *name;
+       struct strlist *metrics;
+};
+
+static int mep_cmp(struct rb_node *rb_node, const void *entry)
+{
+       struct mep *a = container_of(rb_node, struct mep, nd);
+       struct mep *b = (struct mep *)entry;
+
+       return strcmp(a->name, b->name);
+}
+
+static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
+                                       const void *entry)
+{
+       struct mep *me = malloc(sizeof(struct mep));
+
+       if (!me)
+               return NULL;
+       memcpy(me, entry, sizeof(struct mep));
+       me->name = strdup(me->name);
+       if (!me->name)
+               goto out_me;
+       me->metrics = strlist__new(NULL, NULL);
+       if (!me->metrics)
+               goto out_name;
+       return &me->nd;
+out_name:
+       free((char *)me->name);
+out_me:
+       free(me);
+       return NULL;
+}
+
+static struct mep *mep_lookup(struct rblist *groups, const char *name)
+{
+       struct rb_node *nd;
+       struct mep me = {
+               .name = name
+       };
+       nd = rblist__find(groups, &me);
+       if (nd)
+               return container_of(nd, struct mep, nd);
+       rblist__add_node(groups, &me);
+       nd = rblist__find(groups, &me);
+       if (nd)
+               return container_of(nd, struct mep, nd);
+       return NULL;
+}
+
+static void mep_delete(struct rblist *rl __maybe_unused,
+                      struct rb_node *nd)
+{
+       struct mep *me = container_of(nd, struct mep, nd);
+
+       strlist__delete(me->metrics);
+       free((void *)me->name);
+       free(me);
+}
+
+static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
+{
+       struct str_node *sn;
+       int n = 0;
+
+       strlist__for_each_entry (sn, metrics) {
+               if (raw)
+                       printf("%s%s", n > 0 ? " " : "", sn->s);
+               else
+                       printf("  %s\n", sn->s);
+               n++;
+       }
+       if (raw)
+               putchar('\n');
+}
+
+void metricgroup__print(bool metrics, bool metricgroups, char *filter,
+                       bool raw)
+{
+       struct pmu_events_map *map = perf_pmu__find_map();
+       struct pmu_event *pe;
+       int i;
+       struct rblist groups;
+       struct rb_node *node, *next;
+       struct strlist *metriclist = NULL;
+
+       if (!map)
+               return;
+
+       if (!metricgroups) {
+               metriclist = strlist__new(NULL, NULL);
+               if (!metriclist)
+                       return;
+       }
+
+       rblist__init(&groups);
+       groups.node_new = mep_new;
+       groups.node_cmp = mep_cmp;
+       groups.node_delete = mep_delete;
+       for (i = 0; ; i++) {
+               const char *g;
+               pe = &map->table[i];
+
+               if (!pe->name && !pe->metric_group && !pe->metric_name)
+                       break;
+               if (!pe->metric_expr)
+                       continue;
+               g = pe->metric_group;
+               if (!g && pe->metric_name) {
+                       if (pe->name)
+                               continue;
+                       g = "No_group";
+               }
+               if (g) {
+                       char *omg;
+                       char *mg = strdup(g);
+
+                       if (!mg)
+                               return;
+                       omg = mg;
+                       while ((g = strsep(&mg, ";")) != NULL) {
+                               struct mep *me;
+                               char *s;
+
+                               if (*g == 0)
+                                       g = "No_group";
+                               while (isspace(*g))
+                                       g++;
+                               if (filter && !strstr(g, filter))
+                                       continue;
+                               if (raw)
+                                       s = (char *)pe->metric_name;
+                               else {
+                                       if (asprintf(&s, "%s\n\t[%s]",
+                                                    pe->metric_name, pe->desc) < 0)
+                                               return;
+                               }
+
+                               if (!s)
+                                       continue;
+
+                               if (!metricgroups) {
+                                       strlist__add(metriclist, s);
+                               } else {
+                                       me = mep_lookup(&groups, g);
+                                       if (!me)
+                                               continue;
+                                       strlist__add(me->metrics, s);
+                               }
+                       }
+                       free(omg);
+               }
+       }
+
+       if (metricgroups && !raw)
+               printf("\nMetric Groups:\n\n");
+       else if (metrics && !raw)
+               printf("\nMetrics:\n\n");
+
+       for (node = rb_first(&groups.entries); node; node = next) {
+               struct mep *me = container_of(node, struct mep, nd);
+
+               if (metricgroups)
+                       printf("%s%s%s", me->name, metrics ? ":" : "", raw ? " " : "\n");
+               if (metrics)
+                       metricgroup__print_strlist(me->metrics, raw);
+               next = rb_next(node);
+               rblist__remove_node(&groups, node);
+       }
+       if (!metricgroups)
+               metricgroup__print_strlist(metriclist, raw);
+       strlist__delete(metriclist);
+}
+
+static int metricgroup__add_metric(const char *metric, struct strbuf *events,
+                                  struct list_head *group_list)
+{
+       struct pmu_events_map *map = perf_pmu__find_map();
+       struct pmu_event *pe;
+       int ret = -EINVAL;
+       int i, j;
+
+       if (!map)
+               return 0;
+
+       for (i = 0; ; i++) {
+               pe = &map->table[i];
+
+               if (!pe->name && !pe->metric_group && !pe->metric_name)
+                       break;
+               if (!pe->metric_expr)
+                       continue;
+               if (match_metric(pe->metric_group, metric) ||
+                   match_metric(pe->metric_name, metric)) {
+                       const char **ids;
+                       int idnum;
+                       struct egroup *eg;
+
+                       pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
+
+                       if (expr__find_other(pe->metric_expr,
+                                            NULL, &ids, &idnum) < 0)
+                               continue;
+                       if (events->len > 0)
+                               strbuf_addf(events, ",");
+                       for (j = 0; j < idnum; j++) {
+                               pr_debug("found event %s\n", ids[j]);
+                               strbuf_addf(events, "%s%s",
+                                       j == 0 ? "{" : ",",
+                                       ids[j]);
+                       }
+                       strbuf_addf(events, "}:W");
+
+                       eg = malloc(sizeof(struct egroup));
+                       if (!eg) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+                       eg->ids = ids;
+                       eg->idnum = idnum;
+                       eg->metric_name = pe->metric_name;
+                       eg->metric_expr = pe->metric_expr;
+                       list_add_tail(&eg->nd, group_list);
+                       ret = 0;
+               }
+       }
+       return ret;
+}
+
+static int metricgroup__add_metric_list(const char *list, struct strbuf *events,
+                                       struct list_head *group_list)
+{
+       char *llist, *nlist, *p;
+       int ret = -EINVAL;
+
+       nlist = strdup(list);
+       if (!nlist)
+               return -ENOMEM;
+       llist = nlist;
+
+       strbuf_init(events, 100);
+       strbuf_addf(events, "%s", "");
+
+       while ((p = strsep(&llist, ",")) != NULL) {
+               ret = metricgroup__add_metric(p, events, group_list);
+               if (ret == -EINVAL) {
+                       fprintf(stderr, "Cannot find metric or group `%s'\n",
+                                       p);
+                       break;
+               }
+       }
+       free(nlist);
+       return ret;
+}
+
+static void metricgroup__free_egroups(struct list_head *group_list)
+{
+       struct egroup *eg, *egtmp;
+       int i;
+
+       list_for_each_entry_safe (eg, egtmp, group_list, nd) {
+               for (i = 0; i < eg->idnum; i++)
+                       free((char *)eg->ids[i]);
+               free(eg->ids);
+               free(eg);
+       }
+}
+
+int metricgroup__parse_groups(const struct option *opt,
+                          const char *str,
+                          struct rblist *metric_events)
+{
+       struct parse_events_error parse_error;
+       struct perf_evlist *perf_evlist = *(struct perf_evlist **)opt->value;
+       struct strbuf extra_events;
+       LIST_HEAD(group_list);
+       int ret;
+
+       if (metric_events->nr_entries == 0)
+               metricgroup__rblist_init(metric_events);
+       ret = metricgroup__add_metric_list(str, &extra_events, &group_list);
+       if (ret)
+               return ret;
+       pr_debug("adding %s\n", extra_events.buf);
+       memset(&parse_error, 0, sizeof(struct parse_events_error));
+       ret = parse_events(perf_evlist, extra_events.buf, &parse_error);
+       if (ret) {
+               parse_events_print_error(&parse_error, extra_events.buf);
+               goto out;
+       }
+       strbuf_release(&extra_events);
+       ret = metricgroup__setup_events(&group_list, perf_evlist,
+                                       metric_events);
+out:
+       metricgroup__free_egroups(&group_list);
+       return ret;
+}
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
new file mode 100644 (file)
index 0000000..06854e1
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef METRICGROUP_H
+#define METRICGROUP_H 1
+
+#include "linux/list.h"
+#include "rblist.h"
+#include <subcmd/parse-options.h>
+#include "evlist.h"
+#include "strbuf.h"
+
+struct metric_event {
+       struct rb_node nd;
+       struct perf_evsel *evsel;
+       struct list_head head; /* list of metric_expr */
+};
+
+struct metric_expr {
+       struct list_head nd;
+       const char *metric_expr;
+       const char *metric_name;
+       struct perf_evsel **metric_events;
+};
+
+struct metric_event *metricgroup__lookup(struct rblist *metric_events,
+                                        struct perf_evsel *evsel,
+                                        bool create);
+int metricgroup__parse_groups(const struct option *opt,
+                       const char *str,
+                       struct rblist *metric_events);
+
+void metricgroup__print(bool metrics, bool groups, char *filter, bool raw);
+#endif
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
new file mode 100644 (file)
index 0000000..9fe5f9c
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2011-2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Parts came from evlist.c builtin-{top,stat,record}.c, see those files for further
+ * copyright notes.
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include <sys/mman.h>
+#include <inttypes.h>
+#include <asm/bug.h>
+#include "debug.h"
+#include "event.h"
+#include "mmap.h"
+#include "util.h" /* page_size */
+
+size_t perf_mmap__mmap_len(struct perf_mmap *map)
+{
+       return map->mask + 1 + page_size;
+}
+
+/* When check_messup is true, 'end' must points to a good entry */
+static union perf_event *perf_mmap__read(struct perf_mmap *map, bool check_messup,
+                                        u64 start, u64 end, u64 *prev)
+{
+       unsigned char *data = map->base + page_size;
+       union perf_event *event = NULL;
+       int diff = end - start;
+
+       if (check_messup) {
+               /*
+                * If we're further behind than half the buffer, there's a chance
+                * the writer will bite our tail and mess up the samples under us.
+                *
+                * If we somehow ended up ahead of the 'end', we got messed up.
+                *
+                * In either case, truncate and restart at 'end'.
+                */
+               if (diff > map->mask / 2 || diff < 0) {
+                       fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
+
+                       /*
+                        * 'end' points to a known good entry, start there.
+                        */
+                       start = end;
+                       diff = 0;
+               }
+       }
+
+       if (diff >= (int)sizeof(event->header)) {
+               size_t size;
+
+               event = (union perf_event *)&data[start & map->mask];
+               size = event->header.size;
+
+               if (size < sizeof(event->header) || diff < (int)size) {
+                       event = NULL;
+                       goto broken_event;
+               }
+
+               /*
+                * Event straddles the mmap boundary -- header should always
+                * be inside due to u64 alignment of output.
+                */
+               if ((start & map->mask) + size != ((start + size) & map->mask)) {
+                       unsigned int offset = start;
+                       unsigned int len = min(sizeof(*event), size), cpy;
+                       void *dst = map->event_copy;
+
+                       do {
+                               cpy = min(map->mask + 1 - (offset & map->mask), len);
+                               memcpy(dst, &data[offset & map->mask], cpy);
+                               offset += cpy;
+                               dst += cpy;
+                               len -= cpy;
+                       } while (len);
+
+                       event = (union perf_event *)map->event_copy;
+               }
+
+               start += size;
+       }
+
+broken_event:
+       if (prev)
+               *prev = start;
+
+       return event;
+}
+
+union perf_event *perf_mmap__read_forward(struct perf_mmap *map, bool check_messup)
+{
+       u64 head;
+       u64 old = map->prev;
+
+       /*
+        * Check if event was unmapped due to a POLLHUP/POLLERR.
+        */
+       if (!refcount_read(&map->refcnt))
+               return NULL;
+
+       head = perf_mmap__read_head(map);
+
+       return perf_mmap__read(map, check_messup, old, head, &map->prev);
+}
+
+union perf_event *perf_mmap__read_backward(struct perf_mmap *map)
+{
+       u64 head, end;
+       u64 start = map->prev;
+
+       /*
+        * Check if event was unmapped due to a POLLHUP/POLLERR.
+        */
+       if (!refcount_read(&map->refcnt))
+               return NULL;
+
+       head = perf_mmap__read_head(map);
+       if (!head)
+               return NULL;
+
+       /*
+        * 'head' pointer starts from 0. Kernel minus sizeof(record) form
+        * it each time when kernel writes to it, so in fact 'head' is
+        * negative. 'end' pointer is made manually by adding the size of
+        * the ring buffer to 'head' pointer, means the validate data can
+        * read is the whole ring buffer. If 'end' is positive, the ring
+        * buffer has not fully filled, so we must adjust 'end' to 0.
+        *
+        * However, since both 'head' and 'end' is unsigned, we can't
+        * simply compare 'end' against 0. Here we compare '-head' and
+        * the size of the ring buffer, where -head is the number of bytes
+        * kernel write to the ring buffer.
+        */
+       if (-head < (u64)(map->mask + 1))
+               end = 0;
+       else
+               end = head + map->mask + 1;
+
+       return perf_mmap__read(map, false, start, end, &map->prev);
+}
+
+void perf_mmap__read_catchup(struct perf_mmap *map)
+{
+       u64 head;
+
+       if (!refcount_read(&map->refcnt))
+               return;
+
+       head = perf_mmap__read_head(map);
+       map->prev = head;
+}
+
+static bool perf_mmap__empty(struct perf_mmap *map)
+{
+       return perf_mmap__read_head(map) == map->prev && !map->auxtrace_mmap.base;
+}
+
+void perf_mmap__get(struct perf_mmap *map)
+{
+       refcount_inc(&map->refcnt);
+}
+
+void perf_mmap__put(struct perf_mmap *map)
+{
+       BUG_ON(map->base && refcount_read(&map->refcnt) == 0);
+
+       if (refcount_dec_and_test(&map->refcnt))
+               perf_mmap__munmap(map);
+}
+
+void perf_mmap__consume(struct perf_mmap *map, bool overwrite)
+{
+       if (!overwrite) {
+               u64 old = map->prev;
+
+               perf_mmap__write_tail(map, old);
+       }
+
+       if (refcount_read(&map->refcnt) == 1 && perf_mmap__empty(map))
+               perf_mmap__put(map);
+}
+
+int __weak auxtrace_mmap__mmap(struct auxtrace_mmap *mm __maybe_unused,
+                              struct auxtrace_mmap_params *mp __maybe_unused,
+                              void *userpg __maybe_unused,
+                              int fd __maybe_unused)
+{
+       return 0;
+}
+
+void __weak auxtrace_mmap__munmap(struct auxtrace_mmap *mm __maybe_unused)
+{
+}
+
+void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_unused,
+                                      off_t auxtrace_offset __maybe_unused,
+                                      unsigned int auxtrace_pages __maybe_unused,
+                                      bool auxtrace_overwrite __maybe_unused)
+{
+}
+
+void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused,
+                                         struct perf_evlist *evlist __maybe_unused,
+                                         int idx __maybe_unused,
+                                         bool per_cpu __maybe_unused)
+{
+}
+
+void perf_mmap__munmap(struct perf_mmap *map)
+{
+       if (map->base != NULL) {
+               munmap(map->base, perf_mmap__mmap_len(map));
+               map->base = NULL;
+               map->fd = -1;
+               refcount_set(&map->refcnt, 0);
+       }
+       auxtrace_mmap__munmap(&map->auxtrace_mmap);
+}
+
+int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd)
+{
+       /*
+        * The last one will be done at perf_evlist__mmap_consume(), so that we
+        * make sure we don't prevent tools from consuming every last event in
+        * the ring buffer.
+        *
+        * I.e. we can get the POLLHUP meaning that the fd doesn't exist
+        * anymore, but the last events for it are still in the ring buffer,
+        * waiting to be consumed.
+        *
+        * Tools can chose to ignore this at their own discretion, but the
+        * evlist layer can't just drop it when filtering events in
+        * perf_evlist__filter_pollfd().
+        */
+       refcount_set(&map->refcnt, 2);
+       map->prev = 0;
+       map->mask = mp->mask;
+       map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot,
+                        MAP_SHARED, fd, 0);
+       if (map->base == MAP_FAILED) {
+               pr_debug2("failed to mmap perf event ring buffer, error %d\n",
+                         errno);
+               map->base = NULL;
+               return -1;
+       }
+       map->fd = fd;
+
+       if (auxtrace_mmap__mmap(&map->auxtrace_mmap,
+                               &mp->auxtrace_mp, map->base, fd))
+               return -1;
+
+       return 0;
+}
+
+static int backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end)
+{
+       struct perf_event_header *pheader;
+       u64 evt_head = head;
+       int size = mask + 1;
+
+       pr_debug2("backward_rb_find_range: buf=%p, head=%"PRIx64"\n", buf, head);
+       pheader = (struct perf_event_header *)(buf + (head & mask));
+       *start = head;
+       while (true) {
+               if (evt_head - head >= (unsigned int)size) {
+                       pr_debug("Finished reading backward ring buffer: rewind\n");
+                       if (evt_head - head > (unsigned int)size)
+                               evt_head -= pheader->size;
+                       *end = evt_head;
+                       return 0;
+               }
+
+               pheader = (struct perf_event_header *)(buf + (evt_head & mask));
+
+               if (pheader->size == 0) {
+                       pr_debug("Finished reading backward ring buffer: get start\n");
+                       *end = evt_head;
+                       return 0;
+               }
+
+               evt_head += pheader->size;
+               pr_debug3("move evt_head: %"PRIx64"\n", evt_head);
+       }
+       WARN_ONCE(1, "Shouldn't get here\n");
+       return -1;
+}
+
+static int rb_find_range(void *data, int mask, u64 head, u64 old,
+                        u64 *start, u64 *end, bool backward)
+{
+       if (!backward) {
+               *start = old;
+               *end = head;
+               return 0;
+       }
+
+       return backward_rb_find_range(data, mask, head, start, end);
+}
+
+int perf_mmap__push(struct perf_mmap *md, bool overwrite, bool backward,
+                   void *to, int push(void *to, void *buf, size_t size))
+{
+       u64 head = perf_mmap__read_head(md);
+       u64 old = md->prev;
+       u64 end = head, start = old;
+       unsigned char *data = md->base + page_size;
+       unsigned long size;
+       void *buf;
+       int rc = 0;
+
+       if (rb_find_range(data, md->mask, head, old, &start, &end, backward))
+               return -1;
+
+       if (start == end)
+               return 0;
+
+       size = end - start;
+       if (size > (unsigned long)(md->mask) + 1) {
+               WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
+
+               md->prev = head;
+               perf_mmap__consume(md, overwrite || backward);
+               return 0;
+       }
+
+       if ((start & md->mask) + size != (end & md->mask)) {
+               buf = &data[start & md->mask];
+               size = md->mask + 1 - (start & md->mask);
+               start += size;
+
+               if (push(to, buf, size) < 0) {
+                       rc = -1;
+                       goto out;
+               }
+       }
+
+       buf = &data[start & md->mask];
+       size = end - start;
+       start += size;
+
+       if (push(to, buf, size) < 0) {
+               rc = -1;
+               goto out;
+       }
+
+       md->prev = head;
+       perf_mmap__consume(md, overwrite || backward);
+out:
+       return rc;
+}
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
new file mode 100644 (file)
index 0000000..efd78b8
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef __PERF_MMAP_H
+#define __PERF_MMAP_H 1
+
+#include <linux/compiler.h>
+#include <linux/refcount.h>
+#include <linux/types.h>
+#include <asm/barrier.h>
+#include <stdbool.h>
+#include "auxtrace.h"
+#include "event.h"
+
+/**
+ * struct perf_mmap - perf's ring buffer mmap details
+ *
+ * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this
+ */
+struct perf_mmap {
+       void             *base;
+       int              mask;
+       int              fd;
+       refcount_t       refcnt;
+       u64              prev;
+       struct auxtrace_mmap auxtrace_mmap;
+       char             event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
+};
+
+/*
+ * State machine of bkw_mmap_state:
+ *
+ *                     .________________(forbid)_____________.
+ *                     |                                     V
+ * NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY
+ *                     ^  ^              |   ^               |
+ *                     |  |__(forbid)____/   |___(forbid)___/|
+ *                     |                                     |
+ *                      \_________________(3)_______________/
+ *
+ * NOTREADY     : Backward ring buffers are not ready
+ * RUNNING      : Backward ring buffers are recording
+ * DATA_PENDING : We are required to collect data from backward ring buffers
+ * EMPTY        : We have collected data from backward ring buffers.
+ *
+ * (0): Setup backward ring buffer
+ * (1): Pause ring buffers for reading
+ * (2): Read from ring buffers
+ * (3): Resume ring buffers for recording
+ */
+enum bkw_mmap_state {
+       BKW_MMAP_NOTREADY,
+       BKW_MMAP_RUNNING,
+       BKW_MMAP_DATA_PENDING,
+       BKW_MMAP_EMPTY,
+};
+
+struct mmap_params {
+       int                         prot, mask;
+       struct auxtrace_mmap_params auxtrace_mp;
+};
+
+int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd);
+void perf_mmap__munmap(struct perf_mmap *map);
+
+void perf_mmap__get(struct perf_mmap *map);
+void perf_mmap__put(struct perf_mmap *map);
+
+void perf_mmap__consume(struct perf_mmap *map, bool overwrite);
+
+void perf_mmap__read_catchup(struct perf_mmap *md);
+
+static inline u64 perf_mmap__read_head(struct perf_mmap *mm)
+{
+       struct perf_event_mmap_page *pc = mm->base;
+       u64 head = ACCESS_ONCE(pc->data_head);
+       rmb();
+       return head;
+}
+
+static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail)
+{
+       struct perf_event_mmap_page *pc = md->base;
+
+       /*
+        * ensure all reads are done before we write the tail out.
+        */
+       mb();
+       pc->data_tail = tail;
+}
+
+union perf_event *perf_mmap__read_forward(struct perf_mmap *map, bool check_messup);
+union perf_event *perf_mmap__read_backward(struct perf_mmap *map);
+
+int perf_mmap__push(struct perf_mmap *md, bool overwrite, bool backward,
+                   void *to, int push(void *to, void *buf, size_t size));
+
+size_t perf_mmap__mmap_len(struct perf_mmap *map);
+
+#endif /*__PERF_MMAP_H */
index a58e91197729a40305d071809b95d83b49bc8548..5be021701f34e758aae5eda1d95bb7a9ce49ebad 100644 (file)
@@ -11,6 +11,7 @@
 #include "event.h"
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <sched.h>
 #include <stdlib.h>
index 05d82601c9a62574180eb1657dda83a4670c42e9..760558dcfd1810c432684b7a7cea1f0aacaba677 100644 (file)
@@ -9,9 +9,10 @@
 #ifndef __PERF_NAMESPACES_H
 #define __PERF_NAMESPACES_H
 
-#include "../perf.h"
-#include <linux/list.h>
+#include <sys/types.h>
+#include <linux/perf_event.h>
 #include <linux/refcount.h>
+#include <linux/types.h>
 
 struct namespaces_event;
 
index 56694e3409ea3552911541d2438d527c1c641b1f..a7fcd95961ef0776f07c6968088a7b6cf7836924 100644 (file)
@@ -29,6 +29,7 @@
 #include "probe-file.h"
 #include "asm/bug.h"
 #include "util/parse-branch-options.h"
+#include "metricgroup.h"
 
 #define MAX_NAME_LEN 100
 
@@ -1220,11 +1221,17 @@ static int __parse_events_add_pmu(struct parse_events_state *parse_state,
        struct perf_pmu_info info;
        struct perf_pmu *pmu;
        struct perf_evsel *evsel;
+       struct parse_events_error *err = parse_state->error;
        LIST_HEAD(config_terms);
 
        pmu = perf_pmu__find(name);
-       if (!pmu)
+       if (!pmu) {
+               if (asprintf(&err->str,
+                               "Cannot find PMU `%s'. Missing kernel support?",
+                               name) < 0)
+                       err->str = NULL;
                return -EINVAL;
+       }
 
        if (pmu->default_config) {
                memcpy(&attr, pmu->default_config,
@@ -1368,6 +1375,7 @@ struct event_modifier {
        int exclude_GH;
        int sample_read;
        int pinned;
+       int weak;
 };
 
 static int get_event_modifier(struct event_modifier *mod, char *str,
@@ -1386,6 +1394,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
 
        int exclude = eu | ek | eh;
        int exclude_GH = evsel ? evsel->exclude_GH : 0;
+       int weak = 0;
 
        memset(mod, 0, sizeof(*mod));
 
@@ -1423,6 +1432,8 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
                        sample_read = 1;
                } else if (*str == 'D') {
                        pinned = 1;
+               } else if (*str == 'W') {
+                       weak = 1;
                } else
                        break;
 
@@ -1453,6 +1464,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
        mod->exclude_GH = exclude_GH;
        mod->sample_read = sample_read;
        mod->pinned = pinned;
+       mod->weak = weak;
 
        return 0;
 }
@@ -1466,7 +1478,7 @@ static int check_modifier(char *str)
        char *p = str;
 
        /* The sizeof includes 0 byte as well. */
-       if (strlen(str) > (sizeof("ukhGHpppPSDI") - 1))
+       if (strlen(str) > (sizeof("ukhGHpppPSDIW") - 1))
                return -1;
 
        while (*p) {
@@ -1506,6 +1518,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
                evsel->exclude_GH          = mod.exclude_GH;
                evsel->sample_read         = mod.sample_read;
                evsel->precise_max         = mod.precise_max;
+               evsel->weak_group          = mod.weak;
 
                if (perf_evsel__is_group_leader(evsel))
                        evsel->attr.pinned = mod.pinned;
@@ -1728,8 +1741,8 @@ static int get_term_width(void)
        return ws.ws_col > MAX_WIDTH ? MAX_WIDTH : ws.ws_col;
 }
 
-static void parse_events_print_error(struct parse_events_error *err,
-                                    const char *event)
+void parse_events_print_error(struct parse_events_error *err,
+                             const char *event)
 {
        const char *str = "invalid or unsupported event: ";
        char _buf[MAX_WIDTH];
@@ -1784,8 +1797,6 @@ static void parse_events_print_error(struct parse_events_error *err,
                zfree(&err->str);
                zfree(&err->help);
        }
-
-       fprintf(stderr, "Run 'perf list' for a list of valid events\n");
 }
 
 #undef MAX_WIDTH
@@ -1797,8 +1808,10 @@ int parse_events_option(const struct option *opt, const char *str,
        struct parse_events_error err = { .idx = 0, };
        int ret = parse_events(evlist, str, &err);
 
-       if (ret)
+       if (ret) {
                parse_events_print_error(&err, str);
+               fprintf(stderr, "Run 'perf list' for a list of valid events\n");
+       }
 
        return ret;
 }
@@ -2376,6 +2389,8 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag,
        print_tracepoint_events(NULL, NULL, name_only);
 
        print_sdt_events(NULL, NULL, name_only);
+
+       metricgroup__print(true, true, NULL, name_only);
 }
 
 int parse_events__is_hardcoded_term(struct parse_events_term *term)
index eed50b54bab3293541ac245186f1d1f00164b478..be337c266697a718d3ad595a166f8f3e3602cb93 100644 (file)
@@ -203,6 +203,9 @@ int is_valid_tracepoint(const char *event_string);
 int valid_event_mount(const char *eventfs);
 char *parse_events_formats_error_string(char *additional_terms);
 
+void parse_events_print_error(struct parse_events_error *err,
+                             const char *event);
+
 #ifdef HAVE_LIBELF_SUPPORT
 /*
  * If the probe point starts with '%',
index 6680e4fb79672c4aaa117554896005d5f4d45018..655ecff636a8d41ec3b3bf52122fe16cc3220e6b 100644 (file)
@@ -5,6 +5,7 @@
 %option stack
 %option bison-locations
 %option yylineno
+%option reject
 
 %{
 #include <errno.h>
@@ -178,7 +179,7 @@ name                [a-zA-Z_*?][a-zA-Z0-9_*?.]*
 name_minus     [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]*
 drv_cfg_term   [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)?
 /* If you add a modifier you need to update check_modifier() */
-modifier_event [ukhpPGHSDI]+
+modifier_event [ukhpPGHSDIW]+
 modifier_bp    [rwx]{1,3}
 
 %%
@@ -305,6 +306,7 @@ cpu-migrations|migrations                   { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COU
 alignment-faults                               { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
 emulation-faults                               { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
 dummy                                          { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
+duration_time                                  { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
 bpf-output                                     { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); }
 
        /*
@@ -339,8 +341,8 @@ r{num_raw_hex}              { return raw(yyscanner); }
 {num_hex}              { return value(yyscanner, 16); }
 
 {modifier_event}       { return str(yyscanner, PE_MODIFIER_EVENT); }
-{bpf_object}           { if (!isbpf(yyscanner)) USER_REJECT; return str(yyscanner, PE_BPF_OBJECT); }
-{bpf_source}           { if (!isbpf(yyscanner)) USER_REJECT; return str(yyscanner, PE_BPF_SOURCE); }
+{bpf_object}           { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); }
+{bpf_source}           { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); }
 {name}                 { return pmu_str_check(yyscanner); }
 "/"                    { BEGIN(config); return '/'; }
 -                      { return '-'; }
index b10b35a6313819f1ff560e1c1b9e67b4111fb796..07cb2ac041d7a63b53298b4205fd0b4cd629c349 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/compiler.h>
 #include <sys/types.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -541,16 +542,8 @@ char * __weak get_cpuid_str(void)
        return NULL;
 }
 
-/*
- * From the pmu_events_map, find the table of PMU events that corresponds
- * to the current running CPU. Then, add all PMU events from that table
- * as aliases.
- */
-static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
+static char *perf_pmu__getcpuid(void)
 {
-       int i;
-       struct pmu_events_map *map;
-       struct pmu_event *pe;
        char *cpuid;
        static bool printed;
 
@@ -560,22 +553,50 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
        if (!cpuid)
                cpuid = get_cpuid_str();
        if (!cpuid)
-               return;
+               return NULL;
 
        if (!printed) {
                pr_debug("Using CPUID %s\n", cpuid);
                printed = true;
        }
+       return cpuid;
+}
+
+struct pmu_events_map *perf_pmu__find_map(void)
+{
+       struct pmu_events_map *map;
+       char *cpuid = perf_pmu__getcpuid();
+       int i;
 
        i = 0;
-       while (1) {
+       for (;;) {
                map = &pmu_events_map[i++];
-               if (!map->table)
-                       goto out;
+               if (!map->table) {
+                       map = NULL;
+                       break;
+               }
 
                if (!strcmp(map->cpuid, cpuid))
                        break;
        }
+       free(cpuid);
+       return map;
+}
+
+/*
+ * From the pmu_events_map, find the table of PMU events that corresponds
+ * to the current running CPU. Then, add all PMU events from that table
+ * as aliases.
+ */
+static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
+{
+       int i;
+       struct pmu_events_map *map;
+       struct pmu_event *pe;
+
+       map = perf_pmu__find_map();
+       if (!map)
+               return;
 
        /*
         * Found a matching PMU events table. Create aliases
@@ -585,8 +606,11 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
                const char *pname;
 
                pe = &map->table[i++];
-               if (!pe->name)
+               if (!pe->name) {
+                       if (pe->metric_group || pe->metric_name)
+                               continue;
                        break;
+               }
 
                pname = pe->pmu ? pe->pmu : "cpu";
                if (strncmp(pname, name, strlen(pname)))
@@ -600,9 +624,6 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
                                (char *)pe->metric_expr,
                                (char *)pe->metric_name);
        }
-
-out:
-       free(cpuid);
 }
 
 struct perf_event_attr * __weak
index eca99435f4a0b98f23479e4209e97e6a1cc3f05f..27c75e63586695cd7a32d71bf35f0501043477ea 100644 (file)
@@ -92,4 +92,6 @@ int perf_pmu__test(void);
 
 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
 
+struct pmu_events_map *perf_pmu__find_map(void);
+
 #endif /* __PMU_H */
index 779e35c9e566f1386b3a294519c2dc831f3f45a9..23e3670634465c6061b19e4b26c628902cfb4a6e 100644 (file)
@@ -3,40 +3,42 @@
 #include <linux/log2.h>
 #include "sane_ctype.h"
 
-void print_binary(unsigned char *data, size_t len,
-                 size_t bytes_per_line, print_binary_t printer,
-                 void *extra)
+int binary__fprintf(unsigned char *data, size_t len,
+                   size_t bytes_per_line, binary__fprintf_t printer,
+                   void *extra, FILE *fp)
 {
        size_t i, j, mask;
+       int printed = 0;
 
        if (!printer)
-               return;
+               return 0;
 
        bytes_per_line = roundup_pow_of_two(bytes_per_line);
        mask = bytes_per_line - 1;
 
-       printer(BINARY_PRINT_DATA_BEGIN, 0, extra);
+       printed += printer(BINARY_PRINT_DATA_BEGIN, 0, extra, fp);
        for (i = 0; i < len; i++) {
                if ((i & mask) == 0) {
-                       printer(BINARY_PRINT_LINE_BEGIN, -1, extra);
-                       printer(BINARY_PRINT_ADDR, i, extra);
+                       printed += printer(BINARY_PRINT_LINE_BEGIN, -1, extra, fp);
+                       printed += printer(BINARY_PRINT_ADDR, i, extra, fp);
                }
 
-               printer(BINARY_PRINT_NUM_DATA, data[i], extra);
+               printed += printer(BINARY_PRINT_NUM_DATA, data[i], extra, fp);
 
                if (((i & mask) == mask) || i == len - 1) {
                        for (j = 0; j < mask-(i & mask); j++)
-                               printer(BINARY_PRINT_NUM_PAD, -1, extra);
+                               printed += printer(BINARY_PRINT_NUM_PAD, -1, extra, fp);
 
-                       printer(BINARY_PRINT_SEP, i, extra);
+                       printer(BINARY_PRINT_SEP, i, extra, fp);
                        for (j = i & ~mask; j <= i; j++)
-                               printer(BINARY_PRINT_CHAR_DATA, data[j], extra);
+                               printed += printer(BINARY_PRINT_CHAR_DATA, data[j], extra, fp);
                        for (j = 0; j < mask-(i & mask); j++)
-                               printer(BINARY_PRINT_CHAR_PAD, i, extra);
-                       printer(BINARY_PRINT_LINE_END, -1, extra);
+                               printed += printer(BINARY_PRINT_CHAR_PAD, i, extra, fp);
+                       printed += printer(BINARY_PRINT_LINE_END, -1, extra, fp);
                }
        }
-       printer(BINARY_PRINT_DATA_END, -1, extra);
+       printed += printer(BINARY_PRINT_DATA_END, -1, extra, fp);
+       return printed;
 }
 
 int is_printable_array(char *p, unsigned int len)
index 2be3075e2b05a37c172d5585ba7b010e0c6e6fc5..2a1554afc95757a9dcde5aaebb6284cf9a47ce2c 100644 (file)
@@ -3,6 +3,7 @@
 #define PERF_PRINT_BINARY_H
 
 #include <stddef.h>
+#include <stdio.h>
 
 enum binary_printer_ops {
        BINARY_PRINT_DATA_BEGIN,
@@ -17,12 +18,19 @@ enum binary_printer_ops {
        BINARY_PRINT_DATA_END,
 };
 
-typedef void (*print_binary_t)(enum binary_printer_ops op,
-                              unsigned int val, void *extra);
+typedef int (*binary__fprintf_t)(enum binary_printer_ops op,
+                                unsigned int val, void *extra, FILE *fp);
 
-void print_binary(unsigned char *data, size_t len,
-                 size_t bytes_per_line, print_binary_t printer,
-                 void *extra);
+int binary__fprintf(unsigned char *data, size_t len,
+                   size_t bytes_per_line, binary__fprintf_t printer,
+                   void *extra, FILE *fp);
+
+static inline void print_binary(unsigned char *data, size_t len,
+                               size_t bytes_per_line, binary__fprintf_t printer,
+                               void *extra)
+{
+       binary__fprintf(data, len, bytes_per_line, printer, extra, stdout);
+}
 
 int is_printable_array(char *p, unsigned int len);
 
index cdf8d83a484c1408608c78cace95da4e29b0c242..4ae1123c67949a01cadc1f4080728b038e15b88b 100644 (file)
@@ -15,6 +15,7 @@
  *
  */
 #include <errno.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/uio.h>
index e66dc495809a86d2be847561be6de861ac75de19..b4f2f06722a7acf8f8b036c560df03c000bd1d26 100644 (file)
@@ -10,6 +10,7 @@ util/ctype.c
 util/evlist.c
 util/evsel.c
 util/cpumap.c
+util/mmap.c
 util/namespaces.c
 ../lib/bitmap.c
 ../lib/find_bit.c
index 7d8972b33f6bcefe81542a9a4c04388f52eb3b67..a920f702a74dfdb817e8a71eca6c5139c9001d3d 100644 (file)
@@ -144,7 +144,8 @@ struct __name##_sorted *__name = __name##_sorted__new
                                  __ilist->rblist.nr_entries)
 
 /* For 'struct machine->threads' */
-#define DECLARE_RESORT_RB_MACHINE_THREADS(__name, __machine)                   \
-       DECLARE_RESORT_RB(__name)(&__machine->threads, __machine->nr_threads)
+#define DECLARE_RESORT_RB_MACHINE_THREADS(__name, __machine, hash_bucket)      \
+       DECLARE_RESORT_RB(__name)(&__machine->threads[hash_bucket].entries,     \
+                                 __machine->threads[hash_bucket].nr)
 
 #endif /* _PERF_RESORT_RB_H_ */
diff --git a/tools/perf/util/rwsem.c b/tools/perf/util/rwsem.c
new file mode 100644 (file)
index 0000000..5e52e7b
--- /dev/null
@@ -0,0 +1,32 @@
+#include "util.h"
+#include "rwsem.h"
+
+int init_rwsem(struct rw_semaphore *sem)
+{
+       return pthread_rwlock_init(&sem->lock, NULL);
+}
+
+int exit_rwsem(struct rw_semaphore *sem)
+{
+       return pthread_rwlock_destroy(&sem->lock);
+}
+
+int down_read(struct rw_semaphore *sem)
+{
+       return perf_singlethreaded ? 0 : pthread_rwlock_rdlock(&sem->lock);
+}
+
+int up_read(struct rw_semaphore *sem)
+{
+       return perf_singlethreaded ? 0 : pthread_rwlock_unlock(&sem->lock);
+}
+
+int down_write(struct rw_semaphore *sem)
+{
+       return perf_singlethreaded ? 0 : pthread_rwlock_wrlock(&sem->lock);
+}
+
+int up_write(struct rw_semaphore *sem)
+{
+       return perf_singlethreaded ? 0 : pthread_rwlock_unlock(&sem->lock);
+}
diff --git a/tools/perf/util/rwsem.h b/tools/perf/util/rwsem.h
new file mode 100644 (file)
index 0000000..94565ad
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _PERF_RWSEM_H
+#define _PERF_RWSEM_H
+
+#include <pthread.h>
+
+struct rw_semaphore {
+       pthread_rwlock_t lock;
+};
+
+int init_rwsem(struct rw_semaphore *sem);
+int exit_rwsem(struct rw_semaphore *sem);
+
+int down_read(struct rw_semaphore *sem);
+int up_read(struct rw_semaphore *sem);
+
+int down_write(struct rw_semaphore *sem);
+int up_write(struct rw_semaphore *sem);
+
+#endif /* _PERF_RWSEM_H */
index da55081aefc693043edc219c5ed96413e8c74857..5c412310f26644236844dd59e114cc770e04b0d0 100644 (file)
@@ -33,14 +33,14 @@ static int perf_session__deliver_event(struct perf_session *session,
 
 static int perf_session__open(struct perf_session *session)
 {
-       struct perf_data_file *file = session->file;
+       struct perf_data *data = session->data;
 
        if (perf_session__read_header(session) < 0) {
                pr_err("incompatible file format (rerun with -v to learn more)\n");
                return -1;
        }
 
-       if (perf_data_file__is_pipe(file))
+       if (perf_data__is_pipe(data))
                return 0;
 
        if (perf_header__has_feat(&session->header, HEADER_STAT))
@@ -121,7 +121,7 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
                                           session->tool, event->file_offset);
 }
 
-struct perf_session *perf_session__new(struct perf_data_file *file,
+struct perf_session *perf_session__new(struct perf_data *data,
                                       bool repipe, struct perf_tool *tool)
 {
        struct perf_session *session = zalloc(sizeof(*session));
@@ -135,13 +135,13 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
        machines__init(&session->machines);
        ordered_events__init(&session->ordered_events, ordered_events__deliver_event);
 
-       if (file) {
-               if (perf_data_file__open(file))
+       if (data) {
+               if (perf_data__open(data))
                        goto out_delete;
 
-               session->file = file;
+               session->data = data;
 
-               if (perf_data_file__is_read(file)) {
+               if (perf_data__is_read(data)) {
                        if (perf_session__open(session) < 0)
                                goto out_close;
 
@@ -149,7 +149,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                         * set session attributes that are present in perf.data
                         * but not in pipe-mode.
                         */
-                       if (!file->is_pipe) {
+                       if (!data->is_pipe) {
                                perf_session__set_id_hdr_size(session);
                                perf_session__set_comm_exec(session);
                        }
@@ -158,7 +158,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                session->machines.host.env = &perf_env;
        }
 
-       if (!file || perf_data_file__is_write(file)) {
+       if (!data || perf_data__is_write(data)) {
                /*
                 * In O_RDONLY mode this will be performed when reading the
                 * kernel MMAP event, in perf_event__process_mmap().
@@ -171,7 +171,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
         * In pipe-mode, evlist is empty until PERF_RECORD_HEADER_ATTR is
         * processed, so perf_evlist__sample_id_all is not meaningful here.
         */
-       if ((!file || !file->is_pipe) && tool && tool->ordering_requires_timestamps &&
+       if ((!data || !data->is_pipe) && tool && tool->ordering_requires_timestamps &&
            tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {
                dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
                tool->ordered_events = false;
@@ -180,7 +180,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
        return session;
 
  out_close:
-       perf_data_file__close(file);
+       perf_data__close(data);
  out_delete:
        perf_session__delete(session);
  out:
@@ -202,8 +202,8 @@ void perf_session__delete(struct perf_session *session)
        perf_session__delete_threads(session);
        perf_env__exit(&session->header.env);
        machines__exit(&session->machines);
-       if (session->file)
-               perf_data_file__close(session->file);
+       if (session->data)
+               perf_data__close(session->data);
        free(session);
 }
 
@@ -291,8 +291,8 @@ static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
                                       __maybe_unused)
 {
        dump_printf(": unhandled!\n");
-       if (perf_data_file__is_pipe(session->file))
-               skipn(perf_data_file__fd(session->file), event->auxtrace.size);
+       if (perf_data__is_pipe(session->data))
+               skipn(perf_data__fd(session->data), event->auxtrace.size);
        return event->auxtrace.size;
 }
 
@@ -1350,7 +1350,7 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 {
        struct ordered_events *oe = &session->ordered_events;
        struct perf_tool *tool = session->tool;
-       int fd = perf_data_file__fd(session->file);
+       int fd = perf_data__fd(session->data);
        int err;
 
        dump_event(session->evlist, event, file_offset, NULL);
@@ -1450,10 +1450,10 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
                goto out_parse_sample;
        }
 
-       if (perf_data_file__is_pipe(session->file))
+       if (perf_data__is_pipe(session->data))
                return -1;
 
-       fd = perf_data_file__fd(session->file);
+       fd = perf_data__fd(session->data);
        hdr_sz = sizeof(struct perf_event_header);
 
        if (buf_sz < hdr_sz)
@@ -1688,7 +1688,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
 {
        struct ordered_events *oe = &session->ordered_events;
        struct perf_tool *tool = session->tool;
-       int fd = perf_data_file__fd(session->file);
+       int fd = perf_data__fd(session->data);
        union perf_event *event;
        uint32_t size, cur_size = 0;
        void *buf = NULL;
@@ -1829,7 +1829,7 @@ static int __perf_session__process_events(struct perf_session *session,
 {
        struct ordered_events *oe = &session->ordered_events;
        struct perf_tool *tool = session->tool;
-       int fd = perf_data_file__fd(session->file);
+       int fd = perf_data__fd(session->data);
        u64 head, page_offset, file_offset, file_pos, size;
        int err, mmap_prot, mmap_flags, map_idx = 0;
        size_t  mmap_size;
@@ -1850,7 +1850,7 @@ static int __perf_session__process_events(struct perf_session *session,
        if (data_offset + data_size < file_size)
                file_size = data_offset + data_size;
 
-       ui_progress__init(&prog, file_size, "Processing events...");
+       ui_progress__init_size(&prog, file_size, "Processing events...");
 
        mmap_size = MMAP_SIZE;
        if (mmap_size > file_size) {
@@ -1946,13 +1946,13 @@ out_err:
 
 int perf_session__process_events(struct perf_session *session)
 {
-       u64 size = perf_data_file__size(session->file);
+       u64 size = perf_data__size(session->data);
        int err;
 
        if (perf_session__register_idle_thread(session) < 0)
                return -ENOMEM;
 
-       if (!perf_data_file__is_pipe(session->file))
+       if (!perf_data__is_pipe(session->data))
                err = __perf_session__process_events(session,
                                                     session->header.data_offset,
                                                     session->header.data_size, size);
index 41caa098ed15534f7b8100025e9eac533ad24c0e..da1434a7c120d5682c02f1d5b0c24fc11d583886 100644 (file)
@@ -33,13 +33,13 @@ struct perf_session {
        void                    *one_mmap_addr;
        u64                     one_mmap_offset;
        struct ordered_events   ordered_events;
-       struct perf_data_file   *file;
+       struct perf_data        *data;
        struct perf_tool        *tool;
 };
 
 struct perf_tool;
 
-struct perf_session *perf_session__new(struct perf_data_file *file,
+struct perf_session *perf_session__new(struct perf_data *data,
                                       bool repipe, struct perf_tool *tool);
 void perf_session__delete(struct perf_session *session);
 
@@ -114,7 +114,7 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
 
 extern volatile int session_done;
 
-#define session_done() ACCESS_ONCE(session_done)
+#define session_done() READ_ONCE(session_done)
 
 int perf_session__deliver_synth_event(struct perf_session *session,
                                      union perf_event *event,
index 84a33f1e9ec9222c8a7a7030be59e7b96427ce26..a00eacdf02ed9d826f0d9d666c12edf526f2bec6 100644 (file)
@@ -226,6 +226,9 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
        if (sym_l == sym_r)
                return 0;
 
+       if (sym_l->inlined || sym_r->inlined)
+               return strcmp(sym_l->name, sym_r->name);
+
        if (sym_l->start != sym_r->start)
                return (int64_t)(sym_r->start - sym_l->start);
 
@@ -284,6 +287,9 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
                        ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
                                               width - ret,
                                               sym->name);
+                       if (sym->inlined)
+                               ret += repsep_snprintf(bf + ret, size - ret,
+                                                      " (inlined)");
                }
        } else {
                size_t len = BITS_PER_LONG / 4;
index b2b55e5149a7a79432dbda09ae797280193614ad..f5901c10a563c3eb5ed88391709fa38356e0ae87 100644 (file)
@@ -130,7 +130,6 @@ struct hist_entry {
        };
        char                    *srcline;
        char                    *srcfile;
-       struct inline_node      *inline_node;
        struct symbol           *parent;
        struct branch_info      *branch_info;
        struct hists            *hists;
index 4105682afc7aa393b7d3a4714b65074fafd5c616..d19f05c56de61ff87805e9f412dbf491b2b870c3 100644 (file)
@@ -11,7 +11,7 @@
 #include "util/debug.h"
 #include "util/callchain.h"
 #include "srcline.h"
-
+#include "string2.h"
 #include "symbol.h"
 
 bool srcline_full_filename;
@@ -34,28 +34,17 @@ static const char *dso__name(struct dso *dso)
        return dso_name;
 }
 
-static int inline_list__append(char *filename, char *funcname, int line_nr,
-                              struct inline_node *node, struct dso *dso)
+static int inline_list__append(struct symbol *symbol, char *srcline,
+                              struct inline_node *node)
 {
        struct inline_list *ilist;
-       char *demangled;
 
        ilist = zalloc(sizeof(*ilist));
        if (ilist == NULL)
                return -1;
 
-       ilist->filename = filename;
-       ilist->line_nr = line_nr;
-
-       if (dso != NULL) {
-               demangled = dso__demangle_sym(dso, 0, funcname);
-               if (demangled == NULL) {
-                       ilist->funcname = funcname;
-               } else {
-                       ilist->funcname = demangled;
-                       free(funcname);
-               }
-       }
+       ilist->symbol = symbol;
+       ilist->srcline = srcline;
 
        if (callchain_param.order == ORDER_CALLEE)
                list_add_tail(&ilist->list, &node->val);
@@ -65,6 +54,65 @@ static int inline_list__append(char *filename, char *funcname, int line_nr,
        return 0;
 }
 
+/* basename version that takes a const input string */
+static const char *gnu_basename(const char *path)
+{
+       const char *base = strrchr(path, '/');
+
+       return base ? base + 1 : path;
+}
+
+static char *srcline_from_fileline(const char *file, unsigned int line)
+{
+       char *srcline;
+
+       if (!file)
+               return NULL;
+
+       if (!srcline_full_filename)
+               file = gnu_basename(file);
+
+       if (asprintf(&srcline, "%s:%u", file, line) < 0)
+               return NULL;
+
+       return srcline;
+}
+
+static struct symbol *new_inline_sym(struct dso *dso,
+                                    struct symbol *base_sym,
+                                    const char *funcname)
+{
+       struct symbol *inline_sym;
+       char *demangled = NULL;
+
+       if (dso) {
+               demangled = dso__demangle_sym(dso, 0, funcname);
+               if (demangled)
+                       funcname = demangled;
+       }
+
+       if (base_sym && strcmp(funcname, base_sym->name) == 0) {
+               /* reuse the real, existing symbol */
+               inline_sym = base_sym;
+               /* ensure that we don't alias an inlined symbol, which could
+                * lead to double frees in inline_node__delete
+                */
+               assert(!base_sym->inlined);
+       } else {
+               /* create a fake symbol for the inline frame */
+               inline_sym = symbol__new(base_sym ? base_sym->start : 0,
+                                        base_sym ? base_sym->end : 0,
+                                        base_sym ? base_sym->binding : 0,
+                                        funcname);
+               if (inline_sym)
+                       inline_sym->inlined = 1;
+       }
+
+       free(demangled);
+
+       return inline_sym;
+}
+
 #ifdef HAVE_LIBBFD_SUPPORT
 
 /*
@@ -208,18 +256,23 @@ static void addr2line_cleanup(struct a2l_data *a2l)
 #define MAX_INLINE_NEST 1024
 
 static int inline_list__append_dso_a2l(struct dso *dso,
-                                      struct inline_node *node)
+                                      struct inline_node *node,
+                                      struct symbol *sym)
 {
        struct a2l_data *a2l = dso->a2l;
-       char *funcname = a2l->funcname ? strdup(a2l->funcname) : NULL;
-       char *filename = a2l->filename ? strdup(a2l->filename) : NULL;
+       struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname);
+       char *srcline = NULL;
 
-       return inline_list__append(filename, funcname, a2l->line, node, dso);
+       if (a2l->filename)
+               srcline = srcline_from_fileline(a2l->filename, a2l->line);
+
+       return inline_list__append(inline_sym, srcline, node);
 }
 
 static int addr2line(const char *dso_name, u64 addr,
                     char **file, unsigned int *line, struct dso *dso,
-                    bool unwind_inlines, struct inline_node *node)
+                    bool unwind_inlines, struct inline_node *node,
+                    struct symbol *sym)
 {
        int ret = 0;
        struct a2l_data *a2l = dso->a2l;
@@ -245,7 +298,7 @@ static int addr2line(const char *dso_name, u64 addr,
        if (unwind_inlines) {
                int cnt = 0;
 
-               if (node && inline_list__append_dso_a2l(dso, node))
+               if (node && inline_list__append_dso_a2l(dso, node, sym))
                        return 0;
 
                while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
@@ -256,7 +309,7 @@ static int addr2line(const char *dso_name, u64 addr,
                                a2l->filename = NULL;
 
                        if (node != NULL) {
-                               if (inline_list__append_dso_a2l(dso, node))
+                               if (inline_list__append_dso_a2l(dso, node, sym))
                                        return 0;
                                // found at least one inline frame
                                ret = 1;
@@ -288,7 +341,7 @@ void dso__free_a2l(struct dso *dso)
 }
 
 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
-       struct dso *dso)
+                                       struct dso *dso, struct symbol *sym)
 {
        struct inline_node *node;
 
@@ -301,17 +354,8 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
        INIT_LIST_HEAD(&node->val);
        node->addr = addr;
 
-       if (!addr2line(dso_name, addr, NULL, NULL, dso, TRUE, node))
-               goto out_free_inline_node;
-
-       if (list_empty(&node->val))
-               goto out_free_inline_node;
-
+       addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym);
        return node;
-
-out_free_inline_node:
-       inline_node__delete(node);
-       return NULL;
 }
 
 #else /* HAVE_LIBBFD_SUPPORT */
@@ -341,7 +385,8 @@ static int addr2line(const char *dso_name, u64 addr,
                     char **file, unsigned int *line_nr,
                     struct dso *dso __maybe_unused,
                     bool unwind_inlines __maybe_unused,
-                    struct inline_node *node __maybe_unused)
+                    struct inline_node *node __maybe_unused,
+                    struct symbol *sym __maybe_unused)
 {
        FILE *fp;
        char cmd[PATH_MAX];
@@ -381,16 +426,18 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
 }
 
 static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
-       struct dso *dso __maybe_unused)
+                                       struct dso *dso __maybe_unused,
+                                       struct symbol *sym)
 {
        FILE *fp;
        char cmd[PATH_MAX];
        struct inline_node *node;
        char *filename = NULL;
-       size_t len;
+       char *funcname = NULL;
+       size_t filelen, funclen;
        unsigned int line_nr = 0;
 
-       scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
+       scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i -f %016"PRIx64,
                  dso_name, addr);
 
        fp = popen(cmd, "r");
@@ -408,26 +455,34 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
        INIT_LIST_HEAD(&node->val);
        node->addr = addr;
 
-       while (getline(&filename, &len, fp) != -1) {
-               if (filename_split(filename, &line_nr) != 1) {
-                       free(filename);
+       /* addr2line -f generates two lines for each inlined functions */
+       while (getline(&funcname, &funclen, fp) != -1) {
+               char *srcline;
+               struct symbol *inline_sym;
+
+               rtrim(funcname);
+
+               if (getline(&filename, &filelen, fp) == -1)
                        goto out;
-               }
 
-               if (inline_list__append(filename, NULL, line_nr, node,
-                                       NULL) != 0)
+               if (filename_split(filename, &line_nr) != 1)
                        goto out;
 
-               filename = NULL;
+               srcline = srcline_from_fileline(filename, line_nr);
+               inline_sym = new_inline_sym(dso, sym, funcname);
+
+               if (inline_list__append(inline_sym, srcline, node) != 0) {
+                       free(srcline);
+                       if (inline_sym && inline_sym->inlined)
+                               symbol__delete(inline_sym);
+                       goto out;
+               }
        }
 
 out:
        pclose(fp);
-
-       if (list_empty(&node->val)) {
-               inline_node__delete(node);
-               return NULL;
-       }
+       free(filename);
+       free(funcname);
 
        return node;
 }
@@ -455,19 +510,18 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
        if (dso_name == NULL)
                goto out;
 
-       if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL))
+       if (!addr2line(dso_name, addr, &file, &line, dso,
+                      unwind_inlines, NULL, sym))
                goto out;
 
-       if (asprintf(&srcline, "%s:%u",
-                               srcline_full_filename ? file : basename(file),
-                               line) < 0) {
-               free(file);
+       srcline = srcline_from_fileline(file, line);
+       free(file);
+
+       if (!srcline)
                goto out;
-       }
 
        dso->a2l_fails = 0;
 
-       free(file);
        return srcline;
 
 out:
@@ -501,7 +555,74 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
        return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
 }
 
-struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
+struct srcline_node {
+       u64                     addr;
+       char                    *srcline;
+       struct rb_node          rb_node;
+};
+
+void srcline__tree_insert(struct rb_root *tree, u64 addr, char *srcline)
+{
+       struct rb_node **p = &tree->rb_node;
+       struct rb_node *parent = NULL;
+       struct srcline_node *i, *node;
+
+       node = zalloc(sizeof(struct srcline_node));
+       if (!node) {
+               perror("not enough memory for the srcline node");
+               return;
+       }
+
+       node->addr = addr;
+       node->srcline = srcline;
+
+       while (*p != NULL) {
+               parent = *p;
+               i = rb_entry(parent, struct srcline_node, rb_node);
+               if (addr < i->addr)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&node->rb_node, parent, p);
+       rb_insert_color(&node->rb_node, tree);
+}
+
+char *srcline__tree_find(struct rb_root *tree, u64 addr)
+{
+       struct rb_node *n = tree->rb_node;
+
+       while (n) {
+               struct srcline_node *i = rb_entry(n, struct srcline_node,
+                                                 rb_node);
+
+               if (addr < i->addr)
+                       n = n->rb_left;
+               else if (addr > i->addr)
+                       n = n->rb_right;
+               else
+                       return i->srcline;
+       }
+
+       return NULL;
+}
+
+void srcline__tree_delete(struct rb_root *tree)
+{
+       struct srcline_node *pos;
+       struct rb_node *next = rb_first(tree);
+
+       while (next) {
+               pos = rb_entry(next, struct srcline_node, rb_node);
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, tree);
+               free_srcline(pos->srcline);
+               zfree(&pos);
+       }
+}
+
+struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
+                                           struct symbol *sym)
 {
        const char *dso_name;
 
@@ -509,7 +630,7 @@ struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
        if (dso_name == NULL)
                return NULL;
 
-       return addr2inlines(dso_name, addr, dso);
+       return addr2inlines(dso_name, addr, dso, sym);
 }
 
 void inline_node__delete(struct inline_node *node)
@@ -518,10 +639,63 @@ void inline_node__delete(struct inline_node *node)
 
        list_for_each_entry_safe(ilist, tmp, &node->val, list) {
                list_del_init(&ilist->list);
-               zfree(&ilist->filename);
-               zfree(&ilist->funcname);
+               free_srcline(ilist->srcline);
+               /* only the inlined symbols are owned by the list */
+               if (ilist->symbol && ilist->symbol->inlined)
+                       symbol__delete(ilist->symbol);
                free(ilist);
        }
 
        free(node);
 }
+
+void inlines__tree_insert(struct rb_root *tree, struct inline_node *inlines)
+{
+       struct rb_node **p = &tree->rb_node;
+       struct rb_node *parent = NULL;
+       const u64 addr = inlines->addr;
+       struct inline_node *i;
+
+       while (*p != NULL) {
+               parent = *p;
+               i = rb_entry(parent, struct inline_node, rb_node);
+               if (addr < i->addr)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&inlines->rb_node, parent, p);
+       rb_insert_color(&inlines->rb_node, tree);
+}
+
+struct inline_node *inlines__tree_find(struct rb_root *tree, u64 addr)
+{
+       struct rb_node *n = tree->rb_node;
+
+       while (n) {
+               struct inline_node *i = rb_entry(n, struct inline_node,
+                                                rb_node);
+
+               if (addr < i->addr)
+                       n = n->rb_left;
+               else if (addr > i->addr)
+                       n = n->rb_right;
+               else
+                       return i;
+       }
+
+       return NULL;
+}
+
+void inlines__tree_delete(struct rb_root *tree)
+{
+       struct inline_node *pos;
+       struct rb_node *next = rb_first(tree);
+
+       while (next) {
+               pos = rb_entry(next, struct inline_node, rb_node);
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, tree);
+               inline_node__delete(pos);
+       }
+}
index 8e73f607dfa315d4a1808285adf7a759501b1f23..847b7086182c1ac52d293b29390c04168563e792 100644 (file)
@@ -3,6 +3,7 @@
 #define PERF_SRCLINE_H
 
 #include <linux/list.h>
+#include <linux/rbtree.h>
 #include <linux/types.h>
 
 struct dso;
@@ -15,21 +16,38 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
                  bool show_sym, bool show_addr, bool unwind_inlines);
 void free_srcline(char *srcline);
 
+/* insert the srcline into the DSO, which will take ownership */
+void srcline__tree_insert(struct rb_root *tree, u64 addr, char *srcline);
+/* find previously inserted srcline */
+char *srcline__tree_find(struct rb_root *tree, u64 addr);
+/* delete all srclines within the tree */
+void srcline__tree_delete(struct rb_root *tree);
+
 #define SRCLINE_UNKNOWN  ((char *) "??:0")
 
 struct inline_list {
-       char                    *filename;
-       char                    *funcname;
-       unsigned int            line_nr;
+       struct symbol           *symbol;
+       char                    *srcline;
        struct list_head        list;
 };
 
 struct inline_node {
        u64                     addr;
        struct list_head        val;
+       struct rb_node          rb_node;
 };
 
-struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr);
+/* parse inlined frames for the given address */
+struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr,
+                                           struct symbol *sym);
+/* free resources associated to the inline node list */
 void inline_node__delete(struct inline_node *node);
 
+/* insert the inline node list into the DSO, which will take ownership */
+void inlines__tree_insert(struct rb_root *tree, struct inline_node *inlines);
+/* find previously inserted inline node list */
+struct inline_node *inlines__tree_find(struct rb_root *tree, u64 addr);
+/* delete all nodes within the tree of inline_node s */
+void inlines__tree_delete(struct rb_root *tree);
+
 #endif /* PERF_SRCLINE_H */
index 37363869c9a1b52db7d1a59e977987139925bb46..855e35cbb1dcec3bf65bcfe1ab4a2afd614b4141 100644 (file)
@@ -7,6 +7,7 @@
 #include "rblist.h"
 #include "evlist.h"
 #include "expr.h"
+#include "metricgroup.h"
 
 enum {
        CTX_BIT_USER    = 1 << 0,
@@ -56,7 +57,6 @@ struct saved_value {
        struct rb_node rb_node;
        struct perf_evsel *evsel;
        int cpu;
-       int ctx;
        struct stats stats;
 };
 
@@ -67,8 +67,6 @@ static int saved_value_cmp(struct rb_node *rb_node, const void *entry)
                                             rb_node);
        const struct saved_value *b = entry;
 
-       if (a->ctx != b->ctx)
-               return a->ctx - b->ctx;
        if (a->cpu != b->cpu)
                return a->cpu - b->cpu;
        if (a->evsel == b->evsel)
@@ -90,13 +88,12 @@ static struct rb_node *saved_value_new(struct rblist *rblist __maybe_unused,
 }
 
 static struct saved_value *saved_value_lookup(struct perf_evsel *evsel,
-                                             int cpu, int ctx,
+                                             int cpu,
                                              bool create)
 {
        struct rb_node *nd;
        struct saved_value dm = {
                .cpu = cpu,
-               .ctx = ctx,
                .evsel = evsel,
        };
        nd = rblist__find(&runtime_saved_values, &dm);
@@ -182,59 +179,60 @@ void perf_stat__reset_shadow_stats(void)
  * more semantic information such as miss/hit ratios,
  * instruction rates, etc:
  */
-void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
+void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count,
                                    int cpu)
 {
        int ctx = evsel_context(counter);
 
+       count *= counter->scale;
+
        if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK) ||
            perf_evsel__match(counter, SOFTWARE, SW_CPU_CLOCK))
-               update_stats(&runtime_nsecs_stats[cpu], count[0]);
+               update_stats(&runtime_nsecs_stats[cpu], count);
        else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
-               update_stats(&runtime_cycles_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_cycles_stats[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, CYCLES_IN_TX))
-               update_stats(&runtime_cycles_in_tx_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_cycles_in_tx_stats[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, TRANSACTION_START))
-               update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_transaction_stats[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, ELISION_START))
-               update_stats(&runtime_elision_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_elision_stats[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, TOPDOWN_TOTAL_SLOTS))
-               update_stats(&runtime_topdown_total_slots[ctx][cpu], count[0]);
+               update_stats(&runtime_topdown_total_slots[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_ISSUED))
-               update_stats(&runtime_topdown_slots_issued[ctx][cpu], count[0]);
+               update_stats(&runtime_topdown_slots_issued[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_RETIRED))
-               update_stats(&runtime_topdown_slots_retired[ctx][cpu], count[0]);
+               update_stats(&runtime_topdown_slots_retired[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_BUBBLES))
-               update_stats(&runtime_topdown_fetch_bubbles[ctx][cpu],count[0]);
+               update_stats(&runtime_topdown_fetch_bubbles[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, TOPDOWN_RECOVERY_BUBBLES))
-               update_stats(&runtime_topdown_recovery_bubbles[ctx][cpu], count[0]);
+               update_stats(&runtime_topdown_recovery_bubbles[ctx][cpu], count);
        else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
-               update_stats(&runtime_stalled_cycles_front_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_stalled_cycles_front_stats[ctx][cpu], count);
        else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
-               update_stats(&runtime_stalled_cycles_back_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_stalled_cycles_back_stats[ctx][cpu], count);
        else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
-               update_stats(&runtime_branches_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_branches_stats[ctx][cpu], count);
        else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES))
-               update_stats(&runtime_cacherefs_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_cacherefs_stats[ctx][cpu], count);
        else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D))
-               update_stats(&runtime_l1_dcache_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_l1_dcache_stats[ctx][cpu], count);
        else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1I))
-               update_stats(&runtime_ll_cache_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_ll_cache_stats[ctx][cpu], count);
        else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_LL))
-               update_stats(&runtime_ll_cache_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_ll_cache_stats[ctx][cpu], count);
        else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_DTLB))
-               update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count);
        else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
-               update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_itlb_cache_stats[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, SMI_NUM))
-               update_stats(&runtime_smi_num_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_smi_num_stats[ctx][cpu], count);
        else if (perf_stat_evsel__is(counter, APERF))
-               update_stats(&runtime_aperf_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_aperf_stats[ctx][cpu], count);
 
        if (counter->collect_stat) {
-               struct saved_value *v = saved_value_lookup(counter, cpu, ctx,
-                                                          true);
-               update_stats(&v->stats, count[0]);
+               struct saved_value *v = saved_value_lookup(counter, cpu, true);
+               update_stats(&v->stats, count);
        }
 }
 
@@ -628,15 +626,68 @@ static void print_smi_cost(int cpu, struct perf_evsel *evsel,
        out->print_metric(out->ctx, NULL, "%4.0f", "SMI#", smi_num);
 }
 
+static void generic_metric(const char *metric_expr,
+                          struct perf_evsel **metric_events,
+                          char *name,
+                          const char *metric_name,
+                          double avg,
+                          int cpu,
+                          struct perf_stat_output_ctx *out)
+{
+       print_metric_t print_metric = out->print_metric;
+       struct parse_ctx pctx;
+       double ratio;
+       int i;
+       void *ctxp = out->ctx;
+
+       expr__ctx_init(&pctx);
+       expr__add_id(&pctx, name, avg);
+       for (i = 0; metric_events[i]; i++) {
+               struct saved_value *v;
+               struct stats *stats;
+               double scale;
+
+               if (!strcmp(metric_events[i]->name, "duration_time")) {
+                       stats = &walltime_nsecs_stats;
+                       scale = 1e-9;
+               } else {
+                       v = saved_value_lookup(metric_events[i], cpu, false);
+                       if (!v)
+                               break;
+                       stats = &v->stats;
+                       scale = 1.0;
+               }
+               expr__add_id(&pctx, metric_events[i]->name, avg_stats(stats)*scale);
+       }
+       if (!metric_events[i]) {
+               const char *p = metric_expr;
+
+               if (expr__parse(&ratio, &pctx, &p) == 0)
+                       print_metric(ctxp, NULL, "%8.1f",
+                               metric_name ?
+                               metric_name :
+                               out->force_header ?  name : "",
+                               ratio);
+               else
+                       print_metric(ctxp, NULL, NULL,
+                                    out->force_header ?
+                                    (metric_name ? metric_name : name) : "", 0);
+       } else
+               print_metric(ctxp, NULL, NULL, "", 0);
+}
+
 void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
                                   double avg, int cpu,
-                                  struct perf_stat_output_ctx *out)
+                                  struct perf_stat_output_ctx *out,
+                                  struct rblist *metric_events)
 {
        void *ctxp = out->ctx;
        print_metric_t print_metric = out->print_metric;
        double total, ratio = 0.0, total2;
        const char *color = NULL;
        int ctx = evsel_context(evsel);
+       struct metric_event *me;
+       int num = 1;
 
        if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
                total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
@@ -820,33 +871,8 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
                else
                        print_metric(ctxp, NULL, NULL, name, 0);
        } else if (evsel->metric_expr) {
-               struct parse_ctx pctx;
-               int i;
-
-               expr__ctx_init(&pctx);
-               expr__add_id(&pctx, evsel->name, avg);
-               for (i = 0; evsel->metric_events[i]; i++) {
-                       struct saved_value *v;
-
-                       v = saved_value_lookup(evsel->metric_events[i], cpu, ctx, false);
-                       if (!v)
-                               break;
-                       expr__add_id(&pctx, evsel->metric_events[i]->name,
-                                            avg_stats(&v->stats));
-               }
-               if (!evsel->metric_events[i]) {
-                       const char *p = evsel->metric_expr;
-
-                       if (expr__parse(&ratio, &pctx, &p) == 0)
-                               print_metric(ctxp, NULL, "%8.1f",
-                                       evsel->metric_name ?
-                                       evsel->metric_name :
-                                       out->force_header ?  evsel->name : "",
-                                       ratio);
-                       else
-                               print_metric(ctxp, NULL, NULL, "", 0);
-               } else
-                       print_metric(ctxp, NULL, NULL, "", 0);
+               generic_metric(evsel->metric_expr, evsel->metric_events, evsel->name,
+                               evsel->metric_name, avg, cpu, out);
        } else if (runtime_nsecs_stats[cpu].n != 0) {
                char unit = 'M';
                char unit_buf[10];
@@ -864,6 +890,20 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
        } else if (perf_stat_evsel__is(evsel, SMI_NUM)) {
                print_smi_cost(cpu, evsel, out);
        } else {
-               print_metric(ctxp, NULL, NULL, NULL, 0);
+               num = 0;
        }
+
+       if ((me = metricgroup__lookup(metric_events, evsel, false)) != NULL) {
+               struct metric_expr *mexp;
+
+               list_for_each_entry (mexp, &me->head, nd) {
+                       if (num++ > 0)
+                               out->new_line(ctxp);
+                       generic_metric(mexp->metric_expr, mexp->metric_events,
+                                       evsel->name, mexp->metric_name,
+                                       avg, cpu, out);
+               }
+       }
+       if (num == 0)
+               print_metric(ctxp, NULL, NULL, NULL, 0);
 }
index c9bae5fb8b479434edb3c0d1436373e79fe83be7..151e9efd728623328d22bffb280f2948ff79591e 100644 (file)
@@ -70,7 +70,7 @@ double rel_stddev_stats(double stddev, double avg)
 bool __perf_evsel_stat__is(struct perf_evsel *evsel,
                           enum perf_stat_evsel_id id)
 {
-       struct perf_stat_evsel *ps = evsel->priv;
+       struct perf_stat_evsel *ps = evsel->stats;
 
        return ps->id == id;
 }
@@ -94,7 +94,7 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = {
 
 void perf_stat_evsel_id_init(struct perf_evsel *evsel)
 {
-       struct perf_stat_evsel *ps = evsel->priv;
+       struct perf_stat_evsel *ps = evsel->stats;
        int i;
 
        /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
@@ -110,7 +110,7 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)
 static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
 {
        int i;
-       struct perf_stat_evsel *ps = evsel->priv;
+       struct perf_stat_evsel *ps = evsel->stats;
 
        for (i = 0; i < 3; i++)
                init_stats(&ps->res_stats[i]);
@@ -120,8 +120,8 @@ static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
 
 static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
 {
-       evsel->priv = zalloc(sizeof(struct perf_stat_evsel));
-       if (evsel->priv == NULL)
+       evsel->stats = zalloc(sizeof(struct perf_stat_evsel));
+       if (evsel->stats == NULL)
                return -ENOMEM;
        perf_evsel__reset_stat_priv(evsel);
        return 0;
@@ -129,11 +129,11 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
 
 static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
 {
-       struct perf_stat_evsel *ps = evsel->priv;
+       struct perf_stat_evsel *ps = evsel->stats;
 
        if (ps)
                free(ps->group_data);
-       zfree(&evsel->priv);
+       zfree(&evsel->stats);
 }
 
 static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
@@ -278,7 +278,9 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel
                        perf_evsel__compute_deltas(evsel, cpu, thread, count);
                perf_counts_values__scale(count, config->scale, NULL);
                if (config->aggr_mode == AGGR_NONE)
-                       perf_stat__update_shadow_stats(evsel, count->values, cpu);
+                       perf_stat__update_shadow_stats(evsel, count->val, cpu);
+               if (config->aggr_mode == AGGR_THREAD)
+                       perf_stat__update_shadow_stats(evsel, count->val, 0);
                break;
        case AGGR_GLOBAL:
                aggr->val += count->val;
@@ -319,9 +321,8 @@ int perf_stat_process_counter(struct perf_stat_config *config,
                              struct perf_evsel *counter)
 {
        struct perf_counts_values *aggr = &counter->counts->aggr;
-       struct perf_stat_evsel *ps = counter->priv;
+       struct perf_stat_evsel *ps = counter->stats;
        u64 *count = counter->counts->aggr.values;
-       u64 val;
        int i, ret;
 
        aggr->val = aggr->ena = aggr->run = 0;
@@ -361,8 +362,7 @@ int perf_stat_process_counter(struct perf_stat_config *config,
        /*
         * Save the full runtime - to allow normalization during printout:
         */
-       val = counter->scale * *count;
-       perf_stat__update_shadow_stats(counter, &val, 0);
+       perf_stat__update_shadow_stats(counter, *count, 0);
 
        return 0;
 }
index 96326b1f944381b3e69da77d42149f667e02787a..eefca5c981fdc4f310c45c79d4bfee348679306a 100644 (file)
@@ -83,7 +83,7 @@ typedef void (*new_line_t )(void *ctx);
 
 void perf_stat__init_shadow_stats(void);
 void perf_stat__reset_shadow_stats(void);
-void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
+void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count,
                                    int cpu);
 struct perf_stat_output_ctx {
        void *ctx;
@@ -92,9 +92,11 @@ struct perf_stat_output_ctx {
        bool force_header;
 };
 
+struct rblist;
 void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
                                   double avg, int cpu,
-                                  struct perf_stat_output_ctx *out);
+                                  struct perf_stat_output_ctx *out,
+                                  struct rblist *metric_events);
 void perf_stat__collect_metric_expr(struct perf_evlist *);
 
 int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
index 6492ef38b0907c3e1b3788204fbd2066d5b4d596..1b67a8639dfeb0e96b794434c9686c9b9aa96190 100644 (file)
@@ -46,6 +46,7 @@ struct symbol_conf symbol_conf = {
        .show_hist_headers      = true,
        .symfs                  = "",
        .event_group            = true,
+       .inline_name            = true,
 };
 
 static enum dso_binary_type binary_type_symtab[] = {
@@ -227,7 +228,7 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
        struct maps *maps = &mg->maps[type];
        struct map *next, *curr;
 
-       pthread_rwlock_wrlock(&maps->lock);
+       down_write(&maps->lock);
 
        curr = maps__first(maps);
        if (curr == NULL)
@@ -247,7 +248,7 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
                curr->end = ~0ULL;
 
 out_unlock:
-       pthread_rwlock_unlock(&maps->lock);
+       up_write(&maps->lock);
 }
 
 struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
@@ -1672,7 +1673,7 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
        struct maps *maps = &mg->maps[type];
        struct map *map;
 
-       pthread_rwlock_rdlock(&maps->lock);
+       down_read(&maps->lock);
 
        for (map = maps__first(maps); map; map = map__next(map)) {
                if (map->dso && strcmp(map->dso->short_name, name) == 0)
@@ -1682,7 +1683,7 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
        map = NULL;
 
 out_unlock:
-       pthread_rwlock_unlock(&maps->lock);
+       up_read(&maps->lock);
        return map;
 }
 
index 6352022593c6b7697f3dc24221961fc8caa516af..a4f0075b4e5cf285d955ddd1c4a91a4193737768 100644 (file)
@@ -60,6 +60,7 @@ struct symbol {
        u8              binding;
        u8              idle:1;
        u8              ignore:1;
+       u8              inlined:1;
        u8              arch_sym;
        char            name[0];
 };
@@ -209,6 +210,7 @@ struct addr_location {
        struct thread *thread;
        struct map    *map;
        struct symbol *sym;
+       const char    *srcline;
        u64           addr;
        char          level;
        u8            filtered;
index 1dbcd3c8dee045787a1f53676888e5d3a5efcf79..68b65b10579bcce74ef5cdb99b8a1b43501ee88b 100644 (file)
@@ -46,6 +46,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)
                thread->cpu = -1;
                INIT_LIST_HEAD(&thread->namespaces_list);
                INIT_LIST_HEAD(&thread->comm_list);
+               init_rwsem(&thread->namespaces_lock);
+               init_rwsem(&thread->comm_lock);
 
                comm_str = malloc(32);
                if (!comm_str)
@@ -84,18 +86,26 @@ void thread__delete(struct thread *thread)
                map_groups__put(thread->mg);
                thread->mg = NULL;
        }
+       down_write(&thread->namespaces_lock);
        list_for_each_entry_safe(namespaces, tmp_namespaces,
                                 &thread->namespaces_list, list) {
                list_del(&namespaces->list);
                namespaces__free(namespaces);
        }
+       up_write(&thread->namespaces_lock);
+
+       down_write(&thread->comm_lock);
        list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
                list_del(&comm->list);
                comm__free(comm);
        }
+       up_write(&thread->comm_lock);
+
        unwind__finish_access(thread);
        nsinfo__zput(thread->nsinfo);
 
+       exit_rwsem(&thread->namespaces_lock);
+       exit_rwsem(&thread->comm_lock);
        free(thread);
 }
 
@@ -126,8 +136,8 @@ struct namespaces *thread__namespaces(const struct thread *thread)
        return list_first_entry(&thread->namespaces_list, struct namespaces, list);
 }
 
-int thread__set_namespaces(struct thread *thread, u64 timestamp,
-                          struct namespaces_event *event)
+static int __thread__set_namespaces(struct thread *thread, u64 timestamp,
+                                   struct namespaces_event *event)
 {
        struct namespaces *new, *curr = thread__namespaces(thread);
 
@@ -150,6 +160,17 @@ int thread__set_namespaces(struct thread *thread, u64 timestamp,
        return 0;
 }
 
+int thread__set_namespaces(struct thread *thread, u64 timestamp,
+                          struct namespaces_event *event)
+{
+       int ret;
+
+       down_write(&thread->namespaces_lock);
+       ret = __thread__set_namespaces(thread, timestamp, event);
+       up_write(&thread->namespaces_lock);
+       return ret;
+}
+
 struct comm *thread__comm(const struct thread *thread)
 {
        if (list_empty(&thread->comm_list))
@@ -171,8 +192,8 @@ struct comm *thread__exec_comm(const struct thread *thread)
        return last;
 }
 
-int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
-                      bool exec)
+static int ____thread__set_comm(struct thread *thread, const char *str,
+                               u64 timestamp, bool exec)
 {
        struct comm *new, *curr = thread__comm(thread);
 
@@ -196,6 +217,17 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
        return 0;
 }
 
+int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
+                      bool exec)
+{
+       int ret;
+
+       down_write(&thread->comm_lock);
+       ret = ____thread__set_comm(thread, str, timestamp, exec);
+       up_write(&thread->comm_lock);
+       return ret;
+}
+
 int thread__set_comm_from_proc(struct thread *thread)
 {
        char path[64];
@@ -213,7 +245,7 @@ int thread__set_comm_from_proc(struct thread *thread)
        return err;
 }
 
-const char *thread__comm_str(const struct thread *thread)
+static const char *__thread__comm_str(const struct thread *thread)
 {
        const struct comm *comm = thread__comm(thread);
 
@@ -223,6 +255,17 @@ const char *thread__comm_str(const struct thread *thread)
        return comm__str(comm);
 }
 
+const char *thread__comm_str(const struct thread *thread)
+{
+       const char *str;
+
+       down_read((struct rw_semaphore *)&thread->comm_lock);
+       str = __thread__comm_str(thread);
+       up_read((struct rw_semaphore *)&thread->comm_lock);
+
+       return str;
+}
+
 /* CHECKME: it should probably better return the max comm len from its comm list */
 int thread__comm_len(struct thread *thread)
 {
@@ -265,7 +308,7 @@ static int __thread__prepare_access(struct thread *thread)
                struct maps *maps = &thread->mg->maps[i];
                struct map *map;
 
-               pthread_rwlock_rdlock(&maps->lock);
+               down_read(&maps->lock);
 
                for (map = maps__first(maps); map; map = map__next(map)) {
                        err = unwind__prepare_access(thread, map, &initialized);
@@ -273,7 +316,7 @@ static int __thread__prepare_access(struct thread *thread)
                                break;
                }
 
-               pthread_rwlock_unlock(&maps->lock);
+               up_read(&maps->lock);
        }
 
        return err;
index fdcea7c0cac1d880a13c57896eb8cd907b8a397f..40cfa36c022ab71171a07b8a518fde8d4a035f99 100644 (file)
@@ -10,6 +10,7 @@
 #include "symbol.h"
 #include <strlist.h>
 #include <intlist.h>
+#include "rwsem.h"
 
 struct thread_stack;
 struct unwind_libunwind_ops;
@@ -30,7 +31,9 @@ struct thread {
        int                     comm_len;
        bool                    dead; /* if set thread has exited */
        struct list_head        namespaces_list;
+       struct rw_semaphore     namespaces_lock;
        struct list_head        comm_list;
+       struct rw_semaphore     comm_lock;
        u64                     db_id;
 
        void                    *priv;
index 506150a75bd008d0a1cbf0cf95fa2255e8b74a48..9892323cdd7cea3ea364541bb56e5d994e41d788 100644 (file)
@@ -38,6 +38,7 @@ struct perf_top {
        int                sym_pcnt_filter;
        const char         *sym_filter;
        float              min_percent;
+       unsigned int       nr_threads_synthesize;
 };
 
 #define CONSOLE_CLEAR "\e[H\e[2J"
index e7d60d05596d2ff54aa6f8ec1d2a0b8afcd17546..d7f2113462fbb97b3fb9e44294cd1be732831a45 100644 (file)
@@ -28,7 +28,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
-#include <pthread.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
index 8a9a677f75768205c47343c126813808e564a38a..40b425949aa31d7b4b334fa5923436f57dd2c842 100644 (file)
@@ -27,7 +27,6 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/mman.h>
-#include <pthread.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
index 3687b720327ac8ac4b0492cc2d814adbdc20a3ab..a789f952b3e9b8d84c6999f5486fb25d5a3676ba 100644 (file)
@@ -7,6 +7,7 @@
 #include <sys/stat.h>
 #include <sys/utsname.h>
 #include <dirent.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <signal.h>
 #include <stdio.h>
 /*
  * XXX We need to find a better place for these things...
  */
+
+bool perf_singlethreaded = true;
+
+void perf_set_singlethreaded(void)
+{
+       perf_singlethreaded = true;
+}
+
+void perf_set_multithreaded(void)
+{
+       perf_singlethreaded = false;
+}
+
 unsigned int page_size;
 int cacheline_size;
 
@@ -175,7 +189,7 @@ out:
        return err;
 }
 
-int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)
+static int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)
 {
        void *ptr;
        loff_t pgoff;
index b52765e6d7b472723b26bc0c2e4bbe8594d26ef1..01434509c2e9850611c863825396ee62e54ff45d 100644 (file)
@@ -6,7 +6,6 @@
 /* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
 #define _DEFAULT_SOURCE 1
 
-#include <fcntl.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdlib.h>
@@ -36,7 +35,6 @@ bool lsdir_no_dot_filter(const char *name, struct dirent *d);
 int copyfile(const char *from, const char *to);
 int copyfile_mode(const char *from, const char *to, mode_t mode);
 int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi);
-int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size);
 
 ssize_t readn(int fd, void *buf, size_t n);
 ssize_t writen(int fd, const void *buf, size_t n);
@@ -65,4 +63,9 @@ int sched_getcpu(void);
 int setns(int fd, int nstype);
 #endif
 
+extern bool perf_singlethreaded;
+
+void perf_set_singlethreaded(void);
+void perf_set_multithreaded(void);
+
 #endif /* GIT_COMPAT_UTIL_H */
index cffcda448c2820c7d51074188db8a90f901cea0c..0acb1ec0e2f08c0ead7aa14835725b3a20f2fd76 100644 (file)
@@ -320,7 +320,7 @@ struct dso *machine__findnew_vdso(struct machine *machine,
        struct vdso_info *vdso_info;
        struct dso *dso = NULL;
 
-       pthread_rwlock_wrlock(&machine->dsos.lock);
+       down_write(&machine->dsos.lock);
        if (!machine->vdso_info)
                machine->vdso_info = vdso_info__new();
 
@@ -348,7 +348,7 @@ struct dso *machine__findnew_vdso(struct machine *machine,
 
 out_unlock:
        dso__get(dso);
-       pthread_rwlock_unlock(&machine->dsos.lock);
+       up_write(&machine->dsos.lock);
        return dso;
 }
 
index 008fe68d7b76d83010c49d27d7fff469b2df7b7a..a725b958cf31bb67f04267d75b951035cb767a8c 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/stat.h>
index f7c7af1f9258b08ec2eb4f1c01a63184ea217b95..b436f8675f6a2e75ffbe414de36096280d3fa542 100644 (file)
@@ -39,6 +39,7 @@ TOOL_OBJS = \
        utnonansi.o\
        utprint.o\
        utstring.o\
+       utstrsuppt.o\
        utstrtoul64.o\
        utxferror.o\
        oslinuxtbl.o\
index 60df1fbd4a776a7e23da202b3ea6e3d69f93de78..0634449156d82e028427a90654523e0477424393 100644 (file)
@@ -287,8 +287,7 @@ int ap_dump_table_by_address(char *ascii_address)
 
        /* Convert argument to an integer physical address */
 
-       status = acpi_ut_strtoul64(ascii_address, ACPI_STRTOUL_64BIT,
-                                  &long_address);
+       status = acpi_ut_strtoul64(ascii_address, &long_address);
        if (ACPI_FAILURE(status)) {
                fprintf(stderr, "%s: Could not convert to a physical address\n",
                        ascii_address);
index 943b6b6146834384128c63b47ca6317f5be8fec4..22c3b4ee1617b8c83cde926d5e9e9fb1f37ee882 100644 (file)
@@ -208,9 +208,7 @@ static int ap_do_options(int argc, char **argv)
                case 'r':       /* Dump tables from specified RSDP */
 
                        status =
-                           acpi_ut_strtoul64(acpi_gbl_optarg,
-                                             ACPI_STRTOUL_64BIT,
-                                             &gbl_rsdp_base);
+                           acpi_ut_strtoul64(acpi_gbl_optarg, &gbl_rsdp_base);
                        if (ACPI_FAILURE(status)) {
                                fprintf(stderr,
                                        "%s: Could not convert to a physical address\n",
index d42073f12609e8a5dd63ce772f84dc35b5cb294d..1f9977cc609cf10adf5916f0cde5313019cbe116 100644 (file)
@@ -1,7 +1,6 @@
 .libs
 libcpupower.so
-libcpupower.so.0
-libcpupower.so.0.0.0
+libcpupower.so.*
 build/ccdv
 cpufreq-info
 cpufreq-set
index d6e1c02ddcfead4532cdc73f2d81207f62a8db5f..da205d1fa03c546c4972d1e696a5eeeaab1d9711 100644 (file)
@@ -30,6 +30,8 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
 $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
 endif
 
+include ../../scripts/Makefile.arch
+
 # --- CONFIGURATION BEGIN ---
 
 # Set the following to `true' to make a unstripped, unoptimized
@@ -79,7 +81,11 @@ bindir ?=    /usr/bin
 sbindir ?=     /usr/sbin
 mandir ?=      /usr/man
 includedir ?=  /usr/include
+ifeq ($(IS_64_BIT), 1)
+libdir ?=      /usr/lib64
+else
 libdir ?=      /usr/lib
+endif
 localedir ?=   /usr/share/locale
 docdir ?=       /usr/share/doc/packages/cpupower
 confdir ?=      /etc/
index 3e701f0e9c1438f781b6dd0248212d250da800a5..df43cd45d810447a50787c58964515ee79ea226d 100644 (file)
@@ -93,8 +93,6 @@ static void print_speed(unsigned long speed)
                if (speed > 1000000)
                        printf("%u.%06u GHz", ((unsigned int) speed/1000000),
                                ((unsigned int) speed%1000000));
-               else if (speed > 100000)
-                       printf("%u MHz", (unsigned int) speed);
                else if (speed > 1000)
                        printf("%u.%03u MHz", ((unsigned int) speed/1000),
                                (unsigned int) (speed%1000));
index 18ea223bd398a27aa966e3007e418f6a19d0de2c..cdb840bc54f2c64f9f8d30908848363762aa28d1 100644 (file)
@@ -39,7 +39,7 @@
 #define rmb()  asm volatile("lwsync":::"memory")
 #define wmb()  asm volatile("lwsync":::"memory")
 
-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+#define READ_ONCE(x) (*(volatile typeof(x) *)&(x))
 
 /* Prilvilege state DSCR access */
 inline unsigned long get_dscr(void)
index df17c3bab0a7e00496f4e80e7d78b7f3668d7238..9e1a37e93b63f7d4c8ece995fc2d2439f1d3cf40 100644 (file)
@@ -27,7 +27,7 @@ static void *do_test(void *in)
                unsigned long d, cur_dscr, cur_dscr_usr;
                unsigned long s1, s2;
 
-               s1 = ACCESS_ONCE(sequence);
+               s1 = READ_ONCE(sequence);
                if (s1 & 1)
                        continue;
                rmb();
index 49fa51726ce3fa8634db3581165f76e654a079c9..ef7fcbac3d421ad6d171ab1fed57a5ee2d716221 100755 (executable)
@@ -42,7 +42,7 @@ else
        exit 1
 fi
 
-T=/tmp/config_override.sh.$$
+T=${TMPDIR-/tmp}/config_override.sh.$$
 trap 'rm -rf $T' 0
 mkdir $T
 
index 70fca318a82b0b946e533f5a1b7c4a3f2b6570ff..197deece7c7c12fb5a407fc0b0daf2a5bf670102 100755 (executable)
@@ -19,7 +19,7 @@
 #
 # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 
-T=/tmp/abat-chk-config.sh.$$
+T=${TMPDIR-/tmp}/abat-chk-config.sh.$$
 trap 'rm -rf $T' 0
 mkdir $T
 
index 3f81a109520693ec6ebac0abe78c73388b8fc334..51f66a7ce876946391fa4bac164862853b69d51a 100755 (executable)
@@ -32,7 +32,7 @@
 #
 # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 
-T=/tmp/configinit.sh.$$
+T=${TMPDIR-/tmp}/configinit.sh.$$
 trap 'rm -rf $T' 0
 mkdir $T
 
index 46752c1646763bd6ea513c618dfd26bc14408cd3..fb66d017363883765361623a9fc351223e0bf255 100755 (executable)
@@ -35,7 +35,7 @@ then
        exit 1
 fi
 
-T=/tmp/test-linux.sh.$$
+T=${TMPDIR-/tmp}/test-linux.sh.$$
 trap 'rm -rf $T' 0
 mkdir $T
 
index 0af36a721b9c325ce8897f24889c4d3c3556594d..ab14b97c942c27dc74b03508153d3b744cb42133 100755 (executable)
@@ -38,7 +38,7 @@
 #
 # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 
-T=/tmp/kvm-test-1-run.sh.$$
+T=${TMPDIR-/tmp}/kvm-test-1-run.sh.$$
 trap 'rm -rf $T' 0
 mkdir $T
 
index b55895fb10edffcba90398ec5ef737a2f6159fac..ccd49e958fd28e10a57bc8f21a2a9053c15bcbd7 100755 (executable)
@@ -30,7 +30,7 @@
 scriptname=$0
 args="$*"
 
-T=/tmp/kvm.sh.$$
+T=${TMPDIR-/tmp}/kvm.sh.$$
 trap 'rm -rf $T' 0
 mkdir $T
 
@@ -222,7 +222,7 @@ do
                exit 1
        fi
 done
-sort -k2nr $T/cfgcpu > $T/cfgcpu.sort
+sort -k2nr $T/cfgcpu -T="$T" > $T/cfgcpu.sort
 
 # Use a greedy bin-packing algorithm, sorting the list accordingly.
 awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus '
index a6b57622c2e589c67f36455f49c853a5203640ab..24fe5f822b28d9ddcd9ddebe9df4d0bdfebde704 100755 (executable)
@@ -28,7 +28,7 @@
 
 F=$1
 title=$2
-T=/tmp/parse-build.sh.$$
+T=${TMPDIR-/tmp}/parse-build.sh.$$
 trap 'rm -rf $T' 0
 mkdir $T
 
index e3c5f0705696d648cfd7d8d3d05bad143593cfab..f12c38909b00ae99fb12f223f241d4c6690316e0 100755 (executable)
@@ -27,7 +27,7 @@
 #
 # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 
-T=/tmp/parse-torture.sh.$$
+T=${TMPDIR-/tmp}/parse-torture.sh.$$
 file="$1"
 title="$2"
 
index be3fdd351937c254fd8fe8f8cd6f16ea8b09e039..3f95a768a03b45c4fc32393297a4ed6af88145d6 100644 (file)
@@ -35,8 +35,7 @@
 #define rs_smp_mb() do {} while (0)
 #endif
 
-#define ACCESS_ONCE(x) (*(volatile typeof(x) *) &(x))
-#define READ_ONCE(x) ACCESS_ONCE(x)
-#define WRITE_ONCE(x, val) (ACCESS_ONCE(x) = (val))
+#define READ_ONCE(x) (*(volatile typeof(x) *) &(x))
+#define WRITE_ONCE(x) ((*(volatile typeof(x) *) &(x)) = (val))
 
 #endif
index d075ea0e5ca1ac0a42ce0d48e25b30a1a059de48..361466a2eaef34492e24588d4ef52d8aa68a53ac 100644 (file)
@@ -95,6 +95,27 @@ asm (
        "int3\n\t"
        "vmcode_int80:\n\t"
        "int $0x80\n\t"
+       "vmcode_umip:\n\t"
+       /* addressing via displacements */
+       "smsw (2052)\n\t"
+       "sidt (2054)\n\t"
+       "sgdt (2060)\n\t"
+       /* addressing via registers */
+       "mov $2066, %bx\n\t"
+       "smsw (%bx)\n\t"
+       "mov $2068, %bx\n\t"
+       "sidt (%bx)\n\t"
+       "mov $2074, %bx\n\t"
+       "sgdt (%bx)\n\t"
+       /* register operands, only for smsw */
+       "smsw %ax\n\t"
+       "mov %ax, (2080)\n\t"
+       "int3\n\t"
+       "vmcode_umip_str:\n\t"
+       "str %eax\n\t"
+       "vmcode_umip_sldt:\n\t"
+       "sldt %eax\n\t"
+       "int3\n\t"
        ".size vmcode, . - vmcode\n\t"
        "end_vmcode:\n\t"
        ".code32\n\t"
@@ -103,7 +124,8 @@ asm (
 
 extern unsigned char vmcode[], end_vmcode[];
 extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[],
-       vmcode_sti[], vmcode_int3[], vmcode_int80[];
+       vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[],
+       vmcode_umip_str[], vmcode_umip_sldt[];
 
 /* Returns false if the test was skipped. */
 static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
@@ -160,6 +182,68 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
        return true;
 }
 
+void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem)
+{
+       struct table_desc {
+               unsigned short limit;
+               unsigned long base;
+       } __attribute__((packed));
+
+       /* Initialize variables with arbitrary values */
+       struct table_desc gdt1 = { .base = 0x3c3c3c3c, .limit = 0x9999 };
+       struct table_desc gdt2 = { .base = 0x1a1a1a1a, .limit = 0xaeae };
+       struct table_desc idt1 = { .base = 0x7b7b7b7b, .limit = 0xf1f1 };
+       struct table_desc idt2 = { .base = 0x89898989, .limit = 0x1313 };
+       unsigned short msw1 = 0x1414, msw2 = 0x2525, msw3 = 3737;
+
+       /* UMIP -- exit with INT3 unless kernel emulation did not trap #GP */
+       do_test(vm86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests");
+
+       /* Results from displacement-only addressing */
+       msw1 = *(unsigned short *)(test_mem + 2052);
+       memcpy(&idt1, test_mem + 2054, sizeof(idt1));
+       memcpy(&gdt1, test_mem + 2060, sizeof(gdt1));
+
+       /* Results from register-indirect addressing */
+       msw2 = *(unsigned short *)(test_mem + 2066);
+       memcpy(&idt2, test_mem + 2068, sizeof(idt2));
+       memcpy(&gdt2, test_mem + 2074, sizeof(gdt2));
+
+       /* Results when using register operands */
+       msw3 = *(unsigned short *)(test_mem + 2080);
+
+       printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1);
+       printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n",
+              idt1.limit, idt1.base);
+       printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n",
+              gdt1.limit, gdt1.base);
+
+       if (msw1 != msw2 || msw1 != msw3)
+               printf("[FAIL]\tAll the results of SMSW should be the same.\n");
+       else
+               printf("[PASS]\tAll the results from SMSW are identical.\n");
+
+       if (memcmp(&gdt1, &gdt2, sizeof(gdt1)))
+               printf("[FAIL]\tAll the results of SGDT should be the same.\n");
+       else
+               printf("[PASS]\tAll the results from SGDT are identical.\n");
+
+       if (memcmp(&idt1, &idt2, sizeof(idt1)))
+               printf("[FAIL]\tAll the results of SIDT should be the same.\n");
+       else
+               printf("[PASS]\tAll the results from SIDT are identical.\n");
+
+       sethandler(SIGILL, sighandler, 0);
+       do_test(vm86, vmcode_umip_str - vmcode, VM86_SIGNAL, 0,
+               "STR instruction");
+       clearhandler(SIGILL);
+
+       sethandler(SIGILL, sighandler, 0);
+       do_test(vm86, vmcode_umip_sldt - vmcode, VM86_SIGNAL, 0,
+               "SLDT instruction");
+       clearhandler(SIGILL);
+}
+
 int main(void)
 {
        struct vm86plus_struct v86;
@@ -218,6 +302,9 @@ int main(void)
        v86.regs.eax = (unsigned int)-1;
        do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80");
 
+       /* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */
+       do_umip_tests(&v86, addr);
+
        /* Execute a null pointer */
        v86.regs.cs = 0;
        v86.regs.ss = 0;
index 961e3ee26c27229312e539f155aa3d89e391241b..66e5ce5b91f008d5dffc7848d0e99d730ad589b5 100644 (file)
@@ -115,7 +115,15 @@ static void check_valid_segment(uint16_t index, int ldt,
                return;
        }
 
-       if (ar != expected_ar) {
+       /* The SDM says "bits 19:16 are undefined".  Thanks. */
+       ar &= ~0xF0000;
+
+       /*
+        * NB: Different Linux versions do different things with the
+        * accessed bit in set_thread_area().
+        */
+       if (ar != expected_ar &&
+           (ldt || ar != (expected_ar | AR_ACCESSED))) {
                printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n",
                       (ldt ? "LDT" : "GDT"), index, ar, expected_ar);
                nerrs++;
@@ -129,30 +137,51 @@ static void check_valid_segment(uint16_t index, int ldt,
        }
 }
 
-static bool install_valid_mode(const struct user_desc *desc, uint32_t ar,
-                              bool oldmode)
+static bool install_valid_mode(const struct user_desc *d, uint32_t ar,
+                              bool oldmode, bool ldt)
 {
-       int ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,
-                         desc, sizeof(*desc));
-       if (ret < -1)
-               errno = -ret;
+       struct user_desc desc = *d;
+       int ret;
+
+       if (!ldt) {
+#ifndef __i386__
+               /* No point testing set_thread_area in a 64-bit build */
+               return false;
+#endif
+               if (!gdt_entry_num)
+                       return false;
+               desc.entry_number = gdt_entry_num;
+
+               ret = syscall(SYS_set_thread_area, &desc);
+       } else {
+               ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,
+                             &desc, sizeof(desc));
+
+               if (ret < -1)
+                       errno = -ret;
+
+               if (ret != 0 && errno == ENOSYS) {
+                       printf("[OK]\tmodify_ldt returned -ENOSYS\n");
+                       return false;
+               }
+       }
+
        if (ret == 0) {
-               uint32_t limit = desc->limit;
-               if (desc->limit_in_pages)
+               uint32_t limit = desc.limit;
+               if (desc.limit_in_pages)
                        limit = (limit << 12) + 4095;
-               check_valid_segment(desc->entry_number, 1, ar, limit, true);
+               check_valid_segment(desc.entry_number, ldt, ar, limit, true);
                return true;
-       } else if (errno == ENOSYS) {
-               printf("[OK]\tmodify_ldt returned -ENOSYS\n");
-               return false;
        } else {
-               if (desc->seg_32bit) {
-                       printf("[FAIL]\tUnexpected modify_ldt failure %d\n",
+               if (desc.seg_32bit) {
+                       printf("[FAIL]\tUnexpected %s failure %d\n",
+                              ldt ? "modify_ldt" : "set_thread_area",
                               errno);
                        nerrs++;
                        return false;
                } else {
-                       printf("[OK]\tmodify_ldt rejected 16 bit segment\n");
+                       printf("[OK]\t%s rejected 16 bit segment\n",
+                              ldt ? "modify_ldt" : "set_thread_area");
                        return false;
                }
        }
@@ -160,7 +189,15 @@ static bool install_valid_mode(const struct user_desc *desc, uint32_t ar,
 
 static bool install_valid(const struct user_desc *desc, uint32_t ar)
 {
-       return install_valid_mode(desc, ar, false);
+       bool ret = install_valid_mode(desc, ar, false, true);
+
+       if (desc->contents <= 1 && desc->seg_32bit &&
+           !desc->seg_not_present) {
+               /* Should work in the GDT, too. */
+               install_valid_mode(desc, ar, false, false);
+       }
+
+       return ret;
 }
 
 static void install_invalid(const struct user_desc *desc, bool oldmode)
@@ -367,9 +404,24 @@ static void do_simple_tests(void)
        install_invalid(&desc, false);
 
        desc.seg_not_present = 0;
-       desc.read_exec_only = 0;
        desc.seg_32bit = 1;
+       desc.read_exec_only = 0;
+       desc.limit = 0xfffff;
+
        install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB);
+
+       desc.limit_in_pages = 1;
+
+       install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB | AR_G);
+       desc.read_exec_only = 1;
+       install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S | AR_P | AR_DB | AR_G);
+       desc.contents = 1;
+       desc.read_exec_only = 0;
+       install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G);
+       desc.read_exec_only = 1;
+       install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G);
+
+       desc.limit = 0;
        install_invalid(&desc, true);
 }
 
index 555e43ca846b2bd5fb27cf50d796b2696c85989a..7a1cc0e56d2d6a5006548f9f4488ae003db24911 100644 (file)
@@ -189,17 +189,29 @@ void lots_o_noops_around_write(int *write_to_me)
 #define u64 uint64_t
 
 #ifdef __i386__
-#define SYS_mprotect_key 380
-#define SYS_pkey_alloc  381
-#define SYS_pkey_free   382
+
+#ifndef SYS_mprotect_key
+# define SYS_mprotect_key 380
+#endif
+#ifndef SYS_pkey_alloc
+# define SYS_pkey_alloc         381
+# define SYS_pkey_free  382
+#endif
 #define REG_IP_IDX REG_EIP
 #define si_pkey_offset 0x14
+
 #else
-#define SYS_mprotect_key 329
-#define SYS_pkey_alloc  330
-#define SYS_pkey_free   331
+
+#ifndef SYS_mprotect_key
+# define SYS_mprotect_key 329
+#endif
+#ifndef SYS_pkey_alloc
+# define SYS_pkey_alloc         330
+# define SYS_pkey_free  331
+#endif
 #define REG_IP_IDX REG_RIP
 #define si_pkey_offset 0x20
+
 #endif
 
 void dump_mem(void *dumpme, int len_bytes)
index 90b0133004e17ddbc48b90a9eab2e6a489da13b0..5706e075adf2655280db219951cdc34544823871 100644 (file)
@@ -110,11 +110,15 @@ static inline void busy_wait(void)
                barrier();
 } 
 
+#if defined(__x86_64__) || defined(__i386__)
+#define smp_mb()     asm volatile("lock; addl $0,-128(%%rsp)" ::: "memory", "cc")
+#else
 /*
  * Not using __ATOMIC_SEQ_CST since gcc docs say they are only synchronized
  * with other __ATOMIC_SEQ_CST calls.
  */
 #define smp_mb() __sync_synchronize()
+#endif
 
 /*
  * This abuses the atomic builtins for thread fences, and
index 9deb5a245b83032ffaa960d42cd6f01ecb614b1b..ce507ae1d4f50e6af019c94baaa800a8aaaa695c 100644 (file)
@@ -2302,7 +2302,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 (!ACCESS_ONCE(vcpu->preempted))
+                       if (!READ_ONCE(vcpu->preempted))
                                continue;
                        if (vcpu == me)
                                continue;