From 1c0f7ae38f6e34183c37e58c41f95260796b1a3f Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 22 Mar 2013 08:42:57 -0400 Subject: [PATCH] --- yaml --- r: 373287 b: refs/heads/master c: 73a999fab313053ceebffa9293fadf5a306a58e8 h: refs/heads/master i: 373285: cddbf2752749f8c19f30144bb26261a83585f071 373283: b1675f7f0726527d69b07c4ce67bde35099afead 373279: aeaecf457cff43dc575954be3b2f9aca45bcebf4 v: v3 --- [refs] | 2 +- trunk/Documentation/RCU/stallwarn.txt | 2 +- trunk/Documentation/cpu-freq/governors.txt | 4 +- .../bindings/input/cros-ec-keyb.txt | 72 - .../devicetree/bindings/mfd/as3711.txt | 73 - .../devicetree/bindings/mfd/cros-ec.txt | 56 - .../devicetree/bindings/mfd/omap-usb-host.txt | 80 - .../devicetree/bindings/mfd/omap-usb-tll.txt | 17 - .../devicetree/bindings/sound/wm8994.txt | 58 +- trunk/Documentation/kernel-parameters.txt | 8 - trunk/Documentation/s390/CommonIO | 12 +- trunk/Documentation/timers/NO_HZ.txt | 273 --- trunk/Documentation/virtual/kvm/api.txt | 146 +- .../Documentation/virtual/kvm/devices/README | 1 - .../virtual/kvm/devices/mpic.txt | 53 - .../virtual/kvm/devices/xics.txt | 66 - trunk/Makefile | 2 +- trunk/arch/Kconfig | 6 - trunk/arch/arm/include/asm/idmap.h | 1 + trunk/arch/arm/include/asm/kvm_host.h | 47 +- trunk/arch/arm/include/asm/kvm_mmu.h | 28 +- trunk/arch/arm/kernel/asm-offsets.c | 2 +- trunk/arch/arm/kernel/swp_emulate.c | 2 +- trunk/arch/arm/kernel/vmlinux.lds.S | 7 +- trunk/arch/arm/kvm/Kconfig | 6 +- trunk/arch/arm/kvm/Makefile | 2 +- trunk/arch/arm/kvm/arch_timer.c | 7 +- trunk/arch/arm/kvm/arm.c | 129 +- trunk/arch/arm/kvm/init.S | 78 +- trunk/arch/arm/kvm/mmu.c | 455 ++-- trunk/arch/arm/kvm/perf.c | 68 - trunk/arch/arm/mach-imx/Kconfig | 2 + trunk/arch/arm/mach-omap1/pm.c | 2 +- trunk/arch/arm/mach-s3c64xx/Kconfig | 3 + .../arm/mach-s3c64xx/mach-crag6410-module.c | 4 +- trunk/arch/arm/mm/idmap.c | 32 +- trunk/arch/blackfin/Kconfig | 5 +- trunk/arch/cris/arch-v10/kernel/fasttimer.c | 2 +- trunk/arch/cris/arch-v32/kernel/fasttimer.c | 2 +- trunk/arch/h8300/Kconfig | 5 +- trunk/arch/h8300/kernel/gpio.c | 2 +- trunk/arch/ia64/include/asm/kvm_host.h | 1 - trunk/arch/ia64/include/uapi/asm/kvm.h | 1 + trunk/arch/ia64/kernel/palinfo.c | 2 +- trunk/arch/ia64/kernel/salinfo.c | 2 +- trunk/arch/ia64/kvm/Kconfig | 14 +- trunk/arch/ia64/kvm/Makefile | 6 +- trunk/arch/ia64/kvm/kvm-ia64.c | 35 +- trunk/arch/ia64/kvm/lapic.h | 6 + trunk/arch/ia64/sn/kernel/sn2/prominfo_proc.c | 4 +- trunk/arch/metag/Kconfig | 5 +- trunk/arch/mips/kernel/smtc-proc.c | 2 +- trunk/arch/mips/pci/ops-pmcmsp.c | 4 +- trunk/arch/mips/sibyte/sb1250/bus_watcher.c | 2 +- trunk/arch/parisc/kernel/pdc_chassis.c | 2 +- trunk/arch/powerpc/include/asm/hvcall.h | 3 - trunk/arch/powerpc/include/asm/kvm_book3s.h | 7 +- .../arch/powerpc/include/asm/kvm_book3s_64.h | 13 - .../arch/powerpc/include/asm/kvm_book3s_asm.h | 8 +- trunk/arch/powerpc/include/asm/kvm_booke.h | 2 - trunk/arch/powerpc/include/asm/kvm_host.h | 41 +- trunk/arch/powerpc/include/asm/kvm_ppc.h | 114 +- trunk/arch/powerpc/include/asm/reg.h | 1 - trunk/arch/powerpc/include/uapi/asm/kvm.h | 94 - trunk/arch/powerpc/kernel/asm-offsets.c | 4 - trunk/arch/powerpc/kvm/44x.c | 12 - trunk/arch/powerpc/kvm/Kconfig | 26 +- trunk/arch/powerpc/kvm/Makefile | 12 +- trunk/arch/powerpc/kvm/book3s.c | 36 +- trunk/arch/powerpc/kvm/book3s_64_mmu_hv.c | 120 +- trunk/arch/powerpc/kvm/book3s_emulate.c | 4 +- trunk/arch/powerpc/kvm/book3s_hv.c | 92 +- trunk/arch/powerpc/kvm/book3s_hv_rm_mmu.c | 11 + trunk/arch/powerpc/kvm/book3s_hv_rm_xics.c | 406 ---- trunk/arch/powerpc/kvm/book3s_hv_rmhandlers.S | 228 +- trunk/arch/powerpc/kvm/book3s_pr.c | 7 +- trunk/arch/powerpc/kvm/book3s_pr_papr.c | 21 - trunk/arch/powerpc/kvm/book3s_rtas.c | 274 --- trunk/arch/powerpc/kvm/book3s_xics.c | 1270 ----------- trunk/arch/powerpc/kvm/book3s_xics.h | 130 -- trunk/arch/powerpc/kvm/booke.c | 158 +- trunk/arch/powerpc/kvm/booke_interrupts.S | 42 +- trunk/arch/powerpc/kvm/e500.c | 14 - trunk/arch/powerpc/kvm/e500.h | 22 - trunk/arch/powerpc/kvm/e500_emulate.c | 19 - trunk/arch/powerpc/kvm/e500_mmu.c | 192 +- trunk/arch/powerpc/kvm/e500mc.c | 16 - trunk/arch/powerpc/kvm/emulate.c | 2 - trunk/arch/powerpc/kvm/irq.h | 20 - trunk/arch/powerpc/kvm/mpic.c | 1853 ----------------- trunk/arch/powerpc/kvm/powerpc.c | 133 +- trunk/arch/powerpc/sysdev/xics/icp-native.c | 8 - trunk/arch/s390/include/asm/pgtable.h | 66 +- trunk/arch/s390/include/asm/setup.h | 9 +- trunk/arch/s390/include/uapi/asm/Kbuild | 1 - trunk/arch/s390/include/uapi/asm/virtio-ccw.h | 21 - trunk/arch/s390/kernel/Makefile | 2 +- trunk/arch/s390/kernel/crash_dump.c | 6 +- trunk/arch/s390/kernel/early.c | 1 + trunk/arch/s390/kernel/mem_detect.c | 145 ++ trunk/arch/s390/kernel/setup.c | 65 +- trunk/arch/s390/kvm/Kconfig | 1 - trunk/arch/s390/kvm/Makefile | 2 +- trunk/arch/s390/kvm/diag.c | 26 - trunk/arch/s390/kvm/gaccess.h | 429 +++- trunk/arch/s390/kvm/intercept.c | 18 +- trunk/arch/s390/kvm/interrupt.c | 245 ++- trunk/arch/s390/kvm/kvm-s390.c | 43 +- trunk/arch/s390/kvm/kvm-s390.h | 12 +- trunk/arch/s390/kvm/priv.c | 270 ++- trunk/arch/s390/lib/uaccess_pt.c | 3 - trunk/arch/s390/mm/Makefile | 2 +- trunk/arch/s390/mm/init.c | 11 - trunk/arch/s390/mm/mem_detect.c | 134 -- trunk/arch/s390/mm/pgtable.c | 121 +- trunk/arch/s390/mm/vmem.c | 8 +- trunk/arch/sh/drivers/dma/dma-api.c | 2 +- trunk/arch/sparc/Kconfig | 20 +- trunk/arch/sparc/Makefile | 1 - trunk/arch/sparc/include/asm/cmpxchg_64.h | 1 - trunk/arch/sparc/include/asm/head_32.h | 6 +- trunk/arch/sparc/include/asm/hibernate.h | 23 - trunk/arch/sparc/include/asm/leon_pci.h | 1 - trunk/arch/sparc/include/asm/mmu_context_64.h | 2 +- trunk/arch/sparc/include/asm/processor_64.h | 3 + trunk/arch/sparc/kernel/Makefile | 3 +- trunk/arch/sparc/kernel/asm-offsets.c | 15 - trunk/arch/sparc/kernel/leon_kernel.c | 10 +- trunk/arch/sparc/kernel/leon_pci.c | 2 - trunk/arch/sparc/kernel/leon_pci_grpci1.c | 724 ------- trunk/arch/sparc/kernel/leon_pci_grpci2.c | 5 - trunk/arch/sparc/kernel/leon_pmc.c | 4 +- trunk/arch/sparc/kernel/vio.c | 1 - trunk/arch/sparc/mm/init_64.c | 7 +- trunk/arch/sparc/power/Makefile | 3 - trunk/arch/sparc/power/hibernate.c | 42 - trunk/arch/sparc/power/hibernate_asm.S | 131 -- trunk/arch/um/include/shared/common-offsets.h | 4 +- trunk/arch/um/os-Linux/time.c | 2 +- trunk/arch/x86/include/asm/entry_arch.h | 4 - trunk/arch/x86/include/asm/hardirq.h | 3 - trunk/arch/x86/include/asm/hw_irq.h | 1 - trunk/arch/x86/include/asm/irq_vectors.h | 5 - trunk/arch/x86/include/asm/kvm_host.h | 26 +- trunk/arch/x86/include/asm/vmx.h | 18 - trunk/arch/x86/include/uapi/asm/kvm.h | 1 + trunk/arch/x86/include/uapi/asm/msr-index.h | 2 - trunk/arch/x86/include/uapi/asm/vmx.h | 5 +- trunk/arch/x86/kernel/cpu/perf_event_intel.c | 13 +- .../x86/kernel/cpu/perf_event_intel_lbr.c | 27 +- .../x86/kernel/cpu/perf_event_intel_uncore.c | 19 +- trunk/arch/x86/kernel/entry_64.S | 5 - trunk/arch/x86/kernel/irq.c | 26 +- trunk/arch/x86/kernel/irqinit.c | 4 - trunk/arch/x86/kernel/kvmclock.c | 9 +- trunk/arch/x86/kvm/Kconfig | 14 +- trunk/arch/x86/kvm/Makefile | 5 +- trunk/arch/x86/kvm/emulate.c | 31 +- trunk/arch/x86/kvm/i8254.c | 4 +- trunk/arch/x86/kvm/lapic.c | 189 +- trunk/arch/x86/kvm/lapic.h | 22 +- trunk/arch/x86/kvm/mmu.c | 108 +- trunk/arch/x86/kvm/mmu.h | 11 +- trunk/arch/x86/kvm/paging_tmpl.h | 2 +- trunk/arch/x86/kvm/pmu.c | 14 +- trunk/arch/x86/kvm/svm.c | 40 +- trunk/arch/x86/kvm/vmx.c | 1077 +++------- trunk/arch/x86/kvm/x86.c | 243 +-- .../crypto/asymmetric_keys/x509_cert_parser.c | 55 +- trunk/drivers/char/ds1620.c | 2 +- trunk/drivers/char/efirtc.c | 2 +- trunk/drivers/char/genrtc.c | 2 +- trunk/drivers/gpio/gpio-ucb1400.c | 19 +- trunk/drivers/input/keyboard/Kconfig | 12 - trunk/drivers/input/keyboard/Makefile | 1 - trunk/drivers/input/keyboard/cros_ec_keyb.c | 334 --- trunk/drivers/input/keyboard/lpc32xx-keys.c | 11 +- trunk/drivers/input/keyboard/omap4-keypad.c | 16 +- trunk/drivers/input/keyboard/tca8418_keypad.c | 7 +- trunk/drivers/input/matrix-keymap.c | 20 - trunk/drivers/input/misc/hp_sdc_rtc.c | 2 +- trunk/drivers/mfd/88pm860x-core.c | 12 +- trunk/drivers/mfd/Kconfig | 1606 +++++++------- trunk/drivers/mfd/Makefile | 9 +- trunk/drivers/mfd/aat2870-core.c | 20 +- trunk/drivers/mfd/ab3100-otp.c | 14 +- trunk/drivers/mfd/ab8500-core.c | 28 +- trunk/drivers/mfd/ab8500-gpadc.c | 2 +- trunk/drivers/mfd/ab8500-sysctrl.c | 2 +- trunk/drivers/mfd/adp5520.c | 20 +- trunk/drivers/mfd/arizona-core.c | 267 +-- trunk/drivers/mfd/arizona-irq.c | 106 +- trunk/drivers/mfd/arizona-spi.c | 2 +- trunk/drivers/mfd/as3711.c | 27 +- trunk/drivers/mfd/cros_ec.c | 196 -- trunk/drivers/mfd/cros_ec_i2c.c | 201 -- trunk/drivers/mfd/cros_ec_spi.c | 375 ---- trunk/drivers/mfd/da903x.c | 19 +- trunk/drivers/mfd/da9052-spi.c | 4 +- trunk/drivers/mfd/da9055-core.c | 2 +- trunk/drivers/mfd/davinci_voicecodec.c | 12 +- trunk/drivers/mfd/db8500-prcmu.c | 72 +- trunk/drivers/mfd/ezx-pcap.c | 21 +- trunk/drivers/mfd/htc-pasic3.c | 13 +- trunk/drivers/mfd/intel_msic.c | 10 +- trunk/drivers/mfd/lm3533-core.c | 8 +- trunk/drivers/mfd/max77686.c | 2 +- trunk/drivers/mfd/mc13xxx-spi.c | 6 +- trunk/drivers/mfd/omap-usb-host.c | 209 +- trunk/drivers/mfd/omap-usb-tll.c | 219 +- trunk/drivers/mfd/omap-usb.h | 5 +- trunk/drivers/mfd/palmas.c | 7 +- trunk/drivers/mfd/retu-mfd.c | 85 +- trunk/drivers/mfd/rts5249.c | 241 --- trunk/drivers/mfd/rtsx_pcr.c | 11 +- trunk/drivers/mfd/rtsx_pcr.h | 1 - trunk/drivers/mfd/si476x-cmd.c | 1553 -------------- trunk/drivers/mfd/si476x-i2c.c | 886 -------- trunk/drivers/mfd/si476x-prop.c | 241 --- trunk/drivers/mfd/sta2x11-mfd.c | 11 + trunk/drivers/mfd/stmpe-i2c.c | 1 - trunk/drivers/mfd/stmpe-spi.c | 2 +- trunk/drivers/mfd/stmpe.c | 105 +- trunk/drivers/mfd/stmpe.h | 49 - trunk/drivers/mfd/syscon.c | 80 +- trunk/drivers/mfd/tc3589x.c | 21 +- trunk/drivers/mfd/tps65090.c | 11 - trunk/drivers/mfd/twl4030-madc.c | 14 +- trunk/drivers/mfd/twl6040.c | 31 +- trunk/drivers/mfd/ucb1400_core.c | 5 - trunk/drivers/mfd/vexpress-config.c | 35 +- trunk/drivers/mfd/vexpress-sysreg.c | 4 +- trunk/drivers/mfd/wm5102-tables.c | 56 +- trunk/drivers/mfd/wm831x-spi.c | 6 +- trunk/drivers/mfd/wm8994-core.c | 88 +- trunk/drivers/mtd/chips/gen_probe.c | 8 +- .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- trunk/drivers/net/ethernet/emulex/benet/be.h | 1 - .../net/ethernet/emulex/benet/be_cmds.c | 35 +- .../net/ethernet/emulex/benet/be_cmds.h | 2 +- .../net/ethernet/emulex/benet/be_ethtool.c | 1 - .../net/ethernet/emulex/benet/be_main.c | 54 +- trunk/drivers/net/ethernet/marvell/sky2.c | 2 - trunk/drivers/net/ethernet/ti/cpsw.c | 2 +- trunk/drivers/net/usb/asix_common.c | 3 - trunk/drivers/net/usb/pegasus.c | 3 +- trunk/drivers/net/usb/qmi_wwan.c | 1 - trunk/drivers/net/wireless/atmel.c | 2 +- trunk/drivers/net/wireless/hostap/hostap_ap.c | 4 +- trunk/drivers/net/wireless/hostap/hostap_hw.c | 2 +- .../drivers/net/wireless/hostap/hostap_proc.c | 6 +- trunk/drivers/net/xen-netback/netback.c | 69 +- trunk/drivers/power/rx51_battery.c | 1 - trunk/drivers/s390/char/sclp_cmd.c | 20 +- trunk/drivers/s390/char/zcore.c | 34 +- trunk/drivers/s390/cio/blacklist.c | 28 +- trunk/drivers/s390/crypto/ap_bus.c | 17 +- trunk/drivers/s390/kvm/kvm_virtio.c | 11 +- trunk/drivers/s390/kvm/virtio_ccw.c | 20 +- trunk/drivers/scsi/megaraid.c | 2 +- trunk/drivers/staging/comedi/proc.c | 2 +- trunk/drivers/staging/csr/io.c | 2 +- trunk/drivers/staging/cxt1e1/sbeproc.c | 2 +- .../ft1000/ft1000-pcmcia/ft1000_proc.c | 2 +- .../staging/ft1000/ft1000-usb/ft1000_proc.c | 2 +- trunk/drivers/staging/rtl8187se/r8180_core.c | 2 +- trunk/drivers/staging/rtl8192u/r8192U_core.c | 2 +- trunk/drivers/staging/wlags49_h2/wl_main.c | 2 +- trunk/drivers/tty/serial/sunsu.c | 1 - trunk/drivers/usb/gadget/fsl_udc_core.c | 2 +- trunk/drivers/usb/gadget/goku_udc.c | 2 +- trunk/fs/autofs4/expire.c | 9 + trunk/fs/autofs4/root.c | 2 +- trunk/fs/cifs/connect.c | 56 +- trunk/include/asm-generic/cputime_nsecs.h | 28 +- trunk/include/asm-generic/unistd.h | 1 - trunk/include/asm-generic/vmlinux.lds.h | 8 +- trunk/include/linux/export.h | 20 +- trunk/include/linux/i2c/twl4030-madc.h | 2 - trunk/include/linux/input/matrix_keypad.h | 19 - trunk/include/linux/kernel.h | 7 + trunk/include/linux/kvm_host.h | 166 +- trunk/include/linux/linkage.h | 20 +- trunk/include/linux/mfd/arizona/pdata.h | 7 +- trunk/include/linux/mfd/cros_ec.h | 170 -- trunk/include/linux/mfd/cros_ec_commands.h | 1369 ------------ trunk/include/linux/mfd/palmas.h | 12 +- trunk/include/linux/mfd/retu.h | 8 +- trunk/include/linux/mfd/rtsx_pci.h | 36 - trunk/include/linux/mfd/si476x-core.h | 533 ----- trunk/include/linux/mfd/si476x-platform.h | 267 --- trunk/include/linux/mfd/si476x-reports.h | 163 -- trunk/include/linux/mfd/stmpe.h | 3 - trunk/include/linux/mfd/syscon.h | 3 - trunk/include/linux/mfd/tps65090.h | 1 - trunk/include/linux/module.h | 4 +- trunk/include/linux/of.h | 5 - trunk/include/linux/perf_event.h | 6 - trunk/include/linux/posix-timers.h | 2 - trunk/include/linux/rcupdate.h | 7 - trunk/include/linux/sched.h | 19 +- trunk/include/linux/tick.h | 25 +- trunk/include/linux/ucb1400.h | 18 +- trunk/include/trace/events/kvm.h | 12 +- trunk/include/trace/events/timer.h | 21 - trunk/include/uapi/linux/kvm.h | 45 +- trunk/init/Kconfig | 12 +- trunk/init/main.c | 1 - trunk/ipc/sem.c | 86 +- trunk/kernel/Makefile | 2 +- trunk/kernel/events/core.c | 17 +- trunk/kernel/events/ring_buffer.c | 14 +- trunk/kernel/hrtimer.c | 4 +- trunk/kernel/kallsyms.c | 26 +- trunk/kernel/modsign_certificate.S | 13 +- trunk/kernel/module.c | 18 +- trunk/kernel/posix-cpu-timers.c | 76 +- trunk/kernel/rcutree.c | 16 +- trunk/kernel/rcutree.h | 2 +- trunk/kernel/rcutree_plugin.h | 33 +- trunk/kernel/rcutree_trace.c | 8 +- trunk/kernel/sched/core.c | 92 +- trunk/kernel/sched/fair.c | 10 +- trunk/kernel/sched/idle_task.c | 1 - trunk/kernel/sched/sched.h | 25 +- trunk/kernel/softirq.c | 19 +- trunk/kernel/time/Kconfig | 80 +- trunk/kernel/time/tick-broadcast.c | 3 +- trunk/kernel/time/tick-common.c | 5 +- trunk/kernel/time/tick-sched.c | 296 +-- trunk/kernel/timer.c | 16 +- trunk/lib/oid_registry.c | 5 - trunk/net/8021q/vlan_dev.c | 2 +- trunk/net/bridge/br_stp_timer.c | 2 +- trunk/net/core/dev.c | 2 +- trunk/net/core/ethtool.c | 2 +- trunk/net/ipv4/af_inet.c | 1 - trunk/net/ipv4/gre.c | 4 +- trunk/net/ipv4/udp.c | 7 +- trunk/net/packet/af_packet.c | 53 +- trunk/net/tipc/bcast.c | 40 +- trunk/scripts/Makefile.build | 3 +- trunk/scripts/Makefile.lib | 7 + trunk/scripts/Makefile.modpost | 8 +- trunk/scripts/genksyms/genksyms.c | 18 +- trunk/scripts/link-vmlinux.sh | 5 +- trunk/scripts/mod/modpost.c | 94 +- trunk/virt/kvm/Kconfig | 3 - trunk/virt/kvm/assigned-dev.c | 43 +- trunk/virt/kvm/eventfd.c | 53 +- trunk/virt/kvm/ioapic.c | 163 +- trunk/virt/kvm/ioapic.h | 27 +- trunk/virt/kvm/irq_comm.c | 215 +- trunk/virt/kvm/irqchip.c | 237 --- trunk/virt/kvm/kvm_main.c | 258 +-- 355 files changed, 4451 insertions(+), 20521 deletions(-) delete mode 100644 trunk/Documentation/devicetree/bindings/input/cros-ec-keyb.txt delete mode 100644 trunk/Documentation/devicetree/bindings/mfd/as3711.txt delete mode 100644 trunk/Documentation/devicetree/bindings/mfd/cros-ec.txt delete mode 100644 trunk/Documentation/devicetree/bindings/mfd/omap-usb-host.txt delete mode 100644 trunk/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt delete mode 100644 trunk/Documentation/timers/NO_HZ.txt delete mode 100644 trunk/Documentation/virtual/kvm/devices/README delete mode 100644 trunk/Documentation/virtual/kvm/devices/mpic.txt delete mode 100644 trunk/Documentation/virtual/kvm/devices/xics.txt delete mode 100644 trunk/arch/arm/kvm/perf.c delete mode 100644 trunk/arch/powerpc/kvm/book3s_hv_rm_xics.c delete mode 100644 trunk/arch/powerpc/kvm/book3s_rtas.c delete mode 100644 trunk/arch/powerpc/kvm/book3s_xics.c delete mode 100644 trunk/arch/powerpc/kvm/book3s_xics.h delete mode 100644 trunk/arch/powerpc/kvm/irq.h delete mode 100644 trunk/arch/powerpc/kvm/mpic.c delete mode 100644 trunk/arch/s390/include/uapi/asm/virtio-ccw.h create mode 100644 trunk/arch/s390/kernel/mem_detect.c delete mode 100644 trunk/arch/s390/mm/mem_detect.c delete mode 100644 trunk/arch/sparc/include/asm/hibernate.h delete mode 100644 trunk/arch/sparc/kernel/leon_pci_grpci1.c delete mode 100644 trunk/arch/sparc/power/Makefile delete mode 100644 trunk/arch/sparc/power/hibernate.c delete mode 100644 trunk/arch/sparc/power/hibernate_asm.S delete mode 100644 trunk/drivers/input/keyboard/cros_ec_keyb.c delete mode 100644 trunk/drivers/mfd/cros_ec.c delete mode 100644 trunk/drivers/mfd/cros_ec_i2c.c delete mode 100644 trunk/drivers/mfd/cros_ec_spi.c delete mode 100644 trunk/drivers/mfd/rts5249.c delete mode 100644 trunk/drivers/mfd/si476x-cmd.c delete mode 100644 trunk/drivers/mfd/si476x-i2c.c delete mode 100644 trunk/drivers/mfd/si476x-prop.c delete mode 100644 trunk/include/linux/mfd/cros_ec.h delete mode 100644 trunk/include/linux/mfd/cros_ec_commands.h delete mode 100644 trunk/include/linux/mfd/si476x-core.h delete mode 100644 trunk/include/linux/mfd/si476x-platform.h delete mode 100644 trunk/include/linux/mfd/si476x-reports.h delete mode 100644 trunk/virt/kvm/irqchip.c diff --git a/[refs] b/[refs] index 16771a86bfb0..8c74b6fe2a8d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: ce8a5dbdf9e709bdaf4618d7ef8cceb91e8adc69 +refs/heads/master: 73a999fab313053ceebffa9293fadf5a306a58e8 diff --git a/trunk/Documentation/RCU/stallwarn.txt b/trunk/Documentation/RCU/stallwarn.txt index 8e9359de1d28..e38b8df3d727 100644 --- a/trunk/Documentation/RCU/stallwarn.txt +++ b/trunk/Documentation/RCU/stallwarn.txt @@ -191,7 +191,7 @@ o A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that 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 - result in RCU CPU stall warnings for CONFIG_NO_HZ_COMMON=n kernels. + result in RCU CPU stall warnings for CONFIG_NO_HZ=n kernels. o A bug in the RCU implementation. diff --git a/trunk/Documentation/cpu-freq/governors.txt b/trunk/Documentation/cpu-freq/governors.txt index 219970ba54b7..66f9cc310686 100644 --- a/trunk/Documentation/cpu-freq/governors.txt +++ b/trunk/Documentation/cpu-freq/governors.txt @@ -131,8 +131,8 @@ sampling_rate_min: The sampling rate is limited by the HW transition latency: transition_latency * 100 Or by kernel restrictions: -If CONFIG_NO_HZ_COMMON is set, the limit is 10ms fixed. -If CONFIG_NO_HZ_COMMON is not set or nohz=off boot parameter is used, the +If CONFIG_NO_HZ is set, the limit is 10ms fixed. +If CONFIG_NO_HZ is not set or nohz=off boot parameter is used, the limits depend on the CONFIG_HZ option: HZ=1000: min=20000us (20ms) HZ=250: min=80000us (80ms) diff --git a/trunk/Documentation/devicetree/bindings/input/cros-ec-keyb.txt b/trunk/Documentation/devicetree/bindings/input/cros-ec-keyb.txt deleted file mode 100644 index 0f6355ce39b5..000000000000 --- a/trunk/Documentation/devicetree/bindings/input/cros-ec-keyb.txt +++ /dev/null @@ -1,72 +0,0 @@ -ChromeOS EC Keyboard - -Google's ChromeOS EC Keyboard is a simple matrix keyboard implemented on -a separate EC (Embedded Controller) device. It provides a message for reading -key scans from the EC. These are then converted into keycodes for processing -by the kernel. - -This binding is based on matrix-keymap.txt and extends/modifies it as follows: - -Required properties: -- compatible: "google,cros-ec-keyb" - -Optional properties: -- google,needs-ghost-filter: True to enable a ghost filter for the matrix -keyboard. This is recommended if the EC does not have its own logic or -hardware for this. - - -Example: - -cros-ec-keyb { - compatible = "google,cros-ec-keyb"; - keypad,num-rows = <8>; - keypad,num-columns = <13>; - google,needs-ghost-filter; - /* - * Keymap entries take the form of 0xRRCCKKKK where - * RR=Row CC=Column KKKK=Key Code - * The values below are for a US keyboard layout and - * are taken from the Linux driver. Note that the - * 102ND key is not used for US keyboards. - */ - linux,keymap = < - /* CAPSLCK F1 B F10 */ - 0x0001003a 0x0002003b 0x00030030 0x00040044 - /* N = R_ALT ESC */ - 0x00060031 0x0008000d 0x000a0064 0x01010001 - /* F4 G F7 H */ - 0x0102003e 0x01030022 0x01040041 0x01060023 - /* ' F9 BKSPACE L_CTRL */ - 0x01080028 0x01090043 0x010b000e 0x0200001d - /* TAB F3 T F6 */ - 0x0201000f 0x0202003d 0x02030014 0x02040040 - /* ] Y 102ND [ */ - 0x0205001b 0x02060015 0x02070056 0x0208001a - /* F8 GRAVE F2 5 */ - 0x02090042 0x03010029 0x0302003c 0x03030006 - /* F5 6 - \ */ - 0x0304003f 0x03060007 0x0308000c 0x030b002b - /* R_CTRL A D F */ - 0x04000061 0x0401001e 0x04020020 0x04030021 - /* S K J ; */ - 0x0404001f 0x04050025 0x04060024 0x04080027 - /* L ENTER Z C */ - 0x04090026 0x040b001c 0x0501002c 0x0502002e - /* V X , M */ - 0x0503002f 0x0504002d 0x05050033 0x05060032 - /* L_SHIFT / . SPACE */ - 0x0507002a 0x05080035 0x05090034 0x050B0039 - /* 1 3 4 2 */ - 0x06010002 0x06020004 0x06030005 0x06040003 - /* 8 7 0 9 */ - 0x06050009 0x06060008 0x0608000b 0x0609000a - /* L_ALT DOWN RIGHT Q */ - 0x060a0038 0x060b006c 0x060c006a 0x07010010 - /* E R W I */ - 0x07020012 0x07030013 0x07040011 0x07050017 - /* U R_SHIFT P O */ - 0x07060016 0x07070036 0x07080019 0x07090018 - /* UP LEFT */ - 0x070b0067 0x070c0069>; -}; diff --git a/trunk/Documentation/devicetree/bindings/mfd/as3711.txt b/trunk/Documentation/devicetree/bindings/mfd/as3711.txt deleted file mode 100644 index d98cf18c721c..000000000000 --- a/trunk/Documentation/devicetree/bindings/mfd/as3711.txt +++ /dev/null @@ -1,73 +0,0 @@ -AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power -supplies, a battery charger and an RTC. So far only bindings for the two stepup -DCDC converters are defined. Other DCDC and LDO supplies are configured, using -standard regulator properties, they must belong to a sub-node, called -"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter -configuration should be placed in a subnode, called "backlight." - -Compulsory properties: -- compatible : must be "ams,as3711" -- reg : specifies the I2C address - -To use the SU1 converter as a backlight source the following two properties must -be provided: -- su1-dev : framebuffer phandle -- su1-max-uA : maximum current - -To use the SU2 converter as a backlight source the following two properties must -be provided: -- su2-dev : framebuffer phandle -- su1-max-uA : maximum current - -Additionally one of these properties must be provided to select the type of -feedback used: -- su2-feedback-voltage : voltage feedback is used -- su2-feedback-curr1 : CURR1 input used for current feedback -- su2-feedback-curr2 : CURR2 input used for current feedback -- su2-feedback-curr3 : CURR3 input used for current feedback -- su2-feedback-curr-auto: automatic current feedback selection - -and one of these to select the over-voltage protection pin -- su2-fbprot-lx-sd4 : LX_SD4 is used for over-voltage protection -- su2-fbprot-gpio2 : GPIO2 is used for over-voltage protection -- su2-fbprot-gpio3 : GPIO3 is used for over-voltage protection -- su2-fbprot-gpio4 : GPIO4 is used for over-voltage protection - -If "su2-feedback-curr-auto" is selected, one or more of the following properties -have to be specified: -- su2-auto-curr1 : use CURR1 input for current feedback -- su2-auto-curr2 : use CURR2 input for current feedback -- su2-auto-curr3 : use CURR3 input for current feedback - -Example: - -as3711@40 { - compatible = "ams,as3711"; - reg = <0x40>; - - regulators { - sd4 { - regulator-name = "1.215V"; - regulator-min-microvolt = <1215000>; - regulator-max-microvolt = <1235000>; - }; - ldo2 { - regulator-name = "2.8V CPU"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - regulator-always-on; - regulator-boot-on; - }; - }; - - backlight { - compatible = "ams,as3711-bl"; - su2-dev = <&lcdc>; - su2-max-uA = <36000>; - su2-feedback-curr-auto; - su2-fbprot-gpio4; - su2-auto-curr1; - su2-auto-curr2; - su2-auto-curr3; - }; -}; diff --git a/trunk/Documentation/devicetree/bindings/mfd/cros-ec.txt b/trunk/Documentation/devicetree/bindings/mfd/cros-ec.txt deleted file mode 100644 index e0e59c58a1f9..000000000000 --- a/trunk/Documentation/devicetree/bindings/mfd/cros-ec.txt +++ /dev/null @@ -1,56 +0,0 @@ -ChromeOS Embedded Controller - -Google's ChromeOS EC is a Cortex-M device which talks to the AP and -implements various function such as keyboard and battery charging. - -The EC can be connect through various means (I2C, SPI, LPC) and the -compatible string used depends on the inteface. Each connection method has -its own driver which connects to the top level interface-agnostic EC driver. -Other Linux driver (such as cros-ec-keyb for the matrix keyboard) connect to -the top-level driver. - -Required properties (I2C): -- compatible: "google,cros-ec-i2c" -- reg: I2C slave address - -Required properties (SPI): -- compatible: "google,cros-ec-spi" -- reg: SPI chip select - -Required properties (LPC): -- compatible: "google,cros-ec-lpc" -- reg: List of (IO address, size) pairs defining the interface uses - - -Example for I2C: - -i2c@12CA0000 { - cros-ec@1e { - reg = <0x1e>; - compatible = "google,cros-ec-i2c"; - interrupts = <14 0>; - interrupt-parent = <&wakeup_eint>; - wakeup-source; - }; - - -Example for SPI: - -spi@131b0000 { - ec@0 { - compatible = "google,cros-ec-spi"; - reg = <0x0>; - interrupts = <14 0>; - interrupt-parent = <&wakeup_eint>; - wakeup-source; - spi-max-frequency = <5000000>; - controller-data { - cs-gpio = <&gpf0 3 4 3 0>; - samsung,spi-cs; - samsung,spi-feedback-delay = <2>; - }; - }; -}; - - -Example for LPC is not supplied as it is not yet implemented. diff --git a/trunk/Documentation/devicetree/bindings/mfd/omap-usb-host.txt b/trunk/Documentation/devicetree/bindings/mfd/omap-usb-host.txt deleted file mode 100644 index b381fa696bf9..000000000000 --- a/trunk/Documentation/devicetree/bindings/mfd/omap-usb-host.txt +++ /dev/null @@ -1,80 +0,0 @@ -OMAP HS USB Host - -Required properties: - -- compatible: should be "ti,usbhs-host" -- reg: should contain one register range i.e. start and length -- ti,hwmods: must contain "usb_host_hs" - -Optional properties: - -- num-ports: number of USB ports. Usually this is automatically detected - from the IP's revision register but can be overridden by specifying - this property. A maximum of 3 ports are supported at the moment. - -- portN-mode: String specifying the port mode for port N, where N can be - from 1 to 3. If the port mode is not specified, that port is treated - as unused. When specified, it must be one of the following. - "ehci-phy", - "ehci-tll", - "ehci-hsic", - "ohci-phy-6pin-datse0", - "ohci-phy-6pin-dpdm", - "ohci-phy-3pin-datse0", - "ohci-phy-4pin-dpdm", - "ohci-tll-6pin-datse0", - "ohci-tll-6pin-dpdm", - "ohci-tll-3pin-datse0", - "ohci-tll-4pin-dpdm", - "ohci-tll-2pin-datse0", - "ohci-tll-2pin-dpdm", - -- single-ulpi-bypass: Must be present if the controller contains a single - ULPI bypass control bit. e.g. OMAP3 silicon <= ES2.1 - -Required properties if child node exists: - -- #address-cells: Must be 1 -- #size-cells: Must be 1 -- ranges: must be present - -Properties for children: - -The OMAP HS USB Host subsystem contains EHCI and OHCI controllers. -See Documentation/devicetree/bindings/usb/omap-ehci.txt and -omap3-ohci.txt - -Example for OMAP4: - -usbhshost: usbhshost@4a064000 { - compatible = "ti,usbhs-host"; - reg = <0x4a064000 0x800>; - ti,hwmods = "usb_host_hs"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - usbhsohci: ohci@4a064800 { - compatible = "ti,ohci-omap3", "usb-ohci"; - reg = <0x4a064800 0x400>; - interrupt-parent = <&gic>; - interrupts = <0 76 0x4>; - }; - - usbhsehci: ehci@4a064c00 { - compatible = "ti,ehci-omap", "usb-ehci"; - reg = <0x4a064c00 0x400>; - interrupt-parent = <&gic>; - interrupts = <0 77 0x4>; - }; -}; - -&usbhshost { - port1-mode = "ehci-phy"; - port2-mode = "ehci-tll"; - port3-mode = "ehci-phy"; -}; - -&usbhsehci { - phys = <&hsusb1_phy 0 &hsusb3_phy>; -}; diff --git a/trunk/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt b/trunk/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt deleted file mode 100644 index 62fe69724e3b..000000000000 --- a/trunk/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt +++ /dev/null @@ -1,17 +0,0 @@ -OMAP HS USB Host TLL (Transceiver-Less Interface) - -Required properties: - -- compatible : should be "ti,usbhs-tll" -- reg : should contain one register range i.e. start and length -- interrupts : should contain the TLL module's interrupt -- ti,hwmod : must contain "usb_tll_hs" - -Example: - - usbhstll: usbhstll@4a062000 { - compatible = "ti,usbhs-tll"; - reg = <0x4a062000 0x1000>; - interrupts = <78>; - ti,hwmods = "usb_tll_hs"; - }; diff --git a/trunk/Documentation/devicetree/bindings/sound/wm8994.txt b/trunk/Documentation/devicetree/bindings/sound/wm8994.txt index f2f3e80934d2..7a7eb1e7bda6 100644 --- a/trunk/Documentation/devicetree/bindings/sound/wm8994.txt +++ b/trunk/Documentation/devicetree/bindings/sound/wm8994.txt @@ -5,70 +5,14 @@ on the board). Required properties: - - compatible : One of "wlf,wm1811", "wlf,wm8994" or "wlf,wm8958". + - compatible : "wlf,wm1811", "wlf,wm8994", "wlf,wm8958" - reg : the I2C address of the device for I2C, the chip select number for SPI. - - gpio-controller : Indicates this device is a GPIO controller. - - #gpio-cells : Must be 2. The first cell is the pin number and the - second cell is used to specify optional parameters (currently unused). - - - AVDD2-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply, - SPKVDD1-supply, SPKVDD2-supply : power supplies for the device, as covered - in Documentation/devicetree/bindings/regulator/regulator.txt - -Optional properties: - - - interrupts : The interrupt line the IRQ signal for the device is - connected to. This is optional, if it is not connected then none - of the interrupt related properties should be specified. - - interrupt-controller : These devices contain interrupt controllers - and may provide interrupt services to other devices if they have an - interrupt line connected. - - interrupt-parent : The parent interrupt controller. - - #interrupt-cells: the number of cells to describe an IRQ, this should be 2. - The first cell is the IRQ number. - The second cell is the flags, encoded as the trigger masks from - Documentation/devicetree/bindings/interrupts.txt - - - wlf,gpio-cfg : A list of GPIO configuration register values. If absent, - no configuration of these registers is performed. If any value is - over 0xffff then the register will be left as default. If present 11 - values must be supplied. - - - wlf,micbias-cfg : Two MICBIAS register values for WM1811 or - WM8958. If absent the register defaults will be used. - - - wlf,ldo1ena : GPIO specifier for control of LDO1ENA input to device. - - wlf,ldo2ena : GPIO specifier for control of LDO2ENA input to device. - - - wlf,lineout1-se : If present LINEOUT1 is in single ended mode. - - wlf,lineout2-se : If present LINEOUT2 is in single ended mode. - - - wlf,lineout1-feedback : If present LINEOUT1 has common mode feedback - connected. - - wlf,lineout2-feedback : If present LINEOUT2 has common mode feedback - connected. - - - wlf,ldoena-always-driven : If present LDOENA is always driven. - Example: codec: wm8994@1a { compatible = "wlf,wm8994"; reg = <0x1a>; - - gpio-controller; - #gpio-cells = <2>; - - lineout1-se; - - AVDD2-supply = <®ulator>; - CPVDD-supply = <®ulator>; - DBVDD1-supply = <®ulator>; - DBVDD2-supply = <®ulator>; - DBVDD3-supply = <®ulator>; - SPKVDD1-supply = <®ulator>; - SPKVDD2-supply = <®ulator>; }; diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 8920f9f5fa9e..9653cf2f9727 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -1964,14 +1964,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Valid arguments: on, off Default: on - nohz_full= [KNL,BOOT] - In kernels built with CONFIG_NO_HZ_FULL=y, set - the specified list of CPUs whose tick will be stopped - whenever possible. The boot CPU will be forced outside - the range to maintain the timekeeping. - The CPUs in this range must also be included in the - rcu_nocbs= set. - noiotrap [SH] Disables trapped I/O port accesses. noirqdebug [X86-32] Disables the code which attempts to detect and diff --git a/trunk/Documentation/s390/CommonIO b/trunk/Documentation/s390/CommonIO index 6e0f63f343b4..d378cba66456 100644 --- a/trunk/Documentation/s390/CommonIO +++ b/trunk/Documentation/s390/CommonIO @@ -8,9 +8,9 @@ Command line parameters Enable logging of debug information in case of ccw device timeouts. -* cio_ignore = device[,device[,..]] - - device := {all | [!]ipldev | [!]condev | [!] | [!]-} +* cio_ignore = {all} | + { | } | + {! | !} The given devices will be ignored by the common I/O-layer; no detection and device sensing will be done on any of those devices. The subchannel to @@ -24,10 +24,8 @@ Command line parameters device numbers (0xabcd or abcd, for 2.4 backward compatibility). If you give a device number 0xabcd, it will be interpreted as 0.0.abcd. - You can use the 'all' keyword to ignore all devices. The 'ipldev' and 'condev' - keywords can be used to refer to the CCW based boot device and CCW console - device respectively (these are probably useful only when combined with the '!' - operator). The '!' operator will cause the I/O-layer to _not_ ignore a device. + You can use the 'all' keyword to ignore all devices. + The '!' operator will cause the I/O-layer to _not_ ignore a device. The command line is parsed from left to right. For example, diff --git a/trunk/Documentation/timers/NO_HZ.txt b/trunk/Documentation/timers/NO_HZ.txt deleted file mode 100644 index 5b5322024067..000000000000 --- a/trunk/Documentation/timers/NO_HZ.txt +++ /dev/null @@ -1,273 +0,0 @@ - NO_HZ: Reducing Scheduling-Clock Ticks - - -This document describes Kconfig options and boot parameters that can -reduce the number of scheduling-clock interrupts, thereby improving energy -efficiency and reducing OS jitter. Reducing OS jitter is important for -some types of computationally intensive high-performance computing (HPC) -applications and for real-time applications. - -There are two main contexts in which the number of scheduling-clock -interrupts can be reduced compared to the old-school approach of sending -a scheduling-clock interrupt to all CPUs every jiffy whether they need -it or not (CONFIG_HZ_PERIODIC=y or CONFIG_NO_HZ=n for older kernels): - -1. Idle CPUs (CONFIG_NO_HZ_IDLE=y or CONFIG_NO_HZ=y for older kernels). - -2. CPUs having only one runnable task (CONFIG_NO_HZ_FULL=y). - -These two cases are described in the following two sections, followed -by a third section on RCU-specific considerations and a fourth and final -section listing known issues. - - -IDLE CPUs - -If a CPU is idle, there is little point in sending it a scheduling-clock -interrupt. After all, the primary purpose of a scheduling-clock interrupt -is to force a busy CPU to shift its attention among multiple duties, -and an idle CPU has no duties to shift its attention among. - -The CONFIG_NO_HZ_IDLE=y Kconfig option causes the kernel to avoid sending -scheduling-clock interrupts to idle CPUs, which is critically important -both to battery-powered devices and to highly virtualized mainframes. -A battery-powered device running a CONFIG_HZ_PERIODIC=y kernel would -drain its battery very quickly, easily 2-3 times as fast as would the -same device running a CONFIG_NO_HZ_IDLE=y kernel. A mainframe running -1,500 OS instances might find that half of its CPU time was consumed by -unnecessary scheduling-clock interrupts. In these situations, there -is strong motivation to avoid sending scheduling-clock interrupts to -idle CPUs. That said, dyntick-idle mode is not free: - -1. It increases the number of instructions executed on the path - to and from the idle loop. - -2. On many architectures, dyntick-idle mode also increases the - number of expensive clock-reprogramming operations. - -Therefore, systems with aggressive real-time response constraints often -run CONFIG_HZ_PERIODIC=y kernels (or CONFIG_NO_HZ=n for older kernels) -in order to avoid degrading from-idle transition latencies. - -An idle CPU that is not receiving scheduling-clock interrupts is said to -be "dyntick-idle", "in dyntick-idle mode", "in nohz mode", or "running -tickless". The remainder of this document will use "dyntick-idle mode". - -There is also a boot parameter "nohz=" that can be used to disable -dyntick-idle mode in CONFIG_NO_HZ_IDLE=y kernels by specifying "nohz=off". -By default, CONFIG_NO_HZ_IDLE=y kernels boot with "nohz=on", enabling -dyntick-idle mode. - - -CPUs WITH ONLY ONE RUNNABLE TASK - -If a CPU has only one runnable task, there is little point in sending it -a scheduling-clock interrupt because there is no other task to switch to. - -The CONFIG_NO_HZ_FULL=y Kconfig option causes the kernel to avoid -sending scheduling-clock interrupts to CPUs with a single runnable task, -and such CPUs are said to be "adaptive-ticks CPUs". This is important -for applications with aggressive real-time response constraints because -it allows them to improve their worst-case response times by the maximum -duration of a scheduling-clock interrupt. It is also important for -computationally intensive short-iteration workloads: If any CPU is -delayed during a given iteration, all the other CPUs will be forced to -wait idle while the delayed CPU finishes. Thus, the delay is multiplied -by one less than the number of CPUs. In these situations, there is -again strong motivation to avoid sending scheduling-clock interrupts. - -By default, no CPU will be an adaptive-ticks CPU. The "nohz_full=" -boot parameter specifies the adaptive-ticks CPUs. For example, -"nohz_full=1,6-8" says that CPUs 1, 6, 7, and 8 are to be adaptive-ticks -CPUs. Note that you are prohibited from marking all of the CPUs as -adaptive-tick CPUs: At least one non-adaptive-tick CPU must remain -online to handle timekeeping tasks in order to ensure that system calls -like gettimeofday() returns accurate values on adaptive-tick CPUs. -(This is not an issue for CONFIG_NO_HZ_IDLE=y because there are no -running user processes to observe slight drifts in clock rate.) -Therefore, the boot CPU is prohibited from entering adaptive-ticks -mode. Specifying a "nohz_full=" mask that includes the boot CPU will -result in a boot-time error message, and the boot CPU will be removed -from the mask. - -Alternatively, the CONFIG_NO_HZ_FULL_ALL=y Kconfig parameter specifies -that all CPUs other than the boot CPU are adaptive-ticks CPUs. This -Kconfig parameter will be overridden by the "nohz_full=" boot parameter, -so that if both the CONFIG_NO_HZ_FULL_ALL=y Kconfig parameter and -the "nohz_full=1" boot parameter is specified, the boot parameter will -prevail so that only CPU 1 will be an adaptive-ticks CPU. - -Finally, adaptive-ticks CPUs must have their RCU callbacks offloaded. -This is covered in the "RCU IMPLICATIONS" section below. - -Normally, a CPU remains in adaptive-ticks mode as long as possible. -In particular, transitioning to kernel mode does not automatically change -the mode. Instead, the CPU will exit adaptive-ticks mode only if needed, -for example, if that CPU enqueues an RCU callback. - -Just as with dyntick-idle mode, the benefits of adaptive-tick mode do -not come for free: - -1. CONFIG_NO_HZ_FULL selects CONFIG_NO_HZ_COMMON, so you cannot run - adaptive ticks without also running dyntick idle. This dependency - extends down into the implementation, so that all of the costs - of CONFIG_NO_HZ_IDLE are also incurred by CONFIG_NO_HZ_FULL. - -2. The user/kernel transitions are slightly more expensive due - to the need to inform kernel subsystems (such as RCU) about - the change in mode. - -3. POSIX CPU timers on adaptive-tick CPUs may miss their deadlines - (perhaps indefinitely) because they currently rely on - scheduling-tick interrupts. This will likely be fixed in - one of two ways: (1) Prevent CPUs with POSIX CPU timers from - entering adaptive-tick mode, or (2) Use hrtimers or other - adaptive-ticks-immune mechanism to cause the POSIX CPU timer to - fire properly. - -4. If there are more perf events pending than the hardware can - accommodate, they are normally round-robined so as to collect - all of them over time. Adaptive-tick mode may prevent this - round-robining from happening. This will likely be fixed by - preventing CPUs with large numbers of perf events pending from - entering adaptive-tick mode. - -5. Scheduler statistics for adaptive-tick CPUs may be computed - slightly differently than those for non-adaptive-tick CPUs. - This might in turn perturb load-balancing of real-time tasks. - -6. The LB_BIAS scheduler feature is disabled by adaptive ticks. - -Although improvements are expected over time, adaptive ticks is quite -useful for many types of real-time and compute-intensive applications. -However, the drawbacks listed above mean that adaptive ticks should not -(yet) be enabled by default. - - -RCU IMPLICATIONS - -There are situations in which idle CPUs cannot be permitted to -enter either dyntick-idle mode or adaptive-tick mode, the most -common being when that CPU has RCU callbacks pending. - -The CONFIG_RCU_FAST_NO_HZ=y Kconfig option may be used to cause such CPUs -to enter dyntick-idle mode or adaptive-tick mode anyway. In this case, -a timer will awaken these CPUs every four jiffies in order to ensure -that the RCU callbacks are processed in a timely fashion. - -Another approach is to offload RCU callback processing to "rcuo" kthreads -using the CONFIG_RCU_NOCB_CPU=y Kconfig option. The specific CPUs to -offload may be selected via several methods: - -1. One of three mutually exclusive Kconfig options specify a - build-time default for the CPUs to offload: - - a. The CONFIG_RCU_NOCB_CPU_NONE=y Kconfig option results in - no CPUs being offloaded. - - b. The CONFIG_RCU_NOCB_CPU_ZERO=y Kconfig option causes - CPU 0 to be offloaded. - - c. The CONFIG_RCU_NOCB_CPU_ALL=y Kconfig option causes all - CPUs to be offloaded. Note that the callbacks will be - offloaded to "rcuo" kthreads, and that those kthreads - will in fact run on some CPU. However, this approach - gives fine-grained control on exactly which CPUs the - callbacks run on, along with their scheduling priority - (including the default of SCHED_OTHER), and it further - allows this control to be varied dynamically at runtime. - -2. The "rcu_nocbs=" kernel boot parameter, which takes a comma-separated - list of CPUs and CPU ranges, for example, "1,3-5" selects CPUs 1, - 3, 4, and 5. The specified CPUs will be offloaded in addition to - any CPUs specified as offloaded by CONFIG_RCU_NOCB_CPU_ZERO=y or - CONFIG_RCU_NOCB_CPU_ALL=y. This means that the "rcu_nocbs=" boot - parameter has no effect for kernels built with RCU_NOCB_CPU_ALL=y. - -The offloaded CPUs will never queue RCU callbacks, and therefore RCU -never prevents offloaded CPUs from entering either dyntick-idle mode -or adaptive-tick mode. That said, note that it is up to userspace to -pin the "rcuo" kthreads to specific CPUs if desired. Otherwise, the -scheduler will decide where to run them, which might or might not be -where you want them to run. - - -KNOWN ISSUES - -o Dyntick-idle slows transitions to and from idle slightly. - In practice, this has not been a problem except for the most - aggressive real-time workloads, which have the option of disabling - dyntick-idle mode, an option that most of them take. However, - some workloads will no doubt want to use adaptive ticks to - eliminate scheduling-clock interrupt latencies. Here are some - options for these workloads: - - a. Use PMQOS from userspace to inform the kernel of your - latency requirements (preferred). - - b. On x86 systems, use the "idle=mwait" boot parameter. - - c. On x86 systems, use the "intel_idle.max_cstate=" to limit - ` the maximum C-state depth. - - d. On x86 systems, use the "idle=poll" boot parameter. - However, please note that use of this parameter can cause - your CPU to overheat, which may cause thermal throttling - to degrade your latencies -- and that this degradation can - be even worse than that of dyntick-idle. Furthermore, - this parameter effectively disables Turbo Mode on Intel - CPUs, which can significantly reduce maximum performance. - -o Adaptive-ticks slows user/kernel transitions slightly. - This is not expected to be a problem for computationally intensive - workloads, which have few such transitions. Careful benchmarking - will be required to determine whether or not other workloads - are significantly affected by this effect. - -o Adaptive-ticks does not do anything unless there is only one - runnable task for a given CPU, even though there are a number - of other situations where the scheduling-clock tick is not - needed. To give but one example, consider a CPU that has one - runnable high-priority SCHED_FIFO task and an arbitrary number - of low-priority SCHED_OTHER tasks. In this case, the CPU is - required to run the SCHED_FIFO task until it either blocks or - some other higher-priority task awakens on (or is assigned to) - this CPU, so there is no point in sending a scheduling-clock - interrupt to this CPU. However, the current implementation - nevertheless sends scheduling-clock interrupts to CPUs having a - single runnable SCHED_FIFO task and multiple runnable SCHED_OTHER - tasks, even though these interrupts are unnecessary. - - Better handling of these sorts of situations is future work. - -o A reboot is required to reconfigure both adaptive idle and RCU - callback offloading. Runtime reconfiguration could be provided - if needed, however, due to the complexity of reconfiguring RCU at - runtime, there would need to be an earthshakingly good reason. - Especially given that you have the straightforward option of - simply offloading RCU callbacks from all CPUs and pinning them - where you want them whenever you want them pinned. - -o Additional configuration is required to deal with other sources - of OS jitter, including interrupts and system-utility tasks - and processes. This configuration normally involves binding - interrupts and tasks to particular CPUs. - -o Some sources of OS jitter can currently be eliminated only by - constraining the workload. For example, the only way to eliminate - OS jitter due to global TLB shootdowns is to avoid the unmapping - operations (such as kernel module unload operations) that - result in these shootdowns. For another example, page faults - and TLB misses can be reduced (and in some cases eliminated) by - using huge pages and by constraining the amount of memory used - by the application. Pre-faulting the working set can also be - helpful, especially when combined with the mlock() and mlockall() - system calls. - -o Unless all CPUs are idle, at least one CPU must keep the - scheduling-clock interrupt going in order to support accurate - timekeeping. - -o If there are adaptive-ticks CPUs, there will be at least one - CPU keeping the scheduling-clock interrupt going, even if all - CPUs are otherwise idle. diff --git a/trunk/Documentation/virtual/kvm/api.txt b/trunk/Documentation/virtual/kvm/api.txt index 5f91eda91647..119358dfb742 100644 --- a/trunk/Documentation/virtual/kvm/api.txt +++ b/trunk/Documentation/virtual/kvm/api.txt @@ -1486,23 +1486,15 @@ struct kvm_ioeventfd { __u8 pad[36]; }; -For the special case of virtio-ccw devices on s390, the ioevent is matched -to a subchannel/virtqueue tuple instead. - The following flags are defined: #define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch) #define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio) #define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign) -#define KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY \ - (1 << kvm_ioeventfd_flag_nr_virtio_ccw_notify) If datamatch flag is set, the event will be signaled only if the written value to the registered address is equal to datamatch in struct kvm_ioeventfd. -For virtio-ccw devices, addr contains the subchannel id and datamatch the -virtqueue index. - 4.60 KVM_DIRTY_TLB @@ -1788,48 +1780,27 @@ registers, find a list below: PPC | KVM_REG_PPC_VPA_DTL | 128 PPC | KVM_REG_PPC_EPCR | 32 PPC | KVM_REG_PPC_EPR | 32 - PPC | KVM_REG_PPC_TCR | 32 - PPC | KVM_REG_PPC_TSR | 32 - PPC | KVM_REG_PPC_OR_TSR | 32 - PPC | KVM_REG_PPC_CLEAR_TSR | 32 - PPC | KVM_REG_PPC_MAS0 | 32 - PPC | KVM_REG_PPC_MAS1 | 32 - PPC | KVM_REG_PPC_MAS2 | 64 - PPC | KVM_REG_PPC_MAS7_3 | 64 - PPC | KVM_REG_PPC_MAS4 | 32 - PPC | KVM_REG_PPC_MAS6 | 32 - PPC | KVM_REG_PPC_MMUCFG | 32 - PPC | KVM_REG_PPC_TLB0CFG | 32 - PPC | KVM_REG_PPC_TLB1CFG | 32 - PPC | KVM_REG_PPC_TLB2CFG | 32 - PPC | KVM_REG_PPC_TLB3CFG | 32 - PPC | KVM_REG_PPC_TLB0PS | 32 - PPC | KVM_REG_PPC_TLB1PS | 32 - PPC | KVM_REG_PPC_TLB2PS | 32 - PPC | KVM_REG_PPC_TLB3PS | 32 - PPC | KVM_REG_PPC_EPTCFG | 32 - PPC | KVM_REG_PPC_ICP_STATE | 64 ARM registers are mapped using the lower 32 bits. The upper 16 of that is the register group type, or coprocessor number: ARM core registers have the following id bit patterns: - 0x4020 0000 0010 + 0x4002 0000 0010 ARM 32-bit CP15 registers have the following id bit patterns: - 0x4020 0000 000F + 0x4002 0000 000F ARM 64-bit CP15 registers have the following id bit patterns: - 0x4030 0000 000F + 0x4003 0000 000F ARM CCSIDR registers are demultiplexed by CSSELR value: - 0x4020 0000 0011 00 + 0x4002 0000 0011 00 ARM 32-bit VFP control registers have the following id bit patterns: - 0x4020 0000 0012 1 + 0x4002 0000 0012 1 ARM 64-bit FP registers have the following id bit patterns: - 0x4030 0000 0012 0 + 0x4002 0000 0012 0 4.69 KVM_GET_ONE_REG @@ -2190,76 +2161,6 @@ header; first `n_valid' valid entries with contents from the data written, then `n_invalid' invalid entries, invalidating any previously valid entries found. -4.79 KVM_CREATE_DEVICE - -Capability: KVM_CAP_DEVICE_CTRL -Type: vm ioctl -Parameters: struct kvm_create_device (in/out) -Returns: 0 on success, -1 on error -Errors: - ENODEV: The device type is unknown or unsupported - EEXIST: Device already created, and this type of device may not - be instantiated multiple times - - Other error conditions may be defined by individual device types or - have their standard meanings. - -Creates an emulated device in the kernel. The file descriptor returned -in fd can be used with KVM_SET/GET/HAS_DEVICE_ATTR. - -If the KVM_CREATE_DEVICE_TEST flag is set, only test whether the -device type is supported (not necessarily whether it can be created -in the current vm). - -Individual devices should not define flags. Attributes should be used -for specifying any behavior that is not implied by the device type -number. - -struct kvm_create_device { - __u32 type; /* in: KVM_DEV_TYPE_xxx */ - __u32 fd; /* out: device handle */ - __u32 flags; /* in: KVM_CREATE_DEVICE_xxx */ -}; - -4.80 KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR - -Capability: KVM_CAP_DEVICE_CTRL -Type: device ioctl -Parameters: struct kvm_device_attr -Returns: 0 on success, -1 on error -Errors: - ENXIO: The group or attribute is unknown/unsupported for this device - EPERM: The attribute cannot (currently) be accessed this way - (e.g. read-only attribute, or attribute that only makes - sense when the device is in a different state) - - Other error conditions may be defined by individual device types. - -Gets/sets a specified piece of device configuration and/or state. The -semantics are device-specific. See individual device documentation in -the "devices" directory. As with ONE_REG, the size of the data -transferred is defined by the particular attribute. - -struct kvm_device_attr { - __u32 flags; /* no flags currently defined */ - __u32 group; /* device-defined */ - __u64 attr; /* group-defined */ - __u64 addr; /* userspace address of attr data */ -}; - -4.81 KVM_HAS_DEVICE_ATTR - -Capability: KVM_CAP_DEVICE_CTRL -Type: device ioctl -Parameters: struct kvm_device_attr -Returns: 0 on success, -1 on error -Errors: - ENXIO: The group or attribute is unknown/unsupported for this device - -Tests whether a device supports a particular attribute. A successful -return indicates the attribute is implemented. It does not necessarily -indicate that the attribute can be read or written in the device's -current state. "addr" is ignored. 4.77 KVM_ARM_VCPU_INIT @@ -2342,25 +2243,6 @@ and distributor interface, the ioctl must be called after calling KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the base addresses will return -EEXIST. -4.82 KVM_PPC_RTAS_DEFINE_TOKEN - -Capability: KVM_CAP_PPC_RTAS -Architectures: ppc -Type: vm ioctl -Parameters: struct kvm_rtas_token_args -Returns: 0 on success, -1 on error - -Defines a token value for a RTAS (Run Time Abstraction Services) -service in order to allow it to be handled in the kernel. The -argument struct gives the name of the service, which must be the name -of a service that has a kernel-side implementation. If the token -value is non-zero, it will be associated with that service, and -subsequent RTAS calls by the guest specifying that token will be -handled by the kernel. If the token value is 0, then any token -associated with the service will be forgotten, and subsequent RTAS -calls by the guest for that service will be passed to userspace to be -handled. - 5. The kvm_run structure ------------------------ @@ -2764,19 +2646,3 @@ to receive the topmost interrupt vector. When disabled (args[0] == 0), behavior is as if this facility is unsupported. When this capability is enabled, KVM_EXIT_EPR can occur. - -6.6 KVM_CAP_IRQ_MPIC - -Architectures: ppc -Parameters: args[0] is the MPIC device fd - args[1] is the MPIC CPU number for this vcpu - -This capability connects the vcpu to an in-kernel MPIC device. - -6.7 KVM_CAP_IRQ_XICS - -Architectures: ppc -Parameters: args[0] is the XICS device fd - args[1] is the XICS CPU number (server ID) for this vcpu - -This capability connects the vcpu to an in-kernel XICS device. diff --git a/trunk/Documentation/virtual/kvm/devices/README b/trunk/Documentation/virtual/kvm/devices/README deleted file mode 100644 index 34a69834124a..000000000000 --- a/trunk/Documentation/virtual/kvm/devices/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains specific device bindings for KVM_CAP_DEVICE_CTRL. diff --git a/trunk/Documentation/virtual/kvm/devices/mpic.txt b/trunk/Documentation/virtual/kvm/devices/mpic.txt deleted file mode 100644 index 8257397adc3c..000000000000 --- a/trunk/Documentation/virtual/kvm/devices/mpic.txt +++ /dev/null @@ -1,53 +0,0 @@ -MPIC interrupt controller -========================= - -Device types supported: - KVM_DEV_TYPE_FSL_MPIC_20 Freescale MPIC v2.0 - KVM_DEV_TYPE_FSL_MPIC_42 Freescale MPIC v4.2 - -Only one MPIC instance, of any type, may be instantiated. The created -MPIC will act as the system interrupt controller, connecting to each -vcpu's interrupt inputs. - -Groups: - KVM_DEV_MPIC_GRP_MISC - Attributes: - KVM_DEV_MPIC_BASE_ADDR (rw, 64-bit) - Base address of the 256 KiB MPIC register space. Must be - naturally aligned. A value of zero disables the mapping. - Reset value is zero. - - KVM_DEV_MPIC_GRP_REGISTER (rw, 32-bit) - Access an MPIC register, as if the access were made from the guest. - "attr" is the byte offset into the MPIC register space. Accesses - must be 4-byte aligned. - - MSIs may be signaled by using this attribute group to write - to the relevant MSIIR. - - KVM_DEV_MPIC_GRP_IRQ_ACTIVE (rw, 32-bit) - IRQ input line for each standard openpic source. 0 is inactive and 1 - is active, regardless of interrupt sense. - - For edge-triggered interrupts: Writing 1 is considered an activating - edge, and writing 0 is ignored. Reading returns 1 if a previously - signaled edge has not been acknowledged, and 0 otherwise. - - "attr" is the IRQ number. IRQ numbers for standard sources are the - byte offset of the relevant IVPR from EIVPR0, divided by 32. - -IRQ Routing: - - The MPIC emulation supports IRQ routing. Only a single MPIC device can - be instantiated. Once that device has been created, it's available as - irqchip id 0. - - This irqchip 0 has 256 interrupt pins, which expose the interrupts in - the main array of interrupt sources (a.k.a. "SRC" interrupts). - - The numbering is the same as the MPIC device tree binding -- based on - the register offset from the beginning of the sources array, without - regard to any subdivisions in chip documentation such as "internal" - or "external" interrupts. - - Access to non-SRC interrupts is not implemented through IRQ routing mechanisms. diff --git a/trunk/Documentation/virtual/kvm/devices/xics.txt b/trunk/Documentation/virtual/kvm/devices/xics.txt deleted file mode 100644 index 42864935ac5d..000000000000 --- a/trunk/Documentation/virtual/kvm/devices/xics.txt +++ /dev/null @@ -1,66 +0,0 @@ -XICS interrupt controller - -Device type supported: KVM_DEV_TYPE_XICS - -Groups: - KVM_DEV_XICS_SOURCES - Attributes: One per interrupt source, indexed by the source number. - -This device emulates the XICS (eXternal Interrupt Controller -Specification) defined in PAPR. The XICS has a set of interrupt -sources, each identified by a 20-bit source number, and a set of -Interrupt Control Presentation (ICP) entities, also called "servers", -each associated with a virtual CPU. - -The ICP entities are created by enabling the KVM_CAP_IRQ_ARCH -capability for each vcpu, specifying KVM_CAP_IRQ_XICS in args[0] and -the interrupt server number (i.e. the vcpu number from the XICS's -point of view) in args[1] of the kvm_enable_cap struct. Each ICP has -64 bits of state which can be read and written using the -KVM_GET_ONE_REG and KVM_SET_ONE_REG ioctls on the vcpu. The 64 bit -state word has the following bitfields, starting at the -least-significant end of the word: - -* Unused, 16 bits - -* Pending interrupt priority, 8 bits - Zero is the highest priority, 255 means no interrupt is pending. - -* Pending IPI (inter-processor interrupt) priority, 8 bits - Zero is the highest priority, 255 means no IPI is pending. - -* Pending interrupt source number, 24 bits - Zero means no interrupt pending, 2 means an IPI is pending - -* Current processor priority, 8 bits - Zero is the highest priority, meaning no interrupts can be - delivered, and 255 is the lowest priority. - -Each source has 64 bits of state that can be read and written using -the KVM_GET_DEVICE_ATTR and KVM_SET_DEVICE_ATTR ioctls, specifying the -KVM_DEV_XICS_SOURCES attribute group, with the attribute number being -the interrupt source number. The 64 bit state word has the following -bitfields, starting from the least-significant end of the word: - -* Destination (server number), 32 bits - This specifies where the interrupt should be sent, and is the - interrupt server number specified for the destination vcpu. - -* Priority, 8 bits - This is the priority specified for this interrupt source, where 0 is - the highest priority and 255 is the lowest. An interrupt with a - priority of 255 will never be delivered. - -* Level sensitive flag, 1 bit - This bit is 1 for a level-sensitive interrupt source, or 0 for - edge-sensitive (or MSI). - -* Masked flag, 1 bit - This bit is set to 1 if the interrupt is masked (cannot be delivered - regardless of its priority), for example by the ibm,int-off RTAS - call, or 0 if it is not masked. - -* Pending flag, 1 bit - This bit is 1 if the source has a pending interrupt, otherwise 0. - -Only one XICS instance may be created per VM. diff --git a/trunk/Makefile b/trunk/Makefile index 878d7aa3d2dd..4572f106e30b 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1399,7 +1399,7 @@ quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files)) # Run depmod only if we have System.map and depmod is executable quiet_cmd_depmod = DEPMOD $(KERNELRELEASE) cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \ - $(KERNELRELEASE) "$(patsubst y,_,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX))" + $(KERNELRELEASE) "$(patsubst "%",%,$(CONFIG_SYMBOL_PREFIX))" # Create temporary dir for module support files # clean it up only when building all modules diff --git a/trunk/arch/Kconfig b/trunk/arch/Kconfig index dd0e8eb8042f..99f0e17df429 100644 --- a/trunk/arch/Kconfig +++ b/trunk/arch/Kconfig @@ -381,12 +381,6 @@ config MODULES_USE_ELF_REL Modules only use ELF REL relocations. Modules with ELF RELA relocations will give an error. -config HAVE_UNDERSCORE_SYMBOL_PREFIX - bool - help - Some architectures generate an _ in front of C symbols; things like - module loading and assembly files need to know about this. - # # ABI hall of shame # diff --git a/trunk/arch/arm/include/asm/idmap.h b/trunk/arch/arm/include/asm/idmap.h index bf863edb517d..1a66f907e5cc 100644 --- a/trunk/arch/arm/include/asm/idmap.h +++ b/trunk/arch/arm/include/asm/idmap.h @@ -8,6 +8,7 @@ #define __idmap __section(.idmap.text) noinline notrace extern pgd_t *idmap_pgd; +extern pgd_t *hyp_pgd; void setup_mm_for_reboot(void); diff --git a/trunk/arch/arm/include/asm/kvm_host.h b/trunk/arch/arm/include/asm/kvm_host.h index 57cb786a6203..0c4e643d939e 100644 --- a/trunk/arch/arm/include/asm/kvm_host.h +++ b/trunk/arch/arm/include/asm/kvm_host.h @@ -87,7 +87,7 @@ struct kvm_vcpu_fault_info { u32 hyp_pc; /* PC when exception was taken from Hyp mode */ }; -typedef struct vfp_hard_struct kvm_cpu_context_t; +typedef struct vfp_hard_struct kvm_kernel_vfp_t; struct kvm_vcpu_arch { struct kvm_regs regs; @@ -105,10 +105,8 @@ struct kvm_vcpu_arch { struct kvm_vcpu_fault_info fault; /* Floating point registers (VFP and Advanced SIMD/NEON) */ - struct vfp_hard_struct vfp_guest; - - /* Host FP context */ - kvm_cpu_context_t *host_cpu_context; + kvm_kernel_vfp_t vfp_guest; + kvm_kernel_vfp_t *vfp_host; /* VGIC state */ struct vgic_cpu vgic_cpu; @@ -190,38 +188,23 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, int exception_index); -static inline void __cpu_init_hyp_mode(unsigned long long boot_pgd_ptr, - unsigned long long pgd_ptr, +static inline void __cpu_init_hyp_mode(unsigned long long pgd_ptr, unsigned long hyp_stack_ptr, unsigned long vector_ptr) { - /* - * Call initialization code, and switch to the full blown HYP - * code. The init code doesn't need to preserve these - * registers as r0-r3 are already callee saved according to - * the AAPCS. - * Note that we slightly misuse the prototype by casing the - * stack pointer to a void *. - * - * We don't have enough registers to perform the full init in - * one go. Install the boot PGD first, and then install the - * runtime PGD, stack pointer and vectors. The PGDs are always - * passed as the third argument, in order to be passed into - * r2-r3 to the init code (yes, this is compliant with the - * PCS!). - */ + unsigned long pgd_low, pgd_high; - kvm_call_hyp(NULL, 0, boot_pgd_ptr); - - kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr); -} + pgd_low = (pgd_ptr & ((1ULL << 32) - 1)); + pgd_high = (pgd_ptr >> 32ULL); -static inline int kvm_arch_dev_ioctl_check_extension(long ext) -{ - return 0; + /* + * Call initialization code, and switch to the full blown + * HYP code. The init code doesn't need to preserve these registers as + * r1-r3 and r12 are already callee save according to the AAPCS. + * Note that we slightly misuse the prototype by casing the pgd_low to + * a void *. + */ + kvm_call_hyp((void *)pgd_low, pgd_high, hyp_stack_ptr, vector_ptr); } -int kvm_perf_init(void); -int kvm_perf_teardown(void); - #endif /* __ARM_KVM_HOST_H__ */ diff --git a/trunk/arch/arm/include/asm/kvm_mmu.h b/trunk/arch/arm/include/asm/kvm_mmu.h index 472ac7091003..970f3b5fa109 100644 --- a/trunk/arch/arm/include/asm/kvm_mmu.h +++ b/trunk/arch/arm/include/asm/kvm_mmu.h @@ -19,33 +19,21 @@ #ifndef __ARM_KVM_MMU_H__ #define __ARM_KVM_MMU_H__ -#include -#include +#include +#include +#include /* * We directly use the kernel VA for the HYP, as we can directly share * the mapping (HTTBR "covers" TTBR1). */ -#define HYP_PAGE_OFFSET_MASK UL(~0) +#define HYP_PAGE_OFFSET_MASK (~0UL) #define HYP_PAGE_OFFSET PAGE_OFFSET #define KERN_TO_HYP(kva) (kva) -/* - * Our virtual mapping for the boot-time MMU-enable code. Must be - * shared across all the page-tables. Conveniently, we use the vectors - * page, where no kernel data will ever be shared with HYP. - */ -#define TRAMPOLINE_VA UL(CONFIG_VECTORS_BASE) - -#ifndef __ASSEMBLY__ - -#include -#include - int create_hyp_mappings(void *from, void *to); int create_hyp_io_mappings(void *from, void *to, phys_addr_t); -void free_boot_hyp_pgd(void); -void free_hyp_pgds(void); +void free_hyp_pmds(void); int kvm_alloc_stage2_pgd(struct kvm *kvm); void kvm_free_stage2_pgd(struct kvm *kvm); @@ -57,8 +45,6 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run); void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu); phys_addr_t kvm_mmu_get_httbr(void); -phys_addr_t kvm_mmu_get_boot_httbr(void); -phys_addr_t kvm_get_idmap_vector(void); int kvm_mmu_init(void); void kvm_clear_hyp_idmap(void); @@ -128,8 +114,4 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn) } } -#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l)) - -#endif /* !__ASSEMBLY__ */ - #endif /* __ARM_KVM_MMU_H__ */ diff --git a/trunk/arch/arm/kernel/asm-offsets.c b/trunk/arch/arm/kernel/asm-offsets.c index ee68cce6b48e..a53efa993690 100644 --- a/trunk/arch/arm/kernel/asm-offsets.c +++ b/trunk/arch/arm/kernel/asm-offsets.c @@ -158,7 +158,7 @@ int main(void) DEFINE(VCPU_MIDR, offsetof(struct kvm_vcpu, arch.midr)); DEFINE(VCPU_CP15, offsetof(struct kvm_vcpu, arch.cp15)); DEFINE(VCPU_VFP_GUEST, offsetof(struct kvm_vcpu, arch.vfp_guest)); - DEFINE(VCPU_VFP_HOST, offsetof(struct kvm_vcpu, arch.host_cpu_context)); + DEFINE(VCPU_VFP_HOST, offsetof(struct kvm_vcpu, arch.vfp_host)); DEFINE(VCPU_REGS, offsetof(struct kvm_vcpu, arch.regs)); DEFINE(VCPU_USR_REGS, offsetof(struct kvm_vcpu, arch.regs.usr_regs)); DEFINE(VCPU_SVC_REGS, offsetof(struct kvm_vcpu, arch.regs.svc_regs)); diff --git a/trunk/arch/arm/kernel/swp_emulate.c b/trunk/arch/arm/kernel/swp_emulate.c index b1b89882b113..087fc321e9e5 100644 --- a/trunk/arch/arm/kernel/swp_emulate.c +++ b/trunk/arch/arm/kernel/swp_emulate.c @@ -99,7 +99,7 @@ static const struct file_operations proc_status_fops = { .open = proc_status_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif diff --git a/trunk/arch/arm/kernel/vmlinux.lds.S b/trunk/arch/arm/kernel/vmlinux.lds.S index a871b8e00fca..b571484e9f03 100644 --- a/trunk/arch/arm/kernel/vmlinux.lds.S +++ b/trunk/arch/arm/kernel/vmlinux.lds.S @@ -20,7 +20,7 @@ VMLINUX_SYMBOL(__idmap_text_start) = .; \ *(.idmap.text) \ VMLINUX_SYMBOL(__idmap_text_end) = .; \ - . = ALIGN(32); \ + ALIGN_FUNCTION(); \ VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ *(.hyp.idmap.text) \ VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; @@ -315,8 +315,3 @@ SECTIONS */ ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support") ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined") -/* - * The HYP init code can't be more than a page long. - * The above comment applies as well. - */ -ASSERT(((__hyp_idmap_text_end - __hyp_idmap_text_start) <= PAGE_SIZE), "HYP init code too big") diff --git a/trunk/arch/arm/kvm/Kconfig b/trunk/arch/arm/kvm/Kconfig index 370e1a8af6ac..49dd64e579c2 100644 --- a/trunk/arch/arm/kvm/Kconfig +++ b/trunk/arch/arm/kvm/Kconfig @@ -41,9 +41,9 @@ config KVM_ARM_HOST Provides host support for ARM processors. config KVM_ARM_MAX_VCPUS - int "Number maximum supported virtual CPUs per VM" if KVM_ARM_HOST - default 4 if KVM_ARM_HOST - default 0 + int "Number maximum supported virtual CPUs per VM" + depends on KVM_ARM_HOST + default 4 help Static number of max supported virtual CPUs per VM. diff --git a/trunk/arch/arm/kvm/Makefile b/trunk/arch/arm/kvm/Makefile index 53c5ed83d16f..8dc5e76cb789 100644 --- a/trunk/arch/arm/kvm/Makefile +++ b/trunk/arch/arm/kvm/Makefile @@ -18,6 +18,6 @@ kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) obj-y += kvm-arm.o init.o interrupts.o obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o -obj-y += coproc.o coproc_a15.o mmio.o psci.o perf.o +obj-y += coproc.o coproc_a15.o mmio.o psci.o obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o diff --git a/trunk/arch/arm/kvm/arch_timer.c b/trunk/arch/arm/kvm/arch_timer.c index c55b6089e923..6ac938d46297 100644 --- a/trunk/arch/arm/kvm/arch_timer.c +++ b/trunk/arch/arm/kvm/arch_timer.c @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -65,7 +64,7 @@ static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu) { struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; - timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK; + timer->cntv_ctl |= 1 << 1; /* Mask the interrupt in the guest */ kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, vcpu->arch.timer_cpu.irq->irq, vcpu->arch.timer_cpu.irq->level); @@ -134,8 +133,8 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) cycle_t cval, now; u64 ns; - if ((timer->cntv_ctl & ARCH_TIMER_CTRL_IT_MASK) || - !(timer->cntv_ctl & ARCH_TIMER_CTRL_ENABLE)) + /* Check if the timer is enabled and unmasked first */ + if ((timer->cntv_ctl & 3) != 1) return; cval = timer->cntv_cval; diff --git a/trunk/arch/arm/kvm/arm.c b/trunk/arch/arm/kvm/arm.c index 37d216d814cd..a0dfc2a53f91 100644 --- a/trunk/arch/arm/kvm/arm.c +++ b/trunk/arch/arm/kvm/arm.c @@ -16,7 +16,6 @@ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include #include #include #include @@ -49,7 +48,7 @@ __asm__(".arch_extension virt"); #endif static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); -static kvm_cpu_context_t __percpu *kvm_host_cpu_state; +static kvm_kernel_vfp_t __percpu *kvm_host_vfp_state; static unsigned long hyp_default_vectors; /* Per-CPU variable containing the currently running vcpu. */ @@ -207,7 +206,7 @@ int kvm_dev_ioctl_check_extension(long ext) r = KVM_MAX_VCPUS; break; default: - r = kvm_arch_dev_ioctl_check_extension(ext); + r = 0; break; } return r; @@ -219,18 +218,27 @@ long kvm_arch_dev_ioctl(struct file *filp, return -EINVAL; } +int kvm_arch_set_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + struct kvm_memory_slot old, + int user_alloc) +{ + return 0; +} + int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *memslot, + struct kvm_memory_slot old, struct kvm_userspace_memory_region *mem, - enum kvm_mr_change change) + bool user_alloc) { return 0; } void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old, - enum kvm_mr_change change) + struct kvm_memory_slot old, + bool user_alloc) { } @@ -318,7 +326,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { vcpu->cpu = cpu; - vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state); + vcpu->arch.vfp_host = this_cpu_ptr(kvm_host_vfp_state); /* * Check whether this vcpu requires the cache to be flushed on @@ -631,8 +639,7 @@ static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level) return 0; } -int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level, - bool line_status) +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level) { u32 irq = irq_level->irq; unsigned int irq_type, vcpu_idx, irq_num; @@ -787,48 +794,30 @@ long kvm_arch_vm_ioctl(struct file *filp, } } -static void cpu_init_hyp_mode(void *dummy) +static void cpu_init_hyp_mode(void *vector) { - unsigned long long boot_pgd_ptr; unsigned long long pgd_ptr; unsigned long hyp_stack_ptr; unsigned long stack_page; unsigned long vector_ptr; /* Switch from the HYP stub to our own HYP init vector */ - __hyp_set_vectors(kvm_get_idmap_vector()); + __hyp_set_vectors((unsigned long)vector); - boot_pgd_ptr = (unsigned long long)kvm_mmu_get_boot_httbr(); pgd_ptr = (unsigned long long)kvm_mmu_get_httbr(); stack_page = __get_cpu_var(kvm_arm_hyp_stack_page); hyp_stack_ptr = stack_page + PAGE_SIZE; vector_ptr = (unsigned long)__kvm_hyp_vector; - __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); -} - -static int hyp_init_cpu_notify(struct notifier_block *self, - unsigned long action, void *cpu) -{ - switch (action) { - case CPU_STARTING: - case CPU_STARTING_FROZEN: - cpu_init_hyp_mode(NULL); - break; - } - - return NOTIFY_OK; + __cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr); } -static struct notifier_block hyp_init_cpu_nb = { - .notifier_call = hyp_init_cpu_notify, -}; - /** * Inits Hyp-mode on all online CPUs */ static int init_hyp_mode(void) { + phys_addr_t init_phys_addr; int cpu; int err = 0; @@ -860,6 +849,24 @@ static int init_hyp_mode(void) per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page; } + /* + * Execute the init code on each CPU. + * + * Note: The stack is not mapped yet, so don't do anything else than + * initializing the hypervisor mode on each CPU using a local stack + * space for temporary storage. + */ + init_phys_addr = virt_to_phys(__kvm_hyp_init); + for_each_online_cpu(cpu) { + smp_call_function_single(cpu, cpu_init_hyp_mode, + (void *)(long)init_phys_addr, 1); + } + + /* + * Unmap the identity mapping + */ + kvm_clear_hyp_idmap(); + /* * Map the Hyp-code called directly from the host */ @@ -883,38 +890,33 @@ static int init_hyp_mode(void) } /* - * Map the host CPU structures + * Map the host VFP structures */ - kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t); - if (!kvm_host_cpu_state) { + kvm_host_vfp_state = alloc_percpu(kvm_kernel_vfp_t); + if (!kvm_host_vfp_state) { err = -ENOMEM; - kvm_err("Cannot allocate host CPU state\n"); + kvm_err("Cannot allocate host VFP state\n"); goto out_free_mappings; } for_each_possible_cpu(cpu) { - kvm_cpu_context_t *cpu_ctxt; + kvm_kernel_vfp_t *vfp; - cpu_ctxt = per_cpu_ptr(kvm_host_cpu_state, cpu); - err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1); + vfp = per_cpu_ptr(kvm_host_vfp_state, cpu); + err = create_hyp_mappings(vfp, vfp + 1); if (err) { - kvm_err("Cannot map host CPU state: %d\n", err); - goto out_free_context; + kvm_err("Cannot map host VFP state: %d\n", err); + goto out_free_vfp; } } - /* - * Execute the init code on each CPU. - */ - on_each_cpu(cpu_init_hyp_mode, NULL, 1); - /* * Init HYP view of VGIC */ err = kvm_vgic_hyp_init(); if (err) - goto out_free_context; + goto out_free_vfp; #ifdef CONFIG_KVM_ARM_VGIC vgic_present = true; @@ -927,19 +929,12 @@ static int init_hyp_mode(void) if (err) goto out_free_mappings; -#ifndef CONFIG_HOTPLUG_CPU - free_boot_hyp_pgd(); -#endif - - kvm_perf_init(); - kvm_info("Hyp mode initialized successfully\n"); - return 0; -out_free_context: - free_percpu(kvm_host_cpu_state); +out_free_vfp: + free_percpu(kvm_host_vfp_state); out_free_mappings: - free_hyp_pgds(); + free_hyp_pmds(); out_free_stack_pages: for_each_possible_cpu(cpu) free_page(per_cpu(kvm_arm_hyp_stack_page, cpu)); @@ -948,42 +943,27 @@ static int init_hyp_mode(void) return err; } -static void check_kvm_target_cpu(void *ret) -{ - *(int *)ret = kvm_target_cpu(); -} - /** * Initialize Hyp-mode and memory mappings on all CPUs. */ int kvm_arch_init(void *opaque) { int err; - int ret, cpu; if (!is_hyp_mode_available()) { kvm_err("HYP mode not available\n"); return -ENODEV; } - for_each_online_cpu(cpu) { - smp_call_function_single(cpu, check_kvm_target_cpu, &ret, 1); - if (ret < 0) { - kvm_err("Error, CPU %d not supported!\n", cpu); - return -ENODEV; - } + if (kvm_target_cpu() < 0) { + kvm_err("Target CPU not supported!\n"); + return -ENODEV; } err = init_hyp_mode(); if (err) goto out_err; - err = register_cpu_notifier(&hyp_init_cpu_nb); - if (err) { - kvm_err("Cannot register HYP init CPU notifier (%d)\n", err); - goto out_err; - } - kvm_coproc_table_init(); return 0; out_err: @@ -993,7 +973,6 @@ int kvm_arch_init(void *opaque) /* NOP: Compiling as a module not supported */ void kvm_arch_exit(void) { - kvm_perf_teardown(); } static int arm_init(void) diff --git a/trunk/arch/arm/kvm/init.S b/trunk/arch/arm/kvm/init.S index f048338135f7..9f37a79b880b 100644 --- a/trunk/arch/arm/kvm/init.S +++ b/trunk/arch/arm/kvm/init.S @@ -21,33 +21,13 @@ #include #include #include -#include /******************************************************************** * Hypervisor initialization * - should be called with: - * r0 = top of Hyp stack (kernel VA) - * r1 = pointer to hyp vectors - * r2,r3 = Hypervisor pgd pointer - * - * The init scenario is: - * - We jump in HYP with four parameters: boot HYP pgd, runtime HYP pgd, - * runtime stack, runtime vectors - * - Enable the MMU with the boot pgd - * - Jump to a target into the trampoline page (remember, this is the same - * physical page!) - * - Now switch to the runtime pgd (same VA, and still the same physical - * page!) - * - Invalidate TLBs - * - Set stack and vectors - * - Profit! (or eret, if you only care about the code). - * - * As we only have four registers available to pass parameters (and we - * need six), we split the init in two phases: - * - Phase 1: r0 = 0, r1 = 0, r2,r3 contain the boot PGD. - * Provides the basic HYP init, and enable the MMU. - * - Phase 2: r0 = ToS, r1 = vectors, r2,r3 contain the runtime PGD. - * Switches to the runtime PGD, set stack and vectors. + * r0,r1 = Hypervisor pgd pointer + * r2 = top of Hyp stack (kernel VA) + * r3 = pointer to hyp vectors */ .text @@ -67,25 +47,22 @@ __kvm_hyp_init: W(b) . __do_hyp_init: - cmp r0, #0 @ We have a SP? - bne phase2 @ Yes, second stage init - @ Set the HTTBR to point to the hypervisor PGD pointer passed - mcrr p15, 4, r2, r3, c2 + mcrr p15, 4, r0, r1, c2 @ Set the HTCR and VTCR to the same shareability and cacheability @ settings as the non-secure TTBCR and with T0SZ == 0. mrc p15, 4, r0, c2, c0, 2 @ HTCR - ldr r2, =HTCR_MASK - bic r0, r0, r2 + ldr r12, =HTCR_MASK + bic r0, r0, r12 mrc p15, 0, r1, c2, c0, 2 @ TTBCR and r1, r1, #(HTCR_MASK & ~TTBCR_T0SZ) orr r0, r0, r1 mcr p15, 4, r0, c2, c0, 2 @ HTCR mrc p15, 4, r1, c2, c1, 2 @ VTCR - ldr r2, =VTCR_MASK - bic r1, r1, r2 + ldr r12, =VTCR_MASK + bic r1, r1, r12 bic r0, r0, #(~VTCR_HTCR_SH) @ clear non-reusable HTCR bits orr r1, r0, r1 orr r1, r1, #(KVM_VTCR_SL0 | KVM_VTCR_T0SZ | KVM_VTCR_S) @@ -108,41 +85,24 @@ __do_hyp_init: @ - Memory alignment checks: enabled @ - MMU: enabled (this code must be run from an identity mapping) mrc p15, 4, r0, c1, c0, 0 @ HSCR - ldr r2, =HSCTLR_MASK - bic r0, r0, r2 + ldr r12, =HSCTLR_MASK + bic r0, r0, r12 mrc p15, 0, r1, c1, c0, 0 @ SCTLR - ldr r2, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C) - and r1, r1, r2 - ARM( ldr r2, =(HSCTLR_M | HSCTLR_A) ) - THUMB( ldr r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) ) - orr r1, r1, r2 + ldr r12, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C) + and r1, r1, r12 + ARM( ldr r12, =(HSCTLR_M | HSCTLR_A) ) + THUMB( ldr r12, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) ) + orr r1, r1, r12 orr r0, r0, r1 isb mcr p15, 4, r0, c1, c0, 0 @ HSCR + isb - @ End of init phase-1 - eret - -phase2: - @ Set stack pointer - mov sp, r0 + @ Set stack pointer and return to the kernel + mov sp, r2 @ Set HVBAR to point to the HYP vectors - mcr p15, 4, r1, c12, c0, 0 @ HVBAR - - @ Jump to the trampoline page - ldr r0, =TRAMPOLINE_VA - adr r1, target - bfi r0, r1, #0, #PAGE_SHIFT - mov pc, r0 - -target: @ We're now in the trampoline code, switch page tables - mcrr p15, 4, r2, r3, c2 - isb - - @ Invalidate the old TLBs - mcr p15, 4, r0, c8, c7, 0 @ TLBIALLH - dsb + mcr p15, 4, r3, c12, c0, 0 @ HVBAR eret diff --git a/trunk/arch/arm/kvm/mmu.c b/trunk/arch/arm/kvm/mmu.c index 965706578f13..2f12e4056408 100644 --- a/trunk/arch/arm/kvm/mmu.c +++ b/trunk/arch/arm/kvm/mmu.c @@ -32,15 +32,8 @@ extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; -static pgd_t *boot_hyp_pgd; -static pgd_t *hyp_pgd; static DEFINE_MUTEX(kvm_hyp_pgd_mutex); -static void *init_bounce_page; -static unsigned long hyp_idmap_start; -static unsigned long hyp_idmap_end; -static phys_addr_t hyp_idmap_vector; - static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) { kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa); @@ -78,224 +71,172 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc) return p; } -static void clear_pud_entry(pud_t *pud) -{ - pmd_t *pmd_table = pmd_offset(pud, 0); - pud_clear(pud); - pmd_free(NULL, pmd_table); - put_page(virt_to_page(pud)); -} - -static void clear_pmd_entry(pmd_t *pmd) -{ - pte_t *pte_table = pte_offset_kernel(pmd, 0); - pmd_clear(pmd); - pte_free_kernel(NULL, pte_table); - put_page(virt_to_page(pmd)); -} - -static bool pmd_empty(pmd_t *pmd) +static void free_ptes(pmd_t *pmd, unsigned long addr) { - struct page *pmd_page = virt_to_page(pmd); - return page_count(pmd_page) == 1; -} + pte_t *pte; + unsigned int i; -static void clear_pte_entry(pte_t *pte) -{ - if (pte_present(*pte)) { - kvm_set_pte(pte, __pte(0)); - put_page(virt_to_page(pte)); + for (i = 0; i < PTRS_PER_PMD; i++, addr += PMD_SIZE) { + if (!pmd_none(*pmd) && pmd_table(*pmd)) { + pte = pte_offset_kernel(pmd, addr); + pte_free_kernel(NULL, pte); + } + pmd++; } } -static bool pte_empty(pte_t *pte) -{ - struct page *pte_page = virt_to_page(pte); - return page_count(pte_page) == 1; -} - -static void unmap_range(pgd_t *pgdp, unsigned long long start, u64 size) +static void free_hyp_pgd_entry(unsigned long addr) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; - pte_t *pte; - unsigned long long addr = start, end = start + size; - u64 range; - - while (addr < end) { - pgd = pgdp + pgd_index(addr); - pud = pud_offset(pgd, addr); - if (pud_none(*pud)) { - addr += PUD_SIZE; - continue; - } - - pmd = pmd_offset(pud, addr); - if (pmd_none(*pmd)) { - addr += PMD_SIZE; - continue; - } + unsigned long hyp_addr = KERN_TO_HYP(addr); - pte = pte_offset_kernel(pmd, addr); - clear_pte_entry(pte); - range = PAGE_SIZE; + pgd = hyp_pgd + pgd_index(hyp_addr); + pud = pud_offset(pgd, hyp_addr); - /* If we emptied the pte, walk back up the ladder */ - if (pte_empty(pte)) { - clear_pmd_entry(pmd); - range = PMD_SIZE; - if (pmd_empty(pmd)) { - clear_pud_entry(pud); - range = PUD_SIZE; - } - } + if (pud_none(*pud)) + return; + BUG_ON(pud_bad(*pud)); - addr += range; - } + pmd = pmd_offset(pud, hyp_addr); + free_ptes(pmd, addr); + pmd_free(NULL, pmd); + pud_clear(pud); } /** - * free_boot_hyp_pgd - free HYP boot page tables + * free_hyp_pmds - free a Hyp-mode level-2 tables and child level-3 tables * - * Free the HYP boot page tables. The bounce page is also freed. + * Assumes this is a page table used strictly in Hyp-mode and therefore contains + * either mappings in the kernel memory area (above PAGE_OFFSET), or + * device mappings in the vmalloc range (from VMALLOC_START to VMALLOC_END). */ -void free_boot_hyp_pgd(void) +void free_hyp_pmds(void) { - mutex_lock(&kvm_hyp_pgd_mutex); - - if (boot_hyp_pgd) { - unmap_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE); - unmap_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE); - kfree(boot_hyp_pgd); - boot_hyp_pgd = NULL; - } - - if (hyp_pgd) - unmap_range(hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE); - - kfree(init_bounce_page); - init_bounce_page = NULL; + unsigned long addr; + mutex_lock(&kvm_hyp_pgd_mutex); + for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) + free_hyp_pgd_entry(addr); + for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) + free_hyp_pgd_entry(addr); mutex_unlock(&kvm_hyp_pgd_mutex); } -/** - * free_hyp_pgds - free Hyp-mode page tables - * - * Assumes hyp_pgd is a page table used strictly in Hyp-mode and - * therefore contains either mappings in the kernel memory area (above - * PAGE_OFFSET), or device mappings in the vmalloc range (from - * VMALLOC_START to VMALLOC_END). - * - * boot_hyp_pgd should only map two pages for the init code. - */ -void free_hyp_pgds(void) +static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start, + unsigned long end) { + pte_t *pte; unsigned long addr; + struct page *page; - free_boot_hyp_pgd(); - - mutex_lock(&kvm_hyp_pgd_mutex); + for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) { + unsigned long hyp_addr = KERN_TO_HYP(addr); - if (hyp_pgd) { - for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) - unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); - for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) - unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); - kfree(hyp_pgd); - hyp_pgd = NULL; + pte = pte_offset_kernel(pmd, hyp_addr); + BUG_ON(!virt_addr_valid(addr)); + page = virt_to_page(addr); + kvm_set_pte(pte, mk_pte(page, PAGE_HYP)); } - - mutex_unlock(&kvm_hyp_pgd_mutex); } -static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start, - unsigned long end, unsigned long pfn, - pgprot_t prot) +static void create_hyp_io_pte_mappings(pmd_t *pmd, unsigned long start, + unsigned long end, + unsigned long *pfn_base) { pte_t *pte; unsigned long addr; - addr = start; - do { - pte = pte_offset_kernel(pmd, addr); - kvm_set_pte(pte, pfn_pte(pfn, prot)); - get_page(virt_to_page(pte)); - kvm_flush_dcache_to_poc(pte, sizeof(*pte)); - pfn++; - } while (addr += PAGE_SIZE, addr != end); + for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) { + unsigned long hyp_addr = KERN_TO_HYP(addr); + + pte = pte_offset_kernel(pmd, hyp_addr); + BUG_ON(pfn_valid(*pfn_base)); + kvm_set_pte(pte, pfn_pte(*pfn_base, PAGE_HYP_DEVICE)); + (*pfn_base)++; + } } static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start, - unsigned long end, unsigned long pfn, - pgprot_t prot) + unsigned long end, unsigned long *pfn_base) { pmd_t *pmd; pte_t *pte; unsigned long addr, next; - addr = start; - do { - pmd = pmd_offset(pud, addr); + for (addr = start; addr < end; addr = next) { + unsigned long hyp_addr = KERN_TO_HYP(addr); + pmd = pmd_offset(pud, hyp_addr); BUG_ON(pmd_sect(*pmd)); if (pmd_none(*pmd)) { - pte = pte_alloc_one_kernel(NULL, addr); + pte = pte_alloc_one_kernel(NULL, hyp_addr); if (!pte) { kvm_err("Cannot allocate Hyp pte\n"); return -ENOMEM; } pmd_populate_kernel(NULL, pmd, pte); - get_page(virt_to_page(pmd)); - kvm_flush_dcache_to_poc(pmd, sizeof(*pmd)); } next = pmd_addr_end(addr, end); - create_hyp_pte_mappings(pmd, addr, next, pfn, prot); - pfn += (next - addr) >> PAGE_SHIFT; - } while (addr = next, addr != end); + /* + * If pfn_base is NULL, we map kernel pages into HYP with the + * virtual address. Otherwise, this is considered an I/O + * mapping and we map the physical region starting at + * *pfn_base to [start, end[. + */ + if (!pfn_base) + create_hyp_pte_mappings(pmd, addr, next); + else + create_hyp_io_pte_mappings(pmd, addr, next, pfn_base); + } return 0; } -static int __create_hyp_mappings(pgd_t *pgdp, - unsigned long start, unsigned long end, - unsigned long pfn, pgprot_t prot) +static int __create_hyp_mappings(void *from, void *to, unsigned long *pfn_base) { + unsigned long start = (unsigned long)from; + unsigned long end = (unsigned long)to; pgd_t *pgd; pud_t *pud; pmd_t *pmd; unsigned long addr, next; int err = 0; + if (start >= end) + return -EINVAL; + /* Check for a valid kernel memory mapping */ + if (!pfn_base && (!virt_addr_valid(from) || !virt_addr_valid(to - 1))) + return -EINVAL; + /* Check for a valid kernel IO mapping */ + if (pfn_base && (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1))) + return -EINVAL; + mutex_lock(&kvm_hyp_pgd_mutex); - addr = start & PAGE_MASK; - end = PAGE_ALIGN(end); - do { - pgd = pgdp + pgd_index(addr); - pud = pud_offset(pgd, addr); + for (addr = start; addr < end; addr = next) { + unsigned long hyp_addr = KERN_TO_HYP(addr); + pgd = hyp_pgd + pgd_index(hyp_addr); + pud = pud_offset(pgd, hyp_addr); if (pud_none_or_clear_bad(pud)) { - pmd = pmd_alloc_one(NULL, addr); + pmd = pmd_alloc_one(NULL, hyp_addr); if (!pmd) { kvm_err("Cannot allocate Hyp pmd\n"); err = -ENOMEM; goto out; } pud_populate(NULL, pud, pmd); - get_page(virt_to_page(pud)); - kvm_flush_dcache_to_poc(pud, sizeof(*pud)); } next = pgd_addr_end(addr, end); - err = create_hyp_pmd_mappings(pud, addr, next, pfn, prot); + err = create_hyp_pmd_mappings(pud, addr, next, pfn_base); if (err) goto out; - pfn += (next - addr) >> PAGE_SHIFT; - } while (addr = next, addr != end); + } out: mutex_unlock(&kvm_hyp_pgd_mutex); return err; @@ -309,41 +250,27 @@ static int __create_hyp_mappings(pgd_t *pgdp, * The same virtual address as the kernel virtual address is also used * in Hyp-mode mapping (modulo HYP_PAGE_OFFSET) to the same underlying * physical pages. + * + * Note: Wrapping around zero in the "to" address is not supported. */ int create_hyp_mappings(void *from, void *to) { - unsigned long phys_addr = virt_to_phys(from); - unsigned long start = KERN_TO_HYP((unsigned long)from); - unsigned long end = KERN_TO_HYP((unsigned long)to); - - /* Check for a valid kernel memory mapping */ - if (!virt_addr_valid(from) || !virt_addr_valid(to - 1)) - return -EINVAL; - - return __create_hyp_mappings(hyp_pgd, start, end, - __phys_to_pfn(phys_addr), PAGE_HYP); + return __create_hyp_mappings(from, to, NULL); } /** * create_hyp_io_mappings - duplicate a kernel IO mapping into Hyp mode * @from: The kernel start VA of the range * @to: The kernel end VA of the range (exclusive) - * @phys_addr: The physical start address which gets mapped + * @addr: The physical start address which gets mapped * * The resulting HYP VA is the same as the kernel VA, modulo * HYP_PAGE_OFFSET. */ -int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr) +int create_hyp_io_mappings(void *from, void *to, phys_addr_t addr) { - unsigned long start = KERN_TO_HYP((unsigned long)from); - unsigned long end = KERN_TO_HYP((unsigned long)to); - - /* Check for a valid kernel IO mapping */ - if (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1)) - return -EINVAL; - - return __create_hyp_mappings(hyp_pgd, start, end, - __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE); + unsigned long pfn = __phys_to_pfn(addr); + return __create_hyp_mappings(from, to, &pfn); } /** @@ -380,6 +307,42 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm) return 0; } +static void clear_pud_entry(pud_t *pud) +{ + pmd_t *pmd_table = pmd_offset(pud, 0); + pud_clear(pud); + pmd_free(NULL, pmd_table); + put_page(virt_to_page(pud)); +} + +static void clear_pmd_entry(pmd_t *pmd) +{ + pte_t *pte_table = pte_offset_kernel(pmd, 0); + pmd_clear(pmd); + pte_free_kernel(NULL, pte_table); + put_page(virt_to_page(pmd)); +} + +static bool pmd_empty(pmd_t *pmd) +{ + struct page *pmd_page = virt_to_page(pmd); + return page_count(pmd_page) == 1; +} + +static void clear_pte_entry(pte_t *pte) +{ + if (pte_present(*pte)) { + kvm_set_pte(pte, __pte(0)); + put_page(virt_to_page(pte)); + } +} + +static bool pte_empty(pte_t *pte) +{ + struct page *pte_page = virt_to_page(pte); + return page_count(pte_page) == 1; +} + /** * unmap_stage2_range -- Clear stage2 page table entries to unmap a range * @kvm: The VM pointer @@ -393,7 +356,43 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm) */ static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size) { - unmap_range(kvm->arch.pgd, start, size); + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + phys_addr_t addr = start, end = start + size; + u64 range; + + while (addr < end) { + pgd = kvm->arch.pgd + pgd_index(addr); + pud = pud_offset(pgd, addr); + if (pud_none(*pud)) { + addr += PUD_SIZE; + continue; + } + + pmd = pmd_offset(pud, addr); + if (pmd_none(*pmd)) { + addr += PMD_SIZE; + continue; + } + + pte = pte_offset_kernel(pmd, addr); + clear_pte_entry(pte); + range = PAGE_SIZE; + + /* If we emptied the pte, walk back up the ladder */ + if (pte_empty(pte)) { + clear_pmd_entry(pmd); + range = PMD_SIZE; + if (pmd_empty(pmd)) { + clear_pud_entry(pud); + range = PUD_SIZE; + } + } + + addr += range; + } } /** @@ -729,105 +728,47 @@ void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu) phys_addr_t kvm_mmu_get_httbr(void) { + VM_BUG_ON(!virt_addr_valid(hyp_pgd)); return virt_to_phys(hyp_pgd); } -phys_addr_t kvm_mmu_get_boot_httbr(void) -{ - return virt_to_phys(boot_hyp_pgd); -} - -phys_addr_t kvm_get_idmap_vector(void) -{ - return hyp_idmap_vector; -} - int kvm_mmu_init(void) { - int err; - - hyp_idmap_start = virt_to_phys(__hyp_idmap_text_start); - hyp_idmap_end = virt_to_phys(__hyp_idmap_text_end); - hyp_idmap_vector = virt_to_phys(__kvm_hyp_init); - - if ((hyp_idmap_start ^ hyp_idmap_end) & PAGE_MASK) { - /* - * Our init code is crossing a page boundary. Allocate - * a bounce page, copy the code over and use that. - */ - size_t len = __hyp_idmap_text_end - __hyp_idmap_text_start; - phys_addr_t phys_base; - - init_bounce_page = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!init_bounce_page) { - kvm_err("Couldn't allocate HYP init bounce page\n"); - err = -ENOMEM; - goto out; - } - - memcpy(init_bounce_page, __hyp_idmap_text_start, len); - /* - * Warning: the code we just copied to the bounce page - * must be flushed to the point of coherency. - * Otherwise, the data may be sitting in L2, and HYP - * mode won't be able to observe it as it runs with - * caches off at that point. - */ - kvm_flush_dcache_to_poc(init_bounce_page, len); - - phys_base = virt_to_phys(init_bounce_page); - hyp_idmap_vector += phys_base - hyp_idmap_start; - hyp_idmap_start = phys_base; - hyp_idmap_end = phys_base + len; - - kvm_info("Using HYP init bounce page @%lx\n", - (unsigned long)phys_base); - } - - hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); - boot_hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); - if (!hyp_pgd || !boot_hyp_pgd) { + if (!hyp_pgd) { kvm_err("Hyp mode PGD not allocated\n"); - err = -ENOMEM; - goto out; + return -ENOMEM; } - /* Create the idmap in the boot page tables */ - err = __create_hyp_mappings(boot_hyp_pgd, - hyp_idmap_start, hyp_idmap_end, - __phys_to_pfn(hyp_idmap_start), - PAGE_HYP); + return 0; +} - if (err) { - kvm_err("Failed to idmap %lx-%lx\n", - hyp_idmap_start, hyp_idmap_end); - goto out; - } +/** + * kvm_clear_idmap - remove all idmaps from the hyp pgd + * + * Free the underlying pmds for all pgds in range and clear the pgds (but + * don't free them) afterwards. + */ +void kvm_clear_hyp_idmap(void) +{ + unsigned long addr, end; + unsigned long next; + pgd_t *pgd = hyp_pgd; + pud_t *pud; + pmd_t *pmd; - /* Map the very same page at the trampoline VA */ - err = __create_hyp_mappings(boot_hyp_pgd, - TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE, - __phys_to_pfn(hyp_idmap_start), - PAGE_HYP); - if (err) { - kvm_err("Failed to map trampoline @%lx into boot HYP pgd\n", - TRAMPOLINE_VA); - goto out; - } + addr = virt_to_phys(__hyp_idmap_text_start); + end = virt_to_phys(__hyp_idmap_text_end); - /* Map the same page again into the runtime page tables */ - err = __create_hyp_mappings(hyp_pgd, - TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE, - __phys_to_pfn(hyp_idmap_start), - PAGE_HYP); - if (err) { - kvm_err("Failed to map trampoline @%lx into runtime HYP pgd\n", - TRAMPOLINE_VA); - goto out; - } + pgd += pgd_index(addr); + do { + next = pgd_addr_end(addr, end); + if (pgd_none_or_clear_bad(pgd)) + continue; + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); - return 0; -out: - free_hyp_pgds(); - return err; + pud_clear(pud); + kvm_clean_pmd_entry(pmd); + pmd_free(NULL, (pmd_t *)((unsigned long)pmd & PAGE_MASK)); + } while (pgd++, addr = next, addr < end); } diff --git a/trunk/arch/arm/kvm/perf.c b/trunk/arch/arm/kvm/perf.c deleted file mode 100644 index 1a3849da0b4b..000000000000 --- a/trunk/arch/arm/kvm/perf.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Based on the x86 implementation. - * - * Copyright (C) 2012 ARM Ltd. - * Author: Marc Zyngier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include - -static int kvm_is_in_guest(void) -{ - return kvm_arm_get_running_vcpu() != NULL; -} - -static int kvm_is_user_mode(void) -{ - struct kvm_vcpu *vcpu; - - vcpu = kvm_arm_get_running_vcpu(); - - if (vcpu) - return !vcpu_mode_priv(vcpu); - - return 0; -} - -static unsigned long kvm_get_guest_ip(void) -{ - struct kvm_vcpu *vcpu; - - vcpu = kvm_arm_get_running_vcpu(); - - if (vcpu) - return *vcpu_pc(vcpu); - - return 0; -} - -static struct perf_guest_info_callbacks kvm_guest_cbs = { - .is_in_guest = kvm_is_in_guest, - .is_user_mode = kvm_is_user_mode, - .get_guest_ip = kvm_get_guest_ip, -}; - -int kvm_perf_init(void) -{ - return perf_register_guest_info_callbacks(&kvm_guest_cbs); -} - -int kvm_perf_teardown(void) -{ - return perf_unregister_guest_info_callbacks(&kvm_guest_cbs); -} diff --git a/trunk/arch/arm/mach-imx/Kconfig b/trunk/arch/arm/mach-imx/Kconfig index 2ebc97e16b91..d58ad4ff8d34 100644 --- a/trunk/arch/arm/mach-imx/Kconfig +++ b/trunk/arch/arm/mach-imx/Kconfig @@ -466,6 +466,8 @@ config MACH_MX31ADS_WM1133_EV1 depends on MACH_MX31ADS depends on MFD_WM8350_I2C depends on REGULATOR_WM8350 = y + select MFD_WM8350_CONFIG_MODE_0 + select MFD_WM8352_CONFIG_MODE_0 help Include support for the Wolfson Microelectronics 1133-EV1 PMU and audio module for the MX31ADS platform. diff --git a/trunk/arch/arm/mach-omap1/pm.c b/trunk/arch/arm/mach-omap1/pm.c index 358b82cb9f78..dd712f109738 100644 --- a/trunk/arch/arm/mach-omap1/pm.c +++ b/trunk/arch/arm/mach-omap1/pm.c @@ -557,7 +557,7 @@ static const struct file_operations omap_pm_debug_fops = { .open = omap_pm_debug_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static void omap_pm_init_debugfs(void) diff --git a/trunk/arch/arm/mach-s3c64xx/Kconfig b/trunk/arch/arm/mach-s3c64xx/Kconfig index 20578536aec7..283cb77d4721 100644 --- a/trunk/arch/arm/mach-s3c64xx/Kconfig +++ b/trunk/arch/arm/mach-s3c64xx/Kconfig @@ -200,7 +200,10 @@ endchoice config SMDK6410_WM1190_EV1 bool "Support Wolfson Microelectronics 1190-EV1 PMIC card" depends on MACH_SMDK6410 + select MFD_WM8350_CONFIG_MODE_0 + select MFD_WM8350_CONFIG_MODE_3 select MFD_WM8350_I2C + select MFD_WM8352_CONFIG_MODE_0 select REGULATOR select REGULATOR_WM8350 select SAMSUNG_GPIO_EXTRA64 diff --git a/trunk/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/trunk/arch/arm/mach-s3c64xx/mach-crag6410-module.c index 7ccfef227c77..a946b759fabd 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -208,7 +208,7 @@ static const struct i2c_board_info wm1277_devs[] = { static struct arizona_pdata wm5102_reva_pdata = { .ldoena = S3C64XX_GPN(7), .gpio_base = CODEC_GPIO_BASE, - .irq_flags = IRQF_TRIGGER_HIGH, + .irq_active_high = true, .micd_pol_gpio = CODEC_GPIO_BASE + 4, .micd_rate = 6, .gpio_defaults = { @@ -238,7 +238,7 @@ static struct spi_board_info wm5102_reva_spi_devs[] = { static struct arizona_pdata wm5102_pdata = { .ldoena = S3C64XX_GPN(7), .gpio_base = CODEC_GPIO_BASE, - .irq_flags = IRQF_TRIGGER_HIGH, + .irq_active_high = true, .micd_pol_gpio = CODEC_GPIO_BASE + 2, .gpio_defaults = { [2] = 0x10000, /* AIF3TXLRCLK */ diff --git a/trunk/arch/arm/mm/idmap.c b/trunk/arch/arm/mm/idmap.c index 83cb3ac27095..5ee505c937d1 100644 --- a/trunk/arch/arm/mm/idmap.c +++ b/trunk/arch/arm/mm/idmap.c @@ -8,6 +8,7 @@ #include #include #include +#include pgd_t *idmap_pgd; @@ -82,10 +83,37 @@ static void identity_mapping_add(pgd_t *pgd, const char *text_start, } while (pgd++, addr = next, addr != end); } +#if defined(CONFIG_ARM_VIRT_EXT) && defined(CONFIG_ARM_LPAE) +pgd_t *hyp_pgd; + +extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[]; + +static int __init init_static_idmap_hyp(void) +{ + hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); + if (!hyp_pgd) + return -ENOMEM; + + pr_info("Setting up static HYP identity map for 0x%p - 0x%p\n", + __hyp_idmap_text_start, __hyp_idmap_text_end); + identity_mapping_add(hyp_pgd, __hyp_idmap_text_start, + __hyp_idmap_text_end, PMD_SECT_AP1); + + return 0; +} +#else +static int __init init_static_idmap_hyp(void) +{ + return 0; +} +#endif + extern char __idmap_text_start[], __idmap_text_end[]; static int __init init_static_idmap(void) { + int ret; + idmap_pgd = pgd_alloc(&init_mm); if (!idmap_pgd) return -ENOMEM; @@ -95,10 +123,12 @@ static int __init init_static_idmap(void) identity_mapping_add(idmap_pgd, __idmap_text_start, __idmap_text_end, 0); + ret = init_static_idmap_hyp(); + /* Flush L1 for the hardware to see this page table content */ flush_cache_louis(); - return 0; + return ret; } early_initcall(init_static_idmap); diff --git a/trunk/arch/blackfin/Kconfig b/trunk/arch/blackfin/Kconfig index 453ebe46b065..c3f2e0bc644a 100644 --- a/trunk/arch/blackfin/Kconfig +++ b/trunk/arch/blackfin/Kconfig @@ -1,3 +1,7 @@ +config SYMBOL_PREFIX + string + default "_" + config MMU def_bool n @@ -29,7 +33,6 @@ config BLACKFIN select ARCH_HAVE_CUSTOM_GPIO_H select ARCH_WANT_OPTIONAL_GPIOLIB select HAVE_UID16 - select HAVE_UNDERSCORE_SYMBOL_PREFIX select VIRT_TO_BUS select ARCH_WANT_IPC_PARSE_VERSION select HAVE_GENERIC_HARDIRQS diff --git a/trunk/arch/cris/arch-v10/kernel/fasttimer.c b/trunk/arch/cris/arch-v10/kernel/fasttimer.c index 48a59afbeeb1..ce6f512968a4 100644 --- a/trunk/arch/cris/arch-v10/kernel/fasttimer.c +++ b/trunk/arch/cris/arch-v10/kernel/fasttimer.c @@ -644,7 +644,7 @@ static const struct file_operations proc_fasttimer_fops = { .open = proc_fasttimer_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif /* PROC_FS */ diff --git a/trunk/arch/cris/arch-v32/kernel/fasttimer.c b/trunk/arch/cris/arch-v32/kernel/fasttimer.c index f6644535b17e..e43dd70acd96 100644 --- a/trunk/arch/cris/arch-v32/kernel/fasttimer.c +++ b/trunk/arch/cris/arch-v32/kernel/fasttimer.c @@ -616,7 +616,7 @@ static const struct file_operations proc_fasttimer_fops = { .open = proc_fasttimer_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif /* PROC_FS */ diff --git a/trunk/arch/h8300/Kconfig b/trunk/arch/h8300/Kconfig index 303e4f9a79d1..79250de1b12a 100644 --- a/trunk/arch/h8300/Kconfig +++ b/trunk/arch/h8300/Kconfig @@ -12,7 +12,10 @@ config H8300 select MODULES_USE_ELF_RELA select OLD_SIGSUSPEND3 select OLD_SIGACTION - select HAVE_UNDERSCORE_SYMBOL_PREFIX + +config SYMBOL_PREFIX + string + default "_" config MMU bool diff --git a/trunk/arch/h8300/kernel/gpio.c b/trunk/arch/h8300/kernel/gpio.c index 084bfd0c107e..b02c752cd326 100644 --- a/trunk/arch/h8300/kernel/gpio.c +++ b/trunk/arch/h8300/kernel/gpio.c @@ -161,7 +161,7 @@ static const struct file_operations gpio_proc_fops = { .open = gpio_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static __init int register_proc(void) diff --git a/trunk/arch/ia64/include/asm/kvm_host.h b/trunk/arch/ia64/include/asm/kvm_host.h index 989dd3fe8de1..cfa74983c675 100644 --- a/trunk/arch/ia64/include/asm/kvm_host.h +++ b/trunk/arch/ia64/include/asm/kvm_host.h @@ -26,7 +26,6 @@ #define KVM_USER_MEM_SLOTS 32 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 -#define KVM_IRQCHIP_NUM_PINS KVM_IOAPIC_NUM_PINS /* define exit reasons from vmm to kvm*/ #define EXIT_REASON_VM_PANIC 0 diff --git a/trunk/arch/ia64/include/uapi/asm/kvm.h b/trunk/arch/ia64/include/uapi/asm/kvm.h index 99503c284400..ec6c6b301238 100644 --- a/trunk/arch/ia64/include/uapi/asm/kvm.h +++ b/trunk/arch/ia64/include/uapi/asm/kvm.h @@ -27,6 +27,7 @@ /* Select x86 specific features in */ #define __KVM_HAVE_IOAPIC #define __KVM_HAVE_IRQ_LINE +#define __KVM_HAVE_DEVICE_ASSIGNMENT /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 diff --git a/trunk/arch/ia64/kernel/palinfo.c b/trunk/arch/ia64/kernel/palinfo.c index 2b3c2d79256f..b17129e3b7c8 100644 --- a/trunk/arch/ia64/kernel/palinfo.c +++ b/trunk/arch/ia64/kernel/palinfo.c @@ -929,7 +929,7 @@ static const struct file_operations proc_palinfo_fops = { .open = proc_palinfo_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static void __cpuinit diff --git a/trunk/arch/ia64/kernel/salinfo.c b/trunk/arch/ia64/kernel/salinfo.c index 4bc580af67b3..5035245cb258 100644 --- a/trunk/arch/ia64/kernel/salinfo.c +++ b/trunk/arch/ia64/kernel/salinfo.c @@ -694,7 +694,7 @@ static const struct file_operations proc_salinfo_fops = { .open = proc_salinfo_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; module_init(salinfo_init); diff --git a/trunk/arch/ia64/kvm/Kconfig b/trunk/arch/ia64/kvm/Kconfig index 990b86420cc6..2cd225f8c68d 100644 --- a/trunk/arch/ia64/kvm/Kconfig +++ b/trunk/arch/ia64/kvm/Kconfig @@ -21,11 +21,12 @@ config KVM tristate "Kernel-based Virtual Machine (KVM) support" depends on BROKEN depends on HAVE_KVM && MODULES + # for device assignment: + depends on PCI depends on BROKEN select PREEMPT_NOTIFIERS select ANON_INODES select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQ_ROUTING select KVM_APIC_ARCHITECTURE select KVM_MMIO ---help--- @@ -49,17 +50,6 @@ config KVM_INTEL Provides support for KVM on Itanium 2 processors equipped with the VT extensions. -config KVM_DEVICE_ASSIGNMENT - bool "KVM legacy PCI device assignment support" - depends on KVM && PCI && IOMMU_API - default y - ---help--- - Provide support for legacy PCI device assignment through KVM. The - kernel now also supports a full featured userspace device driver - framework through VFIO, which supersedes much of this support. - - If unsure, say Y. - source drivers/vhost/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/ia64/kvm/Makefile b/trunk/arch/ia64/kvm/Makefile index 1a4053789d01..db3d7c5d1071 100644 --- a/trunk/arch/ia64/kvm/Makefile +++ b/trunk/arch/ia64/kvm/Makefile @@ -49,10 +49,10 @@ ccflags-y := -Ivirt/kvm -Iarch/ia64/kvm/ asflags-y := -Ivirt/kvm -Iarch/ia64/kvm/ common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \ - coalesced_mmio.o irq_comm.o) + coalesced_mmio.o irq_comm.o assigned-dev.o) -ifeq ($(CONFIG_KVM_DEVICE_ASSIGNMENT),y) -common-objs += $(addprefix ../../../virt/kvm/, assigned-dev.o iommu.o) +ifeq ($(CONFIG_IOMMU_API),y) +common-objs += $(addprefix ../../../virt/kvm/, iommu.o) endif kvm-objs := $(common-objs) kvm-ia64.o kvm_fw.o diff --git a/trunk/arch/ia64/kvm/kvm-ia64.c b/trunk/arch/ia64/kvm/kvm-ia64.c index 5b2dc0d10c8f..ad3126a58644 100644 --- a/trunk/arch/ia64/kvm/kvm-ia64.c +++ b/trunk/arch/ia64/kvm/kvm-ia64.c @@ -204,11 +204,9 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_COALESCED_MMIO: r = KVM_COALESCED_MMIO_PAGE_OFFSET; break; -#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT case KVM_CAP_IOMMU: r = iommu_present(&pci_bus_type); break; -#endif default: r = 0; } @@ -926,15 +924,13 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return 0; } -int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, - bool line_status) +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event) { if (!irqchip_in_kernel(kvm)) return -ENXIO; irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, - irq_event->irq, irq_event->level, - line_status); + irq_event->irq, irq_event->level); return 0; } @@ -946,6 +942,24 @@ long kvm_arch_vm_ioctl(struct file *filp, int r = -ENOTTY; switch (ioctl) { + case KVM_SET_MEMORY_REGION: { + struct kvm_memory_region kvm_mem; + struct kvm_userspace_memory_region kvm_userspace_mem; + + r = -EFAULT; + if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) + goto out; + kvm_userspace_mem.slot = kvm_mem.slot; + kvm_userspace_mem.flags = kvm_mem.flags; + kvm_userspace_mem.guest_phys_addr = + kvm_mem.guest_phys_addr; + kvm_userspace_mem.memory_size = kvm_mem.memory_size; + r = kvm_vm_ioctl_set_memory_region(kvm, + &kvm_userspace_mem, false); + if (r) + goto out; + break; + } case KVM_CREATE_IRQCHIP: r = -EFAULT; r = kvm_ioapic_init(kvm); @@ -1370,7 +1384,9 @@ void kvm_arch_sync_events(struct kvm *kvm) void kvm_arch_destroy_vm(struct kvm *kvm) { kvm_iommu_unmap_guest(kvm); +#ifdef KVM_CAP_DEVICE_ASSIGNMENT kvm_free_all_assigned_devices(kvm); +#endif kfree(kvm->arch.vioapic); kvm_release_vm_pages(kvm); } @@ -1562,8 +1578,9 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *memslot, + struct kvm_memory_slot old, struct kvm_userspace_memory_region *mem, - enum kvm_mr_change change) + bool user_alloc) { unsigned long i; unsigned long pfn; @@ -1593,8 +1610,8 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old, - enum kvm_mr_change change) + struct kvm_memory_slot old, + bool user_alloc) { return; } diff --git a/trunk/arch/ia64/kvm/lapic.h b/trunk/arch/ia64/kvm/lapic.h index c5f92a926a9a..c3e2935b6db4 100644 --- a/trunk/arch/ia64/kvm/lapic.h +++ b/trunk/arch/ia64/kvm/lapic.h @@ -27,4 +27,10 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq); #define kvm_apic_present(x) (true) #define kvm_lapic_enabled(x) (true) +static inline bool kvm_apic_vid_enabled(void) +{ + /* IA64 has no apicv supporting, do nothing here */ + return false; +} + #endif diff --git a/trunk/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/trunk/arch/ia64/sn/kernel/sn2/prominfo_proc.c index ec4de2b09653..daa8d6badb16 100644 --- a/trunk/arch/ia64/sn/kernel/sn2/prominfo_proc.c +++ b/trunk/arch/ia64/sn/kernel/sn2/prominfo_proc.c @@ -149,7 +149,7 @@ static const struct file_operations proc_fit_fops = { .open = proc_fit_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int proc_version_show(struct seq_file *m, void *v) @@ -183,7 +183,7 @@ static const struct file_operations proc_version_fops = { .open = proc_version_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /* module entry points */ diff --git a/trunk/arch/metag/Kconfig b/trunk/arch/metag/Kconfig index 6f16c1469327..b06b41861aac 100644 --- a/trunk/arch/metag/Kconfig +++ b/trunk/arch/metag/Kconfig @@ -1,3 +1,7 @@ +config SYMBOL_PREFIX + string + default "_" + config METAG def_bool y select EMBEDDED @@ -24,7 +28,6 @@ config METAG select HAVE_OPROFILE select HAVE_PERF_EVENTS select HAVE_SYSCALL_TRACEPOINTS - select HAVE_UNDERSCORE_SYMBOL_PREFIX select IRQ_DOMAIN select MODULES_USE_ELF_RELA select OF diff --git a/trunk/arch/mips/kernel/smtc-proc.c b/trunk/arch/mips/kernel/smtc-proc.c index c10aa84c9fa9..9fb714450e95 100644 --- a/trunk/arch/mips/kernel/smtc-proc.c +++ b/trunk/arch/mips/kernel/smtc-proc.c @@ -61,7 +61,7 @@ static const struct file_operations smtc_proc_fops = { .open = smtc_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; void init_smtc_stats(void) diff --git a/trunk/arch/mips/pci/ops-pmcmsp.c b/trunk/arch/mips/pci/ops-pmcmsp.c index 3d27800edba2..4eaab6327369 100644 --- a/trunk/arch/mips/pci/ops-pmcmsp.c +++ b/trunk/arch/mips/pci/ops-pmcmsp.c @@ -92,7 +92,7 @@ static const struct file_operations msp_pci_rd_cnt_fops = { .open = msp_pci_rd_cnt_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /***************************************************************************** @@ -169,7 +169,7 @@ static const struct file_operations gen_pci_cfg_wr_fops = { .open = gen_pci_cfg_wr_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /***************************************************************************** diff --git a/trunk/arch/mips/sibyte/sb1250/bus_watcher.c b/trunk/arch/mips/sibyte/sb1250/bus_watcher.c index 8871e3345bff..cb1e3cb37d70 100644 --- a/trunk/arch/mips/sibyte/sb1250/bus_watcher.c +++ b/trunk/arch/mips/sibyte/sb1250/bus_watcher.c @@ -145,7 +145,7 @@ static const struct file_operations bw_proc_fops = { .open = bw_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static void create_proc_decoder(struct bw_stats_struct *stats) diff --git a/trunk/arch/parisc/kernel/pdc_chassis.c b/trunk/arch/parisc/kernel/pdc_chassis.c index 3e04242de5a7..8fa314fbfb18 100644 --- a/trunk/arch/parisc/kernel/pdc_chassis.c +++ b/trunk/arch/parisc/kernel/pdc_chassis.c @@ -275,7 +275,7 @@ static const struct file_operations pdc_chassis_warn_fops = { .open = pdc_chassis_warn_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int __init pdc_chassis_create_procfs(void) diff --git a/trunk/arch/powerpc/include/asm/hvcall.h b/trunk/arch/powerpc/include/asm/hvcall.h index cf4df8e2139a..4bc2c3dad6ad 100644 --- a/trunk/arch/powerpc/include/asm/hvcall.h +++ b/trunk/arch/powerpc/include/asm/hvcall.h @@ -270,9 +270,6 @@ #define H_SET_MODE 0x31C #define MAX_HCALL_OPCODE H_SET_MODE -/* Platform specific hcalls, used by KVM */ -#define H_RTAS 0xf000 - #ifndef __ASSEMBLY__ /** diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s.h b/trunk/arch/powerpc/include/asm/kvm_book3s.h index 349ed85c7d61..5a56e1c5f851 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s.h @@ -142,8 +142,6 @@ extern int kvmppc_mmu_hv_init(void); extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data); extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data); extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec); -extern void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu, - unsigned int vec); extern void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags); extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper, u32 val); @@ -158,8 +156,7 @@ void kvmppc_clear_ref_hpte(struct kvm *kvm, unsigned long *hptep, unsigned long pte_index); extern void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long addr, unsigned long *nb_ret); -extern void kvmppc_unpin_guest_page(struct kvm *kvm, void *addr, - unsigned long gpa, bool dirty); +extern void kvmppc_unpin_guest_page(struct kvm *kvm, void *addr); extern long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags, long pte_index, unsigned long pteh, unsigned long ptel); extern long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags, @@ -461,8 +458,6 @@ static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu) #define OSI_SC_MAGIC_R4 0x77810F9B #define INS_DCBZ 0x7c0007ec -/* TO = 31 for unconditional trap */ -#define INS_TW 0x7fe00008 /* LPIDs we support with this build -- runtime limit may be lower */ #define KVMPPC_NR_LPIDS (LPID_RSVD + 1) diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s_64.h b/trunk/arch/powerpc/include/asm/kvm_book3s_64.h index 9c1ff330c805..38bec1dc9928 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s_64.h @@ -268,17 +268,4 @@ static inline int is_vrma_hpte(unsigned long hpte_v) (HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16))); } -#ifdef CONFIG_KVM_BOOK3S_64_HV -/* - * Note modification of an HPTE; set the HPTE modified bit - * if anyone is interested. - */ -static inline void note_hpte_modification(struct kvm *kvm, - struct revmap_entry *rev) -{ - if (atomic_read(&kvm->arch.hpte_mod_interest)) - rev->guest_rpte |= HPTE_GR_MODIFIED; -} -#endif /* CONFIG_KVM_BOOK3S_64_HV */ - #endif /* __ASM_KVM_BOOK3S_64_H__ */ diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s_asm.h b/trunk/arch/powerpc/include/asm/kvm_book3s_asm.h index 9039d3c97eec..cdc3d2717cc6 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s_asm.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s_asm.h @@ -20,11 +20,6 @@ #ifndef __ASM_KVM_BOOK3S_ASM_H__ #define __ASM_KVM_BOOK3S_ASM_H__ -/* XICS ICP register offsets */ -#define XICS_XIRR 4 -#define XICS_MFRR 0xc -#define XICS_IPI 2 /* interrupt source # for IPIs */ - #ifdef __ASSEMBLY__ #ifdef CONFIG_KVM_BOOK3S_HANDLER @@ -86,11 +81,10 @@ struct kvmppc_host_state { #ifdef CONFIG_KVM_BOOK3S_64_HV u8 hwthread_req; u8 hwthread_state; - u8 host_ipi; + struct kvm_vcpu *kvm_vcpu; struct kvmppc_vcore *kvm_vcore; unsigned long xics_phys; - u32 saved_xirr; u64 dabr; u64 host_mmcr[3]; u32 host_pmc[8]; diff --git a/trunk/arch/powerpc/include/asm/kvm_booke.h b/trunk/arch/powerpc/include/asm/kvm_booke.h index d3c1eb34c986..b7cd3356a532 100644 --- a/trunk/arch/powerpc/include/asm/kvm_booke.h +++ b/trunk/arch/powerpc/include/asm/kvm_booke.h @@ -26,8 +26,6 @@ /* LPIDs we support with this build -- runtime limit may be lower */ #define KVMPPC_NR_LPIDS 64 -#define KVMPPC_INST_EHPRIV 0x7c00021c - static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) { vcpu->arch.gpr[num] = val; diff --git a/trunk/arch/powerpc/include/asm/kvm_host.h b/trunk/arch/powerpc/include/asm/kvm_host.h index af326cde7cb6..d1bb86074721 100644 --- a/trunk/arch/powerpc/include/asm/kvm_host.h +++ b/trunk/arch/powerpc/include/asm/kvm_host.h @@ -44,10 +44,6 @@ #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 #endif -/* These values are internal and can be increased later */ -#define KVM_NR_IRQCHIPS 1 -#define KVM_IRQCHIP_NUM_PINS 256 - #if !defined(CONFIG_KVM_440) #include @@ -192,10 +188,6 @@ struct kvmppc_linear_info { int type; }; -/* XICS components, defined in book3s_xics.c */ -struct kvmppc_xics; -struct kvmppc_icp; - /* * The reverse mapping array has one entry for each HPTE, * which stores the guest's view of the second word of the HPTE @@ -263,13 +255,6 @@ struct kvm_arch { #endif /* CONFIG_KVM_BOOK3S_64_HV */ #ifdef CONFIG_PPC_BOOK3S_64 struct list_head spapr_tce_tables; - struct list_head rtas_tokens; -#endif -#ifdef CONFIG_KVM_MPIC - struct openpic *mpic; -#endif -#ifdef CONFIG_KVM_XICS - struct kvmppc_xics *xics; #endif }; @@ -316,13 +301,11 @@ struct kvmppc_vcore { * that a guest can register. */ struct kvmppc_vpa { - unsigned long gpa; /* Current guest phys addr */ void *pinned_addr; /* Address in kernel linear mapping */ void *pinned_end; /* End of region */ unsigned long next_gpa; /* Guest phys addr for update */ unsigned long len; /* Number of bytes required */ u8 update_pending; /* 1 => update pinned_addr from next_gpa */ - bool dirty; /* true => area has been modified by kernel */ }; struct kvmppc_pte { @@ -376,11 +359,6 @@ struct kvmppc_slb { #define KVMPPC_BOOKE_MAX_IAC 4 #define KVMPPC_BOOKE_MAX_DAC 2 -/* KVMPPC_EPR_USER takes precedence over KVMPPC_EPR_KERNEL */ -#define KVMPPC_EPR_NONE 0 /* EPR not supported */ -#define KVMPPC_EPR_USER 1 /* exit to userspace to fill EPR */ -#define KVMPPC_EPR_KERNEL 2 /* in-kernel irqchip */ - struct kvmppc_booke_debug_reg { u32 dbcr0; u32 dbcr1; @@ -392,12 +370,6 @@ struct kvmppc_booke_debug_reg { u64 dac[KVMPPC_BOOKE_MAX_DAC]; }; -#define KVMPPC_IRQ_DEFAULT 0 -#define KVMPPC_IRQ_MPIC 1 -#define KVMPPC_IRQ_XICS 2 - -struct openpic; - struct kvm_vcpu_arch { ulong host_stack; u32 host_pid; @@ -530,11 +502,8 @@ struct kvm_vcpu_arch { spinlock_t wdt_lock; struct timer_list wdt_timer; u32 tlbcfg[4]; - u32 tlbps[4]; u32 mmucfg; - u32 eptcfg; u32 epr; - u32 crit_save; struct kvmppc_booke_debug_reg dbg_reg; #endif gpa_t paddr_accessed; @@ -552,7 +521,7 @@ struct kvm_vcpu_arch { u8 sane; u8 cpu_type; u8 hcall_needed; - u8 epr_flags; /* KVMPPC_EPR_xxx */ + u8 epr_enabled; u8 epr_needed; u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ @@ -579,13 +548,6 @@ struct kvm_vcpu_arch { unsigned long magic_page_pa; /* phys addr to map the magic page to */ unsigned long magic_page_ea; /* effect. addr to map the magic page to */ - int irq_type; /* one of KVM_IRQ_* */ - int irq_cpu_id; - struct openpic *mpic; /* KVM_IRQ_MPIC */ -#ifdef CONFIG_KVM_XICS - struct kvmppc_icp *icp; /* XICS presentation controller */ -#endif - #ifdef CONFIG_KVM_BOOK3S_64_HV struct kvm_vcpu_arch_shared shregs; @@ -626,6 +588,5 @@ struct kvm_vcpu_arch { #define KVM_MMIO_REG_FQPR 0x0060 #define __KVM_HAVE_ARCH_WQP -#define __KVM_HAVE_CREATE_DEVICE #endif /* __POWERPC_KVM_HOST_H__ */ diff --git a/trunk/arch/powerpc/include/asm/kvm_ppc.h b/trunk/arch/powerpc/include/asm/kvm_ppc.h index a5287fe03d77..44a657adf416 100644 --- a/trunk/arch/powerpc/include/asm/kvm_ppc.h +++ b/trunk/arch/powerpc/include/asm/kvm_ppc.h @@ -44,7 +44,7 @@ enum emulation_result { EMULATE_DO_DCR, /* kvm_run filled with DCR request */ EMULATE_FAIL, /* can't emulate this instruction */ EMULATE_AGAIN, /* something went wrong. go again */ - EMULATE_EXIT_USER, /* emulation requires exit to user-space */ + EMULATE_DO_PAPR, /* kvm_run filled with PAPR request */ }; extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); @@ -104,7 +104,8 @@ extern void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu); extern void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu); extern void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq); -extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu); +extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, + struct kvm_interrupt *irq); extern void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu); extern int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, @@ -130,7 +131,6 @@ extern long kvmppc_prepare_vrma(struct kvm *kvm, extern void kvmppc_map_vrma(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot, unsigned long porder); extern int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu); - extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, struct kvm_create_spapr_tce *args); extern long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, @@ -152,7 +152,7 @@ extern int kvmppc_core_prepare_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem); extern void kvmppc_core_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old); + struct kvm_memory_slot old); extern int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info); extern void kvmppc_core_flush_memslot(struct kvm *kvm, @@ -165,18 +165,6 @@ extern int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu); extern int kvm_vm_ioctl_get_htab_fd(struct kvm *kvm, struct kvm_get_htab_fd *); -int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq); - -extern int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp); -extern int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu); -extern void kvmppc_rtas_tokens_free(struct kvm *kvm); -extern int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, - u32 priority); -extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, - u32 *priority); -extern int kvmppc_xics_int_on(struct kvm *kvm, u32 irq); -extern int kvmppc_xics_int_off(struct kvm *kvm, u32 irq); - /* * Cuts out inst bits with ordering according to spec. * That means the leftmost bit is zero. All given bits are included. @@ -258,29 +246,12 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *); void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid); -struct openpic; - #ifdef CONFIG_KVM_BOOK3S_64_HV static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) { paca[cpu].kvm_hstate.xics_phys = addr; } -static inline u32 kvmppc_get_xics_latch(void) -{ - u32 xirr = get_paca()->kvm_hstate.saved_xirr; - - get_paca()->kvm_hstate.saved_xirr = 0; - - return xirr; -} - -static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi) -{ - paca[cpu].kvm_hstate.host_ipi = host_ipi; -} - -extern void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu); extern void kvm_linear_init(void); #else @@ -289,46 +260,6 @@ static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) static inline void kvm_linear_init(void) {} - -static inline u32 kvmppc_get_xics_latch(void) -{ - return 0; -} - -static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi) -{} - -static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu) -{ - kvm_vcpu_kick(vcpu); -} -#endif - -#ifdef CONFIG_KVM_XICS -static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.irq_type == KVMPPC_IRQ_XICS; -} -extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu); -extern int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server); -extern int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args); -extern int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd); -extern u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu); -extern int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval); -extern int kvmppc_xics_connect_vcpu(struct kvm_device *dev, - struct kvm_vcpu *vcpu, u32 cpu); -#else -static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu) - { return 0; } -static inline void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) { } -static inline int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, - unsigned long server) - { return -EINVAL; } -static inline int kvm_vm_ioctl_xics_irq(struct kvm *kvm, - struct kvm_irq_level *args) - { return -ENOTTY; } -static inline int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd) - { return 0; } #endif static inline void kvmppc_set_epr(struct kvm_vcpu *vcpu, u32 epr) @@ -340,32 +271,6 @@ static inline void kvmppc_set_epr(struct kvm_vcpu *vcpu, u32 epr) #endif } -#ifdef CONFIG_KVM_MPIC - -void kvmppc_mpic_set_epr(struct kvm_vcpu *vcpu); -int kvmppc_mpic_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu, - u32 cpu); -void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, struct kvm_vcpu *vcpu); - -#else - -static inline void kvmppc_mpic_set_epr(struct kvm_vcpu *vcpu) -{ -} - -static inline int kvmppc_mpic_connect_vcpu(struct kvm_device *dev, - struct kvm_vcpu *vcpu, u32 cpu) -{ - return -EINVAL; -} - -static inline void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, - struct kvm_vcpu *vcpu) -{ -} - -#endif /* CONFIG_KVM_MPIC */ - int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu, struct kvm_config_tlb *cfg); int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu, @@ -378,15 +283,8 @@ void kvmppc_init_lpid(unsigned long nr_lpids); static inline void kvmppc_mmu_flush_icache(pfn_t pfn) { - struct page *page; - /* - * We can only access pages that the kernel maps - * as memory. Bail out for unmapped ones. - */ - if (!pfn_valid(pfn)) - return; - /* Clear i-cache for new pages */ + struct page *page; page = pfn_to_page(pfn); if (!test_bit(PG_arch_1, &page->flags)) { flush_dcache_icache_page(page); @@ -426,6 +324,4 @@ static inline ulong kvmppc_get_ea_indexed(struct kvm_vcpu *vcpu, int ra, int rb) return ea; } -extern void xics_wake_cpu(int cpu); - #endif /* __POWERPC_KVM_PPC_H__ */ diff --git a/trunk/arch/powerpc/include/asm/reg.h b/trunk/arch/powerpc/include/asm/reg.h index a6136515c7f2..3d17427e4fd7 100644 --- a/trunk/arch/powerpc/include/asm/reg.h +++ b/trunk/arch/powerpc/include/asm/reg.h @@ -300,7 +300,6 @@ #define LPCR_PECE1 0x00002000 /* decrementer can cause exit */ #define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */ #define LPCR_MER 0x00000800 /* Mediated External Exception */ -#define LPCR_MER_SH 11 #define LPCR_LPES 0x0000000c #define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */ #define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */ diff --git a/trunk/arch/powerpc/include/uapi/asm/kvm.h b/trunk/arch/powerpc/include/uapi/asm/kvm.h index 0fb1a6e9ff90..16064d00adb9 100644 --- a/trunk/arch/powerpc/include/uapi/asm/kvm.h +++ b/trunk/arch/powerpc/include/uapi/asm/kvm.h @@ -25,8 +25,6 @@ /* Select powerpc specific features in */ #define __KVM_HAVE_SPAPR_TCE #define __KVM_HAVE_PPC_SMT -#define __KVM_HAVE_IRQCHIP -#define __KVM_HAVE_IRQ_LINE struct kvm_regs { __u64 pc; @@ -274,31 +272,8 @@ struct kvm_debug_exit_arch { /* for KVM_SET_GUEST_DEBUG */ struct kvm_guest_debug_arch { - struct { - /* H/W breakpoint/watchpoint address */ - __u64 addr; - /* - * Type denotes h/w breakpoint, read watchpoint, write - * watchpoint or watchpoint (both read and write). - */ -#define KVMPPC_DEBUG_NONE 0x0 -#define KVMPPC_DEBUG_BREAKPOINT (1UL << 1) -#define KVMPPC_DEBUG_WATCH_WRITE (1UL << 2) -#define KVMPPC_DEBUG_WATCH_READ (1UL << 3) - __u32 type; - __u32 reserved; - } bp[16]; }; -/* Debug related defines */ -/* - * kvm_guest_debug->control is a 32 bit field. The lower 16 bits are generic - * and upper 16 bits are architecture specific. Architecture specific defines - * that ioctl is for setting hardware breakpoint or software breakpoint. - */ -#define KVM_GUESTDBG_USE_SW_BP 0x00010000 -#define KVM_GUESTDBG_USE_HW_BP 0x00020000 - /* definition of registers in kvm_run */ struct kvm_sync_regs { }; @@ -324,12 +299,6 @@ struct kvm_allocate_rma { __u64 rma_size; }; -/* for KVM_CAP_PPC_RTAS */ -struct kvm_rtas_token_args { - char name[120]; - __u64 token; /* Use a token of 0 to undefine a mapping */ -}; - struct kvm_book3e_206_tlb_entry { __u32 mas8; __u32 mas1; @@ -390,26 +359,6 @@ struct kvm_get_htab_header { __u16 n_invalid; }; -/* Per-vcpu XICS interrupt controller state */ -#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c) - -#define KVM_REG_PPC_ICP_CPPR_SHIFT 56 /* current proc priority */ -#define KVM_REG_PPC_ICP_CPPR_MASK 0xff -#define KVM_REG_PPC_ICP_XISR_SHIFT 32 /* interrupt status field */ -#define KVM_REG_PPC_ICP_XISR_MASK 0xffffff -#define KVM_REG_PPC_ICP_MFRR_SHIFT 24 /* pending IPI priority */ -#define KVM_REG_PPC_ICP_MFRR_MASK 0xff -#define KVM_REG_PPC_ICP_PPRI_SHIFT 16 /* pending irq priority */ -#define KVM_REG_PPC_ICP_PPRI_MASK 0xff - -/* Device control API: PPC-specific devices */ -#define KVM_DEV_MPIC_GRP_MISC 1 -#define KVM_DEV_MPIC_BASE_ADDR 0 /* 64-bit */ - -#define KVM_DEV_MPIC_GRP_REGISTER 2 /* 32-bit */ -#define KVM_DEV_MPIC_GRP_IRQ_ACTIVE 3 /* 32-bit */ - -/* One-Reg API: PPC-specific registers */ #define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1) #define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2) #define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3) @@ -468,47 +417,4 @@ struct kvm_get_htab_header { #define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85) #define KVM_REG_PPC_EPR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x86) -/* Timer Status Register OR/CLEAR interface */ -#define KVM_REG_PPC_OR_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x87) -#define KVM_REG_PPC_CLEAR_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x88) -#define KVM_REG_PPC_TCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x89) -#define KVM_REG_PPC_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8a) - -/* Debugging: Special instruction for software breakpoint */ -#define KVM_REG_PPC_DEBUG_INST (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8b) - -/* MMU registers */ -#define KVM_REG_PPC_MAS0 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8c) -#define KVM_REG_PPC_MAS1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8d) -#define KVM_REG_PPC_MAS2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8e) -#define KVM_REG_PPC_MAS7_3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8f) -#define KVM_REG_PPC_MAS4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x90) -#define KVM_REG_PPC_MAS6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x91) -#define KVM_REG_PPC_MMUCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x92) -/* - * TLBnCFG fields TLBnCFG_N_ENTRY and TLBnCFG_ASSOC can be changed only using - * KVM_CAP_SW_TLB ioctl - */ -#define KVM_REG_PPC_TLB0CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x93) -#define KVM_REG_PPC_TLB1CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x94) -#define KVM_REG_PPC_TLB2CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x95) -#define KVM_REG_PPC_TLB3CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x96) -#define KVM_REG_PPC_TLB0PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x97) -#define KVM_REG_PPC_TLB1PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x98) -#define KVM_REG_PPC_TLB2PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x99) -#define KVM_REG_PPC_TLB3PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9a) -#define KVM_REG_PPC_EPTCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9b) - -/* PPC64 eXternal Interrupt Controller Specification */ -#define KVM_DEV_XICS_GRP_SOURCES 1 /* 64-bit source attributes */ - -/* Layout of 64-bit source attribute values */ -#define KVM_XICS_DESTINATION_SHIFT 0 -#define KVM_XICS_DESTINATION_MASK 0xffffffffULL -#define KVM_XICS_PRIORITY_SHIFT 32 -#define KVM_XICS_PRIORITY_MASK 0xff -#define KVM_XICS_LEVEL_SENSITIVE (1ULL << 40) -#define KVM_XICS_MASKED (1ULL << 41) -#define KVM_XICS_PENDING (1ULL << 42) - #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c index b51a97cfedf8..172233eab799 100644 --- a/trunk/arch/powerpc/kernel/asm-offsets.c +++ b/trunk/arch/powerpc/kernel/asm-offsets.c @@ -480,7 +480,6 @@ int main(void) DEFINE(VCPU_DSISR, offsetof(struct kvm_vcpu, arch.shregs.dsisr)); DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar)); DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr)); - DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty)); #endif #ifdef CONFIG_PPC_BOOK3S DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id)); @@ -577,8 +576,6 @@ int main(void) HSTATE_FIELD(HSTATE_KVM_VCPU, kvm_vcpu); HSTATE_FIELD(HSTATE_KVM_VCORE, kvm_vcore); HSTATE_FIELD(HSTATE_XICS_PHYS, xics_phys); - HSTATE_FIELD(HSTATE_SAVED_XIRR, saved_xirr); - HSTATE_FIELD(HSTATE_HOST_IPI, host_ipi); HSTATE_FIELD(HSTATE_MMCR, host_mmcr); HSTATE_FIELD(HSTATE_PMC, host_pmc); HSTATE_FIELD(HSTATE_PURR, host_purr); @@ -602,7 +599,6 @@ int main(void) DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst)); DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); - DEFINE(VCPU_CRIT_SAVE, offsetof(struct kvm_vcpu, arch.crit_save)); #endif /* CONFIG_PPC_BOOK3S */ #endif /* CONFIG_KVM */ diff --git a/trunk/arch/powerpc/kvm/44x.c b/trunk/arch/powerpc/kvm/44x.c index 2f5c6b6d6877..3d7fd21c65f9 100644 --- a/trunk/arch/powerpc/kvm/44x.c +++ b/trunk/arch/powerpc/kvm/44x.c @@ -124,18 +124,6 @@ int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) return kvmppc_set_sregs_ivor(vcpu, sregs); } -int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, - union kvmppc_one_reg *val) -{ - return -EINVAL; -} - -int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, - union kvmppc_one_reg *val) -{ - return -EINVAL; -} - struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) { struct kvmppc_vcpu_44x *vcpu_44x; diff --git a/trunk/arch/powerpc/kvm/Kconfig b/trunk/arch/powerpc/kvm/Kconfig index eb643f862579..63c67ec72e43 100644 --- a/trunk/arch/powerpc/kvm/Kconfig +++ b/trunk/arch/powerpc/kvm/Kconfig @@ -136,41 +136,21 @@ config KVM_E500V2 If unsure, say N. config KVM_E500MC - bool "KVM support for PowerPC E500MC/E5500/E6500 processors" + bool "KVM support for PowerPC E500MC/E5500 processors" depends on PPC_E500MC select KVM select KVM_MMIO select KVM_BOOKE_HV select MMU_NOTIFIER ---help--- - Support running unmodified E500MC/E5500/E6500 guest kernels in - virtual machines on E500MC/E5500/E6500 host processors. + Support running unmodified E500MC/E5500 (32-bit) guest kernels in + virtual machines on E500MC/E5500 host processors. This module provides access to the hardware capabilities through a character device node named /dev/kvm. If unsure, say N. -config KVM_MPIC - bool "KVM in-kernel MPIC emulation" - depends on KVM && E500 - select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQ_ROUTING - select HAVE_KVM_MSI - help - Enable support for emulating MPIC devices inside the - host kernel, rather than relying on userspace to emulate. - Currently, support is limited to certain versions of - Freescale's MPIC implementation. - -config KVM_XICS - bool "KVM in-kernel XICS emulation" - depends on KVM_BOOK3S_64 && !KVM_MPIC - ---help--- - Include support for the XICS (eXternal Interrupt Controller - Specification) interrupt controller architecture used on - IBM POWER (pSeries) servers. - source drivers/vhost/Kconfig endif # VIRTUALIZATION diff --git a/trunk/arch/powerpc/kvm/Makefile b/trunk/arch/powerpc/kvm/Makefile index 422de3f4d46c..b772eded8c26 100644 --- a/trunk/arch/powerpc/kvm/Makefile +++ b/trunk/arch/powerpc/kvm/Makefile @@ -72,18 +72,12 @@ kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ book3s_hv.o \ book3s_hv_interrupts.o \ book3s_64_mmu_hv.o -kvm-book3s_64-builtin-xics-objs-$(CONFIG_KVM_XICS) := \ - book3s_hv_rm_xics.o kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ book3s_hv_rmhandlers.o \ book3s_hv_rm_mmu.o \ book3s_64_vio_hv.o \ book3s_hv_ras.o \ - book3s_hv_builtin.o \ - $(kvm-book3s_64-builtin-xics-objs-y) - -kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \ - book3s_xics.o + book3s_hv_builtin.o kvm-book3s_64-module-objs := \ ../../../virt/kvm/kvm_main.o \ @@ -92,7 +86,6 @@ kvm-book3s_64-module-objs := \ emulate.o \ book3s.o \ book3s_64_vio.o \ - book3s_rtas.o \ $(kvm-book3s_64-objs-y) kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-module-objs) @@ -110,9 +103,6 @@ kvm-book3s_32-objs := \ book3s_32_mmu.o kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs) -kvm-objs-$(CONFIG_KVM_MPIC) += mpic.o -kvm-objs-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(addprefix ../../../virt/kvm/, irqchip.o) - kvm-objs := $(kvm-objs-m) $(kvm-objs-y) obj-$(CONFIG_KVM_440) += kvm.o diff --git a/trunk/arch/powerpc/kvm/book3s.c b/trunk/arch/powerpc/kvm/book3s.c index 700df6f1d32c..a4b645285240 100644 --- a/trunk/arch/powerpc/kvm/book3s.c +++ b/trunk/arch/powerpc/kvm/book3s.c @@ -104,7 +104,7 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec) return prio; } -void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu, +static void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) { unsigned long old_pending = vcpu->arch.pending_exceptions; @@ -160,7 +160,8 @@ void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, kvmppc_book3s_queue_irqprio(vcpu, vec); } -void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu) +void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, + struct kvm_interrupt *irq) { kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL); @@ -529,21 +530,6 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) val = get_reg_val(reg->id, vcpu->arch.vscr.u[3]); break; #endif /* CONFIG_ALTIVEC */ - case KVM_REG_PPC_DEBUG_INST: { - u32 opcode = INS_TW; - r = copy_to_user((u32 __user *)(long)reg->addr, - &opcode, sizeof(u32)); - break; - } -#ifdef CONFIG_KVM_XICS - case KVM_REG_PPC_ICP_STATE: - if (!vcpu->arch.icp) { - r = -ENXIO; - break; - } - val = get_reg_val(reg->id, kvmppc_xics_get_icp(vcpu)); - break; -#endif /* CONFIG_KVM_XICS */ default: r = -EINVAL; break; @@ -606,16 +592,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) vcpu->arch.vscr.u[3] = set_reg_val(reg->id, val); break; #endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_KVM_XICS - case KVM_REG_PPC_ICP_STATE: - if (!vcpu->arch.icp) { - r = -ENXIO; - break; - } - r = kvmppc_xics_set_icp(vcpu, - set_reg_val(reg->id, val)); - break; -#endif /* CONFIG_KVM_XICS */ default: r = -EINVAL; break; @@ -631,12 +607,6 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, return 0; } -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, - struct kvm_guest_debug *dbg) -{ - return -EINVAL; -} - void kvmppc_decrementer_func(unsigned long data) { struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data; diff --git a/trunk/arch/powerpc/kvm/book3s_64_mmu_hv.c b/trunk/arch/powerpc/kvm/book3s_64_mmu_hv.c index 5880dfb31074..da98e26f6e45 100644 --- a/trunk/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/trunk/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -893,10 +893,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, /* Harvest R and C */ rcbits = hptep[1] & (HPTE_R_R | HPTE_R_C); *rmapp |= rcbits << KVMPPC_RMAP_RC_SHIFT; - if (rcbits & ~rev[i].guest_rpte) { - rev[i].guest_rpte = ptel | rcbits; - note_hpte_modification(kvm, &rev[i]); - } + rev[i].guest_rpte = ptel | rcbits; } unlock_rmap(rmapp); hptep[0] &= ~HPTE_V_HVLOCK; @@ -979,10 +976,7 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, /* Now check and modify the HPTE */ if ((hptep[0] & HPTE_V_VALID) && (hptep[1] & HPTE_R_R)) { kvmppc_clear_ref_hpte(kvm, hptep, i); - if (!(rev[i].guest_rpte & HPTE_R_R)) { - rev[i].guest_rpte |= HPTE_R_R; - note_hpte_modification(kvm, &rev[i]); - } + rev[i].guest_rpte |= HPTE_R_R; ret = 1; } hptep[0] &= ~HPTE_V_HVLOCK; @@ -1086,10 +1080,7 @@ static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp) hptep[1] &= ~HPTE_R_C; eieio(); hptep[0] = (hptep[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID; - if (!(rev[i].guest_rpte & HPTE_R_C)) { - rev[i].guest_rpte |= HPTE_R_C; - note_hpte_modification(kvm, &rev[i]); - } + rev[i].guest_rpte |= HPTE_R_C; ret = 1; } hptep[0] &= ~HPTE_V_HVLOCK; @@ -1099,30 +1090,11 @@ static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp) return ret; } -static void harvest_vpa_dirty(struct kvmppc_vpa *vpa, - struct kvm_memory_slot *memslot, - unsigned long *map) -{ - unsigned long gfn; - - if (!vpa->dirty || !vpa->pinned_addr) - return; - gfn = vpa->gpa >> PAGE_SHIFT; - if (gfn < memslot->base_gfn || - gfn >= memslot->base_gfn + memslot->npages) - return; - - vpa->dirty = false; - if (map) - __set_bit_le(gfn - memslot->base_gfn, map); -} - long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot, unsigned long *map) { unsigned long i; unsigned long *rmapp; - struct kvm_vcpu *vcpu; preempt_disable(); rmapp = memslot->arch.rmap; @@ -1131,15 +1103,6 @@ long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot, __set_bit_le(i, map); ++rmapp; } - - /* Harvest dirty bits from VPA and DTL updates */ - /* Note: we never modify the SLB shadow buffer areas */ - kvm_for_each_vcpu(i, vcpu, kvm) { - spin_lock(&vcpu->arch.vpa_update_lock); - harvest_vpa_dirty(&vcpu->arch.vpa, memslot, map); - harvest_vpa_dirty(&vcpu->arch.dtl, memslot, map); - spin_unlock(&vcpu->arch.vpa_update_lock); - } preempt_enable(); return 0; } @@ -1151,7 +1114,7 @@ void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long gpa, unsigned long gfn = gpa >> PAGE_SHIFT; struct page *page, *pages[1]; int npages; - unsigned long hva, offset; + unsigned long hva, psize, offset; unsigned long pa; unsigned long *physp; int srcu_idx; @@ -1183,9 +1146,14 @@ void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long gpa, } srcu_read_unlock(&kvm->srcu, srcu_idx); - offset = gpa & (PAGE_SIZE - 1); + psize = PAGE_SIZE; + if (PageHuge(page)) { + page = compound_head(page); + psize <<= compound_order(page); + } + offset = gpa & (psize - 1); if (nb_ret) - *nb_ret = PAGE_SIZE - offset; + *nb_ret = psize - offset; return page_address(page) + offset; err: @@ -1193,31 +1161,11 @@ void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long gpa, return NULL; } -void kvmppc_unpin_guest_page(struct kvm *kvm, void *va, unsigned long gpa, - bool dirty) +void kvmppc_unpin_guest_page(struct kvm *kvm, void *va) { struct page *page = virt_to_page(va); - struct kvm_memory_slot *memslot; - unsigned long gfn; - unsigned long *rmap; - int srcu_idx; put_page(page); - - if (!dirty || !kvm->arch.using_mmu_notifiers) - return; - - /* We need to mark this page dirty in the rmap chain */ - gfn = gpa >> PAGE_SHIFT; - srcu_idx = srcu_read_lock(&kvm->srcu); - memslot = gfn_to_memslot(kvm, gfn); - if (memslot) { - rmap = &memslot->arch.rmap[gfn - memslot->base_gfn]; - lock_rmap(rmap); - *rmap |= KVMPPC_RMAP_CHANGED; - unlock_rmap(rmap); - } - srcu_read_unlock(&kvm->srcu, srcu_idx); } /* @@ -1245,36 +1193,16 @@ struct kvm_htab_ctx { #define HPTE_SIZE (2 * sizeof(unsigned long)) -/* - * Returns 1 if this HPT entry has been modified or has pending - * R/C bit changes. - */ -static int hpte_dirty(struct revmap_entry *revp, unsigned long *hptp) -{ - unsigned long rcbits_unset; - - if (revp->guest_rpte & HPTE_GR_MODIFIED) - return 1; - - /* Also need to consider changes in reference and changed bits */ - rcbits_unset = ~revp->guest_rpte & (HPTE_R_R | HPTE_R_C); - if ((hptp[0] & HPTE_V_VALID) && (hptp[1] & rcbits_unset)) - return 1; - - return 0; -} - static long record_hpte(unsigned long flags, unsigned long *hptp, unsigned long *hpte, struct revmap_entry *revp, int want_valid, int first_pass) { unsigned long v, r; - unsigned long rcbits_unset; int ok = 1; int valid, dirty; /* Unmodified entries are uninteresting except on the first pass */ - dirty = hpte_dirty(revp, hptp); + dirty = !!(revp->guest_rpte & HPTE_GR_MODIFIED); if (!first_pass && !dirty) return 0; @@ -1295,28 +1223,16 @@ static long record_hpte(unsigned long flags, unsigned long *hptp, while (!try_lock_hpte(hptp, HPTE_V_HVLOCK)) cpu_relax(); v = hptp[0]; - - /* re-evaluate valid and dirty from synchronized HPTE value */ - valid = !!(v & HPTE_V_VALID); - dirty = !!(revp->guest_rpte & HPTE_GR_MODIFIED); - - /* Harvest R and C into guest view if necessary */ - rcbits_unset = ~revp->guest_rpte & (HPTE_R_R | HPTE_R_C); - if (valid && (rcbits_unset & hptp[1])) { - revp->guest_rpte |= (hptp[1] & (HPTE_R_R | HPTE_R_C)) | - HPTE_GR_MODIFIED; - dirty = 1; - } - if (v & HPTE_V_ABSENT) { v &= ~HPTE_V_ABSENT; v |= HPTE_V_VALID; - valid = 1; } + /* re-evaluate valid and dirty from synchronized HPTE value */ + valid = !!(v & HPTE_V_VALID); if ((flags & KVM_GET_HTAB_BOLTED_ONLY) && !(v & HPTE_V_BOLTED)) valid = 0; - - r = revp->guest_rpte; + r = revp->guest_rpte | (hptp[1] & (HPTE_R_R | HPTE_R_C)); + dirty = !!(revp->guest_rpte & HPTE_GR_MODIFIED); /* only clear modified if this is the right sort of entry */ if (valid == want_valid && dirty) { r &= ~HPTE_GR_MODIFIED; @@ -1372,7 +1288,7 @@ static ssize_t kvm_htab_read(struct file *file, char __user *buf, /* Skip uninteresting entries, i.e. clean on not-first pass */ if (!first_pass) { while (i < kvm->arch.hpt_npte && - !hpte_dirty(revp, hptp)) { + !(revp->guest_rpte & HPTE_GR_MODIFIED)) { ++i; hptp += 2; ++revp; diff --git a/trunk/arch/powerpc/kvm/book3s_emulate.c b/trunk/arch/powerpc/kvm/book3s_emulate.c index 1f6344c4408d..836c56975e21 100644 --- a/trunk/arch/powerpc/kvm/book3s_emulate.c +++ b/trunk/arch/powerpc/kvm/book3s_emulate.c @@ -194,9 +194,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, run->papr_hcall.args[i] = gpr; } - run->exit_reason = KVM_EXIT_PAPR_HCALL; - vcpu->arch.hcall_needed = 1; - emulated = EMULATE_EXIT_USER; + emulated = EMULATE_DO_PAPR; break; } #endif diff --git a/trunk/arch/powerpc/kvm/book3s_hv.c b/trunk/arch/powerpc/kvm/book3s_hv.c index 9de24f8e03c7..f5416934932b 100644 --- a/trunk/arch/powerpc/kvm/book3s_hv.c +++ b/trunk/arch/powerpc/kvm/book3s_hv.c @@ -66,31 +66,6 @@ static void kvmppc_end_cede(struct kvm_vcpu *vcpu); static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu); -void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu) -{ - int me; - int cpu = vcpu->cpu; - wait_queue_head_t *wqp; - - wqp = kvm_arch_vcpu_wq(vcpu); - if (waitqueue_active(wqp)) { - wake_up_interruptible(wqp); - ++vcpu->stat.halt_wakeup; - } - - me = get_cpu(); - - /* CPU points to the first thread of the core */ - if (cpu != me && cpu >= 0 && cpu < nr_cpu_ids) { - int real_cpu = cpu + vcpu->arch.ptid; - if (paca[real_cpu].kvm_hstate.xics_phys) - xics_wake_cpu(real_cpu); - else if (cpu_online(cpu)) - smp_send_reschedule(cpu); - } - put_cpu(); -} - /* * We use the vcpu_load/put functions to measure stolen time. * Stolen time is counted as time when either the vcpu is able to @@ -284,7 +259,7 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu, len = ((struct reg_vpa *)va)->length.hword; else len = ((struct reg_vpa *)va)->length.word; - kvmppc_unpin_guest_page(kvm, va, vpa, false); + kvmppc_unpin_guest_page(kvm, va); /* Check length */ if (len > nb || len < sizeof(struct reg_vpa)) @@ -384,13 +359,13 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) va = NULL; nb = 0; if (gpa) - va = kvmppc_pin_guest_page(kvm, gpa, &nb); + va = kvmppc_pin_guest_page(kvm, vpap->next_gpa, &nb); spin_lock(&vcpu->arch.vpa_update_lock); if (gpa == vpap->next_gpa) break; /* sigh... unpin that one and try again */ if (va) - kvmppc_unpin_guest_page(kvm, va, gpa, false); + kvmppc_unpin_guest_page(kvm, va); } vpap->update_pending = 0; @@ -400,15 +375,12 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) * has changed the mappings underlying guest memory, * so unregister the region. */ - kvmppc_unpin_guest_page(kvm, va, gpa, false); + kvmppc_unpin_guest_page(kvm, va); va = NULL; } if (vpap->pinned_addr) - kvmppc_unpin_guest_page(kvm, vpap->pinned_addr, vpap->gpa, - vpap->dirty); - vpap->gpa = gpa; + kvmppc_unpin_guest_page(kvm, vpap->pinned_addr); vpap->pinned_addr = va; - vpap->dirty = false; if (va) vpap->pinned_end = va + vpap->len; } @@ -500,7 +472,6 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu, /* order writing *dt vs. writing vpa->dtl_idx */ smp_wmb(); vpa->dtl_idx = ++vcpu->arch.dtl_index; - vcpu->arch.dtl.dirty = true; } int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) @@ -508,7 +479,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) unsigned long req = kvmppc_get_gpr(vcpu, 3); unsigned long target, ret = H_SUCCESS; struct kvm_vcpu *tvcpu; - int idx, rc; + int idx; switch (req) { case H_ENTER: @@ -544,28 +515,6 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) kvmppc_get_gpr(vcpu, 5), kvmppc_get_gpr(vcpu, 6)); break; - case H_RTAS: - if (list_empty(&vcpu->kvm->arch.rtas_tokens)) - return RESUME_HOST; - - rc = kvmppc_rtas_hcall(vcpu); - - if (rc == -ENOENT) - return RESUME_HOST; - else if (rc == 0) - break; - - /* Send the error out to userspace via KVM_RUN */ - return rc; - - case H_XIRR: - case H_CPPR: - case H_EOI: - case H_IPI: - if (kvmppc_xics_enabled(vcpu)) { - ret = kvmppc_xics_hcall(vcpu, req); - break; - } /* fallthrough */ default: return RESUME_HOST; } @@ -964,19 +913,15 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) return ERR_PTR(err); } -static void unpin_vpa(struct kvm *kvm, struct kvmppc_vpa *vpa) -{ - if (vpa->pinned_addr) - kvmppc_unpin_guest_page(kvm, vpa->pinned_addr, vpa->gpa, - vpa->dirty); -} - void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) { spin_lock(&vcpu->arch.vpa_update_lock); - unpin_vpa(vcpu->kvm, &vcpu->arch.dtl); - unpin_vpa(vcpu->kvm, &vcpu->arch.slb_shadow); - unpin_vpa(vcpu->kvm, &vcpu->arch.vpa); + if (vcpu->arch.dtl.pinned_addr) + kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.dtl.pinned_addr); + if (vcpu->arch.slb_shadow.pinned_addr) + kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.slb_shadow.pinned_addr); + if (vcpu->arch.vpa.pinned_addr) + kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.vpa.pinned_addr); spin_unlock(&vcpu->arch.vpa_update_lock); kvm_vcpu_uninit(vcpu); kmem_cache_free(kvm_vcpu_cache, vcpu); @@ -1010,6 +955,7 @@ static void kvmppc_end_cede(struct kvm_vcpu *vcpu) } extern int __kvmppc_vcore_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); +extern void xics_wake_cpu(int cpu); static void kvmppc_remove_runnable(struct kvmppc_vcore *vc, struct kvm_vcpu *vcpu) @@ -1384,12 +1330,9 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) break; vc->runner = vcpu; n_ceded = 0; - list_for_each_entry(v, &vc->runnable_threads, arch.run_list) { + list_for_each_entry(v, &vc->runnable_threads, arch.run_list) if (!v->arch.pending_exceptions) n_ceded += v->arch.ceded; - else - v->arch.ceded = 0; - } if (n_ceded == vc->n_runnable) kvmppc_vcore_blocked(vc); else @@ -1702,12 +1645,12 @@ int kvmppc_core_prepare_memory_region(struct kvm *kvm, void kvmppc_core_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old) + struct kvm_memory_slot old) { unsigned long npages = mem->memory_size >> PAGE_SHIFT; struct kvm_memory_slot *memslot; - if (npages && old->npages) { + if (npages && old.npages) { /* * If modifying a memslot, reset all the rmap dirty bits. * If this is a new memslot, we don't need to do anything @@ -1884,7 +1827,6 @@ int kvmppc_core_init_vm(struct kvm *kvm) cpumask_setall(&kvm->arch.need_tlb_flush); INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables); - INIT_LIST_HEAD(&kvm->arch.rtas_tokens); kvm->arch.rma = NULL; @@ -1930,8 +1872,6 @@ void kvmppc_core_destroy_vm(struct kvm *kvm) kvm->arch.rma = NULL; } - kvmppc_rtas_tokens_free(kvm); - kvmppc_free_hpt(kvm); WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables)); } diff --git a/trunk/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/trunk/arch/powerpc/kvm/book3s_hv_rm_mmu.c index 6dcbb49105a4..19c93bae1aea 100644 --- a/trunk/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/trunk/arch/powerpc/kvm/book3s_hv_rm_mmu.c @@ -97,6 +97,17 @@ void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev, } EXPORT_SYMBOL_GPL(kvmppc_add_revmap_chain); +/* + * Note modification of an HPTE; set the HPTE modified bit + * if anyone is interested. + */ +static inline void note_hpte_modification(struct kvm *kvm, + struct revmap_entry *rev) +{ + if (atomic_read(&kvm->arch.hpte_mod_interest)) + rev->guest_rpte |= HPTE_GR_MODIFIED; +} + /* Remove this HPTE from the chain for a real page */ static void remove_revmap_chain(struct kvm *kvm, long pte_index, struct revmap_entry *rev, diff --git a/trunk/arch/powerpc/kvm/book3s_hv_rm_xics.c b/trunk/arch/powerpc/kvm/book3s_hv_rm_xics.c deleted file mode 100644 index b4b0082f761c..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright 2012 Michael Ellerman, IBM Corporation. - * Copyright 2012 Benjamin Herrenschmidt, IBM 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 -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "book3s_xics.h" - -#define DEBUG_PASSUP - -static inline void rm_writeb(unsigned long paddr, u8 val) -{ - __asm__ __volatile__("sync; stbcix %0,0,%1" - : : "r" (val), "r" (paddr) : "memory"); -} - -static void icp_rm_set_vcpu_irq(struct kvm_vcpu *vcpu, - struct kvm_vcpu *this_vcpu) -{ - struct kvmppc_icp *this_icp = this_vcpu->arch.icp; - unsigned long xics_phys; - int cpu; - - /* Mark the target VCPU as having an interrupt pending */ - vcpu->stat.queue_intr++; - set_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions); - - /* Kick self ? Just set MER and return */ - if (vcpu == this_vcpu) { - mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_MER); - return; - } - - /* Check if the core is loaded, if not, too hard */ - cpu = vcpu->cpu; - if (cpu < 0 || cpu >= nr_cpu_ids) { - this_icp->rm_action |= XICS_RM_KICK_VCPU; - this_icp->rm_kick_target = vcpu; - return; - } - /* In SMT cpu will always point to thread 0, we adjust it */ - cpu += vcpu->arch.ptid; - - /* Not too hard, then poke the target */ - xics_phys = paca[cpu].kvm_hstate.xics_phys; - rm_writeb(xics_phys + XICS_MFRR, IPI_PRIORITY); -} - -static void icp_rm_clr_vcpu_irq(struct kvm_vcpu *vcpu) -{ - /* Note: Only called on self ! */ - clear_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, - &vcpu->arch.pending_exceptions); - mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~LPCR_MER); -} - -static inline bool icp_rm_try_update(struct kvmppc_icp *icp, - union kvmppc_icp_state old, - union kvmppc_icp_state new) -{ - struct kvm_vcpu *this_vcpu = local_paca->kvm_hstate.kvm_vcpu; - bool success; - - /* Calculate new output value */ - new.out_ee = (new.xisr && (new.pending_pri < new.cppr)); - - /* Attempt atomic update */ - success = cmpxchg64(&icp->state.raw, old.raw, new.raw) == old.raw; - if (!success) - goto bail; - - /* - * Check for output state update - * - * Note that this is racy since another processor could be updating - * the state already. This is why we never clear the interrupt output - * here, we only ever set it. The clear only happens prior to doing - * an update and only by the processor itself. Currently we do it - * in Accept (H_XIRR) and Up_Cppr (H_XPPR). - * - * We also do not try to figure out whether the EE state has changed, - * we unconditionally set it if the new state calls for it. The reason - * for that is that we opportunistically remove the pending interrupt - * flag when raising CPPR, so we need to set it back here if an - * interrupt is still pending. - */ - if (new.out_ee) - icp_rm_set_vcpu_irq(icp->vcpu, this_vcpu); - - /* Expose the state change for debug purposes */ - this_vcpu->arch.icp->rm_dbgstate = new; - this_vcpu->arch.icp->rm_dbgtgt = icp->vcpu; - - bail: - return success; -} - -static inline int check_too_hard(struct kvmppc_xics *xics, - struct kvmppc_icp *icp) -{ - return (xics->real_mode_dbg || icp->rm_action) ? H_TOO_HARD : H_SUCCESS; -} - -static void icp_rm_down_cppr(struct kvmppc_xics *xics, struct kvmppc_icp *icp, - u8 new_cppr) -{ - union kvmppc_icp_state old_state, new_state; - bool resend; - - /* - * This handles several related states in one operation: - * - * ICP State: Down_CPPR - * - * Load CPPR with new value and if the XISR is 0 - * then check for resends: - * - * ICP State: Resend - * - * If MFRR is more favored than CPPR, check for IPIs - * and notify ICS of a potential resend. This is done - * asynchronously (when used in real mode, we will have - * to exit here). - * - * We do not handle the complete Check_IPI as documented - * here. In the PAPR, this state will be used for both - * Set_MFRR and Down_CPPR. However, we know that we aren't - * changing the MFRR state here so we don't need to handle - * the case of an MFRR causing a reject of a pending irq, - * this will have been handled when the MFRR was set in the - * first place. - * - * Thus we don't have to handle rejects, only resends. - * - * When implementing real mode for HV KVM, resend will lead to - * a H_TOO_HARD return and the whole transaction will be handled - * in virtual mode. - */ - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - /* Down_CPPR */ - new_state.cppr = new_cppr; - - /* - * Cut down Resend / Check_IPI / IPI - * - * The logic is that we cannot have a pending interrupt - * trumped by an IPI at this point (see above), so we - * know that either the pending interrupt is already an - * IPI (in which case we don't care to override it) or - * it's either more favored than us or non existent - */ - if (new_state.mfrr < new_cppr && - new_state.mfrr <= new_state.pending_pri) { - new_state.pending_pri = new_state.mfrr; - new_state.xisr = XICS_IPI; - } - - /* Latch/clear resend bit */ - resend = new_state.need_resend; - new_state.need_resend = 0; - - } while (!icp_rm_try_update(icp, old_state, new_state)); - - /* - * Now handle resend checks. Those are asynchronous to the ICP - * state update in HW (ie bus transactions) so we can handle them - * separately here as well. - */ - if (resend) - icp->rm_action |= XICS_RM_CHECK_RESEND; -} - - -unsigned long kvmppc_rm_h_xirr(struct kvm_vcpu *vcpu) -{ - union kvmppc_icp_state old_state, new_state; - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - struct kvmppc_icp *icp = vcpu->arch.icp; - u32 xirr; - - if (!xics || !xics->real_mode) - return H_TOO_HARD; - - /* First clear the interrupt */ - icp_rm_clr_vcpu_irq(icp->vcpu); - - /* - * ICP State: Accept_Interrupt - * - * Return the pending interrupt (if any) along with the - * current CPPR, then clear the XISR & set CPPR to the - * pending priority - */ - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - xirr = old_state.xisr | (((u32)old_state.cppr) << 24); - if (!old_state.xisr) - break; - new_state.cppr = new_state.pending_pri; - new_state.pending_pri = 0xff; - new_state.xisr = 0; - - } while (!icp_rm_try_update(icp, old_state, new_state)); - - /* Return the result in GPR4 */ - vcpu->arch.gpr[4] = xirr; - - return check_too_hard(xics, icp); -} - -int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, - unsigned long mfrr) -{ - union kvmppc_icp_state old_state, new_state; - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - struct kvmppc_icp *icp, *this_icp = vcpu->arch.icp; - u32 reject; - bool resend; - bool local; - - if (!xics || !xics->real_mode) - return H_TOO_HARD; - - local = this_icp->server_num == server; - if (local) - icp = this_icp; - else - icp = kvmppc_xics_find_server(vcpu->kvm, server); - if (!icp) - return H_PARAMETER; - - /* - * ICP state: Set_MFRR - * - * If the CPPR is more favored than the new MFRR, then - * nothing needs to be done as there can be no XISR to - * reject. - * - * If the CPPR is less favored, then we might be replacing - * an interrupt, and thus need to possibly reject it as in - * - * ICP state: Check_IPI - */ - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - /* Set_MFRR */ - new_state.mfrr = mfrr; - - /* Check_IPI */ - reject = 0; - resend = false; - if (mfrr < new_state.cppr) { - /* Reject a pending interrupt if not an IPI */ - if (mfrr <= new_state.pending_pri) - reject = new_state.xisr; - new_state.pending_pri = mfrr; - new_state.xisr = XICS_IPI; - } - - if (mfrr > old_state.mfrr && mfrr > new_state.cppr) { - resend = new_state.need_resend; - new_state.need_resend = 0; - } - } while (!icp_rm_try_update(icp, old_state, new_state)); - - /* Pass rejects to virtual mode */ - if (reject && reject != XICS_IPI) { - this_icp->rm_action |= XICS_RM_REJECT; - this_icp->rm_reject = reject; - } - - /* Pass resends to virtual mode */ - if (resend) - this_icp->rm_action |= XICS_RM_CHECK_RESEND; - - return check_too_hard(xics, this_icp); -} - -int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr) -{ - union kvmppc_icp_state old_state, new_state; - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - struct kvmppc_icp *icp = vcpu->arch.icp; - u32 reject; - - if (!xics || !xics->real_mode) - return H_TOO_HARD; - - /* - * ICP State: Set_CPPR - * - * We can safely compare the new value with the current - * value outside of the transaction as the CPPR is only - * ever changed by the processor on itself - */ - if (cppr > icp->state.cppr) { - icp_rm_down_cppr(xics, icp, cppr); - goto bail; - } else if (cppr == icp->state.cppr) - return H_SUCCESS; - - /* - * ICP State: Up_CPPR - * - * The processor is raising its priority, this can result - * in a rejection of a pending interrupt: - * - * ICP State: Reject_Current - * - * We can remove EE from the current processor, the update - * transaction will set it again if needed - */ - icp_rm_clr_vcpu_irq(icp->vcpu); - - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - reject = 0; - new_state.cppr = cppr; - - if (cppr <= new_state.pending_pri) { - reject = new_state.xisr; - new_state.xisr = 0; - new_state.pending_pri = 0xff; - } - - } while (!icp_rm_try_update(icp, old_state, new_state)); - - /* Pass rejects to virtual mode */ - if (reject && reject != XICS_IPI) { - icp->rm_action |= XICS_RM_REJECT; - icp->rm_reject = reject; - } - bail: - return check_too_hard(xics, icp); -} - -int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) -{ - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - struct kvmppc_icp *icp = vcpu->arch.icp; - struct kvmppc_ics *ics; - struct ics_irq_state *state; - u32 irq = xirr & 0x00ffffff; - u16 src; - - if (!xics || !xics->real_mode) - return H_TOO_HARD; - - /* - * ICP State: EOI - * - * Note: If EOI is incorrectly used by SW to lower the CPPR - * value (ie more favored), we do not check for rejection of - * a pending interrupt, this is a SW error and PAPR sepcifies - * that we don't have to deal with it. - * - * The sending of an EOI to the ICS is handled after the - * CPPR update - * - * ICP State: Down_CPPR which we handle - * in a separate function as it's shared with H_CPPR. - */ - icp_rm_down_cppr(xics, icp, xirr >> 24); - - /* IPIs have no EOI */ - if (irq == XICS_IPI) - goto bail; - /* - * EOI handling: If the interrupt is still asserted, we need to - * resend it. We can take a lockless "peek" at the ICS state here. - * - * "Message" interrupts will never have "asserted" set - */ - ics = kvmppc_xics_find_ics(xics, irq, &src); - if (!ics) - goto bail; - state = &ics->irq_state[src]; - - /* Still asserted, resend it, we make it look like a reject */ - if (state->asserted) { - icp->rm_action |= XICS_RM_REJECT; - icp->rm_reject = irq; - } - bail: - return check_too_hard(xics, icp); -} diff --git a/trunk/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/trunk/arch/powerpc/kvm/book3s_hv_rmhandlers.S index b02f91e4c70d..e33d11f1b977 100644 --- a/trunk/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/trunk/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -79,6 +79,10 @@ _GLOBAL(kvmppc_hv_entry_trampoline) * * *****************************************************************************/ +#define XICS_XIRR 4 +#define XICS_QIRR 0xc +#define XICS_IPI 2 /* interrupt source # for IPIs */ + /* * We come in here when wakened from nap mode on a secondary hw thread. * Relocation is off and most register values are lost. @@ -97,51 +101,50 @@ kvm_start_guest: li r0,1 stb r0,PACA_NAPSTATELOST(r13) - /* were we napping due to cede? */ - lbz r0,HSTATE_NAPPING(r13) - cmpwi r0,0 - bne kvm_end_cede - - /* - * We weren't napping due to cede, so this must be a secondary - * thread being woken up to run a guest, or being woken up due - * to a stray IPI. (Or due to some machine check or hypervisor - * maintenance interrupt while the core is in KVM.) - */ + /* get vcpu pointer, NULL if we have no vcpu to run */ + ld r4,HSTATE_KVM_VCPU(r13) + cmpdi cr1,r4,0 /* Check the wake reason in SRR1 to see why we got here */ mfspr r3,SPRN_SRR1 rlwinm r3,r3,44-31,0x7 /* extract wake reason field */ cmpwi r3,4 /* was it an external interrupt? */ - bne 27f /* if not */ - ld r5,HSTATE_XICS_PHYS(r13) - li r7,XICS_XIRR /* if it was an external interrupt, */ + bne 27f + + /* + * External interrupt - for now assume it is an IPI, since we + * should never get any other interrupts sent to offline threads. + * Only do this for secondary threads. + */ + beq cr1,25f + lwz r3,VCPU_PTID(r4) + cmpwi r3,0 + beq 27f +25: ld r5,HSTATE_XICS_PHYS(r13) + li r0,0xff + li r6,XICS_QIRR + li r7,XICS_XIRR lwzcix r8,r5,r7 /* get and ack the interrupt */ sync clrldi. r9,r8,40 /* get interrupt source ID. */ - beq 28f /* none there? */ - cmpwi r9,XICS_IPI /* was it an IPI? */ - bne 29f - li r0,0xff - li r6,XICS_MFRR + beq 27f /* none there? */ + cmpwi r9,XICS_IPI + bne 26f stbcix r0,r5,r6 /* clear IPI */ - stwcix r8,r5,r7 /* EOI the interrupt */ - sync /* order loading of vcpu after that */ +26: stwcix r8,r5,r7 /* EOI the interrupt */ - /* get vcpu pointer, NULL if we have no vcpu to run */ +27: /* XXX should handle hypervisor maintenance interrupts etc. here */ + + /* reload vcpu pointer after clearing the IPI */ ld r4,HSTATE_KVM_VCPU(r13) cmpdi r4,0 /* if we have no vcpu to run, go back to sleep */ beq kvm_no_guest - b kvmppc_hv_entry -27: /* XXX should handle hypervisor maintenance interrupts etc. here */ - b kvm_no_guest -28: /* SRR1 said external but ICP said nope?? */ - b kvm_no_guest -29: /* External non-IPI interrupt to offline secondary thread? help?? */ - stw r8,HSTATE_SAVED_XIRR(r13) - b kvm_no_guest + /* were we napping due to cede? */ + lbz r0,HSTATE_NAPPING(r13) + cmpwi r0,0 + bne kvm_end_cede .global kvmppc_hv_entry kvmppc_hv_entry: @@ -257,8 +260,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) lwz r5, LPPACA_YIELDCOUNT(r3) addi r5, r5, 1 stw r5, LPPACA_YIELDCOUNT(r3) - li r6, 1 - stb r6, VCPU_VPA_DIRTY(r4) 25: /* Load up DAR and DSISR */ ld r5, VCPU_DAR(r4) @@ -484,20 +485,20 @@ toc_tlbie_lock: mtctr r6 mtxer r7 - ld r10, VCPU_PC(r4) - ld r11, VCPU_MSR(r4) kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ ld r6, VCPU_SRR0(r4) ld r7, VCPU_SRR1(r4) + ld r10, VCPU_PC(r4) + ld r11, VCPU_MSR(r4) /* r11 = vcpu->arch.msr & ~MSR_HV */ - /* r11 = vcpu->arch.msr & ~MSR_HV */ rldicl r11, r11, 63 - MSR_HV_LG, 1 rotldi r11, r11, 1 + MSR_HV_LG ori r11, r11, MSR_ME /* Check if we can deliver an external or decrementer interrupt now */ ld r0,VCPU_PENDING_EXC(r4) - lis r8,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h + li r8,(1 << BOOK3S_IRQPRIO_EXTERNAL) + oris r8,r8,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h and r0,r0,r8 cmpdi cr1,r0,0 andi. r0,r11,MSR_EE @@ -525,10 +526,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) /* Move SRR0 and SRR1 into the respective regs */ 5: mtspr SPRN_SRR0, r6 mtspr SPRN_SRR1, r7 - -fast_guest_return: li r0,0 stb r0,VCPU_CEDED(r4) /* cancel cede */ + +fast_guest_return: mtspr SPRN_HSRR0,r10 mtspr SPRN_HSRR1,r11 @@ -675,99 +676,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) cmpwi r12,BOOK3S_INTERRUPT_SYSCALL beq hcall_try_real_mode - /* Only handle external interrupts here on arch 206 and later */ + /* Check for mediated interrupts (could be done earlier really ...) */ BEGIN_FTR_SECTION - b ext_interrupt_to_host -END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) - - /* External interrupt ? */ - cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL - bne+ ext_interrupt_to_host - - /* External interrupt, first check for host_ipi. If this is - * set, we know the host wants us out so let's do it now - */ -do_ext_interrupt: - lbz r0, HSTATE_HOST_IPI(r13) - cmpwi r0, 0 - bne ext_interrupt_to_host - - /* Now read the interrupt from the ICP */ - ld r5, HSTATE_XICS_PHYS(r13) - li r7, XICS_XIRR - cmpdi r5, 0 - beq- ext_interrupt_to_host - lwzcix r3, r5, r7 - rlwinm. r0, r3, 0, 0xffffff - sync - beq 3f /* if nothing pending in the ICP */ - - /* We found something in the ICP... - * - * If it's not an IPI, stash it in the PACA and return to - * the host, we don't (yet) handle directing real external - * interrupts directly to the guest - */ - cmpwi r0, XICS_IPI - bne ext_stash_for_host - - /* It's an IPI, clear the MFRR and EOI it */ - li r0, 0xff - li r6, XICS_MFRR - stbcix r0, r5, r6 /* clear the IPI */ - stwcix r3, r5, r7 /* EOI it */ - sync - - /* We need to re-check host IPI now in case it got set in the - * meantime. If it's clear, we bounce the interrupt to the - * guest - */ - lbz r0, HSTATE_HOST_IPI(r13) - cmpwi r0, 0 - bne- 1f - - /* Allright, looks like an IPI for the guest, we need to set MER */ -3: - /* Check if any CPU is heading out to the host, if so head out too */ - ld r5, HSTATE_KVM_VCORE(r13) - lwz r0, VCORE_ENTRY_EXIT(r5) - cmpwi r0, 0x100 - bge ext_interrupt_to_host - - /* See if there is a pending interrupt for the guest */ - mfspr r8, SPRN_LPCR - ld r0, VCPU_PENDING_EXC(r9) - /* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */ - rldicl. r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63 - rldimi r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH - beq 2f - - /* And if the guest EE is set, we can deliver immediately, else - * we return to the guest with MER set - */ - andi. r0, r11, MSR_EE - beq 2f - mtspr SPRN_SRR0, r10 - mtspr SPRN_SRR1, r11 - li r10, BOOK3S_INTERRUPT_EXTERNAL - li r11, (MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ - rotldi r11, r11, 63 -2: mr r4, r9 - mtspr SPRN_LPCR, r8 - b fast_guest_return - - /* We raced with the host, we need to resend that IPI, bummer */ -1: li r0, IPI_PRIORITY - stbcix r0, r5, r6 /* set the IPI */ - sync - b ext_interrupt_to_host - -ext_stash_for_host: - /* It's not an IPI and it's for the host, stash it in the PACA - * before exit, it will be picked up by the host ICP driver - */ - stw r3, HSTATE_SAVED_XIRR(r13) -ext_interrupt_to_host: + cmpwi r12,BOOK3S_INTERRUPT_EXTERNAL + bne+ 1f + andi. r0,r11,MSR_EE + beq 1f + mfspr r5,SPRN_LPCR + andi. r0,r5,LPCR_MER + bne bounce_ext_interrupt +1: +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ /* Save DEC */ @@ -910,7 +829,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) beq 44f ld r8,HSTATE_XICS_PHYS(r6) /* get thread's XICS reg addr */ li r0,IPI_PRIORITY - li r7,XICS_MFRR + li r7,XICS_QIRR stbcix r0,r7,r8 /* trigger the IPI */ 44: srdi. r3,r3,1 addi r6,r6,PACA_SIZE @@ -1099,8 +1018,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) lwz r3, LPPACA_YIELDCOUNT(r8) addi r3, r3, 1 stw r3, LPPACA_YIELDCOUNT(r8) - li r3, 1 - stb r3, VCPU_VPA_DIRTY(r9) 25: /* Save PMU registers if requested */ /* r8 and cr0.eq are live here */ @@ -1433,19 +1350,11 @@ hcall_real_table: .long 0 /* 0x58 */ .long 0 /* 0x5c */ .long 0 /* 0x60 */ -#ifdef CONFIG_KVM_XICS - .long .kvmppc_rm_h_eoi - hcall_real_table - .long .kvmppc_rm_h_cppr - hcall_real_table - .long .kvmppc_rm_h_ipi - hcall_real_table - .long 0 /* 0x70 - H_IPOLL */ - .long .kvmppc_rm_h_xirr - hcall_real_table -#else - .long 0 /* 0x64 - H_EOI */ - .long 0 /* 0x68 - H_CPPR */ - .long 0 /* 0x6c - H_IPI */ - .long 0 /* 0x70 - H_IPOLL */ - .long 0 /* 0x74 - H_XIRR */ -#endif + .long 0 /* 0x64 */ + .long 0 /* 0x68 */ + .long 0 /* 0x6c */ + .long 0 /* 0x70 */ + .long 0 /* 0x74 */ .long 0 /* 0x78 */ .long 0 /* 0x7c */ .long 0 /* 0x80 */ @@ -1496,6 +1405,15 @@ ignore_hdec: mr r4,r9 b fast_guest_return +bounce_ext_interrupt: + mr r4,r9 + mtspr SPRN_SRR0,r10 + mtspr SPRN_SRR1,r11 + li r10,BOOK3S_INTERRUPT_EXTERNAL + li r11,(MSR_ME << 1) | 1 /* synthesize MSR_SF | MSR_ME */ + rotldi r11,r11,63 + b fast_guest_return + _GLOBAL(kvmppc_h_set_dabr) std r4,VCPU_DABR(r3) /* Work around P7 bug where DABR can get corrupted on mtspr */ @@ -1601,9 +1519,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) b . kvm_end_cede: - /* get vcpu pointer */ - ld r4, HSTATE_KVM_VCPU(r13) - /* Woken by external or decrementer interrupt */ ld r1, HSTATE_HOST_R1(r13) @@ -1643,16 +1558,6 @@ kvm_end_cede: li r0,0 stb r0,HSTATE_NAPPING(r13) - /* Check the wake reason in SRR1 to see why we got here */ - mfspr r3, SPRN_SRR1 - rlwinm r3, r3, 44-31, 0x7 /* extract wake reason field */ - cmpwi r3, 4 /* was it an external interrupt? */ - li r12, BOOK3S_INTERRUPT_EXTERNAL - mr r9, r4 - ld r10, VCPU_PC(r9) - ld r11, VCPU_MSR(r9) - beq do_ext_interrupt /* if so */ - /* see if any other thread is already exiting */ lwz r0,VCORE_ENTRY_EXIT(r5) cmpwi r0,0x100 @@ -1672,7 +1577,8 @@ kvm_cede_prodded: /* we've ceded but we want to give control to the host */ kvm_cede_exit: - b hcall_real_fallback + li r3,H_TOO_HARD + blr /* Try to handle a machine check in real mode */ machine_check_realmode: @@ -1720,7 +1626,7 @@ secondary_nap: beq 37f sync li r0, 0xff - li r6, XICS_MFRR + li r6, XICS_QIRR stbcix r0, r5, r6 /* clear the IPI */ stwcix r3, r5, r7 /* EOI it */ 37: sync diff --git a/trunk/arch/powerpc/kvm/book3s_pr.c b/trunk/arch/powerpc/kvm/book3s_pr.c index bdc40b8e77d9..dbdc15aa8127 100644 --- a/trunk/arch/powerpc/kvm/book3s_pr.c +++ b/trunk/arch/powerpc/kvm/book3s_pr.c @@ -762,7 +762,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, run->exit_reason = KVM_EXIT_MMIO; r = RESUME_HOST_NV; break; - case EMULATE_EXIT_USER: + case EMULATE_DO_PAPR: + run->exit_reason = KVM_EXIT_PAPR_HCALL; + vcpu->arch.hcall_needed = 1; r = RESUME_HOST_NV; break; default: @@ -1281,7 +1283,7 @@ int kvmppc_core_prepare_memory_region(struct kvm *kvm, void kvmppc_core_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old) + struct kvm_memory_slot old) { } @@ -1296,7 +1298,6 @@ int kvmppc_core_init_vm(struct kvm *kvm) { #ifdef CONFIG_PPC64 INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables); - INIT_LIST_HEAD(&kvm->arch.rtas_tokens); #endif if (firmware_has_feature(FW_FEATURE_SET_MODE)) { diff --git a/trunk/arch/powerpc/kvm/book3s_pr_papr.c b/trunk/arch/powerpc/kvm/book3s_pr_papr.c index b24309c6c2d5..ee02b30878ed 100644 --- a/trunk/arch/powerpc/kvm/book3s_pr_papr.c +++ b/trunk/arch/powerpc/kvm/book3s_pr_papr.c @@ -227,13 +227,6 @@ static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu) return EMULATE_DONE; } -static int kvmppc_h_pr_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd) -{ - long rc = kvmppc_xics_hcall(vcpu, cmd); - kvmppc_set_gpr(vcpu, 3, rc); - return EMULATE_DONE; -} - int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) { switch (cmd) { @@ -253,20 +246,6 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) clear_bit(KVM_REQ_UNHALT, &vcpu->requests); vcpu->stat.halt_wakeup++; return EMULATE_DONE; - case H_XIRR: - case H_CPPR: - case H_EOI: - case H_IPI: - if (kvmppc_xics_enabled(vcpu)) - return kvmppc_h_pr_xics_hcall(vcpu, cmd); - break; - case H_RTAS: - if (list_empty(&vcpu->kvm->arch.rtas_tokens)) - return RESUME_HOST; - if (kvmppc_rtas_hcall(vcpu)) - break; - kvmppc_set_gpr(vcpu, 3, 0); - return EMULATE_DONE; } return EMULATE_FAIL; diff --git a/trunk/arch/powerpc/kvm/book3s_rtas.c b/trunk/arch/powerpc/kvm/book3s_rtas.c deleted file mode 100644 index 3219ba895246..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_rtas.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2012 Michael Ellerman, IBM 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 -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef CONFIG_KVM_XICS -static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args) -{ - u32 irq, server, priority; - int rc; - - if (args->nargs != 3 || args->nret != 1) { - rc = -3; - goto out; - } - - irq = args->args[0]; - server = args->args[1]; - priority = args->args[2]; - - rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority); - if (rc) - rc = -3; -out: - args->rets[0] = rc; -} - -static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args) -{ - u32 irq, server, priority; - int rc; - - if (args->nargs != 1 || args->nret != 3) { - rc = -3; - goto out; - } - - irq = args->args[0]; - - server = priority = 0; - rc = kvmppc_xics_get_xive(vcpu->kvm, irq, &server, &priority); - if (rc) { - rc = -3; - goto out; - } - - args->rets[1] = server; - args->rets[2] = priority; -out: - args->rets[0] = rc; -} - -static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args) -{ - u32 irq; - int rc; - - if (args->nargs != 1 || args->nret != 1) { - rc = -3; - goto out; - } - - irq = args->args[0]; - - rc = kvmppc_xics_int_off(vcpu->kvm, irq); - if (rc) - rc = -3; -out: - args->rets[0] = rc; -} - -static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args) -{ - u32 irq; - int rc; - - if (args->nargs != 1 || args->nret != 1) { - rc = -3; - goto out; - } - - irq = args->args[0]; - - rc = kvmppc_xics_int_on(vcpu->kvm, irq); - if (rc) - rc = -3; -out: - args->rets[0] = rc; -} -#endif /* CONFIG_KVM_XICS */ - -struct rtas_handler { - void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args); - char *name; -}; - -static struct rtas_handler rtas_handlers[] = { -#ifdef CONFIG_KVM_XICS - { .name = "ibm,set-xive", .handler = kvm_rtas_set_xive }, - { .name = "ibm,get-xive", .handler = kvm_rtas_get_xive }, - { .name = "ibm,int-off", .handler = kvm_rtas_int_off }, - { .name = "ibm,int-on", .handler = kvm_rtas_int_on }, -#endif -}; - -struct rtas_token_definition { - struct list_head list; - struct rtas_handler *handler; - u64 token; -}; - -static int rtas_name_matches(char *s1, char *s2) -{ - struct kvm_rtas_token_args args; - return !strncmp(s1, s2, sizeof(args.name)); -} - -static int rtas_token_undefine(struct kvm *kvm, char *name) -{ - struct rtas_token_definition *d, *tmp; - - lockdep_assert_held(&kvm->lock); - - list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) { - if (rtas_name_matches(d->handler->name, name)) { - list_del(&d->list); - kfree(d); - return 0; - } - } - - /* It's not an error to undefine an undefined token */ - return 0; -} - -static int rtas_token_define(struct kvm *kvm, char *name, u64 token) -{ - struct rtas_token_definition *d; - struct rtas_handler *h = NULL; - bool found; - int i; - - lockdep_assert_held(&kvm->lock); - - list_for_each_entry(d, &kvm->arch.rtas_tokens, list) { - if (d->token == token) - return -EEXIST; - } - - found = false; - for (i = 0; i < ARRAY_SIZE(rtas_handlers); i++) { - h = &rtas_handlers[i]; - if (rtas_name_matches(h->name, name)) { - found = true; - break; - } - } - - if (!found) - return -ENOENT; - - d = kzalloc(sizeof(*d), GFP_KERNEL); - if (!d) - return -ENOMEM; - - d->handler = h; - d->token = token; - - list_add_tail(&d->list, &kvm->arch.rtas_tokens); - - return 0; -} - -int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp) -{ - struct kvm_rtas_token_args args; - int rc; - - if (copy_from_user(&args, argp, sizeof(args))) - return -EFAULT; - - mutex_lock(&kvm->lock); - - if (args.token) - rc = rtas_token_define(kvm, args.name, args.token); - else - rc = rtas_token_undefine(kvm, args.name); - - mutex_unlock(&kvm->lock); - - return rc; -} - -int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu) -{ - struct rtas_token_definition *d; - struct rtas_args args; - rtas_arg_t *orig_rets; - gpa_t args_phys; - int rc; - - /* r4 contains the guest physical address of the RTAS args */ - args_phys = kvmppc_get_gpr(vcpu, 4); - - rc = kvm_read_guest(vcpu->kvm, args_phys, &args, sizeof(args)); - if (rc) - goto fail; - - /* - * args->rets is a pointer into args->args. Now that we've - * copied args we need to fix it up to point into our copy, - * not the guest args. We also need to save the original - * value so we can restore it on the way out. - */ - orig_rets = args.rets; - args.rets = &args.args[args.nargs]; - - mutex_lock(&vcpu->kvm->lock); - - rc = -ENOENT; - list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) { - if (d->token == args.token) { - d->handler->handler(vcpu, &args); - rc = 0; - break; - } - } - - mutex_unlock(&vcpu->kvm->lock); - - if (rc == 0) { - args.rets = orig_rets; - rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args)); - if (rc) - goto fail; - } - - return rc; - -fail: - /* - * We only get here if the guest has called RTAS with a bogus - * args pointer. That means we can't get to the args, and so we - * can't fail the RTAS call. So fail right out to userspace, - * which should kill the guest. - */ - return rc; -} - -void kvmppc_rtas_tokens_free(struct kvm *kvm) -{ - struct rtas_token_definition *d, *tmp; - - lockdep_assert_held(&kvm->lock); - - list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) { - list_del(&d->list); - kfree(d); - } -} diff --git a/trunk/arch/powerpc/kvm/book3s_xics.c b/trunk/arch/powerpc/kvm/book3s_xics.c deleted file mode 100644 index f7a103756618..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_xics.c +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * Copyright 2012 Michael Ellerman, IBM Corporation. - * Copyright 2012 Benjamin Herrenschmidt, IBM 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "book3s_xics.h" - -#if 1 -#define XICS_DBG(fmt...) do { } while (0) -#else -#define XICS_DBG(fmt...) trace_printk(fmt) -#endif - -#define ENABLE_REALMODE true -#define DEBUG_REALMODE false - -/* - * LOCKING - * ======= - * - * Each ICS has a mutex protecting the information about the IRQ - * sources and avoiding simultaneous deliveries if the same interrupt. - * - * ICP operations are done via a single compare & swap transaction - * (most ICP state fits in the union kvmppc_icp_state) - */ - -/* - * TODO - * ==== - * - * - To speed up resends, keep a bitmap of "resend" set bits in the - * ICS - * - * - Speed up server# -> ICP lookup (array ? hash table ?) - * - * - Make ICS lockless as well, or at least a per-interrupt lock or hashed - * locks array to improve scalability - */ - -/* -- ICS routines -- */ - -static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, - u32 new_irq); - -static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level, - bool report_status) -{ - struct ics_irq_state *state; - struct kvmppc_ics *ics; - u16 src; - - XICS_DBG("ics deliver %#x (level: %d)\n", irq, level); - - ics = kvmppc_xics_find_ics(xics, irq, &src); - if (!ics) { - XICS_DBG("ics_deliver_irq: IRQ 0x%06x not found !\n", irq); - return -EINVAL; - } - state = &ics->irq_state[src]; - if (!state->exists) - return -EINVAL; - - if (report_status) - return state->asserted; - - /* - * We set state->asserted locklessly. This should be fine as - * we are the only setter, thus concurrent access is undefined - * to begin with. - */ - if (level == KVM_INTERRUPT_SET_LEVEL) - state->asserted = 1; - else if (level == KVM_INTERRUPT_UNSET) { - state->asserted = 0; - return 0; - } - - /* Attempt delivery */ - icp_deliver_irq(xics, NULL, irq); - - return state->asserted; -} - -static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics, - struct kvmppc_icp *icp) -{ - int i; - - mutex_lock(&ics->lock); - - for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { - struct ics_irq_state *state = &ics->irq_state[i]; - - if (!state->resend) - continue; - - XICS_DBG("resend %#x prio %#x\n", state->number, - state->priority); - - mutex_unlock(&ics->lock); - icp_deliver_irq(xics, icp, state->number); - mutex_lock(&ics->lock); - } - - mutex_unlock(&ics->lock); -} - -static bool write_xive(struct kvmppc_xics *xics, struct kvmppc_ics *ics, - struct ics_irq_state *state, - u32 server, u32 priority, u32 saved_priority) -{ - bool deliver; - - mutex_lock(&ics->lock); - - state->server = server; - state->priority = priority; - state->saved_priority = saved_priority; - deliver = false; - if ((state->masked_pending || state->resend) && priority != MASKED) { - state->masked_pending = 0; - deliver = true; - } - - mutex_unlock(&ics->lock); - - return deliver; -} - -int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) -{ - struct kvmppc_xics *xics = kvm->arch.xics; - struct kvmppc_icp *icp; - struct kvmppc_ics *ics; - struct ics_irq_state *state; - u16 src; - - if (!xics) - return -ENODEV; - - ics = kvmppc_xics_find_ics(xics, irq, &src); - if (!ics) - return -EINVAL; - state = &ics->irq_state[src]; - - icp = kvmppc_xics_find_server(kvm, server); - if (!icp) - return -EINVAL; - - XICS_DBG("set_xive %#x server %#x prio %#x MP:%d RS:%d\n", - irq, server, priority, - state->masked_pending, state->resend); - - if (write_xive(xics, ics, state, server, priority, priority)) - icp_deliver_irq(xics, icp, irq); - - return 0; -} - -int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority) -{ - struct kvmppc_xics *xics = kvm->arch.xics; - struct kvmppc_ics *ics; - struct ics_irq_state *state; - u16 src; - - if (!xics) - return -ENODEV; - - ics = kvmppc_xics_find_ics(xics, irq, &src); - if (!ics) - return -EINVAL; - state = &ics->irq_state[src]; - - mutex_lock(&ics->lock); - *server = state->server; - *priority = state->priority; - mutex_unlock(&ics->lock); - - return 0; -} - -int kvmppc_xics_int_on(struct kvm *kvm, u32 irq) -{ - struct kvmppc_xics *xics = kvm->arch.xics; - struct kvmppc_icp *icp; - struct kvmppc_ics *ics; - struct ics_irq_state *state; - u16 src; - - if (!xics) - return -ENODEV; - - ics = kvmppc_xics_find_ics(xics, irq, &src); - if (!ics) - return -EINVAL; - state = &ics->irq_state[src]; - - icp = kvmppc_xics_find_server(kvm, state->server); - if (!icp) - return -EINVAL; - - if (write_xive(xics, ics, state, state->server, state->saved_priority, - state->saved_priority)) - icp_deliver_irq(xics, icp, irq); - - return 0; -} - -int kvmppc_xics_int_off(struct kvm *kvm, u32 irq) -{ - struct kvmppc_xics *xics = kvm->arch.xics; - struct kvmppc_ics *ics; - struct ics_irq_state *state; - u16 src; - - if (!xics) - return -ENODEV; - - ics = kvmppc_xics_find_ics(xics, irq, &src); - if (!ics) - return -EINVAL; - state = &ics->irq_state[src]; - - write_xive(xics, ics, state, state->server, MASKED, state->priority); - - return 0; -} - -/* -- ICP routines, including hcalls -- */ - -static inline bool icp_try_update(struct kvmppc_icp *icp, - union kvmppc_icp_state old, - union kvmppc_icp_state new, - bool change_self) -{ - bool success; - - /* Calculate new output value */ - new.out_ee = (new.xisr && (new.pending_pri < new.cppr)); - - /* Attempt atomic update */ - success = cmpxchg64(&icp->state.raw, old.raw, new.raw) == old.raw; - if (!success) - goto bail; - - XICS_DBG("UPD [%04x] - C:%02x M:%02x PP: %02x PI:%06x R:%d O:%d\n", - icp->server_num, - old.cppr, old.mfrr, old.pending_pri, old.xisr, - old.need_resend, old.out_ee); - XICS_DBG("UPD - C:%02x M:%02x PP: %02x PI:%06x R:%d O:%d\n", - new.cppr, new.mfrr, new.pending_pri, new.xisr, - new.need_resend, new.out_ee); - /* - * Check for output state update - * - * Note that this is racy since another processor could be updating - * the state already. This is why we never clear the interrupt output - * here, we only ever set it. The clear only happens prior to doing - * an update and only by the processor itself. Currently we do it - * in Accept (H_XIRR) and Up_Cppr (H_XPPR). - * - * We also do not try to figure out whether the EE state has changed, - * we unconditionally set it if the new state calls for it. The reason - * for that is that we opportunistically remove the pending interrupt - * flag when raising CPPR, so we need to set it back here if an - * interrupt is still pending. - */ - if (new.out_ee) { - kvmppc_book3s_queue_irqprio(icp->vcpu, - BOOK3S_INTERRUPT_EXTERNAL_LEVEL); - if (!change_self) - kvmppc_fast_vcpu_kick(icp->vcpu); - } - bail: - return success; -} - -static void icp_check_resend(struct kvmppc_xics *xics, - struct kvmppc_icp *icp) -{ - u32 icsid; - - /* Order this load with the test for need_resend in the caller */ - smp_rmb(); - for_each_set_bit(icsid, icp->resend_map, xics->max_icsid + 1) { - struct kvmppc_ics *ics = xics->ics[icsid]; - - if (!test_and_clear_bit(icsid, icp->resend_map)) - continue; - if (!ics) - continue; - ics_check_resend(xics, ics, icp); - } -} - -static bool icp_try_to_deliver(struct kvmppc_icp *icp, u32 irq, u8 priority, - u32 *reject) -{ - union kvmppc_icp_state old_state, new_state; - bool success; - - XICS_DBG("try deliver %#x(P:%#x) to server %#x\n", irq, priority, - icp->server_num); - - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - *reject = 0; - - /* See if we can deliver */ - success = new_state.cppr > priority && - new_state.mfrr > priority && - new_state.pending_pri > priority; - - /* - * If we can, check for a rejection and perform the - * delivery - */ - if (success) { - *reject = new_state.xisr; - new_state.xisr = irq; - new_state.pending_pri = priority; - } else { - /* - * If we failed to deliver we set need_resend - * so a subsequent CPPR state change causes us - * to try a new delivery. - */ - new_state.need_resend = true; - } - - } while (!icp_try_update(icp, old_state, new_state, false)); - - return success; -} - -static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, - u32 new_irq) -{ - struct ics_irq_state *state; - struct kvmppc_ics *ics; - u32 reject; - u16 src; - - /* - * This is used both for initial delivery of an interrupt and - * for subsequent rejection. - * - * Rejection can be racy vs. resends. We have evaluated the - * rejection in an atomic ICP transaction which is now complete, - * so potentially the ICP can already accept the interrupt again. - * - * So we need to retry the delivery. Essentially the reject path - * boils down to a failed delivery. Always. - * - * Now the interrupt could also have moved to a different target, - * thus we may need to re-do the ICP lookup as well - */ - - again: - /* Get the ICS state and lock it */ - ics = kvmppc_xics_find_ics(xics, new_irq, &src); - if (!ics) { - XICS_DBG("icp_deliver_irq: IRQ 0x%06x not found !\n", new_irq); - return; - } - state = &ics->irq_state[src]; - - /* Get a lock on the ICS */ - mutex_lock(&ics->lock); - - /* Get our server */ - if (!icp || state->server != icp->server_num) { - icp = kvmppc_xics_find_server(xics->kvm, state->server); - if (!icp) { - pr_warn("icp_deliver_irq: IRQ 0x%06x server 0x%x not found !\n", - new_irq, state->server); - goto out; - } - } - - /* Clear the resend bit of that interrupt */ - state->resend = 0; - - /* - * If masked, bail out - * - * Note: PAPR doesn't mention anything about masked pending - * when doing a resend, only when doing a delivery. - * - * However that would have the effect of losing a masked - * interrupt that was rejected and isn't consistent with - * the whole masked_pending business which is about not - * losing interrupts that occur while masked. - * - * I don't differenciate normal deliveries and resends, this - * implementation will differ from PAPR and not lose such - * interrupts. - */ - if (state->priority == MASKED) { - XICS_DBG("irq %#x masked pending\n", new_irq); - state->masked_pending = 1; - goto out; - } - - /* - * Try the delivery, this will set the need_resend flag - * in the ICP as part of the atomic transaction if the - * delivery is not possible. - * - * Note that if successful, the new delivery might have itself - * rejected an interrupt that was "delivered" before we took the - * icp mutex. - * - * In this case we do the whole sequence all over again for the - * new guy. We cannot assume that the rejected interrupt is less - * favored than the new one, and thus doesn't need to be delivered, - * because by the time we exit icp_try_to_deliver() the target - * processor may well have alrady consumed & completed it, and thus - * the rejected interrupt might actually be already acceptable. - */ - if (icp_try_to_deliver(icp, new_irq, state->priority, &reject)) { - /* - * Delivery was successful, did we reject somebody else ? - */ - if (reject && reject != XICS_IPI) { - mutex_unlock(&ics->lock); - new_irq = reject; - goto again; - } - } else { - /* - * We failed to deliver the interrupt we need to set the - * resend map bit and mark the ICS state as needing a resend - */ - set_bit(ics->icsid, icp->resend_map); - state->resend = 1; - - /* - * If the need_resend flag got cleared in the ICP some time - * between icp_try_to_deliver() atomic update and now, then - * we know it might have missed the resend_map bit. So we - * retry - */ - smp_mb(); - if (!icp->state.need_resend) { - mutex_unlock(&ics->lock); - goto again; - } - } - out: - mutex_unlock(&ics->lock); -} - -static void icp_down_cppr(struct kvmppc_xics *xics, struct kvmppc_icp *icp, - u8 new_cppr) -{ - union kvmppc_icp_state old_state, new_state; - bool resend; - - /* - * This handles several related states in one operation: - * - * ICP State: Down_CPPR - * - * Load CPPR with new value and if the XISR is 0 - * then check for resends: - * - * ICP State: Resend - * - * If MFRR is more favored than CPPR, check for IPIs - * and notify ICS of a potential resend. This is done - * asynchronously (when used in real mode, we will have - * to exit here). - * - * We do not handle the complete Check_IPI as documented - * here. In the PAPR, this state will be used for both - * Set_MFRR and Down_CPPR. However, we know that we aren't - * changing the MFRR state here so we don't need to handle - * the case of an MFRR causing a reject of a pending irq, - * this will have been handled when the MFRR was set in the - * first place. - * - * Thus we don't have to handle rejects, only resends. - * - * When implementing real mode for HV KVM, resend will lead to - * a H_TOO_HARD return and the whole transaction will be handled - * in virtual mode. - */ - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - /* Down_CPPR */ - new_state.cppr = new_cppr; - - /* - * Cut down Resend / Check_IPI / IPI - * - * The logic is that we cannot have a pending interrupt - * trumped by an IPI at this point (see above), so we - * know that either the pending interrupt is already an - * IPI (in which case we don't care to override it) or - * it's either more favored than us or non existent - */ - if (new_state.mfrr < new_cppr && - new_state.mfrr <= new_state.pending_pri) { - WARN_ON(new_state.xisr != XICS_IPI && - new_state.xisr != 0); - new_state.pending_pri = new_state.mfrr; - new_state.xisr = XICS_IPI; - } - - /* Latch/clear resend bit */ - resend = new_state.need_resend; - new_state.need_resend = 0; - - } while (!icp_try_update(icp, old_state, new_state, true)); - - /* - * Now handle resend checks. Those are asynchronous to the ICP - * state update in HW (ie bus transactions) so we can handle them - * separately here too - */ - if (resend) - icp_check_resend(xics, icp); -} - -static noinline unsigned long kvmppc_h_xirr(struct kvm_vcpu *vcpu) -{ - union kvmppc_icp_state old_state, new_state; - struct kvmppc_icp *icp = vcpu->arch.icp; - u32 xirr; - - /* First, remove EE from the processor */ - kvmppc_book3s_dequeue_irqprio(icp->vcpu, - BOOK3S_INTERRUPT_EXTERNAL_LEVEL); - - /* - * ICP State: Accept_Interrupt - * - * Return the pending interrupt (if any) along with the - * current CPPR, then clear the XISR & set CPPR to the - * pending priority - */ - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - xirr = old_state.xisr | (((u32)old_state.cppr) << 24); - if (!old_state.xisr) - break; - new_state.cppr = new_state.pending_pri; - new_state.pending_pri = 0xff; - new_state.xisr = 0; - - } while (!icp_try_update(icp, old_state, new_state, true)); - - XICS_DBG("h_xirr vcpu %d xirr %#x\n", vcpu->vcpu_id, xirr); - - return xirr; -} - -static noinline int kvmppc_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, - unsigned long mfrr) -{ - union kvmppc_icp_state old_state, new_state; - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - struct kvmppc_icp *icp; - u32 reject; - bool resend; - bool local; - - XICS_DBG("h_ipi vcpu %d to server %lu mfrr %#lx\n", - vcpu->vcpu_id, server, mfrr); - - icp = vcpu->arch.icp; - local = icp->server_num == server; - if (!local) { - icp = kvmppc_xics_find_server(vcpu->kvm, server); - if (!icp) - return H_PARAMETER; - } - - /* - * ICP state: Set_MFRR - * - * If the CPPR is more favored than the new MFRR, then - * nothing needs to be rejected as there can be no XISR to - * reject. If the MFRR is being made less favored then - * there might be a previously-rejected interrupt needing - * to be resent. - * - * If the CPPR is less favored, then we might be replacing - * an interrupt, and thus need to possibly reject it as in - * - * ICP state: Check_IPI - */ - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - /* Set_MFRR */ - new_state.mfrr = mfrr; - - /* Check_IPI */ - reject = 0; - resend = false; - if (mfrr < new_state.cppr) { - /* Reject a pending interrupt if not an IPI */ - if (mfrr <= new_state.pending_pri) - reject = new_state.xisr; - new_state.pending_pri = mfrr; - new_state.xisr = XICS_IPI; - } - - if (mfrr > old_state.mfrr && mfrr > new_state.cppr) { - resend = new_state.need_resend; - new_state.need_resend = 0; - } - } while (!icp_try_update(icp, old_state, new_state, local)); - - /* Handle reject */ - if (reject && reject != XICS_IPI) - icp_deliver_irq(xics, icp, reject); - - /* Handle resend */ - if (resend) - icp_check_resend(xics, icp); - - return H_SUCCESS; -} - -static noinline void kvmppc_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr) -{ - union kvmppc_icp_state old_state, new_state; - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - struct kvmppc_icp *icp = vcpu->arch.icp; - u32 reject; - - XICS_DBG("h_cppr vcpu %d cppr %#lx\n", vcpu->vcpu_id, cppr); - - /* - * ICP State: Set_CPPR - * - * We can safely compare the new value with the current - * value outside of the transaction as the CPPR is only - * ever changed by the processor on itself - */ - if (cppr > icp->state.cppr) - icp_down_cppr(xics, icp, cppr); - else if (cppr == icp->state.cppr) - return; - - /* - * ICP State: Up_CPPR - * - * The processor is raising its priority, this can result - * in a rejection of a pending interrupt: - * - * ICP State: Reject_Current - * - * We can remove EE from the current processor, the update - * transaction will set it again if needed - */ - kvmppc_book3s_dequeue_irqprio(icp->vcpu, - BOOK3S_INTERRUPT_EXTERNAL_LEVEL); - - do { - old_state = new_state = ACCESS_ONCE(icp->state); - - reject = 0; - new_state.cppr = cppr; - - if (cppr <= new_state.pending_pri) { - reject = new_state.xisr; - new_state.xisr = 0; - new_state.pending_pri = 0xff; - } - - } while (!icp_try_update(icp, old_state, new_state, true)); - - /* - * Check for rejects. They are handled by doing a new delivery - * attempt (see comments in icp_deliver_irq). - */ - if (reject && reject != XICS_IPI) - icp_deliver_irq(xics, icp, reject); -} - -static noinline int kvmppc_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) -{ - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - struct kvmppc_icp *icp = vcpu->arch.icp; - struct kvmppc_ics *ics; - struct ics_irq_state *state; - u32 irq = xirr & 0x00ffffff; - u16 src; - - XICS_DBG("h_eoi vcpu %d eoi %#lx\n", vcpu->vcpu_id, xirr); - - /* - * ICP State: EOI - * - * Note: If EOI is incorrectly used by SW to lower the CPPR - * value (ie more favored), we do not check for rejection of - * a pending interrupt, this is a SW error and PAPR sepcifies - * that we don't have to deal with it. - * - * The sending of an EOI to the ICS is handled after the - * CPPR update - * - * ICP State: Down_CPPR which we handle - * in a separate function as it's shared with H_CPPR. - */ - icp_down_cppr(xics, icp, xirr >> 24); - - /* IPIs have no EOI */ - if (irq == XICS_IPI) - return H_SUCCESS; - /* - * EOI handling: If the interrupt is still asserted, we need to - * resend it. We can take a lockless "peek" at the ICS state here. - * - * "Message" interrupts will never have "asserted" set - */ - ics = kvmppc_xics_find_ics(xics, irq, &src); - if (!ics) { - XICS_DBG("h_eoi: IRQ 0x%06x not found !\n", irq); - return H_PARAMETER; - } - state = &ics->irq_state[src]; - - /* Still asserted, resend it */ - if (state->asserted) - icp_deliver_irq(xics, icp, irq); - - return H_SUCCESS; -} - -static noinline int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall) -{ - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - struct kvmppc_icp *icp = vcpu->arch.icp; - - XICS_DBG("XICS_RM: H_%x completing, act: %x state: %lx tgt: %p\n", - hcall, icp->rm_action, icp->rm_dbgstate.raw, icp->rm_dbgtgt); - - if (icp->rm_action & XICS_RM_KICK_VCPU) - kvmppc_fast_vcpu_kick(icp->rm_kick_target); - if (icp->rm_action & XICS_RM_CHECK_RESEND) - icp_check_resend(xics, icp); - if (icp->rm_action & XICS_RM_REJECT) - icp_deliver_irq(xics, icp, icp->rm_reject); - - icp->rm_action = 0; - - return H_SUCCESS; -} - -int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 req) -{ - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - unsigned long res; - int rc = H_SUCCESS; - - /* Check if we have an ICP */ - if (!xics || !vcpu->arch.icp) - return H_HARDWARE; - - /* Check for real mode returning too hard */ - if (xics->real_mode) - return kvmppc_xics_rm_complete(vcpu, req); - - switch (req) { - case H_XIRR: - res = kvmppc_h_xirr(vcpu); - kvmppc_set_gpr(vcpu, 4, res); - break; - case H_CPPR: - kvmppc_h_cppr(vcpu, kvmppc_get_gpr(vcpu, 4)); - break; - case H_EOI: - rc = kvmppc_h_eoi(vcpu, kvmppc_get_gpr(vcpu, 4)); - break; - case H_IPI: - rc = kvmppc_h_ipi(vcpu, kvmppc_get_gpr(vcpu, 4), - kvmppc_get_gpr(vcpu, 5)); - break; - } - - return rc; -} - - -/* -- Initialisation code etc. -- */ - -static int xics_debug_show(struct seq_file *m, void *private) -{ - struct kvmppc_xics *xics = m->private; - struct kvm *kvm = xics->kvm; - struct kvm_vcpu *vcpu; - int icsid, i; - - if (!kvm) - return 0; - - seq_printf(m, "=========\nICP state\n=========\n"); - - kvm_for_each_vcpu(i, vcpu, kvm) { - struct kvmppc_icp *icp = vcpu->arch.icp; - union kvmppc_icp_state state; - - if (!icp) - continue; - - state.raw = ACCESS_ONCE(icp->state.raw); - seq_printf(m, "cpu server %#lx XIRR:%#x PPRI:%#x CPPR:%#x MFRR:%#x OUT:%d NR:%d\n", - icp->server_num, state.xisr, - state.pending_pri, state.cppr, state.mfrr, - state.out_ee, state.need_resend); - } - - for (icsid = 0; icsid <= KVMPPC_XICS_MAX_ICS_ID; icsid++) { - struct kvmppc_ics *ics = xics->ics[icsid]; - - if (!ics) - continue; - - seq_printf(m, "=========\nICS state for ICS 0x%x\n=========\n", - icsid); - - mutex_lock(&ics->lock); - - for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { - struct ics_irq_state *irq = &ics->irq_state[i]; - - seq_printf(m, "irq 0x%06x: server %#x prio %#x save prio %#x asserted %d resend %d masked pending %d\n", - irq->number, irq->server, irq->priority, - irq->saved_priority, irq->asserted, - irq->resend, irq->masked_pending); - - } - mutex_unlock(&ics->lock); - } - return 0; -} - -static int xics_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, xics_debug_show, inode->i_private); -} - -static const struct file_operations xics_debug_fops = { - .open = xics_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void xics_debugfs_init(struct kvmppc_xics *xics) -{ - char *name; - - name = kasprintf(GFP_KERNEL, "kvm-xics-%p", xics); - if (!name) { - pr_err("%s: no memory for name\n", __func__); - return; - } - - xics->dentry = debugfs_create_file(name, S_IRUGO, powerpc_debugfs_root, - xics, &xics_debug_fops); - - pr_debug("%s: created %s\n", __func__, name); - kfree(name); -} - -static struct kvmppc_ics *kvmppc_xics_create_ics(struct kvm *kvm, - struct kvmppc_xics *xics, int irq) -{ - struct kvmppc_ics *ics; - int i, icsid; - - icsid = irq >> KVMPPC_XICS_ICS_SHIFT; - - mutex_lock(&kvm->lock); - - /* ICS already exists - somebody else got here first */ - if (xics->ics[icsid]) - goto out; - - /* Create the ICS */ - ics = kzalloc(sizeof(struct kvmppc_ics), GFP_KERNEL); - if (!ics) - goto out; - - mutex_init(&ics->lock); - ics->icsid = icsid; - - for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { - ics->irq_state[i].number = (icsid << KVMPPC_XICS_ICS_SHIFT) | i; - ics->irq_state[i].priority = MASKED; - ics->irq_state[i].saved_priority = MASKED; - } - smp_wmb(); - xics->ics[icsid] = ics; - - if (icsid > xics->max_icsid) - xics->max_icsid = icsid; - - out: - mutex_unlock(&kvm->lock); - return xics->ics[icsid]; -} - -int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server_num) -{ - struct kvmppc_icp *icp; - - if (!vcpu->kvm->arch.xics) - return -ENODEV; - - if (kvmppc_xics_find_server(vcpu->kvm, server_num)) - return -EEXIST; - - icp = kzalloc(sizeof(struct kvmppc_icp), GFP_KERNEL); - if (!icp) - return -ENOMEM; - - icp->vcpu = vcpu; - icp->server_num = server_num; - icp->state.mfrr = MASKED; - icp->state.pending_pri = MASKED; - vcpu->arch.icp = icp; - - XICS_DBG("created server for vcpu %d\n", vcpu->vcpu_id); - - return 0; -} - -u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu) -{ - struct kvmppc_icp *icp = vcpu->arch.icp; - union kvmppc_icp_state state; - - if (!icp) - return 0; - state = icp->state; - return ((u64)state.cppr << KVM_REG_PPC_ICP_CPPR_SHIFT) | - ((u64)state.xisr << KVM_REG_PPC_ICP_XISR_SHIFT) | - ((u64)state.mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) | - ((u64)state.pending_pri << KVM_REG_PPC_ICP_PPRI_SHIFT); -} - -int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval) -{ - struct kvmppc_icp *icp = vcpu->arch.icp; - struct kvmppc_xics *xics = vcpu->kvm->arch.xics; - union kvmppc_icp_state old_state, new_state; - struct kvmppc_ics *ics; - u8 cppr, mfrr, pending_pri; - u32 xisr; - u16 src; - bool resend; - - if (!icp || !xics) - return -ENOENT; - - cppr = icpval >> KVM_REG_PPC_ICP_CPPR_SHIFT; - xisr = (icpval >> KVM_REG_PPC_ICP_XISR_SHIFT) & - KVM_REG_PPC_ICP_XISR_MASK; - mfrr = icpval >> KVM_REG_PPC_ICP_MFRR_SHIFT; - pending_pri = icpval >> KVM_REG_PPC_ICP_PPRI_SHIFT; - - /* Require the new state to be internally consistent */ - if (xisr == 0) { - if (pending_pri != 0xff) - return -EINVAL; - } else if (xisr == XICS_IPI) { - if (pending_pri != mfrr || pending_pri >= cppr) - return -EINVAL; - } else { - if (pending_pri >= mfrr || pending_pri >= cppr) - return -EINVAL; - ics = kvmppc_xics_find_ics(xics, xisr, &src); - if (!ics) - return -EINVAL; - } - - new_state.raw = 0; - new_state.cppr = cppr; - new_state.xisr = xisr; - new_state.mfrr = mfrr; - new_state.pending_pri = pending_pri; - - /* - * Deassert the CPU interrupt request. - * icp_try_update will reassert it if necessary. - */ - kvmppc_book3s_dequeue_irqprio(icp->vcpu, - BOOK3S_INTERRUPT_EXTERNAL_LEVEL); - - /* - * Note that if we displace an interrupt from old_state.xisr, - * we don't mark it as rejected. We expect userspace to set - * the state of the interrupt sources to be consistent with - * the ICP states (either before or afterwards, which doesn't - * matter). We do handle resends due to CPPR becoming less - * favoured because that is necessary to end up with a - * consistent state in the situation where userspace restores - * the ICS states before the ICP states. - */ - do { - old_state = ACCESS_ONCE(icp->state); - - if (new_state.mfrr <= old_state.mfrr) { - resend = false; - new_state.need_resend = old_state.need_resend; - } else { - resend = old_state.need_resend; - new_state.need_resend = 0; - } - } while (!icp_try_update(icp, old_state, new_state, false)); - - if (resend) - icp_check_resend(xics, icp); - - return 0; -} - -static int xics_get_source(struct kvmppc_xics *xics, long irq, u64 addr) -{ - int ret; - struct kvmppc_ics *ics; - struct ics_irq_state *irqp; - u64 __user *ubufp = (u64 __user *) addr; - u16 idx; - u64 val, prio; - - ics = kvmppc_xics_find_ics(xics, irq, &idx); - if (!ics) - return -ENOENT; - - irqp = &ics->irq_state[idx]; - mutex_lock(&ics->lock); - ret = -ENOENT; - if (irqp->exists) { - val = irqp->server; - prio = irqp->priority; - if (prio == MASKED) { - val |= KVM_XICS_MASKED; - prio = irqp->saved_priority; - } - val |= prio << KVM_XICS_PRIORITY_SHIFT; - if (irqp->asserted) - val |= KVM_XICS_LEVEL_SENSITIVE | KVM_XICS_PENDING; - else if (irqp->masked_pending || irqp->resend) - val |= KVM_XICS_PENDING; - ret = 0; - } - mutex_unlock(&ics->lock); - - if (!ret && put_user(val, ubufp)) - ret = -EFAULT; - - return ret; -} - -static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr) -{ - struct kvmppc_ics *ics; - struct ics_irq_state *irqp; - u64 __user *ubufp = (u64 __user *) addr; - u16 idx; - u64 val; - u8 prio; - u32 server; - - if (irq < KVMPPC_XICS_FIRST_IRQ || irq >= KVMPPC_XICS_NR_IRQS) - return -ENOENT; - - ics = kvmppc_xics_find_ics(xics, irq, &idx); - if (!ics) { - ics = kvmppc_xics_create_ics(xics->kvm, xics, irq); - if (!ics) - return -ENOMEM; - } - irqp = &ics->irq_state[idx]; - if (get_user(val, ubufp)) - return -EFAULT; - - server = val & KVM_XICS_DESTINATION_MASK; - prio = val >> KVM_XICS_PRIORITY_SHIFT; - if (prio != MASKED && - kvmppc_xics_find_server(xics->kvm, server) == NULL) - return -EINVAL; - - mutex_lock(&ics->lock); - irqp->server = server; - irqp->saved_priority = prio; - if (val & KVM_XICS_MASKED) - prio = MASKED; - irqp->priority = prio; - irqp->resend = 0; - irqp->masked_pending = 0; - irqp->asserted = 0; - if ((val & KVM_XICS_PENDING) && (val & KVM_XICS_LEVEL_SENSITIVE)) - irqp->asserted = 1; - irqp->exists = 1; - mutex_unlock(&ics->lock); - - if (val & KVM_XICS_PENDING) - icp_deliver_irq(xics, NULL, irqp->number); - - return 0; -} - -int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, - bool line_status) -{ - struct kvmppc_xics *xics = kvm->arch.xics; - - return ics_deliver_irq(xics, irq, level, line_status); -} - -static int xics_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - struct kvmppc_xics *xics = dev->private; - - switch (attr->group) { - case KVM_DEV_XICS_GRP_SOURCES: - return xics_set_source(xics, attr->attr, attr->addr); - } - return -ENXIO; -} - -static int xics_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - struct kvmppc_xics *xics = dev->private; - - switch (attr->group) { - case KVM_DEV_XICS_GRP_SOURCES: - return xics_get_source(xics, attr->attr, attr->addr); - } - return -ENXIO; -} - -static int xics_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - switch (attr->group) { - case KVM_DEV_XICS_GRP_SOURCES: - if (attr->attr >= KVMPPC_XICS_FIRST_IRQ && - attr->attr < KVMPPC_XICS_NR_IRQS) - return 0; - break; - } - return -ENXIO; -} - -static void kvmppc_xics_free(struct kvm_device *dev) -{ - struct kvmppc_xics *xics = dev->private; - int i; - struct kvm *kvm = xics->kvm; - - debugfs_remove(xics->dentry); - - if (kvm) - kvm->arch.xics = NULL; - - for (i = 0; i <= xics->max_icsid; i++) - kfree(xics->ics[i]); - kfree(xics); - kfree(dev); -} - -static int kvmppc_xics_create(struct kvm_device *dev, u32 type) -{ - struct kvmppc_xics *xics; - struct kvm *kvm = dev->kvm; - int ret = 0; - - xics = kzalloc(sizeof(*xics), GFP_KERNEL); - if (!xics) - return -ENOMEM; - - dev->private = xics; - xics->dev = dev; - xics->kvm = kvm; - - /* Already there ? */ - mutex_lock(&kvm->lock); - if (kvm->arch.xics) - ret = -EEXIST; - else - kvm->arch.xics = xics; - mutex_unlock(&kvm->lock); - - if (ret) - return ret; - - xics_debugfs_init(xics); - -#ifdef CONFIG_KVM_BOOK3S_64_HV - if (cpu_has_feature(CPU_FTR_ARCH_206)) { - /* Enable real mode support */ - xics->real_mode = ENABLE_REALMODE; - xics->real_mode_dbg = DEBUG_REALMODE; - } -#endif /* CONFIG_KVM_BOOK3S_64_HV */ - - return 0; -} - -struct kvm_device_ops kvm_xics_ops = { - .name = "kvm-xics", - .create = kvmppc_xics_create, - .destroy = kvmppc_xics_free, - .set_attr = xics_set_attr, - .get_attr = xics_get_attr, - .has_attr = xics_has_attr, -}; - -int kvmppc_xics_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu, - u32 xcpu) -{ - struct kvmppc_xics *xics = dev->private; - int r = -EBUSY; - - if (dev->ops != &kvm_xics_ops) - return -EPERM; - if (xics->kvm != vcpu->kvm) - return -EPERM; - if (vcpu->arch.irq_type) - return -EBUSY; - - r = kvmppc_xics_create_icp(vcpu, xcpu); - if (!r) - vcpu->arch.irq_type = KVMPPC_IRQ_XICS; - - return r; -} - -void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) -{ - if (!vcpu->arch.icp) - return; - kfree(vcpu->arch.icp); - vcpu->arch.icp = NULL; - vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT; -} diff --git a/trunk/arch/powerpc/kvm/book3s_xics.h b/trunk/arch/powerpc/kvm/book3s_xics.h deleted file mode 100644 index dd9326c5c19b..000000000000 --- a/trunk/arch/powerpc/kvm/book3s_xics.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2012 Michael Ellerman, IBM Corporation. - * Copyright 2012 Benjamin Herrenschmidt, IBM 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. - */ - -#ifndef _KVM_PPC_BOOK3S_XICS_H -#define _KVM_PPC_BOOK3S_XICS_H - -/* - * We use a two-level tree to store interrupt source information. - * There are up to 1024 ICS nodes, each of which can represent - * 1024 sources. - */ -#define KVMPPC_XICS_MAX_ICS_ID 1023 -#define KVMPPC_XICS_ICS_SHIFT 10 -#define KVMPPC_XICS_IRQ_PER_ICS (1 << KVMPPC_XICS_ICS_SHIFT) -#define KVMPPC_XICS_SRC_MASK (KVMPPC_XICS_IRQ_PER_ICS - 1) - -/* - * Interrupt source numbers below this are reserved, for example - * 0 is "no interrupt", and 2 is used for IPIs. - */ -#define KVMPPC_XICS_FIRST_IRQ 16 -#define KVMPPC_XICS_NR_IRQS ((KVMPPC_XICS_MAX_ICS_ID + 1) * \ - KVMPPC_XICS_IRQ_PER_ICS) - -/* Priority value to use for disabling an interrupt */ -#define MASKED 0xff - -/* State for one irq source */ -struct ics_irq_state { - u32 number; - u32 server; - u8 priority; - u8 saved_priority; - u8 resend; - u8 masked_pending; - u8 asserted; /* Only for LSI */ - u8 exists; -}; - -/* Atomic ICP state, updated with a single compare & swap */ -union kvmppc_icp_state { - unsigned long raw; - struct { - u8 out_ee:1; - u8 need_resend:1; - u8 cppr; - u8 mfrr; - u8 pending_pri; - u32 xisr; - }; -}; - -/* One bit per ICS */ -#define ICP_RESEND_MAP_SIZE (KVMPPC_XICS_MAX_ICS_ID / BITS_PER_LONG + 1) - -struct kvmppc_icp { - struct kvm_vcpu *vcpu; - unsigned long server_num; - union kvmppc_icp_state state; - unsigned long resend_map[ICP_RESEND_MAP_SIZE]; - - /* Real mode might find something too hard, here's the action - * it might request from virtual mode - */ -#define XICS_RM_KICK_VCPU 0x1 -#define XICS_RM_CHECK_RESEND 0x2 -#define XICS_RM_REJECT 0x4 - u32 rm_action; - struct kvm_vcpu *rm_kick_target; - u32 rm_reject; - - /* Debug stuff for real mode */ - union kvmppc_icp_state rm_dbgstate; - struct kvm_vcpu *rm_dbgtgt; -}; - -struct kvmppc_ics { - struct mutex lock; - u16 icsid; - struct ics_irq_state irq_state[KVMPPC_XICS_IRQ_PER_ICS]; -}; - -struct kvmppc_xics { - struct kvm *kvm; - struct kvm_device *dev; - struct dentry *dentry; - u32 max_icsid; - bool real_mode; - bool real_mode_dbg; - struct kvmppc_ics *ics[KVMPPC_XICS_MAX_ICS_ID + 1]; -}; - -static inline struct kvmppc_icp *kvmppc_xics_find_server(struct kvm *kvm, - u32 nr) -{ - struct kvm_vcpu *vcpu = NULL; - int i; - - kvm_for_each_vcpu(i, vcpu, kvm) { - if (vcpu->arch.icp && nr == vcpu->arch.icp->server_num) - return vcpu->arch.icp; - } - return NULL; -} - -static inline struct kvmppc_ics *kvmppc_xics_find_ics(struct kvmppc_xics *xics, - u32 irq, u16 *source) -{ - u32 icsid = irq >> KVMPPC_XICS_ICS_SHIFT; - u16 src = irq & KVMPPC_XICS_SRC_MASK; - struct kvmppc_ics *ics; - - if (source) - *source = src; - if (icsid > KVMPPC_XICS_MAX_ICS_ID) - return NULL; - ics = xics->ics[icsid]; - if (!ics) - return NULL; - return ics; -} - - -#endif /* _KVM_PPC_BOOK3S_XICS_H */ diff --git a/trunk/arch/powerpc/kvm/booke.c b/trunk/arch/powerpc/kvm/booke.c index 1020119226db..020923e43134 100644 --- a/trunk/arch/powerpc/kvm/booke.c +++ b/trunk/arch/powerpc/kvm/booke.c @@ -222,7 +222,8 @@ void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, kvmppc_booke_queue_irqprio(vcpu, prio); } -void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu) +void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, + struct kvm_interrupt *irq) { clear_bit(BOOKE_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions); clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions); @@ -346,7 +347,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, keep_irq = true; } - if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_flags) + if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_enabled) update_epr = true; switch (priority) { @@ -427,14 +428,8 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, set_guest_esr(vcpu, vcpu->arch.queued_esr); if (update_dear == true) set_guest_dear(vcpu, vcpu->arch.queued_dear); - if (update_epr == true) { - if (vcpu->arch.epr_flags & KVMPPC_EPR_USER) - kvm_make_request(KVM_REQ_EPR_EXIT, vcpu); - else if (vcpu->arch.epr_flags & KVMPPC_EPR_KERNEL) { - BUG_ON(vcpu->arch.irq_type != KVMPPC_IRQ_MPIC); - kvmppc_mpic_set_epr(vcpu); - } - } + if (update_epr == true) + kvm_make_request(KVM_REQ_EPR_EXIT, vcpu); new_msr &= msr_mask; #if defined(CONFIG_64BIT) @@ -751,9 +746,6 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu) kvmppc_core_queue_program(vcpu, ESR_PIL); return RESUME_HOST; - case EMULATE_EXIT_USER: - return RESUME_HOST; - default: BUG(); } @@ -1156,18 +1148,6 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, return r; } -static void kvmppc_set_tsr(struct kvm_vcpu *vcpu, u32 new_tsr) -{ - u32 old_tsr = vcpu->arch.tsr; - - vcpu->arch.tsr = new_tsr; - - if ((old_tsr ^ vcpu->arch.tsr) & (TSR_ENW | TSR_WIS)) - arm_next_watchdog(vcpu); - - update_timer_ints(vcpu); -} - /* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) { @@ -1307,8 +1287,16 @@ static int set_sregs_base(struct kvm_vcpu *vcpu, kvmppc_emulate_dec(vcpu); } - if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) - kvmppc_set_tsr(vcpu, sregs->u.e.tsr); + if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) { + u32 old_tsr = vcpu->arch.tsr; + + vcpu->arch.tsr = sregs->u.e.tsr; + + if ((old_tsr ^ vcpu->arch.tsr) & (TSR_ENW | TSR_WIS)) + arm_next_watchdog(vcpu); + + update_timer_ints(vcpu); + } return 0; } @@ -1421,134 +1409,84 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) { - int r = 0; - union kvmppc_one_reg val; - int size; - long int i; - - size = one_reg_size(reg->id); - if (size > sizeof(val)) - return -EINVAL; + int r = -EINVAL; switch (reg->id) { case KVM_REG_PPC_IAC1: case KVM_REG_PPC_IAC2: case KVM_REG_PPC_IAC3: - case KVM_REG_PPC_IAC4: - i = reg->id - KVM_REG_PPC_IAC1; - val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac[i]); + case KVM_REG_PPC_IAC4: { + int iac = reg->id - KVM_REG_PPC_IAC1; + r = copy_to_user((u64 __user *)(long)reg->addr, + &vcpu->arch.dbg_reg.iac[iac], sizeof(u64)); break; + } case KVM_REG_PPC_DAC1: - case KVM_REG_PPC_DAC2: - i = reg->id - KVM_REG_PPC_DAC1; - val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac[i]); + case KVM_REG_PPC_DAC2: { + int dac = reg->id - KVM_REG_PPC_DAC1; + r = copy_to_user((u64 __user *)(long)reg->addr, + &vcpu->arch.dbg_reg.dac[dac], sizeof(u64)); break; + } case KVM_REG_PPC_EPR: { u32 epr = get_guest_epr(vcpu); - val = get_reg_val(reg->id, epr); + r = put_user(epr, (u32 __user *)(long)reg->addr); break; } #if defined(CONFIG_64BIT) case KVM_REG_PPC_EPCR: - val = get_reg_val(reg->id, vcpu->arch.epcr); + r = put_user(vcpu->arch.epcr, (u32 __user *)(long)reg->addr); break; #endif - case KVM_REG_PPC_TCR: - val = get_reg_val(reg->id, vcpu->arch.tcr); - break; - case KVM_REG_PPC_TSR: - val = get_reg_val(reg->id, vcpu->arch.tsr); - break; - case KVM_REG_PPC_DEBUG_INST: - val = get_reg_val(reg->id, KVMPPC_INST_EHPRIV); - break; default: - r = kvmppc_get_one_reg(vcpu, reg->id, &val); break; } - - if (r) - return r; - - if (copy_to_user((char __user *)(unsigned long)reg->addr, &val, size)) - r = -EFAULT; - return r; } int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) { - int r = 0; - union kvmppc_one_reg val; - int size; - long int i; - - size = one_reg_size(reg->id); - if (size > sizeof(val)) - return -EINVAL; - - if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size)) - return -EFAULT; + int r = -EINVAL; switch (reg->id) { case KVM_REG_PPC_IAC1: case KVM_REG_PPC_IAC2: case KVM_REG_PPC_IAC3: - case KVM_REG_PPC_IAC4: - i = reg->id - KVM_REG_PPC_IAC1; - vcpu->arch.dbg_reg.iac[i] = set_reg_val(reg->id, val); + case KVM_REG_PPC_IAC4: { + int iac = reg->id - KVM_REG_PPC_IAC1; + r = copy_from_user(&vcpu->arch.dbg_reg.iac[iac], + (u64 __user *)(long)reg->addr, sizeof(u64)); break; + } case KVM_REG_PPC_DAC1: - case KVM_REG_PPC_DAC2: - i = reg->id - KVM_REG_PPC_DAC1; - vcpu->arch.dbg_reg.dac[i] = set_reg_val(reg->id, val); + case KVM_REG_PPC_DAC2: { + int dac = reg->id - KVM_REG_PPC_DAC1; + r = copy_from_user(&vcpu->arch.dbg_reg.dac[dac], + (u64 __user *)(long)reg->addr, sizeof(u64)); break; + } case KVM_REG_PPC_EPR: { - u32 new_epr = set_reg_val(reg->id, val); - kvmppc_set_epr(vcpu, new_epr); + u32 new_epr; + r = get_user(new_epr, (u32 __user *)(long)reg->addr); + if (!r) + kvmppc_set_epr(vcpu, new_epr); break; } #if defined(CONFIG_64BIT) case KVM_REG_PPC_EPCR: { - u32 new_epcr = set_reg_val(reg->id, val); - kvmppc_set_epcr(vcpu, new_epcr); + u32 new_epcr; + r = get_user(new_epcr, (u32 __user *)(long)reg->addr); + if (r == 0) + kvmppc_set_epcr(vcpu, new_epcr); break; } #endif - case KVM_REG_PPC_OR_TSR: { - u32 tsr_bits = set_reg_val(reg->id, val); - kvmppc_set_tsr_bits(vcpu, tsr_bits); - break; - } - case KVM_REG_PPC_CLEAR_TSR: { - u32 tsr_bits = set_reg_val(reg->id, val); - kvmppc_clr_tsr_bits(vcpu, tsr_bits); - break; - } - case KVM_REG_PPC_TSR: { - u32 tsr = set_reg_val(reg->id, val); - kvmppc_set_tsr(vcpu, tsr); - break; - } - case KVM_REG_PPC_TCR: { - u32 tcr = set_reg_val(reg->id, val); - kvmppc_set_tcr(vcpu, tcr); - break; - } default: - r = kvmppc_set_one_reg(vcpu, reg->id, &val); break; } - return r; } -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, - struct kvm_guest_debug *dbg) -{ - return -EINVAL; -} - int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { return -ENOTSUPP; @@ -1593,7 +1531,7 @@ int kvmppc_core_prepare_memory_region(struct kvm *kvm, void kvmppc_core_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old) + struct kvm_memory_slot old) { } diff --git a/trunk/arch/powerpc/kvm/booke_interrupts.S b/trunk/arch/powerpc/kvm/booke_interrupts.S index 2c6deb5ef2fe..f4bb55c96517 100644 --- a/trunk/arch/powerpc/kvm/booke_interrupts.S +++ b/trunk/arch/powerpc/kvm/booke_interrupts.S @@ -54,7 +54,8 @@ (1< #include -enum vcpu_ftr { - VCPU_FTR_MMU_V2 -}; - #define E500_PID_NUM 3 #define E500_TLB_NUM 2 @@ -135,10 +131,6 @@ void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500); void kvmppc_get_sregs_e500_tlb(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs); int kvmppc_set_sregs_e500_tlb(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs); -int kvmppc_get_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id, - union kvmppc_one_reg *val); -int kvmppc_set_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id, - union kvmppc_one_reg *val); #ifdef CONFIG_KVM_E500V2 unsigned int kvmppc_e500_get_sid(struct kvmppc_vcpu_e500 *vcpu_e500, @@ -303,18 +295,4 @@ static inline unsigned int get_tlbmiss_tid(struct kvm_vcpu *vcpu) #define get_tlb_sts(gtlbe) (MAS1_TS) #endif /* !BOOKE_HV */ -static inline bool has_feature(const struct kvm_vcpu *vcpu, - enum vcpu_ftr ftr) -{ - bool has_ftr; - switch (ftr) { - case VCPU_FTR_MMU_V2: - has_ftr = ((vcpu->arch.mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2); - break; - default: - return false; - } - return has_ftr; -} - #endif /* KVM_E500_H */ diff --git a/trunk/arch/powerpc/kvm/e500_emulate.c b/trunk/arch/powerpc/kvm/e500_emulate.c index b10a01243abd..e78f353a836a 100644 --- a/trunk/arch/powerpc/kvm/e500_emulate.c +++ b/trunk/arch/powerpc/kvm/e500_emulate.c @@ -284,16 +284,6 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) case SPRN_TLB1CFG: *spr_val = vcpu->arch.tlbcfg[1]; break; - case SPRN_TLB0PS: - if (!has_feature(vcpu, VCPU_FTR_MMU_V2)) - return EMULATE_FAIL; - *spr_val = vcpu->arch.tlbps[0]; - break; - case SPRN_TLB1PS: - if (!has_feature(vcpu, VCPU_FTR_MMU_V2)) - return EMULATE_FAIL; - *spr_val = vcpu->arch.tlbps[1]; - break; case SPRN_L1CSR0: *spr_val = vcpu_e500->l1csr0; break; @@ -317,15 +307,6 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) case SPRN_MMUCFG: *spr_val = vcpu->arch.mmucfg; break; - case SPRN_EPTCFG: - if (!has_feature(vcpu, VCPU_FTR_MMU_V2)) - return EMULATE_FAIL; - /* - * Legacy Linux guests access EPTCFG register even if the E.PT - * category is disabled in the VM. Give them a chance to live. - */ - *spr_val = vcpu->arch.eptcfg; - break; /* extra exceptions */ case SPRN_IVOR32: diff --git a/trunk/arch/powerpc/kvm/e500_mmu.c b/trunk/arch/powerpc/kvm/e500_mmu.c index c41a5a96b558..5c4475983f78 100644 --- a/trunk/arch/powerpc/kvm/e500_mmu.c +++ b/trunk/arch/powerpc/kvm/e500_mmu.c @@ -596,140 +596,6 @@ int kvmppc_set_sregs_e500_tlb(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) return 0; } -int kvmppc_get_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id, - union kvmppc_one_reg *val) -{ - int r = 0; - long int i; - - switch (id) { - case KVM_REG_PPC_MAS0: - *val = get_reg_val(id, vcpu->arch.shared->mas0); - break; - case KVM_REG_PPC_MAS1: - *val = get_reg_val(id, vcpu->arch.shared->mas1); - break; - case KVM_REG_PPC_MAS2: - *val = get_reg_val(id, vcpu->arch.shared->mas2); - break; - case KVM_REG_PPC_MAS7_3: - *val = get_reg_val(id, vcpu->arch.shared->mas7_3); - break; - case KVM_REG_PPC_MAS4: - *val = get_reg_val(id, vcpu->arch.shared->mas4); - break; - case KVM_REG_PPC_MAS6: - *val = get_reg_val(id, vcpu->arch.shared->mas6); - break; - case KVM_REG_PPC_MMUCFG: - *val = get_reg_val(id, vcpu->arch.mmucfg); - break; - case KVM_REG_PPC_EPTCFG: - *val = get_reg_val(id, vcpu->arch.eptcfg); - break; - case KVM_REG_PPC_TLB0CFG: - case KVM_REG_PPC_TLB1CFG: - case KVM_REG_PPC_TLB2CFG: - case KVM_REG_PPC_TLB3CFG: - i = id - KVM_REG_PPC_TLB0CFG; - *val = get_reg_val(id, vcpu->arch.tlbcfg[i]); - break; - case KVM_REG_PPC_TLB0PS: - case KVM_REG_PPC_TLB1PS: - case KVM_REG_PPC_TLB2PS: - case KVM_REG_PPC_TLB3PS: - i = id - KVM_REG_PPC_TLB0PS; - *val = get_reg_val(id, vcpu->arch.tlbps[i]); - break; - default: - r = -EINVAL; - break; - } - - return r; -} - -int kvmppc_set_one_reg_e500_tlb(struct kvm_vcpu *vcpu, u64 id, - union kvmppc_one_reg *val) -{ - int r = 0; - long int i; - - switch (id) { - case KVM_REG_PPC_MAS0: - vcpu->arch.shared->mas0 = set_reg_val(id, *val); - break; - case KVM_REG_PPC_MAS1: - vcpu->arch.shared->mas1 = set_reg_val(id, *val); - break; - case KVM_REG_PPC_MAS2: - vcpu->arch.shared->mas2 = set_reg_val(id, *val); - break; - case KVM_REG_PPC_MAS7_3: - vcpu->arch.shared->mas7_3 = set_reg_val(id, *val); - break; - case KVM_REG_PPC_MAS4: - vcpu->arch.shared->mas4 = set_reg_val(id, *val); - break; - case KVM_REG_PPC_MAS6: - vcpu->arch.shared->mas6 = set_reg_val(id, *val); - break; - /* Only allow MMU registers to be set to the config supported by KVM */ - case KVM_REG_PPC_MMUCFG: { - u32 reg = set_reg_val(id, *val); - if (reg != vcpu->arch.mmucfg) - r = -EINVAL; - break; - } - case KVM_REG_PPC_EPTCFG: { - u32 reg = set_reg_val(id, *val); - if (reg != vcpu->arch.eptcfg) - r = -EINVAL; - break; - } - case KVM_REG_PPC_TLB0CFG: - case KVM_REG_PPC_TLB1CFG: - case KVM_REG_PPC_TLB2CFG: - case KVM_REG_PPC_TLB3CFG: { - /* MMU geometry (N_ENTRY/ASSOC) can be set only using SW_TLB */ - u32 reg = set_reg_val(id, *val); - i = id - KVM_REG_PPC_TLB0CFG; - if (reg != vcpu->arch.tlbcfg[i]) - r = -EINVAL; - break; - } - case KVM_REG_PPC_TLB0PS: - case KVM_REG_PPC_TLB1PS: - case KVM_REG_PPC_TLB2PS: - case KVM_REG_PPC_TLB3PS: { - u32 reg = set_reg_val(id, *val); - i = id - KVM_REG_PPC_TLB0PS; - if (reg != vcpu->arch.tlbps[i]) - r = -EINVAL; - break; - } - default: - r = -EINVAL; - break; - } - - return r; -} - -static int vcpu_mmu_geometry_update(struct kvm_vcpu *vcpu, - struct kvm_book3e_206_tlb_params *params) -{ - vcpu->arch.tlbcfg[0] &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); - if (params->tlb_sizes[0] <= 2048) - vcpu->arch.tlbcfg[0] |= params->tlb_sizes[0]; - vcpu->arch.tlbcfg[0] |= params->tlb_ways[0] << TLBnCFG_ASSOC_SHIFT; - - vcpu->arch.tlbcfg[1] &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); - vcpu->arch.tlbcfg[1] |= params->tlb_sizes[1]; - vcpu->arch.tlbcfg[1] |= params->tlb_ways[1] << TLBnCFG_ASSOC_SHIFT; - return 0; -} - int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu, struct kvm_config_tlb *cfg) { @@ -826,8 +692,16 @@ int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu, vcpu_e500->gtlb_offset[0] = 0; vcpu_e500->gtlb_offset[1] = params.tlb_sizes[0]; - /* Update vcpu's MMU geometry based on SW_TLB input */ - vcpu_mmu_geometry_update(vcpu, ¶ms); + vcpu->arch.mmucfg = mfspr(SPRN_MMUCFG) & ~MMUCFG_LPIDSIZE; + + vcpu->arch.tlbcfg[0] &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); + if (params.tlb_sizes[0] <= 2048) + vcpu->arch.tlbcfg[0] |= params.tlb_sizes[0]; + vcpu->arch.tlbcfg[0] |= params.tlb_ways[0] << TLBnCFG_ASSOC_SHIFT; + + vcpu->arch.tlbcfg[1] &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); + vcpu->arch.tlbcfg[1] |= params.tlb_sizes[1]; + vcpu->arch.tlbcfg[1] |= params.tlb_ways[1] << TLBnCFG_ASSOC_SHIFT; vcpu_e500->shared_tlb_pages = pages; vcpu_e500->num_shared_tlb_pages = num_pages; @@ -863,39 +737,6 @@ int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu, return 0; } -/* Vcpu's MMU default configuration */ -static int vcpu_mmu_init(struct kvm_vcpu *vcpu, - struct kvmppc_e500_tlb_params *params) -{ - /* Initialize RASIZE, PIDSIZE, NTLBS and MAVN fields with host values*/ - vcpu->arch.mmucfg = mfspr(SPRN_MMUCFG) & ~MMUCFG_LPIDSIZE; - - /* Initialize TLBnCFG fields with host values and SW_TLB geometry*/ - vcpu->arch.tlbcfg[0] = mfspr(SPRN_TLB0CFG) & - ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); - vcpu->arch.tlbcfg[0] |= params[0].entries; - vcpu->arch.tlbcfg[0] |= params[0].ways << TLBnCFG_ASSOC_SHIFT; - - vcpu->arch.tlbcfg[1] = mfspr(SPRN_TLB1CFG) & - ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); - vcpu->arch.tlbcfg[1] |= params[1].entries; - vcpu->arch.tlbcfg[1] |= params[1].ways << TLBnCFG_ASSOC_SHIFT; - - if (has_feature(vcpu, VCPU_FTR_MMU_V2)) { - vcpu->arch.tlbps[0] = mfspr(SPRN_TLB0PS); - vcpu->arch.tlbps[1] = mfspr(SPRN_TLB1PS); - - vcpu->arch.mmucfg &= ~MMUCFG_LRAT; - - /* Guest mmu emulation currently doesn't handle E.PT */ - vcpu->arch.eptcfg = 0; - vcpu->arch.tlbcfg[0] &= ~TLBnCFG_PT; - vcpu->arch.tlbcfg[1] &= ~TLBnCFG_IND; - } - - return 0; -} - int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) { struct kvm_vcpu *vcpu = &vcpu_e500->vcpu; @@ -940,7 +781,18 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) if (!vcpu_e500->g2h_tlb1_map) goto err; - vcpu_mmu_init(vcpu, vcpu_e500->gtlb_params); + /* Init TLB configuration register */ + vcpu->arch.tlbcfg[0] = mfspr(SPRN_TLB0CFG) & + ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); + vcpu->arch.tlbcfg[0] |= vcpu_e500->gtlb_params[0].entries; + vcpu->arch.tlbcfg[0] |= + vcpu_e500->gtlb_params[0].ways << TLBnCFG_ASSOC_SHIFT; + + vcpu->arch.tlbcfg[1] = mfspr(SPRN_TLB1CFG) & + ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); + vcpu->arch.tlbcfg[1] |= vcpu_e500->gtlb_params[1].entries; + vcpu->arch.tlbcfg[1] |= + vcpu_e500->gtlb_params[1].ways << TLBnCFG_ASSOC_SHIFT; kvmppc_recalc_tlb1map_range(vcpu_e500); return 0; diff --git a/trunk/arch/powerpc/kvm/e500mc.c b/trunk/arch/powerpc/kvm/e500mc.c index 753cc99eff2b..2f4baa074b2e 100644 --- a/trunk/arch/powerpc/kvm/e500mc.c +++ b/trunk/arch/powerpc/kvm/e500mc.c @@ -177,8 +177,6 @@ int kvmppc_core_check_processor_compat(void) r = 0; else if (strcmp(cur_cpu_spec->cpu_name, "e5500") == 0) r = 0; - else if (strcmp(cur_cpu_spec->cpu_name, "e6500") == 0) - r = 0; else r = -ENOTSUPP; @@ -262,20 +260,6 @@ int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) return kvmppc_set_sregs_ivor(vcpu, sregs); } -int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, - union kvmppc_one_reg *val) -{ - int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val); - return r; -} - -int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, - union kvmppc_one_reg *val) -{ - int r = kvmppc_set_one_reg_e500_tlb(vcpu, id, val); - return r; -} - struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) { struct kvmppc_vcpu_e500 *vcpu_e500; diff --git a/trunk/arch/powerpc/kvm/emulate.c b/trunk/arch/powerpc/kvm/emulate.c index 631a2650e4e4..7a73b6f72a8b 100644 --- a/trunk/arch/powerpc/kvm/emulate.c +++ b/trunk/arch/powerpc/kvm/emulate.c @@ -38,7 +38,6 @@ #define OP_31_XOP_TRAP 4 #define OP_31_XOP_LWZX 23 -#define OP_31_XOP_DCBST 54 #define OP_31_XOP_TRAP_64 68 #define OP_31_XOP_DCBF 86 #define OP_31_XOP_LBZX 87 @@ -371,7 +370,6 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) emulated = kvmppc_emulate_mtspr(vcpu, sprn, rs); break; - case OP_31_XOP_DCBST: case OP_31_XOP_DCBF: case OP_31_XOP_DCBI: /* Do nothing. The guest is performing dcbi because diff --git a/trunk/arch/powerpc/kvm/irq.h b/trunk/arch/powerpc/kvm/irq.h deleted file mode 100644 index 5a9a10b90762..000000000000 --- a/trunk/arch/powerpc/kvm/irq.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __IRQ_H -#define __IRQ_H - -#include - -static inline int irqchip_in_kernel(struct kvm *kvm) -{ - int ret = 0; - -#ifdef CONFIG_KVM_MPIC - ret = ret || (kvm->arch.mpic != NULL); -#endif -#ifdef CONFIG_KVM_XICS - ret = ret || (kvm->arch.xics != NULL); -#endif - smp_rmb(); - return ret; -} - -#endif diff --git a/trunk/arch/powerpc/kvm/mpic.c b/trunk/arch/powerpc/kvm/mpic.c deleted file mode 100644 index 2861ae9eaae6..000000000000 --- a/trunk/arch/powerpc/kvm/mpic.c +++ /dev/null @@ -1,1853 +0,0 @@ -/* - * OpenPIC emulation - * - * Copyright (c) 2004 Jocelyn Mayer - * 2011 Alexander Graf - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iodev.h" - -#define MAX_CPU 32 -#define MAX_SRC 256 -#define MAX_TMR 4 -#define MAX_IPI 4 -#define MAX_MSI 8 -#define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR) -#define VID 0x03 /* MPIC version ID */ - -/* OpenPIC capability flags */ -#define OPENPIC_FLAG_IDR_CRIT (1 << 0) -#define OPENPIC_FLAG_ILR (2 << 0) - -/* OpenPIC address map */ -#define OPENPIC_REG_SIZE 0x40000 -#define OPENPIC_GLB_REG_START 0x0 -#define OPENPIC_GLB_REG_SIZE 0x10F0 -#define OPENPIC_TMR_REG_START 0x10F0 -#define OPENPIC_TMR_REG_SIZE 0x220 -#define OPENPIC_MSI_REG_START 0x1600 -#define OPENPIC_MSI_REG_SIZE 0x200 -#define OPENPIC_SUMMARY_REG_START 0x3800 -#define OPENPIC_SUMMARY_REG_SIZE 0x800 -#define OPENPIC_SRC_REG_START 0x10000 -#define OPENPIC_SRC_REG_SIZE (MAX_SRC * 0x20) -#define OPENPIC_CPU_REG_START 0x20000 -#define OPENPIC_CPU_REG_SIZE (0x100 + ((MAX_CPU - 1) * 0x1000)) - -struct fsl_mpic_info { - int max_ext; -}; - -static struct fsl_mpic_info fsl_mpic_20 = { - .max_ext = 12, -}; - -static struct fsl_mpic_info fsl_mpic_42 = { - .max_ext = 12, -}; - -#define FRR_NIRQ_SHIFT 16 -#define FRR_NCPU_SHIFT 8 -#define FRR_VID_SHIFT 0 - -#define VID_REVISION_1_2 2 -#define VID_REVISION_1_3 3 - -#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ - -#define GCR_RESET 0x80000000 -#define GCR_MODE_PASS 0x00000000 -#define GCR_MODE_MIXED 0x20000000 -#define GCR_MODE_PROXY 0x60000000 - -#define TBCR_CI 0x80000000 /* count inhibit */ -#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ - -#define IDR_EP_SHIFT 31 -#define IDR_EP_MASK (1 << IDR_EP_SHIFT) -#define IDR_CI0_SHIFT 30 -#define IDR_CI1_SHIFT 29 -#define IDR_P1_SHIFT 1 -#define IDR_P0_SHIFT 0 - -#define ILR_INTTGT_MASK 0x000000ff -#define ILR_INTTGT_INT 0x00 -#define ILR_INTTGT_CINT 0x01 /* critical */ -#define ILR_INTTGT_MCP 0x02 /* machine check */ -#define NUM_OUTPUTS 3 - -#define MSIIR_OFFSET 0x140 -#define MSIIR_SRS_SHIFT 29 -#define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) -#define MSIIR_IBS_SHIFT 24 -#define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) - -static int get_current_cpu(void) -{ -#if defined(CONFIG_KVM) && defined(CONFIG_BOOKE) - struct kvm_vcpu *vcpu = current->thread.kvm_vcpu; - return vcpu ? vcpu->arch.irq_cpu_id : -1; -#else - /* XXX */ - return -1; -#endif -} - -static int openpic_cpu_write_internal(void *opaque, gpa_t addr, - u32 val, int idx); -static int openpic_cpu_read_internal(void *opaque, gpa_t addr, - u32 *ptr, int idx); - -enum irq_type { - IRQ_TYPE_NORMAL = 0, - IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ - IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ -}; - -struct irq_queue { - /* Round up to the nearest 64 IRQs so that the queue length - * won't change when moving between 32 and 64 bit hosts. - */ - unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)]; - int next; - int priority; -}; - -struct irq_source { - uint32_t ivpr; /* IRQ vector/priority register */ - uint32_t idr; /* IRQ destination register */ - uint32_t destmask; /* bitmap of CPU destinations */ - int last_cpu; - int output; /* IRQ level, e.g. ILR_INTTGT_INT */ - int pending; /* TRUE if IRQ is pending */ - enum irq_type type; - bool level:1; /* level-triggered */ - bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ -}; - -#define IVPR_MASK_SHIFT 31 -#define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT) -#define IVPR_ACTIVITY_SHIFT 30 -#define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT) -#define IVPR_MODE_SHIFT 29 -#define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT) -#define IVPR_POLARITY_SHIFT 23 -#define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT) -#define IVPR_SENSE_SHIFT 22 -#define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT) - -#define IVPR_PRIORITY_MASK (0xF << 16) -#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) -#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) - -/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ -#define IDR_EP 0x80000000 /* external pin */ -#define IDR_CI 0x40000000 /* critical interrupt */ - -struct irq_dest { - struct kvm_vcpu *vcpu; - - int32_t ctpr; /* CPU current task priority */ - struct irq_queue raised; - struct irq_queue servicing; - - /* Count of IRQ sources asserting on non-INT outputs */ - uint32_t outputs_active[NUM_OUTPUTS]; -}; - -#define MAX_MMIO_REGIONS 10 - -struct openpic { - struct kvm *kvm; - struct kvm_device *dev; - struct kvm_io_device mmio; - const struct mem_reg *mmio_regions[MAX_MMIO_REGIONS]; - int num_mmio_regions; - - gpa_t reg_base; - spinlock_t lock; - - /* Behavior control */ - struct fsl_mpic_info *fsl; - uint32_t model; - uint32_t flags; - uint32_t nb_irqs; - uint32_t vid; - uint32_t vir; /* Vendor identification register */ - uint32_t vector_mask; - uint32_t tfrr_reset; - uint32_t ivpr_reset; - uint32_t idr_reset; - uint32_t brr1; - uint32_t mpic_mode_mask; - - /* Global registers */ - uint32_t frr; /* Feature reporting register */ - uint32_t gcr; /* Global configuration register */ - uint32_t pir; /* Processor initialization register */ - uint32_t spve; /* Spurious vector register */ - uint32_t tfrr; /* Timer frequency reporting register */ - /* Source registers */ - struct irq_source src[MAX_IRQ]; - /* Local registers per output pin */ - struct irq_dest dst[MAX_CPU]; - uint32_t nb_cpus; - /* Timer registers */ - struct { - uint32_t tccr; /* Global timer current count register */ - uint32_t tbcr; /* Global timer base count register */ - } timers[MAX_TMR]; - /* Shared MSI registers */ - struct { - uint32_t msir; /* Shared Message Signaled Interrupt Register */ - } msi[MAX_MSI]; - uint32_t max_irq; - uint32_t irq_ipi0; - uint32_t irq_tim0; - uint32_t irq_msi; -}; - - -static void mpic_irq_raise(struct openpic *opp, struct irq_dest *dst, - int output) -{ - struct kvm_interrupt irq = { - .irq = KVM_INTERRUPT_SET_LEVEL, - }; - - if (!dst->vcpu) { - pr_debug("%s: destination cpu %d does not exist\n", - __func__, (int)(dst - &opp->dst[0])); - return; - } - - pr_debug("%s: cpu %d output %d\n", __func__, dst->vcpu->arch.irq_cpu_id, - output); - - if (output != ILR_INTTGT_INT) /* TODO */ - return; - - kvm_vcpu_ioctl_interrupt(dst->vcpu, &irq); -} - -static void mpic_irq_lower(struct openpic *opp, struct irq_dest *dst, - int output) -{ - if (!dst->vcpu) { - pr_debug("%s: destination cpu %d does not exist\n", - __func__, (int)(dst - &opp->dst[0])); - return; - } - - pr_debug("%s: cpu %d output %d\n", __func__, dst->vcpu->arch.irq_cpu_id, - output); - - if (output != ILR_INTTGT_INT) /* TODO */ - return; - - kvmppc_core_dequeue_external(dst->vcpu); -} - -static inline void IRQ_setbit(struct irq_queue *q, int n_IRQ) -{ - set_bit(n_IRQ, q->queue); -} - -static inline void IRQ_resetbit(struct irq_queue *q, int n_IRQ) -{ - clear_bit(n_IRQ, q->queue); -} - -static inline int IRQ_testbit(struct irq_queue *q, int n_IRQ) -{ - return test_bit(n_IRQ, q->queue); -} - -static void IRQ_check(struct openpic *opp, struct irq_queue *q) -{ - int irq = -1; - int next = -1; - int priority = -1; - - for (;;) { - irq = find_next_bit(q->queue, opp->max_irq, irq + 1); - if (irq == opp->max_irq) - break; - - pr_debug("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", - irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); - - if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { - next = irq; - priority = IVPR_PRIORITY(opp->src[irq].ivpr); - } - } - - q->next = next; - q->priority = priority; -} - -static int IRQ_get_next(struct openpic *opp, struct irq_queue *q) -{ - /* XXX: optimize */ - IRQ_check(opp, q); - - return q->next; -} - -static void IRQ_local_pipe(struct openpic *opp, int n_CPU, int n_IRQ, - bool active, bool was_active) -{ - struct irq_dest *dst; - struct irq_source *src; - int priority; - - dst = &opp->dst[n_CPU]; - src = &opp->src[n_IRQ]; - - pr_debug("%s: IRQ %d active %d was %d\n", - __func__, n_IRQ, active, was_active); - - if (src->output != ILR_INTTGT_INT) { - pr_debug("%s: output %d irq %d active %d was %d count %d\n", - __func__, src->output, n_IRQ, active, was_active, - dst->outputs_active[src->output]); - - /* On Freescale MPIC, critical interrupts ignore priority, - * IACK, EOI, etc. Before MPIC v4.1 they also ignore - * masking. - */ - if (active) { - if (!was_active && - dst->outputs_active[src->output]++ == 0) { - pr_debug("%s: Raise OpenPIC output %d cpu %d irq %d\n", - __func__, src->output, n_CPU, n_IRQ); - mpic_irq_raise(opp, dst, src->output); - } - } else { - if (was_active && - --dst->outputs_active[src->output] == 0) { - pr_debug("%s: Lower OpenPIC output %d cpu %d irq %d\n", - __func__, src->output, n_CPU, n_IRQ); - mpic_irq_lower(opp, dst, src->output); - } - } - - return; - } - - priority = IVPR_PRIORITY(src->ivpr); - - /* Even if the interrupt doesn't have enough priority, - * it is still raised, in case ctpr is lowered later. - */ - if (active) - IRQ_setbit(&dst->raised, n_IRQ); - else - IRQ_resetbit(&dst->raised, n_IRQ); - - IRQ_check(opp, &dst->raised); - - if (active && priority <= dst->ctpr) { - pr_debug("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", - __func__, n_IRQ, priority, dst->ctpr, n_CPU); - active = 0; - } - - if (active) { - if (IRQ_get_next(opp, &dst->servicing) >= 0 && - priority <= dst->servicing.priority) { - pr_debug("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", - __func__, n_IRQ, dst->servicing.next, n_CPU); - } else { - pr_debug("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", - __func__, n_CPU, n_IRQ, dst->raised.next); - mpic_irq_raise(opp, dst, ILR_INTTGT_INT); - } - } else { - IRQ_get_next(opp, &dst->servicing); - if (dst->raised.priority > dst->ctpr && - dst->raised.priority > dst->servicing.priority) { - pr_debug("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", - __func__, n_IRQ, dst->raised.next, - dst->raised.priority, dst->ctpr, - dst->servicing.priority, n_CPU); - /* IRQ line stays asserted */ - } else { - pr_debug("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", - __func__, n_IRQ, dst->ctpr, - dst->servicing.priority, n_CPU); - mpic_irq_lower(opp, dst, ILR_INTTGT_INT); - } - } -} - -/* update pic state because registers for n_IRQ have changed value */ -static void openpic_update_irq(struct openpic *opp, int n_IRQ) -{ - struct irq_source *src; - bool active, was_active; - int i; - - src = &opp->src[n_IRQ]; - active = src->pending; - - if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { - /* Interrupt source is disabled */ - pr_debug("%s: IRQ %d is disabled\n", __func__, n_IRQ); - active = false; - } - - was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); - - /* - * We don't have a similar check for already-active because - * ctpr may have changed and we need to withdraw the interrupt. - */ - if (!active && !was_active) { - pr_debug("%s: IRQ %d is already inactive\n", __func__, n_IRQ); - return; - } - - if (active) - src->ivpr |= IVPR_ACTIVITY_MASK; - else - src->ivpr &= ~IVPR_ACTIVITY_MASK; - - if (src->destmask == 0) { - /* No target */ - pr_debug("%s: IRQ %d has no target\n", __func__, n_IRQ); - return; - } - - if (src->destmask == (1 << src->last_cpu)) { - /* Only one CPU is allowed to receive this IRQ */ - IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); - } else if (!(src->ivpr & IVPR_MODE_MASK)) { - /* Directed delivery mode */ - for (i = 0; i < opp->nb_cpus; i++) { - if (src->destmask & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ, active, - was_active); - } - } - } else { - /* Distributed delivery mode */ - for (i = src->last_cpu + 1; i != src->last_cpu; i++) { - if (i == opp->nb_cpus) - i = 0; - - if (src->destmask & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ, active, - was_active); - src->last_cpu = i; - break; - } - } - } -} - -static void openpic_set_irq(void *opaque, int n_IRQ, int level) -{ - struct openpic *opp = opaque; - struct irq_source *src; - - if (n_IRQ >= MAX_IRQ) { - WARN_ONCE(1, "%s: IRQ %d out of range\n", __func__, n_IRQ); - return; - } - - src = &opp->src[n_IRQ]; - pr_debug("openpic: set irq %d = %d ivpr=0x%08x\n", - n_IRQ, level, src->ivpr); - if (src->level) { - /* level-sensitive irq */ - src->pending = level; - openpic_update_irq(opp, n_IRQ); - } else { - /* edge-sensitive irq */ - if (level) { - src->pending = 1; - openpic_update_irq(opp, n_IRQ); - } - - if (src->output != ILR_INTTGT_INT) { - /* Edge-triggered interrupts shouldn't be used - * with non-INT delivery, but just in case, - * try to make it do something sane rather than - * cause an interrupt storm. This is close to - * what you'd probably see happen in real hardware. - */ - src->pending = 0; - openpic_update_irq(opp, n_IRQ); - } - } -} - -static void openpic_reset(struct openpic *opp) -{ - int i; - - opp->gcr = GCR_RESET; - /* Initialise controller registers */ - opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) | - (opp->vid << FRR_VID_SHIFT); - - opp->pir = 0; - opp->spve = -1 & opp->vector_mask; - opp->tfrr = opp->tfrr_reset; - /* Initialise IRQ sources */ - for (i = 0; i < opp->max_irq; i++) { - opp->src[i].ivpr = opp->ivpr_reset; - opp->src[i].idr = opp->idr_reset; - - switch (opp->src[i].type) { - case IRQ_TYPE_NORMAL: - opp->src[i].level = - !!(opp->ivpr_reset & IVPR_SENSE_MASK); - break; - - case IRQ_TYPE_FSLINT: - opp->src[i].ivpr |= IVPR_POLARITY_MASK; - break; - - case IRQ_TYPE_FSLSPECIAL: - break; - } - } - /* Initialise IRQ destinations */ - for (i = 0; i < MAX_CPU; i++) { - opp->dst[i].ctpr = 15; - memset(&opp->dst[i].raised, 0, sizeof(struct irq_queue)); - opp->dst[i].raised.next = -1; - memset(&opp->dst[i].servicing, 0, sizeof(struct irq_queue)); - opp->dst[i].servicing.next = -1; - } - /* Initialise timers */ - for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].tccr = 0; - opp->timers[i].tbcr = TBCR_CI; - } - /* Go out of RESET state */ - opp->gcr = 0; -} - -static inline uint32_t read_IRQreg_idr(struct openpic *opp, int n_IRQ) -{ - return opp->src[n_IRQ].idr; -} - -static inline uint32_t read_IRQreg_ilr(struct openpic *opp, int n_IRQ) -{ - if (opp->flags & OPENPIC_FLAG_ILR) - return opp->src[n_IRQ].output; - - return 0xffffffff; -} - -static inline uint32_t read_IRQreg_ivpr(struct openpic *opp, int n_IRQ) -{ - return opp->src[n_IRQ].ivpr; -} - -static inline void write_IRQreg_idr(struct openpic *opp, int n_IRQ, - uint32_t val) -{ - struct irq_source *src = &opp->src[n_IRQ]; - uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; - uint32_t crit_mask = 0; - uint32_t mask = normal_mask; - int crit_shift = IDR_EP_SHIFT - opp->nb_cpus; - int i; - - if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { - crit_mask = mask << crit_shift; - mask |= crit_mask | IDR_EP; - } - - src->idr = val & mask; - pr_debug("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); - - if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { - if (src->idr & crit_mask) { - if (src->idr & normal_mask) { - pr_debug("%s: IRQ configured for multiple output types, using critical\n", - __func__); - } - - src->output = ILR_INTTGT_CINT; - src->nomask = true; - src->destmask = 0; - - for (i = 0; i < opp->nb_cpus; i++) { - int n_ci = IDR_CI0_SHIFT - i; - - if (src->idr & (1UL << n_ci)) - src->destmask |= 1UL << i; - } - } else { - src->output = ILR_INTTGT_INT; - src->nomask = false; - src->destmask = src->idr & normal_mask; - } - } else { - src->destmask = src->idr; - } -} - -static inline void write_IRQreg_ilr(struct openpic *opp, int n_IRQ, - uint32_t val) -{ - if (opp->flags & OPENPIC_FLAG_ILR) { - struct irq_source *src = &opp->src[n_IRQ]; - - src->output = val & ILR_INTTGT_MASK; - pr_debug("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr, - src->output); - - /* TODO: on MPIC v4.0 only, set nomask for non-INT */ - } -} - -static inline void write_IRQreg_ivpr(struct openpic *opp, int n_IRQ, - uint32_t val) -{ - uint32_t mask; - - /* NOTE when implementing newer FSL MPIC models: starting with v4.0, - * the polarity bit is read-only on internal interrupts. - */ - mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | - IVPR_POLARITY_MASK | opp->vector_mask; - - /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ivpr = - (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); - - /* For FSL internal interrupts, The sense bit is reserved and zero, - * and the interrupt is always level-triggered. Timers and IPIs - * have no sense or polarity bits, and are edge-triggered. - */ - switch (opp->src[n_IRQ].type) { - case IRQ_TYPE_NORMAL: - opp->src[n_IRQ].level = - !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); - break; - - case IRQ_TYPE_FSLINT: - opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; - break; - - case IRQ_TYPE_FSLSPECIAL: - opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); - break; - } - - openpic_update_irq(opp, n_IRQ); - pr_debug("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, - opp->src[n_IRQ].ivpr); -} - -static void openpic_gcr_write(struct openpic *opp, uint64_t val) -{ - if (val & GCR_RESET) { - openpic_reset(opp); - return; - } - - opp->gcr &= ~opp->mpic_mode_mask; - opp->gcr |= val & opp->mpic_mode_mask; -} - -static int openpic_gbl_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - int err = 0; - - pr_debug("%s: addr %#llx <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return 0; - - switch (addr) { - case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ - break; - case 0x40: - case 0x50: - case 0x60: - case 0x70: - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - err = openpic_cpu_write_internal(opp, addr, val, - get_current_cpu()); - break; - case 0x1000: /* FRR */ - break; - case 0x1020: /* GCR */ - openpic_gcr_write(opp, val); - break; - case 0x1080: /* VIR */ - break; - case 0x1090: /* PIR */ - /* - * This register is used to reset a CPU core -- - * let userspace handle it. - */ - err = -ENXIO; - break; - case 0x10A0: /* IPI_IVPR */ - case 0x10B0: - case 0x10C0: - case 0x10D0: { - int idx; - idx = (addr - 0x10A0) >> 4; - write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); - break; - } - case 0x10E0: /* SPVE */ - opp->spve = val & opp->vector_mask; - break; - default: - break; - } - - return err; -} - -static int openpic_gbl_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - u32 retval; - int err = 0; - - pr_debug("%s: addr %#llx\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - goto out; - - switch (addr) { - case 0x1000: /* FRR */ - retval = opp->frr; - retval |= (opp->nb_cpus - 1) << FRR_NCPU_SHIFT; - break; - case 0x1020: /* GCR */ - retval = opp->gcr; - break; - case 0x1080: /* VIR */ - retval = opp->vir; - break; - case 0x1090: /* PIR */ - retval = 0x00000000; - break; - case 0x00: /* Block Revision Register1 (BRR1) */ - retval = opp->brr1; - break; - case 0x40: - case 0x50: - case 0x60: - case 0x70: - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - err = openpic_cpu_read_internal(opp, addr, - &retval, get_current_cpu()); - break; - case 0x10A0: /* IPI_IVPR */ - case 0x10B0: - case 0x10C0: - case 0x10D0: - { - int idx; - idx = (addr - 0x10A0) >> 4; - retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx); - } - break; - case 0x10E0: /* SPVE */ - retval = opp->spve; - break; - default: - break; - } - -out: - pr_debug("%s: => 0x%08x\n", __func__, retval); - *ptr = retval; - return err; -} - -static int openpic_tmr_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - int idx; - - addr += 0x10f0; - - pr_debug("%s: addr %#llx <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return 0; - - if (addr == 0x10f0) { - /* TFRR */ - opp->tfrr = val; - return 0; - } - - idx = (addr >> 6) & 0x3; - addr = addr & 0x30; - - switch (addr & 0x30) { - case 0x00: /* TCCR */ - break; - case 0x10: /* TBCR */ - if ((opp->timers[idx].tccr & TCCR_TOG) != 0 && - (val & TBCR_CI) == 0 && - (opp->timers[idx].tbcr & TBCR_CI) != 0) - opp->timers[idx].tccr &= ~TCCR_TOG; - - opp->timers[idx].tbcr = val; - break; - case 0x20: /* TVPR */ - write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val); - break; - case 0x30: /* TDR */ - write_IRQreg_idr(opp, opp->irq_tim0 + idx, val); - break; - } - - return 0; -} - -static int openpic_tmr_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - uint32_t retval = -1; - int idx; - - pr_debug("%s: addr %#llx\n", __func__, addr); - if (addr & 0xF) - goto out; - - idx = (addr >> 6) & 0x3; - if (addr == 0x0) { - /* TFRR */ - retval = opp->tfrr; - goto out; - } - - switch (addr & 0x30) { - case 0x00: /* TCCR */ - retval = opp->timers[idx].tccr; - break; - case 0x10: /* TBCR */ - retval = opp->timers[idx].tbcr; - break; - case 0x20: /* TIPV */ - retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); - break; - case 0x30: /* TIDE (TIDR) */ - retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx); - break; - } - -out: - pr_debug("%s: => 0x%08x\n", __func__, retval); - *ptr = retval; - return 0; -} - -static int openpic_src_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - int idx; - - pr_debug("%s: addr %#llx <= %08x\n", __func__, addr, val); - - addr = addr & 0xffff; - idx = addr >> 5; - - switch (addr & 0x1f) { - case 0x00: - write_IRQreg_ivpr(opp, idx, val); - break; - case 0x10: - write_IRQreg_idr(opp, idx, val); - break; - case 0x18: - write_IRQreg_ilr(opp, idx, val); - break; - } - - return 0; -} - -static int openpic_src_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - uint32_t retval; - int idx; - - pr_debug("%s: addr %#llx\n", __func__, addr); - retval = 0xFFFFFFFF; - - addr = addr & 0xffff; - idx = addr >> 5; - - switch (addr & 0x1f) { - case 0x00: - retval = read_IRQreg_ivpr(opp, idx); - break; - case 0x10: - retval = read_IRQreg_idr(opp, idx); - break; - case 0x18: - retval = read_IRQreg_ilr(opp, idx); - break; - } - - pr_debug("%s: => 0x%08x\n", __func__, retval); - *ptr = retval; - return 0; -} - -static int openpic_msi_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - int idx = opp->irq_msi; - int srs, ibs; - - pr_debug("%s: addr %#llx <= 0x%08x\n", __func__, addr, val); - if (addr & 0xF) - return 0; - - switch (addr) { - case MSIIR_OFFSET: - srs = val >> MSIIR_SRS_SHIFT; - idx += srs; - ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT; - opp->msi[srs].msir |= 1 << ibs; - openpic_set_irq(opp, idx, 1); - break; - default: - /* most registers are read-only, thus ignored */ - break; - } - - return 0; -} - -static int openpic_msi_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - uint32_t r = 0; - int i, srs; - - pr_debug("%s: addr %#llx\n", __func__, addr); - if (addr & 0xF) - return -ENXIO; - - srs = addr >> 4; - - switch (addr) { - case 0x00: - case 0x10: - case 0x20: - case 0x30: - case 0x40: - case 0x50: - case 0x60: - case 0x70: /* MSIRs */ - r = opp->msi[srs].msir; - /* Clear on read */ - opp->msi[srs].msir = 0; - openpic_set_irq(opp, opp->irq_msi + srs, 0); - break; - case 0x120: /* MSISR */ - for (i = 0; i < MAX_MSI; i++) - r |= (opp->msi[i].msir ? 1 : 0) << i; - break; - } - - pr_debug("%s: => 0x%08x\n", __func__, r); - *ptr = r; - return 0; -} - -static int openpic_summary_read(void *opaque, gpa_t addr, u32 *ptr) -{ - uint32_t r = 0; - - pr_debug("%s: addr %#llx\n", __func__, addr); - - /* TODO: EISR/EIMR */ - - *ptr = r; - return 0; -} - -static int openpic_summary_write(void *opaque, gpa_t addr, u32 val) -{ - pr_debug("%s: addr %#llx <= 0x%08x\n", __func__, addr, val); - - /* TODO: EISR/EIMR */ - return 0; -} - -static int openpic_cpu_write_internal(void *opaque, gpa_t addr, - u32 val, int idx) -{ - struct openpic *opp = opaque; - struct irq_source *src; - struct irq_dest *dst; - int s_IRQ, n_IRQ; - - pr_debug("%s: cpu %d addr %#llx <= 0x%08x\n", __func__, idx, - addr, val); - - if (idx < 0) - return 0; - - if (addr & 0xF) - return 0; - - dst = &opp->dst[idx]; - addr &= 0xFF0; - switch (addr) { - case 0x40: /* IPIDR */ - case 0x50: - case 0x60: - case 0x70: - idx = (addr - 0x40) >> 4; - /* we use IDE as mask which CPUs to deliver the IPI to still. */ - opp->src[opp->irq_ipi0 + idx].destmask |= val; - openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); - openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); - break; - case 0x80: /* CTPR */ - dst->ctpr = val & 0x0000000F; - - pr_debug("%s: set CPU %d ctpr to %d, raised %d servicing %d\n", - __func__, idx, dst->ctpr, dst->raised.priority, - dst->servicing.priority); - - if (dst->raised.priority <= dst->ctpr) { - pr_debug("%s: Lower OpenPIC INT output cpu %d due to ctpr\n", - __func__, idx); - mpic_irq_lower(opp, dst, ILR_INTTGT_INT); - } else if (dst->raised.priority > dst->servicing.priority) { - pr_debug("%s: Raise OpenPIC INT output cpu %d irq %d\n", - __func__, idx, dst->raised.next); - mpic_irq_raise(opp, dst, ILR_INTTGT_INT); - } - - break; - case 0x90: /* WHOAMI */ - /* Read-only register */ - break; - case 0xA0: /* IACK */ - /* Read-only register */ - break; - case 0xB0: { /* EOI */ - int notify_eoi; - - pr_debug("EOI\n"); - s_IRQ = IRQ_get_next(opp, &dst->servicing); - - if (s_IRQ < 0) { - pr_debug("%s: EOI with no interrupt in service\n", - __func__); - break; - } - - IRQ_resetbit(&dst->servicing, s_IRQ); - /* Notify listeners that the IRQ is over */ - notify_eoi = s_IRQ; - /* Set up next servicing IRQ */ - s_IRQ = IRQ_get_next(opp, &dst->servicing); - /* Check queued interrupts. */ - n_IRQ = IRQ_get_next(opp, &dst->raised); - src = &opp->src[n_IRQ]; - if (n_IRQ != -1 && - (s_IRQ == -1 || - IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { - pr_debug("Raise OpenPIC INT output cpu %d irq %d\n", - idx, n_IRQ); - mpic_irq_raise(opp, dst, ILR_INTTGT_INT); - } - - spin_unlock(&opp->lock); - kvm_notify_acked_irq(opp->kvm, 0, notify_eoi); - spin_lock(&opp->lock); - - break; - } - default: - break; - } - - return 0; -} - -static int openpic_cpu_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - - return openpic_cpu_write_internal(opp, addr, val, - (addr & 0x1f000) >> 12); -} - -static uint32_t openpic_iack(struct openpic *opp, struct irq_dest *dst, - int cpu) -{ - struct irq_source *src; - int retval, irq; - - pr_debug("Lower OpenPIC INT output\n"); - mpic_irq_lower(opp, dst, ILR_INTTGT_INT); - - irq = IRQ_get_next(opp, &dst->raised); - pr_debug("IACK: irq=%d\n", irq); - - if (irq == -1) - /* No more interrupt pending */ - return opp->spve; - - src = &opp->src[irq]; - if (!(src->ivpr & IVPR_ACTIVITY_MASK) || - !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { - pr_err("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n", - __func__, irq, dst->ctpr, src->ivpr); - openpic_update_irq(opp, irq); - retval = opp->spve; - } else { - /* IRQ enter servicing state */ - IRQ_setbit(&dst->servicing, irq); - retval = IVPR_VECTOR(opp, src->ivpr); - } - - if (!src->level) { - /* edge-sensitive IRQ */ - src->ivpr &= ~IVPR_ACTIVITY_MASK; - src->pending = 0; - IRQ_resetbit(&dst->raised, irq); - } - - if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { - src->destmask &= ~(1 << cpu); - if (src->destmask && !src->level) { - /* trigger on CPUs that didn't know about it yet */ - openpic_set_irq(opp, irq, 1); - openpic_set_irq(opp, irq, 0); - /* if all CPUs knew about it, set active bit again */ - src->ivpr |= IVPR_ACTIVITY_MASK; - } - } - - return retval; -} - -void kvmppc_mpic_set_epr(struct kvm_vcpu *vcpu) -{ - struct openpic *opp = vcpu->arch.mpic; - int cpu = vcpu->arch.irq_cpu_id; - unsigned long flags; - - spin_lock_irqsave(&opp->lock, flags); - - if ((opp->gcr & opp->mpic_mode_mask) == GCR_MODE_PROXY) - kvmppc_set_epr(vcpu, openpic_iack(opp, &opp->dst[cpu], cpu)); - - spin_unlock_irqrestore(&opp->lock, flags); -} - -static int openpic_cpu_read_internal(void *opaque, gpa_t addr, - u32 *ptr, int idx) -{ - struct openpic *opp = opaque; - struct irq_dest *dst; - uint32_t retval; - - pr_debug("%s: cpu %d addr %#llx\n", __func__, idx, addr); - retval = 0xFFFFFFFF; - - if (idx < 0) - goto out; - - if (addr & 0xF) - goto out; - - dst = &opp->dst[idx]; - addr &= 0xFF0; - switch (addr) { - case 0x80: /* CTPR */ - retval = dst->ctpr; - break; - case 0x90: /* WHOAMI */ - retval = idx; - break; - case 0xA0: /* IACK */ - retval = openpic_iack(opp, dst, idx); - break; - case 0xB0: /* EOI */ - retval = 0; - break; - default: - break; - } - pr_debug("%s: => 0x%08x\n", __func__, retval); - -out: - *ptr = retval; - return 0; -} - -static int openpic_cpu_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - - return openpic_cpu_read_internal(opp, addr, ptr, - (addr & 0x1f000) >> 12); -} - -struct mem_reg { - int (*read)(void *opaque, gpa_t addr, u32 *ptr); - int (*write)(void *opaque, gpa_t addr, u32 val); - gpa_t start_addr; - int size; -}; - -static const struct mem_reg openpic_gbl_mmio = { - .write = openpic_gbl_write, - .read = openpic_gbl_read, - .start_addr = OPENPIC_GLB_REG_START, - .size = OPENPIC_GLB_REG_SIZE, -}; - -static const struct mem_reg openpic_tmr_mmio = { - .write = openpic_tmr_write, - .read = openpic_tmr_read, - .start_addr = OPENPIC_TMR_REG_START, - .size = OPENPIC_TMR_REG_SIZE, -}; - -static const struct mem_reg openpic_cpu_mmio = { - .write = openpic_cpu_write, - .read = openpic_cpu_read, - .start_addr = OPENPIC_CPU_REG_START, - .size = OPENPIC_CPU_REG_SIZE, -}; - -static const struct mem_reg openpic_src_mmio = { - .write = openpic_src_write, - .read = openpic_src_read, - .start_addr = OPENPIC_SRC_REG_START, - .size = OPENPIC_SRC_REG_SIZE, -}; - -static const struct mem_reg openpic_msi_mmio = { - .read = openpic_msi_read, - .write = openpic_msi_write, - .start_addr = OPENPIC_MSI_REG_START, - .size = OPENPIC_MSI_REG_SIZE, -}; - -static const struct mem_reg openpic_summary_mmio = { - .read = openpic_summary_read, - .write = openpic_summary_write, - .start_addr = OPENPIC_SUMMARY_REG_START, - .size = OPENPIC_SUMMARY_REG_SIZE, -}; - -static void add_mmio_region(struct openpic *opp, const struct mem_reg *mr) -{ - if (opp->num_mmio_regions >= MAX_MMIO_REGIONS) { - WARN(1, "kvm mpic: too many mmio regions\n"); - return; - } - - opp->mmio_regions[opp->num_mmio_regions++] = mr; -} - -static void fsl_common_init(struct openpic *opp) -{ - int i; - int virq = MAX_SRC; - - add_mmio_region(opp, &openpic_msi_mmio); - add_mmio_region(opp, &openpic_summary_mmio); - - opp->vid = VID_REVISION_1_2; - opp->vir = VIR_GENERIC; - opp->vector_mask = 0xFFFF; - opp->tfrr_reset = 0; - opp->ivpr_reset = IVPR_MASK_MASK; - opp->idr_reset = 1 << 0; - opp->max_irq = MAX_IRQ; - - opp->irq_ipi0 = virq; - virq += MAX_IPI; - opp->irq_tim0 = virq; - virq += MAX_TMR; - - BUG_ON(virq > MAX_IRQ); - - opp->irq_msi = 224; - - for (i = 0; i < opp->fsl->max_ext; i++) - opp->src[i].level = false; - - /* Internal interrupts, including message and MSI */ - for (i = 16; i < MAX_SRC; i++) { - opp->src[i].type = IRQ_TYPE_FSLINT; - opp->src[i].level = true; - } - - /* timers and IPIs */ - for (i = MAX_SRC; i < virq; i++) { - opp->src[i].type = IRQ_TYPE_FSLSPECIAL; - opp->src[i].level = false; - } -} - -static int kvm_mpic_read_internal(struct openpic *opp, gpa_t addr, u32 *ptr) -{ - int i; - - for (i = 0; i < opp->num_mmio_regions; i++) { - const struct mem_reg *mr = opp->mmio_regions[i]; - - if (mr->start_addr > addr || addr >= mr->start_addr + mr->size) - continue; - - return mr->read(opp, addr - mr->start_addr, ptr); - } - - return -ENXIO; -} - -static int kvm_mpic_write_internal(struct openpic *opp, gpa_t addr, u32 val) -{ - int i; - - for (i = 0; i < opp->num_mmio_regions; i++) { - const struct mem_reg *mr = opp->mmio_regions[i]; - - if (mr->start_addr > addr || addr >= mr->start_addr + mr->size) - continue; - - return mr->write(opp, addr - mr->start_addr, val); - } - - return -ENXIO; -} - -static int kvm_mpic_read(struct kvm_io_device *this, gpa_t addr, - int len, void *ptr) -{ - struct openpic *opp = container_of(this, struct openpic, mmio); - int ret; - union { - u32 val; - u8 bytes[4]; - } u; - - if (addr & (len - 1)) { - pr_debug("%s: bad alignment %llx/%d\n", - __func__, addr, len); - return -EINVAL; - } - - spin_lock_irq(&opp->lock); - ret = kvm_mpic_read_internal(opp, addr - opp->reg_base, &u.val); - spin_unlock_irq(&opp->lock); - - /* - * Technically only 32-bit accesses are allowed, but be nice to - * people dumping registers a byte at a time -- it works in real - * hardware (reads only, not writes). - */ - if (len == 4) { - *(u32 *)ptr = u.val; - pr_debug("%s: addr %llx ret %d len 4 val %x\n", - __func__, addr, ret, u.val); - } else if (len == 1) { - *(u8 *)ptr = u.bytes[addr & 3]; - pr_debug("%s: addr %llx ret %d len 1 val %x\n", - __func__, addr, ret, u.bytes[addr & 3]); - } else { - pr_debug("%s: bad length %d\n", __func__, len); - return -EINVAL; - } - - return ret; -} - -static int kvm_mpic_write(struct kvm_io_device *this, gpa_t addr, - int len, const void *ptr) -{ - struct openpic *opp = container_of(this, struct openpic, mmio); - int ret; - - if (len != 4) { - pr_debug("%s: bad length %d\n", __func__, len); - return -EOPNOTSUPP; - } - if (addr & 3) { - pr_debug("%s: bad alignment %llx/%d\n", __func__, addr, len); - return -EOPNOTSUPP; - } - - spin_lock_irq(&opp->lock); - ret = kvm_mpic_write_internal(opp, addr - opp->reg_base, - *(const u32 *)ptr); - spin_unlock_irq(&opp->lock); - - pr_debug("%s: addr %llx ret %d val %x\n", - __func__, addr, ret, *(const u32 *)ptr); - - return ret; -} - -static const struct kvm_io_device_ops mpic_mmio_ops = { - .read = kvm_mpic_read, - .write = kvm_mpic_write, -}; - -static void map_mmio(struct openpic *opp) -{ - kvm_iodevice_init(&opp->mmio, &mpic_mmio_ops); - - kvm_io_bus_register_dev(opp->kvm, KVM_MMIO_BUS, - opp->reg_base, OPENPIC_REG_SIZE, - &opp->mmio); -} - -static void unmap_mmio(struct openpic *opp) -{ - kvm_io_bus_unregister_dev(opp->kvm, KVM_MMIO_BUS, &opp->mmio); -} - -static int set_base_addr(struct openpic *opp, struct kvm_device_attr *attr) -{ - u64 base; - - if (copy_from_user(&base, (u64 __user *)(long)attr->addr, sizeof(u64))) - return -EFAULT; - - if (base & 0x3ffff) { - pr_debug("kvm mpic %s: KVM_DEV_MPIC_BASE_ADDR %08llx not aligned\n", - __func__, base); - return -EINVAL; - } - - if (base == opp->reg_base) - return 0; - - mutex_lock(&opp->kvm->slots_lock); - - unmap_mmio(opp); - opp->reg_base = base; - - pr_debug("kvm mpic %s: KVM_DEV_MPIC_BASE_ADDR %08llx\n", - __func__, base); - - if (base == 0) - goto out; - - map_mmio(opp); - -out: - mutex_unlock(&opp->kvm->slots_lock); - return 0; -} - -#define ATTR_SET 0 -#define ATTR_GET 1 - -static int access_reg(struct openpic *opp, gpa_t addr, u32 *val, int type) -{ - int ret; - - if (addr & 3) - return -ENXIO; - - spin_lock_irq(&opp->lock); - - if (type == ATTR_SET) - ret = kvm_mpic_write_internal(opp, addr, *val); - else - ret = kvm_mpic_read_internal(opp, addr, val); - - spin_unlock_irq(&opp->lock); - - pr_debug("%s: type %d addr %llx val %x\n", __func__, type, addr, *val); - - return ret; -} - -static int mpic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - struct openpic *opp = dev->private; - u32 attr32; - - switch (attr->group) { - case KVM_DEV_MPIC_GRP_MISC: - switch (attr->attr) { - case KVM_DEV_MPIC_BASE_ADDR: - return set_base_addr(opp, attr); - } - - break; - - case KVM_DEV_MPIC_GRP_REGISTER: - if (get_user(attr32, (u32 __user *)(long)attr->addr)) - return -EFAULT; - - return access_reg(opp, attr->attr, &attr32, ATTR_SET); - - case KVM_DEV_MPIC_GRP_IRQ_ACTIVE: - if (attr->attr > MAX_SRC) - return -EINVAL; - - if (get_user(attr32, (u32 __user *)(long)attr->addr)) - return -EFAULT; - - if (attr32 != 0 && attr32 != 1) - return -EINVAL; - - spin_lock_irq(&opp->lock); - openpic_set_irq(opp, attr->attr, attr32); - spin_unlock_irq(&opp->lock); - return 0; - } - - return -ENXIO; -} - -static int mpic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - struct openpic *opp = dev->private; - u64 attr64; - u32 attr32; - int ret; - - switch (attr->group) { - case KVM_DEV_MPIC_GRP_MISC: - switch (attr->attr) { - case KVM_DEV_MPIC_BASE_ADDR: - mutex_lock(&opp->kvm->slots_lock); - attr64 = opp->reg_base; - mutex_unlock(&opp->kvm->slots_lock); - - if (copy_to_user((u64 __user *)(long)attr->addr, - &attr64, sizeof(u64))) - return -EFAULT; - - return 0; - } - - break; - - case KVM_DEV_MPIC_GRP_REGISTER: - ret = access_reg(opp, attr->attr, &attr32, ATTR_GET); - if (ret) - return ret; - - if (put_user(attr32, (u32 __user *)(long)attr->addr)) - return -EFAULT; - - return 0; - - case KVM_DEV_MPIC_GRP_IRQ_ACTIVE: - if (attr->attr > MAX_SRC) - return -EINVAL; - - spin_lock_irq(&opp->lock); - attr32 = opp->src[attr->attr].pending; - spin_unlock_irq(&opp->lock); - - if (put_user(attr32, (u32 __user *)(long)attr->addr)) - return -EFAULT; - - return 0; - } - - return -ENXIO; -} - -static int mpic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - switch (attr->group) { - case KVM_DEV_MPIC_GRP_MISC: - switch (attr->attr) { - case KVM_DEV_MPIC_BASE_ADDR: - return 0; - } - - break; - - case KVM_DEV_MPIC_GRP_REGISTER: - return 0; - - case KVM_DEV_MPIC_GRP_IRQ_ACTIVE: - if (attr->attr > MAX_SRC) - break; - - return 0; - } - - return -ENXIO; -} - -static void mpic_destroy(struct kvm_device *dev) -{ - struct openpic *opp = dev->private; - - dev->kvm->arch.mpic = NULL; - kfree(opp); -} - -static int mpic_set_default_irq_routing(struct openpic *opp) -{ - struct kvm_irq_routing_entry *routing; - - /* Create a nop default map, so that dereferencing it still works */ - routing = kzalloc((sizeof(*routing)), GFP_KERNEL); - if (!routing) - return -ENOMEM; - - kvm_set_irq_routing(opp->kvm, routing, 0, 0); - - kfree(routing); - return 0; -} - -static int mpic_create(struct kvm_device *dev, u32 type) -{ - struct openpic *opp; - int ret; - - /* We only support one MPIC at a time for now */ - if (dev->kvm->arch.mpic) - return -EINVAL; - - opp = kzalloc(sizeof(struct openpic), GFP_KERNEL); - if (!opp) - return -ENOMEM; - - dev->private = opp; - opp->kvm = dev->kvm; - opp->dev = dev; - opp->model = type; - spin_lock_init(&opp->lock); - - add_mmio_region(opp, &openpic_gbl_mmio); - add_mmio_region(opp, &openpic_tmr_mmio); - add_mmio_region(opp, &openpic_src_mmio); - add_mmio_region(opp, &openpic_cpu_mmio); - - switch (opp->model) { - case KVM_DEV_TYPE_FSL_MPIC_20: - opp->fsl = &fsl_mpic_20; - opp->brr1 = 0x00400200; - opp->flags |= OPENPIC_FLAG_IDR_CRIT; - opp->nb_irqs = 80; - opp->mpic_mode_mask = GCR_MODE_MIXED; - - fsl_common_init(opp); - - break; - - case KVM_DEV_TYPE_FSL_MPIC_42: - opp->fsl = &fsl_mpic_42; - opp->brr1 = 0x00400402; - opp->flags |= OPENPIC_FLAG_ILR; - opp->nb_irqs = 196; - opp->mpic_mode_mask = GCR_MODE_PROXY; - - fsl_common_init(opp); - - break; - - default: - ret = -ENODEV; - goto err; - } - - ret = mpic_set_default_irq_routing(opp); - if (ret) - goto err; - - openpic_reset(opp); - - smp_wmb(); - dev->kvm->arch.mpic = opp; - - return 0; - -err: - kfree(opp); - return ret; -} - -struct kvm_device_ops kvm_mpic_ops = { - .name = "kvm-mpic", - .create = mpic_create, - .destroy = mpic_destroy, - .set_attr = mpic_set_attr, - .get_attr = mpic_get_attr, - .has_attr = mpic_has_attr, -}; - -int kvmppc_mpic_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu, - u32 cpu) -{ - struct openpic *opp = dev->private; - int ret = 0; - - if (dev->ops != &kvm_mpic_ops) - return -EPERM; - if (opp->kvm != vcpu->kvm) - return -EPERM; - if (cpu < 0 || cpu >= MAX_CPU) - return -EPERM; - - spin_lock_irq(&opp->lock); - - if (opp->dst[cpu].vcpu) { - ret = -EEXIST; - goto out; - } - if (vcpu->arch.irq_type) { - ret = -EBUSY; - goto out; - } - - opp->dst[cpu].vcpu = vcpu; - opp->nb_cpus = max(opp->nb_cpus, cpu + 1); - - vcpu->arch.mpic = opp; - vcpu->arch.irq_cpu_id = cpu; - vcpu->arch.irq_type = KVMPPC_IRQ_MPIC; - - /* This might need to be changed if GCR gets extended */ - if (opp->mpic_mode_mask == GCR_MODE_PROXY) - vcpu->arch.epr_flags |= KVMPPC_EPR_KERNEL; - -out: - spin_unlock_irq(&opp->lock); - return ret; -} - -/* - * This should only happen immediately before the mpic is destroyed, - * so we shouldn't need to worry about anything still trying to - * access the vcpu pointer. - */ -void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, struct kvm_vcpu *vcpu) -{ - BUG_ON(!opp->dst[vcpu->arch.irq_cpu_id].vcpu); - - opp->dst[vcpu->arch.irq_cpu_id].vcpu = NULL; -} - -/* - * Return value: - * < 0 Interrupt was ignored (masked or not delivered for other reasons) - * = 0 Interrupt was coalesced (previous irq is still pending) - * > 0 Number of CPUs interrupt was delivered to - */ -static int mpic_set_irq(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level, - bool line_status) -{ - u32 irq = e->irqchip.pin; - struct openpic *opp = kvm->arch.mpic; - unsigned long flags; - - spin_lock_irqsave(&opp->lock, flags); - openpic_set_irq(opp, irq, level); - spin_unlock_irqrestore(&opp->lock, flags); - - /* All code paths we care about don't check for the return value */ - return 0; -} - -int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level, bool line_status) -{ - struct openpic *opp = kvm->arch.mpic; - unsigned long flags; - - spin_lock_irqsave(&opp->lock, flags); - - /* - * XXX We ignore the target address for now, as we only support - * a single MSI bank. - */ - openpic_msi_write(kvm->arch.mpic, MSIIR_OFFSET, e->msi.data); - spin_unlock_irqrestore(&opp->lock, flags); - - /* All code paths we care about don't check for the return value */ - return 0; -} - -int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, - struct kvm_kernel_irq_routing_entry *e, - const struct kvm_irq_routing_entry *ue) -{ - int r = -EINVAL; - - switch (ue->type) { - case KVM_IRQ_ROUTING_IRQCHIP: - e->set = mpic_set_irq; - e->irqchip.irqchip = ue->u.irqchip.irqchip; - e->irqchip.pin = ue->u.irqchip.pin; - if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) - goto out; - rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi; - break; - case KVM_IRQ_ROUTING_MSI: - e->set = kvm_set_msi; - e->msi.address_lo = ue->u.msi.address_lo; - e->msi.address_hi = ue->u.msi.address_hi; - e->msi.data = ue->u.msi.data; - break; - default: - goto out; - } - - r = 0; -out: - return r; -} diff --git a/trunk/arch/powerpc/kvm/powerpc.c b/trunk/arch/powerpc/kvm/powerpc.c index 6316ee336e88..934413cd3a1b 100644 --- a/trunk/arch/powerpc/kvm/powerpc.c +++ b/trunk/arch/powerpc/kvm/powerpc.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -33,7 +32,6 @@ #include #include #include "timing.h" -#include "irq.h" #include "../mm/mmu_decl.h" #define CREATE_TRACE_POINTS @@ -319,7 +317,6 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_ENABLE_CAP: case KVM_CAP_ONE_REG: case KVM_CAP_IOEVENTFD: - case KVM_CAP_DEVICE_CTRL: r = 1; break; #ifndef CONFIG_KVM_BOOK3S_64_HV @@ -328,9 +325,6 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_PPC_GET_PVINFO: #if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) case KVM_CAP_SW_TLB: -#endif -#ifdef CONFIG_KVM_MPIC - case KVM_CAP_IRQ_MPIC: #endif r = 1; break; @@ -341,10 +335,6 @@ int kvm_dev_ioctl_check_extension(long ext) #ifdef CONFIG_PPC_BOOK3S_64 case KVM_CAP_SPAPR_TCE: case KVM_CAP_PPC_ALLOC_HTAB: - case KVM_CAP_PPC_RTAS: -#ifdef CONFIG_KVM_XICS - case KVM_CAP_IRQ_XICS: -#endif r = 1; break; #endif /* CONFIG_PPC_BOOK3S_64 */ @@ -421,17 +411,18 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) } int kvm_arch_prepare_memory_region(struct kvm *kvm, - struct kvm_memory_slot *memslot, - struct kvm_userspace_memory_region *mem, - enum kvm_mr_change change) + struct kvm_memory_slot *memslot, + struct kvm_memory_slot old, + struct kvm_userspace_memory_region *mem, + bool user_alloc) { return kvmppc_core_prepare_memory_region(kvm, memslot, mem); } void kvm_arch_commit_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old, - enum kvm_mr_change change) + struct kvm_userspace_memory_region *mem, + struct kvm_memory_slot old, + bool user_alloc) { kvmppc_core_commit_memory_region(kvm, mem, old); } @@ -469,16 +460,6 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu) tasklet_kill(&vcpu->arch.tasklet); kvmppc_remove_vcpu_debugfs(vcpu); - - switch (vcpu->arch.irq_type) { - case KVMPPC_IRQ_MPIC: - kvmppc_mpic_disconnect_vcpu(vcpu->arch.mpic, vcpu); - break; - case KVMPPC_IRQ_XICS: - kvmppc_xics_free_icp(vcpu); - break; - } - kvmppc_core_vcpu_free(vcpu); } @@ -551,6 +532,12 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) #endif } +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + return -EINVAL; +} + static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu, struct kvm_run *run) { @@ -625,8 +612,6 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned int rt, unsigned int bytes, int is_bigendian) { - int idx, ret; - if (bytes > sizeof(run->mmio.data)) { printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, run->mmio.len); @@ -642,14 +627,8 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, vcpu->mmio_is_write = 0; vcpu->arch.mmio_sign_extend = 0; - idx = srcu_read_lock(&vcpu->kvm->srcu); - - ret = kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, - bytes, &run->mmio.data); - - srcu_read_unlock(&vcpu->kvm->srcu, idx); - - if (!ret) { + if (!kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, + bytes, &run->mmio.data)) { kvmppc_complete_mmio_load(vcpu, run); vcpu->mmio_needed = 0; return EMULATE_DONE; @@ -674,7 +653,6 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, u64 val, unsigned int bytes, int is_bigendian) { void *data = run->mmio.data; - int idx, ret; if (bytes > sizeof(run->mmio.data)) { printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, @@ -704,14 +682,9 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, } } - idx = srcu_read_lock(&vcpu->kvm->srcu); - - ret = kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, - bytes, &run->mmio.data); - - srcu_read_unlock(&vcpu->kvm->srcu, idx); - - if (!ret) { + if (!kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, + bytes, &run->mmio.data)) { + kvmppc_complete_mmio_load(vcpu, run); vcpu->mmio_needed = 0; return EMULATE_DONE; } @@ -767,7 +740,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { if (irq->irq == KVM_INTERRUPT_UNSET) { - kvmppc_core_dequeue_external(vcpu); + kvmppc_core_dequeue_external(vcpu, irq); return 0; } @@ -797,10 +770,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, break; case KVM_CAP_PPC_EPR: r = 0; - if (cap->args[0]) - vcpu->arch.epr_flags |= KVMPPC_EPR_USER; - else - vcpu->arch.epr_flags &= ~KVMPPC_EPR_USER; + vcpu->arch.epr_enabled = cap->args[0]; break; #ifdef CONFIG_BOOKE case KVM_CAP_PPC_BOOKE_WATCHDOG: @@ -821,44 +791,6 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, break; } #endif -#ifdef CONFIG_KVM_MPIC - case KVM_CAP_IRQ_MPIC: { - struct file *filp; - struct kvm_device *dev; - - r = -EBADF; - filp = fget(cap->args[0]); - if (!filp) - break; - - r = -EPERM; - dev = kvm_device_from_filp(filp); - if (dev) - r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); - - fput(filp); - break; - } -#endif -#ifdef CONFIG_KVM_XICS - case KVM_CAP_IRQ_XICS: { - struct file *filp; - struct kvm_device *dev; - - r = -EBADF; - filp = fget(cap->args[0]); - if (!filp) - break; - - r = -EPERM; - dev = kvm_device_from_filp(filp); - if (dev) - r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]); - - fput(filp); - break; - } -#endif /* CONFIG_KVM_XICS */ default: r = -EINVAL; break; @@ -981,22 +913,9 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo) return 0; } -int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, - bool line_status) -{ - if (!irqchip_in_kernel(kvm)) - return -ENXIO; - - irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, - irq_event->irq, irq_event->level, - line_status); - return 0; -} - long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { - struct kvm *kvm __maybe_unused = filp->private_data; void __user *argp = (void __user *)arg; long r; @@ -1015,6 +934,7 @@ long kvm_arch_vm_ioctl(struct file *filp, #ifdef CONFIG_PPC_BOOK3S_64 case KVM_CREATE_SPAPR_TCE: { struct kvm_create_spapr_tce create_tce; + struct kvm *kvm = filp->private_data; r = -EFAULT; if (copy_from_user(&create_tce, argp, sizeof(create_tce))) @@ -1026,8 +946,8 @@ long kvm_arch_vm_ioctl(struct file *filp, #ifdef CONFIG_KVM_BOOK3S_64_HV case KVM_ALLOCATE_RMA: { - struct kvm_allocate_rma rma; struct kvm *kvm = filp->private_data; + struct kvm_allocate_rma rma; r = kvm_vm_ioctl_allocate_rma(kvm, &rma); if (r >= 0 && copy_to_user(argp, &rma, sizeof(rma))) @@ -1036,6 +956,7 @@ long kvm_arch_vm_ioctl(struct file *filp, } case KVM_PPC_ALLOCATE_HTAB: { + struct kvm *kvm = filp->private_data; u32 htab_order; r = -EFAULT; @@ -1052,6 +973,7 @@ long kvm_arch_vm_ioctl(struct file *filp, } case KVM_PPC_GET_HTAB_FD: { + struct kvm *kvm = filp->private_data; struct kvm_get_htab_fd ghf; r = -EFAULT; @@ -1064,6 +986,7 @@ long kvm_arch_vm_ioctl(struct file *filp, #ifdef CONFIG_PPC_BOOK3S_64 case KVM_PPC_GET_SMMU_INFO: { + struct kvm *kvm = filp->private_data; struct kvm_ppc_smmu_info info; memset(&info, 0, sizeof(info)); @@ -1072,12 +995,6 @@ long kvm_arch_vm_ioctl(struct file *filp, r = -EFAULT; break; } - case KVM_PPC_RTAS_DEFINE_TOKEN: { - struct kvm *kvm = filp->private_data; - - r = kvm_vm_ioctl_rtas_define_token(kvm, argp); - break; - } #endif /* CONFIG_PPC_BOOK3S_64 */ default: r = -ENOTTY; diff --git a/trunk/arch/powerpc/sysdev/xics/icp-native.c b/trunk/arch/powerpc/sysdev/xics/icp-native.c index 7cd728b3b5e4..89db29d17c25 100644 --- a/trunk/arch/powerpc/sysdev/xics/icp-native.c +++ b/trunk/arch/powerpc/sysdev/xics/icp-native.c @@ -51,12 +51,6 @@ static struct icp_ipl __iomem *icp_native_regs[NR_CPUS]; static inline unsigned int icp_native_get_xirr(void) { int cpu = smp_processor_id(); - unsigned int xirr; - - /* Handled an interrupt latched by KVM */ - xirr = kvmppc_get_xics_latch(); - if (xirr) - return xirr; return in_be32(&icp_native_regs[cpu]->xirr.word); } @@ -144,7 +138,6 @@ static unsigned int icp_native_get_irq(void) static void icp_native_cause_ipi(int cpu, unsigned long data) { - kvmppc_set_host_ipi(cpu, 1); icp_native_set_qirr(cpu, IPI_PRIORITY); } @@ -158,7 +151,6 @@ static irqreturn_t icp_native_ipi_action(int irq, void *dev_id) { int cpu = smp_processor_id(); - kvmppc_set_host_ipi(cpu, 0); icp_native_set_qirr(cpu, 0xff); return smp_ipi_demux(); diff --git a/trunk/arch/s390/include/asm/pgtable.h b/trunk/arch/s390/include/asm/pgtable.h index 4105b8221fdd..b4622915bd15 100644 --- a/trunk/arch/s390/include/asm/pgtable.h +++ b/trunk/arch/s390/include/asm/pgtable.h @@ -306,7 +306,6 @@ extern unsigned long MODULES_END; #define RCP_HC_BIT 0x00200000UL #define RCP_GR_BIT 0x00040000UL #define RCP_GC_BIT 0x00020000UL -#define RCP_IN_BIT 0x00008000UL /* IPTE notify bit */ /* User dirty / referenced bit for KVM's migration feature */ #define KVM_UR_BIT 0x00008000UL @@ -374,7 +373,6 @@ extern unsigned long MODULES_END; #define RCP_HC_BIT 0x0020000000000000UL #define RCP_GR_BIT 0x0004000000000000UL #define RCP_GC_BIT 0x0002000000000000UL -#define RCP_IN_BIT 0x0000800000000000UL /* IPTE notify bit */ /* User dirty / referenced bit for KVM's migration feature */ #define KVM_UR_BIT 0x0000800000000000UL @@ -748,42 +746,30 @@ struct gmap { /** * struct gmap_rmap - reverse mapping for segment table entries - * @gmap: pointer to the gmap_struct + * @next: pointer to the next gmap_rmap structure in the list * @entry: pointer to a segment table entry - * @vmaddr: virtual address in the guest address space */ struct gmap_rmap { struct list_head list; - struct gmap *gmap; unsigned long *entry; - unsigned long vmaddr; }; /** * struct gmap_pgtable - gmap information attached to a page table * @vmaddr: address of the 1MB segment in the process virtual memory - * @mapper: list of segment table entries mapping a page table + * @mapper: list of segment table entries maping a page table */ struct gmap_pgtable { unsigned long vmaddr; struct list_head mapper; }; -/** - * struct gmap_notifier - notify function block for page invalidation - * @notifier_call: address of callback function - */ -struct gmap_notifier { - struct list_head list; - void (*notifier_call)(struct gmap *gmap, unsigned long address); -}; - struct gmap *gmap_alloc(struct mm_struct *mm); void gmap_free(struct gmap *gmap); void gmap_enable(struct gmap *gmap); void gmap_disable(struct gmap *gmap); int gmap_map_segment(struct gmap *gmap, unsigned long from, - unsigned long to, unsigned long len); + unsigned long to, unsigned long length); int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); unsigned long __gmap_translate(unsigned long address, struct gmap *); unsigned long gmap_translate(unsigned long address, struct gmap *); @@ -791,24 +777,6 @@ unsigned long __gmap_fault(unsigned long address, struct gmap *); unsigned long gmap_fault(unsigned long address, struct gmap *); void gmap_discard(unsigned long from, unsigned long to, struct gmap *); -void gmap_register_ipte_notifier(struct gmap_notifier *); -void gmap_unregister_ipte_notifier(struct gmap_notifier *); -int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len); -void gmap_do_ipte_notify(struct mm_struct *, unsigned long addr, pte_t *); - -static inline pgste_t pgste_ipte_notify(struct mm_struct *mm, - unsigned long addr, - pte_t *ptep, pgste_t pgste) -{ -#ifdef CONFIG_PGSTE - if (pgste_val(pgste) & RCP_IN_BIT) { - pgste_val(pgste) &= ~RCP_IN_BIT; - gmap_do_ipte_notify(mm, addr, ptep); - } -#endif - return pgste; -} - /* * Certain architectures need to do special things when PTEs * within a page table are directly modified. Thus, the following @@ -1064,10 +1032,8 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, pte_t pte; mm->context.flush_mm = 1; - if (mm_has_pgste(mm)) { + if (mm_has_pgste(mm)) pgste = pgste_get_lock(ptep); - pgste = pgste_ipte_notify(mm, address, ptep, pgste); - } pte = *ptep; if (!mm_exclusive(mm)) @@ -1086,14 +1052,11 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, unsigned long address, pte_t *ptep) { - pgste_t pgste; pte_t pte; mm->context.flush_mm = 1; - if (mm_has_pgste(mm)) { - pgste = pgste_get_lock(ptep); - pgste_ipte_notify(mm, address, ptep, pgste); - } + if (mm_has_pgste(mm)) + pgste_get_lock(ptep); pte = *ptep; if (!mm_exclusive(mm)) @@ -1119,10 +1082,8 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, pgste_t pgste; pte_t pte; - if (mm_has_pgste(vma->vm_mm)) { + if (mm_has_pgste(vma->vm_mm)) pgste = pgste_get_lock(ptep); - pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste); - } pte = *ptep; __ptep_ipte(address, ptep); @@ -1150,11 +1111,8 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, pgste_t pgste; pte_t pte; - if (mm_has_pgste(mm)) { + if (mm_has_pgste(mm)) pgste = pgste_get_lock(ptep); - if (!full) - pgste = pgste_ipte_notify(mm, address, ptep, pgste); - } pte = *ptep; if (!full) @@ -1177,10 +1135,8 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm, if (pte_write(pte)) { mm->context.flush_mm = 1; - if (mm_has_pgste(mm)) { + if (mm_has_pgste(mm)) pgste = pgste_get_lock(ptep); - pgste = pgste_ipte_notify(mm, address, ptep, pgste); - } if (!mm_exclusive(mm)) __ptep_ipte(address, ptep); @@ -1204,10 +1160,8 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma, if (pte_same(*ptep, entry)) return 0; - if (mm_has_pgste(vma->vm_mm)) { + if (mm_has_pgste(vma->vm_mm)) pgste = pgste_get_lock(ptep); - pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste); - } __ptep_ipte(address, ptep); diff --git a/trunk/arch/s390/include/asm/setup.h b/trunk/arch/s390/include/asm/setup.h index 59880dbaf360..ff67d730c00c 100644 --- a/trunk/arch/s390/include/asm/setup.h +++ b/trunk/arch/s390/include/asm/setup.h @@ -33,6 +33,8 @@ #define CHUNK_READ_WRITE 0 #define CHUNK_READ_ONLY 1 +#define CHUNK_OLDMEM 4 +#define CHUNK_CRASHK 5 struct mem_chunk { unsigned long addr; @@ -41,12 +43,13 @@ struct mem_chunk { }; extern struct mem_chunk memory_chunk[]; +extern unsigned long real_memory_size; extern int memory_end_set; extern unsigned long memory_end; -void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize); -void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr, - unsigned long size); +void detect_memory_layout(struct mem_chunk chunk[]); +void create_mem_hole(struct mem_chunk memory_chunk[], unsigned long addr, + unsigned long size, int type); #define PRIMARY_SPACE_MODE 0 #define ACCESS_REGISTER_MODE 1 diff --git a/trunk/arch/s390/include/uapi/asm/Kbuild b/trunk/arch/s390/include/uapi/asm/Kbuild index 9ccd1905bdad..7bf68fff7c5d 100644 --- a/trunk/arch/s390/include/uapi/asm/Kbuild +++ b/trunk/arch/s390/include/uapi/asm/Kbuild @@ -44,6 +44,5 @@ header-y += termios.h header-y += types.h header-y += ucontext.h header-y += unistd.h -header-y += virtio-ccw.h header-y += vtoc.h header-y += zcrypt.h diff --git a/trunk/arch/s390/include/uapi/asm/virtio-ccw.h b/trunk/arch/s390/include/uapi/asm/virtio-ccw.h deleted file mode 100644 index a9a4ebf79fa7..000000000000 --- a/trunk/arch/s390/include/uapi/asm/virtio-ccw.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Definitions for virtio-ccw devices. - * - * Copyright IBM Corp. 2013 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (version 2 only) - * as published by the Free Software Foundation. - * - * Author(s): Cornelia Huck - */ -#ifndef __KVM_VIRTIO_CCW_H -#define __KVM_VIRTIO_CCW_H - -/* Alignment of vring buffers. */ -#define KVM_VIRTIO_CCW_RING_ALIGN 4096 - -/* Subcode for diagnose 500 (virtio hypercall). */ -#define KVM_S390_VIRTIO_CCW_NOTIFY 3 - -#endif diff --git a/trunk/arch/s390/kernel/Makefile b/trunk/arch/s390/kernel/Makefile index 4bb2a4656163..1386fcaf4ef6 100644 --- a/trunk/arch/s390/kernel/Makefile +++ b/trunk/arch/s390/kernel/Makefile @@ -30,7 +30,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.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 sclp.o vdso.o +obj-y += debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += dumpstack.o diff --git a/trunk/arch/s390/kernel/crash_dump.c b/trunk/arch/s390/kernel/crash_dump.c index f703d91bf720..fb8d8781a011 100644 --- a/trunk/arch/s390/kernel/crash_dump.c +++ b/trunk/arch/s390/kernel/crash_dump.c @@ -88,8 +88,8 @@ static struct mem_chunk *get_memory_layout(void) struct mem_chunk *chunk_array; chunk_array = kzalloc_panic(MEMORY_CHUNKS * sizeof(struct mem_chunk)); - detect_memory_layout(chunk_array, 0); - create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE); + detect_memory_layout(chunk_array); + create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE, CHUNK_CRASHK); return chunk_array; } @@ -344,7 +344,7 @@ static int loads_init(Elf64_Phdr *phdr, u64 loads_offset) for (i = 0; i < MEMORY_CHUNKS; i++) { mem_chunk = &chunk_array[i]; if (mem_chunk->size == 0) - continue; + break; if (chunk_array[i].type != CHUNK_READ_WRITE && chunk_array[i].type != CHUNK_READ_ONLY) continue; diff --git a/trunk/arch/s390/kernel/early.c b/trunk/arch/s390/kernel/early.c index dc8770d7173c..bda011e2f8ae 100644 --- a/trunk/arch/s390/kernel/early.c +++ b/trunk/arch/s390/kernel/early.c @@ -482,6 +482,7 @@ void __init startup_init(void) detect_machine_facilities(); setup_topology(); sclp_facilities_detect(); + detect_memory_layout(memory_chunk); #ifdef CONFIG_DYNAMIC_FTRACE S390_lowcore.ftrace_func = (unsigned long)ftrace_caller; #endif diff --git a/trunk/arch/s390/kernel/mem_detect.c b/trunk/arch/s390/kernel/mem_detect.c new file mode 100644 index 000000000000..22d502e885ed --- /dev/null +++ b/trunk/arch/s390/kernel/mem_detect.c @@ -0,0 +1,145 @@ +/* + * Copyright IBM Corp. 2008, 2009 + * + * Author(s): Heiko Carstens + */ + +#include +#include +#include +#include +#include + +#define ADDR2G (1ULL << 31) + +static void find_memory_chunks(struct mem_chunk chunk[]) +{ + unsigned long long memsize, rnmax, rzm; + unsigned long addr = 0, size; + int i = 0, type; + + rzm = sclp_get_rzm(); + rnmax = sclp_get_rnmax(); + memsize = rzm * rnmax; + if (!rzm) + rzm = 1ULL << 17; + if (sizeof(long) == 4) { + rzm = min(ADDR2G, rzm); + memsize = memsize ? min(ADDR2G, memsize) : ADDR2G; + } + do { + size = 0; + type = tprot(addr); + do { + size += rzm; + if (memsize && addr + size >= memsize) + break; + } while (type == tprot(addr + size)); + if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) { + chunk[i].addr = addr; + chunk[i].size = size; + chunk[i].type = type; + i++; + } + addr += size; + } while (addr < memsize && i < MEMORY_CHUNKS); +} + +void detect_memory_layout(struct mem_chunk chunk[]) +{ + unsigned long flags, cr0; + + memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); + /* Disable IRQs, DAT and low address protection so tprot does the + * right thing and we don't get scheduled away with low address + * protection disabled. + */ + flags = __arch_local_irq_stnsm(0xf8); + __ctl_store(cr0, 0, 0); + __ctl_clear_bit(0, 28); + find_memory_chunks(chunk); + __ctl_load(cr0, 0, 0); + arch_local_irq_restore(flags); +} +EXPORT_SYMBOL(detect_memory_layout); + +/* + * Move memory chunks array from index "from" to index "to" + */ +static void mem_chunk_move(struct mem_chunk chunk[], int to, int from) +{ + int cnt = MEMORY_CHUNKS - to; + + memmove(&chunk[to], &chunk[from], cnt * sizeof(struct mem_chunk)); +} + +/* + * Initialize memory chunk + */ +static void mem_chunk_init(struct mem_chunk *chunk, unsigned long addr, + unsigned long size, int type) +{ + chunk->type = type; + chunk->addr = addr; + chunk->size = size; +} + +/* + * Create memory hole with given address, size, and type + */ +void create_mem_hole(struct mem_chunk chunk[], unsigned long addr, + unsigned long size, int type) +{ + unsigned long lh_start, lh_end, lh_size, ch_start, ch_end, ch_size; + int i, ch_type; + + for (i = 0; i < MEMORY_CHUNKS; i++) { + if (chunk[i].size == 0) + continue; + + /* Define chunk properties */ + ch_start = chunk[i].addr; + ch_size = chunk[i].size; + ch_end = ch_start + ch_size - 1; + ch_type = chunk[i].type; + + /* Is memory chunk hit by memory hole? */ + if (addr + size <= ch_start) + continue; /* No: memory hole in front of chunk */ + if (addr > ch_end) + continue; /* No: memory hole after chunk */ + + /* Yes: Define local hole properties */ + lh_start = max(addr, chunk[i].addr); + lh_end = min(addr + size - 1, ch_end); + lh_size = lh_end - lh_start + 1; + + if (lh_start == ch_start && lh_end == ch_end) { + /* Hole covers complete memory chunk */ + mem_chunk_init(&chunk[i], lh_start, lh_size, type); + } else if (lh_end == ch_end) { + /* Hole starts in memory chunk and convers chunk end */ + mem_chunk_move(chunk, i + 1, i); + mem_chunk_init(&chunk[i], ch_start, ch_size - lh_size, + ch_type); + mem_chunk_init(&chunk[i + 1], lh_start, lh_size, type); + i += 1; + } else if (lh_start == ch_start) { + /* Hole ends in memory chunk */ + mem_chunk_move(chunk, i + 1, i); + mem_chunk_init(&chunk[i], lh_start, lh_size, type); + mem_chunk_init(&chunk[i + 1], lh_end + 1, + ch_size - lh_size, ch_type); + break; + } else { + /* Hole splits memory chunk */ + mem_chunk_move(chunk, i + 2, i); + mem_chunk_init(&chunk[i], ch_start, + lh_start - ch_start, ch_type); + mem_chunk_init(&chunk[i + 1], lh_start, lh_size, type); + mem_chunk_init(&chunk[i + 2], lh_end + 1, + ch_end - lh_end, ch_type); + break; + } + } +} diff --git a/trunk/arch/s390/kernel/setup.c b/trunk/arch/s390/kernel/setup.c index 0a49095104c9..0f419c5765c8 100644 --- a/trunk/arch/s390/kernel/setup.c +++ b/trunk/arch/s390/kernel/setup.c @@ -226,17 +226,25 @@ static void __init conmode_default(void) } #ifdef CONFIG_ZFCPDUMP -static void __init setup_zfcpdump(void) +static void __init setup_zfcpdump(unsigned int console_devno) { + static char str[41]; + if (ipl_info.type != IPL_TYPE_FCP_DUMP) return; if (OLDMEM_BASE) return; - strcat(boot_command_line, " cio_ignore=all,!ipldev,!condev"); + if (console_devno != -1) + sprintf(str, " cio_ignore=all,!0.0.%04x,!0.0.%04x", + ipl_info.data.fcp.dev_id.devno, console_devno); + else + sprintf(str, " cio_ignore=all,!0.0.%04x", + ipl_info.data.fcp.dev_id.devno); + strcat(boot_command_line, str); console_loglevel = 2; } #else -static inline void setup_zfcpdump(void) {} +static inline void setup_zfcpdump(unsigned int console_devno) {} #endif /* CONFIG_ZFCPDUMP */ /* @@ -463,10 +471,14 @@ static void __init setup_resources(void) for (i = 0; i < MEMORY_CHUNKS; i++) { if (!memory_chunk[i].size) continue; + if (memory_chunk[i].type == CHUNK_OLDMEM || + memory_chunk[i].type == CHUNK_CRASHK) + continue; res = alloc_bootmem_low(sizeof(*res)); res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; switch (memory_chunk[i].type) { case CHUNK_READ_WRITE: + case CHUNK_CRASHK: res->name = "System RAM"; break; case CHUNK_READ_ONLY: @@ -498,10 +510,12 @@ static void __init setup_resources(void) } } +unsigned long real_memory_size; +EXPORT_SYMBOL_GPL(real_memory_size); + static void __init setup_memory_end(void) { unsigned long vmax, vmalloc_size, tmp; - unsigned long real_memory_size = 0; int i; @@ -511,6 +525,7 @@ static void __init setup_memory_end(void) memory_end_set = 1; } #endif + real_memory_size = 0; memory_end &= PAGE_MASK; /* @@ -523,8 +538,6 @@ static void __init setup_memory_end(void) unsigned long align; chunk = &memory_chunk[i]; - if (!chunk->size) - continue; align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1); start = (chunk->addr + align - 1) & ~(align - 1); end = (chunk->addr + chunk->size) & ~(align - 1); @@ -575,8 +588,6 @@ static void __init setup_memory_end(void) for (i = 0; i < MEMORY_CHUNKS; i++) { struct mem_chunk *chunk = &memory_chunk[i]; - if (!chunk->size) - continue; if (chunk->addr >= memory_end) { memset(chunk, 0, sizeof(*chunk)); continue; @@ -676,6 +687,15 @@ static int __init verify_crash_base(unsigned long crash_base, return -EINVAL; } +/* + * Reserve kdump memory by creating a memory hole in the mem_chunk array + */ +static void __init reserve_kdump_bootmem(unsigned long addr, unsigned long size, + int type) +{ + create_mem_hole(memory_chunk, addr, size, type); +} + /* * When kdump is enabled, we have to ensure that no memory from * the area [0 - crashkernel memory size] and @@ -707,22 +727,16 @@ static struct notifier_block kdump_mem_nb = { static void reserve_oldmem(void) { #ifdef CONFIG_CRASH_DUMP - unsigned long real_size = 0; - int i; - if (!OLDMEM_BASE) return; - for (i = 0; i < MEMORY_CHUNKS; i++) { - struct mem_chunk *chunk = &memory_chunk[i]; - real_size = max(real_size, chunk->addr + chunk->size); - } - create_mem_hole(memory_chunk, OLDMEM_BASE, OLDMEM_SIZE); - create_mem_hole(memory_chunk, OLDMEM_SIZE, real_size - OLDMEM_SIZE); - if (OLDMEM_BASE + OLDMEM_SIZE == real_size) + reserve_kdump_bootmem(OLDMEM_BASE, OLDMEM_SIZE, CHUNK_OLDMEM); + reserve_kdump_bootmem(OLDMEM_SIZE, memory_end - OLDMEM_SIZE, + CHUNK_OLDMEM); + if (OLDMEM_BASE + OLDMEM_SIZE == real_memory_size) saved_max_pfn = PFN_DOWN(OLDMEM_BASE) - 1; else - saved_max_pfn = PFN_DOWN(real_size) - 1; + saved_max_pfn = PFN_DOWN(real_memory_size) - 1; #endif } @@ -761,7 +775,7 @@ static void __init reserve_crashkernel(void) crashk_res.start = crash_base; crashk_res.end = crash_base + crash_size - 1; insert_resource(&iomem_resource, &crashk_res); - create_mem_hole(memory_chunk, crash_base, crash_size); + reserve_kdump_bootmem(crash_base, crash_size, CHUNK_CRASHK); pr_info("Reserving %lluMB of memory at %lluMB " "for crashkernel (System RAM: %luMB)\n", crash_size >> 20, crash_base >> 20, memory_end >> 20); @@ -833,10 +847,11 @@ static void __init setup_memory(void) * Register RAM areas with the bootmem allocator. */ - for (i = 0; i < MEMORY_CHUNKS; i++) { + for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { unsigned long start_chunk, end_chunk, pfn; - if (!memory_chunk[i].size) + if (memory_chunk[i].type != CHUNK_READ_WRITE && + memory_chunk[i].type != CHUNK_CRASHK) continue; start_chunk = PFN_DOWN(memory_chunk[i].addr); end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size); @@ -1052,12 +1067,12 @@ void __init setup_arch(char **cmdline_p) memcpy(&uaccess, &uaccess_std, sizeof(uaccess)); parse_early_param(); - detect_memory_layout(memory_chunk, memory_end); + os_info_init(); setup_ipl(); - reserve_oldmem(); setup_memory_end(); setup_addressing_mode(); + reserve_oldmem(); reserve_crashkernel(); setup_memory(); setup_resources(); @@ -1082,5 +1097,5 @@ void __init setup_arch(char **cmdline_p) set_preferred_console(); /* Setup zfcpdump support */ - setup_zfcpdump(); + setup_zfcpdump(console_devno); } diff --git a/trunk/arch/s390/kvm/Kconfig b/trunk/arch/s390/kvm/Kconfig index 70b46eacf8e1..60f9f8ae0fc8 100644 --- a/trunk/arch/s390/kvm/Kconfig +++ b/trunk/arch/s390/kvm/Kconfig @@ -22,7 +22,6 @@ config KVM select PREEMPT_NOTIFIERS select ANON_INODES select HAVE_KVM_CPU_RELAX_INTERCEPT - select HAVE_KVM_EVENTFD ---help--- Support hosting paravirtualized guest machines using the SIE virtualization capability on the mainframe. This should work diff --git a/trunk/arch/s390/kvm/Makefile b/trunk/arch/s390/kvm/Makefile index 8fe9d65a4585..3975722bb19d 100644 --- a/trunk/arch/s390/kvm/Makefile +++ b/trunk/arch/s390/kvm/Makefile @@ -6,7 +6,7 @@ # it under the terms of the GNU General Public License (version 2 only) # as published by the Free Software Foundation. -common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o eventfd.o) +common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o) ccflags-y := -Ivirt/kvm -Iarch/s390/kvm diff --git a/trunk/arch/s390/kvm/diag.c b/trunk/arch/s390/kvm/diag.c index 1c01a9912989..a390687feb13 100644 --- a/trunk/arch/s390/kvm/diag.c +++ b/trunk/arch/s390/kvm/diag.c @@ -13,7 +13,6 @@ #include #include -#include #include "kvm-s390.h" #include "trace.h" #include "trace-s390.h" @@ -105,29 +104,6 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) return -EREMOTE; } -static int __diag_virtio_hypercall(struct kvm_vcpu *vcpu) -{ - int ret, idx; - - /* No virtio-ccw notification? Get out quickly. */ - if (!vcpu->kvm->arch.css_support || - (vcpu->run->s.regs.gprs[1] != KVM_S390_VIRTIO_CCW_NOTIFY)) - return -EOPNOTSUPP; - - idx = srcu_read_lock(&vcpu->kvm->srcu); - /* - * The layout is as follows: - * - gpr 2 contains the subchannel id (passed as addr) - * - gpr 3 contains the virtqueue index (passed as datamatch) - */ - ret = kvm_io_bus_write(vcpu->kvm, KVM_VIRTIO_CCW_NOTIFY_BUS, - vcpu->run->s.regs.gprs[2], - 8, &vcpu->run->s.regs.gprs[3]); - srcu_read_unlock(&vcpu->kvm->srcu, idx); - /* kvm_io_bus_write returns -EOPNOTSUPP if it found no match. */ - return ret < 0 ? ret : 0; -} - int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) { int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; @@ -142,8 +118,6 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) return __diag_time_slice_end_directed(vcpu); case 0x308: return __diag_ipl_functions(vcpu); - case 0x500: - return __diag_virtio_hypercall(vcpu); default: return -EOPNOTSUPP; } diff --git a/trunk/arch/s390/kvm/gaccess.h b/trunk/arch/s390/kvm/gaccess.h index 302e0e52b009..4703f129e95e 100644 --- a/trunk/arch/s390/kvm/gaccess.h +++ b/trunk/arch/s390/kvm/gaccess.h @@ -18,86 +18,369 @@ #include #include "kvm-s390.h" -static inline void __user *__gptr_to_uptr(struct kvm_vcpu *vcpu, - void __user *gptr, - int prefixing) +static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu, + unsigned long guestaddr) { unsigned long prefix = vcpu->arch.sie_block->prefix; - unsigned long gaddr = (unsigned long) gptr; - unsigned long uaddr; - - if (prefixing) { - if (gaddr < 2 * PAGE_SIZE) - gaddr += prefix; - else if ((gaddr >= prefix) && (gaddr < prefix + 2 * PAGE_SIZE)) - gaddr -= prefix; + + if (guestaddr < 2 * PAGE_SIZE) + guestaddr += prefix; + else if ((guestaddr >= prefix) && (guestaddr < prefix + 2 * PAGE_SIZE)) + guestaddr -= prefix; + + return (void __user *) gmap_fault(guestaddr, vcpu->arch.gmap); +} + +static inline int get_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr, + u64 *result) +{ + void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); + + BUG_ON(guestaddr & 7); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + return get_user(*result, (unsigned long __user *) uptr); +} + +static inline int get_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr, + u32 *result) +{ + void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); + + BUG_ON(guestaddr & 3); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + return get_user(*result, (u32 __user *) uptr); +} + +static inline int get_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr, + u16 *result) +{ + void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); + + BUG_ON(guestaddr & 1); + + if (IS_ERR(uptr)) + return PTR_ERR(uptr); + + return get_user(*result, (u16 __user *) uptr); +} + +static inline int get_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr, + u8 *result) +{ + void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + return get_user(*result, (u8 __user *) uptr); +} + +static inline int put_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr, + u64 value) +{ + void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); + + BUG_ON(guestaddr & 7); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + return put_user(value, (u64 __user *) uptr); +} + +static inline int put_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr, + u32 value) +{ + void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); + + BUG_ON(guestaddr & 3); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + return put_user(value, (u32 __user *) uptr); +} + +static inline int put_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr, + u16 value) +{ + void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); + + BUG_ON(guestaddr & 1); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + return put_user(value, (u16 __user *) uptr); +} + +static inline int put_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr, + u8 value) +{ + void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + return put_user(value, (u8 __user *) uptr); +} + + +static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, + unsigned long guestdest, + void *from, unsigned long n) +{ + int rc; + unsigned long i; + u8 *data = from; + + for (i = 0; i < n; i++) { + rc = put_guest_u8(vcpu, guestdest++, *(data++)); + if (rc < 0) + return rc; } - uaddr = gmap_fault(gaddr, vcpu->arch.gmap); - if (IS_ERR_VALUE(uaddr)) - uaddr = -EFAULT; - return (void __user *)uaddr; -} - -#define get_guest(vcpu, x, gptr) \ -({ \ - __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\ - int __mask = sizeof(__typeof__(*(gptr))) - 1; \ - int __ret = PTR_RET((void __force *)__uptr); \ - \ - if (!__ret) { \ - BUG_ON((unsigned long)__uptr & __mask); \ - __ret = get_user(x, __uptr); \ - } \ - __ret; \ -}) - -#define put_guest(vcpu, x, gptr) \ -({ \ - __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\ - int __mask = sizeof(__typeof__(*(gptr))) - 1; \ - int __ret = PTR_RET((void __force *)__uptr); \ - \ - if (!__ret) { \ - BUG_ON((unsigned long)__uptr & __mask); \ - __ret = put_user(x, __uptr); \ - } \ - __ret; \ -}) - -static inline int __copy_guest(struct kvm_vcpu *vcpu, unsigned long to, - unsigned long from, unsigned long len, - int to_guest, int prefixing) -{ - unsigned long _len, rc; + return 0; +} + +static inline int __copy_to_guest_fast(struct kvm_vcpu *vcpu, + unsigned long guestdest, + void *from, unsigned long n) +{ + int r; void __user *uptr; + unsigned long size; + + if (guestdest + n < guestdest) + return -EFAULT; + + /* simple case: all within one segment table entry? */ + if ((guestdest & PMD_MASK) == ((guestdest+n) & PMD_MASK)) { + uptr = (void __user *) gmap_fault(guestdest, vcpu->arch.gmap); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + r = copy_to_user(uptr, from, n); + + if (r) + r = -EFAULT; + + goto out; + } + + /* copy first segment */ + uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); - while (len) { - uptr = to_guest ? (void __user *)to : (void __user *)from; - uptr = __gptr_to_uptr(vcpu, uptr, prefixing); - if (IS_ERR((void __force *)uptr)) - return -EFAULT; - _len = PAGE_SIZE - ((unsigned long)uptr & (PAGE_SIZE - 1)); - _len = min(_len, len); - if (to_guest) - rc = copy_to_user((void __user *) uptr, (void *)from, _len); - else - rc = copy_from_user((void *)to, (void __user *)uptr, _len); - if (rc) - return -EFAULT; - len -= _len; - from += _len; - to += _len; + size = PMD_SIZE - (guestdest & ~PMD_MASK); + + r = copy_to_user(uptr, from, size); + + if (r) { + r = -EFAULT; + goto out; + } + from += size; + n -= size; + guestdest += size; + + /* copy full segments */ + while (n >= PMD_SIZE) { + uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + r = copy_to_user(uptr, from, PMD_SIZE); + + if (r) { + r = -EFAULT; + goto out; + } + from += PMD_SIZE; + n -= PMD_SIZE; + guestdest += PMD_SIZE; + } + + /* copy the tail segment */ + if (n) { + uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + r = copy_to_user(uptr, from, n); + + if (r) + r = -EFAULT; + } +out: + return r; +} + +static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, + unsigned long guestdest, + void *from, unsigned long n) +{ + return __copy_to_guest_fast(vcpu, guestdest, from, n); +} + +static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest, + void *from, unsigned long n) +{ + unsigned long prefix = vcpu->arch.sie_block->prefix; + + if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE)) + goto slowpath; + + if ((guestdest < prefix) && (guestdest + n > prefix)) + goto slowpath; + + if ((guestdest < prefix + 2 * PAGE_SIZE) + && (guestdest + n > prefix + 2 * PAGE_SIZE)) + goto slowpath; + + if (guestdest < 2 * PAGE_SIZE) + guestdest += prefix; + else if ((guestdest >= prefix) && (guestdest < prefix + 2 * PAGE_SIZE)) + guestdest -= prefix; + + return __copy_to_guest_fast(vcpu, guestdest, from, n); +slowpath: + return __copy_to_guest_slow(vcpu, guestdest, from, n); +} + +static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to, + unsigned long guestsrc, + unsigned long n) +{ + int rc; + unsigned long i; + u8 *data = to; + + for (i = 0; i < n; i++) { + rc = get_guest_u8(vcpu, guestsrc++, data++); + if (rc < 0) + return rc; } return 0; } -#define copy_to_guest(vcpu, to, from, size) \ - __copy_guest(vcpu, to, (unsigned long)from, size, 1, 1) -#define copy_from_guest(vcpu, to, from, size) \ - __copy_guest(vcpu, (unsigned long)to, from, size, 0, 1) -#define copy_to_guest_absolute(vcpu, to, from, size) \ - __copy_guest(vcpu, to, (unsigned long)from, size, 1, 0) -#define copy_from_guest_absolute(vcpu, to, from, size) \ - __copy_guest(vcpu, (unsigned long)to, from, size, 0, 0) +static inline int __copy_from_guest_fast(struct kvm_vcpu *vcpu, void *to, + unsigned long guestsrc, + unsigned long n) +{ + int r; + void __user *uptr; + unsigned long size; + + if (guestsrc + n < guestsrc) + return -EFAULT; + + /* simple case: all within one segment table entry? */ + if ((guestsrc & PMD_MASK) == ((guestsrc+n) & PMD_MASK)) { + uptr = (void __user *) gmap_fault(guestsrc, vcpu->arch.gmap); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + r = copy_from_user(to, uptr, n); + + if (r) + r = -EFAULT; + + goto out; + } + + /* copy first segment */ + uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + size = PMD_SIZE - (guestsrc & ~PMD_MASK); + + r = copy_from_user(to, uptr, size); + + if (r) { + r = -EFAULT; + goto out; + } + to += size; + n -= size; + guestsrc += size; + + /* copy full segments */ + while (n >= PMD_SIZE) { + uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + r = copy_from_user(to, uptr, PMD_SIZE); + + if (r) { + r = -EFAULT; + goto out; + } + to += PMD_SIZE; + n -= PMD_SIZE; + guestsrc += PMD_SIZE; + } + + /* copy the tail segment */ + if (n) { + uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); + + if (IS_ERR((void __force *) uptr)) + return PTR_ERR((void __force *) uptr); + + r = copy_from_user(to, uptr, n); + + if (r) + r = -EFAULT; + } +out: + return r; +} + +static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to, + unsigned long guestsrc, + unsigned long n) +{ + return __copy_from_guest_fast(vcpu, to, guestsrc, n); +} + +static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to, + unsigned long guestsrc, unsigned long n) +{ + unsigned long prefix = vcpu->arch.sie_block->prefix; + + if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE)) + goto slowpath; -#endif /* __KVM_S390_GACCESS_H */ + if ((guestsrc < prefix) && (guestsrc + n > prefix)) + goto slowpath; + + if ((guestsrc < prefix + 2 * PAGE_SIZE) + && (guestsrc + n > prefix + 2 * PAGE_SIZE)) + goto slowpath; + + if (guestsrc < 2 * PAGE_SIZE) + guestsrc += prefix; + else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE)) + guestsrc -= prefix; + + return __copy_from_guest_fast(vcpu, to, guestsrc, n); +slowpath: + return __copy_from_guest_slow(vcpu, to, guestsrc, n); +} +#endif diff --git a/trunk/arch/s390/kvm/intercept.c b/trunk/arch/s390/kvm/intercept.c index b7d1b2edeeb3..f26ff1e31bdb 100644 --- a/trunk/arch/s390/kvm/intercept.c +++ b/trunk/arch/s390/kvm/intercept.c @@ -43,10 +43,12 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr); do { - rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg], - (u64 __user *) useraddr); - if (rc) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = get_guest_u64(vcpu, useraddr, + &vcpu->arch.sie_block->gcr[reg]); + if (rc == -EFAULT) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + break; + } useraddr += 8; if (reg == reg3) break; @@ -76,9 +78,11 @@ static int handle_lctl(struct kvm_vcpu *vcpu) reg = reg1; do { - rc = get_guest(vcpu, val, (u32 __user *) useraddr); - if (rc) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = get_guest_u32(vcpu, useraddr, &val); + if (rc == -EFAULT) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + break; + } vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; vcpu->arch.sie_block->gcr[reg] |= val; useraddr += 4; diff --git a/trunk/arch/s390/kvm/interrupt.c b/trunk/arch/s390/kvm/interrupt.c index 5c948177529e..37116a77cb4b 100644 --- a/trunk/arch/s390/kvm/interrupt.c +++ b/trunk/arch/s390/kvm/interrupt.c @@ -180,7 +180,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, struct kvm_s390_interrupt_info *inti) { const unsigned short table[] = { 2, 4, 4, 6 }; - int rc = 0; + int rc, exception = 0; switch (inti->type) { case KVM_S390_INT_EMERGENCY: @@ -188,41 +188,74 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_emergency_signal++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->emerg.code, 0); - rc = put_guest(vcpu, 0x1201, (u16 __user *)__LC_EXT_INT_CODE); - rc |= put_guest(vcpu, inti->emerg.code, - (u16 __user *)__LC_EXT_CPU_ADDR); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); + rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->emerg.code); + if (rc == -EFAULT) + exception = 1; + + rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_EXT_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; break; + case KVM_S390_INT_EXTERNAL_CALL: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); vcpu->stat.deliver_external_call++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->extcall.code, 0); - rc = put_guest(vcpu, 0x1202, (u16 __user *)__LC_EXT_INT_CODE); - rc |= put_guest(vcpu, inti->extcall.code, - (u16 __user *)__LC_EXT_CPU_ADDR); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); + rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->extcall.code); + if (rc == -EFAULT) + exception = 1; + + rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_EXT_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; break; + case KVM_S390_INT_SERVICE: VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", inti->ext.ext_params); vcpu->stat.deliver_service_signal++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->ext.ext_params, 0); - rc = put_guest(vcpu, 0x2401, (u16 __user *)__LC_EXT_INT_CODE); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - rc |= put_guest(vcpu, inti->ext.ext_params, - (u32 __user *)__LC_EXT_PARAMS); + rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401); + if (rc == -EFAULT) + exception = 1; + + rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_EXT_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); + if (rc == -EFAULT) + exception = 1; break; + case KVM_S390_INT_VIRTIO: VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx", inti->ext.ext_params, inti->ext.ext_params2); @@ -230,17 +263,34 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->ext.ext_params, inti->ext.ext_params2); - rc = put_guest(vcpu, 0x2603, (u16 __user *)__LC_EXT_INT_CODE); - rc |= put_guest(vcpu, 0x0d00, (u16 __user *)__LC_EXT_CPU_ADDR); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - rc |= put_guest(vcpu, inti->ext.ext_params, - (u32 __user *)__LC_EXT_PARAMS); - rc |= put_guest(vcpu, inti->ext.ext_params2, - (u64 __user *)__LC_EXT_PARAMS2); + rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, 0x0d00); + if (rc == -EFAULT) + exception = 1; + + rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_EXT_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u64(vcpu, __LC_EXT_PARAMS2, + inti->ext.ext_params2); + if (rc == -EFAULT) + exception = 1; break; + case KVM_S390_SIGP_STOP: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); vcpu->stat.deliver_stop_signal++; @@ -263,14 +313,18 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_restart_signal++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0, 0); - rc = copy_to_guest(vcpu, - offsetof(struct _lowcore, restart_old_psw), - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - offsetof(struct _lowcore, restart_psw), - sizeof(psw_t)); + rc = copy_to_guest(vcpu, offsetof(struct _lowcore, + restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + offsetof(struct _lowcore, restart_psw), sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); break; + case KVM_S390_PROGRAM_INT: VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x", inti->pgm.code, @@ -278,13 +332,24 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_program_int++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->pgm.code, 0); - rc = put_guest(vcpu, inti->pgm.code, (u16 __user *)__LC_PGM_INT_CODE); - rc |= put_guest(vcpu, table[vcpu->arch.sie_block->ipa >> 14], - (u16 __user *)__LC_PGM_ILC); - rc |= copy_to_guest(vcpu, __LC_PGM_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_PGM_NEW_PSW, sizeof(psw_t)); + rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u16(vcpu, __LC_PGM_ILC, + table[vcpu->arch.sie_block->ipa >> 14]); + if (rc == -EFAULT) + exception = 1; + + rc = copy_to_guest(vcpu, __LC_PGM_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_PGM_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; break; case KVM_S390_MCHK: @@ -293,13 +358,24 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, inti->mchk.cr14, inti->mchk.mcic); - rc = kvm_s390_vcpu_store_status(vcpu, - KVM_S390_STORE_STATUS_PREFIXED); - rc |= put_guest(vcpu, inti->mchk.mcic, (u64 __user *) __LC_MCCK_CODE); - rc |= copy_to_guest(vcpu, __LC_MCK_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_MCK_NEW_PSW, sizeof(psw_t)); + rc = kvm_s390_vcpu_store_status(vcpu, + KVM_S390_STORE_STATUS_PREFIXED); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u64(vcpu, __LC_MCCK_CODE, inti->mchk.mcic); + if (rc == -EFAULT) + exception = 1; + + rc = copy_to_guest(vcpu, __LC_MCK_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_MCK_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; break; case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: @@ -312,44 +388,67 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, vcpu->stat.deliver_io_int++; trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, param0, param1); - rc = put_guest(vcpu, inti->io.subchannel_id, - (u16 __user *) __LC_SUBCHANNEL_ID); - rc |= put_guest(vcpu, inti->io.subchannel_nr, - (u16 __user *) __LC_SUBCHANNEL_NR); - rc |= put_guest(vcpu, inti->io.io_int_parm, - (u32 __user *) __LC_IO_INT_PARM); - rc |= put_guest(vcpu, inti->io.io_int_word, - (u32 __user *) __LC_IO_INT_WORD); - rc |= copy_to_guest(vcpu, __LC_IO_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_IO_NEW_PSW, sizeof(psw_t)); + rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_ID, + inti->io.subchannel_id); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_NR, + inti->io.subchannel_nr); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u32(vcpu, __LC_IO_INT_PARM, + inti->io.io_int_parm); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u32(vcpu, __LC_IO_INT_WORD, + inti->io.io_int_word); + if (rc == -EFAULT) + exception = 1; + + rc = copy_to_guest(vcpu, __LC_IO_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_IO_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; break; } default: BUG(); } - if (rc) { + if (exception) { printk("kvm: The guest lowcore is not mapped during interrupt " - "delivery, killing userspace\n"); + "delivery, killing userspace\n"); do_exit(SIGKILL); } } static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu) { - int rc; + int rc, exception = 0; if (psw_extint_disabled(vcpu)) return 0; if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul)) return 0; - rc = put_guest(vcpu, 0x1004, (u16 __user *)__LC_EXT_INT_CODE); - rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - if (rc) { + rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1004); + if (rc == -EFAULT) + exception = 1; + rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_EXT_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + if (exception) { printk("kvm: The guest lowcore is not mapped during interrupt " "delivery, killing userspace\n"); do_exit(SIGKILL); diff --git a/trunk/arch/s390/kvm/kvm-s390.c b/trunk/arch/s390/kvm/kvm-s390.c index c1c7c683fa26..4cf35a0a79e7 100644 --- a/trunk/arch/s390/kvm/kvm-s390.c +++ b/trunk/arch/s390/kvm/kvm-s390.c @@ -142,16 +142,12 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_ONE_REG: case KVM_CAP_ENABLE_CAP: case KVM_CAP_S390_CSS_SUPPORT: - case KVM_CAP_IOEVENTFD: r = 1; break; case KVM_CAP_NR_VCPUS: case KVM_CAP_MAX_VCPUS: r = KVM_MAX_VCPUS; break; - case KVM_CAP_NR_MEMSLOTS: - r = KVM_USER_MEM_SLOTS; - break; case KVM_CAP_S390_COW: r = MACHINE_HAS_ESOP; break; @@ -636,7 +632,8 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) } else { VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); trace_kvm_s390_sie_fault(vcpu); - rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = 0; } } VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", @@ -977,13 +974,22 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) /* Section: memory related */ int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *memslot, + struct kvm_memory_slot old, struct kvm_userspace_memory_region *mem, - enum kvm_mr_change change) + bool user_alloc) { - /* A few sanity checks. We can have memory slots which have to be - located/ended at a segment boundary (1MB). The memory in userland is - ok to be fragmented into various different vmas. It is okay to mmap() - and munmap() stuff in this slot after doing this call at any time */ + /* A few sanity checks. We can have exactly one memory slot which has + to start at guest virtual zero and which has to be located at a + page boundary in userland and which has to end at a page boundary. + The memory in userland is ok to be fragmented into various different + vmas. It is okay to mmap() and munmap() stuff in this slot after + doing this call at any time */ + + if (mem->slot) + return -EINVAL; + + if (mem->guest_phys_addr) + return -EINVAL; if (mem->userspace_addr & 0xffffful) return -EINVAL; @@ -991,26 +997,19 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, if (mem->memory_size & 0xffffful) return -EINVAL; + if (!user_alloc) + return -EINVAL; + return 0; } void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old, - enum kvm_mr_change change) + struct kvm_memory_slot old, + bool user_alloc) { int rc; - /* If the basics of the memslot do not change, we do not want - * to update the gmap. Every update causes several unnecessary - * segment translation exceptions. This is usually handled just - * fine by the normal fault handler + gmap, but it will also - * cause faults on the prefix page of running guest CPUs. - */ - if (old->userspace_addr == mem->userspace_addr && - old->base_gfn * PAGE_SIZE == mem->guest_phys_addr && - old->npages * PAGE_SIZE == mem->memory_size) - return; rc = gmap_map_segment(kvm->arch.gmap, mem->userspace_addr, mem->guest_phys_addr, mem->memory_size); diff --git a/trunk/arch/s390/kvm/kvm-s390.h b/trunk/arch/s390/kvm/kvm-s390.h index efc14f687265..4d89d64a8161 100644 --- a/trunk/arch/s390/kvm/kvm-s390.h +++ b/trunk/arch/s390/kvm/kvm-s390.h @@ -110,12 +110,12 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer); void kvm_s390_tasklet(unsigned long parm); void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu); -int __must_check kvm_s390_inject_vm(struct kvm *kvm, - struct kvm_s390_interrupt *s390int); -int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, - struct kvm_s390_interrupt *s390int); -int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); -int __must_check kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); +int kvm_s390_inject_vm(struct kvm *kvm, + struct kvm_s390_interrupt *s390int); +int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, + struct kvm_s390_interrupt *s390int); +int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); +int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, u64 cr6, u64 schid); diff --git a/trunk/arch/s390/kvm/priv.c b/trunk/arch/s390/kvm/priv.c index 6bbd7b5a0bbe..0ef9894606e5 100644 --- a/trunk/arch/s390/kvm/priv.c +++ b/trunk/arch/s390/kvm/priv.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include @@ -37,24 +35,31 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu) operand2 = kvm_s390_get_base_disp_s(vcpu); /* must be word boundary */ - if (operand2 & 3) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + if (operand2 & 3) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } /* get the value */ - if (get_guest(vcpu, address, (u32 __user *) operand2)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + if (get_guest_u32(vcpu, operand2, &address)) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + goto out; + } address = address & 0x7fffe000u; /* make sure that the new value is valid memory */ if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || - (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + goto out; + } kvm_s390_set_prefix(vcpu, address); VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); trace_kvm_s390_handle_prefix(vcpu, 1, address); +out: return 0; } @@ -68,37 +73,49 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu) operand2 = kvm_s390_get_base_disp_s(vcpu); /* must be word boundary */ - if (operand2 & 3) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + if (operand2 & 3) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } address = vcpu->arch.sie_block->prefix; address = address & 0x7fffe000u; /* get the value */ - if (put_guest(vcpu, address, (u32 __user *)operand2)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + if (put_guest_u32(vcpu, operand2, address)) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + goto out; + } VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); trace_kvm_s390_handle_prefix(vcpu, 0, address); +out: return 0; } static int handle_store_cpu_address(struct kvm_vcpu *vcpu) { u64 useraddr; + int rc; vcpu->stat.instruction_stap++; useraddr = kvm_s390_get_base_disp_s(vcpu); - if (useraddr & 1) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + if (useraddr & 1) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } - if (put_guest(vcpu, vcpu->vcpu_id, (u16 __user *)useraddr)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id); + if (rc == -EFAULT) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + goto out; + } VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); trace_kvm_s390_handle_stap(vcpu, useraddr); +out: return 0; } @@ -112,38 +129,36 @@ static int handle_skey(struct kvm_vcpu *vcpu) static int handle_tpi(struct kvm_vcpu *vcpu) { - struct kvm_s390_interrupt_info *inti; u64 addr; + struct kvm_s390_interrupt_info *inti; int cc; addr = kvm_s390_get_base_disp_s(vcpu); - if (addr & 3) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - cc = 0; + inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->run->s.regs.crs[6], 0); - if (!inti) - goto no_interrupt; - cc = 1; - if (addr) { - /* - * Store the two-word I/O interruption code into the - * provided area. - */ - put_guest(vcpu, inti->io.subchannel_id, (u16 __user *) addr); - put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *) (addr + 2)); - put_guest(vcpu, inti->io.io_int_parm, (u32 __user *) (addr + 4)); - } else { - /* - * Store the three-word I/O interruption code into - * the appropriate lowcore area. - */ - put_guest(vcpu, inti->io.subchannel_id, (u16 __user *) __LC_SUBCHANNEL_ID); - put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *) __LC_SUBCHANNEL_NR); - put_guest(vcpu, inti->io.io_int_parm, (u32 __user *) __LC_IO_INT_PARM); - put_guest(vcpu, inti->io.io_int_word, (u32 __user *) __LC_IO_INT_WORD); - } + if (inti) { + if (addr) { + /* + * Store the two-word I/O interruption code into the + * provided area. + */ + put_guest_u16(vcpu, addr, inti->io.subchannel_id); + put_guest_u16(vcpu, addr + 2, inti->io.subchannel_nr); + put_guest_u32(vcpu, addr + 4, inti->io.io_int_parm); + } else { + /* + * Store the three-word I/O interruption code into + * the appropriate lowcore area. + */ + put_guest_u16(vcpu, 184, inti->io.subchannel_id); + put_guest_u16(vcpu, 186, inti->io.subchannel_nr); + put_guest_u32(vcpu, 188, inti->io.io_int_parm); + put_guest_u32(vcpu, 192, inti->io.io_int_word); + } + cc = 1; + } else + cc = 0; kfree(inti); -no_interrupt: /* Set condition code and we're done. */ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->arch.sie_block->gpsw.mask |= (cc & 3ul) << 44; @@ -215,10 +230,13 @@ static int handle_stfl(struct kvm_vcpu *vcpu) rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), &facility_list, sizeof(facility_list)); - if (rc) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - VCPU_EVENT(vcpu, 5, "store facility list value %x", facility_list); - trace_kvm_s390_handle_stfl(vcpu, facility_list); + if (rc == -EFAULT) + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + else { + VCPU_EVENT(vcpu, 5, "store facility list value %x", + facility_list); + trace_kvm_s390_handle_stfl(vcpu, facility_list); + } return 0; } @@ -231,80 +249,112 @@ static void handle_new_psw(struct kvm_vcpu *vcpu) #define PSW_MASK_ADDR_MODE (PSW_MASK_EA | PSW_MASK_BA) #define PSW_MASK_UNASSIGNED 0xb80800fe7fffffffUL -#define PSW_ADDR_24 0x0000000000ffffffUL +#define PSW_ADDR_24 0x00000000000fffffUL #define PSW_ADDR_31 0x000000007fffffffUL -static int is_valid_psw(psw_t *psw) { - if (psw->mask & PSW_MASK_UNASSIGNED) - return 0; - if ((psw->mask & PSW_MASK_ADDR_MODE) == PSW_MASK_BA) { - if (psw->addr & ~PSW_ADDR_31) - return 0; - } - if (!(psw->mask & PSW_MASK_ADDR_MODE) && (psw->addr & ~PSW_ADDR_24)) - return 0; - if ((psw->mask & PSW_MASK_ADDR_MODE) == PSW_MASK_EA) - return 0; - return 1; -} - int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu) { - psw_t *gpsw = &vcpu->arch.sie_block->gpsw; - psw_compat_t new_psw; u64 addr; + psw_compat_t new_psw; - if (gpsw->mask & PSW_MASK_PSTATE) + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OPERATION); + addr = kvm_s390_get_base_disp_s(vcpu); - if (addr & 7) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - if (!(new_psw.mask & PSW32_MASK_BASE)) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - gpsw->mask = (new_psw.mask & ~PSW32_MASK_BASE) << 32; - gpsw->mask |= new_psw.addr & PSW32_ADDR_AMODE; - gpsw->addr = new_psw.addr & ~PSW32_ADDR_AMODE; - if (!is_valid_psw(gpsw)) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + + if (addr & 7) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } + + if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + goto out; + } + + if (!(new_psw.mask & PSW32_MASK_BASE)) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } + + vcpu->arch.sie_block->gpsw.mask = + (new_psw.mask & ~PSW32_MASK_BASE) << 32; + vcpu->arch.sie_block->gpsw.addr = new_psw.addr; + + if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_UNASSIGNED) || + (!(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) && + (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_24)) || + ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == + PSW_MASK_EA)) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } + handle_new_psw(vcpu); +out: return 0; } static int handle_lpswe(struct kvm_vcpu *vcpu) { - psw_t new_psw; u64 addr; + psw_t new_psw; addr = kvm_s390_get_base_disp_s(vcpu); - if (addr & 7) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - vcpu->arch.sie_block->gpsw = new_psw; - if (!is_valid_psw(&vcpu->arch.sie_block->gpsw)) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + + if (addr & 7) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } + + if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + goto out; + } + + vcpu->arch.sie_block->gpsw.mask = new_psw.mask; + vcpu->arch.sie_block->gpsw.addr = new_psw.addr; + + if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_UNASSIGNED) || + (((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == + PSW_MASK_BA) && + (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_31)) || + (!(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) && + (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_24)) || + ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == + PSW_MASK_EA)) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } + handle_new_psw(vcpu); +out: return 0; } static int handle_stidp(struct kvm_vcpu *vcpu) { u64 operand2; + int rc; vcpu->stat.instruction_stidp++; operand2 = kvm_s390_get_base_disp_s(vcpu); - if (operand2 & 7) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + if (operand2 & 7) { + kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + goto out; + } - if (put_guest(vcpu, vcpu->arch.stidp_data, (u64 __user *)operand2)) - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + rc = put_guest_u64(vcpu, operand2, vcpu->arch.stidp_data); + if (rc == -EFAULT) { + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + goto out; + } VCPU_EVENT(vcpu, 5, "%s", "store cpu id"); +out: return 0; } @@ -344,9 +394,8 @@ static int handle_stsi(struct kvm_vcpu *vcpu) int fc = (vcpu->run->s.regs.gprs[0] & 0xf0000000) >> 28; int sel1 = vcpu->run->s.regs.gprs[0] & 0xff; int sel2 = vcpu->run->s.regs.gprs[1] & 0xffff; - unsigned long mem = 0; u64 operand2; - int rc = 0; + unsigned long mem; vcpu->stat.instruction_stsi++; VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2); @@ -365,37 +414,37 @@ static int handle_stsi(struct kvm_vcpu *vcpu) case 2: mem = get_zeroed_page(GFP_KERNEL); if (!mem) - goto out_no_data; + goto out_fail; if (stsi((void *) mem, fc, sel1, sel2)) - goto out_no_data; + goto out_mem; break; case 3: if (sel1 != 2 || sel2 != 2) - goto out_no_data; + goto out_fail; mem = get_zeroed_page(GFP_KERNEL); if (!mem) - goto out_no_data; + goto out_fail; handle_stsi_3_2_2(vcpu, (void *) mem); break; default: - goto out_no_data; + goto out_fail; } if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) { - rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - goto out_exception; + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + goto out_mem; } trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2); free_page(mem); vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->run->s.regs.gprs[0] = 0; return 0; -out_no_data: +out_mem: + free_page(mem); +out_fail: /* condition code 3 */ vcpu->arch.sie_block->gpsw.mask |= 3ul << 44; -out_exception: - free_page(mem); - return rc; + return 0; } static const intercept_handler_t b2_handlers[256] = { @@ -526,13 +575,20 @@ static int handle_tprot(struct kvm_vcpu *vcpu) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) return -EOPNOTSUPP; + + /* we must resolve the address without holding the mmap semaphore. + * This is ok since the userspace hypervisor is not supposed to change + * the mapping while the guest queries the memory. Otherwise the guest + * might crash or get wrong info anyway. */ + user_address = (unsigned long) __guestaddr_to_user(vcpu, address1); + down_read(¤t->mm->mmap_sem); - user_address = __gmap_translate(address1, vcpu->arch.gmap); - if (IS_ERR_VALUE(user_address)) - goto out_inject; vma = find_vma(current->mm, user_address); - if (!vma) - goto out_inject; + if (!vma) { + up_read(¤t->mm->mmap_sem); + return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + } + vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); if (!(vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_READ)) vcpu->arch.sie_block->gpsw.mask |= (1ul << 44); @@ -541,10 +597,6 @@ static int handle_tprot(struct kvm_vcpu *vcpu) up_read(¤t->mm->mmap_sem); return 0; - -out_inject: - up_read(¤t->mm->mmap_sem); - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); } int kvm_s390_handle_e5(struct kvm_vcpu *vcpu) diff --git a/trunk/arch/s390/lib/uaccess_pt.c b/trunk/arch/s390/lib/uaccess_pt.c index 50ea137a2d3c..466fb3383960 100644 --- a/trunk/arch/s390/lib/uaccess_pt.c +++ b/trunk/arch/s390/lib/uaccess_pt.c @@ -89,19 +89,16 @@ static unsigned long follow_table(struct mm_struct *mm, if (unlikely(*table & _REGION_ENTRY_INV)) return -0x39UL; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - /* fallthrough */ case _ASCE_TYPE_REGION2: table = table + ((address >> 42) & 0x7ff); if (unlikely(*table & _REGION_ENTRY_INV)) return -0x3aUL; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - /* fallthrough */ case _ASCE_TYPE_REGION3: table = table + ((address >> 31) & 0x7ff); if (unlikely(*table & _REGION_ENTRY_INV)) return -0x3bUL; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); - /* fallthrough */ case _ASCE_TYPE_SEGMENT: table = table + ((address >> 20) & 0x7ff); if (unlikely(*table & _SEGMENT_ENTRY_INV)) diff --git a/trunk/arch/s390/mm/Makefile b/trunk/arch/s390/mm/Makefile index 839592ca265c..640bea12303c 100644 --- a/trunk/arch/s390/mm/Makefile +++ b/trunk/arch/s390/mm/Makefile @@ -3,7 +3,7 @@ # obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o -obj-y += page-states.o gup.o extable.o pageattr.o mem_detect.o +obj-y += page-states.o gup.o extable.o pageattr.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/trunk/arch/s390/mm/init.c b/trunk/arch/s390/mm/init.c index 89ebae4008f2..0b09b2342302 100644 --- a/trunk/arch/s390/mm/init.c +++ b/trunk/arch/s390/mm/init.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -37,7 +36,6 @@ #include #include #include -#include pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); @@ -216,15 +214,6 @@ int arch_add_memory(int nid, u64 start, u64 size) return rc; } -unsigned long memory_block_size_bytes(void) -{ - /* - * Make sure the memory block size is always greater - * or equal than the memory increment size. - */ - return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp_get_rzm()); -} - #ifdef CONFIG_MEMORY_HOTREMOVE int arch_remove_memory(u64 start, u64 size) { diff --git a/trunk/arch/s390/mm/mem_detect.c b/trunk/arch/s390/mm/mem_detect.c deleted file mode 100644 index 3cbd3b8bf311..000000000000 --- a/trunk/arch/s390/mm/mem_detect.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright IBM Corp. 2008, 2009 - * - * Author(s): Heiko Carstens - */ - -#include -#include -#include -#include -#include - -#define ADDR2G (1ULL << 31) - -static void find_memory_chunks(struct mem_chunk chunk[], unsigned long maxsize) -{ - unsigned long long memsize, rnmax, rzm; - unsigned long addr = 0, size; - int i = 0, type; - - rzm = sclp_get_rzm(); - rnmax = sclp_get_rnmax(); - memsize = rzm * rnmax; - if (!rzm) - rzm = 1ULL << 17; - if (sizeof(long) == 4) { - rzm = min(ADDR2G, rzm); - memsize = memsize ? min(ADDR2G, memsize) : ADDR2G; - } - if (maxsize) - memsize = memsize ? min((unsigned long)memsize, maxsize) : maxsize; - do { - size = 0; - type = tprot(addr); - do { - size += rzm; - if (memsize && addr + size >= memsize) - break; - } while (type == tprot(addr + size)); - if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) { - if (memsize && (addr + size > memsize)) - size = memsize - addr; - chunk[i].addr = addr; - chunk[i].size = size; - chunk[i].type = type; - i++; - } - addr += size; - } while (addr < memsize && i < MEMORY_CHUNKS); -} - -/** - * detect_memory_layout - fill mem_chunk array with memory layout data - * @chunk: mem_chunk array to be filled - * @maxsize: maximum address where memory detection should stop - * - * Fills the passed in memory chunk array with the memory layout of the - * machine. The array must have a size of at least MEMORY_CHUNKS and will - * be fully initialized afterwards. - * If the maxsize paramater has a value > 0 memory detection will stop at - * that address. It is guaranteed that all chunks have an ending address - * that is smaller than maxsize. - * If maxsize is 0 all memory will be detected. - */ -void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize) -{ - unsigned long flags, flags_dat, cr0; - - memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); - /* - * Disable IRQs, DAT and low address protection so tprot does the - * right thing and we don't get scheduled away with low address - * protection disabled. - */ - local_irq_save(flags); - flags_dat = __arch_local_irq_stnsm(0xfb); - /* - * In case DAT was enabled, make sure chunk doesn't reside in vmalloc - * space. We have disabled DAT and any access to vmalloc area will - * cause an exception. - * If DAT was disabled we are called from early ipl code. - */ - if (test_bit(5, &flags_dat)) { - if (WARN_ON_ONCE(is_vmalloc_or_module_addr(chunk))) - goto out; - } - __ctl_store(cr0, 0, 0); - __ctl_clear_bit(0, 28); - find_memory_chunks(chunk, maxsize); - __ctl_load(cr0, 0, 0); -out: - __arch_local_irq_ssm(flags_dat); - local_irq_restore(flags); -} -EXPORT_SYMBOL(detect_memory_layout); - -/* - * Create memory hole with given address and size. - */ -void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr, - unsigned long size) -{ - int i; - - for (i = 0; i < MEMORY_CHUNKS; i++) { - struct mem_chunk *chunk = &mem_chunk[i]; - - if (chunk->size == 0) - continue; - if (addr > chunk->addr + chunk->size) - continue; - if (addr + size <= chunk->addr) - continue; - /* Split */ - if ((addr > chunk->addr) && - (addr + size < chunk->addr + chunk->size)) { - struct mem_chunk *new = chunk + 1; - - memmove(new, chunk, (MEMORY_CHUNKS-i-1) * sizeof(*new)); - new->addr = addr + size; - new->size = chunk->addr + chunk->size - new->addr; - chunk->size = addr - chunk->addr; - continue; - } else if ((addr <= chunk->addr) && - (addr + size >= chunk->addr + chunk->size)) { - memset(chunk, 0 , sizeof(*chunk)); - } else if (addr + size < chunk->addr + chunk->size) { - chunk->size = chunk->addr + chunk->size - addr - size; - chunk->addr = addr + size; - } else if (addr > chunk->addr) { - chunk->size = addr - chunk->addr; - } - } -} diff --git a/trunk/arch/s390/mm/pgtable.c b/trunk/arch/s390/mm/pgtable.c index 7805ddca833d..bd954e96f51c 100644 --- a/trunk/arch/s390/mm/pgtable.c +++ b/trunk/arch/s390/mm/pgtable.c @@ -454,8 +454,9 @@ unsigned long gmap_translate(unsigned long address, struct gmap *gmap) } EXPORT_SYMBOL_GPL(gmap_translate); -static int gmap_connect_pgtable(unsigned long address, unsigned long segment, - unsigned long *segment_ptr, struct gmap *gmap) +static int gmap_connect_pgtable(unsigned long segment, + unsigned long *segment_ptr, + struct gmap *gmap) { unsigned long vmaddr; struct vm_area_struct *vma; @@ -490,9 +491,7 @@ static int gmap_connect_pgtable(unsigned long address, unsigned long segment, /* Link gmap segment table entry location to page table. */ page = pmd_page(*pmd); mp = (struct gmap_pgtable *) page->index; - rmap->gmap = gmap; rmap->entry = segment_ptr; - rmap->vmaddr = address; spin_lock(&mm->page_table_lock); if (*segment_ptr == segment) { list_add(&rmap->list, &mp->mapper); @@ -554,7 +553,7 @@ unsigned long __gmap_fault(unsigned long address, struct gmap *gmap) if (!(segment & _SEGMENT_ENTRY_RO)) /* Nothing mapped in the gmap address space. */ break; - rc = gmap_connect_pgtable(address, segment, segment_ptr, gmap); + rc = gmap_connect_pgtable(segment, segment_ptr, gmap); if (rc) return rc; } @@ -620,118 +619,6 @@ void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap) } EXPORT_SYMBOL_GPL(gmap_discard); -static LIST_HEAD(gmap_notifier_list); -static DEFINE_SPINLOCK(gmap_notifier_lock); - -/** - * gmap_register_ipte_notifier - register a pte invalidation callback - * @nb: pointer to the gmap notifier block - */ -void gmap_register_ipte_notifier(struct gmap_notifier *nb) -{ - spin_lock(&gmap_notifier_lock); - list_add(&nb->list, &gmap_notifier_list); - spin_unlock(&gmap_notifier_lock); -} -EXPORT_SYMBOL_GPL(gmap_register_ipte_notifier); - -/** - * gmap_unregister_ipte_notifier - remove a pte invalidation callback - * @nb: pointer to the gmap notifier block - */ -void gmap_unregister_ipte_notifier(struct gmap_notifier *nb) -{ - spin_lock(&gmap_notifier_lock); - list_del_init(&nb->list); - spin_unlock(&gmap_notifier_lock); -} -EXPORT_SYMBOL_GPL(gmap_unregister_ipte_notifier); - -/** - * gmap_ipte_notify - mark a range of ptes for invalidation notification - * @gmap: pointer to guest mapping meta data structure - * @address: virtual address in the guest address space - * @len: size of area - * - * Returns 0 if for each page in the given range a gmap mapping exists and - * the invalidation notification could be set. If the gmap mapping is missing - * for one or more pages -EFAULT is returned. If no memory could be allocated - * -ENOMEM is returned. This function establishes missing page table entries. - */ -int gmap_ipte_notify(struct gmap *gmap, unsigned long start, unsigned long len) -{ - unsigned long addr; - spinlock_t *ptl; - pte_t *ptep, entry; - pgste_t pgste; - int rc = 0; - - if ((start & ~PAGE_MASK) || (len & ~PAGE_MASK)) - return -EINVAL; - down_read(&gmap->mm->mmap_sem); - while (len) { - /* Convert gmap address and connect the page tables */ - addr = __gmap_fault(start, gmap); - if (IS_ERR_VALUE(addr)) { - rc = addr; - break; - } - /* Get the page mapped */ - if (get_user_pages(current, gmap->mm, addr, 1, 1, 0, - NULL, NULL) != 1) { - rc = -EFAULT; - break; - } - /* Walk the process page table, lock and get pte pointer */ - ptep = get_locked_pte(gmap->mm, addr, &ptl); - if (unlikely(!ptep)) - continue; - /* Set notification bit in the pgste of the pte */ - entry = *ptep; - if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_RO)) == 0) { - pgste = pgste_get_lock(ptep); - pgste_val(pgste) |= RCP_IN_BIT; - pgste_set_unlock(ptep, pgste); - start += PAGE_SIZE; - len -= PAGE_SIZE; - } - spin_unlock(ptl); - } - up_read(&gmap->mm->mmap_sem); - return rc; -} -EXPORT_SYMBOL_GPL(gmap_ipte_notify); - -/** - * gmap_do_ipte_notify - call all invalidation callbacks for a specific pte. - * @mm: pointer to the process mm_struct - * @addr: virtual address in the process address space - * @pte: pointer to the page table entry - * - * This function is assumed to be called with the page table lock held - * for the pte to notify. - */ -void gmap_do_ipte_notify(struct mm_struct *mm, unsigned long addr, pte_t *pte) -{ - unsigned long segment_offset; - struct gmap_notifier *nb; - struct gmap_pgtable *mp; - struct gmap_rmap *rmap; - struct page *page; - - segment_offset = ((unsigned long) pte) & (255 * sizeof(pte_t)); - segment_offset = segment_offset * (4096 / sizeof(pte_t)); - page = pfn_to_page(__pa(pte) >> PAGE_SHIFT); - mp = (struct gmap_pgtable *) page->index; - spin_lock(&gmap_notifier_lock); - list_for_each_entry(rmap, &mp->mapper, list) { - list_for_each_entry(nb, &gmap_notifier_list, list) - nb->notifier_call(rmap->gmap, - rmap->vmaddr + segment_offset); - } - spin_unlock(&gmap_notifier_lock); -} - static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, unsigned long vmaddr) { diff --git a/trunk/arch/s390/mm/vmem.c b/trunk/arch/s390/mm/vmem.c index 8b268fcc4612..35837054f734 100644 --- a/trunk/arch/s390/mm/vmem.c +++ b/trunk/arch/s390/mm/vmem.c @@ -375,8 +375,9 @@ void __init vmem_map_init(void) ro_start = PFN_ALIGN((unsigned long)&_stext); ro_end = (unsigned long)&_eshared & PAGE_MASK; - for (i = 0; i < MEMORY_CHUNKS; i++) { - if (!memory_chunk[i].size) + for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { + if (memory_chunk[i].type == CHUNK_CRASHK || + memory_chunk[i].type == CHUNK_OLDMEM) continue; start = memory_chunk[i].addr; end = memory_chunk[i].addr + memory_chunk[i].size; @@ -411,6 +412,9 @@ static int __init vmem_convert_memory_chunk(void) for (i = 0; i < MEMORY_CHUNKS; i++) { if (!memory_chunk[i].size) continue; + if (memory_chunk[i].type == CHUNK_CRASHK || + memory_chunk[i].type == CHUNK_OLDMEM) + continue; seg = kzalloc(sizeof(*seg), GFP_KERNEL); if (!seg) panic("Out of memory...\n"); diff --git a/trunk/arch/sh/drivers/dma/dma-api.c b/trunk/arch/sh/drivers/dma/dma-api.c index c0eec08d8f95..851e5106e580 100644 --- a/trunk/arch/sh/drivers/dma/dma-api.c +++ b/trunk/arch/sh/drivers/dma/dma-api.c @@ -348,7 +348,7 @@ static const struct file_operations dma_proc_fops = { .open = dma_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; int register_dmac(struct dma_info *info) diff --git a/trunk/arch/sparc/Kconfig b/trunk/arch/sparc/Kconfig index a639c0d07b8b..f5041d741dea 100644 --- a/trunk/arch/sparc/Kconfig +++ b/trunk/arch/sparc/Kconfig @@ -99,9 +99,6 @@ config HAVE_LATENCYTOP_SUPPORT bool default y if SPARC64 -config ARCH_HIBERNATION_POSSIBLE - def_bool y if SPARC64 - config AUDIT_ARCH bool default y @@ -306,10 +303,6 @@ config ARCH_SPARSEMEM_DEFAULT source "mm/Kconfig" -if SPARC64 -source "kernel/power/Kconfig" -endif - config SCHED_SMT bool "SMT (Hyperthreading) scheduler support" depends on SPARC64 && SMP @@ -479,18 +472,7 @@ config LEON_PCI depends on PCI && SPARC_LEON default y -config SPARC_GRPCI1 - bool "GRPCI Host Bridge Support" - depends on LEON_PCI - default y - help - Say Y here to include the GRPCI Host Bridge Driver. The GRPCI - PCI host controller is typically found in GRLIB SPARC32/LEON - systems. The driver has one property (all_pci_errors) controlled - from the bootloader that makes the GRPCI to generate interrupts - on detected PCI Parity and System errors. - -config SPARC_GRPCI2 +config GRPCI2 bool "GRPCI2 Host Bridge Support" depends on LEON_PCI default y diff --git a/trunk/arch/sparc/Makefile b/trunk/arch/sparc/Makefile index 9ff423678cbc..541b8b075c7d 100644 --- a/trunk/arch/sparc/Makefile +++ b/trunk/arch/sparc/Makefile @@ -57,7 +57,6 @@ core-y += arch/sparc/ libs-y += arch/sparc/prom/ libs-y += arch/sparc/lib/ -drivers-$(CONFIG_PM) += arch/sparc/power/ drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/ boot := arch/sparc/boot diff --git a/trunk/arch/sparc/include/asm/cmpxchg_64.h b/trunk/arch/sparc/include/asm/cmpxchg_64.h index 4adefe8e2885..b30eb37294c5 100644 --- a/trunk/arch/sparc/include/asm/cmpxchg_64.h +++ b/trunk/arch/sparc/include/asm/cmpxchg_64.h @@ -141,6 +141,5 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr, BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg_local((ptr), (o), (n)); \ }) -#define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n)) #endif /* __ARCH_SPARC64_CMPXCHG__ */ diff --git a/trunk/arch/sparc/include/asm/head_32.h b/trunk/arch/sparc/include/asm/head_32.h index 5f1dbe315bc8..a76874838f61 100644 --- a/trunk/arch/sparc/include/asm/head_32.h +++ b/trunk/arch/sparc/include/asm/head_32.h @@ -55,15 +55,15 @@ /* The Get Condition Codes software trap for userland. */ #define GETCC_TRAP \ - b getcc_trap_handler; rd %psr, %l0; nop; nop; + b getcc_trap_handler; mov %psr, %l0; nop; nop; /* The Set Condition Codes software trap for userland. */ #define SETCC_TRAP \ - b setcc_trap_handler; rd %psr, %l0; nop; nop; + b setcc_trap_handler; mov %psr, %l0; nop; nop; /* The Get PSR software trap for userland. */ #define GETPSR_TRAP \ - rd %psr, %i0; jmp %l2; rett %l2 + 4; nop; + mov %psr, %i0; jmp %l2; rett %l2 + 4; nop; /* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and * gets handled with another macro. diff --git a/trunk/arch/sparc/include/asm/hibernate.h b/trunk/arch/sparc/include/asm/hibernate.h deleted file mode 100644 index 2ec34f842249..000000000000 --- a/trunk/arch/sparc/include/asm/hibernate.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * hibernate.h: Hibernaton support specific for sparc64. - * - * Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru) - */ - -#ifndef ___SPARC_HIBERNATE_H -#define ___SPARC_HIBERNATE_H - -struct saved_context { - unsigned long fp; - unsigned long cwp; - unsigned long wstate; - - unsigned long tick; - unsigned long pstate; - - unsigned long g4; - unsigned long g5; - unsigned long g6; -}; - -#endif diff --git a/trunk/arch/sparc/include/asm/leon_pci.h b/trunk/arch/sparc/include/asm/leon_pci.h index bfd3ab3092b5..f48527ebdd8f 100644 --- a/trunk/arch/sparc/include/asm/leon_pci.h +++ b/trunk/arch/sparc/include/asm/leon_pci.h @@ -12,7 +12,6 @@ struct leon_pci_info { struct pci_ops *ops; struct resource io_space; struct resource mem_space; - struct resource busn; int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); }; diff --git a/trunk/arch/sparc/include/asm/mmu_context_64.h b/trunk/arch/sparc/include/asm/mmu_context_64.h index 3d528f06e4b0..9191ca62ed9c 100644 --- a/trunk/arch/sparc/include/asm/mmu_context_64.h +++ b/trunk/arch/sparc/include/asm/mmu_context_64.h @@ -68,7 +68,7 @@ extern void smp_tsb_sync(struct mm_struct *mm); extern void __flush_tlb_mm(unsigned long, unsigned long); -/* Switch the current MM context. */ +/* Switch the current MM context. Interrupts are disabled. */ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) { unsigned long ctx_valid, flags; diff --git a/trunk/arch/sparc/include/asm/processor_64.h b/trunk/arch/sparc/include/asm/processor_64.h index 4c3f7f01c709..cce72ce4c334 100644 --- a/trunk/arch/sparc/include/asm/processor_64.h +++ b/trunk/arch/sparc/include/asm/processor_64.h @@ -18,6 +18,9 @@ #include #include +/* Don't hold the runqueue lock over context switch */ +#define __ARCH_WANT_UNLOCKED_CTXSW + /* The sparc has no problems with write protection */ #define wp_works_ok 1 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */ diff --git a/trunk/arch/sparc/kernel/Makefile b/trunk/arch/sparc/kernel/Makefile index d432fb20358e..5276fd4e9d03 100644 --- a/trunk/arch/sparc/kernel/Makefile +++ b/trunk/arch/sparc/kernel/Makefile @@ -74,8 +74,7 @@ obj-y += dma.o obj-$(CONFIG_PCIC_PCI) += pcic.o obj-$(CONFIG_LEON_PCI) += leon_pci.o -obj-$(CONFIG_SPARC_GRPCI2)+= leon_pci_grpci2.o -obj-$(CONFIG_SPARC_GRPCI1)+= leon_pci_grpci1.o +obj-$(CONFIG_GRPCI2) += leon_pci_grpci2.o obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o diff --git a/trunk/arch/sparc/kernel/asm-offsets.c b/trunk/arch/sparc/kernel/asm-offsets.c index 961b87f99e69..68f7e1118e9b 100644 --- a/trunk/arch/sparc/kernel/asm-offsets.c +++ b/trunk/arch/sparc/kernel/asm-offsets.c @@ -14,8 +14,6 @@ // #include #include -#include - #ifdef CONFIG_SPARC32 int sparc32_foo(void) { @@ -26,19 +24,6 @@ int sparc32_foo(void) #else int sparc64_foo(void) { -#ifdef CONFIG_HIBERNATION - BLANK(); - OFFSET(SC_REG_FP, saved_context, fp); - OFFSET(SC_REG_CWP, saved_context, cwp); - OFFSET(SC_REG_WSTATE, saved_context, wstate); - - OFFSET(SC_REG_TICK, saved_context, tick); - OFFSET(SC_REG_PSTATE, saved_context, pstate); - - OFFSET(SC_REG_G4, saved_context, g4); - OFFSET(SC_REG_G5, saved_context, g5); - OFFSET(SC_REG_G6, saved_context, g6); -#endif return 0; } #endif diff --git a/trunk/arch/sparc/kernel/leon_kernel.c b/trunk/arch/sparc/kernel/leon_kernel.c index 7c0231dabe44..87f60ee65433 100644 --- a/trunk/arch/sparc/kernel/leon_kernel.c +++ b/trunk/arch/sparc/kernel/leon_kernel.c @@ -213,7 +213,6 @@ unsigned int leon_build_device_irq(unsigned int real_irq, { unsigned int irq; unsigned long mask; - struct irq_desc *desc; irq = 0; mask = leon_get_irqmask(real_irq); @@ -227,12 +226,9 @@ unsigned int leon_build_device_irq(unsigned int real_irq, if (do_ack) mask |= LEON_DO_ACK_HW; - desc = irq_to_desc(irq); - if (!desc || !desc->handle_irq || desc->handle_irq == handle_bad_irq) { - irq_set_chip_and_handler_name(irq, &leon_irq, - flow_handler, name); - irq_set_chip_data(irq, (void *)mask); - } + irq_set_chip_and_handler_name(irq, &leon_irq, + flow_handler, name); + irq_set_chip_data(irq, (void *)mask); out: return irq; diff --git a/trunk/arch/sparc/kernel/leon_pci.c b/trunk/arch/sparc/kernel/leon_pci.c index 88aaaa57bb64..852dc8430528 100644 --- a/trunk/arch/sparc/kernel/leon_pci.c +++ b/trunk/arch/sparc/kernel/leon_pci.c @@ -29,8 +29,6 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info) pci_add_resource_offset(&resources, &info->io_space, info->io_space.start - 0x1000); pci_add_resource(&resources, &info->mem_space); - info->busn.flags = IORESOURCE_BUS; - pci_add_resource(&resources, &info->busn); root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info, &resources); diff --git a/trunk/arch/sparc/kernel/leon_pci_grpci1.c b/trunk/arch/sparc/kernel/leon_pci_grpci1.c deleted file mode 100644 index 7739a54315e2..000000000000 --- a/trunk/arch/sparc/kernel/leon_pci_grpci1.c +++ /dev/null @@ -1,724 +0,0 @@ -/* - * leon_pci_grpci1.c: GRPCI1 Host PCI driver - * - * Copyright (C) 2013 Aeroflex Gaisler AB - * - * This GRPCI1 driver does not support PCI interrupts taken from - * GPIO pins. Interrupt generation at PCI parity and system error - * detection is by default turned off since some GRPCI1 cores does - * not support detection. It can be turned on from the bootloader - * using the all_pci_errors property. - * - * Contributors: Daniel Hellstrom - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "irq.h" - -/* Enable/Disable Debugging Configuration Space Access */ -#undef GRPCI1_DEBUG_CFGACCESS - -/* - * GRPCI1 APB Register MAP - */ -struct grpci1_regs { - unsigned int cfg_stat; /* 0x00 Configuration / Status */ - unsigned int bar0; /* 0x04 BAR0 (RO) */ - unsigned int page0; /* 0x08 PAGE0 (RO) */ - unsigned int bar1; /* 0x0C BAR1 (RO) */ - unsigned int page1; /* 0x10 PAGE1 */ - unsigned int iomap; /* 0x14 IO Map */ - unsigned int stat_cmd; /* 0x18 PCI Status & Command (RO) */ - unsigned int irq; /* 0x1C Interrupt register */ -}; - -#define REGLOAD(a) (be32_to_cpu(__raw_readl(&(a)))) -#define REGSTORE(a, v) (__raw_writel(cpu_to_be32(v), &(a))) - -#define PAGE0_BTEN_BIT 0 -#define PAGE0_BTEN (1 << PAGE0_BTEN_BIT) - -#define CFGSTAT_HOST_BIT 13 -#define CFGSTAT_CTO_BIT 8 -#define CFGSTAT_HOST (1 << CFGSTAT_HOST_BIT) -#define CFGSTAT_CTO (1 << CFGSTAT_CTO_BIT) - -#define IRQ_DPE (1 << 9) -#define IRQ_SSE (1 << 8) -#define IRQ_RMA (1 << 7) -#define IRQ_RTA (1 << 6) -#define IRQ_STA (1 << 5) -#define IRQ_DPED (1 << 4) -#define IRQ_INTD (1 << 3) -#define IRQ_INTC (1 << 2) -#define IRQ_INTB (1 << 1) -#define IRQ_INTA (1 << 0) -#define IRQ_DEF_ERRORS (IRQ_RMA | IRQ_RTA | IRQ_STA) -#define IRQ_ALL_ERRORS (IRQ_DPED | IRQ_DEF_ERRORS | IRQ_SSE | IRQ_DPE) -#define IRQ_INTX (IRQ_INTA | IRQ_INTB | IRQ_INTC | IRQ_INTD) -#define IRQ_MASK_BIT 16 - -#define DEF_PCI_ERRORS (PCI_STATUS_SIG_TARGET_ABORT | \ - PCI_STATUS_REC_TARGET_ABORT | \ - PCI_STATUS_REC_MASTER_ABORT) -#define ALL_PCI_ERRORS (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY | \ - PCI_STATUS_SIG_SYSTEM_ERROR | DEF_PCI_ERRORS) - -#define TGT 256 - -struct grpci1_priv { - struct leon_pci_info info; /* must be on top of this structure */ - struct grpci1_regs *regs; /* GRPCI register map */ - struct device *dev; - int pci_err_mask; /* STATUS register error mask */ - int irq; /* LEON irqctrl GRPCI IRQ */ - unsigned char irq_map[4]; /* GRPCI nexus PCI INTX# IRQs */ - unsigned int irq_err; /* GRPCI nexus Virt Error IRQ */ - - /* AHB PCI Windows */ - unsigned long pci_area; /* MEMORY */ - unsigned long pci_area_end; - unsigned long pci_io; /* I/O */ - unsigned long pci_conf; /* CONFIGURATION */ - unsigned long pci_conf_end; - unsigned long pci_io_va; -}; - -static struct grpci1_priv *grpci1priv; - -static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, - unsigned int devfn, int where, u32 val); - -int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - struct grpci1_priv *priv = dev->bus->sysdata; - int irq_group; - - /* Use default IRQ decoding on PCI BUS0 according slot numbering */ - irq_group = slot & 0x3; - pin = ((pin - 1) + irq_group) & 0x3; - - return priv->irq_map[pin]; -} - -static int grpci1_cfg_r32(struct grpci1_priv *priv, unsigned int bus, - unsigned int devfn, int where, u32 *val) -{ - u32 *pci_conf, tmp, cfg; - - if (where & 0x3) - return -EINVAL; - - if (bus == 0) { - devfn += (0x8 * 6); /* start at AD16=Device0 */ - } else if (bus == TGT) { - bus = 0; - devfn = 0; /* special case: bridge controller itself */ - } - - /* Select bus */ - cfg = REGLOAD(priv->regs->cfg_stat); - REGSTORE(priv->regs->cfg_stat, (cfg & ~(0xf << 23)) | (bus << 23)); - - /* do read access */ - pci_conf = (u32 *) (priv->pci_conf | (devfn << 8) | (where & 0xfc)); - tmp = LEON3_BYPASS_LOAD_PA(pci_conf); - - /* check if master abort was received */ - if (REGLOAD(priv->regs->cfg_stat) & CFGSTAT_CTO) { - *val = 0xffffffff; - /* Clear Master abort bit in PCI cfg space (is set) */ - tmp = REGLOAD(priv->regs->stat_cmd); - grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, tmp); - } else { - /* Bus always little endian (unaffected by byte-swapping) */ - *val = flip_dword(tmp); - } - - return 0; -} - -static int grpci1_cfg_r16(struct grpci1_priv *priv, unsigned int bus, - unsigned int devfn, int where, u32 *val) -{ - u32 v; - int ret; - - if (where & 0x1) - return -EINVAL; - ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); - *val = 0xffff & (v >> (8 * (where & 0x3))); - return ret; -} - -static int grpci1_cfg_r8(struct grpci1_priv *priv, unsigned int bus, - unsigned int devfn, int where, u32 *val) -{ - u32 v; - int ret; - - ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); - *val = 0xff & (v >> (8 * (where & 3))); - - return ret; -} - -static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, - unsigned int devfn, int where, u32 val) -{ - unsigned int *pci_conf; - u32 cfg; - - if (where & 0x3) - return -EINVAL; - - if (bus == 0) { - devfn += (0x8 * 6); /* start at AD16=Device0 */ - } else if (bus == TGT) { - bus = 0; - devfn = 0; /* special case: bridge controller itself */ - } - - /* Select bus */ - cfg = REGLOAD(priv->regs->cfg_stat); - REGSTORE(priv->regs->cfg_stat, (cfg & ~(0xf << 23)) | (bus << 23)); - - pci_conf = (unsigned int *) (priv->pci_conf | - (devfn << 8) | (where & 0xfc)); - LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val)); - - return 0; -} - -static int grpci1_cfg_w16(struct grpci1_priv *priv, unsigned int bus, - unsigned int devfn, int where, u32 val) -{ - int ret; - u32 v; - - if (where & 0x1) - return -EINVAL; - ret = grpci1_cfg_r32(priv, bus, devfn, where&~3, &v); - if (ret) - return ret; - v = (v & ~(0xffff << (8 * (where & 0x3)))) | - ((0xffff & val) << (8 * (where & 0x3))); - return grpci1_cfg_w32(priv, bus, devfn, where & ~0x3, v); -} - -static int grpci1_cfg_w8(struct grpci1_priv *priv, unsigned int bus, - unsigned int devfn, int where, u32 val) -{ - int ret; - u32 v; - - ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); - if (ret != 0) - return ret; - v = (v & ~(0xff << (8 * (where & 0x3)))) | - ((0xff & val) << (8 * (where & 0x3))); - return grpci1_cfg_w32(priv, bus, devfn, where & ~0x3, v); -} - -/* Read from Configuration Space. When entering here the PCI layer has taken - * the pci_lock spinlock and IRQ is off. - */ -static int grpci1_read_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - struct grpci1_priv *priv = grpci1priv; - unsigned int busno = bus->number; - int ret; - - if (PCI_SLOT(devfn) > 15 || busno > 15) { - *val = ~0; - return 0; - } - - switch (size) { - case 1: - ret = grpci1_cfg_r8(priv, busno, devfn, where, val); - break; - case 2: - ret = grpci1_cfg_r16(priv, busno, devfn, where, val); - break; - case 4: - ret = grpci1_cfg_r32(priv, busno, devfn, where, val); - break; - default: - ret = -EINVAL; - break; - } - -#ifdef GRPCI1_DEBUG_CFGACCESS - printk(KERN_INFO - "grpci1_read_config: [%02x:%02x:%x] ofs=%d val=%x size=%d\n", - busno, PCI_SLOT(devfn), PCI_FUNC(devfn), where, *val, size); -#endif - - return ret; -} - -/* Write to Configuration Space. When entering here the PCI layer has taken - * the pci_lock spinlock and IRQ is off. - */ -static int grpci1_write_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - struct grpci1_priv *priv = grpci1priv; - unsigned int busno = bus->number; - - if (PCI_SLOT(devfn) > 15 || busno > 15) - return 0; - -#ifdef GRPCI1_DEBUG_CFGACCESS - printk(KERN_INFO - "grpci1_write_config: [%02x:%02x:%x] ofs=%d size=%d val=%x\n", - busno, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); -#endif - - switch (size) { - default: - return -EINVAL; - case 1: - return grpci1_cfg_w8(priv, busno, devfn, where, val); - case 2: - return grpci1_cfg_w16(priv, busno, devfn, where, val); - case 4: - return grpci1_cfg_w32(priv, busno, devfn, where, val); - } -} - -static struct pci_ops grpci1_ops = { - .read = grpci1_read_config, - .write = grpci1_write_config, -}; - -/* GENIRQ IRQ chip implementation for grpci1 irqmode=0..2. In configuration - * 3 where all PCI Interrupts has a separate IRQ on the system IRQ controller - * this is not needed and the standard IRQ controller can be used. - */ - -static void grpci1_mask_irq(struct irq_data *data) -{ - u32 irqidx; - struct grpci1_priv *priv = grpci1priv; - - irqidx = (u32)data->chip_data - 1; - if (irqidx > 3) /* only mask PCI interrupts here */ - return; - irqidx += IRQ_MASK_BIT; - - REGSTORE(priv->regs->irq, REGLOAD(priv->regs->irq) & ~(1 << irqidx)); -} - -static void grpci1_unmask_irq(struct irq_data *data) -{ - u32 irqidx; - struct grpci1_priv *priv = grpci1priv; - - irqidx = (u32)data->chip_data - 1; - if (irqidx > 3) /* only unmask PCI interrupts here */ - return; - irqidx += IRQ_MASK_BIT; - - REGSTORE(priv->regs->irq, REGLOAD(priv->regs->irq) | (1 << irqidx)); -} - -static unsigned int grpci1_startup_irq(struct irq_data *data) -{ - grpci1_unmask_irq(data); - return 0; -} - -static void grpci1_shutdown_irq(struct irq_data *data) -{ - grpci1_mask_irq(data); -} - -static struct irq_chip grpci1_irq = { - .name = "grpci1", - .irq_startup = grpci1_startup_irq, - .irq_shutdown = grpci1_shutdown_irq, - .irq_mask = grpci1_mask_irq, - .irq_unmask = grpci1_unmask_irq, -}; - -/* Handle one or multiple IRQs from the PCI core */ -static void grpci1_pci_flow_irq(unsigned int irq, struct irq_desc *desc) -{ - struct grpci1_priv *priv = grpci1priv; - int i, ack = 0; - unsigned int irqreg; - - irqreg = REGLOAD(priv->regs->irq); - irqreg = (irqreg >> IRQ_MASK_BIT) & irqreg; - - /* Error Interrupt? */ - if (irqreg & IRQ_ALL_ERRORS) { - generic_handle_irq(priv->irq_err); - ack = 1; - } - - /* PCI Interrupt? */ - if (irqreg & IRQ_INTX) { - /* Call respective PCI Interrupt handler */ - for (i = 0; i < 4; i++) { - if (irqreg & (1 << i)) - generic_handle_irq(priv->irq_map[i]); - } - ack = 1; - } - - /* - * Call "first level" IRQ chip end-of-irq handler. It will ACK LEON IRQ - * Controller, this must be done after IRQ sources have been handled to - * avoid double IRQ generation - */ - if (ack) - desc->irq_data.chip->irq_eoi(&desc->irq_data); -} - -/* Create a virtual IRQ */ -static unsigned int grpci1_build_device_irq(unsigned int irq) -{ - unsigned int virq = 0, pil; - - pil = 1 << 8; - virq = irq_alloc(irq, pil); - if (virq == 0) - goto out; - - irq_set_chip_and_handler_name(virq, &grpci1_irq, handle_simple_irq, - "pcilvl"); - irq_set_chip_data(virq, (void *)irq); - -out: - return virq; -} - -/* - * Initialize mappings AMBA<->PCI, clear IRQ state, setup PCI interface - * - * Target BARs: - * BAR0: unused in this implementation - * BAR1: peripheral DMA to host's memory (size at least 256MByte) - * BAR2..BAR5: not implemented in hardware - */ -void grpci1_hw_init(struct grpci1_priv *priv) -{ - u32 ahbadr, bar_sz, data, pciadr; - struct grpci1_regs *regs = priv->regs; - - /* set 1:1 mapping between AHB -> PCI memory space */ - REGSTORE(regs->cfg_stat, priv->pci_area & 0xf0000000); - - /* map PCI accesses to target BAR1 to Linux kernel memory 1:1 */ - ahbadr = 0xf0000000 & (u32)__pa(PAGE_ALIGN((unsigned long) &_end)); - REGSTORE(regs->page1, ahbadr); - - /* translate I/O accesses to 0, I/O Space always @ PCI low 64Kbytes */ - REGSTORE(regs->iomap, REGLOAD(regs->iomap) & 0x0000ffff); - - /* disable and clear pending interrupts */ - REGSTORE(regs->irq, 0); - - /* Setup BAR0 outside access range so that it does not conflict with - * peripheral DMA. There is no need to set up the PAGE0 register. - */ - grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0, 0xffffffff); - grpci1_cfg_r32(priv, TGT, 0, PCI_BASE_ADDRESS_0, &bar_sz); - bar_sz = ~bar_sz + 1; - pciadr = priv->pci_area - bar_sz; - grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0, pciadr); - - /* - * Setup the Host's PCI Target BAR1 for other peripherals to access, - * and do DMA to the host's memory. - */ - grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_1, ahbadr); - - /* - * Setup Latency Timer and cache line size. Default cache line - * size will result in poor performance (256 word fetches), 0xff - * will set it according to the max size of the PCI FIFO. - */ - grpci1_cfg_w8(priv, TGT, 0, PCI_CACHE_LINE_SIZE, 0xff); - grpci1_cfg_w8(priv, TGT, 0, PCI_LATENCY_TIMER, 0x40); - - /* set as bus master, enable pci memory responses, clear status bits */ - grpci1_cfg_r32(priv, TGT, 0, PCI_COMMAND, &data); - data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, data); -} - -static irqreturn_t grpci1_jump_interrupt(int irq, void *arg) -{ - struct grpci1_priv *priv = arg; - dev_err(priv->dev, "Jump IRQ happened\n"); - return IRQ_NONE; -} - -/* Handle GRPCI1 Error Interrupt */ -static irqreturn_t grpci1_err_interrupt(int irq, void *arg) -{ - struct grpci1_priv *priv = arg; - u32 status; - - grpci1_cfg_r16(priv, TGT, 0, PCI_STATUS, &status); - status &= priv->pci_err_mask; - - if (status == 0) - return IRQ_NONE; - - if (status & PCI_STATUS_PARITY) - dev_err(priv->dev, "Data Parity Error\n"); - - if (status & PCI_STATUS_SIG_TARGET_ABORT) - dev_err(priv->dev, "Signalled Target Abort\n"); - - if (status & PCI_STATUS_REC_TARGET_ABORT) - dev_err(priv->dev, "Received Target Abort\n"); - - if (status & PCI_STATUS_REC_MASTER_ABORT) - dev_err(priv->dev, "Received Master Abort\n"); - - if (status & PCI_STATUS_SIG_SYSTEM_ERROR) - dev_err(priv->dev, "Signalled System Error\n"); - - if (status & PCI_STATUS_DETECTED_PARITY) - dev_err(priv->dev, "Parity Error\n"); - - /* Clear handled INT TYPE IRQs */ - grpci1_cfg_w16(priv, TGT, 0, PCI_STATUS, status); - - return IRQ_HANDLED; -} - -static int grpci1_of_probe(struct platform_device *ofdev) -{ - struct grpci1_regs *regs; - struct grpci1_priv *priv; - int err, len; - const int *tmp; - u32 cfg, size, err_mask; - struct resource *res; - - if (grpci1priv) { - dev_err(&ofdev->dev, "only one GRPCI1 supported\n"); - return -ENODEV; - } - - if (ofdev->num_resources < 3) { - dev_err(&ofdev->dev, "not enough APB/AHB resources\n"); - return -EIO; - } - - priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&ofdev->dev, "memory allocation failed\n"); - return -ENOMEM; - } - platform_set_drvdata(ofdev, priv); - priv->dev = &ofdev->dev; - - /* find device register base address */ - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); - regs = devm_request_and_ioremap(&ofdev->dev, res); - if (!regs) { - dev_err(&ofdev->dev, "io-regs mapping failed\n"); - return -EADDRNOTAVAIL; - } - - /* - * check that we're in Host Slot and that we can act as a Host Bridge - * and not only as target/peripheral. - */ - cfg = REGLOAD(regs->cfg_stat); - if ((cfg & CFGSTAT_HOST) == 0) { - dev_err(&ofdev->dev, "not in host system slot\n"); - return -EIO; - } - - /* check that BAR1 support 256 MByte so that we can map kernel space */ - REGSTORE(regs->page1, 0xffffffff); - size = ~REGLOAD(regs->page1) + 1; - if (size < 0x10000000) { - dev_err(&ofdev->dev, "BAR1 must be at least 256MByte\n"); - return -EIO; - } - - /* hardware must support little-endian PCI (byte-twisting) */ - if ((REGLOAD(regs->page0) & PAGE0_BTEN) == 0) { - dev_err(&ofdev->dev, "byte-twisting is required\n"); - return -EIO; - } - - priv->regs = regs; - priv->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); - dev_info(&ofdev->dev, "host found at 0x%p, irq%d\n", regs, priv->irq); - - /* Find PCI Memory, I/O and Configuration Space Windows */ - priv->pci_area = ofdev->resource[1].start; - priv->pci_area_end = ofdev->resource[1].end+1; - priv->pci_io = ofdev->resource[2].start; - priv->pci_conf = ofdev->resource[2].start + 0x10000; - priv->pci_conf_end = priv->pci_conf + 0x10000; - priv->pci_io_va = (unsigned long)ioremap(priv->pci_io, 0x10000); - if (!priv->pci_io_va) { - dev_err(&ofdev->dev, "unable to map PCI I/O area\n"); - return -EIO; - } - - printk(KERN_INFO - "GRPCI1: MEMORY SPACE [0x%08lx - 0x%08lx]\n" - " I/O SPACE [0x%08lx - 0x%08lx]\n" - " CONFIG SPACE [0x%08lx - 0x%08lx]\n", - priv->pci_area, priv->pci_area_end-1, - priv->pci_io, priv->pci_conf-1, - priv->pci_conf, priv->pci_conf_end-1); - - /* - * I/O Space resources in I/O Window mapped into Virtual Adr Space - * We never use low 4KB because some devices seem have problems using - * address 0. - */ - priv->info.io_space.name = "GRPCI1 PCI I/O Space"; - priv->info.io_space.start = priv->pci_io_va + 0x1000; - priv->info.io_space.end = priv->pci_io_va + 0x10000 - 1; - priv->info.io_space.flags = IORESOURCE_IO; - - /* - * grpci1 has no prefetchable memory, map everything as - * non-prefetchable memory - */ - priv->info.mem_space.name = "GRPCI1 PCI MEM Space"; - priv->info.mem_space.start = priv->pci_area; - priv->info.mem_space.end = priv->pci_area_end - 1; - priv->info.mem_space.flags = IORESOURCE_MEM; - - if (request_resource(&iomem_resource, &priv->info.mem_space) < 0) { - dev_err(&ofdev->dev, "unable to request PCI memory area\n"); - err = -ENOMEM; - goto err1; - } - - if (request_resource(&ioport_resource, &priv->info.io_space) < 0) { - dev_err(&ofdev->dev, "unable to request PCI I/O area\n"); - err = -ENOMEM; - goto err2; - } - - /* setup maximum supported PCI buses */ - priv->info.busn.name = "GRPCI1 busn"; - priv->info.busn.start = 0; - priv->info.busn.end = 15; - - grpci1priv = priv; - - /* Initialize hardware */ - grpci1_hw_init(priv); - - /* - * Get PCI Interrupt to System IRQ mapping and setup IRQ handling - * Error IRQ. All PCI and PCI-Error interrupts are shared using the - * same system IRQ. - */ - leon_update_virq_handling(priv->irq, grpci1_pci_flow_irq, "pcilvl", 0); - - priv->irq_map[0] = grpci1_build_device_irq(1); - priv->irq_map[1] = grpci1_build_device_irq(2); - priv->irq_map[2] = grpci1_build_device_irq(3); - priv->irq_map[3] = grpci1_build_device_irq(4); - priv->irq_err = grpci1_build_device_irq(5); - - printk(KERN_INFO " PCI INTA..D#: IRQ%d, IRQ%d, IRQ%d, IRQ%d\n", - priv->irq_map[0], priv->irq_map[1], priv->irq_map[2], - priv->irq_map[3]); - - /* Enable IRQs on LEON IRQ controller */ - err = devm_request_irq(&ofdev->dev, priv->irq, grpci1_jump_interrupt, 0, - "GRPCI1_JUMP", priv); - if (err) { - dev_err(&ofdev->dev, "ERR IRQ request failed: %d\n", err); - goto err3; - } - - /* Setup IRQ handler for access errors */ - err = devm_request_irq(&ofdev->dev, priv->irq_err, - grpci1_err_interrupt, IRQF_SHARED, "GRPCI1_ERR", - priv); - if (err) { - dev_err(&ofdev->dev, "ERR VIRQ request failed: %d\n", err); - goto err3; - } - - tmp = of_get_property(ofdev->dev.of_node, "all_pci_errors", &len); - if (tmp && (len == 4)) { - priv->pci_err_mask = ALL_PCI_ERRORS; - err_mask = IRQ_ALL_ERRORS << IRQ_MASK_BIT; - } else { - priv->pci_err_mask = DEF_PCI_ERRORS; - err_mask = IRQ_DEF_ERRORS << IRQ_MASK_BIT; - } - - /* - * Enable Error Interrupts. PCI interrupts are unmasked once request_irq - * is called by the PCI Device drivers - */ - REGSTORE(regs->irq, err_mask); - - /* Init common layer and scan buses */ - priv->info.ops = &grpci1_ops; - priv->info.map_irq = grpci1_map_irq; - leon_pci_init(ofdev, &priv->info); - - return 0; - -err3: - release_resource(&priv->info.io_space); -err2: - release_resource(&priv->info.mem_space); -err1: - iounmap((void *)priv->pci_io_va); - grpci1priv = NULL; - return err; -} - -static struct of_device_id grpci1_of_match[] = { - { - .name = "GAISLER_PCIFBRG", - }, - { - .name = "01_014", - }, - {}, -}; - -static struct platform_driver grpci1_of_driver = { - .driver = { - .name = "grpci1", - .owner = THIS_MODULE, - .of_match_table = grpci1_of_match, - }, - .probe = grpci1_of_probe, -}; - -static int __init grpci1_init(void) -{ - return platform_driver_register(&grpci1_of_driver); -} - -subsys_initcall(grpci1_init); diff --git a/trunk/arch/sparc/kernel/leon_pci_grpci2.c b/trunk/arch/sparc/kernel/leon_pci_grpci2.c index 5f0402aab7fb..4d1487138d26 100644 --- a/trunk/arch/sparc/kernel/leon_pci_grpci2.c +++ b/trunk/arch/sparc/kernel/leon_pci_grpci2.c @@ -799,11 +799,6 @@ static int grpci2_of_probe(struct platform_device *ofdev) if (request_resource(&ioport_resource, &priv->info.io_space) < 0) goto err4; - /* setup maximum supported PCI buses */ - priv->info.busn.name = "GRPCI2 busn"; - priv->info.busn.start = 0; - priv->info.busn.end = 255; - grpci2_hw_init(priv); /* diff --git a/trunk/arch/sparc/kernel/leon_pmc.c b/trunk/arch/sparc/kernel/leon_pmc.c index bdf53d9a8d46..708bca435219 100644 --- a/trunk/arch/sparc/kernel/leon_pmc.c +++ b/trunk/arch/sparc/kernel/leon_pmc.c @@ -48,7 +48,7 @@ void pmc_leon_idle_fixup(void) */ register unsigned int address = (unsigned int)leon3_irqctrl_regs; __asm__ __volatile__ ( - "wr %%g0, %%asr19\n" + "mov %%g0, %%asr19\n" "lda [%0] %1, %%g0\n" : : "r"(address), "i"(ASI_LEON_BYPASS)); @@ -61,7 +61,7 @@ void pmc_leon_idle_fixup(void) void pmc_leon_idle(void) { /* For systems without power-down, this will be no-op */ - __asm__ __volatile__ ("wr %g0, %asr19\n\t"); + __asm__ __volatile__ ("mov %g0, %asr19\n\t"); } /* Install LEON Power Down function */ diff --git a/trunk/arch/sparc/kernel/vio.c b/trunk/arch/sparc/kernel/vio.c index 8647fcc5ca6c..3e244f31e56b 100644 --- a/trunk/arch/sparc/kernel/vio.c +++ b/trunk/arch/sparc/kernel/vio.c @@ -342,7 +342,6 @@ static void vio_remove(struct mdesc_handle *hp, u64 node) printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev)); device_unregister(dev); - put_device(dev); } } diff --git a/trunk/arch/sparc/mm/init_64.c b/trunk/arch/sparc/mm/init_64.c index cf72a8a5b3aa..6ac99d64a13c 100644 --- a/trunk/arch/sparc/mm/init_64.c +++ b/trunk/arch/sparc/mm/init_64.c @@ -681,9 +681,10 @@ void get_new_mmu_context(struct mm_struct *mm) { unsigned long ctx, new_ctx; unsigned long orig_pgsz_bits; + unsigned long flags; int new_version; - spin_lock(&ctx_alloc_lock); + spin_lock_irqsave(&ctx_alloc_lock, flags); orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK); ctx = (tlb_context_cache + 1) & CTX_NR_MASK; new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx); @@ -719,7 +720,7 @@ void get_new_mmu_context(struct mm_struct *mm) out: tlb_context_cache = new_ctx; mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits; - spin_unlock(&ctx_alloc_lock); + spin_unlock_irqrestore(&ctx_alloc_lock, flags); if (unlikely(new_version)) smp_new_mmu_context_version(); @@ -2124,6 +2125,7 @@ void free_initmem(void) ClearPageReserved(p); init_page_count(p); __free_page(p); + num_physpages++; totalram_pages++; } } @@ -2140,6 +2142,7 @@ void free_initrd_mem(unsigned long start, unsigned long end) ClearPageReserved(p); init_page_count(p); __free_page(p); + num_physpages++; totalram_pages++; } } diff --git a/trunk/arch/sparc/power/Makefile b/trunk/arch/sparc/power/Makefile deleted file mode 100644 index 3201ace0ddbd..000000000000 --- a/trunk/arch/sparc/power/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# Makefile for Sparc-specific hibernate files. - -obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o diff --git a/trunk/arch/sparc/power/hibernate.c b/trunk/arch/sparc/power/hibernate.c deleted file mode 100644 index 42b0b8ce699a..000000000000 --- a/trunk/arch/sparc/power/hibernate.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * hibernate.c: Hibernaton support specific for sparc64. - * - * Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru) - */ - -#include - -#include -#include -#include -#include - -/* References to section boundaries */ -extern const void __nosave_begin, __nosave_end; - -struct saved_context saved_context; - -/* - * pfn_is_nosave - check if given pfn is in the 'nosave' section - */ - -int pfn_is_nosave(unsigned long pfn) -{ - unsigned long nosave_begin_pfn = PFN_DOWN((unsigned long)&__nosave_begin); - unsigned long nosave_end_pfn = PFN_DOWN((unsigned long)&__nosave_end); - - return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); -} - -void save_processor_state(void) -{ - save_and_clear_fpu(); -} - -void restore_processor_state(void) -{ - struct mm_struct *mm = current->active_mm; - - load_secondary_context(mm); - tsb_context_switch(mm); -} diff --git a/trunk/arch/sparc/power/hibernate_asm.S b/trunk/arch/sparc/power/hibernate_asm.S deleted file mode 100644 index 79942166df84..000000000000 --- a/trunk/arch/sparc/power/hibernate_asm.S +++ /dev/null @@ -1,131 +0,0 @@ -/* - * hibernate_asm.S: Hibernaton support specific for sparc64. - * - * Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru) - */ - -#include - -#include -#include -#include - -ENTRY(swsusp_arch_suspend) - save %sp, -128, %sp - save %sp, -128, %sp - flushw - - setuw saved_context, %g3 - - /* Save window regs */ - rdpr %cwp, %g2 - stx %g2, [%g3 + SC_REG_CWP] - rdpr %wstate, %g2 - stx %g2, [%g3 + SC_REG_WSTATE] - stx %fp, [%g3 + SC_REG_FP] - - /* Save state regs */ - rdpr %tick, %g2 - stx %g2, [%g3 + SC_REG_TICK] - rdpr %pstate, %g2 - stx %g2, [%g3 + SC_REG_PSTATE] - - /* Save global regs */ - stx %g4, [%g3 + SC_REG_G4] - stx %g5, [%g3 + SC_REG_G5] - stx %g6, [%g3 + SC_REG_G6] - - call swsusp_save - nop - - mov %o0, %i0 - restore - - mov %o0, %i0 - ret - restore - -ENTRY(swsusp_arch_resume) - /* Write restore_pblist to %l0 */ - sethi %hi(restore_pblist), %l0 - ldx [%l0 + %lo(restore_pblist)], %l0 - - call __flush_tlb_all - nop - - /* Write PAGE_OFFSET to %g7 */ - sethi %uhi(PAGE_OFFSET), %g7 - sllx %g7, 32, %g7 - - setuw (PAGE_SIZE-8), %g3 - - /* Use MMU Bypass */ - rd %asi, %g1 - wr %g0, ASI_PHYS_USE_EC, %asi - - ba fill_itlb - nop - -pbe_loop: - cmp %l0, %g0 - be restore_ctx - sub %l0, %g7, %l0 - - ldxa [%l0 ] %asi, %l1 /* address */ - ldxa [%l0 + 8] %asi, %l2 /* orig_address */ - - /* phys addr */ - sub %l1, %g7, %l1 - sub %l2, %g7, %l2 - - mov %g3, %l3 /* PAGE_SIZE-8 */ -copy_loop: - ldxa [%l1 + %l3] ASI_PHYS_USE_EC, %g2 - stxa %g2, [%l2 + %l3] ASI_PHYS_USE_EC - cmp %l3, %g0 - bne copy_loop - sub %l3, 8, %l3 - - /* next pbe */ - ba pbe_loop - ldxa [%l0 + 16] %asi, %l0 - -restore_ctx: - setuw saved_context, %g3 - - /* Restore window regs */ - wrpr %g0, 0, %canrestore - wrpr %g0, 0, %otherwin - wrpr %g0, 6, %cansave - wrpr %g0, 0, %cleanwin - - ldxa [%g3 + SC_REG_CWP] %asi, %g2 - wrpr %g2, %cwp - ldxa [%g3 + SC_REG_WSTATE] %asi, %g2 - wrpr %g2, %wstate - ldxa [%g3 + SC_REG_FP] %asi, %fp - - /* Restore state regs */ - ldxa [%g3 + SC_REG_PSTATE] %asi, %g2 - wrpr %g2, %pstate - ldxa [%g3 + SC_REG_TICK] %asi, %g2 - wrpr %g2, %tick - - /* Restore global regs */ - ldxa [%g3 + SC_REG_G4] %asi, %g4 - ldxa [%g3 + SC_REG_G5] %asi, %g5 - ldxa [%g3 + SC_REG_G6] %asi, %g6 - - wr %g1, %g0, %asi - - restore - restore - - wrpr %g0, 14, %pil - - retl - mov %g0, %o0 - -fill_itlb: - ba pbe_loop - wrpr %g0, 15, %pil diff --git a/trunk/arch/um/include/shared/common-offsets.h b/trunk/arch/um/include/shared/common-offsets.h index c92306809029..2df313b6a586 100644 --- a/trunk/arch/um/include/shared/common-offsets.h +++ b/trunk/arch/um/include/shared/common-offsets.h @@ -30,8 +30,8 @@ DEFINE(UM_NSEC_PER_USEC, NSEC_PER_USEC); #ifdef CONFIG_PRINTK DEFINE(UML_CONFIG_PRINTK, CONFIG_PRINTK); #endif -#ifdef CONFIG_NO_HZ_COMMON -DEFINE(UML_CONFIG_NO_HZ_COMMON, CONFIG_NO_HZ_COMMON); +#ifdef CONFIG_NO_HZ +DEFINE(UML_CONFIG_NO_HZ, CONFIG_NO_HZ); #endif #ifdef CONFIG_UML_X86 DEFINE(UML_CONFIG_UML_X86, CONFIG_UML_X86); diff --git a/trunk/arch/um/os-Linux/time.c b/trunk/arch/um/os-Linux/time.c index e9824d5dd7d5..fac388cb464f 100644 --- a/trunk/arch/um/os-Linux/time.c +++ b/trunk/arch/um/os-Linux/time.c @@ -79,7 +79,7 @@ long long os_nsecs(void) return timeval_to_ns(&tv); } -#ifdef UML_CONFIG_NO_HZ_COMMON +#ifdef UML_CONFIG_NO_HZ static int after_sleep_interval(struct timespec *ts) { return 0; diff --git a/trunk/arch/x86/include/asm/entry_arch.h b/trunk/arch/x86/include/asm/entry_arch.h index 9bd4ecac72be..40afa0005c69 100644 --- a/trunk/arch/x86/include/asm/entry_arch.h +++ b/trunk/arch/x86/include/asm/entry_arch.h @@ -19,10 +19,6 @@ BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR) BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR) -#ifdef CONFIG_HAVE_KVM -BUILD_INTERRUPT(kvm_posted_intr_ipi, POSTED_INTR_VECTOR) -#endif - /* * every pentium local APIC has two 'local interrupts', with a * soft-definable vector attached to both interrupts, one of diff --git a/trunk/arch/x86/include/asm/hardirq.h b/trunk/arch/x86/include/asm/hardirq.h index ab0ae1aa6d0a..81f04cee5f74 100644 --- a/trunk/arch/x86/include/asm/hardirq.h +++ b/trunk/arch/x86/include/asm/hardirq.h @@ -11,9 +11,6 @@ typedef struct { unsigned int apic_timer_irqs; /* arch dependent */ unsigned int irq_spurious_count; unsigned int icr_read_retry_count; -#endif -#ifdef CONFIG_HAVE_KVM - unsigned int kvm_posted_intr_ipis; #endif unsigned int x86_platform_ipis; /* arch dependent */ unsigned int apic_perf_irqs; diff --git a/trunk/arch/x86/include/asm/hw_irq.h b/trunk/arch/x86/include/asm/hw_irq.h index 1da97efad08a..10a78c3d3d5a 100644 --- a/trunk/arch/x86/include/asm/hw_irq.h +++ b/trunk/arch/x86/include/asm/hw_irq.h @@ -28,7 +28,6 @@ /* Interrupt handlers registered during init_IRQ */ extern void apic_timer_interrupt(void); extern void x86_platform_ipi(void); -extern void kvm_posted_intr_ipi(void); extern void error_interrupt(void); extern void irq_work_interrupt(void); diff --git a/trunk/arch/x86/include/asm/irq_vectors.h b/trunk/arch/x86/include/asm/irq_vectors.h index 5702d7e3111d..aac5fa62a86c 100644 --- a/trunk/arch/x86/include/asm/irq_vectors.h +++ b/trunk/arch/x86/include/asm/irq_vectors.h @@ -102,11 +102,6 @@ */ #define X86_PLATFORM_IPI_VECTOR 0xf7 -/* Vector for KVM to deliver posted interrupt IPI */ -#ifdef CONFIG_HAVE_KVM -#define POSTED_INTR_VECTOR 0xf2 -#endif - /* * IRQ work vector: */ diff --git a/trunk/arch/x86/include/asm/kvm_host.h b/trunk/arch/x86/include/asm/kvm_host.h index 3741c653767c..4979778cc7fb 100644 --- a/trunk/arch/x86/include/asm/kvm_host.h +++ b/trunk/arch/x86/include/asm/kvm_host.h @@ -31,7 +31,7 @@ #include #include -#define KVM_MAX_VCPUS 255 +#define KVM_MAX_VCPUS 254 #define KVM_SOFT_MAX_VCPUS 160 #define KVM_USER_MEM_SLOTS 125 /* memory slots that are not exposed to userspace */ @@ -43,8 +43,6 @@ #define KVM_PIO_PAGE_OFFSET 1 #define KVM_COALESCED_MMIO_PAGE_OFFSET 2 -#define KVM_IRQCHIP_NUM_PINS KVM_IOAPIC_NUM_PINS - #define CR0_RESERVED_BITS \ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \ | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \ @@ -96,6 +94,9 @@ #define ASYNC_PF_PER_VCPU 64 +extern raw_spinlock_t kvm_lock; +extern struct list_head vm_list; + struct kvm_vcpu; struct kvm; struct kvm_async_pf; @@ -229,7 +230,6 @@ struct kvm_mmu_page { #endif int write_flooding_count; - bool mmio_cached; }; struct kvm_pio_request { @@ -345,6 +345,7 @@ struct kvm_vcpu_arch { unsigned long apic_attention; int32_t apic_arb_prio; int mp_state; + int sipi_vector; u64 ia32_misc_enable_msr; bool tpr_access_reporting; @@ -642,7 +643,7 @@ struct kvm_x86_ops { /* Create, but do not attach this VCPU */ struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id); void (*vcpu_free)(struct kvm_vcpu *vcpu); - void (*vcpu_reset)(struct kvm_vcpu *vcpu); + int (*vcpu_reset)(struct kvm_vcpu *vcpu); void (*prepare_guest_switch)(struct kvm_vcpu *vcpu); void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu); @@ -695,16 +696,14 @@ struct kvm_x86_ops { int (*nmi_allowed)(struct kvm_vcpu *vcpu); bool (*get_nmi_mask)(struct kvm_vcpu *vcpu); void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked); - int (*enable_nmi_window)(struct kvm_vcpu *vcpu); - int (*enable_irq_window)(struct kvm_vcpu *vcpu); + void (*enable_nmi_window)(struct kvm_vcpu *vcpu); + void (*enable_irq_window)(struct kvm_vcpu *vcpu); void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); int (*vm_has_apicv)(struct kvm *kvm); void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); void (*hwapic_isr_update)(struct kvm *kvm, int isr); void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu, bool set); - void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector); - void (*sync_pir_to_irr)(struct kvm_vcpu *vcpu); int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); int (*get_tdp_level)(void); u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio); @@ -731,7 +730,6 @@ struct kvm_x86_ops { int (*check_intercept)(struct kvm_vcpu *vcpu, struct x86_instruction_info *info, enum x86_intercept_stage stage); - void (*handle_external_intr)(struct kvm_vcpu *vcpu); }; struct kvm_arch_async_pf { @@ -769,7 +767,6 @@ void kvm_mmu_write_protect_pt_masked(struct kvm *kvm, struct kvm_memory_slot *slot, gfn_t gfn_offset, unsigned long mask); void kvm_mmu_zap_all(struct kvm *kvm); -void kvm_mmu_zap_mmio_sptes(struct kvm *kvm); unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm); void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages); @@ -800,7 +797,6 @@ enum emulation_result { #define EMULTYPE_TRAP_UD (1 << 1) #define EMULTYPE_SKIP (1 << 2) #define EMULTYPE_RETRY (1 << 3) -#define EMULTYPE_NO_REEXECUTE (1 << 4) int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2, int emulation_type, void *insn, int insn_len); @@ -811,7 +807,6 @@ static inline int emulate_instruction(struct kvm_vcpu *vcpu, } void kvm_enable_efer_bits(u64); -bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer); int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data); int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr); @@ -824,7 +819,6 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu); void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); -void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, unsigned int vector); int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, int reason, bool has_error_code, u32 error_code); @@ -979,6 +973,7 @@ enum { * Trap the fault and ignore the instruction if that happens. */ asmlinkage void kvm_spurious_fault(void); +extern bool kvm_rebooting; #define ____kvm_handle_fault_on_reboot(insn, cleanup_insn) \ "666: " insn "\n\t" \ @@ -1007,7 +1002,6 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v); int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); int kvm_cpu_get_interrupt(struct kvm_vcpu *v); -void kvm_vcpu_reset(struct kvm_vcpu *vcpu); void kvm_define_shared_msr(unsigned index, u32 msr); void kvm_set_shared_msr(unsigned index, u64 val, u64 mask); @@ -1033,7 +1027,7 @@ void kvm_pmu_reset(struct kvm_vcpu *vcpu); void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu); bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr); int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data); -int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); +int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data); int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); void kvm_handle_pmu_event(struct kvm_vcpu *vcpu); void kvm_deliver_pmi(struct kvm_vcpu *vcpu); diff --git a/trunk/arch/x86/include/asm/vmx.h b/trunk/arch/x86/include/asm/vmx.h index f3e01a2cbaa1..b6fbf860e398 100644 --- a/trunk/arch/x86/include/asm/vmx.h +++ b/trunk/arch/x86/include/asm/vmx.h @@ -65,16 +65,11 @@ #define SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY 0x00000200 #define SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400 #define SECONDARY_EXEC_ENABLE_INVPCID 0x00001000 -#define SECONDARY_EXEC_SHADOW_VMCS 0x00004000 #define PIN_BASED_EXT_INTR_MASK 0x00000001 #define PIN_BASED_NMI_EXITING 0x00000008 #define PIN_BASED_VIRTUAL_NMIS 0x00000020 -#define PIN_BASED_VMX_PREEMPTION_TIMER 0x00000040 -#define PIN_BASED_POSTED_INTR 0x00000080 - -#define PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR 0x00000016 #define VM_EXIT_SAVE_DEBUG_CONTROLS 0x00000002 #define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 @@ -86,8 +81,6 @@ #define VM_EXIT_LOAD_IA32_EFER 0x00200000 #define VM_EXIT_SAVE_VMX_PREEMPTION_TIMER 0x00400000 -#define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR 0x00036dff - #define VM_ENTRY_LOAD_DEBUG_CONTROLS 0x00000002 #define VM_ENTRY_IA32E_MODE 0x00000200 #define VM_ENTRY_SMM 0x00000400 @@ -96,15 +89,9 @@ #define VM_ENTRY_LOAD_IA32_PAT 0x00004000 #define VM_ENTRY_LOAD_IA32_EFER 0x00008000 -#define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR 0x000011ff - -#define VMX_MISC_PREEMPTION_TIMER_RATE_MASK 0x0000001f -#define VMX_MISC_SAVE_EFER_LMA 0x00000020 - /* VMCS Encodings */ enum vmcs_field { VIRTUAL_PROCESSOR_ID = 0x00000000, - POSTED_INTR_NV = 0x00000002, GUEST_ES_SELECTOR = 0x00000800, GUEST_CS_SELECTOR = 0x00000802, GUEST_SS_SELECTOR = 0x00000804, @@ -139,8 +126,6 @@ enum vmcs_field { VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, APIC_ACCESS_ADDR = 0x00002014, APIC_ACCESS_ADDR_HIGH = 0x00002015, - POSTED_INTR_DESC_ADDR = 0x00002016, - POSTED_INTR_DESC_ADDR_HIGH = 0x00002017, EPT_POINTER = 0x0000201a, EPT_POINTER_HIGH = 0x0000201b, EOI_EXIT_BITMAP0 = 0x0000201c, @@ -151,8 +136,6 @@ enum vmcs_field { EOI_EXIT_BITMAP2_HIGH = 0x00002021, EOI_EXIT_BITMAP3 = 0x00002022, EOI_EXIT_BITMAP3_HIGH = 0x00002023, - VMREAD_BITMAP = 0x00002026, - VMWRITE_BITMAP = 0x00002028, GUEST_PHYSICAL_ADDRESS = 0x00002400, GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401, VMCS_LINK_POINTER = 0x00002800, @@ -226,7 +209,6 @@ enum vmcs_field { GUEST_INTERRUPTIBILITY_INFO = 0x00004824, GUEST_ACTIVITY_STATE = 0X00004826, GUEST_SYSENTER_CS = 0x0000482A, - VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, HOST_IA32_SYSENTER_CS = 0x00004c00, CR0_GUEST_HOST_MASK = 0x00006000, CR4_GUEST_HOST_MASK = 0x00006002, diff --git a/trunk/arch/x86/include/uapi/asm/kvm.h b/trunk/arch/x86/include/uapi/asm/kvm.h index 5d9a3033b3d7..a65ec29e6ffb 100644 --- a/trunk/arch/x86/include/uapi/asm/kvm.h +++ b/trunk/arch/x86/include/uapi/asm/kvm.h @@ -29,6 +29,7 @@ #define __KVM_HAVE_PIT #define __KVM_HAVE_IOAPIC #define __KVM_HAVE_IRQ_LINE +#define __KVM_HAVE_DEVICE_ASSIGNMENT #define __KVM_HAVE_MSI #define __KVM_HAVE_USER_NMI #define __KVM_HAVE_GUEST_DEBUG diff --git a/trunk/arch/x86/include/uapi/asm/msr-index.h b/trunk/arch/x86/include/uapi/asm/msr-index.h index b3a4866661c5..b5757885d7a4 100644 --- a/trunk/arch/x86/include/uapi/asm/msr-index.h +++ b/trunk/arch/x86/include/uapi/asm/msr-index.h @@ -528,8 +528,6 @@ #define VMX_BASIC_MEM_TYPE_WB 6LLU #define VMX_BASIC_INOUT 0x0040000000000000LLU -/* MSR_IA32_VMX_MISC bits */ -#define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29) /* AMD-V MSRs */ #define MSR_VM_CR 0xc0010114 diff --git a/trunk/arch/x86/include/uapi/asm/vmx.h b/trunk/arch/x86/include/uapi/asm/vmx.h index d651082c7cf7..2871fccfee68 100644 --- a/trunk/arch/x86/include/uapi/asm/vmx.h +++ b/trunk/arch/x86/include/uapi/asm/vmx.h @@ -65,7 +65,6 @@ #define EXIT_REASON_EOI_INDUCED 45 #define EXIT_REASON_EPT_VIOLATION 48 #define EXIT_REASON_EPT_MISCONFIG 49 -#define EXIT_REASON_PREEMPTION_TIMER 52 #define EXIT_REASON_WBINVD 54 #define EXIT_REASON_XSETBV 55 #define EXIT_REASON_APIC_WRITE 56 @@ -111,7 +110,7 @@ { EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \ { EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \ { EXIT_REASON_INVD, "INVD" }, \ - { EXIT_REASON_INVPCID, "INVPCID" }, \ - { EXIT_REASON_PREEMPTION_TIMER, "PREEMPTION_TIMER" } + { EXIT_REASON_INVPCID, "INVPCID" } + #endif /* _UAPIVMX_H */ diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel.c b/trunk/arch/x86/kernel/cpu/perf_event_intel.c index f60d41ff9a97..ffd6050a1de4 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel.c @@ -128,15 +128,10 @@ static struct event_constraint intel_ivb_event_constraints[] __read_mostly = INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4), /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */ INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ - /* - * Errata BV98 -- MEM_*_RETIRED events can leak between counters of SMT - * siblings; disable these events because they can corrupt unrelated - * counters. - */ - INTEL_EVENT_CONSTRAINT(0xd0, 0x0), /* MEM_UOPS_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd1, 0x0), /* MEM_LOAD_UOPS_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd2, 0x0), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd3, 0x0), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOPS_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xd3, 0xf), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ EVENT_CONSTRAINT_END }; diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/trunk/arch/x86/kernel/cpu/perf_event_intel_lbr.c index d978353c939b..da02e9cc3754 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -310,7 +310,7 @@ void intel_pmu_lbr_read(void) * - in case there is no HW filter * - in case the HW filter has errata or limitations */ -static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) +static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event) { u64 br_type = event->attr.branch_sample_type; int mask = 0; @@ -318,11 +318,8 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) if (br_type & PERF_SAMPLE_BRANCH_USER) mask |= X86_BR_USER; - if (br_type & PERF_SAMPLE_BRANCH_KERNEL) { - if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + if (br_type & PERF_SAMPLE_BRANCH_KERNEL) mask |= X86_BR_KERNEL; - } /* we ignore BRANCH_HV here */ @@ -342,8 +339,6 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) * be used by fixup code for some CPU */ event->hw.branch_reg.reg = mask; - - return 0; } /* @@ -391,9 +386,7 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event) /* * setup SW LBR filter */ - ret = intel_pmu_setup_sw_lbr_filter(event); - if (ret) - return ret; + intel_pmu_setup_sw_lbr_filter(event); /* * setup HW LBR filter, if any @@ -449,18 +442,8 @@ static int branch_type(unsigned long from, unsigned long to) return X86_BR_NONE; addr = buf; - } else { - /* - * The LBR logs any address in the IP, even if the IP just - * faulted. This means userspace can control the from address. - * Ensure we don't blindy read any address by validating it is - * a known text address. - */ - if (kernel_text_address(from)) - addr = (void *)from; - else - return X86_BR_NONE; - } + } else + addr = (void *)from; /* * decoder needs to know the ABI especially diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/trunk/arch/x86/kernel/cpu/perf_event_intel_uncore.c index 52441a2af538..d0f9e5aa2151 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -3093,7 +3093,7 @@ static void __init uncore_types_exit(struct intel_uncore_type **types) static int __init uncore_type_init(struct intel_uncore_type *type) { struct intel_uncore_pmu *pmus; - struct attribute_group *attr_group; + struct attribute_group *events_group; struct attribute **attrs; int i, j; @@ -3120,19 +3120,19 @@ static int __init uncore_type_init(struct intel_uncore_type *type) while (type->event_descs[i].attr.attr.name) i++; - attr_group = kzalloc(sizeof(struct attribute *) * (i + 1) + - sizeof(*attr_group), GFP_KERNEL); - if (!attr_group) + events_group = kzalloc(sizeof(struct attribute *) * (i + 1) + + sizeof(*events_group), GFP_KERNEL); + if (!events_group) goto fail; - attrs = (struct attribute **)(attr_group + 1); - attr_group->name = "events"; - attr_group->attrs = attrs; + attrs = (struct attribute **)(events_group + 1); + events_group->name = "events"; + events_group->attrs = attrs; for (j = 0; j < i; j++) attrs[j] = &type->event_descs[j].attr.attr; - type->events_group = attr_group; + type->events_group = events_group; } type->pmu_group = &uncore_pmu_attr_group; @@ -3545,12 +3545,11 @@ static int __init uncore_cpu_init(void) msr_uncores = nhm_msr_uncores; break; case 42: /* Sandy Bridge */ - case 58: /* Ivy Bridge */ if (snb_uncore_cbox.num_boxes > max_cores) snb_uncore_cbox.num_boxes = max_cores; msr_uncores = snb_msr_uncores; break; - case 45: /* Sandy Bridge-EP */ + case 45: /* Sandy Birdge-EP */ if (snbep_uncore_cbox.num_boxes > max_cores) snbep_uncore_cbox.num_boxes = max_cores; msr_uncores = snbep_msr_uncores; diff --git a/trunk/arch/x86/kernel/entry_64.S b/trunk/arch/x86/kernel/entry_64.S index 727208941030..c1d01e6ca790 100644 --- a/trunk/arch/x86/kernel/entry_64.S +++ b/trunk/arch/x86/kernel/entry_64.S @@ -1166,11 +1166,6 @@ apicinterrupt LOCAL_TIMER_VECTOR \ apicinterrupt X86_PLATFORM_IPI_VECTOR \ x86_platform_ipi smp_x86_platform_ipi -#ifdef CONFIG_HAVE_KVM -apicinterrupt POSTED_INTR_VECTOR \ - kvm_posted_intr_ipi smp_kvm_posted_intr_ipi -#endif - apicinterrupt THRESHOLD_APIC_VECTOR \ threshold_interrupt smp_threshold_interrupt apicinterrupt THERMAL_APIC_VECTOR \ diff --git a/trunk/arch/x86/kernel/irq.c b/trunk/arch/x86/kernel/irq.c index ac0631d8996f..e4595f105910 100644 --- a/trunk/arch/x86/kernel/irq.c +++ b/trunk/arch/x86/kernel/irq.c @@ -165,6 +165,10 @@ u64 arch_irq_stat_cpu(unsigned int cpu) u64 arch_irq_stat(void) { u64 sum = atomic_read(&irq_err_count); + +#ifdef CONFIG_X86_IO_APIC + sum += atomic_read(&irq_mis_count); +#endif return sum; } @@ -224,28 +228,6 @@ void smp_x86_platform_ipi(struct pt_regs *regs) set_irq_regs(old_regs); } -#ifdef CONFIG_HAVE_KVM -/* - * Handler for POSTED_INTERRUPT_VECTOR. - */ -void smp_kvm_posted_intr_ipi(struct pt_regs *regs) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - - ack_APIC_irq(); - - irq_enter(); - - exit_idle(); - - inc_irq_stat(kvm_posted_intr_ipis); - - irq_exit(); - - set_irq_regs(old_regs); -} -#endif - EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); #ifdef CONFIG_HOTPLUG_CPU diff --git a/trunk/arch/x86/kernel/irqinit.c b/trunk/arch/x86/kernel/irqinit.c index a2a1fbc594ff..7dc4e459c2b3 100644 --- a/trunk/arch/x86/kernel/irqinit.c +++ b/trunk/arch/x86/kernel/irqinit.c @@ -172,10 +172,6 @@ static void __init apic_intr_init(void) /* IPI for X86 platform specific use */ alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi); -#ifdef CONFIG_HAVE_KVM - /* IPI for KVM to deliver posted interrupt */ - alloc_intr_gate(POSTED_INTR_VECTOR, kvm_posted_intr_ipi); -#endif /* IPI vectors for APIC spurious and error interrupts */ alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); diff --git a/trunk/arch/x86/kernel/kvmclock.c b/trunk/arch/x86/kernel/kvmclock.c index d2c381280e3c..0732f0089a3d 100644 --- a/trunk/arch/x86/kernel/kvmclock.c +++ b/trunk/arch/x86/kernel/kvmclock.c @@ -160,12 +160,8 @@ int kvm_register_clock(char *txt) { int cpu = smp_processor_id(); int low, high, ret; - struct pvclock_vcpu_time_info *src; - - if (!hv_clock) - return 0; + struct pvclock_vcpu_time_info *src = &hv_clock[cpu].pvti; - src = &hv_clock[cpu].pvti; low = (int)slow_virt_to_phys(src) | 1; high = ((u64)slow_virt_to_phys(src) >> 32); ret = native_write_msr_safe(msr_kvm_system_time, low, high); @@ -280,9 +276,6 @@ int __init kvm_setup_vsyscall_timeinfo(void) struct pvclock_vcpu_time_info *vcpu_time; unsigned int size; - if (!hv_clock) - return 0; - size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS); preempt_disable(); diff --git a/trunk/arch/x86/kvm/Kconfig b/trunk/arch/x86/kvm/Kconfig index a47a3e54b964..586f00059805 100644 --- a/trunk/arch/x86/kvm/Kconfig +++ b/trunk/arch/x86/kvm/Kconfig @@ -21,13 +21,14 @@ config KVM tristate "Kernel-based Virtual Machine (KVM) support" depends on HAVE_KVM depends on HIGH_RES_TIMERS + # for device assignment: + depends on PCI # for TASKSTATS/TASK_DELAY_ACCT: depends on NET select PREEMPT_NOTIFIERS select MMU_NOTIFIER select ANON_INODES select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_EVENTFD select KVM_APIC_ARCHITECTURE select KVM_ASYNC_PF @@ -81,17 +82,6 @@ config KVM_MMU_AUDIT This option adds a R/W kVM module parameter 'mmu_audit', which allows audit KVM MMU at runtime. -config KVM_DEVICE_ASSIGNMENT - bool "KVM legacy PCI device assignment support" - depends on KVM && PCI && IOMMU_API - default y - ---help--- - Provide support for legacy PCI device assignment through KVM. The - kernel now also supports a full featured userspace device driver - framework through VFIO, which supersedes much of this support. - - If unsure, say Y. - # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. source drivers/vhost/Kconfig diff --git a/trunk/arch/x86/kvm/Makefile b/trunk/arch/x86/kvm/Makefile index d609e1d84048..04d30401c5cb 100644 --- a/trunk/arch/x86/kvm/Makefile +++ b/trunk/arch/x86/kvm/Makefile @@ -7,9 +7,8 @@ CFLAGS_vmx.o := -I. kvm-y += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \ coalesced_mmio.o irq_comm.o eventfd.o \ - irqchip.o) -kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += $(addprefix ../../../virt/kvm/, \ - assigned-dev.o iommu.o) + assigned-dev.o) +kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o) kvm-$(CONFIG_KVM_ASYNC_PF) += $(addprefix ../../../virt/kvm/, async_pf.o) kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \ diff --git a/trunk/arch/x86/kvm/emulate.c b/trunk/arch/x86/kvm/emulate.c index 8e517bba6a7c..a335cc6cde72 100644 --- a/trunk/arch/x86/kvm/emulate.c +++ b/trunk/arch/x86/kvm/emulate.c @@ -132,9 +132,8 @@ #define Priv (1<<27) /* instruction generates #GP if current CPL != 0 */ #define No64 (1<<28) #define PageTable (1 << 29) /* instruction used to write page table */ -#define NotImpl (1 << 30) /* instruction is not implemented */ /* Source 2 operand type */ -#define Src2Shift (31) +#define Src2Shift (30) #define Src2None (OpNone << Src2Shift) #define Src2CL (OpCL << Src2Shift) #define Src2ImmByte (OpImmByte << Src2Shift) @@ -1579,21 +1578,12 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, memset(&seg_desc, 0, sizeof seg_desc); - if (ctxt->mode == X86EMUL_MODE_REAL) { - /* set real mode segment descriptor (keep limit etc. for - * unreal mode) */ + if ((seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86) + || ctxt->mode == X86EMUL_MODE_REAL) { + /* set real mode segment descriptor */ ctxt->ops->get_segment(ctxt, &dummy, &seg_desc, NULL, seg); set_desc_base(&seg_desc, selector << 4); goto load; - } else if (seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86) { - /* VM86 needs a clean new segment descriptor */ - set_desc_base(&seg_desc, selector << 4); - set_desc_limit(&seg_desc, 0xffff); - seg_desc.type = 3; - seg_desc.p = 1; - seg_desc.s = 1; - seg_desc.dpl = 3; - goto load; } rpl = selector & 3; @@ -3625,7 +3615,7 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt) #define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i } #define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \ .check_perm = (_p) } -#define N D(NotImpl) +#define N D(0) #define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) } #define G(_f, _g) { .flags = ((_f) | Group | ModRM), .u.group = (_g) } #define GD(_f, _g) { .flags = ((_f) | GroupDual | ModRM), .u.gdual = (_g) } @@ -3723,7 +3713,7 @@ static const struct opcode group5[] = { I(SrcMemFAddr | ImplicitOps | Stack, em_call_far), I(SrcMem | Stack, em_grp45), I(SrcMemFAddr | ImplicitOps, em_grp45), - I(SrcMem | Stack, em_grp45), D(Undefined), + I(SrcMem | Stack, em_grp45), N, }; static const struct opcode group6[] = { @@ -4172,10 +4162,6 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, break; case OpMem8: ctxt->memop.bytes = 1; - if (ctxt->memop.type == OP_REG) { - ctxt->memop.addr.reg = decode_register(ctxt, ctxt->modrm_rm, 1); - fetch_register_operand(&ctxt->memop); - } goto mem_common; case OpMem16: ctxt->memop.bytes = 2; @@ -4387,7 +4373,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) ctxt->intercept = opcode.intercept; /* Unrecognised? */ - if (ctxt->d == 0 || (ctxt->d & NotImpl)) + if (ctxt->d == 0 || (ctxt->d & Undefined)) return EMULATION_FAILED; if (!(ctxt->d & VendorSpecific) && ctxt->only_vendor_specific_insn) @@ -4525,8 +4511,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) ctxt->mem_read.pos = 0; - if ((ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) || - (ctxt->d & Undefined)) { + if (ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) { rc = emulate_ud(ctxt); goto done; } diff --git a/trunk/arch/x86/kvm/i8254.c b/trunk/arch/x86/kvm/i8254.c index 412a5aa0ef94..c1d30b2fc9bb 100644 --- a/trunk/arch/x86/kvm/i8254.c +++ b/trunk/arch/x86/kvm/i8254.c @@ -290,8 +290,8 @@ static void pit_do_work(struct kthread_work *work) } spin_unlock(&ps->inject_lock); if (inject) { - kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1, false); - kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0, false); + kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1); + kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0); /* * Provides NMI watchdog support via Virtual Wire mode. diff --git a/trunk/arch/x86/kvm/lapic.c b/trunk/arch/x86/kvm/lapic.c index e1adbb4aca75..f77df1c5de6e 100644 --- a/trunk/arch/x86/kvm/lapic.c +++ b/trunk/arch/x86/kvm/lapic.c @@ -94,14 +94,6 @@ static inline int apic_test_vector(int vec, void *bitmap) return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); } -bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector) -{ - struct kvm_lapic *apic = vcpu->arch.apic; - - return apic_test_vector(vector, apic->regs + APIC_ISR) || - apic_test_vector(vector, apic->regs + APIC_IRR); -} - static inline void apic_set_vector(int vec, void *bitmap) { set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); @@ -153,6 +145,53 @@ static inline int kvm_apic_id(struct kvm_lapic *apic) return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; } +void kvm_calculate_eoi_exitmap(struct kvm_vcpu *vcpu, + struct kvm_lapic_irq *irq, + u64 *eoi_exit_bitmap) +{ + struct kvm_lapic **dst; + struct kvm_apic_map *map; + unsigned long bitmap = 1; + int i; + + rcu_read_lock(); + map = rcu_dereference(vcpu->kvm->arch.apic_map); + + if (unlikely(!map)) { + __set_bit(irq->vector, (unsigned long *)eoi_exit_bitmap); + goto out; + } + + if (irq->dest_mode == 0) { /* physical mode */ + if (irq->delivery_mode == APIC_DM_LOWEST || + irq->dest_id == 0xff) { + __set_bit(irq->vector, + (unsigned long *)eoi_exit_bitmap); + goto out; + } + dst = &map->phys_map[irq->dest_id & 0xff]; + } else { + u32 mda = irq->dest_id << (32 - map->ldr_bits); + + dst = map->logical_map[apic_cluster_id(map, mda)]; + + bitmap = apic_logical_id(map, mda); + } + + for_each_set_bit(i, &bitmap, 16) { + if (!dst[i]) + continue; + if (dst[i]->vcpu == vcpu) { + __set_bit(irq->vector, + (unsigned long *)eoi_exit_bitmap); + break; + } + } + +out: + rcu_read_unlock(); +} + static void recalculate_apic_map(struct kvm *kvm) { struct kvm_apic_map *new, *old = NULL; @@ -217,7 +256,7 @@ static void recalculate_apic_map(struct kvm *kvm) if (old) kfree_rcu(old, rcu); - kvm_vcpu_request_scan_ioapic(kvm); + kvm_ioapic_make_eoibitmap_request(kvm); } static inline void kvm_apic_set_id(struct kvm_lapic *apic, u8 id) @@ -318,19 +357,6 @@ static u8 count_vectors(void *bitmap) return count; } -void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir) -{ - u32 i, pir_val; - struct kvm_lapic *apic = vcpu->arch.apic; - - for (i = 0; i <= 7; i++) { - pir_val = xchg(&pir[i], 0); - if (pir_val) - *((u32 *)(apic->regs + APIC_IRR + i * 0x10)) |= pir_val; - } -} -EXPORT_SYMBOL_GPL(kvm_apic_update_irr); - static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) { apic->irr_pending = true; @@ -353,7 +379,6 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic) if (!apic->irr_pending) return -1; - kvm_x86_ops->sync_pir_to_irr(apic->vcpu); result = apic_search_irr(apic); ASSERT(result == -1 || result >= 16); @@ -406,16 +431,14 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) } static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, - int vector, int level, int trig_mode, - unsigned long *dest_map); + int vector, int level, int trig_mode); -int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq, - unsigned long *dest_map) +int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq) { struct kvm_lapic *apic = vcpu->arch.apic; return __apic_accept_irq(apic, irq->delivery_mode, irq->vector, - irq->level, irq->trig_mode, dest_map); + irq->level, irq->trig_mode); } static int pv_eoi_put_user(struct kvm_vcpu *vcpu, u8 val) @@ -482,15 +505,6 @@ static inline int apic_find_highest_isr(struct kvm_lapic *apic) return result; } -void kvm_apic_update_tmr(struct kvm_vcpu *vcpu, u32 *tmr) -{ - struct kvm_lapic *apic = vcpu->arch.apic; - int i; - - for (i = 0; i < 8; i++) - apic_set_reg(apic, APIC_TMR + 0x10 * i, tmr[i]); -} - static void apic_update_ppr(struct kvm_lapic *apic) { u32 tpr, isrv, ppr, old_ppr; @@ -597,7 +611,7 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, } bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, - struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map) + struct kvm_lapic_irq *irq, int *r) { struct kvm_apic_map *map; unsigned long bitmap = 1; @@ -608,7 +622,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, *r = -1; if (irq->shorthand == APIC_DEST_SELF) { - *r = kvm_apic_set_irq(src->vcpu, irq, dest_map); + *r = kvm_apic_set_irq(src->vcpu, irq); return true; } @@ -653,7 +667,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, continue; if (*r < 0) *r = 0; - *r += kvm_apic_set_irq(dst[i]->vcpu, irq, dest_map); + *r += kvm_apic_set_irq(dst[i]->vcpu, irq); } ret = true; @@ -667,8 +681,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, * Return 1 if successfully added and 0 if discarded. */ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, - int vector, int level, int trig_mode, - unsigned long *dest_map) + int vector, int level, int trig_mode) { int result = 0; struct kvm_vcpu *vcpu = apic->vcpu; @@ -681,28 +694,24 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, if (unlikely(!apic_enabled(apic))) break; - if (dest_map) - __set_bit(vcpu->vcpu_id, dest_map); - - if (kvm_x86_ops->deliver_posted_interrupt) { - result = 1; - kvm_x86_ops->deliver_posted_interrupt(vcpu, vector); - } else { - result = !apic_test_and_set_irr(vector, apic); - - if (!result) { - if (trig_mode) - apic_debug("level trig mode repeatedly " - "for vector %d", vector); - goto out; - } + if (trig_mode) { + apic_debug("level trig mode for vector %d", vector); + apic_set_vector(vector, apic->regs + APIC_TMR); + } else + apic_clear_vector(vector, apic->regs + APIC_TMR); - kvm_make_request(KVM_REQ_EVENT, vcpu); - kvm_vcpu_kick(vcpu); - } -out: + result = !apic_test_and_set_irr(vector, apic); trace_kvm_apic_accept_irq(vcpu->vcpu_id, delivery_mode, - trig_mode, vector, !result); + trig_mode, vector, !result); + if (!result) { + if (trig_mode) + apic_debug("level trig mode repeatedly for " + "vector %d", vector); + break; + } + + kvm_make_request(KVM_REQ_EVENT, vcpu); + kvm_vcpu_kick(vcpu); break; case APIC_DM_REMRD: @@ -722,11 +731,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, case APIC_DM_INIT: if (!trig_mode || level) { result = 1; - /* assumes that there are only KVM_APIC_INIT/SIPI */ - apic->pending_events = (1UL << KVM_APIC_INIT); - /* make sure pending_events is visible before sending - * the request */ - smp_wmb(); + vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED; kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); } else { @@ -738,13 +743,13 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, case APIC_DM_STARTUP: apic_debug("SIPI to vcpu %d vector 0x%02x\n", vcpu->vcpu_id, vector); - result = 1; - apic->sipi_vector = vector; - /* make sure sipi_vector is visible for the receiver */ - smp_wmb(); - set_bit(KVM_APIC_SIPI, &apic->pending_events); - kvm_make_request(KVM_REQ_EVENT, vcpu); - kvm_vcpu_kick(vcpu); + if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) { + result = 1; + vcpu->arch.sipi_vector = vector; + vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED; + kvm_make_request(KVM_REQ_EVENT, vcpu); + kvm_vcpu_kick(vcpu); + } break; case APIC_DM_EXTINT: @@ -777,7 +782,7 @@ static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector) trigger_mode = IOAPIC_LEVEL_TRIG; else trigger_mode = IOAPIC_EDGE_TRIG; - kvm_ioapic_update_eoi(apic->vcpu, vector, trigger_mode); + kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode); } } @@ -843,7 +848,7 @@ static void apic_send_ipi(struct kvm_lapic *apic) irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode, irq.vector); - kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq, NULL); + kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq); } static u32 apic_get_tmcct(struct kvm_lapic *apic) @@ -1479,8 +1484,7 @@ int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type) vector = reg & APIC_VECTOR_MASK; mode = reg & APIC_MODE_MASK; trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; - return __apic_accept_irq(apic, mode, vector, 1, trig_mode, - NULL); + return __apic_accept_irq(apic, mode, vector, 1, trig_mode); } return 0; } @@ -1650,7 +1654,6 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, apic->highest_isr_cache = -1; kvm_x86_ops->hwapic_isr_update(vcpu->kvm, apic_find_highest_isr(apic)); kvm_make_request(KVM_REQ_EVENT, vcpu); - kvm_rtc_eoi_tracking_restore_one(vcpu); } void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) @@ -1857,34 +1860,6 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data) addr, sizeof(u8)); } -void kvm_apic_accept_events(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = vcpu->arch.apic; - unsigned int sipi_vector; - - if (!kvm_vcpu_has_lapic(vcpu)) - return; - - if (test_and_clear_bit(KVM_APIC_INIT, &apic->pending_events)) { - kvm_lapic_reset(vcpu); - kvm_vcpu_reset(vcpu); - if (kvm_vcpu_is_bsp(apic->vcpu)) - vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; - else - vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED; - } - if (test_and_clear_bit(KVM_APIC_SIPI, &apic->pending_events) && - vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) { - /* evaluate pending_events before reading the vector */ - smp_rmb(); - sipi_vector = apic->sipi_vector; - pr_debug("vcpu %d received sipi with vector # %x\n", - vcpu->vcpu_id, sipi_vector); - kvm_vcpu_deliver_sipi_vector(vcpu, sipi_vector); - vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; - } -} - void kvm_lapic_init(void) { /* do not patch jump label more than once per second */ diff --git a/trunk/arch/x86/kvm/lapic.h b/trunk/arch/x86/kvm/lapic.h index c730ac9fe801..1676d34ddb4e 100644 --- a/trunk/arch/x86/kvm/lapic.h +++ b/trunk/arch/x86/kvm/lapic.h @@ -5,9 +5,6 @@ #include -#define KVM_APIC_INIT 0 -#define KVM_APIC_SIPI 1 - struct kvm_timer { struct hrtimer timer; s64 period; /* unit: ns */ @@ -35,8 +32,6 @@ struct kvm_lapic { void *regs; gpa_t vapic_addr; struct page *vapic_page; - unsigned long pending_events; - unsigned int sipi_vector; }; int kvm_create_lapic(struct kvm_vcpu *vcpu); void kvm_free_lapic(struct kvm_vcpu *vcpu); @@ -44,7 +39,6 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu); int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu); int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu); -void kvm_apic_accept_events(struct kvm_vcpu *vcpu); void kvm_lapic_reset(struct kvm_vcpu *vcpu); u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); @@ -53,16 +47,13 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); void kvm_apic_set_version(struct kvm_vcpu *vcpu); -void kvm_apic_update_tmr(struct kvm_vcpu *vcpu, u32 *tmr); -void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir); int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); -int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq, - unsigned long *dest_map); +int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq); int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type); bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, - struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map); + struct kvm_lapic_irq *irq, int *r); u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); @@ -163,11 +154,8 @@ static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr) return ldr & map->lid_mask; } -static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.apic->pending_events; -} - -bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector); +void kvm_calculate_eoi_exitmap(struct kvm_vcpu *vcpu, + struct kvm_lapic_irq *irq, + u64 *eoi_bitmap); #endif diff --git a/trunk/arch/x86/kvm/mmu.c b/trunk/arch/x86/kvm/mmu.c index 004cc87b781c..956ca358108a 100644 --- a/trunk/arch/x86/kvm/mmu.c +++ b/trunk/arch/x86/kvm/mmu.c @@ -199,11 +199,8 @@ EXPORT_SYMBOL_GPL(kvm_mmu_set_mmio_spte_mask); static void mark_mmio_spte(u64 *sptep, u64 gfn, unsigned access) { - struct kvm_mmu_page *sp = page_header(__pa(sptep)); - access &= ACC_WRITE_MASK | ACC_USER_MASK; - sp->mmio_cached = true; trace_mark_mmio_spte(sptep, gfn, access); mmu_spte_set(sptep, shadow_mmio_mask | access | gfn << PAGE_SHIFT); } @@ -1505,7 +1502,6 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, u64 *parent_pte, int direct) { struct kvm_mmu_page *sp; - sp = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache); sp->spt = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache); if (!direct) @@ -1648,14 +1644,16 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp, static void kvm_mmu_commit_zap_page(struct kvm *kvm, struct list_head *invalid_list); -#define for_each_gfn_sp(_kvm, _sp, _gfn) \ - hlist_for_each_entry(_sp, \ - &(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)], hash_link) \ - if ((_sp)->gfn != (_gfn)) {} else +#define for_each_gfn_sp(kvm, sp, gfn) \ + hlist_for_each_entry(sp, \ + &(kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)], hash_link) \ + if ((sp)->gfn != (gfn)) {} else -#define for_each_gfn_indirect_valid_sp(_kvm, _sp, _gfn) \ - for_each_gfn_sp(_kvm, _sp, _gfn) \ - if ((_sp)->role.direct || (_sp)->role.invalid) {} else +#define for_each_gfn_indirect_valid_sp(kvm, sp, gfn) \ + hlist_for_each_entry(sp, \ + &(kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)], hash_link) \ + if ((sp)->gfn != (gfn) || (sp)->role.direct || \ + (sp)->role.invalid) {} else /* @sp->gfn should be write-protected at the call site */ static int __kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, @@ -2091,7 +2089,7 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp, static void kvm_mmu_commit_zap_page(struct kvm *kvm, struct list_head *invalid_list) { - struct kvm_mmu_page *sp, *nsp; + struct kvm_mmu_page *sp; if (list_empty(invalid_list)) return; @@ -2108,25 +2106,11 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm, */ kvm_flush_remote_tlbs(kvm); - list_for_each_entry_safe(sp, nsp, invalid_list, link) { + do { + sp = list_first_entry(invalid_list, struct kvm_mmu_page, link); WARN_ON(!sp->role.invalid || sp->root_count); kvm_mmu_free_page(sp); - } -} - -static bool prepare_zap_oldest_mmu_page(struct kvm *kvm, - struct list_head *invalid_list) -{ - struct kvm_mmu_page *sp; - - if (list_empty(&kvm->arch.active_mmu_pages)) - return false; - - sp = list_entry(kvm->arch.active_mmu_pages.prev, - struct kvm_mmu_page, link); - kvm_mmu_prepare_zap_page(kvm, sp, invalid_list); - - return true; + } while (!list_empty(invalid_list)); } /* @@ -2136,15 +2120,23 @@ static bool prepare_zap_oldest_mmu_page(struct kvm *kvm, void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int goal_nr_mmu_pages) { LIST_HEAD(invalid_list); + /* + * If we set the number of mmu pages to be smaller be than the + * number of actived pages , we must to free some mmu pages before we + * change the value + */ spin_lock(&kvm->mmu_lock); if (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages) { - /* Need to free some mmu pages to achieve the goal. */ - while (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages) - if (!prepare_zap_oldest_mmu_page(kvm, &invalid_list)) - break; + while (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages && + !list_empty(&kvm->arch.active_mmu_pages)) { + struct kvm_mmu_page *page; + page = container_of(kvm->arch.active_mmu_pages.prev, + struct kvm_mmu_page, link); + kvm_mmu_prepare_zap_page(kvm, page, &invalid_list); + } kvm_mmu_commit_zap_page(kvm, &invalid_list); goal_nr_mmu_pages = kvm->arch.n_used_mmu_pages; } @@ -2802,7 +2794,6 @@ static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level, static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, gva_t gva, pfn_t *pfn, bool write, bool *writable); -static void make_mmu_pages_available(struct kvm_vcpu *vcpu); static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code, gfn_t gfn, bool prefault) @@ -2844,7 +2835,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code, spin_lock(&vcpu->kvm->mmu_lock); if (mmu_notifier_retry(vcpu->kvm, mmu_seq)) goto out_unlock; - make_mmu_pages_available(vcpu); + kvm_mmu_free_some_pages(vcpu); if (likely(!force_pt_level)) transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level); r = __direct_map(vcpu, v, write, map_writable, level, gfn, pfn, @@ -2922,7 +2913,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) { spin_lock(&vcpu->kvm->mmu_lock); - make_mmu_pages_available(vcpu); + kvm_mmu_free_some_pages(vcpu); sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL, 1, ACC_ALL, NULL); ++sp->root_count; @@ -2934,7 +2925,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) ASSERT(!VALID_PAGE(root)); spin_lock(&vcpu->kvm->mmu_lock); - make_mmu_pages_available(vcpu); + kvm_mmu_free_some_pages(vcpu); sp = kvm_mmu_get_page(vcpu, i << (30 - PAGE_SHIFT), i << 30, PT32_ROOT_LEVEL, 1, ACC_ALL, @@ -2973,7 +2964,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) ASSERT(!VALID_PAGE(root)); spin_lock(&vcpu->kvm->mmu_lock); - make_mmu_pages_available(vcpu); + kvm_mmu_free_some_pages(vcpu); sp = kvm_mmu_get_page(vcpu, root_gfn, 0, PT64_ROOT_LEVEL, 0, ACC_ALL, NULL); root = __pa(sp->spt); @@ -3007,7 +2998,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) return 1; } spin_lock(&vcpu->kvm->mmu_lock); - make_mmu_pages_available(vcpu); + kvm_mmu_free_some_pages(vcpu); sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, PT32_ROOT_LEVEL, 0, ACC_ALL, NULL); @@ -3313,7 +3304,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code, spin_lock(&vcpu->kvm->mmu_lock); if (mmu_notifier_retry(vcpu->kvm, mmu_seq)) goto out_unlock; - make_mmu_pages_available(vcpu); + kvm_mmu_free_some_pages(vcpu); if (likely(!force_pt_level)) transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level); r = __direct_map(vcpu, gpa, write, map_writable, @@ -4015,17 +4006,17 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) } EXPORT_SYMBOL_GPL(kvm_mmu_unprotect_page_virt); -static void make_mmu_pages_available(struct kvm_vcpu *vcpu) +void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) { LIST_HEAD(invalid_list); - if (likely(kvm_mmu_available_pages(vcpu->kvm) >= KVM_MIN_FREE_MMU_PAGES)) - return; - - while (kvm_mmu_available_pages(vcpu->kvm) < KVM_REFILL_PAGES) { - if (!prepare_zap_oldest_mmu_page(vcpu->kvm, &invalid_list)) - break; + while (kvm_mmu_available_pages(vcpu->kvm) < KVM_REFILL_PAGES && + !list_empty(&vcpu->kvm->arch.active_mmu_pages)) { + struct kvm_mmu_page *sp; + sp = container_of(vcpu->kvm->arch.active_mmu_pages.prev, + struct kvm_mmu_page, link); + kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list); ++vcpu->kvm->stat.mmu_recycled; } kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); @@ -4194,22 +4185,17 @@ void kvm_mmu_zap_all(struct kvm *kvm) spin_unlock(&kvm->mmu_lock); } -void kvm_mmu_zap_mmio_sptes(struct kvm *kvm) +static void kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm, + struct list_head *invalid_list) { - struct kvm_mmu_page *sp, *node; - LIST_HEAD(invalid_list); + struct kvm_mmu_page *page; - spin_lock(&kvm->mmu_lock); -restart: - list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) { - if (!sp->mmio_cached) - continue; - if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list)) - goto restart; - } + if (list_empty(&kvm->arch.active_mmu_pages)) + return; - kvm_mmu_commit_zap_page(kvm, &invalid_list); - spin_unlock(&kvm->mmu_lock); + page = container_of(kvm->arch.active_mmu_pages.prev, + struct kvm_mmu_page, link); + kvm_mmu_prepare_zap_page(kvm, page, invalid_list); } static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc) @@ -4246,7 +4232,7 @@ static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc) idx = srcu_read_lock(&kvm->srcu); spin_lock(&kvm->mmu_lock); - prepare_zap_oldest_mmu_page(kvm, &invalid_list); + kvm_mmu_remove_some_alloc_mmu_pages(kvm, &invalid_list); kvm_mmu_commit_zap_page(kvm, &invalid_list); spin_unlock(&kvm->mmu_lock); diff --git a/trunk/arch/x86/kvm/mmu.h b/trunk/arch/x86/kvm/mmu.h index 2adcbc2cac6d..69871080e866 100644 --- a/trunk/arch/x86/kvm/mmu.h +++ b/trunk/arch/x86/kvm/mmu.h @@ -57,11 +57,14 @@ int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context); static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm) { - if (kvm->arch.n_max_mmu_pages > kvm->arch.n_used_mmu_pages) - return kvm->arch.n_max_mmu_pages - - kvm->arch.n_used_mmu_pages; + return kvm->arch.n_max_mmu_pages - + kvm->arch.n_used_mmu_pages; +} - return 0; +static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) +{ + if (unlikely(kvm_mmu_available_pages(vcpu->kvm)< KVM_MIN_FREE_MMU_PAGES)) + __kvm_mmu_free_some_pages(vcpu); } static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu) diff --git a/trunk/arch/x86/kvm/paging_tmpl.h b/trunk/arch/x86/kvm/paging_tmpl.h index da20860b457a..105dd5bd550e 100644 --- a/trunk/arch/x86/kvm/paging_tmpl.h +++ b/trunk/arch/x86/kvm/paging_tmpl.h @@ -627,7 +627,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code, goto out_unlock; kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT); - make_mmu_pages_available(vcpu); + kvm_mmu_free_some_pages(vcpu); if (!force_pt_level) transparent_hugepage_adjust(vcpu, &walker.gfn, &pfn, &level); r = FNAME(fetch)(vcpu, addr, &walker, write_fault, diff --git a/trunk/arch/x86/kvm/pmu.c b/trunk/arch/x86/kvm/pmu.c index c53e797e7369..cfc258a6bf97 100644 --- a/trunk/arch/x86/kvm/pmu.c +++ b/trunk/arch/x86/kvm/pmu.c @@ -360,12 +360,10 @@ int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data) return 1; } -int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data) { struct kvm_pmu *pmu = &vcpu->arch.pmu; struct kvm_pmc *pmc; - u32 index = msr_info->index; - u64 data = msr_info->data; switch (index) { case MSR_CORE_PERF_FIXED_CTR_CTRL: @@ -377,10 +375,6 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) } break; case MSR_CORE_PERF_GLOBAL_STATUS: - if (msr_info->host_initiated) { - pmu->global_status = data; - return 0; - } break; /* RO MSR */ case MSR_CORE_PERF_GLOBAL_CTRL: if (pmu->global_ctrl == data) @@ -392,8 +386,7 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_CORE_PERF_GLOBAL_OVF_CTRL: if (!(data & (pmu->global_ctrl_mask & ~(3ull<<62)))) { - if (!msr_info->host_initiated) - pmu->global_status &= ~data; + pmu->global_status &= ~data; pmu->global_ovf_ctrl = data; return 0; } @@ -401,8 +394,7 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) default: if ((pmc = get_gp_pmc(pmu, index, MSR_IA32_PERFCTR0)) || (pmc = get_fixed_pmc(pmu, index))) { - if (!msr_info->host_initiated) - data = (s64)(s32)data; + data = (s64)(s32)data; pmc->counter += data - read_pmc(pmc); return 0; } else if ((pmc = get_gp_pmc(pmu, index, MSR_P6_EVNTSEL0))) { diff --git a/trunk/arch/x86/kvm/svm.c b/trunk/arch/x86/kvm/svm.c index a14a6eaf871d..7d39d70647e3 100644 --- a/trunk/arch/x86/kvm/svm.c +++ b/trunk/arch/x86/kvm/svm.c @@ -1131,11 +1131,17 @@ static void init_vmcb(struct vcpu_svm *svm) init_seg(&save->gs); save->cs.selector = 0xf000; - save->cs.base = 0xffff0000; /* Executable/Readable Code Segment */ save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK; save->cs.limit = 0xffff; + /* + * cs.base should really be 0xffff0000, but vmx can't handle that, so + * be consistent with it. + * + * Replace when we have real mode working for vmx. + */ + save->cs.base = 0xf0000; save->gdtr.limit = 0xffff; save->idtr.limit = 0xffff; @@ -1185,7 +1191,7 @@ static void init_vmcb(struct vcpu_svm *svm) enable_gif(svm); } -static void svm_vcpu_reset(struct kvm_vcpu *vcpu) +static int svm_vcpu_reset(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); u32 dummy; @@ -1193,8 +1199,16 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu) init_vmcb(svm); + if (!kvm_vcpu_is_bsp(vcpu)) { + kvm_rip_write(vcpu, 0); + svm->vmcb->save.cs.base = svm->vcpu.arch.sipi_vector << 12; + svm->vmcb->save.cs.selector = svm->vcpu.arch.sipi_vector << 8; + } + kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy); kvm_register_write(vcpu, VCPU_REGS_RDX, eax); + + return 0; } static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) @@ -3473,7 +3487,7 @@ static int handle_exit(struct kvm_vcpu *vcpu) exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR && exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH && exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI) - printk(KERN_ERR "%s: unexpected exit_int_info 0x%x " + printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " "exit_code 0x%x\n", __func__, svm->vmcb->control.exit_int_info, exit_code); @@ -3577,11 +3591,6 @@ static void svm_hwapic_isr_update(struct kvm *kvm, int isr) return; } -static void svm_sync_pir_to_irr(struct kvm_vcpu *vcpu) -{ - return; -} - static int svm_nmi_allowed(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3632,7 +3641,7 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu) return ret; } -static int enable_irq_window(struct kvm_vcpu *vcpu) +static void enable_irq_window(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3646,16 +3655,15 @@ static int enable_irq_window(struct kvm_vcpu *vcpu) svm_set_vintr(svm); svm_inject_irq(svm, 0x0); } - return 0; } -static int enable_nmi_window(struct kvm_vcpu *vcpu) +static void enable_nmi_window(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK)) == HF_NMI_MASK) - return 0; /* IRET will cause a vm exit */ + return; /* IRET will cause a vm exit */ /* * Something prevents NMI from been injected. Single step over possible @@ -3664,7 +3672,6 @@ static int enable_nmi_window(struct kvm_vcpu *vcpu) svm->nmi_singlestep = true; svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); update_db_bp_intercept(vcpu); - return 0; } static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) @@ -4240,11 +4247,6 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu, return ret; } -static void svm_handle_external_intr(struct kvm_vcpu *vcpu) -{ - local_irq_enable(); -} - static struct kvm_x86_ops svm_x86_ops = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, @@ -4312,7 +4314,6 @@ static struct kvm_x86_ops svm_x86_ops = { .vm_has_apicv = svm_vm_has_apicv, .load_eoi_exitmap = svm_load_eoi_exitmap, .hwapic_isr_update = svm_hwapic_isr_update, - .sync_pir_to_irr = svm_sync_pir_to_irr, .set_tss_addr = svm_set_tss_addr, .get_tdp_level = get_npt_level, @@ -4341,7 +4342,6 @@ static struct kvm_x86_ops svm_x86_ops = { .set_tdp_cr3 = set_tdp_cr3, .check_intercept = svm_check_intercept, - .handle_external_intr = svm_handle_external_intr, }; static int __init svm_init(void) diff --git a/trunk/arch/x86/kvm/vmx.c b/trunk/arch/x86/kvm/vmx.c index 25a791ed21c8..867b81037f96 100644 --- a/trunk/arch/x86/kvm/vmx.c +++ b/trunk/arch/x86/kvm/vmx.c @@ -84,11 +84,8 @@ module_param(vmm_exclusive, bool, S_IRUGO); static bool __read_mostly fasteoi = 1; module_param(fasteoi, bool, S_IRUGO); -static bool __read_mostly enable_apicv = 1; -module_param(enable_apicv, bool, S_IRUGO); +static bool __read_mostly enable_apicv_reg_vid; -static bool __read_mostly enable_shadow_vmcs = 1; -module_param_named(enable_shadow_vmcs, enable_shadow_vmcs, bool, S_IRUGO); /* * If nested=1, nested virtualization is supported, i.e., guests may use * VMX and be a hypervisor for its own guests. If nested=0, guests may not @@ -301,8 +298,7 @@ struct __packed vmcs12 { u32 guest_activity_state; u32 guest_sysenter_cs; u32 host_ia32_sysenter_cs; - u32 vmx_preemption_timer_value; - u32 padding32[7]; /* room for future expansion */ + u32 padding32[8]; /* room for future expansion */ u16 virtual_processor_id; u16 guest_es_selector; u16 guest_cs_selector; @@ -355,12 +351,6 @@ struct nested_vmx { /* The host-usable pointer to the above */ struct page *current_vmcs12_page; struct vmcs12 *current_vmcs12; - struct vmcs *current_shadow_vmcs; - /* - * Indicates if the shadow vmcs must be updated with the - * data hold by vmcs12 - */ - bool sync_shadow_vmcs; /* vmcs02_list cache of VMCSs recently used to run L2 guests */ struct list_head vmcs02_pool; @@ -375,31 +365,6 @@ struct nested_vmx { struct page *apic_access_page; }; -#define POSTED_INTR_ON 0 -/* Posted-Interrupt Descriptor */ -struct pi_desc { - u32 pir[8]; /* Posted interrupt requested */ - u32 control; /* bit 0 of control is outstanding notification bit */ - u32 rsvd[7]; -} __aligned(64); - -static bool pi_test_and_set_on(struct pi_desc *pi_desc) -{ - return test_and_set_bit(POSTED_INTR_ON, - (unsigned long *)&pi_desc->control); -} - -static bool pi_test_and_clear_on(struct pi_desc *pi_desc) -{ - return test_and_clear_bit(POSTED_INTR_ON, - (unsigned long *)&pi_desc->control); -} - -static int pi_test_and_set_pir(int vector, struct pi_desc *pi_desc) -{ - return test_and_set_bit(vector, (unsigned long *)pi_desc->pir); -} - struct vcpu_vmx { struct kvm_vcpu vcpu; unsigned long host_rsp; @@ -412,7 +377,6 @@ struct vcpu_vmx { struct shared_msr_entry *guest_msrs; int nmsrs; int save_nmsrs; - unsigned long host_idt_base; #ifdef CONFIG_X86_64 u64 msr_host_kernel_gs_base; u64 msr_guest_kernel_gs_base; @@ -464,9 +428,6 @@ struct vcpu_vmx { bool rdtscp_enabled; - /* Posted interrupt descriptor */ - struct pi_desc pi_desc; - /* Support for a guest hypervisor (nested VMX) */ struct nested_vmx nested; }; @@ -490,64 +451,6 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) #define FIELD64(number, name) [number] = VMCS12_OFFSET(name), \ [number##_HIGH] = VMCS12_OFFSET(name)+4 - -static const unsigned long shadow_read_only_fields[] = { - /* - * We do NOT shadow fields that are modified when L0 - * traps and emulates any vmx instruction (e.g. VMPTRLD, - * VMXON...) executed by L1. - * For example, VM_INSTRUCTION_ERROR is read - * by L1 if a vmx instruction fails (part of the error path). - * Note the code assumes this logic. If for some reason - * we start shadowing these fields then we need to - * force a shadow sync when L0 emulates vmx instructions - * (e.g. force a sync if VM_INSTRUCTION_ERROR is modified - * by nested_vmx_failValid) - */ - VM_EXIT_REASON, - VM_EXIT_INTR_INFO, - VM_EXIT_INSTRUCTION_LEN, - IDT_VECTORING_INFO_FIELD, - IDT_VECTORING_ERROR_CODE, - VM_EXIT_INTR_ERROR_CODE, - EXIT_QUALIFICATION, - GUEST_LINEAR_ADDRESS, - GUEST_PHYSICAL_ADDRESS -}; -static const int max_shadow_read_only_fields = - ARRAY_SIZE(shadow_read_only_fields); - -static const unsigned long shadow_read_write_fields[] = { - GUEST_RIP, - GUEST_RSP, - GUEST_CR0, - GUEST_CR3, - GUEST_CR4, - GUEST_INTERRUPTIBILITY_INFO, - GUEST_RFLAGS, - GUEST_CS_SELECTOR, - GUEST_CS_AR_BYTES, - GUEST_CS_LIMIT, - GUEST_CS_BASE, - GUEST_ES_BASE, - CR0_GUEST_HOST_MASK, - CR0_READ_SHADOW, - CR4_READ_SHADOW, - TSC_OFFSET, - EXCEPTION_BITMAP, - CPU_BASED_VM_EXEC_CONTROL, - VM_ENTRY_EXCEPTION_ERROR_CODE, - VM_ENTRY_INTR_INFO_FIELD, - VM_ENTRY_INSTRUCTION_LEN, - VM_ENTRY_EXCEPTION_ERROR_CODE, - HOST_FS_BASE, - HOST_GS_BASE, - HOST_FS_SELECTOR, - HOST_GS_SELECTOR -}; -static const int max_shadow_read_write_fields = - ARRAY_SIZE(shadow_read_write_fields); - static const unsigned short vmcs_field_to_offset_table[] = { FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id), FIELD(GUEST_ES_SELECTOR, guest_es_selector), @@ -634,7 +537,6 @@ static const unsigned short vmcs_field_to_offset_table[] = { FIELD(GUEST_ACTIVITY_STATE, guest_activity_state), FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs), FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs), - FIELD(VMX_PREEMPTION_TIMER_VALUE, vmx_preemption_timer_value), FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask), FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask), FIELD(CR0_READ_SHADOW, cr0_read_shadow), @@ -722,9 +624,6 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); static bool guest_state_valid(struct kvm_vcpu *vcpu); static u32 vmx_segment_access_rights(struct kvm_segment *var); -static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu); -static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx); -static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx); static DEFINE_PER_CPU(struct vmcs *, vmxarea); static DEFINE_PER_CPU(struct vmcs *, current_vmcs); @@ -741,8 +640,6 @@ static unsigned long *vmx_msr_bitmap_legacy; static unsigned long *vmx_msr_bitmap_longmode; static unsigned long *vmx_msr_bitmap_legacy_x2apic; static unsigned long *vmx_msr_bitmap_longmode_x2apic; -static unsigned long *vmx_vmread_bitmap; -static unsigned long *vmx_vmwrite_bitmap; static bool cpu_has_load_ia32_efer; static bool cpu_has_load_perf_global_ctrl; @@ -885,18 +782,6 @@ static inline bool cpu_has_vmx_virtual_intr_delivery(void) SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; } -static inline bool cpu_has_vmx_posted_intr(void) -{ - return vmcs_config.pin_based_exec_ctrl & PIN_BASED_POSTED_INTR; -} - -static inline bool cpu_has_vmx_apicv(void) -{ - return cpu_has_vmx_apic_register_virt() && - cpu_has_vmx_virtual_intr_delivery() && - cpu_has_vmx_posted_intr(); -} - static inline bool cpu_has_vmx_flexpriority(void) { return cpu_has_vmx_tpr_shadow() && @@ -1010,18 +895,6 @@ static inline bool cpu_has_vmx_wbinvd_exit(void) SECONDARY_EXEC_WBINVD_EXITING; } -static inline bool cpu_has_vmx_shadow_vmcs(void) -{ - u64 vmx_msr; - rdmsrl(MSR_IA32_VMX_MISC, vmx_msr); - /* check if the cpu supports writing r/o exit information fields */ - if (!(vmx_msr & MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS)) - return false; - - return vmcs_config.cpu_based_2nd_exec_ctrl & - SECONDARY_EXEC_SHADOW_VMCS; -} - static inline bool report_flexpriority(void) { return flexpriority_enabled; @@ -1917,7 +1790,7 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, u32 intr_info = nr | INTR_INFO_VALID_MASK; if (nr == PF_VECTOR && is_guest_mode(vcpu) && - !vmx->nested.nested_run_pending && nested_pf_handled(vcpu)) + nested_pf_handled(vcpu)) return; if (has_error_code) { @@ -2149,7 +2022,6 @@ static u32 nested_vmx_secondary_ctls_low, nested_vmx_secondary_ctls_high; static u32 nested_vmx_pinbased_ctls_low, nested_vmx_pinbased_ctls_high; static u32 nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high; static u32 nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high; -static u32 nested_vmx_misc_low, nested_vmx_misc_high; static __init void nested_vmx_setup_ctls_msrs(void) { /* @@ -2168,40 +2040,30 @@ static __init void nested_vmx_setup_ctls_msrs(void) */ /* pin-based controls */ - rdmsr(MSR_IA32_VMX_PINBASED_CTLS, - nested_vmx_pinbased_ctls_low, nested_vmx_pinbased_ctls_high); /* * According to the Intel spec, if bit 55 of VMX_BASIC is off (as it is * in our case), bits 1, 2 and 4 (i.e., 0x16) must be 1 in this MSR. */ - nested_vmx_pinbased_ctls_low |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR; - nested_vmx_pinbased_ctls_high &= PIN_BASED_EXT_INTR_MASK | - PIN_BASED_NMI_EXITING | PIN_BASED_VIRTUAL_NMIS | - PIN_BASED_VMX_PREEMPTION_TIMER; - nested_vmx_pinbased_ctls_high |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR; + nested_vmx_pinbased_ctls_low = 0x16 ; + nested_vmx_pinbased_ctls_high = 0x16 | + PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING | + PIN_BASED_VIRTUAL_NMIS; - /* - * Exit controls - * If bit 55 of VMX_BASIC is off, bits 0-8 and 10, 11, 13, 14, 16 and - * 17 must be 1. - */ - nested_vmx_exit_ctls_low = VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR; + /* exit controls */ + nested_vmx_exit_ctls_low = 0; /* Note that guest use of VM_EXIT_ACK_INTR_ON_EXIT is not supported. */ #ifdef CONFIG_X86_64 nested_vmx_exit_ctls_high = VM_EXIT_HOST_ADDR_SPACE_SIZE; #else nested_vmx_exit_ctls_high = 0; #endif - nested_vmx_exit_ctls_high |= VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR; /* entry controls */ rdmsr(MSR_IA32_VMX_ENTRY_CTLS, nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high); - /* If bit 55 of VMX_BASIC is off, bits 0-8 and 12 must be 1. */ - nested_vmx_entry_ctls_low = VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR; + nested_vmx_entry_ctls_low = 0; nested_vmx_entry_ctls_high &= VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_IA32E_MODE; - nested_vmx_entry_ctls_high |= VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR; /* cpu-based controls */ rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, @@ -2218,7 +2080,6 @@ static __init void nested_vmx_setup_ctls_msrs(void) CPU_BASED_MOV_DR_EXITING | CPU_BASED_UNCOND_IO_EXITING | CPU_BASED_USE_IO_BITMAPS | CPU_BASED_MONITOR_EXITING | CPU_BASED_RDPMC_EXITING | CPU_BASED_RDTSC_EXITING | - CPU_BASED_PAUSE_EXITING | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; /* * We can allow some features even when not supported by the @@ -2233,14 +2094,7 @@ static __init void nested_vmx_setup_ctls_msrs(void) nested_vmx_secondary_ctls_low, nested_vmx_secondary_ctls_high); nested_vmx_secondary_ctls_low = 0; nested_vmx_secondary_ctls_high &= - SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | - SECONDARY_EXEC_WBINVD_EXITING; - - /* miscellaneous data */ - rdmsr(MSR_IA32_VMX_MISC, nested_vmx_misc_low, nested_vmx_misc_high); - nested_vmx_misc_low &= VMX_MISC_PREEMPTION_TIMER_RATE_MASK | - VMX_MISC_SAVE_EFER_LMA; - nested_vmx_misc_high = 0; + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; } static inline bool vmx_control_verify(u32 control, u32 low, u32 high) @@ -2311,8 +2165,7 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) nested_vmx_entry_ctls_high); break; case MSR_IA32_VMX_MISC: - *pdata = vmx_control_msr(nested_vmx_misc_low, - nested_vmx_misc_high); + *pdata = 0; break; /* * These MSRs specify bits which the guest must keep fixed (on or off) @@ -2676,6 +2529,12 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) u32 _vmexit_control = 0; u32 _vmentry_control = 0; + min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; + opt = PIN_BASED_VIRTUAL_NMIS; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, + &_pin_based_exec_control) < 0) + return -EIO; + min = CPU_BASED_HLT_EXITING | #ifdef CONFIG_X86_64 CPU_BASED_CR8_LOAD_EXITING | @@ -2714,8 +2573,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) SECONDARY_EXEC_RDTSCP | SECONDARY_EXEC_ENABLE_INVPCID | SECONDARY_EXEC_APIC_REGISTER_VIRT | - SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | - SECONDARY_EXEC_SHADOW_VMCS; + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; if (adjust_vmx_controls(min2, opt2, MSR_IA32_VMX_PROCBASED_CTLS2, &_cpu_based_2nd_exec_control) < 0) @@ -2747,23 +2605,11 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) #ifdef CONFIG_X86_64 min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; #endif - opt = VM_EXIT_SAVE_IA32_PAT | VM_EXIT_LOAD_IA32_PAT | - VM_EXIT_ACK_INTR_ON_EXIT; + opt = VM_EXIT_SAVE_IA32_PAT | VM_EXIT_LOAD_IA32_PAT; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, &_vmexit_control) < 0) return -EIO; - min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; - opt = PIN_BASED_VIRTUAL_NMIS | PIN_BASED_POSTED_INTR; - if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, - &_pin_based_exec_control) < 0) - return -EIO; - - if (!(_cpu_based_2nd_exec_control & - SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY) || - !(_vmexit_control & VM_EXIT_ACK_INTR_ON_EXIT)) - _pin_based_exec_control &= ~PIN_BASED_POSTED_INTR; - min = 0; opt = VM_ENTRY_LOAD_IA32_PAT; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, @@ -2916,8 +2762,6 @@ static __init int hardware_setup(void) if (!cpu_has_vmx_vpid()) enable_vpid = 0; - if (!cpu_has_vmx_shadow_vmcs()) - enable_shadow_vmcs = 0; if (!cpu_has_vmx_ept() || !cpu_has_vmx_ept_4levels()) { @@ -2944,16 +2788,14 @@ static __init int hardware_setup(void) if (!cpu_has_vmx_ple()) ple_gap = 0; - if (!cpu_has_vmx_apicv()) - enable_apicv = 0; + if (!cpu_has_vmx_apic_register_virt() || + !cpu_has_vmx_virtual_intr_delivery()) + enable_apicv_reg_vid = 0; - if (enable_apicv) + if (enable_apicv_reg_vid) kvm_x86_ops->update_cr8_intercept = NULL; - else { + else kvm_x86_ops->hwapic_irr_update = NULL; - kvm_x86_ops->deliver_posted_interrupt = NULL; - kvm_x86_ops->sync_pir_to_irr = vmx_sync_pir_to_irr_dummy; - } if (nested) nested_vmx_setup_ctls_msrs(); @@ -3034,6 +2876,22 @@ static void enter_pmode(struct kvm_vcpu *vcpu) vmx->cpl = 0; } +static gva_t rmode_tss_base(struct kvm *kvm) +{ + if (!kvm->arch.tss_addr) { + struct kvm_memslots *slots; + struct kvm_memory_slot *slot; + gfn_t base_gfn; + + slots = kvm_memslots(kvm); + slot = id_to_memslot(slots, 0); + base_gfn = slot->base_gfn + slot->npages - 3; + + return base_gfn << PAGE_SHIFT; + } + return kvm->arch.tss_addr; +} + static void fix_rmode_seg(int seg, struct kvm_segment *save) { const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; @@ -3084,15 +2942,19 @@ static void enter_rmode(struct kvm_vcpu *vcpu) /* * Very old userspace does not call KVM_SET_TSS_ADDR before entering - * vcpu. Warn the user that an update is overdue. + * vcpu. Call it here with phys address pointing 16M below 4G. */ - if (!vcpu->kvm->arch.tss_addr) + if (!vcpu->kvm->arch.tss_addr) { printk_once(KERN_WARNING "kvm: KVM_SET_TSS_ADDR need to be " "called before entering vcpu\n"); + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); + vmx_set_tss_addr(vcpu->kvm, 0xfeffd000); + vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); + } vmx_segment_cache_clear(vmx); - vmcs_writel(GUEST_TR_BASE, vcpu->kvm->arch.tss_addr); + vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm)); vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1); vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); @@ -3352,9 +3214,7 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) */ if (!nested_vmx_allowed(vcpu)) return 1; - } - if (to_vmx(vcpu)->nested.vmxon && - ((cr4 & VMXON_CR4_ALWAYSON) != VMXON_CR4_ALWAYSON)) + } else if (to_vmx(vcpu)->nested.vmxon) return 1; vcpu->arch.cr4 = cr4; @@ -3690,7 +3550,7 @@ static bool guest_state_valid(struct kvm_vcpu *vcpu) return true; /* real mode guest state checks */ - if (!is_protmode(vcpu) || (vmx_get_rflags(vcpu) & X86_EFLAGS_VM)) { + if (!is_protmode(vcpu)) { if (!rmode_segment_valid(vcpu, VCPU_SREG_CS)) return false; if (!rmode_segment_valid(vcpu, VCPU_SREG_SS)) @@ -3739,7 +3599,7 @@ static int init_rmode_tss(struct kvm *kvm) int r, idx, ret = 0; idx = srcu_read_lock(&kvm->srcu); - fn = kvm->arch.tss_addr >> PAGE_SHIFT; + fn = rmode_tss_base(kvm) >> PAGE_SHIFT; r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE); if (r < 0) goto out; @@ -3832,7 +3692,7 @@ static int alloc_apic_access_page(struct kvm *kvm) kvm_userspace_mem.flags = 0; kvm_userspace_mem.guest_phys_addr = 0xfee00000ULL; kvm_userspace_mem.memory_size = PAGE_SIZE; - r = __kvm_set_memory_region(kvm, &kvm_userspace_mem); + r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, false); if (r) goto out; @@ -3862,7 +3722,7 @@ static int alloc_identity_pagetable(struct kvm *kvm) kvm_userspace_mem.guest_phys_addr = kvm->arch.ept_identity_map_addr; kvm_userspace_mem.memory_size = PAGE_SIZE; - r = __kvm_set_memory_region(kvm, &kvm_userspace_mem); + r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, false); if (r) goto out; @@ -4009,59 +3869,13 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr) msr, MSR_TYPE_W); } -static int vmx_vm_has_apicv(struct kvm *kvm) -{ - return enable_apicv && irqchip_in_kernel(kvm); -} - -/* - * Send interrupt to vcpu via posted interrupt way. - * 1. If target vcpu is running(non-root mode), send posted interrupt - * notification to vcpu and hardware will sync PIR to vIRR atomically. - * 2. If target vcpu isn't running(root mode), kick it to pick up the - * interrupt from PIR in next vmentry. - */ -static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - int r; - - if (pi_test_and_set_pir(vector, &vmx->pi_desc)) - return; - - r = pi_test_and_set_on(&vmx->pi_desc); - kvm_make_request(KVM_REQ_EVENT, vcpu); -#ifdef CONFIG_SMP - if (!r && (vcpu->mode == IN_GUEST_MODE)) - apic->send_IPI_mask(get_cpu_mask(vcpu->cpu), - POSTED_INTR_VECTOR); - else -#endif - kvm_vcpu_kick(vcpu); -} - -static void vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - - if (!pi_test_and_clear_on(&vmx->pi_desc)) - return; - - kvm_apic_update_irr(vcpu, vmx->pi_desc.pir); -} - -static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu) -{ - return; -} - /* * Set up the vmcs's constant host-state fields, i.e., host-state fields that * will not change in the lifetime of the guest. * Note that host-state that does change is set elsewhere. E.g., host-state * that is set differently for each CPU is set in vmx_vcpu_load(), not here. */ -static void vmx_set_constant_host_state(struct vcpu_vmx *vmx) +static void vmx_set_constant_host_state(void) { u32 low32, high32; unsigned long tmpl; @@ -4089,7 +3903,6 @@ static void vmx_set_constant_host_state(struct vcpu_vmx *vmx) native_store_idt(&dt); vmcs_writel(HOST_IDTR_BASE, dt.address); /* 22.2.4 */ - vmx->host_idt_base = dt.address; vmcs_writel(HOST_RIP, vmx_return); /* 22.2.5 */ @@ -4115,15 +3928,6 @@ static void set_cr4_guest_host_mask(struct vcpu_vmx *vmx) vmcs_writel(CR4_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr4_guest_owned_bits); } -static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx) -{ - u32 pin_based_exec_ctrl = vmcs_config.pin_based_exec_ctrl; - - if (!vmx_vm_has_apicv(vmx->vcpu.kvm)) - pin_based_exec_ctrl &= ~PIN_BASED_POSTED_INTR; - return pin_based_exec_ctrl; -} - static u32 vmx_exec_control(struct vcpu_vmx *vmx) { u32 exec_control = vmcs_config.cpu_based_exec_ctrl; @@ -4141,6 +3945,11 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx) return exec_control; } +static int vmx_vm_has_apicv(struct kvm *kvm) +{ + return enable_apicv_reg_vid && irqchip_in_kernel(kvm); +} + static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx) { u32 exec_control = vmcs_config.cpu_based_2nd_exec_ctrl; @@ -4162,12 +3971,6 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx) exec_control &= ~(SECONDARY_EXEC_APIC_REGISTER_VIRT | SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE; - /* SECONDARY_EXEC_SHADOW_VMCS is enabled when L1 executes VMPTRLD - (handle_vmptrld). - We can NOT enable shadow_vmcs here because we don't have yet - a current VMCS12 - */ - exec_control &= ~SECONDARY_EXEC_SHADOW_VMCS; return exec_control; } @@ -4196,17 +3999,14 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmcs_write64(IO_BITMAP_A, __pa(vmx_io_bitmap_a)); vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b)); - if (enable_shadow_vmcs) { - vmcs_write64(VMREAD_BITMAP, __pa(vmx_vmread_bitmap)); - vmcs_write64(VMWRITE_BITMAP, __pa(vmx_vmwrite_bitmap)); - } if (cpu_has_vmx_msr_bitmap()) vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy)); vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ /* Control */ - vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx)); + vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, + vmcs_config.pin_based_exec_ctrl); vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, vmx_exec_control(vmx)); @@ -4215,16 +4015,13 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmx_secondary_exec_control(vmx)); } - if (vmx_vm_has_apicv(vmx->vcpu.kvm)) { + if (enable_apicv_reg_vid) { vmcs_write64(EOI_EXIT_BITMAP0, 0); vmcs_write64(EOI_EXIT_BITMAP1, 0); vmcs_write64(EOI_EXIT_BITMAP2, 0); vmcs_write64(EOI_EXIT_BITMAP3, 0); vmcs_write16(GUEST_INTR_STATUS, 0); - - vmcs_write64(POSTED_INTR_NV, POSTED_INTR_VECTOR); - vmcs_write64(POSTED_INTR_DESC_ADDR, __pa((&vmx->pi_desc))); } if (ple_gap) { @@ -4238,7 +4035,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmcs_write16(HOST_FS_SELECTOR, 0); /* 22.2.4 */ vmcs_write16(HOST_GS_SELECTOR, 0); /* 22.2.4 */ - vmx_set_constant_host_state(vmx); + vmx_set_constant_host_state(); #ifdef CONFIG_X86_64 rdmsrl(MSR_FS_BASE, a); vmcs_writel(HOST_FS_BASE, a); /* 22.2.4 */ @@ -4292,10 +4089,11 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) return 0; } -static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) +static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); u64 msr; + int ret; vmx->rmode.vm86_active = 0; @@ -4311,8 +4109,12 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) vmx_segment_cache_clear(vmx); seg_setup(VCPU_SREG_CS); - vmcs_write16(GUEST_CS_SELECTOR, 0xf000); - vmcs_write32(GUEST_CS_BASE, 0xffff0000); + if (kvm_vcpu_is_bsp(&vmx->vcpu)) + vmcs_write16(GUEST_CS_SELECTOR, 0xf000); + else { + vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.arch.sipi_vector << 8); + vmcs_writel(GUEST_CS_BASE, vmx->vcpu.arch.sipi_vector << 12); + } seg_setup(VCPU_SREG_DS); seg_setup(VCPU_SREG_ES); @@ -4335,7 +4137,10 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) vmcs_writel(GUEST_SYSENTER_EIP, 0); vmcs_writel(GUEST_RFLAGS, 0x02); - kvm_rip_write(vcpu, 0xfff0); + if (kvm_vcpu_is_bsp(&vmx->vcpu)) + kvm_rip_write(vcpu, 0xfff0); + else + kvm_rip_write(vcpu, 0); vmcs_writel(GUEST_GDTR_BASE, 0); vmcs_write32(GUEST_GDTR_LIMIT, 0xffff); @@ -4366,20 +4171,23 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) vmcs_write64(APIC_ACCESS_ADDR, page_to_phys(vmx->vcpu.kvm->arch.apic_access_page)); - if (vmx_vm_has_apicv(vcpu->kvm)) - memset(&vmx->pi_desc, 0, sizeof(struct pi_desc)); - if (vmx->vpid != 0) vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET; + vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu)); /* enter rmode */ + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); vmx_set_cr4(&vmx->vcpu, 0); vmx_set_efer(&vmx->vcpu, 0); vmx_fpu_activate(&vmx->vcpu); update_exception_bitmap(&vmx->vcpu); vpid_sync_context(vmx); + + ret = 0; + + return ret; } /* @@ -4392,45 +4200,40 @@ static bool nested_exit_on_intr(struct kvm_vcpu *vcpu) PIN_BASED_EXT_INTR_MASK; } -static bool nested_exit_on_nmi(struct kvm_vcpu *vcpu) -{ - return get_vmcs12(vcpu)->pin_based_vm_exec_control & - PIN_BASED_NMI_EXITING; -} - -static int enable_irq_window(struct kvm_vcpu *vcpu) +static void enable_irq_window(struct kvm_vcpu *vcpu) { u32 cpu_based_vm_exec_control; - - if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu)) + if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu)) { /* * We get here if vmx_interrupt_allowed() said we can't - * inject to L1 now because L2 must run. The caller will have - * to make L2 exit right after entry, so we can inject to L1 - * more promptly. + * inject to L1 now because L2 must run. Ask L2 to exit + * right after entry, so we can inject to L1 more promptly. */ - return -EBUSY; + kvm_make_request(KVM_REQ_IMMEDIATE_EXIT, vcpu); + return; + } cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); - return 0; } -static int enable_nmi_window(struct kvm_vcpu *vcpu) +static void enable_nmi_window(struct kvm_vcpu *vcpu) { u32 cpu_based_vm_exec_control; - if (!cpu_has_virtual_nmis()) - return enable_irq_window(vcpu); - - if (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI) - return enable_irq_window(vcpu); + if (!cpu_has_virtual_nmis()) { + enable_irq_window(vcpu); + return; + } + if (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI) { + enable_irq_window(vcpu); + return; + } cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_NMI_PENDING; vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); - return 0; } static void vmx_inject_irq(struct kvm_vcpu *vcpu) @@ -4491,6 +4294,16 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu) INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR); } +static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) +{ + if (!cpu_has_virtual_nmis() && to_vmx(vcpu)->soft_vnmi_blocked) + return 0; + + return !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + (GUEST_INTR_STATE_MOV_SS | GUEST_INTR_STATE_STI + | GUEST_INTR_STATE_NMI)); +} + static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu) { if (!cpu_has_virtual_nmis()) @@ -4520,52 +4333,18 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) } } -static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) -{ - if (is_guest_mode(vcpu)) { - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - - if (to_vmx(vcpu)->nested.nested_run_pending) - return 0; - if (nested_exit_on_nmi(vcpu)) { - nested_vmx_vmexit(vcpu); - vmcs12->vm_exit_reason = EXIT_REASON_EXCEPTION_NMI; - vmcs12->vm_exit_intr_info = NMI_VECTOR | - INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK; - /* - * The NMI-triggered VM exit counts as injection: - * clear this one and block further NMIs. - */ - vcpu->arch.nmi_pending = 0; - vmx_set_nmi_mask(vcpu, true); - return 0; - } - } - - if (!cpu_has_virtual_nmis() && to_vmx(vcpu)->soft_vnmi_blocked) - return 0; - - return !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & - (GUEST_INTR_STATE_MOV_SS | GUEST_INTR_STATE_STI - | GUEST_INTR_STATE_NMI)); -} - static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) { - if (is_guest_mode(vcpu)) { + if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu)) { struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - - if (to_vmx(vcpu)->nested.nested_run_pending) + if (to_vmx(vcpu)->nested.nested_run_pending || + (vmcs12->idt_vectoring_info_field & + VECTORING_INFO_VALID_MASK)) return 0; - if (nested_exit_on_intr(vcpu)) { - nested_vmx_vmexit(vcpu); - vmcs12->vm_exit_reason = - EXIT_REASON_EXTERNAL_INTERRUPT; - vmcs12->vm_exit_intr_info = 0; - /* - * fall through to normal code, but now in L1, not L2 - */ - } + nested_vmx_vmexit(vcpu); + vmcs12->vm_exit_reason = EXIT_REASON_EXTERNAL_INTERRUPT; + vmcs12->vm_exit_intr_info = 0; + /* fall through to normal code, but now in L1, not L2 */ } return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && @@ -4583,7 +4362,7 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr) .flags = 0, }; - ret = kvm_set_memory_region(kvm, &tss_mem); + ret = kvm_set_memory_region(kvm, &tss_mem, false); if (ret) return ret; kvm->arch.tss_addr = addr; @@ -4824,50 +4603,34 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) /* called to set cr0 as appropriate for a mov-to-cr0 exit. */ static int handle_set_cr0(struct kvm_vcpu *vcpu, unsigned long val) { - if (is_guest_mode(vcpu)) { - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - unsigned long orig_val = val; + if (to_vmx(vcpu)->nested.vmxon && + ((val & VMXON_CR0_ALWAYSON) != VMXON_CR0_ALWAYSON)) + return 1; + if (is_guest_mode(vcpu)) { /* * We get here when L2 changed cr0 in a way that did not change * any of L1's shadowed bits (see nested_vmx_exit_handled_cr), - * but did change L0 shadowed bits. So we first calculate the - * effective cr0 value that L1 would like to write into the - * hardware. It consists of the L2-owned bits from the new - * value combined with the L1-owned bits from L1's guest_cr0. + * but did change L0 shadowed bits. This can currently happen + * with the TS bit: L0 may want to leave TS on (for lazy fpu + * loading) while pretending to allow the guest to change it. */ - val = (val & ~vmcs12->cr0_guest_host_mask) | - (vmcs12->guest_cr0 & vmcs12->cr0_guest_host_mask); - - /* TODO: will have to take unrestricted guest mode into - * account */ - if ((val & VMXON_CR0_ALWAYSON) != VMXON_CR0_ALWAYSON) + if (kvm_set_cr0(vcpu, (val & vcpu->arch.cr0_guest_owned_bits) | + (vcpu->arch.cr0 & ~vcpu->arch.cr0_guest_owned_bits))) return 1; - - if (kvm_set_cr0(vcpu, val)) - return 1; - vmcs_writel(CR0_READ_SHADOW, orig_val); + vmcs_writel(CR0_READ_SHADOW, val); return 0; - } else { - if (to_vmx(vcpu)->nested.vmxon && - ((val & VMXON_CR0_ALWAYSON) != VMXON_CR0_ALWAYSON)) - return 1; + } else return kvm_set_cr0(vcpu, val); - } } static int handle_set_cr4(struct kvm_vcpu *vcpu, unsigned long val) { if (is_guest_mode(vcpu)) { - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - unsigned long orig_val = val; - - /* analogously to handle_set_cr0 */ - val = (val & ~vmcs12->cr4_guest_host_mask) | - (vmcs12->guest_cr4 & vmcs12->cr4_guest_host_mask); - if (kvm_set_cr4(vcpu, val)) + if (kvm_set_cr4(vcpu, (val & vcpu->arch.cr4_guest_owned_bits) | + (vcpu->arch.cr4 & ~vcpu->arch.cr4_guest_owned_bits))) return 1; - vmcs_writel(CR4_READ_SHADOW, orig_val); + vmcs_writel(CR4_READ_SHADOW, val); return 0; } else return kvm_set_cr4(vcpu, val); @@ -5420,7 +5183,7 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) if (test_bit(KVM_REQ_EVENT, &vcpu->requests)) return 1; - err = emulate_instruction(vcpu, EMULTYPE_NO_REEXECUTE); + err = emulate_instruction(vcpu, 0); if (err == EMULATE_DO_MMIO) { ret = 0; @@ -5496,7 +5259,8 @@ static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx) } /* Create a new VMCS */ - item = kmalloc(sizeof(struct vmcs02_list), GFP_KERNEL); + item = (struct vmcs02_list *) + kmalloc(sizeof(struct vmcs02_list), GFP_KERNEL); if (!item) return NULL; item->vmcs02.vmcs = alloc_vmcs(); @@ -5545,9 +5309,6 @@ static void nested_free_all_saved_vmcss(struct vcpu_vmx *vmx) free_loaded_vmcs(&vmx->vmcs01); } -static void nested_vmx_failValid(struct kvm_vcpu *vcpu, - u32 vm_instruction_error); - /* * Emulate the VMXON instruction. * Currently, we just remember that VMX is active, and do not save or even @@ -5560,7 +5321,6 @@ static int handle_vmon(struct kvm_vcpu *vcpu) { struct kvm_segment cs; struct vcpu_vmx *vmx = to_vmx(vcpu); - struct vmcs *shadow_vmcs; /* The Intel VMX Instruction Reference lists a bunch of bits that * are prerequisite to running VMXON, most notably cr4.VMXE must be @@ -5584,21 +5344,6 @@ static int handle_vmon(struct kvm_vcpu *vcpu) kvm_inject_gp(vcpu, 0); return 1; } - if (vmx->nested.vmxon) { - nested_vmx_failValid(vcpu, VMXERR_VMXON_IN_VMX_ROOT_OPERATION); - skip_emulated_instruction(vcpu); - return 1; - } - if (enable_shadow_vmcs) { - shadow_vmcs = alloc_vmcs(); - if (!shadow_vmcs) - return -ENOMEM; - /* mark vmcs as shadow */ - shadow_vmcs->revision_id |= (1u << 31); - /* init shadow vmcs */ - vmcs_clear(shadow_vmcs); - vmx->nested.current_shadow_vmcs = shadow_vmcs; - } INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool)); vmx->nested.vmcs02_num = 0; @@ -5639,25 +5384,6 @@ static int nested_vmx_check_permission(struct kvm_vcpu *vcpu) return 1; } -static inline void nested_release_vmcs12(struct vcpu_vmx *vmx) -{ - u32 exec_control; - if (enable_shadow_vmcs) { - if (vmx->nested.current_vmcs12 != NULL) { - /* copy to memory all shadowed fields in case - they were modified */ - copy_shadow_to_vmcs12(vmx); - vmx->nested.sync_shadow_vmcs = false; - exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL); - exec_control &= ~SECONDARY_EXEC_SHADOW_VMCS; - vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); - vmcs_write64(VMCS_LINK_POINTER, -1ull); - } - } - kunmap(vmx->nested.current_vmcs12_page); - nested_release_page(vmx->nested.current_vmcs12_page); -} - /* * Free whatever needs to be freed from vmx->nested when L1 goes down, or * just stops using VMX. @@ -5668,12 +5394,11 @@ static void free_nested(struct vcpu_vmx *vmx) return; vmx->nested.vmxon = false; if (vmx->nested.current_vmptr != -1ull) { - nested_release_vmcs12(vmx); + kunmap(vmx->nested.current_vmcs12_page); + nested_release_page(vmx->nested.current_vmcs12_page); vmx->nested.current_vmptr = -1ull; vmx->nested.current_vmcs12 = NULL; } - if (enable_shadow_vmcs) - free_vmcs(vmx->nested.current_shadow_vmcs); /* Unpin physical memory we referred to in current vmcs02 */ if (vmx->nested.apic_access_page) { nested_release_page(vmx->nested.apic_access_page); @@ -5782,10 +5507,6 @@ static void nested_vmx_failValid(struct kvm_vcpu *vcpu, X86_EFLAGS_SF | X86_EFLAGS_OF)) | X86_EFLAGS_ZF); get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error; - /* - * We don't need to force a shadow sync because - * VM_INSTRUCTION_ERROR is not shadowed - */ } /* Emulate the VMCLEAR instruction */ @@ -5818,7 +5539,8 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) } if (vmptr == vmx->nested.current_vmptr) { - nested_release_vmcs12(vmx); + kunmap(vmx->nested.current_vmcs12_page); + nested_release_page(vmx->nested.current_vmcs12_page); vmx->nested.current_vmptr = -1ull; vmx->nested.current_vmcs12 = NULL; } @@ -5917,111 +5639,6 @@ static inline bool vmcs12_read_any(struct kvm_vcpu *vcpu, } } - -static inline bool vmcs12_write_any(struct kvm_vcpu *vcpu, - unsigned long field, u64 field_value){ - short offset = vmcs_field_to_offset(field); - char *p = ((char *) get_vmcs12(vcpu)) + offset; - if (offset < 0) - return false; - - switch (vmcs_field_type(field)) { - case VMCS_FIELD_TYPE_U16: - *(u16 *)p = field_value; - return true; - case VMCS_FIELD_TYPE_U32: - *(u32 *)p = field_value; - return true; - case VMCS_FIELD_TYPE_U64: - *(u64 *)p = field_value; - return true; - case VMCS_FIELD_TYPE_NATURAL_WIDTH: - *(natural_width *)p = field_value; - return true; - default: - return false; /* can never happen. */ - } - -} - -static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx) -{ - int i; - unsigned long field; - u64 field_value; - struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs; - unsigned long *fields = (unsigned long *)shadow_read_write_fields; - int num_fields = max_shadow_read_write_fields; - - vmcs_load(shadow_vmcs); - - for (i = 0; i < num_fields; i++) { - field = fields[i]; - switch (vmcs_field_type(field)) { - case VMCS_FIELD_TYPE_U16: - field_value = vmcs_read16(field); - break; - case VMCS_FIELD_TYPE_U32: - field_value = vmcs_read32(field); - break; - case VMCS_FIELD_TYPE_U64: - field_value = vmcs_read64(field); - break; - case VMCS_FIELD_TYPE_NATURAL_WIDTH: - field_value = vmcs_readl(field); - break; - } - vmcs12_write_any(&vmx->vcpu, field, field_value); - } - - vmcs_clear(shadow_vmcs); - vmcs_load(vmx->loaded_vmcs->vmcs); -} - -static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx) -{ - unsigned long *fields[] = { - (unsigned long *)shadow_read_write_fields, - (unsigned long *)shadow_read_only_fields - }; - int num_lists = ARRAY_SIZE(fields); - int max_fields[] = { - max_shadow_read_write_fields, - max_shadow_read_only_fields - }; - int i, q; - unsigned long field; - u64 field_value = 0; - struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs; - - vmcs_load(shadow_vmcs); - - for (q = 0; q < num_lists; q++) { - for (i = 0; i < max_fields[q]; i++) { - field = fields[q][i]; - vmcs12_read_any(&vmx->vcpu, field, &field_value); - - switch (vmcs_field_type(field)) { - case VMCS_FIELD_TYPE_U16: - vmcs_write16(field, (u16)field_value); - break; - case VMCS_FIELD_TYPE_U32: - vmcs_write32(field, (u32)field_value); - break; - case VMCS_FIELD_TYPE_U64: - vmcs_write64(field, (u64)field_value); - break; - case VMCS_FIELD_TYPE_NATURAL_WIDTH: - vmcs_writel(field, (long)field_value); - break; - } - } - } - - vmcs_clear(shadow_vmcs); - vmcs_load(vmx->loaded_vmcs->vmcs); -} - /* * VMX instructions which assume a current vmcs12 (i.e., that VMPTRLD was * used before) all generate the same failure when it is missing. @@ -6086,6 +5703,8 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) gva_t gva; unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); + char *p; + short offset; /* The value to write might be 32 or 64 bits, depending on L1's long * mode, and eventually we need to write that into a field of several * possible lengths. The code below first zero-extends the value to 64 @@ -6122,7 +5741,28 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) return 1; } - if (!vmcs12_write_any(vcpu, field, field_value)) { + offset = vmcs_field_to_offset(field); + if (offset < 0) { + nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); + skip_emulated_instruction(vcpu); + return 1; + } + p = ((char *) get_vmcs12(vcpu)) + offset; + + switch (vmcs_field_type(field)) { + case VMCS_FIELD_TYPE_U16: + *(u16 *)p = field_value; + break; + case VMCS_FIELD_TYPE_U32: + *(u32 *)p = field_value; + break; + case VMCS_FIELD_TYPE_U64: + *(u64 *)p = field_value; + break; + case VMCS_FIELD_TYPE_NATURAL_WIDTH: + *(natural_width *)p = field_value; + break; + default: nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); skip_emulated_instruction(vcpu); return 1; @@ -6140,7 +5780,6 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) gva_t gva; gpa_t vmptr; struct x86_exception e; - u32 exec_control; if (!nested_vmx_check_permission(vcpu)) return 1; @@ -6179,20 +5818,14 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) skip_emulated_instruction(vcpu); return 1; } - if (vmx->nested.current_vmptr != -1ull) - nested_release_vmcs12(vmx); + if (vmx->nested.current_vmptr != -1ull) { + kunmap(vmx->nested.current_vmcs12_page); + nested_release_page(vmx->nested.current_vmcs12_page); + } vmx->nested.current_vmptr = vmptr; vmx->nested.current_vmcs12 = new_vmcs12; vmx->nested.current_vmcs12_page = page; - if (enable_shadow_vmcs) { - exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL); - exec_control |= SECONDARY_EXEC_SHADOW_VMCS; - vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); - vmcs_write64(VMCS_LINK_POINTER, - __pa(vmx->nested.current_shadow_vmcs)); - vmx->nested.sync_shadow_vmcs = true; - } } nested_vmx_succeed(vcpu); @@ -6275,52 +5908,6 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { static const int kvm_vmx_max_exit_handlers = ARRAY_SIZE(kvm_vmx_exit_handlers); -static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12) -{ - unsigned long exit_qualification; - gpa_t bitmap, last_bitmap; - unsigned int port; - int size; - u8 b; - - if (nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING)) - return 1; - - if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS)) - return 0; - - exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - - port = exit_qualification >> 16; - size = (exit_qualification & 7) + 1; - - last_bitmap = (gpa_t)-1; - b = -1; - - while (size > 0) { - if (port < 0x8000) - bitmap = vmcs12->io_bitmap_a; - else if (port < 0x10000) - bitmap = vmcs12->io_bitmap_b; - else - return 1; - bitmap += (port & 0x7fff) / 8; - - if (last_bitmap != bitmap) - if (kvm_read_guest(vcpu->kvm, bitmap, &b, 1)) - return 1; - if (b & (1 << (port & 7))) - return 1; - - port++; - size--; - last_bitmap = bitmap; - } - - return 0; -} - /* * Return 1 if we should exit from L2 to L1 to handle an MSR access access, * rather than handle it ourselves in L0. I.e., check whether L1 expressed @@ -6352,8 +5939,7 @@ static bool nested_vmx_exit_handled_msr(struct kvm_vcpu *vcpu, /* Then read the msr_index'th bit from this bitmap: */ if (msr_index < 1024*8) { unsigned char b; - if (kvm_read_guest(vcpu->kvm, bitmap + msr_index/8, &b, 1)) - return 1; + kvm_read_guest(vcpu->kvm, bitmap + msr_index/8, &b, 1); return 1 & (b >> (msr_index & 7)); } else return 1; /* let L1 handle the wrong parameter */ @@ -6447,10 +6033,10 @@ static bool nested_vmx_exit_handled_cr(struct kvm_vcpu *vcpu, */ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) { + u32 exit_reason = vmcs_read32(VM_EXIT_REASON); u32 intr_info = vmcs_read32(VM_EXIT_INTR_INFO); struct vcpu_vmx *vmx = to_vmx(vcpu); struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - u32 exit_reason = vmx->exit_reason; if (vmx->nested.nested_run_pending) return 0; @@ -6474,9 +6060,14 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) case EXIT_REASON_TRIPLE_FAULT: return 1; case EXIT_REASON_PENDING_INTERRUPT: - return nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_INTR_PENDING); case EXIT_REASON_NMI_WINDOW: - return nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_NMI_PENDING); + /* + * prepare_vmcs02() set the CPU_BASED_VIRTUAL_INTR_PENDING bit + * (aka Interrupt Window Exiting) only when L1 turned it on, + * so if we got a PENDING_INTERRUPT exit, this must be for L1. + * Same for NMI Window Exiting. + */ + return 1; case EXIT_REASON_TASK_SWITCH: return 1; case EXIT_REASON_CPUID: @@ -6506,7 +6097,8 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) case EXIT_REASON_DR_ACCESS: return nested_cpu_has(vmcs12, CPU_BASED_MOV_DR_EXITING); case EXIT_REASON_IO_INSTRUCTION: - return nested_vmx_exit_handled_io(vcpu, vmcs12); + /* TODO: support IO bitmaps */ + return 1; case EXIT_REASON_MSR_READ: case EXIT_REASON_MSR_WRITE: return nested_vmx_exit_handled_msr(vcpu, vmcs12, exit_reason); @@ -6530,9 +6122,6 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) case EXIT_REASON_EPT_VIOLATION: case EXIT_REASON_EPT_MISCONFIG: return 0; - case EXIT_REASON_PREEMPTION_TIMER: - return vmcs12->pin_based_vm_exec_control & - PIN_BASED_VMX_PREEMPTION_TIMER; case EXIT_REASON_WBINVD: return nested_cpu_has2(vmcs12, SECONDARY_EXEC_WBINVD_EXITING); case EXIT_REASON_XSETBV: @@ -6727,9 +6316,6 @@ static void vmx_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr) static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) { - if (!vmx_vm_has_apicv(vcpu->kvm)) - return; - vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]); vmcs_write64(EOI_EXIT_BITMAP1, eoi_exit_bitmap[1]); vmcs_write64(EOI_EXIT_BITMAP2, eoi_exit_bitmap[2]); @@ -6760,52 +6346,6 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx) } } -static void vmx_handle_external_intr(struct kvm_vcpu *vcpu) -{ - u32 exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - - /* - * If external interrupt exists, IF bit is set in rflags/eflags on the - * interrupt stack frame, and interrupt will be enabled on a return - * from interrupt handler. - */ - if ((exit_intr_info & (INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK)) - == (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR)) { - unsigned int vector; - unsigned long entry; - gate_desc *desc; - struct vcpu_vmx *vmx = to_vmx(vcpu); -#ifdef CONFIG_X86_64 - unsigned long tmp; -#endif - - vector = exit_intr_info & INTR_INFO_VECTOR_MASK; - desc = (gate_desc *)vmx->host_idt_base + vector; - entry = gate_offset(*desc); - asm volatile( -#ifdef CONFIG_X86_64 - "mov %%" _ASM_SP ", %[sp]\n\t" - "and $0xfffffffffffffff0, %%" _ASM_SP "\n\t" - "push $%c[ss]\n\t" - "push %[sp]\n\t" -#endif - "pushf\n\t" - "orl $0x200, (%%" _ASM_SP ")\n\t" - __ASM_SIZE(push) " $%c[cs]\n\t" - "call *%[entry]\n\t" - : -#ifdef CONFIG_X86_64 - [sp]"=&r"(tmp) -#endif - : - [entry]"r"(entry), - [ss]"i"(__KERNEL_DS), - [cs]"i"(__KERNEL_CS) - ); - } else - local_irq_enable(); -} - static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx) { u32 exit_intr_info; @@ -6848,7 +6388,7 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx) ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time)); } -static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu, +static void __vmx_complete_interrupts(struct vcpu_vmx *vmx, u32 idt_vectoring_info, int instr_len_field, int error_code_field) @@ -6859,43 +6399,46 @@ static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu, idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK; - vcpu->arch.nmi_injected = false; - kvm_clear_exception_queue(vcpu); - kvm_clear_interrupt_queue(vcpu); + vmx->vcpu.arch.nmi_injected = false; + kvm_clear_exception_queue(&vmx->vcpu); + kvm_clear_interrupt_queue(&vmx->vcpu); if (!idtv_info_valid) return; - kvm_make_request(KVM_REQ_EVENT, vcpu); + kvm_make_request(KVM_REQ_EVENT, &vmx->vcpu); vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK; type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK; switch (type) { case INTR_TYPE_NMI_INTR: - vcpu->arch.nmi_injected = true; + vmx->vcpu.arch.nmi_injected = true; /* * SDM 3: 27.7.1.2 (September 2008) * Clear bit "block by NMI" before VM entry if a NMI * delivery faulted. */ - vmx_set_nmi_mask(vcpu, false); + vmx_set_nmi_mask(&vmx->vcpu, false); break; case INTR_TYPE_SOFT_EXCEPTION: - vcpu->arch.event_exit_inst_len = vmcs_read32(instr_len_field); + vmx->vcpu.arch.event_exit_inst_len = + vmcs_read32(instr_len_field); /* fall through */ case INTR_TYPE_HARD_EXCEPTION: if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) { u32 err = vmcs_read32(error_code_field); - kvm_queue_exception_e(vcpu, vector, err); + kvm_queue_exception_e(&vmx->vcpu, vector, err); } else - kvm_queue_exception(vcpu, vector); + kvm_queue_exception(&vmx->vcpu, vector); break; case INTR_TYPE_SOFT_INTR: - vcpu->arch.event_exit_inst_len = vmcs_read32(instr_len_field); + vmx->vcpu.arch.event_exit_inst_len = + vmcs_read32(instr_len_field); /* fall through */ case INTR_TYPE_EXT_INTR: - kvm_queue_interrupt(vcpu, vector, type == INTR_TYPE_SOFT_INTR); + kvm_queue_interrupt(&vmx->vcpu, vector, + type == INTR_TYPE_SOFT_INTR); break; default: break; @@ -6904,14 +6447,18 @@ static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu, static void vmx_complete_interrupts(struct vcpu_vmx *vmx) { - __vmx_complete_interrupts(&vmx->vcpu, vmx->idt_vectoring_info, + if (is_guest_mode(&vmx->vcpu)) + return; + __vmx_complete_interrupts(vmx, vmx->idt_vectoring_info, VM_EXIT_INSTRUCTION_LEN, IDT_VECTORING_ERROR_CODE); } static void vmx_cancel_injection(struct kvm_vcpu *vcpu) { - __vmx_complete_interrupts(vcpu, + if (is_guest_mode(vcpu)) + return; + __vmx_complete_interrupts(to_vmx(vcpu), vmcs_read32(VM_ENTRY_INTR_INFO_FIELD), VM_ENTRY_INSTRUCTION_LEN, VM_ENTRY_EXCEPTION_ERROR_CODE); @@ -6942,6 +6489,21 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned long debugctlmsr; + if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending) { + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + if (vmcs12->idt_vectoring_info_field & + VECTORING_INFO_VALID_MASK) { + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + vmcs12->idt_vectoring_info_field); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmcs12->vm_exit_instruction_len); + if (vmcs12->idt_vectoring_info_field & + VECTORING_INFO_DELIVER_CODE_MASK) + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, + vmcs12->idt_vectoring_error_code); + } + } + /* Record the guest's net vcpu time for enforced NMI injections. */ if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked)) vmx->entry_time = ktime_get(); @@ -6951,11 +6513,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) if (vmx->emulation_required) return; - if (vmx->nested.sync_shadow_vmcs) { - copy_vmcs12_to_shadow(vmx); - vmx->nested.sync_shadow_vmcs = false; - } - if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty)) vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]); if (test_bit(VCPU_REGS_RIP, (unsigned long *)&vcpu->arch.regs_dirty)) @@ -7105,6 +6662,17 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); + if (is_guest_mode(vcpu)) { + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + vmcs12->idt_vectoring_info_field = vmx->idt_vectoring_info; + if (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) { + vmcs12->idt_vectoring_error_code = + vmcs_read32(IDT_VECTORING_ERROR_CODE); + vmcs12->vm_exit_instruction_len = + vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + } + } + vmx->loaded_vmcs->launched = 1; vmx->exit_reason = vmcs_read32(VM_EXIT_REASON); @@ -7166,11 +6734,10 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) put_cpu(); if (err) goto free_vmcs; - if (vm_need_virtualize_apic_accesses(kvm)) { + if (vm_need_virtualize_apic_accesses(kvm)) err = alloc_apic_access_page(kvm); if (err) goto free_vmcs; - } if (enable_ept) { if (!kvm->arch.ept_identity_map_addr) @@ -7364,8 +6931,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vmcs12->vm_entry_instruction_len); vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, vmcs12->guest_interruptibility_info); + vmcs_write32(GUEST_ACTIVITY_STATE, vmcs12->guest_activity_state); vmcs_write32(GUEST_SYSENTER_CS, vmcs12->guest_sysenter_cs); - kvm_set_dr(vcpu, 7, vmcs12->guest_dr7); + vmcs_writel(GUEST_DR7, vmcs12->guest_dr7); vmcs_writel(GUEST_RFLAGS, vmcs12->guest_rflags); vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS, vmcs12->guest_pending_dbg_exceptions); @@ -7378,10 +6946,6 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) (vmcs_config.pin_based_exec_ctrl | vmcs12->pin_based_vm_exec_control)); - if (vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER) - vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, - vmcs12->vmx_preemption_timer_value); - /* * Whether page-faults are trapped is determined by a combination of * 3 settings: PFEC_MASK, PFEC_MATCH and EXCEPTION_BITMAP.PF. @@ -7452,7 +7016,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) * Other fields are different per CPU, and will be set later when * vmx_vcpu_load() is called, and when vmx_save_host_state() is called. */ - vmx_set_constant_host_state(vmx); + vmx_set_constant_host_state(); /* * HOST_RSP is normally set correctly in vmx_vcpu_run() just before @@ -7518,7 +7082,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER) vcpu->arch.efer = vmcs12->guest_ia32_efer; - else if (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) + if (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) vcpu->arch.efer |= (EFER_LMA | EFER_LME); else vcpu->arch.efer &= ~(EFER_LMA | EFER_LME); @@ -7557,7 +7121,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) struct vcpu_vmx *vmx = to_vmx(vcpu); int cpu; struct loaded_vmcs *vmcs02; - bool ia32e; if (!nested_vmx_check_permission(vcpu) || !nested_vmx_check_vmcs12(vcpu)) @@ -7566,9 +7129,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) skip_emulated_instruction(vcpu); vmcs12 = get_vmcs12(vcpu); - if (enable_shadow_vmcs) - copy_shadow_to_vmcs12(vmx); - /* * The nested entry process starts with enforcing various prerequisites * on vmcs12 as required by the Intel SDM, and act appropriately when @@ -7586,11 +7146,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) return 1; } - if (vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE) { - nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); - return 1; - } - if ((vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_MSR_BITMAPS) && !IS_ALIGNED(vmcs12->msr_bitmap, PAGE_SIZE)) { /*TODO: Also verify bits beyond physical address width are 0*/ @@ -7648,45 +7203,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) return 1; } - /* - * If the load IA32_EFER VM-entry control is 1, the following checks - * are performed on the field for the IA32_EFER MSR: - * - Bits reserved in the IA32_EFER MSR must be 0. - * - Bit 10 (corresponding to IA32_EFER.LMA) must equal the value of - * the IA-32e mode guest VM-exit control. It must also be identical - * to bit 8 (LME) if bit 31 in the CR0 field (corresponding to - * CR0.PG) is 1. - */ - if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER) { - ia32e = (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) != 0; - if (!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer) || - ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA) || - ((vmcs12->guest_cr0 & X86_CR0_PG) && - ia32e != !!(vmcs12->guest_ia32_efer & EFER_LME))) { - nested_vmx_entry_failure(vcpu, vmcs12, - EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT); - return 1; - } - } - - /* - * If the load IA32_EFER VM-exit control is 1, bits reserved in the - * IA32_EFER MSR must be 0 in the field for that register. In addition, - * the values of the LMA and LME bits in the field must each be that of - * the host address-space size VM-exit control. - */ - if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) { - ia32e = (vmcs12->vm_exit_controls & - VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0; - if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) || - ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) || - ia32e != !!(vmcs12->host_ia32_efer & EFER_LME)) { - nested_vmx_entry_failure(vcpu, vmcs12, - EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT); - return 1; - } - } - /* * We're finally done with prerequisite checking, and can start with * the nested entry. @@ -7707,8 +7223,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) vcpu->cpu = cpu; put_cpu(); - vmx_segment_cache_clear(vmx); - vmcs12->launch_state = 1; prepare_vmcs02(vcpu, vmcs12); @@ -7759,48 +7273,6 @@ vmcs12_guest_cr4(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vcpu->arch.cr4_guest_owned_bits)); } -static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12) -{ - u32 idt_vectoring; - unsigned int nr; - - if (vcpu->arch.exception.pending) { - nr = vcpu->arch.exception.nr; - idt_vectoring = nr | VECTORING_INFO_VALID_MASK; - - if (kvm_exception_is_soft(nr)) { - vmcs12->vm_exit_instruction_len = - vcpu->arch.event_exit_inst_len; - idt_vectoring |= INTR_TYPE_SOFT_EXCEPTION; - } else - idt_vectoring |= INTR_TYPE_HARD_EXCEPTION; - - if (vcpu->arch.exception.has_error_code) { - idt_vectoring |= VECTORING_INFO_DELIVER_CODE_MASK; - vmcs12->idt_vectoring_error_code = - vcpu->arch.exception.error_code; - } - - vmcs12->idt_vectoring_info_field = idt_vectoring; - } else if (vcpu->arch.nmi_pending) { - vmcs12->idt_vectoring_info_field = - INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR; - } else if (vcpu->arch.interrupt.pending) { - nr = vcpu->arch.interrupt.nr; - idt_vectoring = nr | VECTORING_INFO_VALID_MASK; - - if (vcpu->arch.interrupt.soft) { - idt_vectoring |= INTR_TYPE_SOFT_INTR; - vmcs12->vm_entry_instruction_len = - vcpu->arch.event_exit_inst_len; - } else - idt_vectoring |= INTR_TYPE_EXT_INTR; - - vmcs12->idt_vectoring_info_field = idt_vectoring; - } -} - /* * prepare_vmcs12 is part of what we need to do when the nested L2 guest exits * and we want to prepare to run its L1 parent. L1 keeps a vmcs for L2 (vmcs12), @@ -7812,7 +7284,7 @@ static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu, * exit-information fields only. Other fields are modified by L1 with VMWRITE, * which already writes to vmcs12 directly. */ -static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) +void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { /* update guest state fields: */ vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12); @@ -7860,19 +7332,16 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vmcs12->guest_gdtr_base = vmcs_readl(GUEST_GDTR_BASE); vmcs12->guest_idtr_base = vmcs_readl(GUEST_IDTR_BASE); + vmcs12->guest_activity_state = vmcs_read32(GUEST_ACTIVITY_STATE); vmcs12->guest_interruptibility_info = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); vmcs12->guest_pending_dbg_exceptions = vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS); - vmcs12->vm_entry_controls = - (vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) | - (vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_IA32E_MODE); - /* TODO: These cannot have changed unless we have MSR bitmaps and * the relevant bit asks not to trap the change */ vmcs12->guest_ia32_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL); - if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_PAT) + if (vmcs12->vm_entry_controls & VM_EXIT_SAVE_IA32_PAT) vmcs12->guest_ia32_pat = vmcs_read64(GUEST_IA32_PAT); vmcs12->guest_sysenter_cs = vmcs_read32(GUEST_SYSENTER_CS); vmcs12->guest_sysenter_esp = vmcs_readl(GUEST_SYSENTER_ESP); @@ -7880,38 +7349,21 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) /* update exit information fields: */ - vmcs12->vm_exit_reason = to_vmx(vcpu)->exit_reason; + vmcs12->vm_exit_reason = vmcs_read32(VM_EXIT_REASON); vmcs12->exit_qualification = vmcs_readl(EXIT_QUALIFICATION); vmcs12->vm_exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - if ((vmcs12->vm_exit_intr_info & - (INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK)) == - (INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK)) - vmcs12->vm_exit_intr_error_code = - vmcs_read32(VM_EXIT_INTR_ERROR_CODE); - vmcs12->idt_vectoring_info_field = 0; + vmcs12->vm_exit_intr_error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); + vmcs12->idt_vectoring_info_field = + vmcs_read32(IDT_VECTORING_INFO_FIELD); + vmcs12->idt_vectoring_error_code = + vmcs_read32(IDT_VECTORING_ERROR_CODE); vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); - if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) { - /* vm_entry_intr_info_field is cleared on exit. Emulate this - * instead of reading the real value. */ + /* clear vm-entry fields which are to be cleared on exit */ + if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) vmcs12->vm_entry_intr_info_field &= ~INTR_INFO_VALID_MASK; - - /* - * Transfer the event that L0 or L1 may wanted to inject into - * L2 to IDT_VECTORING_INFO_FIELD. - */ - vmcs12_save_pending_event(vcpu, vmcs12); - } - - /* - * Drop what we picked up for L2 via vmx_complete_interrupts. It is - * preserved above and would only end up incorrectly in L1. - */ - vcpu->arch.nmi_injected = false; - kvm_clear_exception_queue(vcpu); - kvm_clear_interrupt_queue(vcpu); } /* @@ -7923,12 +7375,11 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) * Failures During or After Loading Guest State"). * This function should be called when the active VMCS is L1's (vmcs01). */ -static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12) +void load_vmcs12_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) vcpu->arch.efer = vmcs12->host_ia32_efer; - else if (vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE) + if (vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE) vcpu->arch.efer |= (EFER_LMA | EFER_LME); else vcpu->arch.efer &= ~(EFER_LMA | EFER_LME); @@ -7936,7 +7387,6 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->host_rsp); kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->host_rip); - vmx_set_rflags(vcpu, X86_EFLAGS_BIT1); /* * Note that calling vmx_set_cr0 is important, even if cr0 hasn't * actually changed, because it depends on the current state of @@ -7995,9 +7445,6 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, vmcs12->host_ia32_perf_global_ctrl); - - kvm_set_dr(vcpu, 7, 0x400); - vmcs_write64(GUEST_IA32_DEBUGCTL, 0); } /* @@ -8011,9 +7458,6 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu) int cpu; struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - /* trying to cancel vmlaunch/vmresume is a bug */ - WARN_ON_ONCE(vmx->nested.nested_run_pending); - leave_guest_mode(vcpu); prepare_vmcs12(vcpu, vmcs12); @@ -8024,8 +7468,6 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu) vcpu->cpu = cpu; put_cpu(); - vmx_segment_cache_clear(vmx); - /* if no vmcs02 cache requested, remove the one we used */ if (VMCS02_POOL_SIZE == 0) nested_free_vmcs02(vmx, vmx->nested.current_vmptr); @@ -8054,8 +7496,6 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu) nested_vmx_failValid(vcpu, vmcs_read32(VM_INSTRUCTION_ERROR)); } else nested_vmx_succeed(vcpu); - if (enable_shadow_vmcs) - vmx->nested.sync_shadow_vmcs = true; } /* @@ -8073,8 +7513,6 @@ static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, vmcs12->vm_exit_reason = reason | VMX_EXIT_REASONS_FAILED_VMENTRY; vmcs12->exit_qualification = qualification; nested_vmx_succeed(vcpu); - if (enable_shadow_vmcs) - to_vmx(vcpu)->nested.sync_shadow_vmcs = true; } static int vmx_check_intercept(struct kvm_vcpu *vcpu, @@ -8152,8 +7590,6 @@ static struct kvm_x86_ops vmx_x86_ops = { .load_eoi_exitmap = vmx_load_eoi_exitmap, .hwapic_irr_update = vmx_hwapic_irr_update, .hwapic_isr_update = vmx_hwapic_isr_update, - .sync_pir_to_irr = vmx_sync_pir_to_irr, - .deliver_posted_interrupt = vmx_deliver_posted_interrupt, .set_tss_addr = vmx_set_tss_addr, .get_tdp_level = get_ept_level, @@ -8182,7 +7618,6 @@ static struct kvm_x86_ops vmx_x86_ops = { .set_tdp_cr3 = vmx_set_cr3, .check_intercept = vmx_check_intercept, - .handle_external_intr = vmx_handle_external_intr, }; static int __init vmx_init(void) @@ -8221,24 +7656,6 @@ static int __init vmx_init(void) (unsigned long *)__get_free_page(GFP_KERNEL); if (!vmx_msr_bitmap_longmode_x2apic) goto out4; - vmx_vmread_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL); - if (!vmx_vmread_bitmap) - goto out5; - - vmx_vmwrite_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL); - if (!vmx_vmwrite_bitmap) - goto out6; - - memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE); - memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE); - /* shadowed read/write fields */ - for (i = 0; i < max_shadow_read_write_fields; i++) { - clear_bit(shadow_read_write_fields[i], vmx_vmwrite_bitmap); - clear_bit(shadow_read_write_fields[i], vmx_vmread_bitmap); - } - /* shadowed read only fields */ - for (i = 0; i < max_shadow_read_only_fields; i++) - clear_bit(shadow_read_only_fields[i], vmx_vmread_bitmap); /* * Allow direct access to the PC debug port (it is often used for I/O @@ -8257,7 +7674,7 @@ static int __init vmx_init(void) r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), __alignof__(struct vcpu_vmx), THIS_MODULE); if (r) - goto out7; + goto out3; #ifdef CONFIG_KEXEC rcu_assign_pointer(crash_vmclear_loaded_vmcss, @@ -8275,7 +7692,7 @@ static int __init vmx_init(void) memcpy(vmx_msr_bitmap_longmode_x2apic, vmx_msr_bitmap_longmode, PAGE_SIZE); - if (enable_apicv) { + if (enable_apicv_reg_vid) { for (msr = 0x800; msr <= 0x8ff; msr++) vmx_disable_intercept_msr_read_x2apic(msr); @@ -8305,12 +7722,6 @@ static int __init vmx_init(void) return 0; -out7: - free_page((unsigned long)vmx_vmwrite_bitmap); -out6: - free_page((unsigned long)vmx_vmread_bitmap); -out5: - free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic); out4: free_page((unsigned long)vmx_msr_bitmap_longmode); out3: @@ -8332,8 +7743,6 @@ static void __exit vmx_exit(void) free_page((unsigned long)vmx_msr_bitmap_longmode); free_page((unsigned long)vmx_io_bitmap_b); free_page((unsigned long)vmx_io_bitmap_a); - free_page((unsigned long)vmx_vmwrite_bitmap); - free_page((unsigned long)vmx_vmread_bitmap); #ifdef CONFIG_KEXEC rcu_assign_pointer(crash_vmclear_loaded_vmcss, NULL); diff --git a/trunk/arch/x86/kvm/x86.c b/trunk/arch/x86/kvm/x86.c index 05a8b1a2300d..e1721324c271 100644 --- a/trunk/arch/x86/kvm/x86.c +++ b/trunk/arch/x86/kvm/x86.c @@ -162,6 +162,8 @@ u64 __read_mostly host_xcr0; static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt); +static int kvm_vcpu_reset(struct kvm_vcpu *vcpu); + static inline void kvm_async_pf_hash_reset(struct kvm_vcpu *vcpu) { int i; @@ -261,13 +263,6 @@ void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) } EXPORT_SYMBOL_GPL(kvm_set_apic_base); -asmlinkage void kvm_spurious_fault(void) -{ - /* Fault while not rebooting. We want the trace. */ - BUG(); -} -EXPORT_SYMBOL_GPL(kvm_spurious_fault); - #define EXCPT_BENIGN 0 #define EXCPT_CONTRIBUTORY 1 #define EXCPT_PF 2 @@ -845,17 +840,23 @@ static const u32 emulated_msrs[] = { MSR_IA32_MCG_CTL, }; -bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) +static int set_efer(struct kvm_vcpu *vcpu, u64 efer) { + u64 old_efer = vcpu->arch.efer; + if (efer & efer_reserved_bits) - return false; + return 1; + + if (is_paging(vcpu) + && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME)) + return 1; if (efer & EFER_FFXSR) { struct kvm_cpuid_entry2 *feat; feat = kvm_find_cpuid_entry(vcpu, 0x80000001, 0); if (!feat || !(feat->edx & bit(X86_FEATURE_FXSR_OPT))) - return false; + return 1; } if (efer & EFER_SVME) { @@ -863,24 +864,9 @@ bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) feat = kvm_find_cpuid_entry(vcpu, 0x80000001, 0); if (!feat || !(feat->ecx & bit(X86_FEATURE_SVM))) - return false; + return 1; } - return true; -} -EXPORT_SYMBOL_GPL(kvm_valid_efer); - -static int set_efer(struct kvm_vcpu *vcpu, u64 efer) -{ - u64 old_efer = vcpu->arch.efer; - - if (!kvm_valid_efer(vcpu, efer)) - return 1; - - if (is_paging(vcpu) - && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME)) - return 1; - efer &= ~EFER_LMA; efer |= vcpu->arch.efer & EFER_LMA; @@ -1093,10 +1079,6 @@ static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz) u32 thresh_lo, thresh_hi; int use_scaling = 0; - /* tsc_khz can be zero if TSC calibration fails */ - if (this_tsc_khz == 0) - return; - /* Compute a scale to convert nanoseconds in TSC cycles */ kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000, &vcpu->arch.virtual_tsc_shift, @@ -1174,23 +1156,20 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr) ns = get_kernel_ns(); elapsed = ns - kvm->arch.last_tsc_nsec; - if (vcpu->arch.virtual_tsc_khz) { - /* n.b - signed multiplication and division required */ - usdiff = data - kvm->arch.last_tsc_write; + /* n.b - signed multiplication and division required */ + usdiff = data - kvm->arch.last_tsc_write; #ifdef CONFIG_X86_64 - usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz; + usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz; #else - /* do_div() only does unsigned */ - asm("idivl %2; xor %%edx, %%edx" - : "=A"(usdiff) - : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz)); + /* do_div() only does unsigned */ + asm("idivl %2; xor %%edx, %%edx" + : "=A"(usdiff) + : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz)); #endif - do_div(elapsed, 1000); - usdiff -= elapsed; - if (usdiff < 0) - usdiff = -usdiff; - } else - usdiff = USEC_PER_SEC; /* disable TSC match window below */ + do_div(elapsed, 1000); + usdiff -= elapsed; + if (usdiff < 0) + usdiff = -usdiff; /* * Special case: TSC write with a small delta (1 second) of virtual @@ -2055,7 +2034,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_P6_EVNTSEL0: case MSR_P6_EVNTSEL1: if (kvm_pmu_msr(vcpu, msr)) - return kvm_pmu_set_msr(vcpu, msr_info); + return kvm_pmu_set_msr(vcpu, msr, data); if (pr || data != 0) vcpu_unimpl(vcpu, "disabled perfctr wrmsr: " @@ -2101,7 +2080,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr)) return xen_hvm_config(vcpu, data); if (kvm_pmu_msr(vcpu, msr)) - return kvm_pmu_set_msr(vcpu, msr_info); + return kvm_pmu_set_msr(vcpu, msr, data); if (!ignore_msrs) { vcpu_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n", msr, data); @@ -2500,6 +2479,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_USER_NMI: case KVM_CAP_REINJECT_CONTROL: case KVM_CAP_IRQ_INJECT_STATUS: + case KVM_CAP_ASSIGN_DEV_IRQ: case KVM_CAP_IRQFD: case KVM_CAP_IOEVENTFD: case KVM_CAP_PIT2: @@ -2517,12 +2497,10 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_XSAVE: case KVM_CAP_ASYNC_PF: case KVM_CAP_GET_TSC_KHZ: + case KVM_CAP_PCI_2_3: case KVM_CAP_KVMCLOCK_CTRL: case KVM_CAP_READONLY_MEM: -#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT - case KVM_CAP_ASSIGN_DEV_IRQ: - case KVM_CAP_PCI_2_3: -#endif + case KVM_CAP_IRQFD_RESAMPLE: r = 1; break; case KVM_CAP_COALESCED_MMIO: @@ -2543,11 +2521,9 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_PV_MMU: /* obsolete */ r = 0; break; -#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT case KVM_CAP_IOMMU: r = iommu_present(&pci_bus_type); break; -#endif case KVM_CAP_MCE: r = KVM_MAX_MCE_BANKS; break; @@ -2703,7 +2679,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) { - kvm_x86_ops->sync_pir_to_irr(vcpu); memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s); return 0; @@ -2721,7 +2696,7 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { - if (irq->irq >= KVM_NR_INTERRUPTS) + if (irq->irq < 0 || irq->irq >= KVM_NR_INTERRUPTS) return -EINVAL; if (irqchip_in_kernel(vcpu->kvm)) return -ENXIO; @@ -2844,9 +2819,10 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu); events->nmi.pad = 0; - events->sipi_vector = 0; /* never valid when reporting to user space */ + events->sipi_vector = vcpu->arch.sipi_vector; events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING + | KVM_VCPUEVENT_VALID_SIPI_VECTOR | KVM_VCPUEVENT_VALID_SHADOW); memset(&events->reserved, 0, sizeof(events->reserved)); } @@ -2877,9 +2853,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, vcpu->arch.nmi_pending = events->nmi.pending; kvm_x86_ops->set_nmi_mask(vcpu, events->nmi.masked); - if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR && - kvm_vcpu_has_lapic(vcpu)) - vcpu->arch.apic->sipi_vector = events->sipi_vector; + if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR) + vcpu->arch.sipi_vector = events->sipi_vector; kvm_make_request(KVM_REQ_EVENT, vcpu); @@ -3503,15 +3478,13 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) return r; } -int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, - bool line_status) +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event) { if (!irqchip_in_kernel(kvm)) return -ENXIO; irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, - irq_event->irq, irq_event->level, - line_status); + irq_event->irq, irq_event->level); return 0; } @@ -4779,15 +4752,11 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu) } static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2, - bool write_fault_to_shadow_pgtable, - int emulation_type) + bool write_fault_to_shadow_pgtable) { gpa_t gpa = cr2; pfn_t pfn; - if (emulation_type & EMULTYPE_NO_REEXECUTE) - return false; - if (!vcpu->arch.mmu.direct_map) { /* * Write permission should be allowed since only @@ -4930,8 +4899,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, if (r != EMULATION_OK) { if (emulation_type & EMULTYPE_TRAP_UD) return EMULATE_FAIL; - if (reexecute_instruction(vcpu, cr2, write_fault_to_spt, - emulation_type)) + if (reexecute_instruction(vcpu, cr2, + write_fault_to_spt)) return EMULATE_DONE; if (emulation_type & EMULTYPE_SKIP) return EMULATE_FAIL; @@ -4961,8 +4930,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, return EMULATE_DONE; if (r == EMULATION_FAILED) { - if (reexecute_instruction(vcpu, cr2, write_fault_to_spt, - emulation_type)) + if (reexecute_instruction(vcpu, cr2, write_fault_to_spt)) return EMULATE_DONE; return handle_emulation_failure(vcpu); @@ -5673,20 +5641,14 @@ static void kvm_gen_update_masterclock(struct kvm *kvm) #endif } -static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) +static void update_eoi_exitmap(struct kvm_vcpu *vcpu) { u64 eoi_exit_bitmap[4]; - u32 tmr[8]; - - if (!kvm_apic_hw_enabled(vcpu->arch.apic)) - return; memset(eoi_exit_bitmap, 0, 32); - memset(tmr, 0, 32); - kvm_ioapic_scan_entry(vcpu, eoi_exit_bitmap, tmr); + kvm_ioapic_calculate_eoi_exitmap(vcpu, eoi_exit_bitmap); kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap); - kvm_apic_update_tmr(vcpu, tmr); } static int vcpu_enter_guest(struct kvm_vcpu *vcpu) @@ -5694,7 +5656,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) int r; bool req_int_win = !irqchip_in_kernel(vcpu->kvm) && vcpu->run->request_interrupt_window; - bool req_immediate_exit = false; + bool req_immediate_exit = 0; if (vcpu->requests) { if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) @@ -5736,30 +5698,24 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) record_steal_time(vcpu); if (kvm_check_request(KVM_REQ_NMI, vcpu)) process_nmi(vcpu); + req_immediate_exit = + kvm_check_request(KVM_REQ_IMMEDIATE_EXIT, vcpu); if (kvm_check_request(KVM_REQ_PMU, vcpu)) kvm_handle_pmu_event(vcpu); if (kvm_check_request(KVM_REQ_PMI, vcpu)) kvm_deliver_pmi(vcpu); - if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu)) - vcpu_scan_ioapic(vcpu); + if (kvm_check_request(KVM_REQ_EOIBITMAP, vcpu)) + update_eoi_exitmap(vcpu); } if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) { - kvm_apic_accept_events(vcpu); - if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) { - r = 1; - goto out; - } - inject_pending_event(vcpu); /* enable NMI/IRQ window open exits if needed */ if (vcpu->arch.nmi_pending) - req_immediate_exit = - kvm_x86_ops->enable_nmi_window(vcpu) != 0; + kvm_x86_ops->enable_nmi_window(vcpu); else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win) - req_immediate_exit = - kvm_x86_ops->enable_irq_window(vcpu) != 0; + kvm_x86_ops->enable_irq_window(vcpu); if (kvm_lapic_enabled(vcpu)) { /* @@ -5838,9 +5794,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) vcpu->mode = OUTSIDE_GUEST_MODE; smp_wmb(); - - /* Interrupt is enabled by handle_external_intr() */ - kvm_x86_ops->handle_external_intr(vcpu); + local_irq_enable(); ++vcpu->stat.exits; @@ -5889,6 +5843,16 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) int r; struct kvm *kvm = vcpu->kvm; + if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED)) { + pr_debug("vcpu %d received sipi with vector # %x\n", + vcpu->vcpu_id, vcpu->arch.sipi_vector); + kvm_lapic_reset(vcpu); + r = kvm_vcpu_reset(vcpu); + if (r) + return r; + vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; + } + vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); r = vapic_enter(vcpu); if (r) { @@ -5905,8 +5869,8 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx); kvm_vcpu_block(vcpu); vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); - if (kvm_check_request(KVM_REQ_UNHALT, vcpu)) { - kvm_apic_accept_events(vcpu); + if (kvm_check_request(KVM_REQ_UNHALT, vcpu)) + { switch(vcpu->arch.mp_state) { case KVM_MP_STATE_HALTED: vcpu->arch.mp_state = @@ -5914,8 +5878,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) case KVM_MP_STATE_RUNNABLE: vcpu->arch.apf.halted = false; break; - case KVM_MP_STATE_INIT_RECEIVED: - break; + case KVM_MP_STATE_SIPI_RECEIVED: default: r = -EINTR; break; @@ -6050,7 +6013,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) { kvm_vcpu_block(vcpu); - kvm_apic_accept_events(vcpu); clear_bit(KVM_REQ_UNHALT, &vcpu->requests); r = -EAGAIN; goto out; @@ -6207,7 +6169,6 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { - kvm_apic_accept_events(vcpu); mp_state->mp_state = vcpu->arch.mp_state; return 0; } @@ -6215,15 +6176,7 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { - if (!kvm_vcpu_has_lapic(vcpu) && - mp_state->mp_state != KVM_MP_STATE_RUNNABLE) - return -EINVAL; - - if (mp_state->mp_state == KVM_MP_STATE_SIPI_RECEIVED) { - vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED; - set_bit(KVM_APIC_SIPI, &vcpu->arch.apic->pending_events); - } else - vcpu->arch.mp_state = mp_state->mp_state; + vcpu->arch.mp_state = mp_state->mp_state; kvm_make_request(KVM_REQ_EVENT, vcpu); return 0; } @@ -6522,8 +6475,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) r = vcpu_load(vcpu); if (r) return r; - kvm_vcpu_reset(vcpu); - r = kvm_mmu_setup(vcpu); + r = kvm_vcpu_reset(vcpu); + if (r == 0) + r = kvm_mmu_setup(vcpu); vcpu_put(vcpu); return r; @@ -6560,7 +6514,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) kvm_x86_ops->vcpu_free(vcpu); } -void kvm_vcpu_reset(struct kvm_vcpu *vcpu) +static int kvm_vcpu_reset(struct kvm_vcpu *vcpu) { atomic_set(&vcpu->arch.nmi_queued, 0); vcpu->arch.nmi_pending = 0; @@ -6587,18 +6541,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu) vcpu->arch.regs_avail = ~0; vcpu->arch.regs_dirty = ~0; - kvm_x86_ops->vcpu_reset(vcpu); -} - -void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, unsigned int vector) -{ - struct kvm_segment cs; - - kvm_get_segment(vcpu, &cs, VCPU_SREG_CS); - cs.selector = vector << 8; - cs.base = vector << 12; - kvm_set_segment(vcpu, &cs, VCPU_SREG_CS); - kvm_rip_write(vcpu, 0); + return kvm_x86_ops->vcpu_reset(vcpu); } int kvm_arch_hardware_enable(void *garbage) @@ -6763,10 +6706,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) } vcpu->arch.mcg_cap = KVM_MAX_MCE_BANKS; - if (!zalloc_cpumask_var(&vcpu->arch.wbinvd_dirty_mask, GFP_KERNEL)) { - r = -ENOMEM; + if (!zalloc_cpumask_var(&vcpu->arch.wbinvd_dirty_mask, GFP_KERNEL)) goto fail_free_mce_banks; - } r = fx_init(vcpu); if (r) @@ -6870,23 +6811,6 @@ void kvm_arch_sync_events(struct kvm *kvm) void kvm_arch_destroy_vm(struct kvm *kvm) { - if (current->mm == kvm->mm) { - /* - * Free memory regions allocated on behalf of userspace, - * unless the the memory map has changed due to process exit - * or fd copying. - */ - struct kvm_userspace_memory_region mem; - memset(&mem, 0, sizeof(mem)); - mem.slot = APIC_ACCESS_PAGE_PRIVATE_MEMSLOT; - kvm_set_memory_region(kvm, &mem); - - mem.slot = IDENTITY_PAGETABLE_PRIVATE_MEMSLOT; - kvm_set_memory_region(kvm, &mem); - - mem.slot = TSS_PRIVATE_MEMSLOT; - kvm_set_memory_region(kvm, &mem); - } kvm_iommu_unmap_guest(kvm); kfree(kvm->arch.vpic); kfree(kvm->arch.vioapic); @@ -6979,21 +6903,24 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *memslot, + struct kvm_memory_slot old, struct kvm_userspace_memory_region *mem, - enum kvm_mr_change change) + bool user_alloc) { + int npages = memslot->npages; + /* * Only private memory slots need to be mapped here since * KVM_SET_MEMORY_REGION ioctl is no longer supported. */ - if ((memslot->id >= KVM_USER_MEM_SLOTS) && (change == KVM_MR_CREATE)) { + if ((memslot->id >= KVM_USER_MEM_SLOTS) && npages && !old.npages) { unsigned long userspace_addr; /* * MAP_SHARED to prevent internal slot pages from being moved * by fork()/COW. */ - userspace_addr = vm_mmap(NULL, 0, memslot->npages * PAGE_SIZE, + userspace_addr = vm_mmap(NULL, 0, npages * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0); @@ -7008,17 +6935,17 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old, - enum kvm_mr_change change) + struct kvm_memory_slot old, + bool user_alloc) { - int nr_mmu_pages = 0; + int nr_mmu_pages = 0, npages = mem->memory_size >> PAGE_SHIFT; - if ((mem->slot >= KVM_USER_MEM_SLOTS) && (change == KVM_MR_DELETE)) { + if ((mem->slot >= KVM_USER_MEM_SLOTS) && old.npages && !npages) { int ret; - ret = vm_munmap(old->userspace_addr, - old->npages * PAGE_SIZE); + ret = vm_munmap(old.userspace_addr, + old.npages * PAGE_SIZE); if (ret < 0) printk(KERN_WARNING "kvm_vm_ioctl_set_memory_region: " @@ -7035,14 +6962,14 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, * Existing largepage mappings are destroyed here and new ones will * not be created until the end of the logging. */ - if ((change != KVM_MR_DELETE) && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES)) + if (npages && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES)) kvm_mmu_slot_remove_write_access(kvm, mem->slot); /* * If memory slot is created, or moved, we need to clear all * mmio sptes. */ - if ((change == KVM_MR_CREATE) || (change == KVM_MR_MOVE)) { - kvm_mmu_zap_mmio_sptes(kvm); + if (npages && old.base_gfn != mem->guest_phys_addr >> PAGE_SHIFT) { + kvm_mmu_zap_all(kvm); kvm_reload_remote_mmus(kvm); } } @@ -7064,7 +6991,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE && !vcpu->arch.apf.halted) || !list_empty_careful(&vcpu->async_pf.done) - || kvm_apic_has_events(vcpu) + || vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED || atomic_read(&vcpu->arch.nmi_queued) || (kvm_arch_interrupt_allowed(vcpu) && kvm_cpu_has_interrupt(vcpu)); diff --git a/trunk/crypto/asymmetric_keys/x509_cert_parser.c b/trunk/crypto/asymmetric_keys/x509_cert_parser.c index facbf26bc6bb..7fabc4c01993 100644 --- a/trunk/crypto/asymmetric_keys/x509_cert_parser.c +++ b/trunk/crypto/asymmetric_keys/x509_cert_parser.c @@ -373,9 +373,6 @@ int rsa_extract_mpi(void *context, size_t hdrlen, return 0; } -/* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */ -#define SEQ_TAG_KEYID (ASN1_CONT << 6) - /* * Process certificate extensions that are used to qualify the certificate. */ @@ -410,57 +407,21 @@ int x509_process_extension(void *context, size_t hdrlen, } if (ctx->last_oid == OID_authorityKeyIdentifier) { - size_t key_len; - /* Get hold of the CA key fingerprint */ if (vlen < 5) return -EBADMSG; - - /* Authority Key Identifier must be a Constructed SEQUENCE */ - if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5))) + if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5)) || + v[1] != vlen - 2 || + v[2] != (ASN1_CONT << 6) || + v[3] != vlen - 4) return -EBADMSG; + v += 4; + vlen -= 4; - /* Authority Key Identifier is not indefinite length */ - if (unlikely(vlen == ASN1_INDEFINITE_LENGTH)) - return -EBADMSG; - - if (vlen < ASN1_INDEFINITE_LENGTH) { - /* Short Form length */ - if (v[1] != vlen - 2 || - v[2] != SEQ_TAG_KEYID || - v[3] > vlen - 4) - return -EBADMSG; - - key_len = v[3]; - v += 4; - } else { - /* Long Form length */ - size_t seq_len = 0; - size_t sub = v[1] - ASN1_INDEFINITE_LENGTH; - - if (sub > 2) - return -EBADMSG; - - /* calculate the length from subsequent octets */ - v += 2; - for (i = 0; i < sub; i++) { - seq_len <<= 8; - seq_len |= v[i]; - } - - if (seq_len != vlen - 2 - sub || - v[sub] != SEQ_TAG_KEYID || - v[sub + 1] > vlen - 4 - sub) - return -EBADMSG; - - key_len = v[sub + 1]; - v += (sub + 2); - } - - f = kmalloc(key_len * 2 + 1, GFP_KERNEL); + f = kmalloc(vlen * 2 + 1, GFP_KERNEL); if (!f) return -ENOMEM; - for (i = 0; i < key_len; i++) + for (i = 0; i < vlen; i++) sprintf(f + i * 2, "%02x", v[i]); pr_debug("authority %s\n", f); ctx->cert->authority = f; diff --git a/trunk/drivers/char/ds1620.c b/trunk/drivers/char/ds1620.c index 0fae5296e311..544b4ce617f8 100644 --- a/trunk/drivers/char/ds1620.c +++ b/trunk/drivers/char/ds1620.c @@ -355,7 +355,7 @@ static const struct file_operations ds1620_proc_therm_fops = { .open = ds1620_proc_therm_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif diff --git a/trunk/drivers/char/efirtc.c b/trunk/drivers/char/efirtc.c index e39e7402e623..ea54a6e3f5ad 100644 --- a/trunk/drivers/char/efirtc.c +++ b/trunk/drivers/char/efirtc.c @@ -369,7 +369,7 @@ static const struct file_operations efi_rtc_proc_fops = { .open = efi_rtc_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int __init diff --git a/trunk/drivers/char/genrtc.c b/trunk/drivers/char/genrtc.c index 4f943759d376..bc9b84d56ee4 100644 --- a/trunk/drivers/char/genrtc.c +++ b/trunk/drivers/char/genrtc.c @@ -465,7 +465,7 @@ static const struct file_operations gen_rtc_proc_fops = { .open = gen_rtc_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int __init gen_rtc_proc_init(void) diff --git a/trunk/drivers/gpio/gpio-ucb1400.c b/trunk/drivers/gpio/gpio-ucb1400.c index 6d0feb234d3c..26405efe0f9f 100644 --- a/trunk/drivers/gpio/gpio-ucb1400.c +++ b/trunk/drivers/gpio/gpio-ucb1400.c @@ -12,6 +12,8 @@ #include #include +struct ucb1400_gpio_data *ucbdata; + static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off) { struct ucb1400_gpio *gpio; @@ -48,7 +50,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) struct ucb1400_gpio *ucb = dev->dev.platform_data; int err = 0; - if (!(ucb && ucb->gpio_offset)) { + if (!(ucbdata && ucbdata->gpio_offset)) { err = -EINVAL; goto err; } @@ -56,7 +58,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) platform_set_drvdata(dev, ucb); ucb->gc.label = "ucb1400_gpio"; - ucb->gc.base = ucb->gpio_offset; + ucb->gc.base = ucbdata->gpio_offset; ucb->gc.ngpio = 10; ucb->gc.owner = THIS_MODULE; @@ -70,8 +72,8 @@ static int ucb1400_gpio_probe(struct platform_device *dev) if (err) goto err; - if (ucb && ucb->gpio_setup) - err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio); + if (ucbdata && ucbdata->gpio_setup) + err = ucbdata->gpio_setup(&dev->dev, ucb->gc.ngpio); err: return err; @@ -83,8 +85,8 @@ static int ucb1400_gpio_remove(struct platform_device *dev) int err = 0; struct ucb1400_gpio *ucb = platform_get_drvdata(dev); - if (ucb && ucb->gpio_teardown) { - err = ucb->gpio_teardown(&dev->dev, ucb->gc.ngpio); + if (ucbdata && ucbdata->gpio_teardown) { + err = ucbdata->gpio_teardown(&dev->dev, ucb->gc.ngpio); if (err) return err; } @@ -101,6 +103,11 @@ static struct platform_driver ucb1400_gpio_driver = { }, }; +void __init ucb1400_gpio_set_data(struct ucb1400_gpio_data *data) +{ + ucbdata = data; +} + module_platform_driver(ucb1400_gpio_driver); MODULE_DESCRIPTION("Philips UCB1400 GPIO driver"); diff --git a/trunk/drivers/input/keyboard/Kconfig b/trunk/drivers/input/keyboard/Kconfig index 6a195d5e90ff..ac0500667000 100644 --- a/trunk/drivers/input/keyboard/Kconfig +++ b/trunk/drivers/input/keyboard/Kconfig @@ -628,16 +628,4 @@ config KEYBOARD_W90P910 To compile this driver as a module, choose M here: the module will be called w90p910_keypad. -config KEYBOARD_CROS_EC - tristate "ChromeOS EC keyboard" - select INPUT_MATRIXKMAP - depends on MFD_CROS_EC - help - Say Y here to enable the matrix keyboard used by ChromeOS devices - and implemented on the ChromeOS EC. You must enable one bus option - (MFD_CROS_EC_I2C or MFD_CROS_EC_SPI) to use this. - - To compile this driver as a module, choose M here: the - module will be called cros_ec_keyb. - endif diff --git a/trunk/drivers/input/keyboard/Makefile b/trunk/drivers/input/keyboard/Makefile index 0c43e8cf8d0e..49b16453d00e 100644 --- a/trunk/drivers/input/keyboard/Makefile +++ b/trunk/drivers/input/keyboard/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o -obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o diff --git a/trunk/drivers/input/keyboard/cros_ec_keyb.c b/trunk/drivers/input/keyboard/cros_ec_keyb.c deleted file mode 100644 index 49557f27bfa6..000000000000 --- a/trunk/drivers/input/keyboard/cros_ec_keyb.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * ChromeOS EC keyboard driver - * - * Copyright (C) 2012 Google, Inc - * - * 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. - * - * This driver uses the Chrome OS EC byte-level message-based protocol for - * communicating the keyboard state (which keys are pressed) from a keyboard EC - * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, - * but everything else (including deghosting) is done here. The main - * motivation for this is to keep the EC firmware as simple as possible, since - * it cannot be easily upgraded and EC flash/IRAM space is relatively - * expensive. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * @rows: Number of rows in the keypad - * @cols: Number of columns in the keypad - * @row_shift: log2 or number of rows, rounded up - * @keymap_data: Matrix keymap data used to convert to keyscan values - * @ghost_filter: true to enable the matrix key-ghosting filter - * @dev: Device pointer - * @idev: Input device - * @ec: Top level ChromeOS device to use to talk to EC - * @event_notifier: interrupt event notifier for transport devices - */ -struct cros_ec_keyb { - unsigned int rows; - unsigned int cols; - int row_shift; - const struct matrix_keymap_data *keymap_data; - bool ghost_filter; - - struct device *dev; - struct input_dev *idev; - struct cros_ec_device *ec; - struct notifier_block notifier; -}; - - -static bool cros_ec_keyb_row_has_ghosting(struct cros_ec_keyb *ckdev, - uint8_t *buf, int row) -{ - int pressed_in_row = 0; - int row_has_teeth = 0; - int col, mask; - - mask = 1 << row; - for (col = 0; col < ckdev->cols; col++) { - if (buf[col] & mask) { - pressed_in_row++; - row_has_teeth |= buf[col] & ~mask; - if (pressed_in_row > 1 && row_has_teeth) { - /* ghosting */ - dev_dbg(ckdev->dev, - "ghost found at: r%d c%d, pressed %d, teeth 0x%x\n", - row, col, pressed_in_row, - row_has_teeth); - return true; - } - } - } - - return false; -} - -/* - * Returns true when there is at least one combination of pressed keys that - * results in ghosting. - */ -static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) -{ - int row; - - /* - * Ghosting happens if for any pressed key X there are other keys - * pressed both in the same row and column of X as, for instance, - * in the following diagram: - * - * . . Y . g . - * . . . . . . - * . . . . . . - * . . X . Z . - * - * In this case only X, Y, and Z are pressed, but g appears to be - * pressed too (see Wikipedia). - * - * We can detect ghosting in a single pass (*) over the keyboard state - * by maintaining two arrays. pressed_in_row counts how many pressed - * keys we have found in a row. row_has_teeth is true if any of the - * pressed keys for this row has other pressed keys in its column. If - * at any point of the scan we find that a row has multiple pressed - * keys, and at least one of them is at the intersection with a column - * with multiple pressed keys, we're sure there is ghosting. - * Conversely, if there is ghosting, we will detect such situation for - * at least one key during the pass. - * - * (*) This looks linear in the number of keys, but it's not. We can - * cheat because the number of rows is small. - */ - for (row = 0; row < ckdev->rows; row++) - if (cros_ec_keyb_row_has_ghosting(ckdev, buf, row)) - return true; - - return false; -} - -/* - * Compares the new keyboard state to the old one and produces key - * press/release events accordingly. The keyboard state is 13 bytes (one byte - * per column) - */ -static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, - uint8_t *kb_state, int len) -{ - struct input_dev *idev = ckdev->idev; - int col, row; - int new_state; - int num_cols; - - num_cols = len; - - if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) { - /* - * Simple-minded solution: ignore this state. The obvious - * improvement is to only ignore changes to keys involved in - * the ghosting, but process the other changes. - */ - dev_dbg(ckdev->dev, "ghosting found\n"); - return; - } - - for (col = 0; col < ckdev->cols; col++) { - for (row = 0; row < ckdev->rows; row++) { - int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); - const unsigned short *keycodes = idev->keycode; - int code; - - code = keycodes[pos]; - new_state = kb_state[col] & (1 << row); - if (!!new_state != test_bit(code, idev->key)) { - dev_dbg(ckdev->dev, - "changed: [r%d c%d]: byte %02x\n", - row, col, new_state); - - input_report_key(idev, code, new_state); - } - } - } - input_sync(ckdev->idev); -} - -static int cros_ec_keyb_open(struct input_dev *dev) -{ - struct cros_ec_keyb *ckdev = input_get_drvdata(dev); - - return blocking_notifier_chain_register(&ckdev->ec->event_notifier, - &ckdev->notifier); -} - -static void cros_ec_keyb_close(struct input_dev *dev) -{ - struct cros_ec_keyb *ckdev = input_get_drvdata(dev); - - blocking_notifier_chain_unregister(&ckdev->ec->event_notifier, - &ckdev->notifier); -} - -static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) -{ - return ckdev->ec->command_recv(ckdev->ec, EC_CMD_MKBP_STATE, - kb_state, ckdev->cols); -} - -static int cros_ec_keyb_work(struct notifier_block *nb, - unsigned long state, void *_notify) -{ - int ret; - struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, - notifier); - uint8_t kb_state[ckdev->cols]; - - ret = cros_ec_keyb_get_state(ckdev, kb_state); - if (ret >= 0) - cros_ec_keyb_process(ckdev, kb_state, ret); - - return NOTIFY_DONE; -} - -/* Clear any keys in the buffer */ -static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev) -{ - uint8_t old_state[ckdev->cols]; - uint8_t new_state[ckdev->cols]; - unsigned long duration; - int i, ret; - - /* - * Keep reading until we see that the scan state does not change. - * That indicates that we are done. - * - * Assume that the EC keyscan buffer is at most 32 deep. - */ - duration = jiffies; - ret = cros_ec_keyb_get_state(ckdev, new_state); - for (i = 1; !ret && i < 32; i++) { - memcpy(old_state, new_state, sizeof(old_state)); - ret = cros_ec_keyb_get_state(ckdev, new_state); - if (0 == memcmp(old_state, new_state, sizeof(old_state))) - break; - } - duration = jiffies - duration; - dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i, - jiffies_to_usecs(duration)); -} - -static int cros_ec_keyb_probe(struct platform_device *pdev) -{ - struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); - struct device *dev = ec->dev; - struct cros_ec_keyb *ckdev; - struct input_dev *idev; - struct device_node *np; - int err; - - np = pdev->dev.of_node; - if (!np) - return -ENODEV; - - ckdev = devm_kzalloc(&pdev->dev, sizeof(*ckdev), GFP_KERNEL); - if (!ckdev) - return -ENOMEM; - err = matrix_keypad_parse_of_params(&pdev->dev, &ckdev->rows, - &ckdev->cols); - if (err) - return err; - - idev = devm_input_allocate_device(&pdev->dev); - if (!idev) - return -ENOMEM; - - ckdev->ec = ec; - ckdev->notifier.notifier_call = cros_ec_keyb_work; - ckdev->dev = dev; - dev_set_drvdata(&pdev->dev, ckdev); - - idev->name = ec->ec_name; - idev->phys = ec->phys_name; - __set_bit(EV_REP, idev->evbit); - - idev->id.bustype = BUS_VIRTUAL; - idev->id.version = 1; - idev->id.product = 0; - idev->dev.parent = &pdev->dev; - idev->open = cros_ec_keyb_open; - idev->close = cros_ec_keyb_close; - - ckdev->ghost_filter = of_property_read_bool(np, - "google,needs-ghost-filter"); - - err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols, - NULL, idev); - if (err) { - dev_err(dev, "cannot build key matrix\n"); - return err; - } - - ckdev->row_shift = get_count_order(ckdev->cols); - - input_set_capability(idev, EV_MSC, MSC_SCAN); - input_set_drvdata(idev, ckdev); - ckdev->idev = idev; - err = input_register_device(ckdev->idev); - if (err) { - dev_err(dev, "cannot register input device\n"); - return err; - } - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int cros_ec_keyb_resume(struct device *dev) -{ - struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); - - /* - * When the EC is not a wake source, then it could not have caused the - * resume, so we clear the EC's key scan buffer. If the EC was a - * wake source (e.g. the lid is open and the user might press a key to - * wake) then the key scan buffer should be preserved. - */ - if (ckdev->ec->was_wake_device) - cros_ec_keyb_clear_keyboard(ckdev); - - return 0; -} - -#endif - -static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); - -static struct platform_driver cros_ec_keyb_driver = { - .probe = cros_ec_keyb_probe, - .driver = { - .name = "cros-ec-keyb", - .pm = &cros_ec_keyb_pm_ops, - }, -}; - -module_platform_driver(cros_ec_keyb_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ChromeOS EC keyboard driver"); -MODULE_ALIAS("platform:cros-ec-keyb"); diff --git a/trunk/drivers/input/keyboard/lpc32xx-keys.c b/trunk/drivers/input/keyboard/lpc32xx-keys.c index 42181435fe67..1b8add6cfb9d 100644 --- a/trunk/drivers/input/keyboard/lpc32xx-keys.c +++ b/trunk/drivers/input/keyboard/lpc32xx-keys.c @@ -144,13 +144,12 @@ static int lpc32xx_parse_dt(struct device *dev, { struct device_node *np = dev->of_node; u32 rows = 0, columns = 0; - int err; - err = matrix_keypad_parse_of_params(dev, &rows, &columns); - if (err) - return err; - if (rows != columns) { - dev_err(dev, "rows and columns must be equal!\n"); + of_property_read_u32(np, "keypad,num-rows", &rows); + of_property_read_u32(np, "keypad,num-columns", &columns); + if (!rows || rows != columns) { + dev_err(dev, + "rows and columns must be specified and be equal!\n"); return -EINVAL; } diff --git a/trunk/drivers/input/keyboard/omap4-keypad.c b/trunk/drivers/input/keyboard/omap4-keypad.c index 1b289092f4e3..e25b022692cd 100644 --- a/trunk/drivers/input/keyboard/omap4-keypad.c +++ b/trunk/drivers/input/keyboard/omap4-keypad.c @@ -215,12 +215,18 @@ static int omap4_keypad_parse_dt(struct device *dev, struct omap4_keypad *keypad_data) { struct device_node *np = dev->of_node; - int err; - err = matrix_keypad_parse_of_params(dev, &keypad_data->rows, - &keypad_data->cols); - if (err) - return err; + if (!np) { + dev_err(dev, "missing DT data"); + return -EINVAL; + } + + of_property_read_u32(np, "keypad,num-rows", &keypad_data->rows); + of_property_read_u32(np, "keypad,num-columns", &keypad_data->cols); + if (!keypad_data->rows || !keypad_data->cols) { + dev_err(dev, "number of keypad rows/columns not specified\n"); + return -EINVAL; + } if (of_get_property(np, "linux,input-no-autorepeat", NULL)) keypad_data->no_autorepeat = true; diff --git a/trunk/drivers/input/keyboard/tca8418_keypad.c b/trunk/drivers/input/keyboard/tca8418_keypad.c index 55c15304ddbc..a34cc6714e5b 100644 --- a/trunk/drivers/input/keyboard/tca8418_keypad.c +++ b/trunk/drivers/input/keyboard/tca8418_keypad.c @@ -288,11 +288,8 @@ static int tca8418_keypad_probe(struct i2c_client *client, irq_is_gpio = pdata->irq_is_gpio; } else { struct device_node *np = dev->of_node; - int err; - - err = matrix_keypad_parse_of_params(dev, &rows, &cols); - if (err) - return err; + of_property_read_u32(np, "keypad,num-rows", &rows); + of_property_read_u32(np, "keypad,num-columns", &cols); rep = of_property_read_bool(np, "keypad,autorepeat"); } diff --git a/trunk/drivers/input/matrix-keymap.c b/trunk/drivers/input/matrix-keymap.c index 08b61f506db6..3ae496ea5fe6 100644 --- a/trunk/drivers/input/matrix-keymap.c +++ b/trunk/drivers/input/matrix-keymap.c @@ -50,26 +50,6 @@ static bool matrix_keypad_map_key(struct input_dev *input_dev, } #ifdef CONFIG_OF -int matrix_keypad_parse_of_params(struct device *dev, - unsigned int *rows, unsigned int *cols) -{ - struct device_node *np = dev->of_node; - - if (!np) { - dev_err(dev, "missing DT data"); - return -EINVAL; - } - of_property_read_u32(np, "keypad,num-rows", rows); - of_property_read_u32(np, "keypad,num-columns", cols); - if (!*rows || !*cols) { - dev_err(dev, "number of keypad rows/columns not specified\n"); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(matrix_keypad_parse_of_params); - static int matrix_keypad_parse_of_keymap(const char *propname, unsigned int rows, unsigned int cols, struct input_dev *input_dev) diff --git a/trunk/drivers/input/misc/hp_sdc_rtc.c b/trunk/drivers/input/misc/hp_sdc_rtc.c index 86b822806e95..770479df8657 100644 --- a/trunk/drivers/input/misc/hp_sdc_rtc.c +++ b/trunk/drivers/input/misc/hp_sdc_rtc.c @@ -515,7 +515,7 @@ static const struct file_operations hp_sdc_rtc_proc_fops = { .open = hp_sdc_rtc_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int hp_sdc_rtc_ioctl(struct file *file, diff --git a/trunk/drivers/mfd/88pm860x-core.c b/trunk/drivers/mfd/88pm860x-core.c index 31ca55548ef9..893fc1ba6ead 100644 --- a/trunk/drivers/mfd/88pm860x-core.c +++ b/trunk/drivers/mfd/88pm860x-core.c @@ -1144,15 +1144,17 @@ static int pm860x_probe(struct i2c_client *client, return -ENOMEM; ret = pm860x_dt_init(node, &client->dev, pdata); if (ret) - return ret; + goto err; } else if (!pdata) { pr_info("No platform data in %s!\n", __func__); return -EINVAL; } chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; + if (chip == NULL) { + ret = -ENOMEM; + goto err; + } chip->id = verify_addr(client); chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); @@ -1192,6 +1194,10 @@ static int pm860x_probe(struct i2c_client *client, pm860x_device_init(chip, pdata); return 0; +err: + if (node) + devm_kfree(&client->dev, pdata); + return ret; } static int pm860x_remove(struct i2c_client *client) diff --git a/trunk/drivers/mfd/Kconfig b/trunk/drivers/mfd/Kconfig index d9aed1593e5d..ca86581d02ce 100644 --- a/trunk/drivers/mfd/Kconfig +++ b/trunk/drivers/mfd/Kconfig @@ -10,164 +10,111 @@ config MFD_CORE select IRQ_DOMAIN default n -config MFD_CS5535 - tristate "AMD CS5535 and CS5536 southbridge core functions" +config MFD_88PM860X + bool "Support Marvell 88PM8606/88PM8607" + depends on I2C=y && GENERIC_HARDIRQS + select REGMAP_I2C select MFD_CORE - depends on PCI && X86 - ---help--- - This is the core driver for CS5535/CS5536 MFD functions. This is - necessary for using the board's GPIO and MFGPT functionality. + help + This supports for Marvell 88PM8606/88PM8607 Power Management IC. + This includes the I2C driver and the core APIs _only_, you have to + select individual components like voltage regulators, RTC and + battery-charger under the corresponding menus. -config MFD_AS3711 - bool "AMS AS3711" - select MFD_CORE +config MFD_88PM800 + tristate "Support Marvell 88PM800" + depends on I2C=y && GENERIC_HARDIRQS select REGMAP_I2C select REGMAP_IRQ - depends on I2C=y && GENERIC_HARDIRQS - help - Support for the AS3711 PMIC from AMS - -config PMIC_ADP5520 - bool "Analog Devices ADP5520/01 MFD PMIC Core Support" - depends on I2C=y - help - Say yes here to add support for Analog Devices AD5520 and ADP5501, - Multifunction Power Management IC. This includes - the I2C driver and the core APIs _only_, you have to select - individual components like LCD backlight, LEDs, GPIOs and Kepad - under the corresponding menus. - -config MFD_AAT2870_CORE - bool "AnalogicTech AAT2870" select MFD_CORE - depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS help - If you say yes here you get support for the AAT2870. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. + This supports for Marvell 88PM800 Power Management IC. + This includes the I2C driver and the core APIs _only_, you have to + select individual components like voltage regulators, RTC and + battery-charger under the corresponding menus. -config MFD_CROS_EC - tristate "ChromeOS Embedded Controller" +config MFD_88PM805 + tristate "Support Marvell 88PM805" + depends on I2C=y && GENERIC_HARDIRQS + select REGMAP_I2C + select REGMAP_IRQ select MFD_CORE help - If you say Y here you get support for the ChromeOS Embedded - Controller (EC) providing keyboard, battery and power services. - You also ned to enable the driver for the bus you are using. The - protocol for talking to the EC is defined by the bus driver. - -config MFD_CROS_EC_I2C - tristate "ChromeOS Embedded Controller (I2C)" - depends on MFD_CROS_EC && I2C + This supports for Marvell 88PM805 Power Management IC. This includes + the I2C driver and the core APIs _only_, you have to select individual + components like codec device, headset/Mic device under the + corresponding menus. - help - If you say Y here, you get support for talking to the ChromeOS - EC through an I2C bus. This uses a simple byte-level protocol with - a checksum. Failing accesses will be retried three times to - improve reliability. +config MFD_SM501 + tristate "Support for Silicon Motion SM501" + ---help--- + This is the core driver for the Silicon Motion SM501 multimedia + companion chip. This device is a multifunction device which may + provide numerous interfaces including USB host controller, USB gadget, + asynchronous serial ports, audio functions, and a dual display video + interface. The device may be connected by PCI or local bus with + varying functions enabled. -config MFD_CROS_EC_SPI - tristate "ChromeOS Embedded Controller (SPI)" - depends on MFD_CROS_EC && SPI +config MFD_SM501_GPIO + bool "Export GPIO via GPIO layer" + depends on MFD_SM501 && GPIOLIB + ---help--- + This option uses the gpio library layer to export the 64 GPIO + lines on the SM501. The platform data is used to supply the + base number for the first GPIO line to register. - ---help--- - If you say Y here, you get support for talking to the ChromeOS EC - through a SPI bus, using a byte-level protocol. Since the EC's - response time cannot be guaranteed, we support ignoring - 'pre-amble' bytes before the response actually starts. +config MFD_RTSX_PCI + tristate "Support for Realtek PCI-E card reader" + depends on PCI && GENERIC_HARDIRQS + select MFD_CORE + help + This supports for Realtek PCI-Express card reader including rts5209, + rts5229, rtl8411, etc. Realtek card reader supports access to many + types of memory cards, such as Memory Stick, Memory Stick Pro, + Secure Digital and MultiMediaCard. config MFD_ASIC3 - bool "Compaq ASIC3" + bool "Support for Compaq ASIC3" depends on GENERIC_HARDIRQS && GPIOLIB && ARM select MFD_CORE ---help--- This driver supports the ASIC3 multifunction chip found on many PDAs (mainly iPAQ and HTC based ones) -config PMIC_DA903X - bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" - depends on I2C=y - help - Say yes here to support for Dialog Semiconductor DA9030 (a.k.a - ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC - usually found on PXA processors-based platforms. This includes - the I2C driver and the core APIs _only_, you have to select - individual components like LCD backlight, voltage regulators, - LEDs and battery-charger under the corresponding menus. - -config PMIC_DA9052 - bool +config MFD_DAVINCI_VOICECODEC + tristate select MFD_CORE -config MFD_DA9052_SPI - bool "Dialog Semiconductor DA9052/53 PMIC variants with SPI" - select REGMAP_SPI - select REGMAP_IRQ - select PMIC_DA9052 - depends on SPI_MASTER=y && GENERIC_HARDIRQS - help - Support for the Dialog Semiconductor DA9052 PMIC - when controlled using SPI. This driver provides common support - for accessing the device, additional drivers must be enabled in - order to use the functionality of the device. - -config MFD_DA9052_I2C - bool "Dialog Semiconductor DA9052/53 PMIC variants with I2C" - select REGMAP_I2C - select REGMAP_IRQ - select PMIC_DA9052 - depends on I2C=y && GENERIC_HARDIRQS +config MFD_DM355EVM_MSP + bool "DaVinci DM355 EVM microcontroller" + depends on I2C=y && MACH_DAVINCI_DM355_EVM help - Support for the Dialog Semiconductor DA9052 PMIC - when controlled using I2C. This driver provides common support - for accessing the device, additional drivers must be enabled in - order to use the functionality of the device. + This driver supports the MSP430 microcontroller used on these + boards. MSP430 firmware manages resets and power sequencing, + inputs from buttons and the IR remote, LEDs, an RTC, and more. -config MFD_DA9055 - bool "Dialog Semiconductor DA9055 PMIC Support" - select REGMAP_I2C - select REGMAP_IRQ +config MFD_TI_SSP + tristate "TI Sequencer Serial Port support" + depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS select MFD_CORE - depends on I2C=y && GENERIC_HARDIRQS - help - Say yes here for support of Dialog Semiconductor DA9055. This is - a Power Management IC. This driver provides common support for - accessing the device as well as the I2C interface to the chip itself. - Additional drivers must be enabled in order to use the functionality - of the device. - - This driver can be built as a module. If built as a module it will be - called "da9055" + ---help--- + Say Y here if you want support for the Sequencer Serial Port + in a Texas Instruments TNETV107X SoC. -config MFD_MC13783 - tristate + To compile this driver as a module, choose M here: the + module will be called ti-ssp. -config MFD_MC13XXX - tristate - depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS +config MFD_TI_AM335X_TSCADC + tristate "TI ADC / Touch Screen chip support" select MFD_CORE - select MFD_MC13783 - help - Enable support for the Freescale MC13783 and MC13892 PMICs. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config MFD_MC13XXX_SPI - tristate "Freescale MC13783 and MC13892 SPI interface" - depends on SPI_MASTER && GENERIC_HARDIRQS - select REGMAP_SPI - select MFD_MC13XXX - help - Select this if your MC13xxx is connected via an SPI bus. - -config MFD_MC13XXX_I2C - tristate "Freescale MC13892 I2C interface" - depends on I2C && GENERIC_HARDIRQS - select REGMAP_I2C - select MFD_MC13XXX + select REGMAP + select REGMAP_MMIO + depends on GENERIC_HARDIRQS help - Select this if your MC13xxx is connected via an I2C bus. + If you say yes here you get support for Texas Instruments series + of Touch Screen /ADC chips. + To compile this driver as a module, choose M here: the + module will be called ti_am335x_tscadc. config HTC_EGPIO bool "HTC EGPIO support" @@ -196,330 +143,280 @@ config HTC_I2CPLD This device provides input and output GPIOs through an I2C interface to one or more sub-chips. -config LPC_ICH - tristate "Intel ICH LPC" - depends on PCI && GENERIC_HARDIRQS - select MFD_CORE +config UCB1400_CORE + tristate "Philips UCB1400 Core driver" + depends on AC97_BUS + depends on GPIOLIB help - The LPC bridge function of the Intel ICH provides support for - many functional units. This driver provides needed support for - other drivers to control these functions, currently GPIO and - watchdog. + This enables support for the Philips UCB1400 core functions. + The UCB1400 is an AC97 audio codec. -config LPC_SCH - tristate "Intel SCH LPC" - depends on PCI && GENERIC_HARDIRQS + To compile this driver as a module, choose M here: the + module will be called ucb1400_core. + +config MFD_LM3533 + tristate "LM3533 Lighting Power chip" + depends on I2C select MFD_CORE + select REGMAP_I2C + depends on GENERIC_HARDIRQS help - LPC bridge function of the Intel SCH provides support for - System Management Bus and General Purpose I/O. + Say yes here to enable support for National Semiconductor / TI + LM3533 Lighting Power chips. -config MFD_INTEL_MSIC - bool "Intel MSIC" - depends on INTEL_SCU_IPC + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the LED, + backlight or ambient-light-sensor functionality of the device. + +config TPS6105X + tristate "TPS61050/61052 Boost Converters" + depends on I2C + select REGULATOR select MFD_CORE + select REGULATOR_FIXED_VOLTAGE + depends on GENERIC_HARDIRQS help - Select this option to enable access to Intel MSIC (Avatele - Passage) chip. This chip embeds audio, battery, GPIO, etc. - devices used in Intel Medfield platforms. + This option enables a driver for the TP61050/TPS61052 + high-power "white LED driver". This boost converter is + sometimes used for other things than white LEDs, and + also contains a GPIO pin. -config MFD_JANZ_CMODIO - tristate "Janz CMOD-IO PCI MODULbus Carrier Board" - select MFD_CORE - depends on PCI && GENERIC_HARDIRQS +config TPS65010 + tristate "TPS6501x Power Management chips" + depends on I2C && GPIOLIB + default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK help - This is the core driver for the Janz CMOD-IO PCI MODULbus - carrier board. This device is a PCI to MODULbus bridge which may - host many different types of MODULbus daughterboards, including - CAN and GPIO controllers. + If you say yes here you get support for the TPS6501x series of + Power Management chips. These include voltage regulators, + lithium ion/polymer battery charging, and other features that + are often used in portable devices like cell phones and cameras. -config MFD_JZ4740_ADC - bool "Janz JZ4740 ADC core" + This driver can also be built as a module. If so, the module + will be called tps65010. + +config TPS6507X + tristate "TPS6507x Power Management / Touch Screen chips" select MFD_CORE - select GENERIC_IRQ_CHIP - depends on MACH_JZ4740 + depends on I2C && GENERIC_HARDIRQS help - Say yes here if you want support for the ADC unit in the JZ4740 SoC. - This driver is necessary for jz4740-battery and jz4740-hwmon driver. + If you say yes here you get support for the TPS6507x series of + Power Management / Touch Screen chips. These include voltage + regulators, lithium ion/polymer battery charging, touch screen + and other features that are often used in portable devices. + This driver can also be built as a module. If so, the module + will be called tps6507x. -config MFD_88PM800 - tristate "Marvell 88PM800" - depends on I2C=y && GENERIC_HARDIRQS - select REGMAP_I2C - select REGMAP_IRQ +config MFD_TPS65217 + tristate "TPS65217 Power Management / White LED chips" + depends on I2C && GENERIC_HARDIRQS select MFD_CORE + select REGMAP_I2C help - This supports for Marvell 88PM800 Power Management IC. - This includes the I2C driver and the core APIs _only_, you have to - select individual components like voltage regulators, RTC and - battery-charger under the corresponding menus. + If you say yes here you get support for the TPS65217 series of + Power Management / White LED chips. + These include voltage regulators, lithium ion/polymer battery + charger, wled and other features that are often used in portable + devices. -config MFD_88PM805 - tristate "Marvell 88PM805" - depends on I2C=y && GENERIC_HARDIRQS - select REGMAP_I2C - select REGMAP_IRQ - select MFD_CORE - help - This supports for Marvell 88PM805 Power Management IC. This includes - the I2C driver and the core APIs _only_, you have to select individual - components like codec device, headset/Mic device under the - corresponding menus. + This driver can also be built as a module. If so, the module + will be called tps65217. -config MFD_88PM860X - bool "Marvell 88PM8606/88PM8607" +config MFD_TPS6586X + bool "TPS6586x Power Management chips" depends on I2C=y && GENERIC_HARDIRQS - select REGMAP_I2C select MFD_CORE + select REGMAP_I2C help - This supports for Marvell 88PM8606/88PM8607 Power Management IC. - This includes the I2C driver and the core APIs _only_, you have to - select individual components like voltage regulators, RTC and - battery-charger under the corresponding menus. + If you say yes here you get support for the TPS6586X series of + Power Management chips. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. -config MFD_MAX77686 - bool "Maxim Semiconductor MAX77686 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS + This driver can also be built as a module. If so, the module + will be called tps6586x. + +config MFD_TPS65910 + bool "TPS65910 Power Management chip" + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C + select REGMAP_IRQ select IRQ_DOMAIN help - Say yes here to support for Maxim Semiconductor MAX77686. - This is a Power Management IC with RTC on chip. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the functionality - of the device. + if you say yes here you get support for the TPS65910 series of + Power Management chips. -config MFD_MAX77693 - bool "Maxim Semiconductor MAX77693 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS +config MFD_TPS65912 + bool + depends on GPIOLIB + +config MFD_TPS65912_I2C + bool "TPS65912 Power Management chip with I2C" select MFD_CORE - select REGMAP_I2C + select MFD_TPS65912 + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS help - Say yes here to support for Maxim Semiconductor MAX77693. - This is a companion Power Management IC with Flash, Haptic, Charger, - and MUIC(Micro USB Interface Controller) controls on chip. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the functionality - of the device. + If you say yes here you get support for the TPS65912 series of + PM chips with I2C interface. -config MFD_MAX8907 - tristate "Maxim Semiconductor MAX8907 PMIC Support" +config MFD_TPS65912_SPI + bool "TPS65912 Power Management chip with SPI" select MFD_CORE + select MFD_TPS65912 + depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS + help + If you say yes here you get support for the TPS65912 series of + PM chips with SPI interface. + +config MFD_TPS80031 + bool "TI TPS80031/TPS80032 Power Management chips" depends on I2C=y && GENERIC_HARDIRQS + select MFD_CORE select REGMAP_I2C select REGMAP_IRQ help - Say yes here to support for Maxim Semiconductor MAX8907. This is - a Power Management IC. This driver provides common support for - accessing the device; additional drivers must be enabled in order - to use the functionality of the device. + If you say yes here you get support for the Texas Instruments + TPS80031/ TPS80032 Fully Integrated Power Management with Power + Path and Battery Charger. The device provides five configurable + step-down converters, 11 general purpose LDOs, USB OTG Module, + ADC, RTC, 2 PWM, System Voltage Regulator/Battery Charger with + Power Path from USB, 32K clock generator. -config MFD_MAX8925 - bool "Maxim Semiconductor MAX8925 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS - select MFD_CORE +config MENELAUS + bool "Texas Instruments TWL92330/Menelaus PM chip" + depends on I2C=y && ARCH_OMAP2 help - Say yes here to support for Maxim Semiconductor MAX8925. This is - a Power Management IC. This driver provides common support for - accessing the device, additional drivers must be enabled in order - to use the functionality of the device. + If you say yes here you get support for the Texas Instruments + TWL92330/Menelaus Power Management chip. This include voltage + regulators, Dual slot memory card transceivers, real-time clock + and other features that are often used in portable devices like + cell phones and PDAs. -config MFD_MAX8997 - bool "Maxim Semiconductor MAX8997/8966 PMIC Support" +config TWL4030_CORE + bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" depends on I2C=y && GENERIC_HARDIRQS - select MFD_CORE select IRQ_DOMAIN + select REGMAP_I2C help - Say yes here to support for Maxim Semiconductor MAX8997/8966. - This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, - MUIC controls on chip. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the functionality - of the device. + Say yes here if you have TWL4030 / TWL6030 family chip on your board. + This core driver provides register access and IRQ handling + facilities, and registers devices for the various functions + so that function-specific drivers can bind to them. -config MFD_MAX8998 - bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS - select MFD_CORE + These multi-function chips are found on many OMAP2 and OMAP3 + boards, providing power management, RTC, GPIO, keypad, a + high speed USB OTG transceiver, an audio codec (on most + versions) and many other features. + +config TWL4030_MADC + tristate "Texas Instruments TWL4030 MADC" + depends on TWL4030_CORE help - Say yes here to support for Maxim Semiconductor MAX8998 and - National Semiconductor LP3974. This is a Power Management IC. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the functionality - of the device. + This driver provides support for triton TWL4030-MADC. The + driver supports both RT and SW conversion methods. -config EZX_PCAP - bool "Motorola EZXPCAP Support" - depends on GENERIC_HARDIRQS && SPI_MASTER + This driver can be built as a module. If so it will be + named twl4030-madc + +config TWL4030_POWER + bool "Support power resources on TWL4030 family chips" + depends on TWL4030_CORE && ARM help - This enables the PCAP ASIC present on EZX Phones. This is - needed for MMC, TouchScreen, Sound, USB, etc.. + Say yes here if you want to use the power resources on the + TWL4030 family chips. Most of these resources are regulators, + which have a separate driver; some are control signals, such + as clock request handshaking. -config MFD_VIPERBOARD - tristate "Nano River Technologies Viperboard" + This driver uses board-specific data to initialize the resources + and load scripts controlling which resources are switched off/on + or reset when a sleep, wakeup or warm reset event occurs. + +config MFD_TWL4030_AUDIO + bool + depends on TWL4030_CORE && GENERIC_HARDIRQS select MFD_CORE - depends on USB && GENERIC_HARDIRQS default n - help - Say yes here if you want support for Nano River Technologies - Viperboard. - There are mfd cell drivers available for i2c master, adc and - both gpios found on the board. The spi part does not yet - have a driver. - You need to select the mfd cell drivers separately. - The drivers do not support all features the board exposes. -config MFD_RETU - tristate "Nokia Retu and Tahvo multi-function device" +config TWL6040_CORE + bool "Support for TWL6040 audio codec" + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE - depends on I2C && GENERIC_HARDIRQS + select REGMAP_I2C select REGMAP_IRQ + default n help - Retu and Tahvo are a multi-function devices found on Nokia - Internet Tablets (770, N800 and N810). + Say yes here if you want support for Texas Instruments TWL6040 audio + codec. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device (audio, vibra). -config MFD_PCF50633 - tristate "NXP PCF50633" - depends on I2C - select REGMAP_I2C +config MFD_STMPE + bool "Support STMicroelectronics STMPE" + depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS + select MFD_CORE help - Say yes here if you have NXP PCF50633 chip on your board. - This core driver provides register access and IRQ handling - facilities, and registers devices for the various functions - so that function-specific drivers can bind to them. + Support for the STMPE family of I/O Expanders from + STMicroelectronics. -config PCF50633_ADC - tristate "NXP PCF50633 ADC" - depends on MFD_PCF50633 - help - Say yes here if you want to include support for ADC in the - NXP PCF50633 chip. + Currently supported devices are: -config PCF50633_GPIO - tristate "NXP PCF50633 GPIO" - depends on MFD_PCF50633 - help - Say yes here if you want to include support GPIO for pins on - the PCF50633 chip. + STMPE811: GPIO, Touchscreen + STMPE1601: GPIO, Keypad + STMPE2401: GPIO, Keypad + STMPE2403: GPIO, Keypad -config UCB1400_CORE - tristate "Philips UCB1400 Core driver" - depends on AC97_BUS - depends on GPIOLIB - help - This enables support for the Philips UCB1400 core functions. - The UCB1400 is an AC97 audio codec. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the functionality + of the device. Currently available sub drivers are: - To compile this driver as a module, choose M here: the - module will be called ucb1400_core. + GPIO: stmpe-gpio + Keypad: stmpe-keypad + Touchscreen: stmpe-ts -config MFD_PM8XXX - tristate +menu "STMPE Interface Drivers" +depends on MFD_STMPE -config MFD_PM8921_CORE - tristate "Qualcomm PM8921 PMIC chip" - depends on SSBI && BROKEN - select MFD_CORE - select MFD_PM8XXX +config STMPE_I2C + bool "STMPE I2C Inteface" + depends on I2C=y + default y help - If you say yes to this option, support will be included for the - built-in PM8921 PMIC chip. - - This is required if your board has a PM8921 and uses its features, - such as: MPPs, GPIOs, regulators, interrupts, and PWM. - - Say M here if you want to include support for PM8921 chip as a module. - This will build a module called "pm8921-core". + This is used to enable I2C interface of STMPE -config MFD_PM8XXX_IRQ - bool "Qualcomm PM8xxx IRQ features" - depends on MFD_PM8XXX - default y if MFD_PM8XXX +config STMPE_SPI + bool "STMPE SPI Inteface" + depends on SPI_MASTER help - This is the IRQ driver for Qualcomm PM 8xxx PMIC chips. - - This is required to use certain other PM 8xxx features, such as GPIO - and MPP. + This is used to enable SPI interface of STMPE +endmenu -config MFD_RDC321X - tristate "RDC R-321x southbridge" +config MFD_TC3589X + bool "Support Toshiba TC35892 and variants" + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE - depends on PCI && GENERIC_HARDIRQS help - Say yes here if you want to have support for the RDC R-321x SoC - southbridge which provides access to GPIOs and Watchdog using the - southbridge PCI device configuration space. - -config MFD_RTSX_PCI - tristate "Realtek PCI-E card reader" - depends on PCI && GENERIC_HARDIRQS - select MFD_CORE - help - This supports for Realtek PCI-Express card reader including rts5209, - rts5229, rtl8411, etc. Realtek card reader supports access to many - types of memory cards, such as Memory Stick, Memory Stick Pro, - Secure Digital and MultiMediaCard. + Support for the Toshiba TC35892 and variants I/O Expander. -config MFD_RC5T583 - bool "Ricoh RC5T583 Power Management system device" - depends on I2C=y && GENERIC_HARDIRQS - select MFD_CORE - select REGMAP_I2C - help - Select this option to get support for the RICOH583 Power - Management system device. - This driver provides common support for accessing the device - through i2c interface. The device supports multiple sub-devices - like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. - Additional drivers must be enabled in order to use the - different functionality of the device. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. -config MFD_SEC_CORE - bool "SAMSUNG Electronics PMIC Series Support" - depends on I2C=y && GENERIC_HARDIRQS - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - Support for the Samsung Electronics MFD series. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the functionality - of the device +config MFD_TMIO + bool + default n -config MFD_SI476X_CORE - tristate "Silicon Laboratories 4761/64/68 AM/FM radio." - depends on I2C +config MFD_T7L66XB + bool "Support Toshiba T7L66XB" + depends on ARM && HAVE_CLK && GENERIC_HARDIRQS select MFD_CORE - select REGMAP_I2C + select MFD_TMIO help - This is the core driver for the SI476x series of AM/FM - radio. This MFD driver connects the radio-si476x V4L2 module - and the si476x audio codec. - - To compile this driver as a module, choose M here: the - module will be called si476x-core. - -config MFD_SM501 - tristate "Silicon Motion SM501" - ---help--- - This is the core driver for the Silicon Motion SM501 multimedia - companion chip. This device is a multifunction device which may - provide numerous interfaces including USB host controller, USB gadget, - asynchronous serial ports, audio functions, and a dual display video - interface. The device may be connected by PCI or local bus with - varying functions enabled. - -config MFD_SM501_GPIO - bool "Export GPIO via GPIO layer" - depends on MFD_SM501 && GPIOLIB - ---help--- - This option uses the gpio library layer to export the 64 GPIO - lines on the SM501. The platform data is used to supply the - base number for the first GPIO line to register. + Support for Toshiba Mobile IO Controller T7L66XB config MFD_SMSC - bool "SMSC ECE1099 series chips" + bool "Support for the SMSC ECE1099 series chips" depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C @@ -530,158 +427,91 @@ config MFD_SMSC To compile this driver as a module, choose M here: the module will be called smsc. -config ABX500_CORE - bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" - default y if ARCH_U300 || ARCH_U8500 - help - Say yes here if you have the ABX500 Mixed Signal IC family - chips. This core driver expose register access functions. - Functionality specific drivers using these functions can - remain unchanged when IC changes. Binding of the functions to - actual register access is done by the IC core driver. - -config AB3100_CORE - bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" - depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS +config MFD_TC6387XB + bool "Support Toshiba TC6387XB" + depends on ARM && HAVE_CLK select MFD_CORE - default y if ARCH_U300 - help - Select this to enable the AB3100 Mixed Signal IC core - functionality. This connects to a AB3100 on the I2C bus - and expose a number of symbols needed for dependent devices - to read and write registers and subscribe to events from - this multi-functional IC. This is needed to use other features - of the AB3100 such as battery-backed RTC, charging control, - LEDs, vibrator, system power and temperature, power management - and ALSA sound. - -config AB3100_OTP - tristate "ST-Ericsson AB3100 OTP functions" - depends on AB3100_CORE - default y if AB3100_CORE + select MFD_TMIO help - Select this to enable the AB3100 Mixed Signal IC OTP (one-time - programmable memory) support. This exposes a sysfs file to read - out OTP values. + Support for Toshiba Mobile IO Controller TC6387XB -config AB8500_CORE - bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" - depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU - select POWER_SUPPLY +config MFD_TC6393XB + bool "Support Toshiba TC6393XB" + depends on ARM && HAVE_CLK + select GPIOLIB select MFD_CORE - select IRQ_DOMAIN - help - Select this option to enable access to AB8500 power management - chip. This connects to U8500 either on the SSP/SPI bus (deprecated - since hardware version v1.0) or the I2C bus via PRCMU. It also adds - the irq_chip parts for handling the Mixed Signal chip events. - This chip embeds various other multimedia funtionalities as well. - -config AB8500_DEBUG - bool "Enable debug info via debugfs" - depends on AB8500_CORE && DEBUG_FS - default y if DEBUG_FS - help - Select this option if you want debug information using the debug - filesystem, debugfs. - -config AB8500_GPADC - bool "ST-Ericsson AB8500 GPADC driver" - depends on AB8500_CORE && REGULATOR_AB8500 - default y + select MFD_TMIO help - AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage + Support for Toshiba Mobile IO Controller TC6393XB -config MFD_DB8500_PRCMU - bool "ST-Ericsson DB8500 Power Reset Control Management Unit" - depends on UX500_SOC_DB8500 - select MFD_CORE +config PMIC_DA903X + bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" + depends on I2C=y help - Select this option to enable support for the DB8500 Power Reset - and Control Management Unit. This is basically an autonomous - system controller running an XP70 microprocessor, which is accessed - through a register map. + Say yes here to support for Dialog Semiconductor DA9030 (a.k.a + ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC + usually found on PXA processors-based platforms. This includes + the I2C driver and the core APIs _only_, you have to select + individual components like LCD backlight, voltage regulators, + LEDs and battery-charger under the corresponding menus. -config MFD_STMPE - bool "STMicroelectronics STMPE" - depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS +config PMIC_DA9052 + bool select MFD_CORE - help - Support for the STMPE family of I/O Expanders from - STMicroelectronics. - - Currently supported devices are: - - STMPE811: GPIO, Touchscreen - STMPE1601: GPIO, Keypad - STMPE1801: GPIO, Keypad - STMPE2401: GPIO, Keypad - STMPE2403: GPIO, Keypad - - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the functionality - of the device. Currently available sub drivers are: - - GPIO: stmpe-gpio - Keypad: stmpe-keypad - Touchscreen: stmpe-ts - -menu "STMicroelectronics STMPE Interface Drivers" -depends on MFD_STMPE -config STMPE_I2C - bool "STMicroelectronics STMPE I2C Inteface" - depends on I2C=y - default y +config MFD_DA9052_SPI + bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI" + select REGMAP_SPI + select REGMAP_IRQ + select PMIC_DA9052 + depends on SPI_MASTER=y && GENERIC_HARDIRQS help - This is used to enable I2C interface of STMPE + Support for the Dialog Semiconductor DA9052 PMIC + when controlled using SPI. This driver provides common support + for accessing the device, additional drivers must be enabled in + order to use the functionality of the device. -config STMPE_SPI - bool "STMicroelectronics STMPE SPI Inteface" - depends on SPI_MASTER +config MFD_DA9052_I2C + bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C" + select REGMAP_I2C + select REGMAP_IRQ + select PMIC_DA9052 + depends on I2C=y && GENERIC_HARDIRQS help - This is used to enable SPI interface of STMPE -endmenu + Support for the Dialog Semiconductor DA9052 PMIC + when controlled using I2C. This driver provides common support + for accessing the device, additional drivers must be enabled in + order to use the functionality of the device. -config MFD_STA2X11 - bool "STMicroelectronics STA2X11" - depends on STA2X11 && GENERIC_HARDIRQS +config MFD_DA9055 + bool "Dialog Semiconductor DA9055 PMIC Support" + select REGMAP_I2C + select REGMAP_IRQ + select PMIC_DA9055 select MFD_CORE - select REGMAP_MMIO - -config MFD_SYSCON - bool "System Controller Register R/W Based on Regmap" - select REGMAP_MMIO + depends on I2C=y && GENERIC_HARDIRQS help - Select this option to enable accessing system control registers - via regmap. - -config MFD_DAVINCI_VOICECODEC - tristate - select MFD_CORE + Say yes here for support of Dialog Semiconductor DA9055. This is + a Power Management IC. This driver provides common support for + accessing the device as well as the I2C interface to the chip itself. + Additional drivers must be enabled in order to use the functionality + of the device. -config MFD_TI_AM335X_TSCADC - tristate "TI ADC / Touch Screen chip support" - select MFD_CORE - select REGMAP - select REGMAP_MMIO - depends on GENERIC_HARDIRQS - help - If you say yes here you get support for Texas Instruments series - of Touch Screen /ADC chips. - To compile this driver as a module, choose M here: the - module will be called ti_am335x_tscadc. + This driver can be built as a module. If built as a module it will be + called "da9055" -config MFD_DM355EVM_MSP - bool "TI DaVinci DM355 EVM microcontroller" - depends on I2C=y && MACH_DAVINCI_DM355_EVM +config PMIC_ADP5520 + bool "Analog Devices ADP5520/01 MFD PMIC Core Support" + depends on I2C=y help - This driver supports the MSP430 microcontroller used on these - boards. MSP430 firmware manages resets and power sequencing, - inputs from buttons and the IR remote, LEDs, an RTC, and more. + Say yes here to add support for Analog Devices AD5520 and ADP5501, + Multifunction Power Management IC. This includes + the I2C driver and the core APIs _only_, you have to select + individual components like LCD backlight, LEDs, GPIOs and Kepad + under the corresponding menus. config MFD_LP8788 - bool "TI LP8788 Power Management Unit Driver" + bool "Texas Instruments LP8788 Power Management Unit Driver" depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C @@ -690,265 +520,389 @@ config MFD_LP8788 TI LP8788 PMU supports regulators, battery charger, RTC, ADC, backlight driver and current sinks. -config MFD_OMAP_USB_HOST - bool "TI OMAP USBHS core and TLL driver" - depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 - default y - help - This is the core driver for the OAMP EHCI and OHCI drivers. - This MFD driver does the required setup functionalities for - OMAP USB Host drivers. - -config MFD_PALMAS - bool "TI Palmas series chips" +config MFD_MAX77686 + bool "Maxim Semiconductor MAX77686 PMIC Support" + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C - select REGMAP_IRQ - depends on I2C=y && GENERIC_HARDIRQS + select IRQ_DOMAIN help - If you say yes here you get support for the Palmas - series of PMIC chips from Texas Instruments. + Say yes here to support for Maxim Semiconductor MAX77686. + This is a Power Management IC with RTC on chip. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. -config MFD_TI_SSP - tristate "TI Sequencer Serial Port support" - depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS +config MFD_MAX77693 + bool "Maxim Semiconductor MAX77693 PMIC Support" + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE - ---help--- - Say Y here if you want support for the Sequencer Serial Port - in a Texas Instruments TNETV107X SoC. - - To compile this driver as a module, choose M here: the - module will be called ti-ssp. + select REGMAP_I2C + help + Say yes here to support for Maxim Semiconductor MAX77693. + This is a companion Power Management IC with Flash, Haptic, Charger, + and MUIC(Micro USB Interface Controller) controls on chip. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. -config TPS6105X - tristate "TI TPS61050/61052 Boost Converters" - depends on I2C - select REGULATOR +config MFD_MAX8907 + tristate "Maxim Semiconductor MAX8907 PMIC Support" select MFD_CORE - select REGULATOR_FIXED_VOLTAGE - depends on GENERIC_HARDIRQS + depends on I2C=y && GENERIC_HARDIRQS + select REGMAP_I2C + select REGMAP_IRQ help - This option enables a driver for the TP61050/TPS61052 - high-power "white LED driver". This boost converter is - sometimes used for other things than white LEDs, and - also contains a GPIO pin. + Say yes here to support for Maxim Semiconductor MAX8907. This is + a Power Management IC. This driver provides common support for + accessing the device; additional drivers must be enabled in order + to use the functionality of the device. -config TPS65010 - tristate "TI TPS6501x Power Management chips" - depends on I2C && GPIOLIB - default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK +config MFD_MAX8925 + bool "Maxim Semiconductor MAX8925 PMIC Support" + depends on I2C=y && GENERIC_HARDIRQS + select MFD_CORE help - If you say yes here you get support for the TPS6501x series of - Power Management chips. These include voltage regulators, - lithium ion/polymer battery charging, and other features that - are often used in portable devices like cell phones and cameras. - - This driver can also be built as a module. If so, the module - will be called tps65010. + Say yes here to support for Maxim Semiconductor MAX8925. This is + a Power Management IC. This driver provides common support for + accessing the device, additional drivers must be enabled in order + to use the functionality of the device. -config TPS6507X - tristate "TI TPS6507x Power Management / Touch Screen chips" +config MFD_MAX8997 + bool "Maxim Semiconductor MAX8997/8966 PMIC Support" + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE - depends on I2C && GENERIC_HARDIRQS + select IRQ_DOMAIN help - If you say yes here you get support for the TPS6507x series of - Power Management / Touch Screen chips. These include voltage - regulators, lithium ion/polymer battery charging, touch screen - and other features that are often used in portable devices. - This driver can also be built as a module. If so, the module - will be called tps6507x. - -config TPS65911_COMPARATOR - tristate + Say yes here to support for Maxim Semiconductor MAX8997/8966. + This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, + MUIC controls on chip. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. -config MFD_TPS65090 - bool "TI TPS65090 Power Management chips" +config MFD_MAX8998 + bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ help - If you say yes here you get support for the TPS65090 series of - Power Management chips. + Say yes here to support for Maxim Semiconductor MAX8998 and + National Semiconductor LP3974. This is a Power Management IC. This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. + additional drivers must be enabled in order to use the functionality + of the device. -config MFD_TPS65217 - tristate "TI TPS65217 Power Management / White LED chips" - depends on I2C && GENERIC_HARDIRQS +config MFD_SEC_CORE + bool "SAMSUNG Electronics PMIC Series Support" + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C + select REGMAP_IRQ help - If you say yes here you get support for the TPS65217 series of - Power Management / White LED chips. - These include voltage regulators, lithium ion/polymer battery - charger, wled and other features that are often used in portable - devices. + Support for the Samsung Electronics MFD series. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the functionality + of the device - This driver can also be built as a module. If so, the module - will be called tps65217. +config MFD_ARIZONA + select REGMAP + select REGMAP_IRQ + select MFD_CORE + bool -config MFD_TPS6586X - bool "TI TPS6586x Power Management chips" - depends on I2C=y && GENERIC_HARDIRQS +config MFD_ARIZONA_I2C + tristate "Support Wolfson Microelectronics Arizona platform with I2C" + select MFD_ARIZONA select MFD_CORE select REGMAP_I2C + depends on I2C && GENERIC_HARDIRQS help - If you say yes here you get support for the TPS6586X series of - Power Management chips. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. + Support for the Wolfson Microelectronics Arizona platform audio SoC + core functionality controlled via I2C. - This driver can also be built as a module. If so, the module - will be called tps6586x. +config MFD_ARIZONA_SPI + tristate "Support Wolfson Microelectronics Arizona platform with SPI" + select MFD_ARIZONA + select MFD_CORE + select REGMAP_SPI + depends on SPI_MASTER && GENERIC_HARDIRQS + help + Support for the Wolfson Microelectronics Arizona platform audio SoC + core functionality controlled via I2C. -config MFD_TPS65910 - bool "TI TPS65910 Power Management chip" - depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS +config MFD_WM5102 + bool "Support Wolfson Microelectronics WM5102" + depends on MFD_ARIZONA + help + Support for Wolfson Microelectronics WM5102 low power audio SoC + +config MFD_WM5110 + bool "Support Wolfson Microelectronics WM5110" + depends on MFD_ARIZONA + help + Support for Wolfson Microelectronics WM5110 low power audio SoC + +config MFD_WM8400 + bool "Support Wolfson Microelectronics WM8400" select MFD_CORE + depends on I2C=y && GENERIC_HARDIRQS select REGMAP_I2C - select REGMAP_IRQ - select IRQ_DOMAIN help - if you say yes here you get support for the TPS65910 series of - Power Management chips. + Support for the Wolfson Microelecronics WM8400 PMIC and audio + CODEC. This driver provides common support for accessing + the device, additional drivers must be enabled in order to use + the functionality of the device. -config MFD_TPS65912 - bool "TI TPS65912 Power Management chip" - depends on GPIOLIB - help - If you say yes here you get support for the TPS65912 series of - PM chips. +config MFD_WM831X + bool + depends on GENERIC_HARDIRQS -config MFD_TPS65912_I2C - bool "TI TPS65912 Power Management chip with I2C" +config MFD_WM831X_I2C + bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" select MFD_CORE - select MFD_TPS65912 - depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS + select MFD_WM831X + select REGMAP_I2C + select IRQ_DOMAIN + depends on I2C=y && GENERIC_HARDIRQS help - If you say yes here you get support for the TPS65912 series of - PM chips with I2C interface. + Support for the Wolfson Microelecronics WM831x and WM832x PMICs + when controlled using I2C. This driver provides common support + for accessing the device, additional drivers must be enabled in + order to use the functionality of the device. -config MFD_TPS65912_SPI - bool "TI TPS65912 Power Management chip with SPI" +config MFD_WM831X_SPI + bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" select MFD_CORE - select MFD_TPS65912 - depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS + select MFD_WM831X + select REGMAP_SPI + select IRQ_DOMAIN + depends on SPI_MASTER && GENERIC_HARDIRQS help - If you say yes here you get support for the TPS65912 series of - PM chips with SPI interface. + Support for the Wolfson Microelecronics WM831x and WM832x PMICs + when controlled using SPI. This driver provides common support + for accessing the device, additional drivers must be enabled in + order to use the functionality of the device. -config MFD_TPS80031 - bool "TI TPS80031/TPS80032 Power Management chips" +config MFD_WM8350 + bool + depends on GENERIC_HARDIRQS + +config MFD_WM8350_CONFIG_MODE_0 + bool + depends on MFD_WM8350 + +config MFD_WM8350_CONFIG_MODE_1 + bool + depends on MFD_WM8350 + +config MFD_WM8350_CONFIG_MODE_2 + bool + depends on MFD_WM8350 + +config MFD_WM8350_CONFIG_MODE_3 + bool + depends on MFD_WM8350 + +config MFD_WM8351_CONFIG_MODE_0 + bool + depends on MFD_WM8350 + +config MFD_WM8351_CONFIG_MODE_1 + bool + depends on MFD_WM8350 + +config MFD_WM8351_CONFIG_MODE_2 + bool + depends on MFD_WM8350 + +config MFD_WM8351_CONFIG_MODE_3 + bool + depends on MFD_WM8350 + +config MFD_WM8352_CONFIG_MODE_0 + bool + depends on MFD_WM8350 + +config MFD_WM8352_CONFIG_MODE_1 + bool + depends on MFD_WM8350 + +config MFD_WM8352_CONFIG_MODE_2 + bool + depends on MFD_WM8350 + +config MFD_WM8352_CONFIG_MODE_3 + bool + depends on MFD_WM8350 + +config MFD_WM8350_I2C + bool "Support Wolfson Microelectronics WM8350 with I2C" + select MFD_WM8350 depends on I2C=y && GENERIC_HARDIRQS + help + The WM8350 is an integrated audio and power management + subsystem with watchdog and RTC functionality for embedded + systems. This option enables core support for the WM8350 with + I2C as the control interface. Additional options must be + selected to enable support for the functionality of the chip. + +config MFD_WM8994 + bool "Support Wolfson Microelectronics WM8994" select MFD_CORE select REGMAP_I2C select REGMAP_IRQ + depends on I2C=y && GENERIC_HARDIRQS help - If you say yes here you get support for the Texas Instruments - TPS80031/ TPS80032 Fully Integrated Power Management with Power - Path and Battery Charger. The device provides five configurable - step-down converters, 11 general purpose LDOs, USB OTG Module, - ADC, RTC, 2 PWM, System Voltage Regulator/Battery Charger with - Power Path from USB, 32K clock generator. + The WM8994 is a highly integrated hi-fi CODEC designed for + smartphone applicatiosn. As well as audio functionality it + has on board GPIO and regulator functionality which is + supported via the relevant subsystems. This driver provides + core support for the WM8994, in order to use the actual + functionaltiy of the device other drivers must be enabled. -config TWL4030_CORE - bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support" - depends on I2C=y && GENERIC_HARDIRQS - select IRQ_DOMAIN +config MFD_PCF50633 + tristate "Support for NXP PCF50633" + depends on I2C select REGMAP_I2C help - Say yes here if you have TWL4030 / TWL6030 family chip on your board. + Say yes here if you have NXP PCF50633 chip on your board. This core driver provides register access and IRQ handling facilities, and registers devices for the various functions so that function-specific drivers can bind to them. - These multi-function chips are found on many OMAP2 and OMAP3 - boards, providing power management, RTC, GPIO, keypad, a - high speed USB OTG transceiver, an audio codec (on most - versions) and many other features. - -config TWL4030_MADC - tristate "TI TWL4030 MADC" - depends on TWL4030_CORE +config PCF50633_ADC + tristate "Support for NXP PCF50633 ADC" + depends on MFD_PCF50633 help - This driver provides support for triton TWL4030-MADC. The - driver supports both RT and SW conversion methods. - - This driver can be built as a module. If so it will be - named twl4030-madc + Say yes here if you want to include support for ADC in the + NXP PCF50633 chip. -config TWL4030_POWER - bool "TI TWL4030 power resources" - depends on TWL4030_CORE && ARM +config PCF50633_GPIO + tristate "Support for NXP PCF50633 GPIO" + depends on MFD_PCF50633 help - Say yes here if you want to use the power resources on the - TWL4030 family chips. Most of these resources are regulators, - which have a separate driver; some are control signals, such - as clock request handshaking. - - This driver uses board-specific data to initialize the resources - and load scripts controlling which resources are switched off/on - or reset when a sleep, wakeup or warm reset event occurs. + Say yes here if you want to include support GPIO for pins on + the PCF50633 chip. -config MFD_TWL4030_AUDIO - bool "TI TWL4030 Audio" - depends on TWL4030_CORE && GENERIC_HARDIRQS - select MFD_CORE - default n +config MFD_MC13783 + tristate -config TWL6040_CORE - bool "TI TWL6040 audio codec" - depends on I2C=y && GENERIC_HARDIRQS +config MFD_MC13XXX + tristate + depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - default n + select MFD_MC13783 help - Say yes here if you want support for Texas Instruments TWL6040 audio - codec. + Enable support for the Freescale MC13783 and MC13892 PMICs. This driver provides common support for accessing the device, additional drivers must be enabled in order to use the - functionality of the device (audio, vibra). + functionality of the device. -config MENELAUS - bool "TI TWL92330/Menelaus PM chip" - depends on I2C=y && ARCH_OMAP2 +config MFD_MC13XXX_SPI + tristate "Freescale MC13783 and MC13892 SPI interface" + depends on SPI_MASTER && GENERIC_HARDIRQS + select REGMAP_SPI + select MFD_MC13XXX help - If you say yes here you get support for the Texas Instruments - TWL92330/Menelaus Power Management chip. This include voltage - regulators, Dual slot memory card transceivers, real-time clock - and other features that are often used in portable devices like - cell phones and PDAs. + Select this if your MC13xxx is connected via an SPI bus. -config MFD_WL1273_CORE - tristate "TI WL1273 FM radio" +config MFD_MC13XXX_I2C + tristate "Freescale MC13892 I2C interface" depends on I2C && GENERIC_HARDIRQS + select REGMAP_I2C + select MFD_MC13XXX + help + Select this if your MC13xxx is connected via an I2C bus. + +config ABX500_CORE + bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" + default y if ARCH_U300 || ARCH_U8500 + help + Say yes here if you have the ABX500 Mixed Signal IC family + chips. This core driver expose register access functions. + Functionality specific drivers using these functions can + remain unchanged when IC changes. Binding of the functions to + actual register access is done by the IC core driver. + +config AB3100_CORE + bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" + depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS select MFD_CORE - default n + default y if ARCH_U300 + help + Select this to enable the AB3100 Mixed Signal IC core + functionality. This connects to a AB3100 on the I2C bus + and expose a number of symbols needed for dependent devices + to read and write registers and subscribe to events from + this multi-functional IC. This is needed to use other features + of the AB3100 such as battery-backed RTC, charging control, + LEDs, vibrator, system power and temperature, power management + and ALSA sound. + +config AB3100_OTP + tristate "ST-Ericsson AB3100 OTP functions" + depends on AB3100_CORE + default y if AB3100_CORE + help + Select this to enable the AB3100 Mixed Signal IC OTP (one-time + programmable memory) support. This exposes a sysfs file to read + out OTP values. + +config EZX_PCAP + bool "PCAP Support" + depends on GENERIC_HARDIRQS && SPI_MASTER + help + This enables the PCAP ASIC present on EZX Phones. This is + needed for MMC, TouchScreen, Sound, USB, etc.. + +config AB8500_CORE + bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" + depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU + select POWER_SUPPLY + select MFD_CORE + select IRQ_DOMAIN + help + Select this option to enable access to AB8500 power management + chip. This connects to U8500 either on the SSP/SPI bus (deprecated + since hardware version v1.0) or the I2C bus via PRCMU. It also adds + the irq_chip parts for handling the Mixed Signal chip events. + This chip embeds various other multimedia funtionalities as well. + +config AB8500_DEBUG + bool "Enable debug info via debugfs" + depends on AB8500_CORE && DEBUG_FS + default y if DEBUG_FS + help + Select this option if you want debug information using the debug + filesystem, debugfs. + +config AB8500_GPADC + bool "AB8500 GPADC driver" + depends on AB8500_CORE && REGULATOR_AB8500 + default y help - This is the core driver for the TI WL1273 FM radio. This MFD - driver connects the radio-wl1273 V4L2 module and the wl1273 - audio codec. + AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage -config MFD_LM3533 - tristate "TI/National Semiconductor LM3533 Lighting Power chip" - depends on I2C +config MFD_DB8500_PRCMU + bool "ST-Ericsson DB8500 Power Reset Control Management Unit" + depends on UX500_SOC_DB8500 select MFD_CORE - select REGMAP_I2C - depends on GENERIC_HARDIRQS help - Say yes here to enable support for National Semiconductor / TI - LM3533 Lighting Power chips. + Select this option to enable support for the DB8500 Power Reset + and Control Management Unit. This is basically an autonomous + system controller running an XP70 microprocessor, which is accessed + through a register map. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the LED, - backlight or ambient-light-sensor functionality of the device. +config MFD_CS5535 + tristate "Support for CS5535 and CS5536 southbridge core functions" + select MFD_CORE + depends on PCI && X86 + ---help--- + This is the core driver for CS5535/CS5536 MFD functions. This is + necessary for using the board's GPIO and MFGPT functionality. config MFD_TIMBERDALE - tristate "Timberdale FPGA" + tristate "Support for the Timberdale FPGA" select MFD_CORE depends on PCI && GPIOLIB ---help--- @@ -958,48 +912,54 @@ config MFD_TIMBERDALE The timberdale FPGA can be found on the Intel Atom development board for in-vehicle infontainment, called Russellville. -config MFD_TC3589X - bool "Toshiba TC35892 and variants" - depends on I2C=y && GENERIC_HARDIRQS +config LPC_SCH + tristate "Intel SCH LPC" + depends on PCI && GENERIC_HARDIRQS select MFD_CORE help - Support for the Toshiba TC35892 and variants I/O Expander. - - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. + LPC bridge function of the Intel SCH provides support for + System Management Bus and General Purpose I/O. -config MFD_TMIO - bool - default n +config LPC_ICH + tristate "Intel ICH LPC" + depends on PCI && GENERIC_HARDIRQS + select MFD_CORE + help + The LPC bridge function of the Intel ICH provides support for + many functional units. This driver provides needed support for + other drivers to control these functions, currently GPIO and + watchdog. -config MFD_T7L66XB - bool "Toshiba T7L66XB" - depends on ARM && HAVE_CLK && GENERIC_HARDIRQS +config MFD_RDC321X + tristate "Support for RDC-R321x southbridge" select MFD_CORE - select MFD_TMIO + depends on PCI && GENERIC_HARDIRQS help - Support for Toshiba Mobile IO Controller T7L66XB + Say yes here if you want to have support for the RDC R-321x SoC + southbridge which provides access to GPIOs and Watchdog using the + southbridge PCI device configuration space. -config MFD_TC6387XB - bool "Toshiba TC6387XB" - depends on ARM && HAVE_CLK +config MFD_JANZ_CMODIO + tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board" select MFD_CORE - select MFD_TMIO + depends on PCI && GENERIC_HARDIRQS help - Support for Toshiba Mobile IO Controller TC6387XB + This is the core driver for the Janz CMOD-IO PCI MODULbus + carrier board. This device is a PCI to MODULbus bridge which may + host many different types of MODULbus daughterboards, including + CAN and GPIO controllers. -config MFD_TC6393XB - bool "Toshiba TC6393XB" - depends on ARM && HAVE_CLK - select GPIOLIB +config MFD_JZ4740_ADC + bool "Support for the JZ4740 SoC ADC core" select MFD_CORE - select MFD_TMIO + select GENERIC_IRQ_CHIP + depends on MACH_JZ4740 help - Support for Toshiba Mobile IO Controller TC6393XB + Say yes here if you want support for the ADC unit in the JZ4740 SoC. + This driver is necessary for jz4740-battery and jz4740-hwmon driver. config MFD_VX855 - tristate "VIA VX855/VX875 integrated south bridge" + tristate "Support for VIA VX855/VX875 integrated south bridge" depends on PCI && GENERIC_HARDIRQS select MFD_CORE help @@ -1007,113 +967,157 @@ config MFD_VX855 VIA VX855/VX875 south bridge. You will need to enable the vx855_spi and/or vx855_gpio drivers for this to do anything useful. -config MFD_ARIZONA - select REGMAP - select REGMAP_IRQ +config MFD_WL1273_CORE + tristate "Support for TI WL1273 FM radio." + depends on I2C && GENERIC_HARDIRQS select MFD_CORE - bool + default n + help + This is the core driver for the TI WL1273 FM radio. This MFD + driver connects the radio-wl1273 V4L2 module and the wl1273 + audio codec. -config MFD_ARIZONA_I2C - tristate "Wolfson Microelectronics Arizona platform with I2C" - select MFD_ARIZONA - select MFD_CORE - select REGMAP_I2C - depends on I2C && GENERIC_HARDIRQS +config MFD_OMAP_USB_HOST + bool "Support OMAP USBHS core and TLL driver" + depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 + default y help - Support for the Wolfson Microelectronics Arizona platform audio SoC - core functionality controlled via I2C. + This is the core driver for the OAMP EHCI and OHCI drivers. + This MFD driver does the required setup functionalities for + OMAP USB Host drivers. -config MFD_ARIZONA_SPI - tristate "Wolfson Microelectronics Arizona platform with SPI" - select MFD_ARIZONA +config MFD_PM8XXX + tristate + +config MFD_PM8921_CORE + tristate "Qualcomm PM8921 PMIC chip" + depends on SSBI && BROKEN select MFD_CORE - select REGMAP_SPI - depends on SPI_MASTER && GENERIC_HARDIRQS + select MFD_PM8XXX help - Support for the Wolfson Microelectronics Arizona platform audio SoC - core functionality controlled via I2C. + If you say yes to this option, support will be included for the + built-in PM8921 PMIC chip. -config MFD_WM5102 - bool "Wolfson Microelectronics WM5102" - depends on MFD_ARIZONA + This is required if your board has a PM8921 and uses its features, + such as: MPPs, GPIOs, regulators, interrupts, and PWM. + + Say M here if you want to include support for PM8921 chip as a module. + This will build a module called "pm8921-core". + +config MFD_PM8XXX_IRQ + bool "Support for Qualcomm PM8xxx IRQ features" + depends on MFD_PM8XXX + default y if MFD_PM8XXX help - Support for Wolfson Microelectronics WM5102 low power audio SoC + This is the IRQ driver for Qualcomm PM 8xxx PMIC chips. -config MFD_WM5110 - bool "Wolfson Microelectronics WM5110" - depends on MFD_ARIZONA + This is required to use certain other PM 8xxx features, such as GPIO + and MPP. + +config TPS65911_COMPARATOR + tristate + +config MFD_TPS65090 + bool "TPS65090 Power Management chips" + depends on I2C=y && GENERIC_HARDIRQS + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ help - Support for Wolfson Microelectronics WM5110 low power audio SoC + If you say yes here you get support for the TPS65090 series of + Power Management chips. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. -config MFD_WM8400 - bool "Wolfson Microelectronics WM8400" +config MFD_AAT2870_CORE + bool "Support for the AnalogicTech AAT2870" + select MFD_CORE + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS + help + If you say yes here you get support for the AAT2870. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. + +config MFD_INTEL_MSIC + bool "Support for Intel MSIC" + depends on INTEL_SCU_IPC select MFD_CORE + help + Select this option to enable access to Intel MSIC (Avatele + Passage) chip. This chip embeds audio, battery, GPIO, etc. + devices used in Intel Medfield platforms. + +config MFD_RC5T583 + bool "Ricoh RC5T583 Power Management system device" depends on I2C=y && GENERIC_HARDIRQS + select MFD_CORE select REGMAP_I2C help - Support for the Wolfson Microelecronics WM8400 PMIC and audio - CODEC. This driver provides common support for accessing - the device, additional drivers must be enabled in order to use - the functionality of the device. + Select this option to get support for the RICOH583 Power + Management system device. + This driver provides common support for accessing the device + through i2c interface. The device supports multiple sub-devices + like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. + Additional drivers must be enabled in order to use the + different functionality of the device. -config MFD_WM831X - bool - depends on GENERIC_HARDIRQS +config MFD_STA2X11 + bool "STA2X11 multi function device support" + depends on STA2X11 && GENERIC_HARDIRQS + select MFD_CORE + select REGMAP_MMIO -config MFD_WM831X_I2C - bool "Wolfson Microelectronics WM831x/2x PMICs with I2C" +config MFD_SYSCON + bool "System Controller Register R/W Based on Regmap" + depends on OF + select REGMAP_MMIO + help + Select this option to enable accessing system control registers + via regmap. + +config MFD_PALMAS + bool "Support for the TI Palmas series chips" select MFD_CORE - select MFD_WM831X select REGMAP_I2C - select IRQ_DOMAIN + select REGMAP_IRQ depends on I2C=y && GENERIC_HARDIRQS help - Support for the Wolfson Microelecronics WM831x and WM832x PMICs - when controlled using I2C. This driver provides common support - for accessing the device, additional drivers must be enabled in - order to use the functionality of the device. + If you say yes here you get support for the Palmas + series of PMIC chips from Texas Instruments. -config MFD_WM831X_SPI - bool "Wolfson Microelectronics WM831x/2x PMICs with SPI" +config MFD_VIPERBOARD + tristate "Support for Nano River Technologies Viperboard" select MFD_CORE - select MFD_WM831X - select REGMAP_SPI - select IRQ_DOMAIN - depends on SPI_MASTER && GENERIC_HARDIRQS + depends on USB && GENERIC_HARDIRQS + default n help - Support for the Wolfson Microelecronics WM831x and WM832x PMICs - when controlled using SPI. This driver provides common support - for accessing the device, additional drivers must be enabled in - order to use the functionality of the device. - -config MFD_WM8350 - bool - depends on GENERIC_HARDIRQS + Say yes here if you want support for Nano River Technologies + Viperboard. + There are mfd cell drivers available for i2c master, adc and + both gpios found on the board. The spi part does not yet + have a driver. + You need to select the mfd cell drivers separately. + The drivers do not support all features the board exposes. -config MFD_WM8350_I2C - bool "Wolfson Microelectronics WM8350 with I2C" - select MFD_WM8350 - depends on I2C=y && GENERIC_HARDIRQS +config MFD_RETU + tristate "Support for Retu multi-function device" + select MFD_CORE + depends on I2C && GENERIC_HARDIRQS + select REGMAP_IRQ help - The WM8350 is an integrated audio and power management - subsystem with watchdog and RTC functionality for embedded - systems. This option enables core support for the WM8350 with - I2C as the control interface. Additional options must be - selected to enable support for the functionality of the chip. + Retu is a multi-function device found on Nokia Internet Tablets + (770, N800 and N810). -config MFD_WM8994 - bool "Wolfson Microelectronics WM8994" +config MFD_AS3711 + bool "Support for AS3711" select MFD_CORE select REGMAP_I2C select REGMAP_IRQ depends on I2C=y && GENERIC_HARDIRQS help - The WM8994 is a highly integrated hi-fi CODEC designed for - smartphone applicatiosn. As well as audio functionality it - has on board GPIO and regulator functionality which is - supported via the relevant subsystems. This driver provides - core support for the WM8994, in order to use the actual - functionaltiy of the device other drivers must be enabled. + Support for the AS3711 PMIC from AMS endmenu endif diff --git a/trunk/drivers/mfd/Makefile b/trunk/drivers/mfd/Makefile index 718e94a2a9a7..b90409c23664 100644 --- a/trunk/drivers/mfd/Makefile +++ b/trunk/drivers/mfd/Makefile @@ -8,11 +8,8 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o -obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o -obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o -obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o -rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o +rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o @@ -134,10 +131,6 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o - -si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o -obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o - obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o diff --git a/trunk/drivers/mfd/aat2870-core.c b/trunk/drivers/mfd/aat2870-core.c index dfdb0a2b6835..f1beb4971f87 100644 --- a/trunk/drivers/mfd/aat2870-core.c +++ b/trunk/drivers/mfd/aat2870-core.c @@ -367,12 +367,12 @@ static int aat2870_i2c_probe(struct i2c_client *client, int i, j; int ret = 0; - aat2870 = devm_kzalloc(&client->dev, sizeof(struct aat2870_data), - GFP_KERNEL); + aat2870 = kzalloc(sizeof(struct aat2870_data), GFP_KERNEL); if (!aat2870) { dev_err(&client->dev, "Failed to allocate memory for aat2870\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out; } aat2870->dev = &client->dev; @@ -400,12 +400,12 @@ static int aat2870_i2c_probe(struct i2c_client *client, aat2870->init(aat2870); if (aat2870->en_pin >= 0) { - ret = devm_gpio_request_one(&client->dev, aat2870->en_pin, - GPIOF_OUT_INIT_HIGH, "aat2870-en"); + ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH, + "aat2870-en"); if (ret < 0) { dev_err(&client->dev, "Failed to request GPIO %d\n", aat2870->en_pin); - return ret; + goto out_kfree; } } @@ -436,6 +436,11 @@ static int aat2870_i2c_probe(struct i2c_client *client, out_disable: aat2870_disable(aat2870); + if (aat2870->en_pin >= 0) + gpio_free(aat2870->en_pin); +out_kfree: + kfree(aat2870); +out: return ret; } @@ -447,8 +452,11 @@ static int aat2870_i2c_remove(struct i2c_client *client) mfd_remove_devices(aat2870->dev); aat2870_disable(aat2870); + if (aat2870->en_pin >= 0) + gpio_free(aat2870->en_pin); if (aat2870->uninit) aat2870->uninit(aat2870); + kfree(aat2870); return 0; } diff --git a/trunk/drivers/mfd/ab3100-otp.c b/trunk/drivers/mfd/ab3100-otp.c index d7ce016029fa..8440010eb2b8 100644 --- a/trunk/drivers/mfd/ab3100-otp.c +++ b/trunk/drivers/mfd/ab3100-otp.c @@ -248,7 +248,19 @@ static struct platform_driver ab3100_otp_driver = { .remove = __exit_p(ab3100_otp_remove), }; -module_platform_driver_probe(ab3100_otp_driver, ab3100_otp_probe); +static int __init ab3100_otp_init(void) +{ + return platform_driver_probe(&ab3100_otp_driver, + ab3100_otp_probe); +} + +static void __exit ab3100_otp_exit(void) +{ + platform_driver_unregister(&ab3100_otp_driver); +} + +module_init(ab3100_otp_init); +module_exit(ab3100_otp_exit); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("AB3100 OTP Readout Driver"); diff --git a/trunk/drivers/mfd/ab8500-core.c b/trunk/drivers/mfd/ab8500-core.c index 8e8a016effe9..f276352cc9ef 100644 --- a/trunk/drivers/mfd/ab8500-core.c +++ b/trunk/drivers/mfd/ab8500-core.c @@ -458,23 +458,22 @@ static void update_latch_offset(u8 *offset, int i) static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, int latch_offset, u8 latch_val) { - int int_bit, line, i; + int int_bit = __ffs(latch_val); + int line, i; - for (i = 0; i < ab8500->mask_size; i++) - if (ab8500->irq_reg_offset[i] == latch_offset) - break; + do { + int_bit = __ffs(latch_val); - if (i >= ab8500->mask_size) { - dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", - latch_offset); - return -ENXIO; - } + for (i = 0; i < ab8500->mask_size; i++) + if (ab8500->irq_reg_offset[i] == latch_offset) + break; - /* ignore masked out interrupts */ - latch_val &= ~ab8500->mask[i]; + if (i >= ab8500->mask_size) { + dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", + latch_offset); + return -ENXIO; + } - while (latch_val) { - int_bit = __ffs(latch_val); line = (i << 3) + int_bit; latch_val &= ~(1 << int_bit); @@ -492,7 +491,7 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, line += 1; handle_nested_irq(ab8500->irq_base + line); - } + } while (latch_val); return 0; } @@ -1108,7 +1107,6 @@ static struct mfd_cell ab8500_devs[] = { }, { .name = "ab8500-usb", - .of_compatible = "stericsson,ab8500-usb", .num_resources = ARRAY_SIZE(ab8500_usb_resources), .resources = ab8500_usb_resources, }, diff --git a/trunk/drivers/mfd/ab8500-gpadc.c b/trunk/drivers/mfd/ab8500-gpadc.c index 5e65b28a5d09..65f72284185d 100644 --- a/trunk/drivers/mfd/ab8500-gpadc.c +++ b/trunk/drivers/mfd/ab8500-gpadc.c @@ -332,7 +332,7 @@ if (ad_value < 0) { return voltage; } -EXPORT_SYMBOL(ab8500_gpadc_sw_hw_convert); +EXPORT_SYMBOL(ab8500_gpadc_convert); /** * ab8500_gpadc_read_raw() - gpadc read diff --git a/trunk/drivers/mfd/ab8500-sysctrl.c b/trunk/drivers/mfd/ab8500-sysctrl.c index fbca1ced49fa..272479cdb107 100644 --- a/trunk/drivers/mfd/ab8500-sysctrl.c +++ b/trunk/drivers/mfd/ab8500-sysctrl.c @@ -242,7 +242,7 @@ static int __init ab8500_sysctrl_init(void) { return platform_driver_register(&ab8500_sysctrl_driver); } -arch_initcall(ab8500_sysctrl_init); +subsys_initcall(ab8500_sysctrl_init); MODULE_AUTHOR("Mattias Nilsson dev); - adp5520_read(chip->dev, ADP5520_MODE_STATUS, &chip->mode); - /* All other bits are W1C */ - chip->mode &= ADP5520_BL_EN | ADP5520_DIM_EN | ADP5520_nSTNBY; - adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); + adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); return 0; } @@ -339,7 +335,7 @@ static int adp5520_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct adp5520_chip *chip = dev_get_drvdata(&client->dev); - adp5520_write(chip->dev, ADP5520_MODE_STATUS, chip->mode); + adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); return 0; } #endif @@ -364,7 +360,17 @@ static struct i2c_driver adp5520_driver = { .id_table = adp5520_id, }; -module_i2c_driver(adp5520_driver); +static int __init adp5520_init(void) +{ + return i2c_add_driver(&adp5520_driver); +} +module_init(adp5520_init); + +static void __exit adp5520_exit(void) +{ + i2c_del_driver(&adp5520_driver); +} +module_exit(adp5520_exit); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); diff --git a/trunk/drivers/mfd/arizona-core.c b/trunk/drivers/mfd/arizona-core.c index 6ab03043fd60..b562c7bf8a46 100644 --- a/trunk/drivers/mfd/arizona-core.c +++ b/trunk/drivers/mfd/arizona-core.c @@ -39,21 +39,11 @@ int arizona_clk32k_enable(struct arizona *arizona) arizona->clk32k_ref++; - if (arizona->clk32k_ref == 1) { - switch (arizona->pdata.clk32k_src) { - case ARIZONA_32KZ_MCLK1: - ret = pm_runtime_get_sync(arizona->dev); - if (ret != 0) - goto out; - break; - } - + if (arizona->clk32k_ref == 1) ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, ARIZONA_CLK_32K_ENA, ARIZONA_CLK_32K_ENA); - } -out: if (ret != 0) arizona->clk32k_ref--; @@ -73,17 +63,10 @@ int arizona_clk32k_disable(struct arizona *arizona) arizona->clk32k_ref--; - if (arizona->clk32k_ref == 0) { + if (arizona->clk32k_ref == 0) regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, ARIZONA_CLK_32K_ENA, 0); - switch (arizona->pdata.clk32k_src) { - case ARIZONA_32KZ_MCLK1: - pm_runtime_put_sync(arizona->dev); - break; - } - } - mutex_unlock(&arizona->clk_lock); return ret; @@ -196,134 +179,42 @@ static irqreturn_t arizona_overclocked(int irq, void *data) return IRQ_HANDLED; } -static int arizona_poll_reg(struct arizona *arizona, - int timeout, unsigned int reg, - unsigned int mask, unsigned int target) -{ - unsigned int val = 0; - int ret, i; - - for (i = 0; i < timeout; i++) { - ret = regmap_read(arizona->regmap, reg, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read reg %u: %d\n", - reg, ret); - continue; - } - - if ((val & mask) == target) - return 0; - - msleep(1); - } - - dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); - return -ETIMEDOUT; -} - static int arizona_wait_for_boot(struct arizona *arizona) { - int ret; + unsigned int reg; + int ret, i; /* * We can't use an interrupt as we need to runtime resume to do so, * we won't race with the interrupt handler as it'll be blocked on * runtime resume. */ - ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, - ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); - - if (!ret) - regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, - ARIZONA_BOOT_DONE_STS); - - pm_runtime_mark_last_busy(arizona->dev); - - return ret; -} - -static int arizona_apply_hardware_patch(struct arizona* arizona) -{ - unsigned int fll, sysclk; - int ret, err; - - regcache_cache_bypass(arizona->regmap, true); - - /* Cache existing FLL and SYSCLK settings */ - ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); - if (ret != 0) { - dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", - ret); - return ret; - } - ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); - if (ret != 0) { - dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", - ret); - return ret; - } - - /* Start up SYSCLK using the FLL in free running mode */ - ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, - ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to start FLL in freerunning mode: %d\n", - ret); - return ret; - } - ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, - ARIZONA_FLL1_CLOCK_OK_STS, - ARIZONA_FLL1_CLOCK_OK_STS); - if (ret != 0) { - ret = -ETIMEDOUT; - goto err_fll; - } - - ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); - if (ret != 0) { - dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); - goto err_fll; - } + for (i = 0; i < 5; i++) { + msleep(1); - /* Start the write sequencer and wait for it to finish */ - ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, - ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); - if (ret != 0) { - dev_err(arizona->dev, "Failed to start write sequencer: %d\n", - ret); - goto err_sysclk; - } - ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, - ARIZONA_WSEQ_BUSY, 0); - if (ret != 0) { - regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, - ARIZONA_WSEQ_ABORT); - ret = -ETIMEDOUT; - } + ret = regmap_read(arizona->regmap, + ARIZONA_INTERRUPT_RAW_STATUS_5, ®); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read boot state: %d\n", + ret); + continue; + } -err_sysclk: - err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); - if (err != 0) { - dev_err(arizona->dev, - "Failed to re-apply old SYSCLK settings: %d\n", - err); + if (reg & ARIZONA_BOOT_DONE_STS) + break; } -err_fll: - err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); - if (err != 0) { - dev_err(arizona->dev, - "Failed to re-apply old FLL settings: %d\n", - err); + if (reg & ARIZONA_BOOT_DONE_STS) { + regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, + ARIZONA_BOOT_DONE_STS); + } else { + dev_err(arizona->dev, "Device boot timed out: %x\n", reg); + return -ETIMEDOUT; } - regcache_cache_bypass(arizona->regmap, false); + pm_runtime_mark_last_busy(arizona->dev); - if (ret != 0) - return ret; - else - return err; + return 0; } #ifdef CONFIG_PM_RUNTIME @@ -342,44 +233,20 @@ static int arizona_runtime_resume(struct device *dev) regcache_cache_only(arizona->regmap, false); - switch (arizona->type) { - case WM5102: - ret = wm5102_patch(arizona); - if (ret != 0) { - dev_err(arizona->dev, "Failed to apply patch: %d\n", - ret); - goto err; - } - - ret = arizona_apply_hardware_patch(arizona); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to apply hardware patch: %d\n", - ret); - goto err; - } - break; - default: - ret = arizona_wait_for_boot(arizona); - if (ret != 0) { - goto err; - } - - break; + ret = arizona_wait_for_boot(arizona); + if (ret != 0) { + regulator_disable(arizona->dcvdd); + return ret; } ret = regcache_sync(arizona->regmap); if (ret != 0) { dev_err(arizona->dev, "Failed to restore register cache\n"); - goto err; + regulator_disable(arizona->dcvdd); + return ret; } return 0; - -err: - regcache_cache_only(arizona->regmap, true); - regulator_disable(arizona->dcvdd); - return ret; } static int arizona_runtime_suspend(struct device *dev) @@ -504,17 +371,6 @@ int arizona_dev_init(struct arizona *arizona) goto err_early; } - if (arizona->pdata.reset) { - /* Start out with /RESET low to put the chip into reset */ - ret = gpio_request_one(arizona->pdata.reset, - GPIOF_DIR_OUT | GPIOF_INIT_LOW, - "arizona /RESET"); - if (ret != 0) { - dev_err(dev, "Failed to request /RESET: %d\n", ret); - goto err_early; - } - } - ret = regulator_bulk_enable(arizona->num_core_supplies, arizona->core_supplies); if (ret != 0) { @@ -530,8 +386,16 @@ int arizona_dev_init(struct arizona *arizona) } if (arizona->pdata.reset) { + /* Start out with /RESET low to put the chip into reset */ + ret = gpio_request_one(arizona->pdata.reset, + GPIOF_DIR_OUT | GPIOF_INIT_LOW, + "arizona /RESET"); + if (ret != 0) { + dev_err(dev, "Failed to request /RESET: %d\n", ret); + goto err_dcvdd; + } + gpio_set_value_cansleep(arizona->pdata.reset, 1); - msleep(1); } regcache_cache_only(arizona->regmap, false); @@ -560,7 +424,6 @@ int arizona_dev_init(struct arizona *arizona) arizona->type = WM5102; } apply_patch = wm5102_patch; - arizona->rev &= 0x7; break; #endif #ifdef CONFIG_MFD_WM5110 @@ -591,8 +454,6 @@ int arizona_dev_init(struct arizona *arizona) goto err_reset; } - msleep(1); - ret = regcache_sync(arizona->regmap); if (ret != 0) { dev_err(dev, "Failed to sync device: %d\n", ret); @@ -600,24 +461,10 @@ int arizona_dev_init(struct arizona *arizona) } } - switch (arizona->type) { - case WM5102: - ret = regmap_read(arizona->regmap, 0x19, &val); - if (ret != 0) - dev_err(dev, - "Failed to check write sequencer state: %d\n", - ret); - else if (val & 0x01) - break; - /* Fall through */ - default: - ret = arizona_wait_for_boot(arizona); - if (ret != 0) { - dev_err(arizona->dev, - "Device failed initial boot: %d\n", ret); - goto err_reset; - } - break; + ret = arizona_wait_for_boot(arizona); + if (ret != 0) { + dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); + goto err_reset; } if (apply_patch) { @@ -627,20 +474,6 @@ int arizona_dev_init(struct arizona *arizona) ret); goto err_reset; } - - switch (arizona->type) { - case WM5102: - ret = arizona_apply_hardware_patch(arizona); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to apply hardware patch: %d\n", - ret); - goto err_reset; - } - break; - default: - break; - } } for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { @@ -665,7 +498,6 @@ int arizona_dev_init(struct arizona *arizona) regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, ARIZONA_CLK_32K_SRC_MASK, arizona->pdata.clk32k_src - 1); - arizona_clk32k_enable(arizona); break; case ARIZONA_32KZ_NONE: regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, @@ -679,16 +511,10 @@ int arizona_dev_init(struct arizona *arizona) } for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { - if (!arizona->pdata.micbias[i].mV && - !arizona->pdata.micbias[i].bypass) - continue; - - /* Apply default for bypass mode */ if (!arizona->pdata.micbias[i].mV) - arizona->pdata.micbias[i].mV = 2800; + continue; val = (arizona->pdata.micbias[i].mV - 1500) / 100; - val <<= ARIZONA_MICB1_LVL_SHIFT; if (arizona->pdata.micbias[i].ext_cap) @@ -700,14 +526,10 @@ int arizona_dev_init(struct arizona *arizona) if (arizona->pdata.micbias[i].fast_start) val |= ARIZONA_MICB1_RATE; - if (arizona->pdata.micbias[i].bypass) - val |= ARIZONA_MICB1_BYPASS; - regmap_update_bits(arizona->regmap, ARIZONA_MIC_BIAS_CTRL_1 + i, ARIZONA_MICB1_LVL_MASK | ARIZONA_MICB1_DISCH | - ARIZONA_MICB1_BYPASS | ARIZONA_MICB1_RATE, val); } @@ -788,9 +610,10 @@ int arizona_dev_init(struct arizona *arizona) arizona_irq_exit(arizona); err_reset: if (arizona->pdata.reset) { - gpio_set_value_cansleep(arizona->pdata.reset, 0); + gpio_set_value_cansleep(arizona->pdata.reset, 1); gpio_free(arizona->pdata.reset); } +err_dcvdd: regulator_disable(arizona->dcvdd); err_enable: regulator_bulk_disable(arizona->num_core_supplies, diff --git a/trunk/drivers/mfd/arizona-irq.c b/trunk/drivers/mfd/arizona-irq.c index 64cd9b6dac92..2bec5f0db3ee 100644 --- a/trunk/drivers/mfd/arizona-irq.c +++ b/trunk/drivers/mfd/arizona-irq.c @@ -94,7 +94,6 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data) static irqreturn_t arizona_irq_thread(int irq, void *data) { struct arizona *arizona = data; - bool poll; unsigned int val; int ret; @@ -104,39 +103,20 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) return IRQ_NONE; } - do { - poll = false; - - /* Always handle the AoD domain */ - handle_nested_irq(irq_find_mapping(arizona->virq, 0)); - - /* - * Check if one of the main interrupts is asserted and only - * check that domain if it is. - */ - ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, - &val); - if (ret == 0 && val & ARIZONA_IRQ1_STS) { - handle_nested_irq(irq_find_mapping(arizona->virq, 1)); - } else if (ret != 0) { - dev_err(arizona->dev, - "Failed to read main IRQ status: %d\n", ret); - } + /* Always handle the AoD domain */ + handle_nested_irq(irq_find_mapping(arizona->virq, 0)); - /* - * Poll the IRQ pin status to see if we're really done - * if the interrupt controller can't do it for us. - */ - if (!arizona->pdata.irq_gpio) { - break; - } else if (arizona->pdata.irq_flags & IRQF_TRIGGER_RISING && - gpio_get_value_cansleep(arizona->pdata.irq_gpio)) { - poll = true; - } else if (arizona->pdata.irq_flags & IRQF_TRIGGER_FALLING && - !gpio_get_value_cansleep(arizona->pdata.irq_gpio)) { - poll = true; - } - } while (poll); + /* + * Check if one of the main interrupts is asserted and only + * check that domain if it is. + */ + ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val); + if (ret == 0 && val & ARIZONA_IRQ1_STS) { + handle_nested_irq(irq_find_mapping(arizona->virq, 1)); + } else if (ret != 0) { + dev_err(arizona->dev, "Failed to read main IRQ status: %d\n", + ret); + } pm_runtime_mark_last_busy(arizona->dev); pm_runtime_put_autosuspend(arizona->dev); @@ -189,7 +169,6 @@ int arizona_irq_init(struct arizona *arizona) int ret, i; const struct regmap_irq_chip *aod, *irq; bool ctrlif_error = true; - struct irq_data *irq_data; switch (arizona->type) { #ifdef CONFIG_MFD_WM5102 @@ -213,36 +192,7 @@ int arizona_irq_init(struct arizona *arizona) return -EINVAL; } - /* Disable all wake sources by default */ - regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0); - - /* Read the flags from the interrupt controller if not specified */ - if (!arizona->pdata.irq_flags) { - irq_data = irq_get_irq_data(arizona->irq); - if (!irq_data) { - dev_err(arizona->dev, "Invalid IRQ: %d\n", - arizona->irq); - return -EINVAL; - } - - arizona->pdata.irq_flags = irqd_get_trigger_type(irq_data); - switch (arizona->pdata.irq_flags) { - case IRQF_TRIGGER_LOW: - case IRQF_TRIGGER_HIGH: - case IRQF_TRIGGER_RISING: - case IRQF_TRIGGER_FALLING: - break; - - case IRQ_TYPE_NONE: - default: - /* Device default */ - arizona->pdata.irq_flags = IRQF_TRIGGER_LOW; - break; - } - } - - if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH | - IRQF_TRIGGER_RISING)) { + if (arizona->pdata.irq_active_high) { ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1, ARIZONA_IRQ_POL, 0); if (ret != 0) { @@ -250,9 +200,11 @@ int arizona_irq_init(struct arizona *arizona) ret); goto err; } - } - flags |= arizona->pdata.irq_flags; + flags |= IRQF_TRIGGER_HIGH; + } else { + flags |= IRQF_TRIGGER_LOW; + } /* Allocate a virtual IRQ domain to distribute to the regmap domains */ arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, @@ -305,31 +257,11 @@ int arizona_irq_init(struct arizona *arizona) } } - /* Used to emulate edge trigger and to work around broken pinmux */ - if (arizona->pdata.irq_gpio) { - if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) { - dev_warn(arizona->dev, "IRQ %d is not GPIO %d (%d)\n", - arizona->irq, arizona->pdata.irq_gpio, - gpio_to_irq(arizona->pdata.irq_gpio)); - arizona->irq = gpio_to_irq(arizona->pdata.irq_gpio); - } - - ret = devm_gpio_request_one(arizona->dev, - arizona->pdata.irq_gpio, - GPIOF_IN, "arizona IRQ"); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to request IRQ GPIO %d:: %d\n", - arizona->pdata.irq_gpio, ret); - arizona->pdata.irq_gpio = 0; - } - } - ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, flags, "arizona", arizona); if (ret != 0) { - dev_err(arizona->dev, "Failed to request primary IRQ %d: %d\n", + dev_err(arizona->dev, "Failed to request IRQ %d: %d\n", arizona->irq, ret); goto err_main_irq; } diff --git a/trunk/drivers/mfd/arizona-spi.c b/trunk/drivers/mfd/arizona-spi.c index b57e642d2b4a..1b9fdd698b03 100644 --- a/trunk/drivers/mfd/arizona-spi.c +++ b/trunk/drivers/mfd/arizona-spi.c @@ -67,7 +67,7 @@ static int arizona_spi_probe(struct spi_device *spi) static int arizona_spi_remove(struct spi_device *spi) { - struct arizona *arizona = spi_get_drvdata(spi); + struct arizona *arizona = dev_get_drvdata(&spi->dev); arizona_dev_exit(arizona); return 0; } diff --git a/trunk/drivers/mfd/as3711.c b/trunk/drivers/mfd/as3711.c index 01e414162702..e994c9691124 100644 --- a/trunk/drivers/mfd/as3711.c +++ b/trunk/drivers/mfd/as3711.c @@ -112,34 +112,16 @@ static const struct regmap_config as3711_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -#ifdef CONFIG_OF -static struct of_device_id as3711_of_match[] = { - {.compatible = "ams,as3711",}, - {} -}; -MODULE_DEVICE_TABLE(of, as3711_of_match); -#endif - static int as3711_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct as3711 *as3711; - struct as3711_platform_data *pdata; + struct as3711_platform_data *pdata = client->dev.platform_data; unsigned int id1, id2; int ret; - if (!client->dev.of_node) { - pdata = client->dev.platform_data; - if (!pdata) - dev_dbg(&client->dev, "Platform data not found\n"); - } else { - pdata = devm_kzalloc(&client->dev, - sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&client->dev, "Failed to allocate pdata\n"); - return -ENOMEM; - } - } + if (!pdata) + dev_dbg(&client->dev, "Platform data not found\n"); as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL); if (!as3711) { @@ -211,8 +193,7 @@ static struct i2c_driver as3711_i2c_driver = { .driver = { .name = "as3711", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(as3711_of_match), - }, + }, .probe = as3711_i2c_probe, .remove = as3711_i2c_remove, .id_table = as3711_i2c_id, diff --git a/trunk/drivers/mfd/cros_ec.c b/trunk/drivers/mfd/cros_ec.c deleted file mode 100644 index 10cd14e35eb0..000000000000 --- a/trunk/drivers/mfd/cros_ec.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * ChromeOS EC multi-function device - * - * Copyright (C) 2012 Google, Inc - * - * 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. - * - * The ChromeOS EC multi function device is used to mux all the requests - * to the EC device for its multiple features: keyboard controller, - * battery charging and regulator control, firmware update. - */ - -#include -#include -#include -#include -#include -#include - -int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, - struct cros_ec_msg *msg) -{ - uint8_t *out; - int csum, i; - - BUG_ON(msg->out_len > EC_HOST_PARAM_SIZE); - out = ec_dev->dout; - out[0] = EC_CMD_VERSION0 + msg->version; - out[1] = msg->cmd; - out[2] = msg->out_len; - csum = out[0] + out[1] + out[2]; - for (i = 0; i < msg->out_len; i++) - csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->out_buf[i]; - out[EC_MSG_TX_HEADER_BYTES + msg->out_len] = (uint8_t)(csum & 0xff); - - return EC_MSG_TX_PROTO_BYTES + msg->out_len; -} -EXPORT_SYMBOL(cros_ec_prepare_tx); - -static int cros_ec_command_sendrecv(struct cros_ec_device *ec_dev, - uint16_t cmd, void *out_buf, int out_len, - void *in_buf, int in_len) -{ - struct cros_ec_msg msg; - - msg.version = cmd >> 8; - msg.cmd = cmd & 0xff; - msg.out_buf = out_buf; - msg.out_len = out_len; - msg.in_buf = in_buf; - msg.in_len = in_len; - - return ec_dev->command_xfer(ec_dev, &msg); -} - -static int cros_ec_command_recv(struct cros_ec_device *ec_dev, - uint16_t cmd, void *buf, int buf_len) -{ - return cros_ec_command_sendrecv(ec_dev, cmd, NULL, 0, buf, buf_len); -} - -static int cros_ec_command_send(struct cros_ec_device *ec_dev, - uint16_t cmd, void *buf, int buf_len) -{ - return cros_ec_command_sendrecv(ec_dev, cmd, buf, buf_len, NULL, 0); -} - -static irqreturn_t ec_irq_thread(int irq, void *data) -{ - struct cros_ec_device *ec_dev = data; - - if (device_may_wakeup(ec_dev->dev)) - pm_wakeup_event(ec_dev->dev, 0); - - blocking_notifier_call_chain(&ec_dev->event_notifier, 1, ec_dev); - - return IRQ_HANDLED; -} - -static struct mfd_cell cros_devs[] = { - { - .name = "cros-ec-keyb", - .id = 1, - .of_compatible = "google,cros-ec-keyb", - }, -}; - -int cros_ec_register(struct cros_ec_device *ec_dev) -{ - struct device *dev = ec_dev->dev; - int err = 0; - - BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier); - - ec_dev->command_send = cros_ec_command_send; - ec_dev->command_recv = cros_ec_command_recv; - ec_dev->command_sendrecv = cros_ec_command_sendrecv; - - if (ec_dev->din_size) { - ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL); - if (!ec_dev->din) { - err = -ENOMEM; - goto fail_din; - } - } - if (ec_dev->dout_size) { - ec_dev->dout = kmalloc(ec_dev->dout_size, GFP_KERNEL); - if (!ec_dev->dout) { - err = -ENOMEM; - goto fail_dout; - } - } - - if (!ec_dev->irq) { - dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq); - goto fail_irq; - } - - err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "chromeos-ec", ec_dev); - if (err) { - dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err); - goto fail_irq; - } - - err = mfd_add_devices(dev, 0, cros_devs, - ARRAY_SIZE(cros_devs), - NULL, ec_dev->irq, NULL); - if (err) { - dev_err(dev, "failed to add mfd devices\n"); - goto fail_mfd; - } - - dev_info(dev, "Chrome EC (%s)\n", ec_dev->name); - - return 0; - -fail_mfd: - free_irq(ec_dev->irq, ec_dev); -fail_irq: - kfree(ec_dev->dout); -fail_dout: - kfree(ec_dev->din); -fail_din: - return err; -} -EXPORT_SYMBOL(cros_ec_register); - -int cros_ec_remove(struct cros_ec_device *ec_dev) -{ - mfd_remove_devices(ec_dev->dev); - free_irq(ec_dev->irq, ec_dev); - kfree(ec_dev->dout); - kfree(ec_dev->din); - - return 0; -} -EXPORT_SYMBOL(cros_ec_remove); - -#ifdef CONFIG_PM_SLEEP -int cros_ec_suspend(struct cros_ec_device *ec_dev) -{ - struct device *dev = ec_dev->dev; - - if (device_may_wakeup(dev)) - ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); - - disable_irq(ec_dev->irq); - ec_dev->was_wake_device = ec_dev->wake_enabled; - - return 0; -} -EXPORT_SYMBOL(cros_ec_suspend); - -int cros_ec_resume(struct cros_ec_device *ec_dev) -{ - enable_irq(ec_dev->irq); - - if (ec_dev->wake_enabled) { - disable_irq_wake(ec_dev->irq); - ec_dev->wake_enabled = 0; - } - - return 0; -} -EXPORT_SYMBOL(cros_ec_resume); - -#endif diff --git a/trunk/drivers/mfd/cros_ec_i2c.c b/trunk/drivers/mfd/cros_ec_i2c.c deleted file mode 100644 index 123044608b63..000000000000 --- a/trunk/drivers/mfd/cros_ec_i2c.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * ChromeOS EC multi-function device (I2C) - * - * Copyright (C) 2012 Google, Inc - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static inline struct cros_ec_device *to_ec_dev(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - return i2c_get_clientdata(client); -} - -static int cros_ec_command_xfer(struct cros_ec_device *ec_dev, - struct cros_ec_msg *msg) -{ - struct i2c_client *client = ec_dev->priv; - int ret = -ENOMEM; - int i; - int packet_len; - u8 *out_buf = NULL; - u8 *in_buf = NULL; - u8 sum; - struct i2c_msg i2c_msg[2]; - - i2c_msg[0].addr = client->addr; - i2c_msg[0].flags = 0; - i2c_msg[1].addr = client->addr; - i2c_msg[1].flags = I2C_M_RD; - - /* - * allocate larger packet (one byte for checksum, one byte for - * length, and one for result code) - */ - packet_len = msg->in_len + 3; - in_buf = kzalloc(packet_len, GFP_KERNEL); - if (!in_buf) - goto done; - i2c_msg[1].len = packet_len; - i2c_msg[1].buf = (char *)in_buf; - - /* - * allocate larger packet (one byte for checksum, one for - * command code, one for length, and one for command version) - */ - packet_len = msg->out_len + 4; - out_buf = kzalloc(packet_len, GFP_KERNEL); - if (!out_buf) - goto done; - i2c_msg[0].len = packet_len; - i2c_msg[0].buf = (char *)out_buf; - - out_buf[0] = EC_CMD_VERSION0 + msg->version; - out_buf[1] = msg->cmd; - out_buf[2] = msg->out_len; - - /* copy message payload and compute checksum */ - sum = out_buf[0] + out_buf[1] + out_buf[2]; - for (i = 0; i < msg->out_len; i++) { - out_buf[3 + i] = msg->out_buf[i]; - sum += out_buf[3 + i]; - } - out_buf[3 + msg->out_len] = sum; - - /* send command to EC and read answer */ - ret = i2c_transfer(client->adapter, i2c_msg, 2); - if (ret < 0) { - dev_err(ec_dev->dev, "i2c transfer failed: %d\n", ret); - goto done; - } else if (ret != 2) { - dev_err(ec_dev->dev, "failed to get response: %d\n", ret); - ret = -EIO; - goto done; - } - - /* check response error code */ - if (i2c_msg[1].buf[0]) { - dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", - msg->cmd, i2c_msg[1].buf[0]); - ret = -EINVAL; - goto done; - } - - /* copy response packet payload and compute checksum */ - sum = in_buf[0] + in_buf[1]; - for (i = 0; i < msg->in_len; i++) { - msg->in_buf[i] = in_buf[2 + i]; - sum += in_buf[2 + i]; - } - dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n", - i2c_msg[1].len, in_buf, sum); - if (sum != in_buf[2 + msg->in_len]) { - dev_err(ec_dev->dev, "bad packet checksum\n"); - ret = -EBADMSG; - goto done; - } - - ret = 0; - done: - kfree(in_buf); - kfree(out_buf); - return ret; -} - -static int cros_ec_probe_i2c(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - struct device *dev = &client->dev; - struct cros_ec_device *ec_dev = NULL; - int err; - - ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); - if (!ec_dev) - return -ENOMEM; - - i2c_set_clientdata(client, ec_dev); - ec_dev->name = "I2C"; - ec_dev->dev = dev; - ec_dev->priv = client; - ec_dev->irq = client->irq; - ec_dev->command_xfer = cros_ec_command_xfer; - ec_dev->ec_name = client->name; - ec_dev->phys_name = client->adapter->name; - ec_dev->parent = &client->dev; - - err = cros_ec_register(ec_dev); - if (err) { - dev_err(dev, "cannot register EC\n"); - return err; - } - - return 0; -} - -static int cros_ec_remove_i2c(struct i2c_client *client) -{ - struct cros_ec_device *ec_dev = i2c_get_clientdata(client); - - cros_ec_remove(ec_dev); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int cros_ec_i2c_suspend(struct device *dev) -{ - struct cros_ec_device *ec_dev = to_ec_dev(dev); - - return cros_ec_suspend(ec_dev); -} - -static int cros_ec_i2c_resume(struct device *dev) -{ - struct cros_ec_device *ec_dev = to_ec_dev(dev); - - return cros_ec_resume(ec_dev); -} -#endif - -static SIMPLE_DEV_PM_OPS(cros_ec_i2c_pm_ops, cros_ec_i2c_suspend, - cros_ec_i2c_resume); - -static const struct i2c_device_id cros_ec_i2c_id[] = { - { "cros-ec-i2c", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id); - -static struct i2c_driver cros_ec_driver = { - .driver = { - .name = "cros-ec-i2c", - .owner = THIS_MODULE, - .pm = &cros_ec_i2c_pm_ops, - }, - .probe = cros_ec_probe_i2c, - .remove = cros_ec_remove_i2c, - .id_table = cros_ec_i2c_id, -}; - -module_i2c_driver(cros_ec_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ChromeOS EC multi function device"); diff --git a/trunk/drivers/mfd/cros_ec_spi.c b/trunk/drivers/mfd/cros_ec_spi.c deleted file mode 100644 index 19193cf1e7a1..000000000000 --- a/trunk/drivers/mfd/cros_ec_spi.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * ChromeOS EC multi-function device (SPI) - * - * Copyright (C) 2012 Google, Inc - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* The header byte, which follows the preamble */ -#define EC_MSG_HEADER 0xec - -/* - * Number of EC preamble bytes we read at a time. Since it takes - * about 400-500us for the EC to respond there is not a lot of - * point in tuning this. If the EC could respond faster then - * we could increase this so that might expect the preamble and - * message to occur in a single transaction. However, the maximum - * SPI transfer size is 256 bytes, so at 5MHz we need a response - * time of perhaps <320us (200 bytes / 1600 bits). - */ -#define EC_MSG_PREAMBLE_COUNT 32 - -/* - * We must get a response from the EC in 5ms. This is a very long - * time, but the flash write command can take 2-3ms. The EC command - * processing is currently not very fast (about 500us). We could - * look at speeding this up and making the flash write command a - * 'slow' command, requiring a GET_STATUS wait loop, like flash - * erase. - */ -#define EC_MSG_DEADLINE_MS 5 - -/* - * Time between raising the SPI chip select (for the end of a - * transaction) and dropping it again (for the next transaction). - * If we go too fast, the EC will miss the transaction. It seems - * that 50us is enough with the 16MHz STM32 EC. - */ -#define EC_SPI_RECOVERY_TIME_NS (50 * 1000) - -/** - * struct cros_ec_spi - information about a SPI-connected EC - * - * @spi: SPI device we are connected to - * @last_transfer_ns: time that we last finished a transfer, or 0 if there - * if no record - */ -struct cros_ec_spi { - struct spi_device *spi; - s64 last_transfer_ns; -}; - -static void debug_packet(struct device *dev, const char *name, u8 *ptr, - int len) -{ -#ifdef DEBUG - int i; - - dev_dbg(dev, "%s: ", name); - for (i = 0; i < len; i++) - dev_cont(dev, " %02x", ptr[i]); -#endif -} - -/** - * cros_ec_spi_receive_response - Receive a response from the EC. - * - * This function has two phases: reading the preamble bytes (since if we read - * data from the EC before it is ready to send, we just get preamble) and - * reading the actual message. - * - * The received data is placed into ec_dev->din. - * - * @ec_dev: ChromeOS EC device - * @need_len: Number of message bytes we need to read - */ -static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, - int need_len) -{ - struct cros_ec_spi *ec_spi = ec_dev->priv; - struct spi_transfer trans; - struct spi_message msg; - u8 *ptr, *end; - int ret; - unsigned long deadline; - int todo; - - /* Receive data until we see the header byte */ - deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); - do { - memset(&trans, '\0', sizeof(trans)); - trans.cs_change = 1; - trans.rx_buf = ptr = ec_dev->din; - trans.len = EC_MSG_PREAMBLE_COUNT; - - spi_message_init(&msg); - spi_message_add_tail(&trans, &msg); - ret = spi_sync(ec_spi->spi, &msg); - if (ret < 0) { - dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); - return ret; - } - - for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { - if (*ptr == EC_MSG_HEADER) { - dev_dbg(ec_dev->dev, "msg found at %ld\n", - ptr - ec_dev->din); - break; - } - } - - if (time_after(jiffies, deadline)) { - dev_warn(ec_dev->dev, "EC failed to respond in time\n"); - return -ETIMEDOUT; - } - } while (ptr == end); - - /* - * ptr now points to the header byte. Copy any valid data to the - * start of our buffer - */ - todo = end - ++ptr; - BUG_ON(todo < 0 || todo > ec_dev->din_size); - todo = min(todo, need_len); - memmove(ec_dev->din, ptr, todo); - ptr = ec_dev->din + todo; - dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n", - need_len, todo); - need_len -= todo; - - /* Receive data until we have it all */ - while (need_len > 0) { - /* - * We can't support transfers larger than the SPI FIFO size - * unless we have DMA. We don't have DMA on the ISP SPI ports - * for Exynos. We need a way of asking SPI driver for - * maximum-supported transfer size. - */ - todo = min(need_len, 256); - dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%ld\n", - todo, need_len, ptr - ec_dev->din); - - memset(&trans, '\0', sizeof(trans)); - trans.cs_change = 1; - trans.rx_buf = ptr; - trans.len = todo; - spi_message_init(&msg); - spi_message_add_tail(&trans, &msg); - - /* send command to EC and read answer */ - BUG_ON((u8 *)trans.rx_buf - ec_dev->din + todo > - ec_dev->din_size); - ret = spi_sync(ec_spi->spi, &msg); - if (ret < 0) { - dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); - return ret; - } - - debug_packet(ec_dev->dev, "interim", ptr, todo); - ptr += todo; - need_len -= todo; - } - - dev_dbg(ec_dev->dev, "loop done, ptr=%ld\n", ptr - ec_dev->din); - - return 0; -} - -/** - * cros_ec_command_spi_xfer - Transfer a message over SPI and receive the reply - * - * @ec_dev: ChromeOS EC device - * @ec_msg: Message to transfer - */ -static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, - struct cros_ec_msg *ec_msg) -{ - struct cros_ec_spi *ec_spi = ec_dev->priv; - struct spi_transfer trans; - struct spi_message msg; - int i, len; - u8 *ptr; - int sum; - int ret = 0, final_ret; - struct timespec ts; - - len = cros_ec_prepare_tx(ec_dev, ec_msg); - dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); - - /* If it's too soon to do another transaction, wait */ - if (ec_spi->last_transfer_ns) { - struct timespec ts; - unsigned long delay; /* The delay completed so far */ - - ktime_get_ts(&ts); - delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns; - if (delay < EC_SPI_RECOVERY_TIME_NS) - ndelay(delay); - } - - /* Transmit phase - send our message */ - debug_packet(ec_dev->dev, "out", ec_dev->dout, len); - memset(&trans, '\0', sizeof(trans)); - trans.tx_buf = ec_dev->dout; - trans.len = len; - trans.cs_change = 1; - spi_message_init(&msg); - spi_message_add_tail(&trans, &msg); - ret = spi_sync(ec_spi->spi, &msg); - - /* Get the response */ - if (!ret) { - ret = cros_ec_spi_receive_response(ec_dev, - ec_msg->in_len + EC_MSG_TX_PROTO_BYTES); - } else { - dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); - } - - /* turn off CS */ - spi_message_init(&msg); - final_ret = spi_sync(ec_spi->spi, &msg); - ktime_get_ts(&ts); - ec_spi->last_transfer_ns = timespec_to_ns(&ts); - if (!ret) - ret = final_ret; - if (ret < 0) { - dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); - return ret; - } - - /* check response error code */ - ptr = ec_dev->din; - if (ptr[0]) { - dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", - ec_msg->cmd, ptr[0]); - debug_packet(ec_dev->dev, "in_err", ptr, len); - return -EINVAL; - } - len = ptr[1]; - sum = ptr[0] + ptr[1]; - if (len > ec_msg->in_len) { - dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", - len, ec_msg->in_len); - return -ENOSPC; - } - - /* copy response packet payload and compute checksum */ - for (i = 0; i < len; i++) { - sum += ptr[i + 2]; - if (ec_msg->in_len) - ec_msg->in_buf[i] = ptr[i + 2]; - } - sum &= 0xff; - - debug_packet(ec_dev->dev, "in", ptr, len + 3); - - if (sum != ptr[len + 2]) { - dev_err(ec_dev->dev, - "bad packet checksum, expected %02x, got %02x\n", - sum, ptr[len + 2]); - return -EBADMSG; - } - - return 0; -} - -static int cros_ec_probe_spi(struct spi_device *spi) -{ - struct device *dev = &spi->dev; - struct cros_ec_device *ec_dev; - struct cros_ec_spi *ec_spi; - int err; - - spi->bits_per_word = 8; - spi->mode = SPI_MODE_0; - err = spi_setup(spi); - if (err < 0) - return err; - - ec_spi = devm_kzalloc(dev, sizeof(*ec_spi), GFP_KERNEL); - if (ec_spi == NULL) - return -ENOMEM; - ec_spi->spi = spi; - ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); - if (!ec_dev) - return -ENOMEM; - - spi_set_drvdata(spi, ec_dev); - ec_dev->name = "SPI"; - ec_dev->dev = dev; - ec_dev->priv = ec_spi; - ec_dev->irq = spi->irq; - ec_dev->command_xfer = cros_ec_command_spi_xfer; - ec_dev->ec_name = ec_spi->spi->modalias; - ec_dev->phys_name = dev_name(&ec_spi->spi->dev); - ec_dev->parent = &ec_spi->spi->dev; - ec_dev->din_size = EC_MSG_BYTES + EC_MSG_PREAMBLE_COUNT; - ec_dev->dout_size = EC_MSG_BYTES; - - err = cros_ec_register(ec_dev); - if (err) { - dev_err(dev, "cannot register EC\n"); - return err; - } - - return 0; -} - -static int cros_ec_remove_spi(struct spi_device *spi) -{ - struct cros_ec_device *ec_dev; - - ec_dev = spi_get_drvdata(spi); - cros_ec_remove(ec_dev); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int cros_ec_spi_suspend(struct device *dev) -{ - struct cros_ec_device *ec_dev = dev_get_drvdata(dev); - - return cros_ec_suspend(ec_dev); -} - -static int cros_ec_spi_resume(struct device *dev) -{ - struct cros_ec_device *ec_dev = dev_get_drvdata(dev); - - return cros_ec_resume(ec_dev); -} -#endif - -static SIMPLE_DEV_PM_OPS(cros_ec_spi_pm_ops, cros_ec_spi_suspend, - cros_ec_spi_resume); - -static const struct spi_device_id cros_ec_spi_id[] = { - { "cros-ec-spi", 0 }, - { } -}; -MODULE_DEVICE_TABLE(spi, cros_ec_spi_id); - -static struct spi_driver cros_ec_driver_spi = { - .driver = { - .name = "cros-ec-spi", - .owner = THIS_MODULE, - .pm = &cros_ec_spi_pm_ops, - }, - .probe = cros_ec_probe_spi, - .remove = cros_ec_remove_spi, - .id_table = cros_ec_spi_id, -}; - -module_spi_driver(cros_ec_driver_spi); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ChromeOS EC multi function device (SPI)"); diff --git a/trunk/drivers/mfd/da903x.c b/trunk/drivers/mfd/da903x.c index f1a316e0d6a6..05176cd2862b 100644 --- a/trunk/drivers/mfd/da903x.c +++ b/trunk/drivers/mfd/da903x.c @@ -499,8 +499,7 @@ static int da903x_probe(struct i2c_client *client, unsigned int tmp; int ret; - chip = devm_kzalloc(&client->dev, sizeof(struct da903x_chip), - GFP_KERNEL); + chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -516,27 +515,33 @@ static int da903x_probe(struct i2c_client *client, ret = chip->ops->init_chip(chip); if (ret) - return ret; + goto out_free_chip; /* mask and clear all IRQs */ chip->events_mask = 0xffffffff; chip->ops->mask_events(chip, chip->events_mask); chip->ops->read_events(chip, &tmp); - ret = devm_request_irq(&client->dev, client->irq, da903x_irq_handler, + ret = request_irq(client->irq, da903x_irq_handler, IRQF_TRIGGER_FALLING, "da903x", chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - return ret; + goto out_free_chip; } ret = da903x_add_subdevs(chip, pdata); if (ret) - return ret; + goto out_free_irq; return 0; + +out_free_irq: + free_irq(client->irq, chip); +out_free_chip: + kfree(chip); + return ret; } static int da903x_remove(struct i2c_client *client) @@ -544,6 +549,8 @@ static int da903x_remove(struct i2c_client *client) struct da903x_chip *chip = i2c_get_clientdata(client); da903x_remove_subdevs(chip); + free_irq(client->irq, chip); + kfree(chip); return 0; } diff --git a/trunk/drivers/mfd/da9052-spi.c b/trunk/drivers/mfd/da9052-spi.c index 0680bcbc53de..61d63b93576c 100644 --- a/trunk/drivers/mfd/da9052-spi.c +++ b/trunk/drivers/mfd/da9052-spi.c @@ -38,7 +38,7 @@ static int da9052_spi_probe(struct spi_device *spi) da9052->dev = &spi->dev; da9052->chip_irq = spi->irq; - spi_set_drvdata(spi, da9052); + dev_set_drvdata(&spi->dev, da9052); da9052_regmap_config.read_flag_mask = 1; da9052_regmap_config.write_flag_mask = 0; @@ -60,7 +60,7 @@ static int da9052_spi_probe(struct spi_device *spi) static int da9052_spi_remove(struct spi_device *spi) { - struct da9052 *da9052 = spi_get_drvdata(spi); + struct da9052 *da9052 = dev_get_drvdata(&spi->dev); da9052_device_exit(da9052); return 0; diff --git a/trunk/drivers/mfd/da9055-core.c b/trunk/drivers/mfd/da9055-core.c index 49cb23d37469..f56a1a9f7777 100644 --- a/trunk/drivers/mfd/da9055-core.c +++ b/trunk/drivers/mfd/da9055-core.c @@ -391,7 +391,7 @@ int da9055_device_init(struct da9055 *da9055) da9055->irq_base = pdata->irq_base; ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, da9055->irq_base, &da9055_regmap_irq_chip, &da9055->irq_data); if (ret < 0) diff --git a/trunk/drivers/mfd/davinci_voicecodec.c b/trunk/drivers/mfd/davinci_voicecodec.c index c60ab0c3c4db..c0bcc872af4e 100644 --- a/trunk/drivers/mfd/davinci_voicecodec.c +++ b/trunk/drivers/mfd/davinci_voicecodec.c @@ -177,7 +177,17 @@ static struct platform_driver davinci_vc_driver = { .remove = davinci_vc_remove, }; -module_platform_driver_probe(davinci_vc_driver, davinci_vc_probe); +static int __init davinci_vc_init(void) +{ + return platform_driver_probe(&davinci_vc_driver, davinci_vc_probe); +} +module_init(davinci_vc_init); + +static void __exit davinci_vc_exit(void) +{ + platform_driver_unregister(&davinci_vc_driver); +} +module_exit(davinci_vc_exit); MODULE_AUTHOR("Miguel Aguilar"); MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface"); diff --git a/trunk/drivers/mfd/db8500-prcmu.c b/trunk/drivers/mfd/db8500-prcmu.c index 319b8abe742b..21434beb420a 100644 --- a/trunk/drivers/mfd/db8500-prcmu.c +++ b/trunk/drivers/mfd/db8500-prcmu.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -2705,7 +2704,6 @@ static void dbx500_fw_version_init(struct platform_device *pdev, { struct resource *res; void __iomem *tcpm_base; - u32 version; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcpm"); @@ -2715,27 +2713,26 @@ static void dbx500_fw_version_init(struct platform_device *pdev, return; } tcpm_base = ioremap(res->start, resource_size(res)); - if (!tcpm_base) { - dev_err(&pdev->dev, "no prcmu tcpm mem region provided\n"); - return; + if (tcpm_base != NULL) { + u32 version; + + version = readl(tcpm_base + version_offset); + fw_info.version.project = (version & 0xFF); + fw_info.version.api_version = (version >> 8) & 0xFF; + fw_info.version.func_version = (version >> 16) & 0xFF; + fw_info.version.errata = (version >> 24) & 0xFF; + strncpy(fw_info.version.project_name, + fw_project_name(fw_info.version.project), + PRCMU_FW_PROJECT_NAME_LEN); + fw_info.valid = true; + pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n", + fw_info.version.project_name, + fw_info.version.project, + fw_info.version.api_version, + fw_info.version.func_version, + fw_info.version.errata); + iounmap(tcpm_base); } - - version = readl(tcpm_base + version_offset); - fw_info.version.project = (version & 0xFF); - fw_info.version.api_version = (version >> 8) & 0xFF; - fw_info.version.func_version = (version >> 16) & 0xFF; - fw_info.version.errata = (version >> 24) & 0xFF; - strncpy(fw_info.version.project_name, - fw_project_name(fw_info.version.project), - PRCMU_FW_PROJECT_NAME_LEN); - fw_info.valid = true; - pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n", - fw_info.version.project_name, - fw_info.version.project, - fw_info.version.api_version, - fw_info.version.func_version, - fw_info.version.errata); - iounmap(tcpm_base); } void __init db8500_prcmu_early_init(u32 phy_base, u32 size) @@ -3068,15 +3065,6 @@ static struct db8500_thsens_platform_data db8500_thsens_data = { .num_trips = 4, }; -static struct mfd_cell common_prcmu_devs[] = { - { - .name = "ux500_wdt", - .platform_data = &db8500_wdt_pdata, - .pdata_size = sizeof(db8500_wdt_pdata), - .id = -1, - }, -}; - static struct mfd_cell db8500_prcmu_devs[] = { { .name = "db8500-prcmu-regulators", @@ -3090,6 +3078,12 @@ static struct mfd_cell db8500_prcmu_devs[] = { .platform_data = &db8500_cpufreq_table, .pdata_size = sizeof(db8500_cpufreq_table), }, + { + .name = "ux500_wdt", + .platform_data = &db8500_wdt_pdata, + .pdata_size = sizeof(db8500_wdt_pdata), + .id = -1, + }, { .name = "db8500-thermal", .num_resources = ARRAY_SIZE(db8500_thsens_resources), @@ -3179,25 +3173,13 @@ static int db8500_prcmu_probe(struct platform_device *pdev) db8500_prcmu_update_cpufreq(); - err = mfd_add_devices(&pdev->dev, 0, common_prcmu_devs, - ARRAY_SIZE(common_prcmu_devs), NULL, 0, db8500_irq_domain); + err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, + ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, db8500_irq_domain); if (err) { pr_err("prcmu: Failed to add subdevices\n"); return err; } - /* TODO: Remove restriction when clk definitions are available. */ - if (!of_machine_is_compatible("st-ericsson,u8540")) { - err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, - ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, - db8500_irq_domain); - if (err) { - mfd_remove_devices(&pdev->dev); - pr_err("prcmu: Failed to add subdevices\n"); - goto no_irq_return; - } - } - err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata, pdata->ab_irq); if (err) { diff --git a/trunk/drivers/mfd/ezx-pcap.c b/trunk/drivers/mfd/ezx-pcap.c index 5502106ad515..b7a61f0f27a4 100644 --- a/trunk/drivers/mfd/ezx-pcap.c +++ b/trunk/drivers/mfd/ezx-pcap.c @@ -393,7 +393,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap, static int ezx_pcap_remove(struct spi_device *spi) { - struct pcap_chip *pcap = spi_get_drvdata(spi); + struct pcap_chip *pcap = dev_get_drvdata(&spi->dev); struct pcap_platform_data *pdata = spi->dev.platform_data; int i, adc_irq; @@ -403,7 +403,7 @@ static int ezx_pcap_remove(struct spi_device *spi) /* cleanup ADC */ adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); - devm_free_irq(&spi->dev, adc_irq, pcap); + free_irq(adc_irq, pcap); mutex_lock(&pcap->adc_mutex); for (i = 0; i < PCAP_ADC_MAXQ; i++) kfree(pcap->adc_queue[i]); @@ -415,6 +415,8 @@ static int ezx_pcap_remove(struct spi_device *spi) destroy_workqueue(pcap->workqueue); + kfree(pcap); + return 0; } @@ -429,7 +431,7 @@ static int ezx_pcap_probe(struct spi_device *spi) if (!pdata) goto ret; - pcap = devm_kzalloc(&spi->dev, sizeof(*pcap), GFP_KERNEL); + pcap = kzalloc(sizeof(*pcap), GFP_KERNEL); if (!pcap) { ret = -ENOMEM; goto ret; @@ -439,14 +441,14 @@ static int ezx_pcap_probe(struct spi_device *spi) mutex_init(&pcap->adc_mutex); INIT_WORK(&pcap->isr_work, pcap_isr_work); INIT_WORK(&pcap->msr_work, pcap_msr_work); - spi_set_drvdata(spi, pcap); + dev_set_drvdata(&spi->dev, pcap); /* setup spi */ spi->bits_per_word = 32; spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0); ret = spi_setup(spi); if (ret) - goto ret; + goto free_pcap; pcap->spi = spi; @@ -456,7 +458,7 @@ static int ezx_pcap_probe(struct spi_device *spi) if (!pcap->workqueue) { ret = -ENOMEM; dev_err(&spi->dev, "can't create pcap thread\n"); - goto ret; + goto free_pcap; } /* redirect interrupts to AP, except adcdone2 */ @@ -489,8 +491,7 @@ static int ezx_pcap_probe(struct spi_device *spi) adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); - ret = devm_request_irq(&spi->dev, adc_irq, pcap_adc_irq, 0, "ADC", - pcap); + ret = request_irq(adc_irq, pcap_adc_irq, 0, "ADC", pcap); if (ret) goto free_irqchip; @@ -510,12 +511,14 @@ static int ezx_pcap_probe(struct spi_device *spi) remove_subdevs: device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); /* free_adc: */ - devm_free_irq(&spi->dev, adc_irq, pcap); + free_irq(adc_irq, pcap); free_irqchip: for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) irq_set_chip_and_handler(i, NULL, NULL); /* destroy_workqueue: */ destroy_workqueue(pcap->workqueue); +free_pcap: + kfree(pcap); ret: return ret; } diff --git a/trunk/drivers/mfd/htc-pasic3.c b/trunk/drivers/mfd/htc-pasic3.c index 0285fceb99a6..9e5453d21a68 100644 --- a/trunk/drivers/mfd/htc-pasic3.c +++ b/trunk/drivers/mfd/htc-pasic3.c @@ -208,7 +208,18 @@ static struct platform_driver pasic3_driver = { .remove = pasic3_remove, }; -module_platform_driver_probe(pasic3_driver, pasic3_probe); +static int __init pasic3_base_init(void) +{ + return platform_driver_probe(&pasic3_driver, pasic3_probe); +} + +static void __exit pasic3_base_exit(void) +{ + platform_driver_unregister(&pasic3_driver); +} + +module_init(pasic3_base_init); +module_exit(pasic3_base_exit); MODULE_AUTHOR("Philipp Zabel "); MODULE_DESCRIPTION("Core driver for HTC PASIC3"); diff --git a/trunk/drivers/mfd/intel_msic.c b/trunk/drivers/mfd/intel_msic.c index 5be3b5e13855..1804331bd52c 100644 --- a/trunk/drivers/mfd/intel_msic.c +++ b/trunk/drivers/mfd/intel_msic.c @@ -323,8 +323,7 @@ static int intel_msic_init_devices(struct intel_msic *msic) if (pdata->ocd) { unsigned gpio = pdata->ocd->gpio; - ret = devm_gpio_request_one(&pdev->dev, gpio, - GPIOF_IN, "ocd_gpio"); + ret = gpio_request_one(gpio, GPIOF_IN, "ocd_gpio"); if (ret) { dev_err(&pdev->dev, "failed to register OCD GPIO\n"); return ret; @@ -333,6 +332,7 @@ static int intel_msic_init_devices(struct intel_msic *msic) ret = gpio_to_irq(gpio); if (ret < 0) { dev_err(&pdev->dev, "no IRQ number for OCD GPIO\n"); + gpio_free(gpio); return ret; } @@ -359,6 +359,8 @@ static int intel_msic_init_devices(struct intel_msic *msic) fail: mfd_remove_devices(&pdev->dev); + if (pdata->ocd) + gpio_free(pdata->ocd->gpio); return ret; } @@ -366,8 +368,12 @@ static int intel_msic_init_devices(struct intel_msic *msic) static void intel_msic_remove_devices(struct intel_msic *msic) { struct platform_device *pdev = msic->pdev; + struct intel_msic_platform_data *pdata = pdev->dev.platform_data; mfd_remove_devices(&pdev->dev); + + if (pdata->ocd) + gpio_free(pdata->ocd->gpio); } static int intel_msic_probe(struct platform_device *pdev) diff --git a/trunk/drivers/mfd/lm3533-core.c b/trunk/drivers/mfd/lm3533-core.c index 4b7e6dac1de8..ceebf2c1ea97 100644 --- a/trunk/drivers/mfd/lm3533-core.c +++ b/trunk/drivers/mfd/lm3533-core.c @@ -496,8 +496,8 @@ static int lm3533_device_init(struct lm3533 *lm3533) dev_set_drvdata(lm3533->dev, lm3533); if (gpio_is_valid(lm3533->gpio_hwen)) { - ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen, - GPIOF_OUT_INIT_LOW, "lm3533-hwen"); + ret = gpio_request_one(lm3533->gpio_hwen, GPIOF_OUT_INIT_LOW, + "lm3533-hwen"); if (ret < 0) { dev_err(lm3533->dev, "failed to request HWEN GPIO %d\n", @@ -528,6 +528,8 @@ static int lm3533_device_init(struct lm3533 *lm3533) mfd_remove_devices(lm3533->dev); err_disable: lm3533_disable(lm3533); + if (gpio_is_valid(lm3533->gpio_hwen)) + gpio_free(lm3533->gpio_hwen); return ret; } @@ -540,6 +542,8 @@ static void lm3533_device_exit(struct lm3533 *lm3533) mfd_remove_devices(lm3533->dev); lm3533_disable(lm3533); + if (gpio_is_valid(lm3533->gpio_hwen)) + gpio_free(lm3533->gpio_hwen); } static bool lm3533_readable_register(struct device *dev, unsigned int reg) diff --git a/trunk/drivers/mfd/max77686.c b/trunk/drivers/mfd/max77686.c index 1cbb17609c8b..4d73963cd8f0 100644 --- a/trunk/drivers/mfd/max77686.c +++ b/trunk/drivers/mfd/max77686.c @@ -46,7 +46,7 @@ static struct regmap_config max77686_regmap_config = { #ifdef CONFIG_OF static struct of_device_id max77686_pmic_dt_match[] = { - {.compatible = "maxim,max77686", .data = NULL}, + {.compatible = "maxim,max77686", .data = 0}, {}, }; diff --git a/trunk/drivers/mfd/mc13xxx-spi.c b/trunk/drivers/mfd/mc13xxx-spi.c index 77189daadf1e..3032bae20b62 100644 --- a/trunk/drivers/mfd/mc13xxx-spi.c +++ b/trunk/drivers/mfd/mc13xxx-spi.c @@ -131,7 +131,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) if (!mc13xxx) return -ENOMEM; - spi_set_drvdata(spi, mc13xxx); + dev_set_drvdata(&spi->dev, mc13xxx); spi->mode = SPI_MODE_0 | SPI_CS_HIGH; mc13xxx->dev = &spi->dev; @@ -144,7 +144,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) ret = PTR_ERR(mc13xxx->regmap); dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n", ret); - spi_set_drvdata(spi, NULL); + dev_set_drvdata(&spi->dev, NULL); return ret; } @@ -164,7 +164,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) static int mc13xxx_spi_remove(struct spi_device *spi) { - struct mc13xxx *mc13xxx = spi_get_drvdata(spi); + struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); mc13xxx_common_cleanup(mc13xxx); diff --git a/trunk/drivers/mfd/omap-usb-host.c b/trunk/drivers/mfd/omap-usb-host.c index 759fae3ca7fb..4febc5c7fdee 100644 --- a/trunk/drivers/mfd/omap-usb-host.c +++ b/trunk/drivers/mfd/omap-usb-host.c @@ -1,9 +1,8 @@ /** * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI * - * Copyright (C) 2011-2013 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com * Author: Keshava Munegowda - * Author: Roger Quadros * * 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 @@ -28,9 +27,6 @@ #include #include #include -#include -#include -#include #include "omap-usb.h" @@ -141,49 +137,6 @@ static inline u8 usbhs_readb(void __iomem *base, u8 reg) /*-------------------------------------------------------------------------*/ -/** - * Map 'enum usbhs_omap_port_mode' found in - * to the device tree binding portN-mode found in - * 'Documentation/devicetree/bindings/mfd/omap-usb-host.txt' - */ -static const char * const port_modes[] = { - [OMAP_USBHS_PORT_MODE_UNUSED] = "", - [OMAP_EHCI_PORT_MODE_PHY] = "ehci-phy", - [OMAP_EHCI_PORT_MODE_TLL] = "ehci-tll", - [OMAP_EHCI_PORT_MODE_HSIC] = "ehci-hsic", - [OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0] = "ohci-phy-6pin-datse0", - [OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM] = "ohci-phy-6pin-dpdm", - [OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0] = "ohci-phy-3pin-datse0", - [OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM] = "ohci-phy-4pin-dpdm", - [OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0] = "ohci-tll-6pin-datse0", - [OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM] = "ohci-tll-6pin-dpdm", - [OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0] = "ohci-tll-3pin-datse0", - [OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM] = "ohci-tll-4pin-dpdm", - [OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0] = "ohci-tll-2pin-datse0", - [OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM] = "ohci-tll-2pin-dpdm", -}; - -/** - * omap_usbhs_get_dt_port_mode - Get the 'enum usbhs_omap_port_mode' - * from the port mode string. - * @mode: The port mode string, usually obtained from device tree. - * - * The function returns the 'enum usbhs_omap_port_mode' that matches the - * provided port mode string as per the port_modes table. - * If no match is found it returns -ENODEV - */ -static const int omap_usbhs_get_dt_port_mode(const char *mode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(port_modes); i++) { - if (!strcmp(mode, port_modes[i])) - return i; - } - - return -ENODEV; -} - static struct platform_device *omap_usbhs_alloc_child(const char *name, struct resource *res, int num_resources, void *pdata, size_t pdata_size, struct device *dev) @@ -325,7 +278,7 @@ static int usbhs_runtime_resume(struct device *dev) dev_dbg(dev, "usbhs_runtime_resume\n"); - omap_tll_enable(pdata); + omap_tll_enable(); if (!IS_ERR(omap->ehci_logic_fck)) clk_enable(omap->ehci_logic_fck); @@ -400,7 +353,7 @@ static int usbhs_runtime_suspend(struct device *dev) if (!IS_ERR(omap->ehci_logic_fck)) clk_disable(omap->ehci_logic_fck); - omap_tll_disable(pdata); + omap_tll_disable(); return 0; } @@ -477,10 +430,24 @@ static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap, static void omap_usbhs_init(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); + struct usbhs_omap_platform_data *pdata = omap->pdata; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); + if (pdata->phy_reset) { + if (gpio_is_valid(pdata->reset_gpio_port[0])) + gpio_request_one(pdata->reset_gpio_port[0], + GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); + + if (gpio_is_valid(pdata->reset_gpio_port[1])) + gpio_request_one(pdata->reset_gpio_port[1], + GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); + + /* Hold the PHY in RESET for enough time till DIR is high */ + udelay(10); + } + pm_runtime_get_sync(dev); reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); @@ -509,59 +476,36 @@ static void omap_usbhs_init(struct device *dev) dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); pm_runtime_put_sync(dev); -} - -static int usbhs_omap_get_dt_pdata(struct device *dev, - struct usbhs_omap_platform_data *pdata) -{ - int ret, i; - struct device_node *node = dev->of_node; + if (pdata->phy_reset) { + /* Hold the PHY in RESET for enough time till + * PHY is settled and ready + */ + udelay(10); - ret = of_property_read_u32(node, "num-ports", &pdata->nports); - if (ret) - pdata->nports = 0; + if (gpio_is_valid(pdata->reset_gpio_port[0])) + gpio_set_value_cansleep + (pdata->reset_gpio_port[0], 1); - if (pdata->nports > OMAP3_HS_USB_PORTS) { - dev_warn(dev, "Too many num_ports <%d> in device tree. Max %d\n", - pdata->nports, OMAP3_HS_USB_PORTS); - return -ENODEV; + if (gpio_is_valid(pdata->reset_gpio_port[1])) + gpio_set_value_cansleep + (pdata->reset_gpio_port[1], 1); } +} - /* get port modes */ - for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { - char prop[11]; - const char *mode; - - pdata->port_mode[i] = OMAP_USBHS_PORT_MODE_UNUSED; - - snprintf(prop, sizeof(prop), "port%d-mode", i + 1); - ret = of_property_read_string(node, prop, &mode); - if (ret < 0) - continue; +static void omap_usbhs_deinit(struct device *dev) +{ + struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); + struct usbhs_omap_platform_data *pdata = omap->pdata; - ret = omap_usbhs_get_dt_port_mode(mode); - if (ret < 0) { - dev_warn(dev, "Invalid port%d-mode \"%s\" in device tree\n", - i, mode); - return -ENODEV; - } + if (pdata->phy_reset) { + if (gpio_is_valid(pdata->reset_gpio_port[0])) + gpio_free(pdata->reset_gpio_port[0]); - dev_dbg(dev, "port%d-mode: %s -> %d\n", i, mode, ret); - pdata->port_mode[i] = ret; + if (gpio_is_valid(pdata->reset_gpio_port[1])) + gpio_free(pdata->reset_gpio_port[1]); } - - /* get flags */ - pdata->single_ulpi_bypass = of_property_read_bool(node, - "single-ulpi-bypass"); - - return 0; } -static struct of_device_id usbhs_child_match_table[] = { - { .compatible = "ti,omap-ehci", }, - { .compatible = "ti,omap-ohci", }, - { } -}; /** * usbhs_omap_probe - initialize TI-based HCDs @@ -578,46 +522,26 @@ static int usbhs_omap_probe(struct platform_device *pdev) int i; bool need_logic_fck; - if (dev->of_node) { - /* For DT boot we populate platform data from OF node */ - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - ret = usbhs_omap_get_dt_pdata(dev, pdata); - if (ret) - return ret; - - dev->platform_data = pdata; - } - if (!pdata) { dev_err(dev, "Missing platform data\n"); return -ENODEV; } - if (pdata->nports > OMAP3_HS_USB_PORTS) { - dev_info(dev, "Too many num_ports <%d> in platform_data. Max %d\n", - pdata->nports, OMAP3_HS_USB_PORTS); - return -ENODEV; - } - omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); if (!omap) { dev_err(dev, "Memory allocation failed\n"); return -ENOMEM; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - omap->uhh_base = devm_ioremap_resource(dev, res); - if (IS_ERR(omap->uhh_base)) - return PTR_ERR(omap->uhh_base); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); + omap->uhh_base = devm_request_and_ioremap(dev, res); + if (!omap->uhh_base) { + dev_err(dev, "Resource request/ioremap failed\n"); + return -EADDRNOTAVAIL; + } omap->pdata = pdata; - /* Initialize the TLL subsystem */ - omap_tll_init(pdata); - pm_runtime_enable(dev); platform_set_drvdata(pdev, omap); @@ -651,7 +575,6 @@ static int usbhs_omap_probe(struct platform_device *pdev) omap->usbhs_rev, omap->nports); break; } - pdata->nports = omap->nports; } i = sizeof(struct clk *) * omap->nports; @@ -777,28 +700,17 @@ static int usbhs_omap_probe(struct platform_device *pdev) } omap_usbhs_init(dev); - - if (dev->of_node) { - ret = of_platform_populate(dev->of_node, - usbhs_child_match_table, NULL, dev); - - if (ret) { - dev_err(dev, "Failed to create DT children: %d\n", ret); - goto err_alloc; - } - - } else { - ret = omap_usbhs_alloc_children(pdev); - if (ret) { - dev_err(dev, "omap_usbhs_alloc_children failed: %d\n", - ret); - goto err_alloc; - } + ret = omap_usbhs_alloc_children(pdev); + if (ret) { + dev_err(dev, "omap_usbhs_alloc_children failed\n"); + goto err_alloc; } return 0; err_alloc: + omap_usbhs_deinit(&pdev->dev); + for (i = 0; i < omap->nports; i++) { if (!IS_ERR(omap->utmi_clk[i])) clk_put(omap->utmi_clk[i]); @@ -832,13 +744,6 @@ static int usbhs_omap_probe(struct platform_device *pdev) return ret; } -static int usbhs_omap_remove_child(struct device *dev, void *data) -{ - dev_info(dev, "unregistering\n"); - platform_device_unregister(to_platform_device(dev)); - return 0; -} - /** * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs * @pdev: USB Host Controller being removed @@ -850,6 +755,8 @@ static int usbhs_omap_remove(struct platform_device *pdev) struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); int i; + omap_usbhs_deinit(&pdev->dev); + for (i = 0; i < omap->nports; i++) { if (!IS_ERR(omap->utmi_clk[i])) clk_put(omap->utmi_clk[i]); @@ -870,8 +777,6 @@ static int usbhs_omap_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - /* remove children */ - device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child); return 0; } @@ -880,26 +785,16 @@ static const struct dev_pm_ops usbhsomap_dev_pm_ops = { .runtime_resume = usbhs_runtime_resume, }; -static const struct of_device_id usbhs_omap_dt_ids[] = { - { .compatible = "ti,usbhs-host" }, - { } -}; - -MODULE_DEVICE_TABLE(of, usbhs_omap_dt_ids); - - static struct platform_driver usbhs_omap_driver = { .driver = { .name = (char *)usbhs_driver_name, .owner = THIS_MODULE, .pm = &usbhsomap_dev_pm_ops, - .of_match_table = of_match_ptr(usbhs_omap_dt_ids), }, .remove = usbhs_omap_remove, }; MODULE_AUTHOR("Keshava Munegowda "); -MODULE_AUTHOR("Roger Quadros "); MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); diff --git a/trunk/drivers/mfd/omap-usb-tll.c b/trunk/drivers/mfd/omap-usb-tll.c index e59ac4cbac96..0aef1a768880 100644 --- a/trunk/drivers/mfd/omap-usb-tll.c +++ b/trunk/drivers/mfd/omap-usb-tll.c @@ -1,9 +1,8 @@ /** * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI * - * Copyright (C) 2012-2013 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com * Author: Keshava Munegowda - * Author: Roger Quadros * * 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 @@ -28,7 +27,6 @@ #include #include #include -#include #define USBTLL_DRIVER_NAME "usbhs_tll" @@ -107,8 +105,8 @@ struct usbtll_omap { int nch; /* num. of channels */ + struct usbhs_omap_platform_data *pdata; struct clk **ch_clk; - void __iomem *base; }; /*-------------------------------------------------------------------------*/ @@ -212,10 +210,14 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) static int usbtll_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct usbhs_omap_platform_data *pdata = dev->platform_data; + void __iomem *base; struct resource *res; struct usbtll_omap *tll; + unsigned reg; int ret = 0; int i, ver; + bool needs_tll; dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); @@ -225,16 +227,26 @@ static int usbtll_omap_probe(struct platform_device *pdev) return -ENOMEM; } + if (!pdata) { + dev_err(dev, "Platform data missing\n"); + return -ENODEV; + } + + tll->pdata = pdata; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tll->base = devm_ioremap_resource(dev, res); - if (IS_ERR(tll->base)) - return PTR_ERR(tll->base); + base = devm_request_and_ioremap(dev, res); + if (!base) { + ret = -EADDRNOTAVAIL; + dev_err(dev, "Resource request/ioremap failed:%d\n", ret); + return ret; + } platform_set_drvdata(pdev, tll); pm_runtime_enable(dev); pm_runtime_get_sync(dev); - ver = usbtll_read(tll->base, OMAP_USBTLL_REVISION); + ver = usbtll_read(base, OMAP_USBTLL_REVISION); switch (ver) { case OMAP_USBTLL_REV1: case OMAP_USBTLL_REV4: @@ -271,85 +283,11 @@ static int usbtll_omap_probe(struct platform_device *pdev) dev_dbg(dev, "can't get clock : %s\n", clkname); } - pm_runtime_put_sync(dev); - /* only after this can omap_tll_enable/disable work */ - spin_lock(&tll_lock); - tll_dev = dev; - spin_unlock(&tll_lock); - - return 0; - -err_clk_alloc: - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - - return ret; -} - -/** - * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs - * @pdev: USB Host Controller being removed - * - * Reverses the effect of usbtll_omap_probe(). - */ -static int usbtll_omap_remove(struct platform_device *pdev) -{ - struct usbtll_omap *tll = platform_get_drvdata(pdev); - int i; - - spin_lock(&tll_lock); - tll_dev = NULL; - spin_unlock(&tll_lock); - - for (i = 0; i < tll->nch; i++) - if (!IS_ERR(tll->ch_clk[i])) - clk_put(tll->ch_clk[i]); - - pm_runtime_disable(&pdev->dev); - return 0; -} - -static const struct of_device_id usbtll_omap_dt_ids[] = { - { .compatible = "ti,usbhs-tll" }, - { } -}; - -MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids); - -static struct platform_driver usbtll_omap_driver = { - .driver = { - .name = (char *)usbtll_driver_name, - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(usbtll_omap_dt_ids), - }, - .probe = usbtll_omap_probe, - .remove = usbtll_omap_remove, -}; - -int omap_tll_init(struct usbhs_omap_platform_data *pdata) -{ - int i; - bool needs_tll; - unsigned reg; - struct usbtll_omap *tll; - - spin_lock(&tll_lock); - - if (!tll_dev) { - spin_unlock(&tll_lock); - return -ENODEV; - } - - tll = dev_get_drvdata(tll_dev); - needs_tll = false; for (i = 0; i < tll->nch; i++) needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); - pm_runtime_get_sync(tll_dev); - if (needs_tll) { - void __iomem *base = tll->base; /* Program Common TLL register */ reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); @@ -398,29 +336,51 @@ int omap_tll_init(struct usbhs_omap_platform_data *pdata) } } - pm_runtime_put_sync(tll_dev); - + pm_runtime_put_sync(dev); + /* only after this can omap_tll_enable/disable work */ + spin_lock(&tll_lock); + tll_dev = dev; spin_unlock(&tll_lock); return 0; + +err_clk_alloc: + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + + return ret; } -EXPORT_SYMBOL_GPL(omap_tll_init); -int omap_tll_enable(struct usbhs_omap_platform_data *pdata) +/** + * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs + * @pdev: USB Host Controller being removed + * + * Reverses the effect of usbtll_omap_probe(). + */ +static int usbtll_omap_remove(struct platform_device *pdev) { + struct usbtll_omap *tll = platform_get_drvdata(pdev); int i; - struct usbtll_omap *tll; spin_lock(&tll_lock); + tll_dev = NULL; + spin_unlock(&tll_lock); - if (!tll_dev) { - spin_unlock(&tll_lock); - return -ENODEV; - } + for (i = 0; i < tll->nch; i++) + if (!IS_ERR(tll->ch_clk[i])) + clk_put(tll->ch_clk[i]); - tll = dev_get_drvdata(tll_dev); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static int usbtll_runtime_resume(struct device *dev) +{ + struct usbtll_omap *tll = dev_get_drvdata(dev); + struct usbhs_omap_platform_data *pdata = tll->pdata; + int i; - pm_runtime_get_sync(tll_dev); + dev_dbg(dev, "usbtll_runtime_resume\n"); for (i = 0; i < tll->nch; i++) { if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { @@ -431,31 +391,22 @@ int omap_tll_enable(struct usbhs_omap_platform_data *pdata) r = clk_enable(tll->ch_clk[i]); if (r) { - dev_err(tll_dev, + dev_err(dev, "Error enabling ch %d clock: %d\n", i, r); } } } - spin_unlock(&tll_lock); - return 0; } -EXPORT_SYMBOL_GPL(omap_tll_enable); -int omap_tll_disable(struct usbhs_omap_platform_data *pdata) +static int usbtll_runtime_suspend(struct device *dev) { + struct usbtll_omap *tll = dev_get_drvdata(dev); + struct usbhs_omap_platform_data *pdata = tll->pdata; int i; - struct usbtll_omap *tll; - spin_lock(&tll_lock); - - if (!tll_dev) { - spin_unlock(&tll_lock); - return -ENODEV; - } - - tll = dev_get_drvdata(tll_dev); + dev_dbg(dev, "usbtll_runtime_suspend\n"); for (i = 0; i < tll->nch; i++) { if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { @@ -464,16 +415,64 @@ int omap_tll_disable(struct usbhs_omap_platform_data *pdata) } } - pm_runtime_put_sync(tll_dev); + return 0; +} + +static const struct dev_pm_ops usbtllomap_dev_pm_ops = { + SET_RUNTIME_PM_OPS(usbtll_runtime_suspend, + usbtll_runtime_resume, + NULL) +}; + +static struct platform_driver usbtll_omap_driver = { + .driver = { + .name = (char *)usbtll_driver_name, + .owner = THIS_MODULE, + .pm = &usbtllomap_dev_pm_ops, + }, + .probe = usbtll_omap_probe, + .remove = usbtll_omap_remove, +}; + +int omap_tll_enable(void) +{ + int ret; + + spin_lock(&tll_lock); + + if (!tll_dev) { + pr_err("%s: OMAP USB TLL not initialized\n", __func__); + ret = -ENODEV; + } else { + ret = pm_runtime_get_sync(tll_dev); + } + + spin_unlock(&tll_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(omap_tll_enable); + +int omap_tll_disable(void) +{ + int ret; + + spin_lock(&tll_lock); + + if (!tll_dev) { + pr_err("%s: OMAP USB TLL not initialized\n", __func__); + ret = -ENODEV; + } else { + ret = pm_runtime_put_sync(tll_dev); + } spin_unlock(&tll_lock); - return 0; + return ret; } EXPORT_SYMBOL_GPL(omap_tll_disable); MODULE_AUTHOR("Keshava Munegowda "); -MODULE_AUTHOR("Roger Quadros "); MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); diff --git a/trunk/drivers/mfd/omap-usb.h b/trunk/drivers/mfd/omap-usb.h index 2a508b6aeac8..972aa961b064 100644 --- a/trunk/drivers/mfd/omap-usb.h +++ b/trunk/drivers/mfd/omap-usb.h @@ -1,3 +1,2 @@ -extern int omap_tll_init(struct usbhs_omap_platform_data *pdata); -extern int omap_tll_enable(struct usbhs_omap_platform_data *pdata); -extern int omap_tll_disable(struct usbhs_omap_platform_data *pdata); +extern int omap_tll_enable(void); +extern int omap_tll_disable(void); diff --git a/trunk/drivers/mfd/palmas.c b/trunk/drivers/mfd/palmas.c index 53e9fe638d32..73bf76df1044 100644 --- a/trunk/drivers/mfd/palmas.c +++ b/trunk/drivers/mfd/palmas.c @@ -278,20 +278,20 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c, int ret; u32 prop; - ret = of_property_read_u32(node, "ti,mux-pad1", &prop); + ret = of_property_read_u32(node, "ti,mux_pad1", &prop); if (!ret) { pdata->mux_from_pdata = 1; pdata->pad1 = prop; } - ret = of_property_read_u32(node, "ti,mux-pad2", &prop); + ret = of_property_read_u32(node, "ti,mux_pad2", &prop); if (!ret) { pdata->mux_from_pdata = 1; pdata->pad2 = prop; } /* The default for this register is all masked */ - ret = of_property_read_u32(node, "ti,power-ctrl", &prop); + ret = of_property_read_u32(node, "ti,power_ctrl", &prop); if (!ret) pdata->power_ctrl = prop; else @@ -349,7 +349,6 @@ static int palmas_i2c_probe(struct i2c_client *i2c, ret = -ENOMEM; goto err; } - palmas->i2c_clients[i]->dev.of_node = of_node_get(node); } palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], &palmas_regmap_config[i]); diff --git a/trunk/drivers/mfd/retu-mfd.c b/trunk/drivers/mfd/retu-mfd.c index a1830986eeb7..3ba048655bf3 100644 --- a/trunk/drivers/mfd/retu-mfd.c +++ b/trunk/drivers/mfd/retu-mfd.c @@ -1,5 +1,5 @@ /* - * Retu/Tahvo MFD driver + * Retu MFD driver * * Copyright (C) 2004, 2005 Nokia Corporation * @@ -33,8 +33,7 @@ #define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ #define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ #define RETU_REG_IDR 0x01 /* Interrupt ID */ -#define RETU_REG_IMR 0x02 /* Interrupt mask (Retu) */ -#define TAHVO_REG_IMR 0x03 /* Interrupt mask (Tahvo) */ +#define RETU_REG_IMR 0x02 /* Interrupt mask */ /* Interrupt sources */ #define RETU_INT_PWR 0 /* Power button */ @@ -85,62 +84,6 @@ static struct regmap_irq_chip retu_irq_chip = { /* Retu device registered for the power off. */ static struct retu_dev *retu_pm_power_off; -static struct resource tahvo_usb_res[] = { - { - .name = "tahvo-usb", - .start = TAHVO_INT_VBUS, - .end = TAHVO_INT_VBUS, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct mfd_cell tahvo_devs[] = { - { - .name = "tahvo-usb", - .resources = tahvo_usb_res, - .num_resources = ARRAY_SIZE(tahvo_usb_res), - }, -}; - -static struct regmap_irq tahvo_irqs[] = { - [TAHVO_INT_VBUS] = { - .mask = 1 << TAHVO_INT_VBUS, - } -}; - -static struct regmap_irq_chip tahvo_irq_chip = { - .name = "TAHVO", - .irqs = tahvo_irqs, - .num_irqs = ARRAY_SIZE(tahvo_irqs), - .num_regs = 1, - .status_base = RETU_REG_IDR, - .mask_base = TAHVO_REG_IMR, - .ack_base = RETU_REG_IDR, -}; - -static const struct retu_data { - char *chip_name; - char *companion_name; - struct regmap_irq_chip *irq_chip; - struct mfd_cell *children; - int nchildren; -} retu_data[] = { - [0] = { - .chip_name = "Retu", - .companion_name = "Vilma", - .irq_chip = &retu_irq_chip, - .children = retu_devs, - .nchildren = ARRAY_SIZE(retu_devs), - }, - [1] = { - .chip_name = "Tahvo", - .companion_name = "Betty", - .irq_chip = &tahvo_irq_chip, - .children = tahvo_devs, - .nchildren = ARRAY_SIZE(tahvo_devs), - } -}; - int retu_read(struct retu_dev *rdev, u8 reg) { int ret; @@ -230,14 +173,9 @@ static struct regmap_config retu_config = { static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct retu_data const *rdat; struct retu_dev *rdev; int ret; - if (i2c->addr > ARRAY_SIZE(retu_data)) - return -ENODEV; - rdat = &retu_data[i2c->addr - 1]; - rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); if (rdev == NULL) return -ENOMEM; @@ -252,27 +190,25 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) ret = retu_read(rdev, RETU_REG_ASICR); if (ret < 0) { - dev_err(rdev->dev, "could not read %s revision: %d\n", - rdat->chip_name, ret); + dev_err(rdev->dev, "could not read Retu revision: %d\n", ret); return ret; } - dev_info(rdev->dev, "%s%s%s v%d.%d found\n", rdat->chip_name, - (ret & RETU_REG_ASICR_VILMA) ? " & " : "", - (ret & RETU_REG_ASICR_VILMA) ? rdat->companion_name : "", + dev_info(rdev->dev, "Retu%s v%d.%d found\n", + (ret & RETU_REG_ASICR_VILMA) ? " & Vilma" : "", (ret >> 4) & 0x7, ret & 0xf); - /* Mask all interrupts. */ - ret = retu_write(rdev, rdat->irq_chip->mask_base, 0xffff); + /* Mask all RETU interrupts. */ + ret = retu_write(rdev, RETU_REG_IMR, 0xffff); if (ret < 0) return ret; ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, - rdat->irq_chip, &rdev->irq_data); + &retu_irq_chip, &rdev->irq_data); if (ret < 0) return ret; - ret = mfd_add_devices(rdev->dev, -1, rdat->children, rdat->nchildren, + ret = mfd_add_devices(rdev->dev, -1, retu_devs, ARRAY_SIZE(retu_devs), NULL, regmap_irq_chip_get_base(rdev->irq_data), NULL); if (ret < 0) { @@ -280,7 +216,7 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return ret; } - if (i2c->addr == 1 && !pm_power_off) { + if (!pm_power_off) { retu_pm_power_off = rdev; pm_power_off = retu_power_off; } @@ -304,7 +240,6 @@ static int retu_remove(struct i2c_client *i2c) static const struct i2c_device_id retu_id[] = { { "retu-mfd", 0 }, - { "tahvo-mfd", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, retu_id); diff --git a/trunk/drivers/mfd/rts5249.c b/trunk/drivers/mfd/rts5249.c deleted file mode 100644 index 15dc848bc081..000000000000 --- a/trunk/drivers/mfd/rts5249.c +++ /dev/null @@ -1,241 +0,0 @@ -/* Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - * No. 128, West Shenhu Road, Suzhou Industry Park, Suzhou, China - */ - -#include -#include -#include - -#include "rtsx_pcr.h" - -static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr) -{ - u8 val; - - rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); - return val & 0x0F; -} - -static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) -{ - rtsx_pci_init_cmd(pcr); - - /* Configure GPIO as output */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); - /* Switch LDO3318 source from DV33 to card_3v3 */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); - /* LED shine disabled, set initial shine cycle period */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); - /* Correct driving */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CLK_DRIVE_SEL, 0xFF, 0x99); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CMD_DRIVE_SEL, 0xFF, 0x99); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_DAT_DRIVE_SEL, 0xFF, 0x92); - - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5249_optimize_phy(struct rtsx_pcr *pcr) -{ - int err; - - err = rtsx_pci_write_phy_register(pcr, PHY_REG_REV, 0xFE46); - if (err < 0) - return err; - - msleep(1); - - return rtsx_pci_write_phy_register(pcr, PHY_BPCR, 0x05C0); -} - -static int rts5249_turn_on_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); -} - -static int rts5249_turn_off_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); -} - -static int rts5249_enable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); -} - -static int rts5249_disable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); -} - -static int rts5249_card_power_on(struct rtsx_pcr *pcr, int card) -{ - int err; - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_VCC_PARTIAL_POWER_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x02); - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - msleep(5); - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_VCC_POWER_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x06); - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - return 0; -} - -static int rts5249_card_power_off(struct rtsx_pcr *pcr, int card) -{ - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_POWER_OFF); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x00); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) -{ - int err; - u8 clk_drive, cmd_drive, dat_drive; - - if (voltage == OUTPUT_3V3) { - err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4FC0 | 0x24); - if (err < 0) - return err; - clk_drive = 0x99; - cmd_drive = 0x99; - dat_drive = 0x92; - } else if (voltage == OUTPUT_1V8) { - err = rtsx_pci_write_phy_register(pcr, PHY_BACR, 0x3C02); - if (err < 0) - return err; - err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4C40 | 0x24); - if (err < 0) - return err; - clk_drive = 0xb3; - cmd_drive = 0xb3; - dat_drive = 0xb3; - } else { - return -EINVAL; - } - - /* set pad drive */ - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, - 0xFF, clk_drive); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, - 0xFF, cmd_drive); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, - 0xFF, dat_drive); - return rtsx_pci_send_cmd(pcr, 100); -} - -static const struct pcr_ops rts5249_pcr_ops = { - .extra_init_hw = rts5249_extra_init_hw, - .optimize_phy = rts5249_optimize_phy, - .turn_on_led = rts5249_turn_on_led, - .turn_off_led = rts5249_turn_off_led, - .enable_auto_blink = rts5249_enable_auto_blink, - .disable_auto_blink = rts5249_disable_auto_blink, - .card_power_on = rts5249_card_power_on, - .card_power_off = rts5249_card_power_off, - .switch_output_voltage = rts5249_switch_output_voltage, -}; - -/* SD Pull Control Enable: - * SD_DAT[3:0] ==> pull up - * SD_CD ==> pull up - * SD_WP ==> pull up - * SD_CMD ==> pull up - * SD_CLK ==> pull down - */ -static const u32 rts5249_sd_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA), - 0, -}; - -/* SD Pull Control Disable: - * SD_DAT[3:0] ==> pull down - * SD_CD ==> pull up - * SD_WP ==> pull down - * SD_CMD ==> pull down - * SD_CLK ==> pull down - */ -static const u32 rts5249_sd_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), - 0, -}; - -/* MS Pull Control Enable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5249_ms_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -/* MS Pull Control Disable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5249_ms_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -void rts5249_init_params(struct rtsx_pcr *pcr) -{ - pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; - pcr->num_slots = 2; - pcr->ops = &rts5249_pcr_ops; - - pcr->ic_version = rts5249_get_ic_version(pcr); - pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl; - pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl; - pcr->ms_pull_ctl_enable_tbl = rts5249_ms_pull_ctl_enable_tbl; - pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl; -} diff --git a/trunk/drivers/mfd/rtsx_pcr.c b/trunk/drivers/mfd/rtsx_pcr.c index e968c01ca2ac..2f12cc13489a 100644 --- a/trunk/drivers/mfd/rtsx_pcr.c +++ b/trunk/drivers/mfd/rtsx_pcr.c @@ -56,7 +56,6 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = { { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { 0, } }; @@ -1034,10 +1033,6 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) case 0x5227: rts5227_init_params(pcr); break; - - case 0x5249: - rts5249_init_params(pcr); - break; } dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", @@ -1143,7 +1138,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, ret = rtsx_pci_acquire_irq(pcr); if (ret < 0) - goto disable_msi; + goto free_dma; pci_set_master(pcidev); synchronize_irq(pcr->irq); @@ -1167,9 +1162,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, disable_irq: free_irq(pcr->irq, (void *)pcr); -disable_msi: - if (pcr->msi_en) - pci_disable_msi(pcr->pci); +free_dma: dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); unmap: diff --git a/trunk/drivers/mfd/rtsx_pcr.h b/trunk/drivers/mfd/rtsx_pcr.h index 55fcfc25c4e4..2b3ab8a04823 100644 --- a/trunk/drivers/mfd/rtsx_pcr.h +++ b/trunk/drivers/mfd/rtsx_pcr.h @@ -32,6 +32,5 @@ void rts5209_init_params(struct rtsx_pcr *pcr); void rts5229_init_params(struct rtsx_pcr *pcr); void rtl8411_init_params(struct rtsx_pcr *pcr); void rts5227_init_params(struct rtsx_pcr *pcr); -void rts5249_init_params(struct rtsx_pcr *pcr); #endif diff --git a/trunk/drivers/mfd/si476x-cmd.c b/trunk/drivers/mfd/si476x-cmd.c deleted file mode 100644 index de48b4e88450..000000000000 --- a/trunk/drivers/mfd/si476x-cmd.c +++ /dev/null @@ -1,1553 +0,0 @@ -/* - * drivers/mfd/si476x-cmd.c -- Subroutines implementing command - * protocol of si476x series of chips - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * 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; version 2 of the License. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -#define msb(x) ((u8)((u16) x >> 8)) -#define lsb(x) ((u8)((u16) x & 0x00FF)) - - - -#define CMD_POWER_UP 0x01 -#define CMD_POWER_UP_A10_NRESP 1 -#define CMD_POWER_UP_A10_NARGS 5 - -#define CMD_POWER_UP_A20_NRESP 1 -#define CMD_POWER_UP_A20_NARGS 5 - -#define POWER_UP_DELAY_MS 110 - -#define CMD_POWER_DOWN 0x11 -#define CMD_POWER_DOWN_A10_NRESP 1 - -#define CMD_POWER_DOWN_A20_NRESP 1 -#define CMD_POWER_DOWN_A20_NARGS 1 - -#define CMD_FUNC_INFO 0x12 -#define CMD_FUNC_INFO_NRESP 7 - -#define CMD_SET_PROPERTY 0x13 -#define CMD_SET_PROPERTY_NARGS 5 -#define CMD_SET_PROPERTY_NRESP 1 - -#define CMD_GET_PROPERTY 0x14 -#define CMD_GET_PROPERTY_NARGS 3 -#define CMD_GET_PROPERTY_NRESP 4 - -#define CMD_AGC_STATUS 0x17 -#define CMD_AGC_STATUS_NRESP_A10 2 -#define CMD_AGC_STATUS_NRESP_A20 6 - -#define PIN_CFG_BYTE(x) (0x7F & (x)) -#define CMD_DIG_AUDIO_PIN_CFG 0x18 -#define CMD_DIG_AUDIO_PIN_CFG_NARGS 4 -#define CMD_DIG_AUDIO_PIN_CFG_NRESP 5 - -#define CMD_ZIF_PIN_CFG 0x19 -#define CMD_ZIF_PIN_CFG_NARGS 4 -#define CMD_ZIF_PIN_CFG_NRESP 5 - -#define CMD_IC_LINK_GPO_CTL_PIN_CFG 0x1A -#define CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS 4 -#define CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP 5 - -#define CMD_ANA_AUDIO_PIN_CFG 0x1B -#define CMD_ANA_AUDIO_PIN_CFG_NARGS 1 -#define CMD_ANA_AUDIO_PIN_CFG_NRESP 2 - -#define CMD_INTB_PIN_CFG 0x1C -#define CMD_INTB_PIN_CFG_NARGS 2 -#define CMD_INTB_PIN_CFG_A10_NRESP 6 -#define CMD_INTB_PIN_CFG_A20_NRESP 3 - -#define CMD_FM_TUNE_FREQ 0x30 -#define CMD_FM_TUNE_FREQ_A10_NARGS 5 -#define CMD_FM_TUNE_FREQ_A20_NARGS 3 -#define CMD_FM_TUNE_FREQ_NRESP 1 - -#define CMD_FM_RSQ_STATUS 0x32 - -#define CMD_FM_RSQ_STATUS_A10_NARGS 1 -#define CMD_FM_RSQ_STATUS_A10_NRESP 17 -#define CMD_FM_RSQ_STATUS_A30_NARGS 1 -#define CMD_FM_RSQ_STATUS_A30_NRESP 23 - - -#define CMD_FM_SEEK_START 0x31 -#define CMD_FM_SEEK_START_NARGS 1 -#define CMD_FM_SEEK_START_NRESP 1 - -#define CMD_FM_RDS_STATUS 0x36 -#define CMD_FM_RDS_STATUS_NARGS 1 -#define CMD_FM_RDS_STATUS_NRESP 16 - -#define CMD_FM_RDS_BLOCKCOUNT 0x37 -#define CMD_FM_RDS_BLOCKCOUNT_NARGS 1 -#define CMD_FM_RDS_BLOCKCOUNT_NRESP 8 - -#define CMD_FM_PHASE_DIVERSITY 0x38 -#define CMD_FM_PHASE_DIVERSITY_NARGS 1 -#define CMD_FM_PHASE_DIVERSITY_NRESP 1 - -#define CMD_FM_PHASE_DIV_STATUS 0x39 -#define CMD_FM_PHASE_DIV_STATUS_NRESP 2 - -#define CMD_AM_TUNE_FREQ 0x40 -#define CMD_AM_TUNE_FREQ_NARGS 3 -#define CMD_AM_TUNE_FREQ_NRESP 1 - -#define CMD_AM_RSQ_STATUS 0x42 -#define CMD_AM_RSQ_STATUS_NARGS 1 -#define CMD_AM_RSQ_STATUS_NRESP 13 - -#define CMD_AM_SEEK_START 0x41 -#define CMD_AM_SEEK_START_NARGS 1 -#define CMD_AM_SEEK_START_NRESP 1 - - -#define CMD_AM_ACF_STATUS 0x45 -#define CMD_AM_ACF_STATUS_NRESP 6 -#define CMD_AM_ACF_STATUS_NARGS 1 - -#define CMD_FM_ACF_STATUS 0x35 -#define CMD_FM_ACF_STATUS_NRESP 8 -#define CMD_FM_ACF_STATUS_NARGS 1 - -#define CMD_MAX_ARGS_COUNT (10) - - -enum si476x_acf_status_report_bits { - SI476X_ACF_BLEND_INT = (1 << 4), - SI476X_ACF_HIBLEND_INT = (1 << 3), - SI476X_ACF_HICUT_INT = (1 << 2), - SI476X_ACF_CHBW_INT = (1 << 1), - SI476X_ACF_SOFTMUTE_INT = (1 << 0), - - SI476X_ACF_SMUTE = (1 << 0), - SI476X_ACF_SMATTN = 0b11111, - SI476X_ACF_PILOT = (1 << 7), - SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT, -}; - -enum si476x_agc_status_report_bits { - SI476X_AGC_MXHI = (1 << 5), - SI476X_AGC_MXLO = (1 << 4), - SI476X_AGC_LNAHI = (1 << 3), - SI476X_AGC_LNALO = (1 << 2), -}; - -enum si476x_errors { - SI476X_ERR_BAD_COMMAND = 0x10, - SI476X_ERR_BAD_ARG1 = 0x11, - SI476X_ERR_BAD_ARG2 = 0x12, - SI476X_ERR_BAD_ARG3 = 0x13, - SI476X_ERR_BAD_ARG4 = 0x14, - SI476X_ERR_BUSY = 0x18, - SI476X_ERR_BAD_INTERNAL_MEMORY = 0x20, - SI476X_ERR_BAD_PATCH = 0x30, - SI476X_ERR_BAD_BOOT_MODE = 0x31, - SI476X_ERR_BAD_PROPERTY = 0x40, -}; - -static int si476x_core_parse_and_nag_about_error(struct si476x_core *core) -{ - int err; - char *cause; - u8 buffer[2]; - - if (core->revision != SI476X_REVISION_A10) { - err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, - buffer, sizeof(buffer)); - if (err == sizeof(buffer)) { - switch (buffer[1]) { - case SI476X_ERR_BAD_COMMAND: - cause = "Bad command"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_ARG1: - cause = "Bad argument #1"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_ARG2: - cause = "Bad argument #2"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_ARG3: - cause = "Bad argument #3"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_ARG4: - cause = "Bad argument #4"; - err = -EINVAL; - break; - case SI476X_ERR_BUSY: - cause = "Chip is busy"; - err = -EBUSY; - break; - case SI476X_ERR_BAD_INTERNAL_MEMORY: - cause = "Bad internal memory"; - err = -EIO; - break; - case SI476X_ERR_BAD_PATCH: - cause = "Bad patch"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_BOOT_MODE: - cause = "Bad boot mode"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_PROPERTY: - cause = "Bad property"; - err = -EINVAL; - break; - default: - cause = "Unknown"; - err = -EIO; - } - - dev_err(&core->client->dev, - "[Chip error status]: %s\n", cause); - } else { - dev_err(&core->client->dev, - "Failed to fetch error code\n"); - err = (err >= 0) ? -EIO : err; - } - } else { - err = -EIO; - } - - return err; -} - -/** - * si476x_core_send_command() - sends a command to si476x and waits its - * response - * @core: si476x_device structure for the device we are - * communicating with - * @command: command id - * @args: command arguments we are sending - * @argn: actual size of @args - * @response: buffer to place the expected response from the device - * @respn: actual size of @response - * @usecs: amount of time to wait before reading the response (in - * usecs) - * - * Function returns 0 on succsess and negative error code on - * failure - */ -static int si476x_core_send_command(struct si476x_core *core, - const u8 command, - const u8 args[], - const int argn, - u8 resp[], - const int respn, - const int usecs) -{ - struct i2c_client *client = core->client; - int err; - u8 data[CMD_MAX_ARGS_COUNT + 1]; - - if (argn > CMD_MAX_ARGS_COUNT) { - err = -ENOMEM; - goto exit; - } - - if (!client->adapter) { - err = -ENODEV; - goto exit; - } - - /* First send the command and its arguments */ - data[0] = command; - memcpy(&data[1], args, argn); - dev_dbg(&client->dev, "Command:\n %*ph\n", argn + 1, data); - - err = si476x_core_i2c_xfer(core, SI476X_I2C_SEND, - (char *) data, argn + 1); - if (err != argn + 1) { - dev_err(&core->client->dev, - "Error while sending command 0x%02x\n", - command); - err = (err >= 0) ? -EIO : err; - goto exit; - } - /* Set CTS to zero only after the command is send to avoid - * possible racing conditions when working in polling mode */ - atomic_set(&core->cts, 0); - - /* if (unlikely(command == CMD_POWER_DOWN) */ - if (!wait_event_timeout(core->command, - atomic_read(&core->cts), - usecs_to_jiffies(usecs) + 1)) - dev_warn(&core->client->dev, - "(%s) [CMD 0x%02x] Answer timeout.\n", - __func__, command); - - /* - When working in polling mode, for some reason the tuner will - report CTS bit as being set in the first status byte read, - but all the consequtive ones will return zeros until the - tuner is actually completed the POWER_UP command. To - workaround that we wait for second CTS to be reported - */ - if (unlikely(!core->client->irq && command == CMD_POWER_UP)) { - if (!wait_event_timeout(core->command, - atomic_read(&core->cts), - usecs_to_jiffies(usecs) + 1)) - dev_warn(&core->client->dev, - "(%s) Power up took too much time.\n", - __func__); - } - - /* Then get the response */ - err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, resp, respn); - if (err != respn) { - dev_err(&core->client->dev, - "Error while reading response for command 0x%02x\n", - command); - err = (err >= 0) ? -EIO : err; - goto exit; - } - dev_dbg(&client->dev, "Response:\n %*ph\n", respn, resp); - - err = 0; - - if (resp[0] & SI476X_ERR) { - dev_err(&core->client->dev, - "[CMD 0x%02x] Chip set error flag\n", command); - err = si476x_core_parse_and_nag_about_error(core); - goto exit; - } - - if (!(resp[0] & SI476X_CTS)) - err = -EBUSY; -exit: - return err; -} - -static int si476x_cmd_clear_stc(struct si476x_core *core) -{ - int err; - struct si476x_rsq_status_args args = { - .primary = false, - .rsqack = false, - .attune = false, - .cancel = false, - .stcack = true, - }; - - switch (core->power_up_parameters.func) { - case SI476X_FUNC_FM_RECEIVER: - err = si476x_core_cmd_fm_rsq_status(core, &args, NULL); - break; - case SI476X_FUNC_AM_RECEIVER: - err = si476x_core_cmd_am_rsq_status(core, &args, NULL); - break; - default: - err = -EINVAL; - } - - return err; -} - -static int si476x_cmd_tune_seek_freq(struct si476x_core *core, - uint8_t cmd, - const uint8_t args[], size_t argn, - uint8_t *resp, size_t respn) -{ - int err; - - - atomic_set(&core->stc, 0); - err = si476x_core_send_command(core, cmd, args, argn, resp, respn, - SI476X_TIMEOUT_TUNE); - if (!err) { - wait_event_killable(core->tuning, - atomic_read(&core->stc)); - si476x_cmd_clear_stc(core); - } - - return err; -} - -/** - * si476x_cmd_func_info() - send 'FUNC_INFO' command to the device - * @core: device to send the command to - * @info: struct si476x_func_info to fill all the information - * returned by the command - * - * The command requests the firmware and patch version for currently - * loaded firmware (dependent on the function of the device FM/AM/WB) - * - * Function returns 0 on succsess and negative error code on - * failure - */ -int si476x_core_cmd_func_info(struct si476x_core *core, - struct si476x_func_info *info) -{ - int err; - u8 resp[CMD_FUNC_INFO_NRESP]; - - err = si476x_core_send_command(core, CMD_FUNC_INFO, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - - info->firmware.major = resp[1]; - info->firmware.minor[0] = resp[2]; - info->firmware.minor[1] = resp[3]; - - info->patch_id = ((u16) resp[4] << 8) | resp[5]; - info->func = resp[6]; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info); - -/** - * si476x_cmd_set_property() - send 'SET_PROPERTY' command to the device - * @core: device to send the command to - * @property: property address - * @value: property value - * - * Function returns 0 on succsess and negative error code on - * failure - */ -int si476x_core_cmd_set_property(struct si476x_core *core, - u16 property, u16 value) -{ - u8 resp[CMD_SET_PROPERTY_NRESP]; - const u8 args[CMD_SET_PROPERTY_NARGS] = { - 0x00, - msb(property), - lsb(property), - msb(value), - lsb(value), - }; - - return si476x_core_send_command(core, CMD_SET_PROPERTY, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_set_property); - -/** - * si476x_cmd_get_property() - send 'GET_PROPERTY' command to the device - * @core: device to send the command to - * @property: property address - * - * Function return the value of property as u16 on success or a - * negative error on failure - */ -int si476x_core_cmd_get_property(struct si476x_core *core, u16 property) -{ - int err; - u8 resp[CMD_GET_PROPERTY_NRESP]; - const u8 args[CMD_GET_PROPERTY_NARGS] = { - 0x00, - msb(property), - lsb(property), - }; - - err = si476x_core_send_command(core, CMD_GET_PROPERTY, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - else - return be16_to_cpup((__be16 *)(resp + 2)); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); - -/** - * si476x_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to - * the device - * @core: device to send the command to - * @dclk: DCLK pin function configuration: - * #SI476X_DCLK_NOOP - do not modify the behaviour - * #SI476X_DCLK_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * #SI476X_DCLK_DAUDIO - set the pin to be a part of digital - * audio interface - * @dfs: DFS pin function configuration: - * #SI476X_DFS_NOOP - do not modify the behaviour - * #SI476X_DFS_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_DFS_DAUDIO - set the pin to be a part of digital - * audio interface - * @dout - DOUT pin function configuration: - * SI476X_DOUT_NOOP - do not modify the behaviour - * SI476X_DOUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_DOUT_I2S_OUTPUT - set this pin to be digital out on I2S - * port 1 - * SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S - * port 1 - * @xout - XOUT pin function configuration: - * SI476X_XOUT_NOOP - do not modify the behaviour - * SI476X_XOUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_XOUT_I2S_INPUT - set this pin to be digital in on I2S - * port 1 - * SI476X_XOUT_MODE_SELECT - set this pin to be the input that - * selects the mode of the I2S audio - * combiner (analog or HD) - * [SI4761/63/65/67 Only] - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core, - enum si476x_dclk_config dclk, - enum si476x_dfs_config dfs, - enum si476x_dout_config dout, - enum si476x_xout_config xout) -{ - u8 resp[CMD_DIG_AUDIO_PIN_CFG_NRESP]; - const u8 args[CMD_DIG_AUDIO_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(dclk), - PIN_CFG_BYTE(dfs), - PIN_CFG_BYTE(dout), - PIN_CFG_BYTE(xout), - }; - - return si476x_core_send_command(core, CMD_DIG_AUDIO_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); - -/** - * si476x_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND' - * @core - device to send the command to - * @iqclk - IQCL pin function configuration: - * SI476X_IQCLK_NOOP - do not modify the behaviour - * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_IQCLK_IQ - set pin to be a part of I/Q interace - * in master mode - * @iqfs - IQFS pin function configuration: - * SI476X_IQFS_NOOP - do not modify the behaviour - * SI476X_IQFS_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_IQFS_IQ - set pin to be a part of I/Q interace - * in master mode - * @iout - IOUT pin function configuration: - * SI476X_IOUT_NOOP - do not modify the behaviour - * SI476X_IOUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_IOUT_OUTPUT - set pin to be I out - * @qout - QOUT pin function configuration: - * SI476X_QOUT_NOOP - do not modify the behaviour - * SI476X_QOUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_QOUT_OUTPUT - set pin to be Q out - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_zif_pin_cfg(struct si476x_core *core, - enum si476x_iqclk_config iqclk, - enum si476x_iqfs_config iqfs, - enum si476x_iout_config iout, - enum si476x_qout_config qout) -{ - u8 resp[CMD_ZIF_PIN_CFG_NRESP]; - const u8 args[CMD_ZIF_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(iqclk), - PIN_CFG_BYTE(iqfs), - PIN_CFG_BYTE(iout), - PIN_CFG_BYTE(qout), - }; - - return si476x_core_send_command(core, CMD_ZIF_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); - -/** - * si476x_cmd_ic_link_gpo_ctl_pin_cfg - send - * 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device - * @core - device to send the command to - * @icin - ICIN pin function configuration: - * SI476X_ICIN_NOOP - do not modify the behaviour - * SI476X_ICIN_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high - * SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low - * SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link - * @icip - ICIP pin function configuration: - * SI476X_ICIP_NOOP - do not modify the behaviour - * SI476X_ICIP_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high - * SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low - * SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link - * @icon - ICON pin function configuration: - * SI476X_ICON_NOOP - do not modify the behaviour - * SI476X_ICON_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_ICON_I2S - set the pin to be a part of audio - * interface in slave mode (DCLK) - * SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link - * @icop - ICOP pin function configuration: - * SI476X_ICOP_NOOP - do not modify the behaviour - * SI476X_ICOP_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_ICOP_I2S - set the pin to be a part of audio - * interface in slave mode (DOUT) - * [Si4761/63/65/67 Only] - * SI476X_ICOP_IC_LINK - set the pin to be a part of Inter-Chip link - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core, - enum si476x_icin_config icin, - enum si476x_icip_config icip, - enum si476x_icon_config icon, - enum si476x_icop_config icop) -{ - u8 resp[CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP]; - const u8 args[CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(icin), - PIN_CFG_BYTE(icip), - PIN_CFG_BYTE(icon), - PIN_CFG_BYTE(icop), - }; - - return si476x_core_send_command(core, CMD_IC_LINK_GPO_CTL_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg); - -/** - * si476x_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the - * device - * @core - device to send the command to - * @lrout - LROUT pin function configuration: - * SI476X_LROUT_NOOP - do not modify the behaviour - * SI476X_LROUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_LROUT_AUDIO - set pin to be audio output - * SI476X_LROUT_MPX - set pin to be MPX output - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *core, - enum si476x_lrout_config lrout) -{ - u8 resp[CMD_ANA_AUDIO_PIN_CFG_NRESP]; - const u8 args[CMD_ANA_AUDIO_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(lrout), - }; - - return si476x_core_send_command(core, CMD_ANA_AUDIO_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg); - - -/** - * si476x_cmd_intb_pin_cfg - send 'INTB_PIN_CFG' command to the device - * @core - device to send the command to - * @intb - INTB pin function configuration: - * SI476X_INTB_NOOP - do not modify the behaviour - * SI476X_INTB_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_INTB_DAUDIO - set pin to be a part of digital - * audio interface in slave mode - * SI476X_INTB_IRQ - set pin to be an interrupt request line - * @a1 - A1 pin function configuration: - * SI476X_A1_NOOP - do not modify the behaviour - * SI476X_A1_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_A1_IRQ - set pin to be an interrupt request line - * - * Function returns 0 on success and negative error code on failure - */ -static int si476x_core_cmd_intb_pin_cfg_a10(struct si476x_core *core, - enum si476x_intb_config intb, - enum si476x_a1_config a1) -{ - u8 resp[CMD_INTB_PIN_CFG_A10_NRESP]; - const u8 args[CMD_INTB_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(intb), - PIN_CFG_BYTE(a1), - }; - - return si476x_core_send_command(core, CMD_INTB_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} - -static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core, - enum si476x_intb_config intb, - enum si476x_a1_config a1) -{ - u8 resp[CMD_INTB_PIN_CFG_A20_NRESP]; - const u8 args[CMD_INTB_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(intb), - PIN_CFG_BYTE(a1), - }; - - return si476x_core_send_command(core, CMD_INTB_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} - - - -/** - * si476x_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the - * device - * @core - device to send the command to - * @rsqack - if set command clears RSQINT, SNRINT, SNRLINT, RSSIHINT, - * RSSSILINT, BLENDINT, MULTHINT and MULTLINT - * @attune - when set the values in the status report are the values - * that were calculated at tune - * @cancel - abort ongoing seek/tune opertation - * @stcack - clear the STCINT bin in status register - * @report - all signal quality information retured by the command - * (if NULL then the output of the command is ignored) - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_am_rsq_status(struct si476x_core *core, - struct si476x_rsq_status_args *rsqargs, - struct si476x_rsq_status_report *report) -{ - int err; - u8 resp[CMD_AM_RSQ_STATUS_NRESP]; - const u8 args[CMD_AM_RSQ_STATUS_NARGS] = { - rsqargs->rsqack << 3 | rsqargs->attune << 2 | - rsqargs->cancel << 1 | rsqargs->stcack, - }; - - err = si476x_core_send_command(core, CMD_AM_RSQ_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting received signal quality information this - * command can be used to just acknowledge different interrupt - * flags in those cases it is useless to copy and parse - * received data so user can pass NULL, and thus avoid - * unnecessary copying. - */ - if (!report) - return err; - - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); - report->freqoff = resp[5]; - report->rssi = resp[6]; - report->snr = resp[7]; - report->lassi = resp[9]; - report->hassi = resp[10]; - report->mult = resp[11]; - report->dev = resp[12]; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_am_rsq_status); - -int si476x_core_cmd_fm_acf_status(struct si476x_core *core, - struct si476x_acf_status_report *report) -{ - int err; - u8 resp[CMD_FM_ACF_STATUS_NRESP]; - const u8 args[CMD_FM_ACF_STATUS_NARGS] = { - 0x0, - }; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_FM_ACF_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - - report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; - report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; - report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; - report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; - report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; - report->smute = resp[2] & SI476X_ACF_SMUTE; - report->smattn = resp[3] & SI476X_ACF_SMATTN; - report->chbw = resp[4]; - report->hicut = resp[5]; - report->hiblend = resp[6]; - report->pilot = resp[7] & SI476X_ACF_PILOT; - report->stblend = resp[7] & SI476X_ACF_STBLEND; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_acf_status); - -int si476x_core_cmd_am_acf_status(struct si476x_core *core, - struct si476x_acf_status_report *report) -{ - int err; - u8 resp[CMD_AM_ACF_STATUS_NRESP]; - const u8 args[CMD_AM_ACF_STATUS_NARGS] = { - 0x0, - }; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_AM_ACF_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - - report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; - report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; - report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; - report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; - report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; - report->smute = resp[2] & SI476X_ACF_SMUTE; - report->smattn = resp[3] & SI476X_ACF_SMATTN; - report->chbw = resp[4]; - report->hicut = resp[5]; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status); - - -/** - * si476x_cmd_fm_seek_start - send 'FM_SEEK_START' command to the - * device - * @core - device to send the command to - * @seekup - if set the direction of the search is 'up' - * @wrap - if set seek wraps when hitting band limit - * - * This function begins search for a valid station. The station is - * considered valid when 'FM_VALID_SNR_THRESHOLD' and - * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria - * are met. -} * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_fm_seek_start(struct si476x_core *core, - bool seekup, bool wrap) -{ - u8 resp[CMD_FM_SEEK_START_NRESP]; - const u8 args[CMD_FM_SEEK_START_NARGS] = { - seekup << 3 | wrap << 2, - }; - - return si476x_cmd_tune_seek_freq(core, CMD_FM_SEEK_START, - args, sizeof(args), - resp, sizeof(resp)); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start); - -/** - * si476x_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the - * device - * @core - device to send the command to - * @status_only - if set the data is not removed from RDSFIFO, - * RDSFIFOUSED is not decremented and data in all the - * rest RDS data contains the last valid info received - * @mtfifo if set the command clears RDS receive FIFO - * @intack if set the command clards the RDSINT bit. - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_fm_rds_status(struct si476x_core *core, - bool status_only, - bool mtfifo, - bool intack, - struct si476x_rds_status_report *report) -{ - int err; - u8 resp[CMD_FM_RDS_STATUS_NRESP]; - const u8 args[CMD_FM_RDS_STATUS_NARGS] = { - status_only << 2 | mtfifo << 1 | intack, - }; - - err = si476x_core_send_command(core, CMD_FM_RDS_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting RDS status information this command can be - * used to just acknowledge different interrupt flags in those - * cases it is useless to copy and parse received data so user - * can pass NULL, and thus avoid unnecessary copying. - */ - if (err < 0 || report == NULL) - return err; - - report->rdstpptyint = 0b00010000 & resp[1]; - report->rdspiint = 0b00001000 & resp[1]; - report->rdssyncint = 0b00000010 & resp[1]; - report->rdsfifoint = 0b00000001 & resp[1]; - - report->tpptyvalid = 0b00010000 & resp[2]; - report->pivalid = 0b00001000 & resp[2]; - report->rdssync = 0b00000010 & resp[2]; - report->rdsfifolost = 0b00000001 & resp[2]; - - report->tp = 0b00100000 & resp[3]; - report->pty = 0b00011111 & resp[3]; - - report->pi = be16_to_cpup((__be16 *)(resp + 4)); - report->rdsfifoused = resp[6]; - - report->ble[V4L2_RDS_BLOCK_A] = 0b11000000 & resp[7]; - report->ble[V4L2_RDS_BLOCK_B] = 0b00110000 & resp[7]; - report->ble[V4L2_RDS_BLOCK_C] = 0b00001100 & resp[7]; - report->ble[V4L2_RDS_BLOCK_D] = 0b00000011 & resp[7]; - - report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A; - report->rds[V4L2_RDS_BLOCK_A].msb = resp[8]; - report->rds[V4L2_RDS_BLOCK_A].lsb = resp[9]; - - report->rds[V4L2_RDS_BLOCK_B].block = V4L2_RDS_BLOCK_B; - report->rds[V4L2_RDS_BLOCK_B].msb = resp[10]; - report->rds[V4L2_RDS_BLOCK_B].lsb = resp[11]; - - report->rds[V4L2_RDS_BLOCK_C].block = V4L2_RDS_BLOCK_C; - report->rds[V4L2_RDS_BLOCK_C].msb = resp[12]; - report->rds[V4L2_RDS_BLOCK_C].lsb = resp[13]; - - report->rds[V4L2_RDS_BLOCK_D].block = V4L2_RDS_BLOCK_D; - report->rds[V4L2_RDS_BLOCK_D].msb = resp[14]; - report->rds[V4L2_RDS_BLOCK_D].lsb = resp[15]; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_status); - -int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core, - bool clear, - struct si476x_rds_blockcount_report *report) -{ - int err; - u8 resp[CMD_FM_RDS_BLOCKCOUNT_NRESP]; - const u8 args[CMD_FM_RDS_BLOCKCOUNT_NARGS] = { - clear, - }; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_FM_RDS_BLOCKCOUNT, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - - if (!err) { - report->expected = be16_to_cpup((__be16 *)(resp + 2)); - report->received = be16_to_cpup((__be16 *)(resp + 4)); - report->uncorrectable = be16_to_cpup((__be16 *)(resp + 6)); - } - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_blockcount); - -int si476x_core_cmd_fm_phase_diversity(struct si476x_core *core, - enum si476x_phase_diversity_mode mode) -{ - u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP]; - const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = { - mode & 0b111, - }; - - return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); -/** - * si476x_core_cmd_fm_phase_div_status() - get the phase diversity - * status - * - * @core: si476x device - * - * NOTE caller must hold core lock - * - * Function returns the value of the status bit in case of success and - * negative error code in case of failre. - */ -int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core) -{ - int err; - u8 resp[CMD_FM_PHASE_DIV_STATUS_NRESP]; - - err = si476x_core_send_command(core, CMD_FM_PHASE_DIV_STATUS, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - - return (err < 0) ? err : resp[1]; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status); - - -/** - * si476x_cmd_am_seek_start - send 'FM_SEEK_START' command to the - * device - * @core - device to send the command to - * @seekup - if set the direction of the search is 'up' - * @wrap - if set seek wraps when hitting band limit - * - * This function begins search for a valid station. The station is - * considered valid when 'FM_VALID_SNR_THRESHOLD' and - * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria - * are met. - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_am_seek_start(struct si476x_core *core, - bool seekup, bool wrap) -{ - u8 resp[CMD_AM_SEEK_START_NRESP]; - const u8 args[CMD_AM_SEEK_START_NARGS] = { - seekup << 3 | wrap << 2, - }; - - return si476x_cmd_tune_seek_freq(core, CMD_AM_SEEK_START, - args, sizeof(args), - resp, sizeof(resp)); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_am_seek_start); - - - -static int si476x_core_cmd_power_up_a10(struct si476x_core *core, - struct si476x_power_up_args *puargs) -{ - u8 resp[CMD_POWER_UP_A10_NRESP]; - const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); - const bool ctsen = (core->client->irq != 0); - const u8 args[CMD_POWER_UP_A10_NARGS] = { - 0xF7, /* Reserved, always 0xF7 */ - 0x3F & puargs->xcload, /* First two bits are reserved to be - * zeros */ - ctsen << 7 | intsel << 6 | 0x07, /* Last five bits - * are reserved to - * be written as 0x7 */ - puargs->func << 4 | puargs->freq, - 0x11, /* Reserved, always 0x11 */ - }; - - return si476x_core_send_command(core, CMD_POWER_UP, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_TIMEOUT_POWER_UP); -} - -static int si476x_core_cmd_power_up_a20(struct si476x_core *core, - struct si476x_power_up_args *puargs) -{ - u8 resp[CMD_POWER_UP_A20_NRESP]; - const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); - const bool ctsen = (core->client->irq != 0); - const u8 args[CMD_POWER_UP_A20_NARGS] = { - puargs->ibias6x << 7 | puargs->xstart, - 0x3F & puargs->xcload, /* First two bits are reserved to be - * zeros */ - ctsen << 7 | intsel << 6 | puargs->fastboot << 5 | - puargs->xbiashc << 3 | puargs->xbias, - puargs->func << 4 | puargs->freq, - 0x10 | puargs->xmode, - }; - - return si476x_core_send_command(core, CMD_POWER_UP, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_TIMEOUT_POWER_UP); -} - -static int si476x_core_cmd_power_down_a10(struct si476x_core *core, - struct si476x_power_down_args *pdargs) -{ - u8 resp[CMD_POWER_DOWN_A10_NRESP]; - - return si476x_core_send_command(core, CMD_POWER_DOWN, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} - -static int si476x_core_cmd_power_down_a20(struct si476x_core *core, - struct si476x_power_down_args *pdargs) -{ - u8 resp[CMD_POWER_DOWN_A20_NRESP]; - const u8 args[CMD_POWER_DOWN_A20_NARGS] = { - pdargs->xosc, - }; - return si476x_core_send_command(core, CMD_POWER_DOWN, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} - -static int si476x_core_cmd_am_tune_freq_a10(struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs) -{ - - const int am_freq = tuneargs->freq; - u8 resp[CMD_AM_TUNE_FREQ_NRESP]; - const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { - (tuneargs->hd << 6), - msb(am_freq), - lsb(am_freq), - }; - - return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, args, - sizeof(args), - resp, sizeof(resp)); -} - -static int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs) -{ - const int am_freq = tuneargs->freq; - u8 resp[CMD_AM_TUNE_FREQ_NRESP]; - const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { - (tuneargs->zifsr << 6) | (tuneargs->injside & 0b11), - msb(am_freq), - lsb(am_freq), - }; - - return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, - args, sizeof(args), - resp, sizeof(resp)); -} - -static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core, - struct si476x_rsq_status_args *rsqargs, - struct si476x_rsq_status_report *report) -{ - int err; - u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; - const u8 args[CMD_FM_RSQ_STATUS_A10_NARGS] = { - rsqargs->rsqack << 3 | rsqargs->attune << 2 | - rsqargs->cancel << 1 | rsqargs->stcack, - }; - - err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting received signal quality information this - * command can be used to just acknowledge different interrupt - * flags in those cases it is useless to copy and parse - * received data so user can pass NULL, and thus avoid - * unnecessary copying. - */ - if (err < 0 || report == NULL) - return err; - - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); - report->freqoff = resp[5]; - report->rssi = resp[6]; - report->snr = resp[7]; - report->lassi = resp[9]; - report->hassi = resp[10]; - report->mult = resp[11]; - report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); - report->assi = resp[15]; - report->usn = resp[16]; - - return err; -} - -static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core, - struct si476x_rsq_status_args *rsqargs, - struct si476x_rsq_status_report *report) -{ - int err; - u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; - const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { - rsqargs->primary << 4 | rsqargs->rsqack << 3 | - rsqargs->attune << 2 | rsqargs->cancel << 1 | - rsqargs->stcack, - }; - - err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting received signal quality information this - * command can be used to just acknowledge different interrupt - * flags in those cases it is useless to copy and parse - * received data so user can pass NULL, and thus avoid - * unnecessary copying. - */ - if (err < 0 || report == NULL) - return err; - - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); - report->freqoff = resp[5]; - report->rssi = resp[6]; - report->snr = resp[7]; - report->lassi = resp[9]; - report->hassi = resp[10]; - report->mult = resp[11]; - report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); - report->assi = resp[15]; - report->usn = resp[16]; - - return err; -} - - -static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, - struct si476x_rsq_status_args *rsqargs, - struct si476x_rsq_status_report *report) -{ - int err; - u8 resp[CMD_FM_RSQ_STATUS_A30_NRESP]; - const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { - rsqargs->primary << 4 | rsqargs->rsqack << 3 | - rsqargs->attune << 2 | rsqargs->cancel << 1 | - rsqargs->stcack, - }; - - err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting received signal quality information this - * command can be used to just acknowledge different interrupt - * flags in those cases it is useless to copy and parse - * received data so user can pass NULL, and thus avoid - * unnecessary copying. - */ - if (err < 0 || report == NULL) - return err; - - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->injside = 0b00000100 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); - report->freqoff = resp[5]; - report->rssi = resp[6]; - report->snr = resp[7]; - report->issi = resp[8]; - report->lassi = resp[9]; - report->hassi = resp[10]; - report->mult = resp[11]; - report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); - report->assi = resp[15]; - report->usn = resp[16]; - - report->pilotdev = resp[17]; - report->rdsdev = resp[18]; - report->assidev = resp[19]; - report->strongdev = resp[20]; - report->rdspi = be16_to_cpup((__be16 *)(resp + 21)); - - return err; -} - -static int si476x_core_cmd_fm_tune_freq_a10(struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs) -{ - u8 resp[CMD_FM_TUNE_FREQ_NRESP]; - const u8 args[CMD_FM_TUNE_FREQ_A10_NARGS] = { - (tuneargs->hd << 6) | (tuneargs->tunemode << 4) - | (tuneargs->smoothmetrics << 2), - msb(tuneargs->freq), - lsb(tuneargs->freq), - msb(tuneargs->antcap), - lsb(tuneargs->antcap) - }; - - return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, - args, sizeof(args), - resp, sizeof(resp)); -} - -static int si476x_core_cmd_fm_tune_freq_a20(struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs) -{ - u8 resp[CMD_FM_TUNE_FREQ_NRESP]; - const u8 args[CMD_FM_TUNE_FREQ_A20_NARGS] = { - (tuneargs->hd << 6) | (tuneargs->tunemode << 4) - | (tuneargs->smoothmetrics << 2) | (tuneargs->injside), - msb(tuneargs->freq), - lsb(tuneargs->freq), - }; - - return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, - args, sizeof(args), - resp, sizeof(resp)); -} - -static int si476x_core_cmd_agc_status_a20(struct si476x_core *core, - struct si476x_agc_status_report *report) -{ - int err; - u8 resp[CMD_AGC_STATUS_NRESP_A20]; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_AGC_STATUS, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - - report->mxhi = resp[1] & SI476X_AGC_MXHI; - report->mxlo = resp[1] & SI476X_AGC_MXLO; - report->lnahi = resp[1] & SI476X_AGC_LNAHI; - report->lnalo = resp[1] & SI476X_AGC_LNALO; - report->fmagc1 = resp[2]; - report->fmagc2 = resp[3]; - report->pgagain = resp[4]; - report->fmwblang = resp[5]; - - return err; -} - -static int si476x_core_cmd_agc_status_a10(struct si476x_core *core, - struct si476x_agc_status_report *report) -{ - int err; - u8 resp[CMD_AGC_STATUS_NRESP_A10]; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_AGC_STATUS, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - - report->mxhi = resp[1] & SI476X_AGC_MXHI; - report->mxlo = resp[1] & SI476X_AGC_MXLO; - report->lnahi = resp[1] & SI476X_AGC_LNAHI; - report->lnalo = resp[1] & SI476X_AGC_LNALO; - - return err; -} - -typedef int (*tune_freq_func_t) (struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs); - -static struct { - int (*power_up) (struct si476x_core *, - struct si476x_power_up_args *); - int (*power_down) (struct si476x_core *, - struct si476x_power_down_args *); - - tune_freq_func_t fm_tune_freq; - tune_freq_func_t am_tune_freq; - - int (*fm_rsq_status)(struct si476x_core *, - struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); - - int (*agc_status)(struct si476x_core *, - struct si476x_agc_status_report *); - int (*intb_pin_cfg)(struct si476x_core *core, - enum si476x_intb_config intb, - enum si476x_a1_config a1); -} si476x_cmds_vtable[] = { - [SI476X_REVISION_A10] = { - .power_up = si476x_core_cmd_power_up_a10, - .power_down = si476x_core_cmd_power_down_a10, - .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a10, - .am_tune_freq = si476x_core_cmd_am_tune_freq_a10, - .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a10, - .agc_status = si476x_core_cmd_agc_status_a10, - .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a10, - }, - [SI476X_REVISION_A20] = { - .power_up = si476x_core_cmd_power_up_a20, - .power_down = si476x_core_cmd_power_down_a20, - .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, - .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, - .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a20, - .agc_status = si476x_core_cmd_agc_status_a20, - .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, - }, - [SI476X_REVISION_A30] = { - .power_up = si476x_core_cmd_power_up_a20, - .power_down = si476x_core_cmd_power_down_a20, - .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, - .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, - .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a30, - .agc_status = si476x_core_cmd_agc_status_a20, - .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, - }, -}; - -int si476x_core_cmd_power_up(struct si476x_core *core, - struct si476x_power_up_args *args) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].power_up(core, args); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_power_up); - -int si476x_core_cmd_power_down(struct si476x_core *core, - struct si476x_power_down_args *args) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].power_down(core, args); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_power_down); - -int si476x_core_cmd_fm_tune_freq(struct si476x_core *core, - struct si476x_tune_freq_args *args) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].fm_tune_freq(core, args); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_tune_freq); - -int si476x_core_cmd_am_tune_freq(struct si476x_core *core, - struct si476x_tune_freq_args *args) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].am_tune_freq(core, args); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_am_tune_freq); - -int si476x_core_cmd_fm_rsq_status(struct si476x_core *core, - struct si476x_rsq_status_args *args, - struct si476x_rsq_status_report *report) - -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].fm_rsq_status(core, args, - report); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rsq_status); - -int si476x_core_cmd_agc_status(struct si476x_core *core, - struct si476x_agc_status_report *report) - -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].agc_status(core, report); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_agc_status); - -int si476x_core_cmd_intb_pin_cfg(struct si476x_core *core, - enum si476x_intb_config intb, - enum si476x_a1_config a1) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - - return si476x_cmds_vtable[core->revision].intb_pin_cfg(core, intb, a1); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_intb_pin_cfg); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Andrey Smirnov "); -MODULE_DESCRIPTION("API for command exchange for si476x"); diff --git a/trunk/drivers/mfd/si476x-i2c.c b/trunk/drivers/mfd/si476x-i2c.c deleted file mode 100644 index f5bc8e4bd4bf..000000000000 --- a/trunk/drivers/mfd/si476x-i2c.c +++ /dev/null @@ -1,886 +0,0 @@ -/* - * drivers/mfd/si476x-i2c.c -- Core device driver for si476x MFD - * device - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * 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; version 2 of the License. - * - * 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 - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SI476X_MAX_IO_ERRORS 10 -#define SI476X_DRIVER_RDS_FIFO_DEPTH 128 - -/** - * si476x_core_config_pinmux() - pin function configuration function - * - * @core: Core device structure - * - * Configure the functions of the pins of the radio chip. - * - * The function returns zero in case of succes or negative error code - * otherwise. - */ -static int si476x_core_config_pinmux(struct si476x_core *core) -{ - int err; - dev_dbg(&core->client->dev, "Configuring pinmux\n"); - err = si476x_core_cmd_dig_audio_pin_cfg(core, - core->pinmux.dclk, - core->pinmux.dfs, - core->pinmux.dout, - core->pinmux.xout); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure digital audio pins(err = %d)\n", - err); - return err; - } - - err = si476x_core_cmd_zif_pin_cfg(core, - core->pinmux.iqclk, - core->pinmux.iqfs, - core->pinmux.iout, - core->pinmux.qout); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure ZIF pins(err = %d)\n", - err); - return err; - } - - err = si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(core, - core->pinmux.icin, - core->pinmux.icip, - core->pinmux.icon, - core->pinmux.icop); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure IC-Link/GPO pins(err = %d)\n", - err); - return err; - } - - err = si476x_core_cmd_ana_audio_pin_cfg(core, - core->pinmux.lrout); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure analog audio pins(err = %d)\n", - err); - return err; - } - - err = si476x_core_cmd_intb_pin_cfg(core, - core->pinmux.intb, - core->pinmux.a1); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure interrupt pins(err = %d)\n", - err); - return err; - } - - return 0; -} - -static inline void si476x_core_schedule_polling_work(struct si476x_core *core) -{ - schedule_delayed_work(&core->status_monitor, - usecs_to_jiffies(SI476X_STATUS_POLL_US)); -} - -/** - * si476x_core_start() - early chip startup function - * @core: Core device structure - * @soft: When set, this flag forces "soft" startup, where "soft" - * power down is the one done by sending appropriate command instead - * of using reset pin of the tuner - * - * Perform required startup sequence to correctly power - * up the chip and perform initial configuration. It does the - * following sequence of actions: - * 1. Claims and enables the power supplies VD and VIO1 required - * for I2C interface of the chip operation. - * 2. Waits for 100us, pulls the reset line up, enables irq, - * waits for another 100us as it is specified by the - * datasheet. - * 3. Sends 'POWER_UP' command to the device with all provided - * information about power-up parameters. - * 4. Configures, pin multiplexor, disables digital audio and - * configures interrupt sources. - * - * The function returns zero in case of succes or negative error code - * otherwise. - */ -int si476x_core_start(struct si476x_core *core, bool soft) -{ - struct i2c_client *client = core->client; - int err; - - if (!soft) { - if (gpio_is_valid(core->gpio_reset)) - gpio_set_value_cansleep(core->gpio_reset, 1); - - if (client->irq) - enable_irq(client->irq); - - udelay(100); - - if (!client->irq) { - atomic_set(&core->is_alive, 1); - si476x_core_schedule_polling_work(core); - } - } else { - if (client->irq) - enable_irq(client->irq); - else { - atomic_set(&core->is_alive, 1); - si476x_core_schedule_polling_work(core); - } - } - - err = si476x_core_cmd_power_up(core, - &core->power_up_parameters); - - if (err < 0) { - dev_err(&core->client->dev, - "Power up failure(err = %d)\n", - err); - goto disable_irq; - } - - if (client->irq) - atomic_set(&core->is_alive, 1); - - err = si476x_core_config_pinmux(core); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure pinmux(err = %d)\n", - err); - goto disable_irq; - } - - if (client->irq) { - err = regmap_write(core->regmap, - SI476X_PROP_INT_CTL_ENABLE, - SI476X_RDSIEN | - SI476X_STCIEN | - SI476X_CTSIEN); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure interrupt sources" - "(err = %d)\n", err); - goto disable_irq; - } - } - - return 0; - -disable_irq: - if (err == -ENODEV) - atomic_set(&core->is_alive, 0); - - if (client->irq) - disable_irq(client->irq); - else - cancel_delayed_work_sync(&core->status_monitor); - - if (gpio_is_valid(core->gpio_reset)) - gpio_set_value_cansleep(core->gpio_reset, 0); - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_start); - -/** - * si476x_core_stop() - chip power-down function - * @core: Core device structure - * @soft: When set, function sends a POWER_DOWN command instead of - * bringing reset line low - * - * Power down the chip by performing following actions: - * 1. Disable IRQ or stop the polling worker - * 2. Send the POWER_DOWN command if the power down is soft or bring - * reset line low if not. - * - * The function returns zero in case of succes or negative error code - * otherwise. - */ -int si476x_core_stop(struct si476x_core *core, bool soft) -{ - int err = 0; - atomic_set(&core->is_alive, 0); - - if (soft) { - /* TODO: This probably shoud be a configurable option, - * so it is possible to have the chips keep their - * oscillators running - */ - struct si476x_power_down_args args = { - .xosc = false, - }; - err = si476x_core_cmd_power_down(core, &args); - } - - /* We couldn't disable those before - * 'si476x_core_cmd_power_down' since we expect to get CTS - * interrupt */ - if (core->client->irq) - disable_irq(core->client->irq); - else - cancel_delayed_work_sync(&core->status_monitor); - - if (!soft) { - if (gpio_is_valid(core->gpio_reset)) - gpio_set_value_cansleep(core->gpio_reset, 0); - } - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_stop); - -/** - * si476x_core_set_power_state() - set the level at which the power is - * supplied for the chip. - * @core: Core device structure - * @next_state: enum si476x_power_state describing power state to - * switch to. - * - * Switch on all the required power supplies - * - * This function returns 0 in case of suvccess and negative error code - * otherwise. - */ -int si476x_core_set_power_state(struct si476x_core *core, - enum si476x_power_state next_state) -{ - /* - It is not clear form the datasheet if it is possible to - work with device if not all power domains are operational. - So for now the power-up policy is "power-up all the things!" - */ - int err = 0; - - if (core->power_state == SI476X_POWER_INCONSISTENT) { - dev_err(&core->client->dev, - "The device in inconsistent power state\n"); - return -EINVAL; - } - - if (next_state != core->power_state) { - switch (next_state) { - case SI476X_POWER_UP_FULL: - err = regulator_bulk_enable(ARRAY_SIZE(core->supplies), - core->supplies); - if (err < 0) { - core->power_state = SI476X_POWER_INCONSISTENT; - break; - } - /* - * Startup timing diagram recommends to have a - * 100 us delay between enabling of the power - * supplies and turning the tuner on. - */ - udelay(100); - - err = si476x_core_start(core, false); - if (err < 0) - goto disable_regulators; - - core->power_state = next_state; - break; - - case SI476X_POWER_DOWN: - core->power_state = next_state; - err = si476x_core_stop(core, false); - if (err < 0) - core->power_state = SI476X_POWER_INCONSISTENT; -disable_regulators: - err = regulator_bulk_disable(ARRAY_SIZE(core->supplies), - core->supplies); - if (err < 0) - core->power_state = SI476X_POWER_INCONSISTENT; - break; - default: - BUG(); - } - } - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_set_power_state); - -/** - * si476x_core_report_drainer_stop() - mark the completion of the RDS - * buffer drain porcess by the worker. - * - * @core: Core device structure - */ -static inline void si476x_core_report_drainer_stop(struct si476x_core *core) -{ - mutex_lock(&core->rds_drainer_status_lock); - core->rds_drainer_is_working = false; - mutex_unlock(&core->rds_drainer_status_lock); -} - -/** - * si476x_core_start_rds_drainer_once() - start RDS drainer worker if - * ther is none working, do nothing otherwise - * - * @core: Datastructure corresponding to the chip. - */ -static inline void si476x_core_start_rds_drainer_once(struct si476x_core *core) -{ - mutex_lock(&core->rds_drainer_status_lock); - if (!core->rds_drainer_is_working) { - core->rds_drainer_is_working = true; - schedule_work(&core->rds_fifo_drainer); - } - mutex_unlock(&core->rds_drainer_status_lock); -} -/** - * si476x_drain_rds_fifo() - RDS buffer drainer. - * @work: struct work_struct being ppassed to the function by the - * kernel. - * - * Drain the contents of the RDS FIFO of - */ -static void si476x_core_drain_rds_fifo(struct work_struct *work) -{ - int err; - - struct si476x_core *core = container_of(work, struct si476x_core, - rds_fifo_drainer); - - struct si476x_rds_status_report report; - - si476x_core_lock(core); - err = si476x_core_cmd_fm_rds_status(core, true, false, false, &report); - if (!err) { - int i = report.rdsfifoused; - dev_dbg(&core->client->dev, - "%d elements in RDS FIFO. Draining.\n", i); - for (; i > 0; --i) { - err = si476x_core_cmd_fm_rds_status(core, false, false, - (i == 1), &report); - if (err < 0) - goto unlock; - - kfifo_in(&core->rds_fifo, report.rds, - sizeof(report.rds)); - dev_dbg(&core->client->dev, "RDS data:\n %*ph\n", - (int)sizeof(report.rds), report.rds); - } - dev_dbg(&core->client->dev, "Drrrrained!\n"); - wake_up_interruptible(&core->rds_read_queue); - } - -unlock: - si476x_core_unlock(core); - si476x_core_report_drainer_stop(core); -} - -/** - * si476x_core_pronounce_dead() - * - * @core: Core device structure - * - * Mark the device as being dead and wake up all potentially waiting - * threads of execution. - * - */ -static void si476x_core_pronounce_dead(struct si476x_core *core) -{ - dev_info(&core->client->dev, "Core device is dead.\n"); - - atomic_set(&core->is_alive, 0); - - /* Wake up al possible waiting processes */ - wake_up_interruptible(&core->rds_read_queue); - - atomic_set(&core->cts, 1); - wake_up(&core->command); - - atomic_set(&core->stc, 1); - wake_up(&core->tuning); -} - -/** - * si476x_core_i2c_xfer() - * - * @core: Core device structure - * @type: Transfer type - * @buf: Transfer buffer for/with data - * @count: Transfer buffer size - * - * Perfrom and I2C transfer(either read or write) and keep a counter - * of I/O errors. If the error counter rises above the threshold - * pronounce device dead. - * - * The function returns zero on succes or negative error code on - * failure. - */ -int si476x_core_i2c_xfer(struct si476x_core *core, - enum si476x_i2c_type type, - char *buf, int count) -{ - static int io_errors_count; - int err; - if (type == SI476X_I2C_SEND) - err = i2c_master_send(core->client, buf, count); - else - err = i2c_master_recv(core->client, buf, count); - - if (err < 0) { - if (io_errors_count++ > SI476X_MAX_IO_ERRORS) - si476x_core_pronounce_dead(core); - } else { - io_errors_count = 0; - } - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_i2c_xfer); - -/** - * si476x_get_status() - * @core: Core device structure - * - * Get the status byte of the core device by berforming one byte I2C - * read. - * - * The function returns a status value or a negative error code on - * error. - */ -static int si476x_core_get_status(struct si476x_core *core) -{ - u8 response; - int err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, - &response, sizeof(response)); - - return (err < 0) ? err : response; -} - -/** - * si476x_get_and_signal_status() - IRQ dispatcher - * @core: Core device structure - * - * Dispatch the arrived interrupt request based on the value of the - * status byte reported by the tuner. - * - */ -static void si476x_core_get_and_signal_status(struct si476x_core *core) -{ - int status = si476x_core_get_status(core); - if (status < 0) { - dev_err(&core->client->dev, "Failed to get status\n"); - return; - } - - if (status & SI476X_CTS) { - /* Unfortunately completions could not be used for - * signalling CTS since this flag cannot be cleared - * in status byte, and therefore once it becomes true - * multiple calls to 'complete' would cause the - * commands following the current one to be completed - * before they actually are */ - dev_dbg(&core->client->dev, "[interrupt] CTSINT\n"); - atomic_set(&core->cts, 1); - wake_up(&core->command); - } - - if (status & SI476X_FM_RDS_INT) { - dev_dbg(&core->client->dev, "[interrupt] RDSINT\n"); - si476x_core_start_rds_drainer_once(core); - } - - if (status & SI476X_STC_INT) { - dev_dbg(&core->client->dev, "[interrupt] STCINT\n"); - atomic_set(&core->stc, 1); - wake_up(&core->tuning); - } -} - -static void si476x_core_poll_loop(struct work_struct *work) -{ - struct si476x_core *core = SI476X_WORK_TO_CORE(work); - - si476x_core_get_and_signal_status(core); - - if (atomic_read(&core->is_alive)) - si476x_core_schedule_polling_work(core); -} - -static irqreturn_t si476x_core_interrupt(int irq, void *dev) -{ - struct si476x_core *core = dev; - - si476x_core_get_and_signal_status(core); - - return IRQ_HANDLED; -} - -/** - * si476x_firmware_version_to_revision() - * @core: Core device structure - * @major: Firmware major number - * @minor1: Firmware first minor number - * @minor2: Firmware second minor number - * - * Convert a chip's firmware version number into an offset that later - * will be used to as offset in "vtable" of tuner functions - * - * This function returns a positive offset in case of success and a -1 - * in case of failure. - */ -static int si476x_core_fwver_to_revision(struct si476x_core *core, - int func, int major, - int minor1, int minor2) -{ - switch (func) { - case SI476X_FUNC_FM_RECEIVER: - switch (major) { - case 5: - return SI476X_REVISION_A10; - case 8: - return SI476X_REVISION_A20; - case 10: - return SI476X_REVISION_A30; - default: - goto unknown_revision; - } - case SI476X_FUNC_AM_RECEIVER: - switch (major) { - case 5: - return SI476X_REVISION_A10; - case 7: - return SI476X_REVISION_A20; - case 9: - return SI476X_REVISION_A30; - default: - goto unknown_revision; - } - case SI476X_FUNC_WB_RECEIVER: - switch (major) { - case 3: - return SI476X_REVISION_A10; - case 5: - return SI476X_REVISION_A20; - case 7: - return SI476X_REVISION_A30; - default: - goto unknown_revision; - } - case SI476X_FUNC_BOOTLOADER: - default: /* FALLTHROUG */ - BUG(); - return -1; - } - -unknown_revision: - dev_err(&core->client->dev, - "Unsupported version of the firmware: %d.%d.%d, " - "reverting to A10 comptible functions\n", - major, minor1, minor2); - - return SI476X_REVISION_A10; -} - -/** - * si476x_get_revision_info() - * @core: Core device structure - * - * Get the firmware version number of the device. It is done in - * following three steps: - * 1. Power-up the device - * 2. Send the 'FUNC_INFO' command - * 3. Powering the device down. - * - * The function return zero on success and a negative error code on - * failure. - */ -static int si476x_core_get_revision_info(struct si476x_core *core) -{ - int rval; - struct si476x_func_info info; - - si476x_core_lock(core); - rval = si476x_core_set_power_state(core, SI476X_POWER_UP_FULL); - if (rval < 0) - goto exit; - - rval = si476x_core_cmd_func_info(core, &info); - if (rval < 0) - goto power_down; - - core->revision = si476x_core_fwver_to_revision(core, info.func, - info.firmware.major, - info.firmware.minor[0], - info.firmware.minor[1]); -power_down: - si476x_core_set_power_state(core, SI476X_POWER_DOWN); -exit: - si476x_core_unlock(core); - - return rval; -} - -bool si476x_core_has_am(struct si476x_core *core) -{ - return core->chip_id == SI476X_CHIP_SI4761 || - core->chip_id == SI476X_CHIP_SI4764; -} -EXPORT_SYMBOL_GPL(si476x_core_has_am); - -bool si476x_core_has_diversity(struct si476x_core *core) -{ - return core->chip_id == SI476X_CHIP_SI4764; -} -EXPORT_SYMBOL_GPL(si476x_core_has_diversity); - -bool si476x_core_is_a_secondary_tuner(struct si476x_core *core) -{ - return si476x_core_has_diversity(core) && - (core->diversity_mode == SI476X_PHDIV_SECONDARY_ANTENNA || - core->diversity_mode == SI476X_PHDIV_SECONDARY_COMBINING); -} -EXPORT_SYMBOL_GPL(si476x_core_is_a_secondary_tuner); - -bool si476x_core_is_a_primary_tuner(struct si476x_core *core) -{ - return si476x_core_has_diversity(core) && - (core->diversity_mode == SI476X_PHDIV_PRIMARY_ANTENNA || - core->diversity_mode == SI476X_PHDIV_PRIMARY_COMBINING); -} -EXPORT_SYMBOL_GPL(si476x_core_is_a_primary_tuner); - -bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core) -{ - return si476x_core_has_am(core) && - (core->power_up_parameters.func == SI476X_FUNC_AM_RECEIVER); -} -EXPORT_SYMBOL_GPL(si476x_core_is_in_am_receiver_mode); - -bool si476x_core_is_powered_up(struct si476x_core *core) -{ - return core->power_state == SI476X_POWER_UP_FULL; -} -EXPORT_SYMBOL_GPL(si476x_core_is_powered_up); - -static int si476x_core_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rval; - struct si476x_core *core; - struct si476x_platform_data *pdata; - struct mfd_cell *cell; - int cell_num; - - core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL); - if (!core) { - dev_err(&client->dev, - "failed to allocate 'struct si476x_core'\n"); - return -ENOMEM; - } - core->client = client; - - core->regmap = devm_regmap_init_si476x(core); - if (IS_ERR(core->regmap)) { - rval = PTR_ERR(core->regmap); - dev_err(&client->dev, - "Failed to allocate register map: %d\n", - rval); - return rval; - } - - i2c_set_clientdata(client, core); - - atomic_set(&core->is_alive, 0); - core->power_state = SI476X_POWER_DOWN; - - pdata = client->dev.platform_data; - if (pdata) { - memcpy(&core->power_up_parameters, - &pdata->power_up_parameters, - sizeof(core->power_up_parameters)); - - core->gpio_reset = -1; - if (gpio_is_valid(pdata->gpio_reset)) { - rval = gpio_request(pdata->gpio_reset, "si476x reset"); - if (rval) { - dev_err(&client->dev, - "Failed to request gpio: %d\n", rval); - return rval; - } - core->gpio_reset = pdata->gpio_reset; - gpio_direction_output(core->gpio_reset, 0); - } - - core->diversity_mode = pdata->diversity_mode; - memcpy(&core->pinmux, &pdata->pinmux, - sizeof(struct si476x_pinmux)); - } else { - dev_err(&client->dev, "No platform data provided\n"); - return -EINVAL; - } - - core->supplies[0].supply = "vd"; - core->supplies[1].supply = "va"; - core->supplies[2].supply = "vio1"; - core->supplies[3].supply = "vio2"; - - rval = devm_regulator_bulk_get(&client->dev, - ARRAY_SIZE(core->supplies), - core->supplies); - if (rval) { - dev_err(&client->dev, "Failet to gett all of the regulators\n"); - goto free_gpio; - } - - mutex_init(&core->cmd_lock); - init_waitqueue_head(&core->command); - init_waitqueue_head(&core->tuning); - - rval = kfifo_alloc(&core->rds_fifo, - SI476X_DRIVER_RDS_FIFO_DEPTH * - sizeof(struct v4l2_rds_data), - GFP_KERNEL); - if (rval) { - dev_err(&client->dev, "Could not alloate the FIFO\n"); - goto free_gpio; - } - mutex_init(&core->rds_drainer_status_lock); - init_waitqueue_head(&core->rds_read_queue); - INIT_WORK(&core->rds_fifo_drainer, si476x_core_drain_rds_fifo); - - if (client->irq) { - rval = devm_request_threaded_irq(&client->dev, - client->irq, NULL, - si476x_core_interrupt, - IRQF_TRIGGER_FALLING, - client->name, core); - if (rval < 0) { - dev_err(&client->dev, "Could not request IRQ %d\n", - client->irq); - goto free_kfifo; - } - disable_irq(client->irq); - dev_dbg(&client->dev, "IRQ requested.\n"); - - core->rds_fifo_depth = 20; - } else { - INIT_DELAYED_WORK(&core->status_monitor, - si476x_core_poll_loop); - dev_info(&client->dev, - "No IRQ number specified, will use polling\n"); - - core->rds_fifo_depth = 5; - } - - core->chip_id = id->driver_data; - - rval = si476x_core_get_revision_info(core); - if (rval < 0) { - rval = -ENODEV; - goto free_kfifo; - } - - cell_num = 0; - - cell = &core->cells[SI476X_RADIO_CELL]; - cell->name = "si476x-radio"; - cell_num++; - -#ifdef CONFIG_SND_SOC_SI476X - if ((core->chip_id == SI476X_CHIP_SI4761 || - core->chip_id == SI476X_CHIP_SI4764) && - core->pinmux.dclk == SI476X_DCLK_DAUDIO && - core->pinmux.dfs == SI476X_DFS_DAUDIO && - core->pinmux.dout == SI476X_DOUT_I2S_OUTPUT && - core->pinmux.xout == SI476X_XOUT_TRISTATE) { - cell = &core->cells[SI476X_CODEC_CELL]; - cell->name = "si476x-codec"; - cell_num++; - } -#endif - rval = mfd_add_devices(&client->dev, - (client->adapter->nr << 8) + client->addr, - core->cells, cell_num, - NULL, 0, NULL); - if (!rval) - return 0; - -free_kfifo: - kfifo_free(&core->rds_fifo); - -free_gpio: - if (gpio_is_valid(core->gpio_reset)) - gpio_free(core->gpio_reset); - - return rval; -} - -static int si476x_core_remove(struct i2c_client *client) -{ - struct si476x_core *core = i2c_get_clientdata(client); - - si476x_core_pronounce_dead(core); - mfd_remove_devices(&client->dev); - - if (client->irq) - disable_irq(client->irq); - else - cancel_delayed_work_sync(&core->status_monitor); - - kfifo_free(&core->rds_fifo); - - if (gpio_is_valid(core->gpio_reset)) - gpio_free(core->gpio_reset); - - return 0; -} - - -static const struct i2c_device_id si476x_id[] = { - { "si4761", SI476X_CHIP_SI4761 }, - { "si4764", SI476X_CHIP_SI4764 }, - { "si4768", SI476X_CHIP_SI4768 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, si476x_id); - -static struct i2c_driver si476x_core_driver = { - .driver = { - .name = "si476x-core", - .owner = THIS_MODULE, - }, - .probe = si476x_core_probe, - .remove = si476x_core_remove, - .id_table = si476x_id, -}; -module_i2c_driver(si476x_core_driver); - - -MODULE_AUTHOR("Andrey Smirnov "); -MODULE_DESCRIPTION("Si4761/64/68 AM/FM MFD core device driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mfd/si476x-prop.c b/trunk/drivers/mfd/si476x-prop.c deleted file mode 100644 index cfeffa6e15d9..000000000000 --- a/trunk/drivers/mfd/si476x-prop.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * drivers/mfd/si476x-prop.c -- Subroutines to access - * properties of si476x chips - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * 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; version 2 of the License. - * - * 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 - -#include - -struct si476x_property_range { - u16 low, high; -}; - -static bool si476x_core_element_is_in_array(u16 element, - const u16 array[], - size_t size) -{ - int i; - - for (i = 0; i < size; i++) - if (element == array[i]) - return true; - - return false; -} - -static bool si476x_core_element_is_in_range(u16 element, - const struct si476x_property_range range[], - size_t size) -{ - int i; - - for (i = 0; i < size; i++) - if (element <= range[i].high && element >= range[i].low) - return true; - - return false; -} - -static bool si476x_core_is_valid_property_a10(struct si476x_core *core, - u16 property) -{ - static const u16 valid_properties[] = { - 0x0000, - 0x0500, 0x0501, - 0x0600, - 0x0709, 0x070C, 0x070D, 0x70E, 0x710, - 0x0718, - 0x1207, 0x1208, - 0x2007, - 0x2300, - }; - - static const struct si476x_property_range valid_ranges[] = { - { 0x0200, 0x0203 }, - { 0x0300, 0x0303 }, - { 0x0400, 0x0404 }, - { 0x0700, 0x0707 }, - { 0x1100, 0x1102 }, - { 0x1200, 0x1204 }, - { 0x1300, 0x1306 }, - { 0x2000, 0x2005 }, - { 0x2100, 0x2104 }, - { 0x2106, 0x2106 }, - { 0x2200, 0x220E }, - { 0x3100, 0x3104 }, - { 0x3207, 0x320F }, - { 0x3300, 0x3304 }, - { 0x3500, 0x3517 }, - { 0x3600, 0x3617 }, - { 0x3700, 0x3717 }, - { 0x4000, 0x4003 }, - }; - - return si476x_core_element_is_in_range(property, valid_ranges, - ARRAY_SIZE(valid_ranges)) || - si476x_core_element_is_in_array(property, valid_properties, - ARRAY_SIZE(valid_properties)); -} - -static bool si476x_core_is_valid_property_a20(struct si476x_core *core, - u16 property) -{ - static const u16 valid_properties[] = { - 0x071B, - 0x1006, - 0x2210, - 0x3401, - }; - - static const struct si476x_property_range valid_ranges[] = { - { 0x2215, 0x2219 }, - }; - - return si476x_core_is_valid_property_a10(core, property) || - si476x_core_element_is_in_range(property, valid_ranges, - ARRAY_SIZE(valid_ranges)) || - si476x_core_element_is_in_array(property, valid_properties, - ARRAY_SIZE(valid_properties)); -} - -static bool si476x_core_is_valid_property_a30(struct si476x_core *core, - u16 property) -{ - static const u16 valid_properties[] = { - 0x071C, 0x071D, - 0x1007, 0x1008, - 0x220F, 0x2214, - 0x2301, - 0x3105, 0x3106, - 0x3402, - }; - - static const struct si476x_property_range valid_ranges[] = { - { 0x0405, 0x0411 }, - { 0x2008, 0x200B }, - { 0x2220, 0x2223 }, - { 0x3100, 0x3106 }, - }; - - return si476x_core_is_valid_property_a20(core, property) || - si476x_core_element_is_in_range(property, valid_ranges, - ARRAY_SIZE(valid_ranges)) || - si476x_core_element_is_in_array(property, valid_properties, - ARRAY_SIZE(valid_properties)); -} - -typedef bool (*valid_property_pred_t) (struct si476x_core *, u16); - -static bool si476x_core_is_valid_property(struct si476x_core *core, - u16 property) -{ - static const valid_property_pred_t is_valid_property[] = { - [SI476X_REVISION_A10] = si476x_core_is_valid_property_a10, - [SI476X_REVISION_A20] = si476x_core_is_valid_property_a20, - [SI476X_REVISION_A30] = si476x_core_is_valid_property_a30, - }; - - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return is_valid_property[core->revision](core, property); -} - - -static bool si476x_core_is_readonly_property(struct si476x_core *core, - u16 property) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - - switch (core->revision) { - case SI476X_REVISION_A10: - return (property == 0x3200); - case SI476X_REVISION_A20: - return (property == 0x1006 || - property == 0x2210 || - property == 0x3200); - case SI476X_REVISION_A30: - return false; - } - - return false; -} - -static bool si476x_core_regmap_readable_register(struct device *dev, - unsigned int reg) -{ - struct i2c_client *client = to_i2c_client(dev); - struct si476x_core *core = i2c_get_clientdata(client); - - return si476x_core_is_valid_property(core, (u16) reg); - -} - -static bool si476x_core_regmap_writable_register(struct device *dev, - unsigned int reg) -{ - struct i2c_client *client = to_i2c_client(dev); - struct si476x_core *core = i2c_get_clientdata(client); - - return si476x_core_is_valid_property(core, (u16) reg) && - !si476x_core_is_readonly_property(core, (u16) reg); -} - - -static int si476x_core_regmap_write(void *context, unsigned int reg, - unsigned int val) -{ - return si476x_core_cmd_set_property(context, reg, val); -} - -static int si476x_core_regmap_read(void *context, unsigned int reg, - unsigned *val) -{ - struct si476x_core *core = context; - int err; - - err = si476x_core_cmd_get_property(core, reg); - if (err < 0) - return err; - - *val = err; - - return 0; -} - - -static const struct regmap_config si476x_regmap_config = { - .reg_bits = 16, - .val_bits = 16, - - .max_register = 0x4003, - - .writeable_reg = si476x_core_regmap_writable_register, - .readable_reg = si476x_core_regmap_readable_register, - - .reg_read = si476x_core_regmap_read, - .reg_write = si476x_core_regmap_write, - - .cache_type = REGCACHE_RBTREE, -}; - -struct regmap *devm_regmap_init_si476x(struct si476x_core *core) -{ - return devm_regmap_init(&core->client->dev, NULL, - core, &si476x_regmap_config); -} -EXPORT_SYMBOL_GPL(devm_regmap_init_si476x); diff --git a/trunk/drivers/mfd/sta2x11-mfd.c b/trunk/drivers/mfd/sta2x11-mfd.c index d70a343078fd..9bd33169a111 100644 --- a/trunk/drivers/mfd/sta2x11-mfd.c +++ b/trunk/drivers/mfd/sta2x11-mfd.c @@ -98,6 +98,17 @@ static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) return 0; } +static int mfd_remove(struct pci_dev *pdev) +{ + struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); + + if (!mfd) + return -ENODEV; + list_del(&mfd->list); + kfree(mfd); + return 0; +} + /* This function is exported and is not expected to fail */ u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val, enum sta2x11_mfd_plat_dev index) diff --git a/trunk/drivers/mfd/stmpe-i2c.c b/trunk/drivers/mfd/stmpe-i2c.c index 0da02e11d58e..fd5fcb630685 100644 --- a/trunk/drivers/mfd/stmpe-i2c.c +++ b/trunk/drivers/mfd/stmpe-i2c.c @@ -75,7 +75,6 @@ static const struct i2c_device_id stmpe_i2c_id[] = { { "stmpe801", STMPE801 }, { "stmpe811", STMPE811 }, { "stmpe1601", STMPE1601 }, - { "stmpe1801", STMPE1801 }, { "stmpe2401", STMPE2401 }, { "stmpe2403", STMPE2403 }, { } diff --git a/trunk/drivers/mfd/stmpe-spi.c b/trunk/drivers/mfd/stmpe-spi.c index a81badbaa917..973659f8abd9 100644 --- a/trunk/drivers/mfd/stmpe-spi.c +++ b/trunk/drivers/mfd/stmpe-spi.c @@ -103,7 +103,7 @@ stmpe_spi_probe(struct spi_device *spi) static int stmpe_spi_remove(struct spi_device *spi) { - struct stmpe *stmpe = spi_get_drvdata(spi); + struct stmpe *stmpe = dev_get_drvdata(&spi->dev); return stmpe_remove(stmpe); } diff --git a/trunk/drivers/mfd/stmpe.c b/trunk/drivers/mfd/stmpe.c index bbccd514d3ec..4b11202061be 100644 --- a/trunk/drivers/mfd/stmpe.c +++ b/trunk/drivers/mfd/stmpe.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "stmpe.h" static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) @@ -643,88 +642,6 @@ static struct stmpe_variant_info stmpe1601 = { .enable_autosleep = stmpe1601_autosleep, }; -/* - * STMPE1801 - */ -static const u8 stmpe1801_regs[] = { - [STMPE_IDX_CHIP_ID] = STMPE1801_REG_CHIP_ID, - [STMPE_IDX_ICR_LSB] = STMPE1801_REG_INT_CTRL_LOW, - [STMPE_IDX_IER_LSB] = STMPE1801_REG_INT_EN_MASK_LOW, - [STMPE_IDX_ISR_LSB] = STMPE1801_REG_INT_STA_LOW, - [STMPE_IDX_GPMR_LSB] = STMPE1801_REG_GPIO_MP_LOW, - [STMPE_IDX_GPSR_LSB] = STMPE1801_REG_GPIO_SET_LOW, - [STMPE_IDX_GPCR_LSB] = STMPE1801_REG_GPIO_CLR_LOW, - [STMPE_IDX_GPDR_LSB] = STMPE1801_REG_GPIO_SET_DIR_LOW, - [STMPE_IDX_GPRER_LSB] = STMPE1801_REG_GPIO_RE_LOW, - [STMPE_IDX_GPFER_LSB] = STMPE1801_REG_GPIO_FE_LOW, - [STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW, - [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW, -}; - -static struct stmpe_variant_block stmpe1801_blocks[] = { - { - .cell = &stmpe_gpio_cell, - .irq = STMPE1801_IRQ_GPIOC, - .block = STMPE_BLOCK_GPIO, - }, - { - .cell = &stmpe_keypad_cell, - .irq = STMPE1801_IRQ_KEYPAD, - .block = STMPE_BLOCK_KEYPAD, - }, -}; - -static int stmpe1801_enable(struct stmpe *stmpe, unsigned int blocks, - bool enable) -{ - unsigned int mask = 0; - if (blocks & STMPE_BLOCK_GPIO) - mask |= STMPE1801_MSK_INT_EN_GPIO; - - if (blocks & STMPE_BLOCK_KEYPAD) - mask |= STMPE1801_MSK_INT_EN_KPC; - - return __stmpe_set_bits(stmpe, STMPE1801_REG_INT_EN_MASK_LOW, mask, - enable ? mask : 0); -} - -static int stmpe1801_reset(struct stmpe *stmpe) -{ - unsigned long timeout; - int ret = 0; - - ret = __stmpe_set_bits(stmpe, STMPE1801_REG_SYS_CTRL, - STMPE1801_MSK_SYS_CTRL_RESET, STMPE1801_MSK_SYS_CTRL_RESET); - if (ret < 0) - return ret; - - timeout = jiffies + msecs_to_jiffies(100); - while (time_before(jiffies, timeout)) { - ret = __stmpe_reg_read(stmpe, STMPE1801_REG_SYS_CTRL); - if (ret < 0) - return ret; - if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET)) - return 0; - usleep_range(100, 200); - }; - return -EIO; -} - -static struct stmpe_variant_info stmpe1801 = { - .name = "stmpe1801", - .id_val = STMPE1801_ID, - .id_mask = 0xfff0, - .num_gpios = 18, - .af_bits = 0, - .regs = stmpe1801_regs, - .blocks = stmpe1801_blocks, - .num_blocks = ARRAY_SIZE(stmpe1801_blocks), - .num_irqs = STMPE1801_NR_INTERNAL_IRQS, - .enable = stmpe1801_enable, - /* stmpe1801 do not have any gpio alternate function */ - .get_altfunc = NULL, -}; - /* * STMPE24XX */ @@ -823,7 +740,6 @@ static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = { [STMPE801] = &stmpe801, [STMPE811] = &stmpe811, [STMPE1601] = &stmpe1601, - [STMPE1801] = &stmpe1801, [STMPE2401] = &stmpe2401, [STMPE2403] = &stmpe2403, }; @@ -843,7 +759,7 @@ static irqreturn_t stmpe_irq(int irq, void *data) struct stmpe *stmpe = data; struct stmpe_variant_info *variant = stmpe->variant; int num = DIV_ROUND_UP(variant->num_irqs, 8); - u8 israddr; + u8 israddr = stmpe->regs[STMPE_IDX_ISR_MSB]; u8 isr[num]; int ret; int i; @@ -855,11 +771,6 @@ static irqreturn_t stmpe_irq(int irq, void *data) return IRQ_HANDLED; } - if (variant->id_val == STMPE1801_ID) - israddr = stmpe->regs[STMPE_IDX_ISR_LSB]; - else - israddr = stmpe->regs[STMPE_IDX_ISR_MSB]; - ret = stmpe_block_read(stmpe, israddr, num, isr); if (ret < 0) return IRQ_NONE; @@ -1027,12 +938,6 @@ static int stmpe_chip_init(struct stmpe *stmpe) if (ret) return ret; - if (id == STMPE1801_ID) { - ret = stmpe1801_reset(stmpe); - if (ret < 0) - return ret; - } - if (stmpe->irq >= 0) { if (id == STMPE801_ID) icr = STMPE801_REG_SYS_CTRL_INT_EN; @@ -1110,10 +1015,7 @@ void stmpe_of_probe(struct stmpe_platform_data *pdata, struct device_node *np) { struct device_node *child; - pdata->id = of_alias_get_id(np, "stmpe-i2c"); - if (pdata->id < 0) - pdata->id = -1; - + pdata->id = -1; pdata->irq_trigger = IRQF_TRIGGER_NONE; of_property_read_u32(np, "st,autosleep-timeout", @@ -1155,9 +1057,6 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum) return -ENOMEM; stmpe_of_probe(pdata, np); - - if (of_find_property(np, "interrupts", NULL) == NULL) - ci->irq = -1; } stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); diff --git a/trunk/drivers/mfd/stmpe.h b/trunk/drivers/mfd/stmpe.h index ff2b09ba8797..7b8e13f5b764 100644 --- a/trunk/drivers/mfd/stmpe.h +++ b/trunk/drivers/mfd/stmpe.h @@ -198,55 +198,6 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7) #define STPME1601_AUTOSLEEP_ENABLE (1 << 3) -/* - * STMPE1801 - */ -#define STMPE1801_ID 0xc110 -#define STMPE1801_NR_INTERNAL_IRQS 5 -#define STMPE1801_IRQ_KEYPAD_COMBI 4 -#define STMPE1801_IRQ_GPIOC 3 -#define STMPE1801_IRQ_KEYPAD_OVER 2 -#define STMPE1801_IRQ_KEYPAD 1 -#define STMPE1801_IRQ_WAKEUP 0 - -#define STMPE1801_REG_CHIP_ID 0x00 -#define STMPE1801_REG_SYS_CTRL 0x02 -#define STMPE1801_REG_INT_CTRL_LOW 0x04 -#define STMPE1801_REG_INT_EN_MASK_LOW 0x06 -#define STMPE1801_REG_INT_STA_LOW 0x08 -#define STMPE1801_REG_INT_EN_GPIO_MASK_LOW 0x0A -#define STMPE1801_REG_INT_EN_GPIO_MASK_MID 0x0B -#define STMPE1801_REG_INT_EN_GPIO_MASK_HIGH 0x0C -#define STMPE1801_REG_INT_STA_GPIO_LOW 0x0D -#define STMPE1801_REG_INT_STA_GPIO_MID 0x0E -#define STMPE1801_REG_INT_STA_GPIO_HIGH 0x0F -#define STMPE1801_REG_GPIO_SET_LOW 0x10 -#define STMPE1801_REG_GPIO_SET_MID 0x11 -#define STMPE1801_REG_GPIO_SET_HIGH 0x12 -#define STMPE1801_REG_GPIO_CLR_LOW 0x13 -#define STMPE1801_REG_GPIO_CLR_MID 0x14 -#define STMPE1801_REG_GPIO_CLR_HIGH 0x15 -#define STMPE1801_REG_GPIO_MP_LOW 0x16 -#define STMPE1801_REG_GPIO_MP_MID 0x17 -#define STMPE1801_REG_GPIO_MP_HIGH 0x18 -#define STMPE1801_REG_GPIO_SET_DIR_LOW 0x19 -#define STMPE1801_REG_GPIO_SET_DIR_MID 0x1A -#define STMPE1801_REG_GPIO_SET_DIR_HIGH 0x1B -#define STMPE1801_REG_GPIO_RE_LOW 0x1C -#define STMPE1801_REG_GPIO_RE_MID 0x1D -#define STMPE1801_REG_GPIO_RE_HIGH 0x1E -#define STMPE1801_REG_GPIO_FE_LOW 0x1F -#define STMPE1801_REG_GPIO_FE_MID 0x20 -#define STMPE1801_REG_GPIO_FE_HIGH 0x21 -#define STMPE1801_REG_GPIO_PULL_UP_LOW 0x22 -#define STMPE1801_REG_GPIO_PULL_UP_MID 0x23 -#define STMPE1801_REG_GPIO_PULL_UP_HIGH 0x24 - -#define STMPE1801_MSK_SYS_CTRL_RESET (1 << 7) - -#define STMPE1801_MSK_INT_EN_KPC (1 << 1) -#define STMPE1801_MSK_INT_EN_GPIO (1 << 3) - /* * STMPE24xx */ diff --git a/trunk/drivers/mfd/syscon.c b/trunk/drivers/mfd/syscon.c index 962a6e17a01a..61aea6381cdf 100644 --- a/trunk/drivers/mfd/syscon.c +++ b/trunk/drivers/mfd/syscon.c @@ -25,15 +25,17 @@ static struct platform_driver syscon_driver; struct syscon { + struct device *dev; void __iomem *base; struct regmap *regmap; }; -static int syscon_match_node(struct device *dev, void *data) +static int syscon_match(struct device *dev, void *data) { + struct syscon *syscon = dev_get_drvdata(dev); struct device_node *dn = data; - return (dev->of_node == dn) ? 1 : 0; + return (syscon->dev->of_node == dn) ? 1 : 0; } struct regmap *syscon_node_to_regmap(struct device_node *np) @@ -42,7 +44,7 @@ struct regmap *syscon_node_to_regmap(struct device_node *np) struct device *dev; dev = driver_find_device(&syscon_driver.driver, NULL, np, - syscon_match_node); + syscon_match); if (!dev) return ERR_PTR(-EPROBE_DEFER); @@ -68,34 +70,6 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s) } EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); -static int syscon_match_pdevname(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - const struct platform_device_id *id = platform_get_device_id(pdev); - - if (id) - if (!strcmp(id->name, (const char *)data)) - return 1; - - return !strcmp(dev_name(dev), (const char *)data); -} - -struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) -{ - struct device *dev; - struct syscon *syscon; - - dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s, - syscon_match_pdevname); - if (!dev) - return ERR_PTR(-EPROBE_DEFER); - - syscon = dev_get_drvdata(dev); - - return syscon->regmap; -} -EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname); - struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, const char *property) { @@ -127,22 +101,28 @@ static struct regmap_config syscon_regmap_config = { static int syscon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct syscon *syscon; - struct resource *res; + struct resource res; + int ret; + + if (!np) + return -ENOENT; - syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); + syscon = devm_kzalloc(dev, sizeof(struct syscon), + GFP_KERNEL); if (!syscon) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOENT; - - syscon->base = devm_ioremap(dev, res->start, resource_size(res)); + syscon->base = of_iomap(np, 0); if (!syscon->base) - return -ENOMEM; + return -EADDRNOTAVAIL; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; - syscon_regmap_config.max_register = res->end - res->start - 3; + syscon_regmap_config.max_register = res.end - res.start - 3; syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, &syscon_regmap_config); if (IS_ERR(syscon->regmap)) { @@ -150,17 +130,25 @@ static int syscon_probe(struct platform_device *pdev) return PTR_ERR(syscon->regmap); } + syscon->dev = dev; platform_set_drvdata(pdev, syscon); - dev_info(dev, "regmap %pR registered\n", res); + dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n", + res.start, res.end); return 0; } -static const struct platform_device_id syscon_ids[] = { - { "syscon", }, - { } -}; +static int syscon_remove(struct platform_device *pdev) +{ + struct syscon *syscon; + + syscon = platform_get_drvdata(pdev); + iounmap(syscon->base); + platform_set_drvdata(pdev, NULL); + + return 0; +} static struct platform_driver syscon_driver = { .driver = { @@ -169,7 +157,7 @@ static struct platform_driver syscon_driver = { .of_match_table = of_syscon_match, }, .probe = syscon_probe, - .id_table = syscon_ids, + .remove = syscon_remove, }; static int __init syscon_init(void) diff --git a/trunk/drivers/mfd/tc3589x.c b/trunk/drivers/mfd/tc3589x.c index 4cb92bb2aea2..ecc092c7f745 100644 --- a/trunk/drivers/mfd/tc3589x.c +++ b/trunk/drivers/mfd/tc3589x.c @@ -350,8 +350,7 @@ static int tc3589x_probe(struct i2c_client *i2c, | I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; - tc3589x = devm_kzalloc(&i2c->dev, sizeof(struct tc3589x), - GFP_KERNEL); + tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL); if (!tc3589x) return -ENOMEM; @@ -367,27 +366,33 @@ static int tc3589x_probe(struct i2c_client *i2c, ret = tc3589x_chip_init(tc3589x); if (ret) - return ret; + goto out_free; ret = tc3589x_irq_init(tc3589x, np); if (ret) - return ret; + goto out_free; ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "tc3589x", tc3589x); if (ret) { dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); - return ret; + goto out_free; } ret = tc3589x_device_init(tc3589x); if (ret) { dev_err(tc3589x->dev, "failed to add child devices\n"); - return ret; + goto out_freeirq; } return 0; + +out_freeirq: + free_irq(tc3589x->i2c->irq, tc3589x); +out_free: + kfree(tc3589x); + return ret; } static int tc3589x_remove(struct i2c_client *client) @@ -396,6 +401,10 @@ static int tc3589x_remove(struct i2c_client *client) mfd_remove_devices(tc3589x->dev); + free_irq(tc3589x->i2c->irq, tc3589x); + + kfree(tc3589x); + return 0; } diff --git a/trunk/drivers/mfd/tps65090.c b/trunk/drivers/mfd/tps65090.c index fbd6ee67b5a5..98edb5be85c6 100644 --- a/trunk/drivers/mfd/tps65090.c +++ b/trunk/drivers/mfd/tps65090.c @@ -56,23 +56,12 @@ #define TPS65090_INT2_MASK_OVERLOAD_FET6 6 #define TPS65090_INT2_MASK_OVERLOAD_FET7 7 -static struct resource charger_resources[] = { - { - .start = TPS65090_IRQ_VAC_STATUS_CHANGE, - .end = TPS65090_IRQ_VAC_STATUS_CHANGE, - .flags = IORESOURCE_IRQ, - } -}; - static struct mfd_cell tps65090s[] = { { .name = "tps65090-pmic", }, { .name = "tps65090-charger", - .num_resources = ARRAY_SIZE(charger_resources), - .resources = &charger_resources[0], - .of_compatible = "ti,tps65090-charger", }, }; diff --git a/trunk/drivers/mfd/twl4030-madc.c b/trunk/drivers/mfd/twl4030-madc.c index 42bd3ea5df3c..942b666a2a07 100644 --- a/trunk/drivers/mfd/twl4030-madc.c +++ b/trunk/drivers/mfd/twl4030-madc.c @@ -211,14 +211,12 @@ static int twl4030battery_current(int raw_volt) * @reg_base - Base address of the first channel * @Channels - 16 bit bitmap. If the bit is set, channel value is read * @buf - The channel values are stored here. if read fails error - * @raw - Return raw values without conversion * value is stored * Returns the number of successfully read channels. */ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, u8 reg_base, unsigned - long channels, int *buf, - bool raw) + long channels, int *buf) { int count = 0, count_req = 0, i; u8 reg; @@ -232,10 +230,6 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, count_req++; continue; } - if (raw) { - count++; - continue; - } switch (i) { case 10: buf[i] = twl4030battery_current(buf[i]); @@ -377,7 +371,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) method = &twl4030_conversion_methods[r->method]; /* Read results */ len = twl4030_madc_read_channels(madc, method->rbase, - r->channels, r->rbuf, r->raw); + r->channels, r->rbuf); /* Return results to caller */ if (r->func_cb != NULL) { r->func_cb(len, r->channels, r->rbuf); @@ -403,7 +397,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) method = &twl4030_conversion_methods[r->method]; /* Read results */ len = twl4030_madc_read_channels(madc, method->rbase, - r->channels, r->rbuf, r->raw); + r->channels, r->rbuf); /* Return results to caller */ if (r->func_cb != NULL) { r->func_cb(len, r->channels, r->rbuf); @@ -591,7 +585,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) goto out; } ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, - req->channels, req->rbuf, req->raw); + req->channels, req->rbuf); twl4030_madc->requests[req->method].active = 0; out: diff --git a/trunk/drivers/mfd/twl6040.c b/trunk/drivers/mfd/twl6040.c index 492ee2cd3400..f361bf38a0aa 100644 --- a/trunk/drivers/mfd/twl6040.c +++ b/trunk/drivers/mfd/twl6040.c @@ -554,7 +554,7 @@ static int twl6040_probe(struct i2c_client *client, twl6040->supplies[0].supply = "vio"; twl6040->supplies[1].supply = "v2v1"; - ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, + ret = regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, twl6040->supplies); if (ret != 0) { dev_err(&client->dev, "Failed to get supplies: %d\n", ret); @@ -564,7 +564,7 @@ static int twl6040_probe(struct i2c_client *client, ret = regulator_bulk_enable(TWL6040_NUM_SUPPLIES, twl6040->supplies); if (ret != 0) { dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); - goto regulator_get_err; + goto power_err; } twl6040->dev = &client->dev; @@ -586,8 +586,8 @@ static int twl6040_probe(struct i2c_client *client, twl6040->audpwron = -EINVAL; if (gpio_is_valid(twl6040->audpwron)) { - ret = devm_gpio_request_one(&client->dev, twl6040->audpwron, - GPIOF_OUT_INIT_LOW, "audpwron"); + ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW, + "audpwron"); if (ret) goto gpio_err; } @@ -596,14 +596,14 @@ static int twl6040_probe(struct i2c_client *client, IRQF_ONESHOT, 0, &twl6040_irq_chip, &twl6040->irq_data); if (ret < 0) - goto gpio_err; + goto irq_init_err; twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_READY); twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_TH); - ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_ready, NULL, + ret = request_threaded_irq(twl6040->irq_ready, NULL, twl6040_readyint_handler, IRQF_ONESHOT, "twl6040_irq_ready", twl6040); if (ret) { @@ -611,7 +611,7 @@ static int twl6040_probe(struct i2c_client *client, goto readyirq_err; } - ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_th, NULL, + ret = request_threaded_irq(twl6040->irq_th, NULL, twl6040_thint_handler, IRQF_ONESHOT, "twl6040_irq_th", twl6040); if (ret) { @@ -681,13 +681,18 @@ static int twl6040_probe(struct i2c_client *client, return 0; mfd_err: - devm_free_irq(&client->dev, twl6040->irq_th, twl6040); + free_irq(twl6040->irq_th, twl6040); thirq_err: - devm_free_irq(&client->dev, twl6040->irq_ready, twl6040); + free_irq(twl6040->irq_ready, twl6040); readyirq_err: regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); +irq_init_err: + if (gpio_is_valid(twl6040->audpwron)) + gpio_free(twl6040->audpwron); gpio_err: regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); +power_err: + regulator_bulk_free(TWL6040_NUM_SUPPLIES, twl6040->supplies); regulator_get_err: i2c_set_clientdata(client, NULL); err: @@ -701,14 +706,18 @@ static int twl6040_remove(struct i2c_client *client) if (twl6040->power_count) twl6040_power(twl6040, 0); - devm_free_irq(&client->dev, twl6040->irq_ready, twl6040); - devm_free_irq(&client->dev, twl6040->irq_th, twl6040); + if (gpio_is_valid(twl6040->audpwron)) + gpio_free(twl6040->audpwron); + + free_irq(twl6040->irq_ready, twl6040); + free_irq(twl6040->irq_th, twl6040); regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); mfd_remove_devices(&client->dev); i2c_set_clientdata(client, NULL); regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); + regulator_bulk_free(TWL6040_NUM_SUPPLIES, twl6040->supplies); return 0; } diff --git a/trunk/drivers/mfd/ucb1400_core.c b/trunk/drivers/mfd/ucb1400_core.c index e9031fa9d53d..daf69527ed83 100644 --- a/trunk/drivers/mfd/ucb1400_core.c +++ b/trunk/drivers/mfd/ucb1400_core.c @@ -75,11 +75,6 @@ static int ucb1400_core_probe(struct device *dev) /* GPIO */ ucb_gpio.ac97 = ac97; - if (pdata) { - ucb_gpio.gpio_setup = pdata->gpio_setup; - ucb_gpio.gpio_teardown = pdata->gpio_teardown; - ucb_gpio.gpio_offset = pdata->gpio_offset; - } ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); if (!ucb->ucb1400_gpio) { err = -ENOMEM; diff --git a/trunk/drivers/mfd/vexpress-config.c b/trunk/drivers/mfd/vexpress-config.c index 84ce6b9daa3d..3c1723aa6225 100644 --- a/trunk/drivers/mfd/vexpress-config.c +++ b/trunk/drivers/mfd/vexpress-config.c @@ -184,14 +184,13 @@ static int vexpress_config_schedule(struct vexpress_config_trans *trans) spin_lock_irqsave(&bridge->transactions_lock, flags); - if (list_empty(&bridge->transactions)) { - vexpress_config_dump_trans("Executing", trans); + vexpress_config_dump_trans("Executing", trans); + + if (list_empty(&bridge->transactions)) status = bridge->info->func_exec(trans->func->func, trans->offset, trans->write, trans->data); - } else { - vexpress_config_dump_trans("Queuing", trans); + else status = VEXPRESS_CONFIG_STATUS_WAIT; - } switch (status) { case VEXPRESS_CONFIG_STATUS_DONE: @@ -213,31 +212,25 @@ void vexpress_config_complete(struct vexpress_config_bridge *bridge, { struct vexpress_config_trans *trans; unsigned long flags; - const char *message = "Completed"; spin_lock_irqsave(&bridge->transactions_lock, flags); trans = list_first_entry(&bridge->transactions, struct vexpress_config_trans, list); - trans->status = status; + vexpress_config_dump_trans("Completed", trans); - do { - vexpress_config_dump_trans(message, trans); - list_del(&trans->list); - complete(&trans->completion); - - if (list_empty(&bridge->transactions)) - break; + trans->status = status; + list_del(&trans->list); - trans = list_first_entry(&bridge->transactions, - struct vexpress_config_trans, list); - vexpress_config_dump_trans("Executing pending", trans); - trans->status = bridge->info->func_exec(trans->func->func, - trans->offset, trans->write, trans->data); - message = "Finished pending"; - } while (trans->status == VEXPRESS_CONFIG_STATUS_DONE); + if (!list_empty(&bridge->transactions)) { + vexpress_config_dump_trans("Pending", trans); + bridge->info->func_exec(trans->func->func, trans->offset, + trans->write, trans->data); + } spin_unlock_irqrestore(&bridge->transactions_lock, flags); + + complete(&trans->completion); } EXPORT_SYMBOL(vexpress_config_complete); diff --git a/trunk/drivers/mfd/vexpress-sysreg.c b/trunk/drivers/mfd/vexpress-sysreg.c index 96a020b1dcd1..bf75e967a1f3 100644 --- a/trunk/drivers/mfd/vexpress-sysreg.c +++ b/trunk/drivers/mfd/vexpress-sysreg.c @@ -490,12 +490,12 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) return err; } - vexpress_sysreg_dev = &pdev->dev; - platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, sizeof(vexpress_sysreg_leds_pdata)); + vexpress_sysreg_dev = &pdev->dev; + device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); return 0; diff --git a/trunk/drivers/mfd/wm5102-tables.c b/trunk/drivers/mfd/wm5102-tables.c index 155c4a1a6a99..f70c4956ff9d 100644 --- a/trunk/drivers/mfd/wm5102-tables.c +++ b/trunk/drivers/mfd/wm5102-tables.c @@ -10,7 +10,6 @@ * published by the Free Software Foundation. */ -#include #include #include @@ -58,54 +57,31 @@ static const struct reg_default wm5102_reva_patch[] = { }; static const struct reg_default wm5102_revb_patch[] = { - { 0x19, 0x0001 }, { 0x80, 0x0003 }, { 0x081, 0xE022 }, - { 0x410, 0x6080 }, - { 0x418, 0xa080 }, - { 0x420, 0xa080 }, - { 0x428, 0xe000 }, - { 0x443, 0xDC1A }, + { 0x410, 0x4080 }, + { 0x418, 0x4080 }, + { 0x420, 0x4080 }, + { 0x428, 0xC000 }, { 0x4B0, 0x0066 }, { 0x458, 0x000b }, { 0x212, 0x0000 }, - { 0x171, 0x0000 }, - { 0x35E, 0x000C }, - { 0x2D4, 0x0000 }, { 0x80, 0x0000 }, }; /* We use a function so we can use ARRAY_SIZE() */ int wm5102_patch(struct arizona *arizona) { - const struct reg_default *wm5102_patch; - int ret = 0; - int i, patch_size; - switch (arizona->rev) { case 0: - wm5102_patch = wm5102_reva_patch; - patch_size = ARRAY_SIZE(wm5102_reva_patch); + return regmap_register_patch(arizona->regmap, + wm5102_reva_patch, + ARRAY_SIZE(wm5102_reva_patch)); default: - wm5102_patch = wm5102_revb_patch; - patch_size = ARRAY_SIZE(wm5102_revb_patch); - } - - regcache_cache_bypass(arizona->regmap, true); - - for (i = 0; i < patch_size; i++) { - ret = regmap_write(arizona->regmap, wm5102_patch[i].reg, - wm5102_patch[i].def); - if (ret != 0) { - dev_err(arizona->dev, "Failed to write %x = %x: %d\n", - wm5102_patch[i].reg, wm5102_patch[i].def, ret); - goto out; - } + return regmap_register_patch(arizona->regmap, + wm5102_revb_patch, + ARRAY_SIZE(wm5102_revb_patch)); } - -out: - regcache_cache_bypass(arizona->regmap, false); - return ret; } static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = { @@ -306,7 +282,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ - { 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */ + { 0x00000171, 0x0002 }, /* R369 - FLL1 Control 1 */ { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ @@ -390,7 +366,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ - { 0x00000410, 0x6080 }, /* R1040 - Output Path Config 1L */ + { 0x00000410, 0x4080 }, /* R1040 - Output Path Config 1L */ { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */ { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ @@ -398,7 +374,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */ { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ - { 0x00000418, 0xA080 }, /* R1048 - Output Path Config 2L */ + { 0x00000418, 0x4080 }, /* R1048 - Output Path Config 2L */ { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */ { 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */ { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */ @@ -406,11 +382,11 @@ static const struct reg_default wm5102_reg_default[] = { { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */ { 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */ { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */ - { 0x00000420, 0xA080 }, /* R1056 - Output Path Config 3L */ + { 0x00000420, 0x4080 }, /* R1056 - Output Path Config 3L */ { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */ { 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */ { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */ - { 0x00000428, 0xE000 }, /* R1064 - Output Path Config 4L */ + { 0x00000428, 0xC000 }, /* R1064 - Output Path Config 4L */ { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */ { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ @@ -425,7 +401,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */ { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */ { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ - { 0x00000458, 0x000B }, /* R1112 - Noise Gate Control */ + { 0x00000458, 0x0001 }, /* R1112 - Noise Gate Control */ { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */ { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ diff --git a/trunk/drivers/mfd/wm831x-spi.c b/trunk/drivers/mfd/wm831x-spi.c index e7ed14f661d8..4e70e157a909 100644 --- a/trunk/drivers/mfd/wm831x-spi.c +++ b/trunk/drivers/mfd/wm831x-spi.c @@ -37,7 +37,7 @@ static int wm831x_spi_probe(struct spi_device *spi) spi->bits_per_word = 16; spi->mode = SPI_MODE_0; - spi_set_drvdata(spi, wm831x); + dev_set_drvdata(&spi->dev, wm831x); wm831x->dev = &spi->dev; wm831x->regmap = devm_regmap_init_spi(spi, &wm831x_regmap_config); @@ -53,7 +53,7 @@ static int wm831x_spi_probe(struct spi_device *spi) static int wm831x_spi_remove(struct spi_device *spi) { - struct wm831x *wm831x = spi_get_drvdata(spi); + struct wm831x *wm831x = dev_get_drvdata(&spi->dev); wm831x_device_exit(wm831x); @@ -69,7 +69,7 @@ static int wm831x_spi_suspend(struct device *dev) static void wm831x_spi_shutdown(struct spi_device *spi) { - struct wm831x *wm831x = spi_get_drvdata(spi); + struct wm831x *wm831x = dev_get_drvdata(&spi->dev); wm831x_device_shutdown(wm831x); } diff --git a/trunk/drivers/mfd/wm8994-core.c b/trunk/drivers/mfd/wm8994-core.c index 00e4fe2f3c75..803e93fae56a 100644 --- a/trunk/drivers/mfd/wm8994-core.c +++ b/trunk/drivers/mfd/wm8994-core.c @@ -19,9 +19,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -194,7 +191,7 @@ static const char *wm8958_main_supplies[] = { "SPKVDD2", }; -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int wm8994_suspend(struct device *dev) { struct wm8994 *wm8994 = dev_get_drvdata(dev); @@ -399,60 +396,6 @@ static const struct reg_default wm1811_reva_patch[] = { { 0x102, 0x0 }, }; -#ifdef CONFIG_OF -static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) -{ - struct device_node *np = wm8994->dev->of_node; - struct wm8994_pdata *pdata = &wm8994->pdata; - int i; - - if (!np) - return 0; - - if (of_property_read_u32_array(np, "wlf,gpio-cfg", pdata->gpio_defaults, - ARRAY_SIZE(pdata->gpio_defaults)) >= 0) { - for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { - if (wm8994->pdata.gpio_defaults[i] == 0) - pdata->gpio_defaults[i] - = WM8994_CONFIGURE_GPIO; - } - } - - of_property_read_u32_array(np, "wlf,micbias-cfg", pdata->micbias, - ARRAY_SIZE(pdata->micbias)); - - pdata->lineout1_diff = true; - pdata->lineout2_diff = true; - if (of_find_property(np, "wlf,lineout1-se", NULL)) - pdata->lineout1_diff = false; - if (of_find_property(np, "wlf,lineout2-se", NULL)) - pdata->lineout2_diff = false; - - if (of_find_property(np, "wlf,lineout1-feedback", NULL)) - pdata->lineout1fb = true; - if (of_find_property(np, "wlf,lineout2-feedback", NULL)) - pdata->lineout2fb = true; - - if (of_find_property(np, "wlf,ldoena-always-driven", NULL)) - pdata->lineout2fb = true; - - pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0); - if (pdata->ldo[0].enable < 0) - pdata->ldo[0].enable = 0; - - pdata->ldo[1].enable = of_get_named_gpio(np, "wlf,ldo2ena", 0); - if (pdata->ldo[1].enable < 0) - pdata->ldo[1].enable = 0; - - return 0; -} -#else -static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) -{ - return 0; -} -#endif - /* * Instantiate the generic non-control parts of the device. */ @@ -462,7 +405,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) struct regmap_config *regmap_config; const struct reg_default *regmap_patch = NULL; const char *devname; - int ret, i, patch_regs = 0; + int ret, i, patch_regs; int pulls = 0; if (dev_get_platdata(wm8994->dev)) { @@ -471,10 +414,6 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) } pdata = &wm8994->pdata; - ret = wm8994_set_pdata_from_of(wm8994); - if (ret != 0) - return ret; - dev_set_drvdata(wm8994->dev, wm8994); /* Add the on-chip regulators first for bootstrapping */ @@ -734,9 +673,9 @@ static void wm8994_device_exit(struct wm8994 *wm8994) } static const struct of_device_id wm8994_of_match[] = { - { .compatible = "wlf,wm1811", .data = (void *)WM1811 }, - { .compatible = "wlf,wm8994", .data = (void *)WM8994 }, - { .compatible = "wlf,wm8958", .data = (void *)WM8958 }, + { .compatible = "wlf,wm1811", }, + { .compatible = "wlf,wm8994", }, + { .compatible = "wlf,wm8958", }, { } }; MODULE_DEVICE_TABLE(of, wm8994_of_match); @@ -744,7 +683,6 @@ MODULE_DEVICE_TABLE(of, wm8994_of_match); static int wm8994_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - const struct of_device_id *of_id; struct wm8994 *wm8994; int ret; @@ -755,14 +693,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8994); wm8994->dev = &i2c->dev; wm8994->irq = i2c->irq; - - if (i2c->dev.of_node) { - of_id = of_match_device(wm8994_of_match, &i2c->dev); - if (of_id) - wm8994->type = (int)of_id->data; - } else { - wm8994->type = id->driver_data; - } + wm8994->type = id->driver_data; wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config); if (IS_ERR(wm8994->regmap)) { @@ -793,16 +724,15 @@ static const struct i2c_device_id wm8994_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); -static const struct dev_pm_ops wm8994_pm_ops = { - SET_RUNTIME_PM_OPS(wm8994_suspend, wm8994_resume, NULL) -}; +static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, + NULL); static struct i2c_driver wm8994_i2c_driver = { .driver = { .name = "wm8994", .owner = THIS_MODULE, .pm = &wm8994_pm_ops, - .of_match_table = of_match_ptr(wm8994_of_match), + .of_match_table = wm8994_of_match, }, .probe = wm8994_i2c_probe, .remove = wm8994_i2c_remove, diff --git a/trunk/drivers/mtd/chips/gen_probe.c b/trunk/drivers/mtd/chips/gen_probe.c index 74dbb6bcf488..3b9a2843c5f8 100644 --- a/trunk/drivers/mtd/chips/gen_probe.c +++ b/trunk/drivers/mtd/chips/gen_probe.c @@ -204,16 +204,14 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, struct cfi_private *cfi = map->fldrv_priv; __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; #ifdef CONFIG_MODULES - char probename[sizeof(VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X))]; + char probename[16+sizeof(MODULE_SYMBOL_PREFIX)]; cfi_cmdset_fn_t *probe_function; - sprintf(probename, VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X), type); + sprintf(probename, MODULE_SYMBOL_PREFIX "cfi_cmdset_%4.4X", type); probe_function = __symbol_get(probename); if (!probe_function) { - char modname[sizeof("cfi_cmdset_%4.4X")]; - sprintf(modname, "cfi_cmdset_%4.4X", type); - request_module(modname); + request_module(probename + sizeof(MODULE_SYMBOL_PREFIX) - 1); probe_function = __symbol_get(probename); } diff --git a/trunk/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/trunk/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 3cd397d60434..c59ec3ddaa66 100644 --- a/trunk/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/trunk/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5204,7 +5204,7 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev) if (t4_wait_dev_ready(adap) < 0) return PCI_ERS_RESULT_DISCONNECT; - if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL) < 0) + if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL)) return PCI_ERS_RESULT_DISCONNECT; adap->flags |= FW_OK; if (adap_init1(adap, &c)) diff --git a/trunk/drivers/net/ethernet/emulex/benet/be.h b/trunk/drivers/net/ethernet/emulex/benet/be.h index f544b297c9ab..234ce6f07544 100644 --- a/trunk/drivers/net/ethernet/emulex/benet/be.h +++ b/trunk/drivers/net/ethernet/emulex/benet/be.h @@ -327,7 +327,6 @@ enum vf_state { #define BE_FLAGS_LINK_STATUS_INIT 1 #define BE_FLAGS_WORKER_SCHEDULED (1 << 3) -#define BE_FLAGS_NAPI_ENABLED (1 << 9) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 #define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11) diff --git a/trunk/drivers/net/ethernet/emulex/benet/be_cmds.c b/trunk/drivers/net/ethernet/emulex/benet/be_cmds.c index e1e5bb9d9054..25d3290b8cac 100644 --- a/trunk/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/trunk/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -961,8 +961,19 @@ int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, OPCODE_COMMON_CQ_CREATE, sizeof(*req), wrb, NULL); req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); - - if (BEx_chip(adapter)) { + if (lancer_chip(adapter)) { + req->hdr.version = 2; + req->page_size = 1; /* 1 for 4K */ + AMAP_SET_BITS(struct amap_cq_context_lancer, nodelay, ctxt, + no_delay); + AMAP_SET_BITS(struct amap_cq_context_lancer, count, ctxt, + __ilog2_u32(cq->len/256)); + AMAP_SET_BITS(struct amap_cq_context_lancer, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_cq_context_lancer, eventable, + ctxt, 1); + AMAP_SET_BITS(struct amap_cq_context_lancer, eqid, + ctxt, eq->id); + } else { AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt, coalesce_wm); AMAP_SET_BITS(struct amap_cq_context_be, nodelay, @@ -972,18 +983,6 @@ int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id); - } else { - req->hdr.version = 2; - req->page_size = 1; /* 1 for 4K */ - AMAP_SET_BITS(struct amap_cq_context_v2, nodelay, ctxt, - no_delay); - AMAP_SET_BITS(struct amap_cq_context_v2, count, ctxt, - __ilog2_u32(cq->len/256)); - AMAP_SET_BITS(struct amap_cq_context_v2, valid, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context_v2, eventable, - ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context_v2, eqid, - ctxt, eq->id); } be_dws_cpu_to_le(ctxt, sizeof(req->context)); @@ -1764,12 +1763,10 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) req->if_id = cpu_to_le32(adapter->if_handle); if (flags & IFF_PROMISC) { req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | - BE_IF_FLAGS_VLAN_PROMISCUOUS | - BE_IF_FLAGS_MCAST_PROMISCUOUS); + BE_IF_FLAGS_VLAN_PROMISCUOUS); if (value == ON) req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | - BE_IF_FLAGS_VLAN_PROMISCUOUS | - BE_IF_FLAGS_MCAST_PROMISCUOUS); + BE_IF_FLAGS_VLAN_PROMISCUOUS); } else if (flags & IFF_ALLMULTI) { req->if_flags_mask = req->if_flags = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); @@ -2087,7 +2084,7 @@ int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, spin_unlock_bh(&adapter->mcc_lock); if (!wait_for_completion_timeout(&adapter->flash_compl, - msecs_to_jiffies(60000))) + msecs_to_jiffies(30000))) status = -1; else status = adapter->flash_status; diff --git a/trunk/drivers/net/ethernet/emulex/benet/be_cmds.h b/trunk/drivers/net/ethernet/emulex/benet/be_cmds.h index 025bdb0d1764..a855668e0cc5 100644 --- a/trunk/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/trunk/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -381,7 +381,7 @@ struct amap_cq_context_be { u8 rsvd5[32]; /* dword 3*/ } __packed; -struct amap_cq_context_v2 { +struct amap_cq_context_lancer { u8 rsvd0[12]; /* dword 0*/ u8 coalescwm[2]; /* dword 0*/ u8 nodelay; /* dword 0*/ diff --git a/trunk/drivers/net/ethernet/emulex/benet/be_ethtool.c b/trunk/drivers/net/ethernet/emulex/benet/be_ethtool.c index 3d4461adb3b4..5733cde88e2c 100644 --- a/trunk/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/trunk/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -85,7 +85,6 @@ static const struct be_ethtool_stat et_stats[] = { {DRVSTAT_INFO(tx_pauseframes)}, {DRVSTAT_INFO(tx_controlframes)}, {DRVSTAT_INFO(rx_priority_pause_frames)}, - {DRVSTAT_INFO(tx_priority_pauseframes)}, /* Received packets dropped when an internal fifo going into * main packet buffer tank (PMEM) overflows. */ diff --git a/trunk/drivers/net/ethernet/emulex/benet/be_main.c b/trunk/drivers/net/ethernet/emulex/benet/be_main.c index 6c52a60dcdb7..4babc8a4a543 100644 --- a/trunk/drivers/net/ethernet/emulex/benet/be_main.c +++ b/trunk/drivers/net/ethernet/emulex/benet/be_main.c @@ -410,7 +410,6 @@ static void populate_be_v1_stats(struct be_adapter *adapter) drvs->rxpp_fifo_overflow_drop = port_stats->rxpp_fifo_overflow_drop; drvs->tx_pauseframes = port_stats->tx_pauseframes; drvs->tx_controlframes = port_stats->tx_controlframes; - drvs->tx_priority_pauseframes = port_stats->tx_priority_pauseframes; drvs->jabber_events = port_stats->jabber_events; drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; @@ -472,26 +471,11 @@ static void accumulate_16bit_val(u32 *acc, u16 val) ACCESS_ONCE(*acc) = newacc; } -void populate_erx_stats(struct be_adapter *adapter, - struct be_rx_obj *rxo, - u32 erx_stat) -{ - if (!BEx_chip(adapter)) - rx_stats(rxo)->rx_drops_no_frags = erx_stat; - else - /* below erx HW counter can actually wrap around after - * 65535. Driver accumulates a 32-bit value - */ - accumulate_16bit_val(&rx_stats(rxo)->rx_drops_no_frags, - (u16)erx_stat); -} - void be_parse_stats(struct be_adapter *adapter) { struct be_erx_stats_v1 *erx = be_erx_stats_from_cmd(adapter); struct be_rx_obj *rxo; int i; - u32 erx_stat; if (lancer_chip(adapter)) { populate_lancer_stats(adapter); @@ -504,8 +488,12 @@ void be_parse_stats(struct be_adapter *adapter) /* as erx_v1 is longer than v0, ok to use v1 for v0 access */ for_all_rx_queues(adapter, rxo, i) { - erx_stat = erx->rx_drops_no_fragments[rxo->q.id]; - populate_erx_stats(adapter, rxo, erx_stat); + /* below erx HW counter can actually wrap around after + * 65535. Driver accumulates a 32-bit value + */ + accumulate_16bit_val(&rx_stats(rxo)->rx_drops_no_frags, + (u16)erx->rx_drops_no_fragments \ + [rxo->q.id]); } } } @@ -2390,7 +2378,7 @@ static uint be_num_rss_want(struct be_adapter *adapter) return num; } -static int be_msix_enable(struct be_adapter *adapter) +static void be_msix_enable(struct be_adapter *adapter) { #define BE_MIN_MSIX_VECTORS 1 int i, status, num_vec, num_roce_vec = 0; @@ -2415,17 +2403,13 @@ static int be_msix_enable(struct be_adapter *adapter) goto done; } else if (status >= BE_MIN_MSIX_VECTORS) { num_vec = status; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, - num_vec); - if (!status) + if (pci_enable_msix(adapter->pdev, adapter->msix_entries, + num_vec) == 0) goto done; } dev_warn(dev, "MSIx enable failed\n"); - /* INTx is not supported in VFs, so fail probe if enable_msix fails */ - if (!be_physfn(adapter)) - return status; - return 0; + return; done: if (be_roce_supported(adapter)) { if (num_vec > num_roce_vec) { @@ -2439,7 +2423,7 @@ static int be_msix_enable(struct be_adapter *adapter) } else adapter->num_msix_vec = num_vec; dev_info(dev, "enabled %d MSI-x vector(s)\n", adapter->num_msix_vec); - return 0; + return; } static inline int be_msix_vec_get(struct be_adapter *adapter, @@ -2552,11 +2536,8 @@ static int be_close(struct net_device *netdev) be_roce_dev_close(adapter); - if (adapter->flags & BE_FLAGS_NAPI_ENABLED) { - for_all_evt_queues(adapter, eqo, i) - napi_disable(&eqo->napi); - adapter->flags &= ~BE_FLAGS_NAPI_ENABLED; - } + for_all_evt_queues(adapter, eqo, i) + napi_disable(&eqo->napi); be_async_mcc_disable(adapter); @@ -2650,9 +2631,7 @@ static int be_open(struct net_device *netdev) if (status) goto err; - status = be_irq_register(adapter); - if (status) - goto err; + be_irq_register(adapter); for_all_rx_queues(adapter, rxo, i) be_cq_notify(adapter, rxo->cq.id, true, 0); @@ -2666,7 +2645,6 @@ static int be_open(struct net_device *netdev) napi_enable(&eqo->napi); be_eq_notify(adapter, eqo->q.id, true, false, 0); } - adapter->flags |= BE_FLAGS_NAPI_ENABLED; status = be_cmd_link_status_query(adapter, NULL, &link_status, 0); if (!status) @@ -3122,9 +3100,7 @@ static int be_setup(struct be_adapter *adapter) if (status) goto err; - status = be_msix_enable(adapter); - if (status) - goto err; + be_msix_enable(adapter); status = be_evt_queues_create(adapter); if (status) diff --git a/trunk/drivers/net/ethernet/marvell/sky2.c b/trunk/drivers/net/ethernet/marvell/sky2.c index d175bbd3ffd3..256ae789c143 100644 --- a/trunk/drivers/net/ethernet/marvell/sky2.c +++ b/trunk/drivers/net/ethernet/marvell/sky2.c @@ -2496,12 +2496,10 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2, skb->ip_summed = re->skb->ip_summed; skb->csum = re->skb->csum; skb->rxhash = re->skb->rxhash; - skb->vlan_proto = re->skb->vlan_proto; skb->vlan_tci = re->skb->vlan_tci; pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr, length, PCI_DMA_FROMDEVICE); - re->skb->vlan_proto = 0; re->skb->vlan_tci = 0; re->skb->rxhash = 0; re->skb->ip_summed = CHECKSUM_NONE; diff --git a/trunk/drivers/net/ethernet/ti/cpsw.c b/trunk/drivers/net/ethernet/ti/cpsw.c index 21a5b291b4b3..59c43918883e 100644 --- a/trunk/drivers/net/ethernet/ti/cpsw.c +++ b/trunk/drivers/net/ethernet/ti/cpsw.c @@ -555,8 +555,8 @@ static int cpsw_poll(struct napi_struct *napi, int budget) cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); prim_cpsw = cpsw_get_slave_priv(priv, 0); if (prim_cpsw->irq_enabled == false) { - prim_cpsw->irq_enabled = true; cpsw_enable_irq(priv); + prim_cpsw->irq_enabled = true; } } diff --git a/trunk/drivers/net/usb/asix_common.c b/trunk/drivers/net/usb/asix_common.c index 577c72d5f369..f7f623a5390e 100644 --- a/trunk/drivers/net/usb/asix_common.c +++ b/trunk/drivers/net/usb/asix_common.c @@ -100,9 +100,6 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", rx->size); kfree_skb(rx->ax_skb); - rx->ax_skb = NULL; - rx->size = 0U; - return 0; } diff --git a/trunk/drivers/net/usb/pegasus.c b/trunk/drivers/net/usb/pegasus.c index 03e8a15d7deb..09699054b54f 100644 --- a/trunk/drivers/net/usb/pegasus.c +++ b/trunk/drivers/net/usb/pegasus.c @@ -256,9 +256,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc) static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) { pegasus_t *pegasus = netdev_priv(dev); - u16 data = val; - write_mii_word(pegasus, phy_id, loc, &data); + write_mii_word(pegasus, phy_id, loc, (__u16 *)&val); } static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata) diff --git a/trunk/drivers/net/usb/qmi_wwan.c b/trunk/drivers/net/usb/qmi_wwan.c index 834e405fb57a..5a88e72090ce 100644 --- a/trunk/drivers/net/usb/qmi_wwan.c +++ b/trunk/drivers/net/usb/qmi_wwan.c @@ -548,7 +548,6 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x19d2, 0x0265, 4)}, /* ONDA MT8205 4G LTE */ {QMI_FIXED_INTF(0x19d2, 0x0284, 4)}, /* ZTE MF880 */ {QMI_FIXED_INTF(0x19d2, 0x0326, 4)}, /* ZTE MF821D */ - {QMI_FIXED_INTF(0x19d2, 0x0412, 4)}, /* Telewell TW-LTE 4G */ {QMI_FIXED_INTF(0x19d2, 0x1008, 4)}, /* ZTE (Vodafone) K3570-Z */ {QMI_FIXED_INTF(0x19d2, 0x1010, 4)}, /* ZTE (Vodafone) K3571-Z */ {QMI_FIXED_INTF(0x19d2, 0x1012, 4)}, diff --git a/trunk/drivers/net/wireless/atmel.c b/trunk/drivers/net/wireless/atmel.c index 830bb1d1f957..23a3498f14d4 100644 --- a/trunk/drivers/net/wireless/atmel.c +++ b/trunk/drivers/net/wireless/atmel.c @@ -1502,7 +1502,7 @@ static const struct file_operations atmel_proc_fops = { .open = atmel_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static const struct net_device_ops atmel_netdev_ops = { diff --git a/trunk/drivers/net/wireless/hostap/hostap_ap.c b/trunk/drivers/net/wireless/hostap/hostap_ap.c index d6033a8e5dea..19c45e363aa7 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_ap.c +++ b/trunk/drivers/net/wireless/hostap/hostap_ap.c @@ -89,7 +89,7 @@ static const struct file_operations ap_debug_proc_fops = { .open = ap_debug_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif /* PRISM2_NO_PROCFS_DEBUG */ @@ -1116,7 +1116,7 @@ static const struct file_operations prism2_sta_proc_fops = { .open = prism2_sta_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static void handle_add_proc_queue(struct work_struct *work) diff --git a/trunk/drivers/net/wireless/hostap/hostap_hw.c b/trunk/drivers/net/wireless/hostap/hostap_hw.c index 6307a4e36c85..507ab99eef4e 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_hw.c +++ b/trunk/drivers/net/wireless/hostap/hostap_hw.c @@ -2957,7 +2957,7 @@ static const struct file_operations prism2_registers_proc_fops = { .open = prism2_registers_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif /* PRISM2_NO_PROCFS_DEBUG */ diff --git a/trunk/drivers/net/wireless/hostap/hostap_proc.c b/trunk/drivers/net/wireless/hostap/hostap_proc.c index aa7ad3a7a69b..7491dab2c105 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_proc.c +++ b/trunk/drivers/net/wireless/hostap/hostap_proc.c @@ -52,7 +52,7 @@ static const struct file_operations prism2_debug_proc_fops = { .open = prism2_debug_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif /* PRISM2_NO_PROCFS_DEBUG */ @@ -103,7 +103,7 @@ static const struct file_operations prism2_stats_proc_fops = { .open = prism2_stats_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; @@ -265,7 +265,7 @@ static const struct file_operations prism2_crypt_proc_fops = { .open = prism2_crypt_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; diff --git a/trunk/drivers/net/xen-netback/netback.c b/trunk/drivers/net/xen-netback/netback.c index 37984e6d4e99..a2865f17c667 100644 --- a/trunk/drivers/net/xen-netback/netback.c +++ b/trunk/drivers/net/xen-netback/netback.c @@ -51,17 +51,9 @@ * This is the maximum slots a skb can have. If a guest sends a skb * which exceeds this limit it is considered malicious. */ -#define FATAL_SKB_SLOTS_DEFAULT 20 -static unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT; -module_param(fatal_skb_slots, uint, 0444); - -/* - * To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating - * the maximum slots a valid packet can use. Now this value is defined - * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by - * all backend. - */ -#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN +#define MAX_SKB_SLOTS_DEFAULT 20 +static unsigned int max_skb_slots = MAX_SKB_SLOTS_DEFAULT; +module_param(max_skb_slots, uint, 0444); typedef unsigned int pending_ring_idx_t; #define INVALID_PENDING_RING_IDX (~0U) @@ -936,20 +928,18 @@ static void netbk_fatal_tx_err(struct xenvif *vif) static int netbk_count_requests(struct xenvif *vif, struct xen_netif_tx_request *first, + RING_IDX first_idx, struct xen_netif_tx_request *txp, int work_to_do) { RING_IDX cons = vif->tx.req_cons; int slots = 0; int drop_err = 0; - int more_data; if (!(first->flags & XEN_NETTXF_more_data)) return 0; do { - struct xen_netif_tx_request dropped_tx = { 0 }; - if (slots >= work_to_do) { netdev_err(vif->dev, "Asked for %d slots but exceeds this limit\n", @@ -961,32 +951,28 @@ static int netbk_count_requests(struct xenvif *vif, /* This guest is really using too many slots and * considered malicious. */ - if (unlikely(slots >= fatal_skb_slots)) { + if (unlikely(slots >= max_skb_slots)) { netdev_err(vif->dev, "Malicious frontend using %d slots, threshold %u\n", - slots, fatal_skb_slots); + slots, max_skb_slots); netbk_fatal_tx_err(vif); return -E2BIG; } /* Xen network protocol had implicit dependency on - * MAX_SKB_FRAGS. XEN_NETBK_LEGACY_SLOTS_MAX is set to - * the historical MAX_SKB_FRAGS value 18 to honor the - * same behavior as before. Any packet using more than - * 18 slots but less than fatal_skb_slots slots is - * dropped + * MAX_SKB_FRAGS. XEN_NETIF_NR_SLOTS_MIN is set to the + * historical MAX_SKB_FRAGS value 18 to honor the same + * behavior as before. Any packet using more than 18 + * slots but less than max_skb_slots slots is dropped */ - if (!drop_err && slots >= XEN_NETBK_LEGACY_SLOTS_MAX) { + if (!drop_err && slots >= XEN_NETIF_NR_SLOTS_MIN) { if (net_ratelimit()) netdev_dbg(vif->dev, "Too many slots (%d) exceeding limit (%d), dropping packet\n", - slots, XEN_NETBK_LEGACY_SLOTS_MAX); + slots, XEN_NETIF_NR_SLOTS_MIN); drop_err = -E2BIG; } - if (drop_err) - txp = &dropped_tx; - memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + slots), sizeof(*txp)); @@ -1016,16 +1002,10 @@ static int netbk_count_requests(struct xenvif *vif, netbk_fatal_tx_err(vif); return -EINVAL; } - - more_data = txp->flags & XEN_NETTXF_more_data; - - if (!drop_err) - txp++; - - } while (more_data); + } while ((txp++)->flags & XEN_NETTXF_more_data); if (drop_err) { - netbk_tx_err(vif, first, cons + slots); + netbk_tx_err(vif, first, first_idx + slots); return drop_err; } @@ -1062,7 +1042,7 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk, struct pending_tx_info *first = NULL; /* At this point shinfo->nr_frags is in fact the number of - * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. + * slots, which can be as large as XEN_NETIF_NR_SLOTS_MIN. */ nr_slots = shinfo->nr_frags; @@ -1424,12 +1404,12 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) struct sk_buff *skb; int ret; - while ((nr_pending_reqs(netbk) + XEN_NETBK_LEGACY_SLOTS_MAX + while ((nr_pending_reqs(netbk) + XEN_NETIF_NR_SLOTS_MIN < MAX_PENDING_REQS) && !list_empty(&netbk->net_schedule_list)) { struct xenvif *vif; struct xen_netif_tx_request txreq; - struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; + struct xen_netif_tx_request txfrags[max_skb_slots]; struct page *page; struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1]; u16 pending_idx; @@ -1490,7 +1470,8 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) continue; } - ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do); + ret = netbk_count_requests(vif, &txreq, idx, + txfrags, work_to_do); if (unlikely(ret < 0)) continue; @@ -1517,7 +1498,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk) pending_idx = netbk->pending_ring[index]; data_len = (txreq.size > PKT_PROT_LEN && - ret < XEN_NETBK_LEGACY_SLOTS_MAX) ? + ret < XEN_NETIF_NR_SLOTS_MIN) ? PKT_PROT_LEN : txreq.size; skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN, @@ -1796,7 +1777,7 @@ static inline int rx_work_todo(struct xen_netbk *netbk) static inline int tx_work_todo(struct xen_netbk *netbk) { - if ((nr_pending_reqs(netbk) + XEN_NETBK_LEGACY_SLOTS_MAX + if ((nr_pending_reqs(netbk) + XEN_NETIF_NR_SLOTS_MIN < MAX_PENDING_REQS) && !list_empty(&netbk->net_schedule_list)) return 1; @@ -1881,11 +1862,11 @@ static int __init netback_init(void) if (!xen_domain()) return -ENODEV; - if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { + if (max_skb_slots < XEN_NETIF_NR_SLOTS_MIN) { printk(KERN_INFO - "xen-netback: fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", - fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX); - fatal_skb_slots = XEN_NETBK_LEGACY_SLOTS_MAX; + "xen-netback: max_skb_slots too small (%d), bump it to XEN_NETIF_NR_SLOTS_MIN (%d)\n", + max_skb_slots, XEN_NETIF_NR_SLOTS_MIN); + max_skb_slots = XEN_NETIF_NR_SLOTS_MIN; } xen_netbk_group_nr = num_online_cpus(); diff --git a/trunk/drivers/power/rx51_battery.c b/trunk/drivers/power/rx51_battery.c index cbde1d6d3228..1a1dcb831a17 100644 --- a/trunk/drivers/power/rx51_battery.c +++ b/trunk/drivers/power/rx51_battery.c @@ -42,7 +42,6 @@ static int rx51_battery_read_adc(int channel) req.method = TWL4030_MADC_SW1; req.func_cb = NULL; req.type = TWL4030_MADC_WAIT; - req.raw = true; if (twl4030_madc_conversion(&req) <= 0) return -ENODATA; diff --git a/trunk/drivers/s390/char/sclp_cmd.c b/trunk/drivers/s390/char/sclp_cmd.c index bf07c3a188d4..178836ec252b 100644 --- a/trunk/drivers/s390/char/sclp_cmd.c +++ b/trunk/drivers/s390/char/sclp_cmd.c @@ -345,6 +345,7 @@ struct memory_increment { struct list_head list; u16 rn; int standby; + int usecount; }; struct assign_storage_sccb { @@ -462,10 +463,21 @@ static int sclp_mem_change_state(unsigned long start, unsigned long size, break; if (start > istart + rzm - 1) continue; - if (online) + if (online) { + if (incr->usecount++) + continue; + /* + * Don't break the loop if one assign fails. Loop may + * be walked again on CANCEL and we can't save + * information if state changed before or not. + * So continue and increase usecount for all increments. + */ rc |= sclp_assign_storage(incr->rn); - else + } else { + if (--incr->usecount) + continue; sclp_unassign_storage(incr->rn); + } } return rc ? -EIO : 0; } @@ -549,6 +561,8 @@ static void __init sclp_add_standby_memory(void) add_memory_merged(0); } +#define MEM_SCT_SIZE (1UL << SECTION_SIZE_BITS) + static void __init insert_increment(u16 rn, int standby, int assigned) { struct memory_increment *incr, *new_incr; @@ -560,6 +574,8 @@ static void __init insert_increment(u16 rn, int standby, int assigned) return; new_incr->rn = rn; new_incr->standby = standby; + if (!standby) + new_incr->usecount = rzm > MEM_SCT_SIZE ? rzm/MEM_SCT_SIZE : 1; last_rn = 0; prev = &sclp_mem_list; list_for_each_entry(incr, &sclp_mem_list, list) { diff --git a/trunk/drivers/s390/char/zcore.c b/trunk/drivers/s390/char/zcore.c index 9e5e14686e75..22820610022c 100644 --- a/trunk/drivers/s390/char/zcore.c +++ b/trunk/drivers/s390/char/zcore.c @@ -426,7 +426,7 @@ static int zcore_memmap_open(struct inode *inode, struct file *filp) GFP_KERNEL); if (!chunk_array) return -ENOMEM; - detect_memory_layout(chunk_array, 0); + detect_memory_layout(chunk_array); buf = kzalloc(MEMORY_CHUNKS * CHUNK_INFO_SIZE, GFP_KERNEL); if (!buf) { kfree(chunk_array); @@ -557,7 +557,7 @@ static void __init set_lc_mask(struct save_area *map) /* * Initialize dump globals for a given architecture */ -static int __init sys_info_init(enum arch_id arch, unsigned long mem_end) +static int __init sys_info_init(enum arch_id arch) { int rc; @@ -579,7 +579,7 @@ static int __init sys_info_init(enum arch_id arch, unsigned long mem_end) rc = init_cpu_info(arch); if (rc) return rc; - sys_info.mem_size = mem_end; + sys_info.mem_size = real_memory_size; return 0; } @@ -601,7 +601,7 @@ static int __init check_sdias(void) return 0; } -static int __init get_mem_info(unsigned long *mem, unsigned long *end) +static int __init get_mem_size(unsigned long *mem) { int i; struct mem_chunk *chunk_array; @@ -610,31 +610,33 @@ static int __init get_mem_info(unsigned long *mem, unsigned long *end) GFP_KERNEL); if (!chunk_array) return -ENOMEM; - detect_memory_layout(chunk_array, 0); + detect_memory_layout(chunk_array); for (i = 0; i < MEMORY_CHUNKS; i++) { if (chunk_array[i].size == 0) break; *mem += chunk_array[i].size; - *end = max(*end, chunk_array[i].addr + chunk_array[i].size); } kfree(chunk_array); return 0; } -static void __init zcore_header_init(int arch, struct zcore_header *hdr, - unsigned long mem_size) +static int __init zcore_header_init(int arch, struct zcore_header *hdr) { + int rc, i; + unsigned long memory = 0; u32 prefix; - int i; if (arch == ARCH_S390X) hdr->arch_id = DUMP_ARCH_S390X; else hdr->arch_id = DUMP_ARCH_S390; - hdr->mem_size = mem_size; - hdr->rmem_size = mem_size; + rc = get_mem_size(&memory); + if (rc) + return rc; + hdr->mem_size = memory; + hdr->rmem_size = memory; hdr->mem_end = sys_info.mem_size; - hdr->num_pages = mem_size / PAGE_SIZE; + hdr->num_pages = memory / PAGE_SIZE; hdr->tod = get_tod_clock(); get_cpu_id(&hdr->cpu_id); for (i = 0; zfcpdump_save_areas[i]; i++) { @@ -645,6 +647,7 @@ static void __init zcore_header_init(int arch, struct zcore_header *hdr, hdr->lc_vec[hdr->cpu_cnt] = prefix; hdr->cpu_cnt++; } + return 0; } /* @@ -679,11 +682,9 @@ static int __init zcore_reipl_init(void) static int __init zcore_init(void) { - unsigned long mem_size, mem_end; unsigned char arch; int rc; - mem_size = mem_end = 0; if (ipl_info.type != IPL_TYPE_FCP_DUMP) return -ENODATA; if (OLDMEM_BASE) @@ -726,14 +727,13 @@ static int __init zcore_init(void) } #endif /* CONFIG_64BIT */ - rc = get_mem_info(&mem_size, &mem_end); + rc = sys_info_init(arch); if (rc) goto fail; - rc = sys_info_init(arch, mem_end); + rc = zcore_header_init(arch, &zcore_header); if (rc) goto fail; - zcore_header_init(arch, &zcore_header, mem_size); rc = zcore_reipl_init(); if (rc) diff --git a/trunk/drivers/s390/cio/blacklist.c b/trunk/drivers/s390/cio/blacklist.c index a9fe3de2dec1..2d2a966a3b39 100644 --- a/trunk/drivers/s390/cio/blacklist.c +++ b/trunk/drivers/s390/cio/blacklist.c @@ -1,7 +1,7 @@ /* * S/390 common I/O routines -- blacklisting of specific devices * - * Copyright IBM Corp. 1999, 2013 + * Copyright IBM Corp. 1999, 2002 * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) @@ -17,9 +17,8 @@ #include #include -#include #include -#include +#include #include "blacklist.h" #include "cio.h" @@ -173,29 +172,6 @@ static int blacklist_parse_parameters(char *str, range_action action, to_cssid = __MAX_CSSID; to_ssid = __MAX_SSID; to = __MAX_SUBCHANNEL; - } else if (strcmp(parm, "ipldev") == 0) { - if (ipl_info.type == IPL_TYPE_CCW) { - from_cssid = 0; - from_ssid = ipl_info.data.ccw.dev_id.ssid; - from = ipl_info.data.ccw.dev_id.devno; - } else if (ipl_info.type == IPL_TYPE_FCP || - ipl_info.type == IPL_TYPE_FCP_DUMP) { - from_cssid = 0; - from_ssid = ipl_info.data.fcp.dev_id.ssid; - from = ipl_info.data.fcp.dev_id.devno; - } else { - continue; - } - to_cssid = from_cssid; - to_ssid = from_ssid; - to = from; - } else if (strcmp(parm, "condev") == 0) { - if (console_devno == -1) - continue; - - from_cssid = to_cssid = 0; - from_ssid = to_ssid = 0; - from = to = console_devno; } else { rc = parse_busid(strsep(&parm, "-"), &from_cssid, &from_ssid, &from, msgtrigger); diff --git a/trunk/drivers/s390/crypto/ap_bus.c b/trunk/drivers/s390/crypto/ap_bus.c index 9de41aa14896..b8b340ac5332 100644 --- a/trunk/drivers/s390/crypto/ap_bus.c +++ b/trunk/drivers/s390/crypto/ap_bus.c @@ -954,11 +954,15 @@ EXPORT_SYMBOL(ap_driver_unregister); void ap_bus_force_rescan(void) { - /* reconfigure the AP bus rescan timer. */ - mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); - /* processing a asynchronous bus rescan */ - queue_work(ap_work_queue, &ap_config_work); - flush_work(&ap_config_work); + /* Delete the AP bus rescan timer. */ + del_timer(&ap_config_timer); + + /* processing a synchonuous bus rescan */ + ap_scan_bus(NULL); + + /* Setup the AP bus rescan timer again. */ + ap_config_timer.expires = jiffies + ap_config_time * HZ; + add_timer(&ap_config_timer); } EXPORT_SYMBOL(ap_bus_force_rescan); @@ -1301,9 +1305,8 @@ static void ap_scan_bus(struct work_struct *unused) int rc, i; ap_query_configuration(); - if (ap_select_domain() != 0) { + if (ap_select_domain() != 0) return; - } for (i = 0; i < AP_DEVICES; i++) { qid = AP_MKQID(i, ap_domain_index); dev = bus_find_device(&ap_bus_type, NULL, diff --git a/trunk/drivers/s390/kvm/kvm_virtio.c b/trunk/drivers/s390/kvm/kvm_virtio.c index 2ea6165366b6..6711e65764b5 100644 --- a/trunk/drivers/s390/kvm/kvm_virtio.c +++ b/trunk/drivers/s390/kvm/kvm_virtio.c @@ -443,30 +443,29 @@ static int __init test_devices_support(unsigned long addr) } /* * Init function for virtio - * devices are in a single page above top of "normal" + standby mem + * devices are in a single page above top of "normal" mem */ static int __init kvm_devices_init(void) { int rc; - unsigned long total_memory_size = sclp_get_rzm() * sclp_get_rnmax(); if (!MACHINE_IS_KVM) return -ENODEV; - if (test_devices_support(total_memory_size) < 0) + if (test_devices_support(real_memory_size) < 0) return -ENODEV; - rc = vmem_add_mapping(total_memory_size, PAGE_SIZE); + rc = vmem_add_mapping(real_memory_size, PAGE_SIZE); if (rc) return rc; - kvm_devices = (void *) total_memory_size; + kvm_devices = (void *) real_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); + vmem_remove_mapping(real_memory_size, PAGE_SIZE); return rc; } diff --git a/trunk/drivers/s390/kvm/virtio_ccw.c b/trunk/drivers/s390/kvm/virtio_ccw.c index 779dc5136291..fb877b59ec57 100644 --- a/trunk/drivers/s390/kvm/virtio_ccw.c +++ b/trunk/drivers/s390/kvm/virtio_ccw.c @@ -31,7 +31,6 @@ #include #include #include -#include /* * virtio related functions @@ -78,9 +77,12 @@ struct virtio_ccw_vq_info { void *queue; struct vq_info_block *info_block; struct list_head node; - long cookie; }; +#define KVM_VIRTIO_CCW_RING_ALIGN 4096 + +#define KVM_S390_VIRTIO_CCW_NOTIFY 3 + #define CCW_CMD_SET_VQ 0x13 #define CCW_CMD_VDEV_RESET 0x33 #define CCW_CMD_SET_IND 0x43 @@ -133,11 +135,8 @@ static int ccw_io_helper(struct virtio_ccw_device *vcdev, do { spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags); ret = ccw_device_start(vcdev->cdev, ccw, intparm, 0, 0); - if (!ret) { - if (!vcdev->curr_io) - vcdev->err = 0; + if (!ret) vcdev->curr_io |= flag; - } spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags); cpu_relax(); } while (ret == -EBUSY); @@ -146,18 +145,15 @@ static int ccw_io_helper(struct virtio_ccw_device *vcdev, } static inline long do_kvm_notify(struct subchannel_id schid, - unsigned long queue_index, - long cookie) + unsigned long queue_index) { register unsigned long __nr asm("1") = KVM_S390_VIRTIO_CCW_NOTIFY; register struct subchannel_id __schid asm("2") = schid; register unsigned long __index asm("3") = queue_index; register long __rc asm("2"); - register long __cookie asm("4") = cookie; asm volatile ("diag 2,4,0x500\n" - : "=d" (__rc) : "d" (__nr), "d" (__schid), "d" (__index), - "d"(__cookie) + : "=d" (__rc) : "d" (__nr), "d" (__schid), "d" (__index) : "memory", "cc"); return __rc; } @@ -170,7 +166,7 @@ static void virtio_ccw_kvm_notify(struct virtqueue *vq) vcdev = to_vc_device(info->vq->vdev); ccw_device_get_schid(vcdev->cdev, &schid); - info->cookie = do_kvm_notify(schid, vq->index, info->cookie); + do_kvm_notify(schid, vq->index); } static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, diff --git a/trunk/drivers/scsi/megaraid.c b/trunk/drivers/scsi/megaraid.c index 846f475f62c1..7373255aa1e8 100644 --- a/trunk/drivers/scsi/megaraid.c +++ b/trunk/drivers/scsi/megaraid.c @@ -2770,7 +2770,7 @@ static const struct file_operations mega_proc_fops = { .open = mega_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /* diff --git a/trunk/drivers/staging/comedi/proc.c b/trunk/drivers/staging/comedi/proc.c index 886c202de9ab..db790f9fc9db 100644 --- a/trunk/drivers/staging/comedi/proc.c +++ b/trunk/drivers/staging/comedi/proc.c @@ -86,7 +86,7 @@ static const struct file_operations comedi_proc_fops = { .open = comedi_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; void comedi_proc_init(void) diff --git a/trunk/drivers/staging/csr/io.c b/trunk/drivers/staging/csr/io.c index fe4a7ba2acc9..f9b5c22c00b8 100644 --- a/trunk/drivers/staging/csr/io.c +++ b/trunk/drivers/staging/csr/io.c @@ -95,7 +95,7 @@ static const struct file_operations uf_proc_fops = { .open = uf_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif /* CONFIG_PROC_FS */ diff --git a/trunk/drivers/staging/cxt1e1/sbeproc.c b/trunk/drivers/staging/cxt1e1/sbeproc.c index 9361dd8ce125..49f10f0b7d29 100644 --- a/trunk/drivers/staging/cxt1e1/sbeproc.c +++ b/trunk/drivers/staging/cxt1e1/sbeproc.c @@ -189,7 +189,7 @@ static const struct file_operations sbecom_proc_fops = { .open = sbecom_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /* diff --git a/trunk/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c b/trunk/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c index 94e426e4d98b..21b369e0150f 100644 --- a/trunk/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c +++ b/trunk/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c @@ -158,7 +158,7 @@ static const struct file_operations ft1000_proc_fops = { .open = ft1000_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int ft1000NotifyProc(struct notifier_block *this, unsigned long event, diff --git a/trunk/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/trunk/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index eca6f0292b4b..d8294d6c9560 100644 --- a/trunk/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/trunk/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -160,7 +160,7 @@ static const struct file_operations ft1000_proc_fops = { .open = ft1000_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int diff --git a/trunk/drivers/staging/rtl8187se/r8180_core.c b/trunk/drivers/staging/rtl8187se/r8180_core.c index ca691550436a..f7c1d9905ec6 100644 --- a/trunk/drivers/staging/rtl8187se/r8180_core.c +++ b/trunk/drivers/staging/rtl8187se/r8180_core.c @@ -306,7 +306,7 @@ static const struct file_operations rtl8180_proc_fops = { .open = rtl8180_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /* diff --git a/trunk/drivers/staging/rtl8192u/r8192U_core.c b/trunk/drivers/staging/rtl8192u/r8192U_core.c index 71f5cde9ed1c..145923397556 100644 --- a/trunk/drivers/staging/rtl8192u/r8192U_core.c +++ b/trunk/drivers/staging/rtl8192u/r8192U_core.c @@ -647,7 +647,7 @@ static const struct file_operations rtl8192_proc_fops = { .open = rtl8192_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /* diff --git a/trunk/drivers/staging/wlags49_h2/wl_main.c b/trunk/drivers/staging/wlags49_h2/wl_main.c index f28f15baea96..c4264e8c877d 100644 --- a/trunk/drivers/staging/wlags49_h2/wl_main.c +++ b/trunk/drivers/staging/wlags49_h2/wl_main.c @@ -160,7 +160,7 @@ static const struct file_operations scull_read_procmem_fops = { .open = scull_read_procmem_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif /* SCULL_USE_PROC */ diff --git a/trunk/drivers/tty/serial/sunsu.c b/trunk/drivers/tty/serial/sunsu.c index 0d8465728473..451687cb9685 100644 --- a/trunk/drivers/tty/serial/sunsu.c +++ b/trunk/drivers/tty/serial/sunsu.c @@ -1592,7 +1592,6 @@ static int __init sunsu_init(void) static void __exit sunsu_exit(void) { - platform_driver_unregister(&su_driver); if (sunsu_reg.nr) sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr); } diff --git a/trunk/drivers/usb/gadget/fsl_udc_core.c b/trunk/drivers/usb/gadget/fsl_udc_core.c index a766a4ca1cb7..2d8c1cfea699 100644 --- a/trunk/drivers/usb/gadget/fsl_udc_core.c +++ b/trunk/drivers/usb/gadget/fsl_udc_core.c @@ -2211,7 +2211,7 @@ static const struct file_operations fsl_proc_fops = { .open = fsl_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #define create_proc_file() proc_create(proc_filename, 0, NULL, &fsl_proc_fops) diff --git a/trunk/drivers/usb/gadget/goku_udc.c b/trunk/drivers/usb/gadget/goku_udc.c index 52dd6cc6c0aa..480eeb7cfd92 100644 --- a/trunk/drivers/usb/gadget/goku_udc.c +++ b/trunk/drivers/usb/gadget/goku_udc.c @@ -1214,7 +1214,7 @@ static const struct file_operations udc_proc_fops = { .open = udc_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ diff --git a/trunk/fs/autofs4/expire.c b/trunk/fs/autofs4/expire.c index 13ddec92341c..01443ce43ee7 100644 --- a/trunk/fs/autofs4/expire.c +++ b/trunk/fs/autofs4/expire.c @@ -61,6 +61,15 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) /* This is an autofs submount, we can't expire it */ if (autofs_type_indirect(sbi->type)) goto done; + + /* + * Otherwise it's an offset mount and we need to check + * if we can umount its mount, if there is one. + */ + if (!d_mountpoint(path.dentry)) { + status = 0; + goto done; + } } /* Update the expiry counter if fs is busy */ diff --git a/trunk/fs/autofs4/root.c b/trunk/fs/autofs4/root.c index 085da86e07c2..9bd16255dd9c 100644 --- a/trunk/fs/autofs4/root.c +++ b/trunk/fs/autofs4/root.c @@ -408,7 +408,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path) return NULL; } -static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk) +int autofs4_d_manage(struct dentry *dentry, bool rcu_walk) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_info *ino = autofs4_dentry_ino(dentry); diff --git a/trunk/fs/cifs/connect.c b/trunk/fs/cifs/connect.c index 21b3a291c327..06394f5478a2 100644 --- a/trunk/fs/cifs/connect.c +++ b/trunk/fs/cifs/connect.c @@ -95,9 +95,7 @@ enum { /* Mount options which take string value */ Opt_user, Opt_pass, Opt_ip, - Opt_unc, Opt_domain, - Opt_srcaddr, Opt_prefixpath, - Opt_iocharset, + Opt_domain, Opt_srcaddr, Opt_iocharset, Opt_netbiosname, Opt_servern, Opt_ver, Opt_vers, Opt_sec, Opt_cache, @@ -193,14 +191,14 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_blank_ip, "addr=" }, { Opt_ip, "ip=%s" }, { Opt_ip, "addr=%s" }, - { Opt_unc, "unc=%s" }, - { Opt_unc, "target=%s" }, - { Opt_unc, "path=%s" }, + { Opt_ignore, "unc=%s" }, + { Opt_ignore, "target=%s" }, + { Opt_ignore, "path=%s" }, { Opt_domain, "dom=%s" }, { Opt_domain, "domain=%s" }, { Opt_domain, "workgroup=%s" }, { Opt_srcaddr, "srcaddr=%s" }, - { Opt_prefixpath, "prefixpath=%s" }, + { Opt_ignore, "prefixpath=%s" }, { Opt_iocharset, "iocharset=%s" }, { Opt_netbiosname, "netbiosname=%s" }, { Opt_servern, "servern=%s" }, @@ -1660,30 +1658,6 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, } got_ip = true; break; - case Opt_unc: - string = vol->UNC; - vol->UNC = match_strdup(args); - if (vol->UNC == NULL) - goto out_nomem; - - convert_delimiter(vol->UNC, '\\'); - if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') { - printk(KERN_ERR "CIFS: UNC Path does not " - "begin with // or \\\\\n"); - goto cifs_parse_mount_err; - } - - /* Compare old unc= option to new one */ - if (!string || strcmp(string, vol->UNC)) - printk(KERN_WARNING "CIFS: the value of the " - "unc= mount option does not match the " - "device string. Using the unc= option " - "for now. In 3.10, that option will " - "be ignored and the contents of the " - "device string will be used " - "instead. (%s != %s)\n", string, - vol->UNC); - break; case Opt_domain: string = match_strdup(args); if (string == NULL) @@ -1716,26 +1690,6 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, goto cifs_parse_mount_err; } break; - case Opt_prefixpath: - /* skip over any leading delimiter */ - if (*args[0].from == '/' || *args[0].from == '\\') - args[0].from++; - - string = vol->prepath; - vol->prepath = match_strdup(args); - if (vol->prepath == NULL) - goto out_nomem; - /* Compare old prefixpath= option to new one */ - if (!string || strcmp(string, vol->prepath)) - printk(KERN_WARNING "CIFS: the value of the " - "prefixpath= mount option does not " - "match the device string. Using the " - "prefixpath= option for now. In 3.10, " - "that option will be ignored and the " - "contents of the device string will be " - "used instead.(%s != %s)\n", string, - vol->prepath); - break; case Opt_iocharset: string = match_strdup(args); if (string == NULL) diff --git a/trunk/include/asm-generic/cputime_nsecs.h b/trunk/include/asm-generic/cputime_nsecs.h index 2c9e62c2bfd0..a8ece9a33aef 100644 --- a/trunk/include/asm-generic/cputime_nsecs.h +++ b/trunk/include/asm-generic/cputime_nsecs.h @@ -16,27 +16,21 @@ #ifndef _ASM_GENERIC_CPUTIME_NSECS_H #define _ASM_GENERIC_CPUTIME_NSECS_H -#include - typedef u64 __nocast cputime_t; typedef u64 __nocast cputime64_t; #define cputime_one_jiffy jiffies_to_cputime(1) -#define cputime_div(__ct, divisor) div_u64((__force u64)__ct, divisor) -#define cputime_div_rem(__ct, divisor, remainder) \ - div_u64_rem((__force u64)__ct, divisor, remainder); - /* * Convert cputime <-> jiffies (HZ) */ #define cputime_to_jiffies(__ct) \ - cputime_div(__ct, NSEC_PER_SEC / HZ) + ((__force u64)(__ct) / (NSEC_PER_SEC / HZ)) #define cputime_to_scaled(__ct) (__ct) #define jiffies_to_cputime(__jif) \ (__force cputime_t)((__jif) * (NSEC_PER_SEC / HZ)) #define cputime64_to_jiffies64(__ct) \ - cputime_div(__ct, NSEC_PER_SEC / HZ) + ((__force u64)(__ct) / (NSEC_PER_SEC / HZ)) #define jiffies64_to_cputime64(__jif) \ (__force cputime64_t)((__jif) * (NSEC_PER_SEC / HZ)) @@ -51,7 +45,7 @@ typedef u64 __nocast cputime64_t; * Convert cputime <-> microseconds */ #define cputime_to_usecs(__ct) \ - cputime_div(__ct, NSEC_PER_USEC) + ((__force u64)(__ct) / NSEC_PER_USEC) #define usecs_to_cputime(__usecs) \ (__force cputime_t)((__usecs) * NSEC_PER_USEC) #define usecs_to_cputime64(__usecs) \ @@ -61,7 +55,7 @@ typedef u64 __nocast cputime64_t; * Convert cputime <-> seconds */ #define cputime_to_secs(__ct) \ - cputime_div(__ct, NSEC_PER_SEC) + ((__force u64)(__ct) / NSEC_PER_SEC) #define secs_to_cputime(__secs) \ (__force cputime_t)((__secs) * NSEC_PER_SEC) @@ -75,10 +69,8 @@ static inline cputime_t timespec_to_cputime(const struct timespec *val) } static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val) { - u32 rem; - - val->tv_sec = cputime_div_rem(ct, NSEC_PER_SEC, &rem); - val->tv_nsec = rem; + val->tv_sec = (__force u64) ct / NSEC_PER_SEC; + val->tv_nsec = (__force u64) ct % NSEC_PER_SEC; } /* @@ -91,17 +83,15 @@ static inline cputime_t timeval_to_cputime(const struct timeval *val) } static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val) { - u32 rem; - - val->tv_sec = cputime_div_rem(ct, NSEC_PER_SEC, &rem); - val->tv_usec = rem / NSEC_PER_USEC; + val->tv_sec = (__force u64) ct / NSEC_PER_SEC; + val->tv_usec = ((__force u64) ct % NSEC_PER_SEC) / NSEC_PER_USEC; } /* * Convert cputime <-> clock (USER_HZ) */ #define cputime_to_clock_t(__ct) \ - cputime_div(__ct, (NSEC_PER_SEC / USER_HZ)) + ((__force u64)(__ct) / (NSEC_PER_SEC / USER_HZ)) #define clock_t_to_cputime(__x) \ (__force cputime_t)((__x) * (NSEC_PER_SEC / USER_HZ)) diff --git a/trunk/include/asm-generic/unistd.h b/trunk/include/asm-generic/unistd.h index cccc86ecfeaa..0501fa3f783d 100644 --- a/trunk/include/asm-generic/unistd.h +++ b/trunk/include/asm-generic/unistd.h @@ -1,5 +1,4 @@ #include -#include /* * These are required system calls, we should diff --git a/trunk/include/asm-generic/vmlinux.lds.h b/trunk/include/asm-generic/vmlinux.lds.h index eb58d2d7d971..afa12c7a025c 100644 --- a/trunk/include/asm-generic/vmlinux.lds.h +++ b/trunk/include/asm-generic/vmlinux.lds.h @@ -52,7 +52,13 @@ #define LOAD_OFFSET 0 #endif -#include +#ifndef SYMBOL_PREFIX +#define VMLINUX_SYMBOL(sym) sym +#else +#define PASTE2(x,y) x##y +#define PASTE(x,y) PASTE2(x,y) +#define VMLINUX_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym) +#endif /* Align . to a 8 byte boundary equals to maximum function alignment. */ #define ALIGN_FUNCTION() . = ALIGN(8) diff --git a/trunk/include/linux/export.h b/trunk/include/linux/export.h index 412cd509effe..696c0f48afc7 100644 --- a/trunk/include/linux/export.h +++ b/trunk/include/linux/export.h @@ -5,24 +5,17 @@ * to reduce the amount of pointless cruft we feed to gcc when only * exporting a simple symbol or two. * - * Try not to add #includes here. It slows compilation and makes kernel - * hackers place grumpy comments in header files. + * If you feel the need to add #include to this file + * then you are doing something wrong and should go away silently. */ /* Some toolchains use a `_' prefix for all user symbols. */ -#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX -#define __VMLINUX_SYMBOL(x) _##x -#define __VMLINUX_SYMBOL_STR(x) "_" #x +#ifdef CONFIG_SYMBOL_PREFIX +#define MODULE_SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX #else -#define __VMLINUX_SYMBOL(x) x -#define __VMLINUX_SYMBOL_STR(x) #x +#define MODULE_SYMBOL_PREFIX "" #endif -/* Indirect, so macros are expanded before pasting. */ -#define VMLINUX_SYMBOL(x) __VMLINUX_SYMBOL(x) -#define VMLINUX_SYMBOL_STR(x) __VMLINUX_SYMBOL_STR(x) - -#ifndef __ASSEMBLY__ struct kernel_symbol { unsigned long value; @@ -58,7 +51,7 @@ extern struct module __this_module; __CRC_SYMBOL(sym, sec) \ static const char __kstrtab_##sym[] \ __attribute__((section("__ksymtab_strings"), aligned(1))) \ - = VMLINUX_SYMBOL_STR(sym); \ + = MODULE_SYMBOL_PREFIX #sym; \ static const struct kernel_symbol __ksymtab_##sym \ __used \ __attribute__((section("___ksymtab" sec "+" #sym), unused)) \ @@ -92,6 +85,5 @@ extern struct module __this_module; #define EXPORT_UNUSED_SYMBOL_GPL(sym) #endif /* CONFIG_MODULES */ -#endif /* !__ASSEMBLY__ */ #endif /* _LINUX_EXPORT_H */ diff --git a/trunk/include/linux/i2c/twl4030-madc.h b/trunk/include/linux/i2c/twl4030-madc.h index 01f595107048..530e11ba0738 100644 --- a/trunk/include/linux/i2c/twl4030-madc.h +++ b/trunk/include/linux/i2c/twl4030-madc.h @@ -39,7 +39,6 @@ struct twl4030_madc_conversion_method { * @do_avgP: sample the input channel for 4 consecutive cycles * @method: RT, SW1, SW2 * @type: Polling or interrupt based method - * @raw: Return raw value, do not convert it */ struct twl4030_madc_request { @@ -49,7 +48,6 @@ struct twl4030_madc_request { u16 type; bool active; bool result_pending; - bool raw; int rbuf[TWL4030_MADC_MAX_CHANNELS]; void (*func_cb)(int len, int channels, int *buf); }; diff --git a/trunk/include/linux/input/matrix_keypad.h b/trunk/include/linux/input/matrix_keypad.h index 27e06acc509a..5f3aa6b11bfa 100644 --- a/trunk/include/linux/input/matrix_keypad.h +++ b/trunk/include/linux/input/matrix_keypad.h @@ -81,23 +81,4 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, unsigned short *keymap, struct input_dev *input_dev); -#ifdef CONFIG_OF -/** - * matrix_keypad_parse_of_params() - Read parameters from matrix-keypad node - * - * @dev: Device containing of_node - * @rows: Returns number of matrix rows - * @cols: Returns number of matrix columns - * @return 0 if OK, <0 on error - */ -int matrix_keypad_parse_of_params(struct device *dev, - unsigned int *rows, unsigned int *cols); -#else -static inline int matrix_keypad_parse_of_params(struct device *dev, - unsigned int *rows, unsigned int *cols) -{ - return -ENOSYS; -} -#endif /* CONFIG_OF */ - #endif /* _MATRIX_KEYPAD_H */ diff --git a/trunk/include/linux/kernel.h b/trunk/include/linux/kernel.h index e96329ceb28c..6d1844f393c0 100644 --- a/trunk/include/linux/kernel.h +++ b/trunk/include/linux/kernel.h @@ -786,6 +786,13 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } /* Trap pasters of __FUNCTION__ at compile-time */ #define __FUNCTION__ (__func__) +/* This helps us to avoid #ifdef CONFIG_SYMBOL_PREFIX */ +#ifdef CONFIG_SYMBOL_PREFIX +#define SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX +#else +#define SYMBOL_PREFIX "" +#endif + /* Rebuild everything on CONFIG_FTRACE_MCOUNT_RECORD */ #ifdef CONFIG_FTRACE_MCOUNT_RECORD # define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD diff --git a/trunk/include/linux/kvm_host.h b/trunk/include/linux/kvm_host.h index f0eea07d2c2b..c13958251927 100644 --- a/trunk/include/linux/kvm_host.h +++ b/trunk/include/linux/kvm_host.h @@ -117,13 +117,14 @@ static inline bool is_error_page(struct page *page) #define KVM_REQ_APF_HALT 12 #define KVM_REQ_STEAL_UPDATE 13 #define KVM_REQ_NMI 14 -#define KVM_REQ_PMU 15 -#define KVM_REQ_PMI 16 -#define KVM_REQ_WATCHDOG 17 -#define KVM_REQ_MASTERCLOCK_UPDATE 18 -#define KVM_REQ_MCLOCK_INPROGRESS 19 -#define KVM_REQ_EPR_EXIT 20 -#define KVM_REQ_SCAN_IOAPIC 21 +#define KVM_REQ_IMMEDIATE_EXIT 15 +#define KVM_REQ_PMU 16 +#define KVM_REQ_PMI 17 +#define KVM_REQ_WATCHDOG 18 +#define KVM_REQ_MASTERCLOCK_UPDATE 19 +#define KVM_REQ_MCLOCK_INPROGRESS 20 +#define KVM_REQ_EPR_EXIT 21 +#define KVM_REQ_EOIBITMAP 22 #define KVM_USERSPACE_IRQ_SOURCE_ID 0 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 @@ -132,9 +133,6 @@ struct kvm; struct kvm_vcpu; extern struct kmem_cache *kvm_vcpu_cache; -extern raw_spinlock_t kvm_lock; -extern struct list_head vm_list; - struct kvm_io_range { gpa_t addr; int len; @@ -151,7 +149,6 @@ struct kvm_io_bus { enum kvm_bus { KVM_MMIO_BUS, KVM_PIO_BUS, - KVM_VIRTIO_CCW_NOTIFY_BUS, KVM_NR_BUSES }; @@ -255,7 +252,6 @@ struct kvm_vcpu { bool dy_eligible; } spin_loop; #endif - bool preempted; struct kvm_vcpu_arch arch; }; @@ -289,8 +285,7 @@ struct kvm_kernel_irq_routing_entry { u32 gsi; u32 type; int (*set)(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level, - bool line_status); + struct kvm *kvm, int irq_source_id, int level); union { struct { unsigned irqchip; @@ -301,10 +296,10 @@ struct kvm_kernel_irq_routing_entry { struct hlist_node link; }; -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC struct kvm_irq_routing_table { - int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS]; + int chip[KVM_NR_IRQCHIPS][KVM_IOAPIC_NUM_PINS]; struct kvm_kernel_irq_routing_entry *rt_entries; u32 nr_rt_entries; /* @@ -390,7 +385,6 @@ struct kvm { long mmu_notifier_count; #endif long tlbs_dirty; - struct list_head devices; }; #define kvm_err(fmt, ...) \ @@ -430,19 +424,6 @@ void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); int __must_check vcpu_load(struct kvm_vcpu *vcpu); void vcpu_put(struct kvm_vcpu *vcpu); -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING -int kvm_irqfd_init(void); -void kvm_irqfd_exit(void); -#else -static inline int kvm_irqfd_init(void) -{ - return 0; -} - -static inline void kvm_irqfd_exit(void) -{ -} -#endif int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, struct module *module); void kvm_exit(void); @@ -471,39 +452,24 @@ id_to_memslot(struct kvm_memslots *slots, int id) return slot; } -/* - * KVM_SET_USER_MEMORY_REGION ioctl allows the following operations: - * - create a new memory slot - * - delete an existing memory slot - * - modify an existing memory slot - * -- move it in the guest physical memory space - * -- just change its flags - * - * Since flags can be changed by some of these operations, the following - * differentiation is the best we can do for __kvm_set_memory_region(): - */ -enum kvm_mr_change { - KVM_MR_CREATE, - KVM_MR_DELETE, - KVM_MR_MOVE, - KVM_MR_FLAGS_ONLY, -}; - int kvm_set_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem); + struct kvm_userspace_memory_region *mem, + bool user_alloc); int __kvm_set_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem); + struct kvm_userspace_memory_region *mem, + bool user_alloc); void kvm_arch_free_memslot(struct kvm_memory_slot *free, struct kvm_memory_slot *dont); int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages); int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *memslot, + struct kvm_memory_slot old, struct kvm_userspace_memory_region *mem, - enum kvm_mr_change change); + bool user_alloc); void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, - const struct kvm_memory_slot *old, - enum kvm_mr_change change); + struct kvm_memory_slot old, + bool user_alloc); bool kvm_largepages_enabled(void); void kvm_disable_largepages(void); /* flush all memory translations */ @@ -573,7 +539,7 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); void kvm_flush_remote_tlbs(struct kvm *kvm); void kvm_reload_remote_mmus(struct kvm *kvm); void kvm_make_mclock_inprogress_request(struct kvm *kvm); -void kvm_make_scan_ioapic_request(struct kvm *kvm); +void kvm_make_update_eoibitmap_request(struct kvm *kvm); long kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); @@ -589,9 +555,10 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log); int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem); -int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level, - bool line_status); + struct + kvm_userspace_memory_region *mem, + bool user_alloc); +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level); long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); @@ -665,6 +632,7 @@ static inline wait_queue_head_t *kvm_arch_vcpu_wq(struct kvm_vcpu *vcpu) int kvm_arch_init_vm(struct kvm *kvm, unsigned long type); void kvm_arch_destroy_vm(struct kvm *kvm); +void kvm_free_all_assigned_devices(struct kvm *kvm); void kvm_arch_sync_events(struct kvm *kvm); int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); @@ -716,11 +684,15 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq, void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin, bool mask); -int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, - bool line_status); +#ifdef __KVM_HAVE_IOAPIC +void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic, + union kvm_ioapic_redirect_entry *entry, + unsigned long *deliver_bitmask); +#endif +int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level); int kvm_set_irq_inatomic(struct kvm *kvm, int irq_source_id, u32 irq, int level); int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm, - int irq_source_id, int level, bool line_status); + int irq_source_id, int level); bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin); void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin); void kvm_register_irq_ack_notifier(struct kvm *kvm, @@ -733,7 +705,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id); /* For vcpu->arch.iommu_flags */ #define KVM_IOMMU_CACHE_COHERENCY 0x1 -#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT +#ifdef CONFIG_IOMMU_API int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot); void kvm_iommu_unmap_pages(struct kvm *kvm, struct kvm_memory_slot *slot); int kvm_iommu_map_guest(struct kvm *kvm); @@ -742,7 +714,7 @@ int kvm_assign_device(struct kvm *kvm, struct kvm_assigned_dev_kernel *assigned_dev); int kvm_deassign_device(struct kvm *kvm, struct kvm_assigned_dev_kernel *assigned_dev); -#else +#else /* CONFIG_IOMMU_API */ static inline int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) { @@ -754,11 +726,28 @@ static inline void kvm_iommu_unmap_pages(struct kvm *kvm, { } +static inline int kvm_iommu_map_guest(struct kvm *kvm) +{ + return -ENODEV; +} + static inline int kvm_iommu_unmap_guest(struct kvm *kvm) { return 0; } -#endif + +static inline int kvm_assign_device(struct kvm *kvm, + struct kvm_assigned_dev_kernel *assigned_dev) +{ + return 0; +} + +static inline int kvm_deassign_device(struct kvm *kvm, + struct kvm_assigned_dev_kernel *assigned_dev) +{ + return 0; +} +#endif /* CONFIG_IOMMU_API */ static inline void __guest_enter(void) { @@ -932,7 +921,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq) } #endif -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef KVM_CAP_IRQ_ROUTING #define KVM_MAX_IRQ_ROUTES 1024 @@ -941,9 +930,6 @@ int kvm_set_irq_routing(struct kvm *kvm, const struct kvm_irq_routing_entry *entries, unsigned nr, unsigned flags); -int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, - struct kvm_kernel_irq_routing_entry *e, - const struct kvm_irq_routing_entry *ue); void kvm_free_irq_routing(struct kvm *kvm); int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi); @@ -1012,13 +998,11 @@ static inline bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) { return true; } #endif -#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT +#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl, unsigned long arg); -void kvm_free_all_assigned_devices(struct kvm *kvm); - #else static inline long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl, @@ -1027,8 +1011,6 @@ static inline long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl, return -ENOTTY; } -static inline void kvm_free_all_assigned_devices(struct kvm *kvm) {} - #endif static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu) @@ -1046,46 +1028,6 @@ static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu) } } -extern bool kvm_rebooting; - -struct kvm_device_ops; - -struct kvm_device { - struct kvm_device_ops *ops; - struct kvm *kvm; - void *private; - struct list_head vm_node; -}; - -/* create, destroy, and name are mandatory */ -struct kvm_device_ops { - const char *name; - int (*create)(struct kvm_device *dev, u32 type); - - /* - * Destroy is responsible for freeing dev. - * - * Destroy may be called before or after destructors are called - * on emulated I/O regions, depending on whether a reference is - * held by a vcpu or other kvm component that gets destroyed - * after the emulated I/O. - */ - void (*destroy)(struct kvm_device *dev); - - int (*set_attr)(struct kvm_device *dev, struct kvm_device_attr *attr); - int (*get_attr)(struct kvm_device *dev, struct kvm_device_attr *attr); - int (*has_attr)(struct kvm_device *dev, struct kvm_device_attr *attr); - long (*ioctl)(struct kvm_device *dev, unsigned int ioctl, - unsigned long arg); -}; - -void kvm_device_get(struct kvm_device *dev); -void kvm_device_put(struct kvm_device *dev); -struct kvm_device *kvm_device_from_filp(struct file *filp); - -extern struct kvm_device_ops kvm_mpic_ops; -extern struct kvm_device_ops kvm_xics_ops; - #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val) diff --git a/trunk/include/linux/linkage.h b/trunk/include/linux/linkage.h index d3e8ad23a8e0..de09dec25ec3 100644 --- a/trunk/include/linux/linkage.h +++ b/trunk/include/linux/linkage.h @@ -3,7 +3,6 @@ #include #include -#include #include #ifdef __cplusplus @@ -16,18 +15,21 @@ #define asmlinkage CPP_ASMLINKAGE #endif +#ifdef CONFIG_SYMBOL_PREFIX +#define __SYMBOL_NAME(x) CONFIG_SYMBOL_PREFIX __stringify(x) +#else +#define __SYMBOL_NAME(x) __stringify(x) +#endif + #ifndef cond_syscall -#define cond_syscall(x) asm( \ - ".weak " VMLINUX_SYMBOL_STR(x) "\n\t" \ - ".set " VMLINUX_SYMBOL_STR(x) "," \ - VMLINUX_SYMBOL_STR(sys_ni_syscall)) +#define cond_syscall(x) asm(".weak\t" __SYMBOL_NAME(x) \ + "\n\t.set\t" __SYMBOL_NAME(x) "," __SYMBOL_NAME(sys_ni_syscall)); #endif #ifndef SYSCALL_ALIAS -#define SYSCALL_ALIAS(alias, name) asm( \ - ".globl " VMLINUX_SYMBOL_STR(alias) "\n\t" \ - ".set " VMLINUX_SYMBOL_STR(alias) "," \ - VMLINUX_SYMBOL_STR(name)) +#define SYSCALL_ALIAS(alias, name) \ + asm ("\t.globl " __SYMBOL_NAME(alias) \ + "\n\t.set\t" __SYMBOL_NAME(alias) "," __SYMBOL_NAME(name)) #endif #define __page_aligned_data __section(.data..page_aligned) __aligned(PAGE_SIZE) diff --git a/trunk/include/linux/mfd/arizona/pdata.h b/trunk/include/linux/mfd/arizona/pdata.h index 80dead1f7100..a0f940987a3e 100644 --- a/trunk/include/linux/mfd/arizona/pdata.h +++ b/trunk/include/linux/mfd/arizona/pdata.h @@ -78,7 +78,6 @@ struct arizona_micbias { unsigned int ext_cap:1; /** External capacitor fitted */ unsigned int discharge:1; /** Actively discharge */ unsigned int fast_start:1; /** Enable aggressive startup ramp rate */ - unsigned int bypass:1; /** Use bypass mode */ }; struct arizona_micd_config { @@ -105,8 +104,7 @@ struct arizona_pdata { /** If a direct 32kHz clock is provided on an MCLK specify it here */ int clk32k_src; - /** Mode for primary IRQ (defaults to active low) */ - unsigned int irq_flags; + bool irq_active_high; /** IRQ polarity */ /* Base GPIO */ int gpio_base; @@ -185,9 +183,6 @@ struct arizona_pdata { /** Haptic actuator type */ unsigned int hap_act; - - /** GPIO for primary IRQ (used for edge triggered emulation) */ - int irq_gpio; }; #endif diff --git a/trunk/include/linux/mfd/cros_ec.h b/trunk/include/linux/mfd/cros_ec.h deleted file mode 100644 index 032af7fc5b2e..000000000000 --- a/trunk/include/linux/mfd/cros_ec.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * ChromeOS EC multi-function device - * - * Copyright (C) 2012 Google, Inc - * - * 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 __LINUX_MFD_CROS_EC_H -#define __LINUX_MFD_CROS_EC_H - -#include - -/* - * Command interface between EC and AP, for LPC, I2C and SPI interfaces. - */ -enum { - EC_MSG_TX_HEADER_BYTES = 3, - EC_MSG_TX_TRAILER_BYTES = 1, - EC_MSG_TX_PROTO_BYTES = EC_MSG_TX_HEADER_BYTES + - EC_MSG_TX_TRAILER_BYTES, - EC_MSG_RX_PROTO_BYTES = 3, - - /* Max length of messages */ - EC_MSG_BYTES = EC_HOST_PARAM_SIZE + EC_MSG_TX_PROTO_BYTES, - -}; - -/** - * struct cros_ec_msg - A message sent to the EC, and its reply - * - * @version: Command version number (often 0) - * @cmd: Command to send (EC_CMD_...) - * @out_buf: Outgoing payload (to EC) - * @outlen: Outgoing length - * @in_buf: Incoming payload (from EC) - * @in_len: Incoming length - */ -struct cros_ec_msg { - u8 version; - u8 cmd; - uint8_t *out_buf; - int out_len; - uint8_t *in_buf; - int in_len; -}; - -/** - * struct cros_ec_device - Information about a ChromeOS EC device - * - * @name: Name of this EC interface - * @priv: Private data - * @irq: Interrupt to use - * @din: input buffer (from EC) - * @dout: output buffer (to EC) - * \note - * These two buffers will always be dword-aligned and include enough - * space for up to 7 word-alignment bytes also, so we can ensure that - * the body of the message is always dword-aligned (64-bit). - * - * We use this alignment to keep ARM and x86 happy. Probably word - * alignment would be OK, there might be a small performance advantage - * to using dword. - * @din_size: size of din buffer - * @dout_size: size of dout buffer - * @command_send: send a command - * @command_recv: receive a command - * @ec_name: name of EC device (e.g. 'chromeos-ec') - * @phys_name: name of physical comms layer (e.g. 'i2c-4') - * @parent: pointer to parent device (e.g. i2c or spi device) - * @dev: Device pointer - * dev_lock: Lock to prevent concurrent access - * @wake_enabled: true if this device can wake the system from sleep - * @was_wake_device: true if this device was set to wake the system from - * sleep at the last suspend - * @event_notifier: interrupt event notifier for transport devices - */ -struct cros_ec_device { - const char *name; - void *priv; - int irq; - uint8_t *din; - uint8_t *dout; - int din_size; - int dout_size; - int (*command_send)(struct cros_ec_device *ec, - uint16_t cmd, void *out_buf, int out_len); - int (*command_recv)(struct cros_ec_device *ec, - uint16_t cmd, void *in_buf, int in_len); - int (*command_sendrecv)(struct cros_ec_device *ec, - uint16_t cmd, void *out_buf, int out_len, - void *in_buf, int in_len); - int (*command_xfer)(struct cros_ec_device *ec, - struct cros_ec_msg *msg); - - const char *ec_name; - const char *phys_name; - struct device *parent; - - /* These are --private-- fields - do not assign */ - struct device *dev; - struct mutex dev_lock; - bool wake_enabled; - bool was_wake_device; - struct blocking_notifier_head event_notifier; -}; - -/** - * cros_ec_suspend - Handle a suspend operation for the ChromeOS EC device - * - * This can be called by drivers to handle a suspend event. - * - * ec_dev: Device to suspend - * @return 0 if ok, -ve on error - */ -int cros_ec_suspend(struct cros_ec_device *ec_dev); - -/** - * cros_ec_resume - Handle a resume operation for the ChromeOS EC device - * - * This can be called by drivers to handle a resume event. - * - * @ec_dev: Device to resume - * @return 0 if ok, -ve on error - */ -int cros_ec_resume(struct cros_ec_device *ec_dev); - -/** - * cros_ec_prepare_tx - Prepare an outgoing message in the output buffer - * - * This is intended to be used by all ChromeOS EC drivers, but at present - * only SPI uses it. Once LPC uses the same protocol it can start using it. - * I2C could use it now, with a refactor of the existing code. - * - * @ec_dev: Device to register - * @msg: Message to write - */ -int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, - struct cros_ec_msg *msg); - -/** - * cros_ec_remove - Remove a ChromeOS EC - * - * Call this to deregister a ChromeOS EC. After this you should call - * cros_ec_free(). - * - * @ec_dev: Device to register - * @return 0 if ok, -ve on error - */ -int cros_ec_remove(struct cros_ec_device *ec_dev); - -/** - * cros_ec_register - Register a new ChromeOS EC, using the provided info - * - * Before calling this, allocate a pointer to a new device and then fill - * in all the fields up to the --private-- marker. - * - * @ec_dev: Device to register - * @return 0 if ok, -ve on error - */ -int cros_ec_register(struct cros_ec_device *ec_dev); - -#endif /* __LINUX_MFD_CROS_EC_H */ diff --git a/trunk/include/linux/mfd/cros_ec_commands.h b/trunk/include/linux/mfd/cros_ec_commands.h deleted file mode 100644 index 86fd06953bcd..000000000000 --- a/trunk/include/linux/mfd/cros_ec_commands.h +++ /dev/null @@ -1,1369 +0,0 @@ -/* - * Host communication command constants for ChromeOS EC - * - * Copyright (C) 2012 Google, Inc - * - * 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. - * - * The ChromeOS EC multi function device is used to mux all the requests - * to the EC device for its multiple features: keyboard controller, - * battery charging and regulator control, firmware update. - * - * NOTE: This file is copied verbatim from the ChromeOS EC Open Source - * project in an attempt to make future updates easy to make. - */ - -#ifndef __CROS_EC_COMMANDS_H -#define __CROS_EC_COMMANDS_H - -/* - * Protocol overview - * - * request: CMD [ P0 P1 P2 ... Pn S ] - * response: ERR [ P0 P1 P2 ... Pn S ] - * - * where the bytes are defined as follow : - * - CMD is the command code. (defined by EC_CMD_ constants) - * - ERR is the error code. (defined by EC_RES_ constants) - * - Px is the optional payload. - * it is not sent if the error code is not success. - * (defined by ec_params_ and ec_response_ structures) - * - S is the checksum which is the sum of all payload bytes. - * - * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD - * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM. - * On I2C, all bytes are sent serially in the same message. - */ - -/* Current version of this protocol */ -#define EC_PROTO_VERSION 0x00000002 - -/* Command version mask */ -#define EC_VER_MASK(version) (1UL << (version)) - -/* I/O addresses for ACPI commands */ -#define EC_LPC_ADDR_ACPI_DATA 0x62 -#define EC_LPC_ADDR_ACPI_CMD 0x66 - -/* I/O addresses for host command */ -#define EC_LPC_ADDR_HOST_DATA 0x200 -#define EC_LPC_ADDR_HOST_CMD 0x204 - -/* I/O addresses for host command args and params */ -#define EC_LPC_ADDR_HOST_ARGS 0x800 -#define EC_LPC_ADDR_HOST_PARAM 0x804 -#define EC_HOST_PARAM_SIZE 0x0fc /* Size of param area in bytes */ - -/* I/O addresses for host command params, old interface */ -#define EC_LPC_ADDR_OLD_PARAM 0x880 -#define EC_OLD_PARAM_SIZE 0x080 /* Size of param area in bytes */ - -/* EC command register bit functions */ -#define EC_LPC_CMDR_DATA (1 << 0) /* Data ready for host to read */ -#define EC_LPC_CMDR_PENDING (1 << 1) /* Write pending to EC */ -#define EC_LPC_CMDR_BUSY (1 << 2) /* EC is busy processing a command */ -#define EC_LPC_CMDR_CMD (1 << 3) /* Last host write was a command */ -#define EC_LPC_CMDR_ACPI_BRST (1 << 4) /* Burst mode (not used) */ -#define EC_LPC_CMDR_SCI (1 << 5) /* SCI event is pending */ -#define EC_LPC_CMDR_SMI (1 << 6) /* SMI event is pending */ - -#define EC_LPC_ADDR_MEMMAP 0x900 -#define EC_MEMMAP_SIZE 255 /* ACPI IO buffer max is 255 bytes */ -#define EC_MEMMAP_TEXT_MAX 8 /* Size of a string in the memory map */ - -/* The offset address of each type of data in mapped memory. */ -#define EC_MEMMAP_TEMP_SENSOR 0x00 /* Temp sensors */ -#define EC_MEMMAP_FAN 0x10 /* Fan speeds */ -#define EC_MEMMAP_TEMP_SENSOR_B 0x18 /* Temp sensors (second set) */ -#define EC_MEMMAP_ID 0x20 /* 'E' 'C' */ -#define EC_MEMMAP_ID_VERSION 0x22 /* Version of data in 0x20 - 0x2f */ -#define EC_MEMMAP_THERMAL_VERSION 0x23 /* Version of data in 0x00 - 0x1f */ -#define EC_MEMMAP_BATTERY_VERSION 0x24 /* Version of data in 0x40 - 0x7f */ -#define EC_MEMMAP_SWITCHES_VERSION 0x25 /* Version of data in 0x30 - 0x33 */ -#define EC_MEMMAP_EVENTS_VERSION 0x26 /* Version of data in 0x34 - 0x3f */ -#define EC_MEMMAP_HOST_CMD_FLAGS 0x27 /* Host command interface flags */ -#define EC_MEMMAP_SWITCHES 0x30 -#define EC_MEMMAP_HOST_EVENTS 0x34 -#define EC_MEMMAP_BATT_VOLT 0x40 /* Battery Present Voltage */ -#define EC_MEMMAP_BATT_RATE 0x44 /* Battery Present Rate */ -#define EC_MEMMAP_BATT_CAP 0x48 /* Battery Remaining Capacity */ -#define EC_MEMMAP_BATT_FLAG 0x4c /* Battery State, defined below */ -#define EC_MEMMAP_BATT_DCAP 0x50 /* Battery Design Capacity */ -#define EC_MEMMAP_BATT_DVLT 0x54 /* Battery Design Voltage */ -#define EC_MEMMAP_BATT_LFCC 0x58 /* Battery Last Full Charge Capacity */ -#define EC_MEMMAP_BATT_CCNT 0x5c /* Battery Cycle Count */ -#define EC_MEMMAP_BATT_MFGR 0x60 /* Battery Manufacturer String */ -#define EC_MEMMAP_BATT_MODEL 0x68 /* Battery Model Number String */ -#define EC_MEMMAP_BATT_SERIAL 0x70 /* Battery Serial Number String */ -#define EC_MEMMAP_BATT_TYPE 0x78 /* Battery Type String */ - -/* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */ -#define EC_TEMP_SENSOR_ENTRIES 16 -/* - * Number of temp sensors at EC_MEMMAP_TEMP_SENSOR_B. - * - * Valid only if EC_MEMMAP_THERMAL_VERSION returns >= 2. - */ -#define EC_TEMP_SENSOR_B_ENTRIES 8 -#define EC_TEMP_SENSOR_NOT_PRESENT 0xff -#define EC_TEMP_SENSOR_ERROR 0xfe -#define EC_TEMP_SENSOR_NOT_POWERED 0xfd -#define EC_TEMP_SENSOR_NOT_CALIBRATED 0xfc -/* - * The offset of temperature value stored in mapped memory. This allows - * reporting a temperature range of 200K to 454K = -73C to 181C. - */ -#define EC_TEMP_SENSOR_OFFSET 200 - -#define EC_FAN_SPEED_ENTRIES 4 /* Number of fans at EC_MEMMAP_FAN */ -#define EC_FAN_SPEED_NOT_PRESENT 0xffff /* Entry not present */ -#define EC_FAN_SPEED_STALLED 0xfffe /* Fan stalled */ - -/* Battery bit flags at EC_MEMMAP_BATT_FLAG. */ -#define EC_BATT_FLAG_AC_PRESENT 0x01 -#define EC_BATT_FLAG_BATT_PRESENT 0x02 -#define EC_BATT_FLAG_DISCHARGING 0x04 -#define EC_BATT_FLAG_CHARGING 0x08 -#define EC_BATT_FLAG_LEVEL_CRITICAL 0x10 - -/* Switch flags at EC_MEMMAP_SWITCHES */ -#define EC_SWITCH_LID_OPEN 0x01 -#define EC_SWITCH_POWER_BUTTON_PRESSED 0x02 -#define EC_SWITCH_WRITE_PROTECT_DISABLED 0x04 -/* Recovery requested via keyboard */ -#define EC_SWITCH_KEYBOARD_RECOVERY 0x08 -/* Recovery requested via dedicated signal (from servo board) */ -#define EC_SWITCH_DEDICATED_RECOVERY 0x10 -/* Was fake developer mode switch; now unused. Remove in next refactor. */ -#define EC_SWITCH_IGNORE0 0x20 - -/* Host command interface flags */ -/* Host command interface supports LPC args (LPC interface only) */ -#define EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED 0x01 - -/* Wireless switch flags */ -#define EC_WIRELESS_SWITCH_WLAN 0x01 -#define EC_WIRELESS_SWITCH_BLUETOOTH 0x02 - -/* - * This header file is used in coreboot both in C and ACPI code. The ACPI code - * is pre-processed to handle constants but the ASL compiler is unable to - * handle actual C code so keep it separate. - */ -#ifndef __ACPI__ - -/* LPC command status byte masks */ -/* EC has written a byte in the data register and host hasn't read it yet */ -#define EC_LPC_STATUS_TO_HOST 0x01 -/* Host has written a command/data byte and the EC hasn't read it yet */ -#define EC_LPC_STATUS_FROM_HOST 0x02 -/* EC is processing a command */ -#define EC_LPC_STATUS_PROCESSING 0x04 -/* Last write to EC was a command, not data */ -#define EC_LPC_STATUS_LAST_CMD 0x08 -/* EC is in burst mode. Unsupported by Chrome EC, so this bit is never set */ -#define EC_LPC_STATUS_BURST_MODE 0x10 -/* SCI event is pending (requesting SCI query) */ -#define EC_LPC_STATUS_SCI_PENDING 0x20 -/* SMI event is pending (requesting SMI query) */ -#define EC_LPC_STATUS_SMI_PENDING 0x40 -/* (reserved) */ -#define EC_LPC_STATUS_RESERVED 0x80 - -/* - * EC is busy. This covers both the EC processing a command, and the host has - * written a new command but the EC hasn't picked it up yet. - */ -#define EC_LPC_STATUS_BUSY_MASK \ - (EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING) - -/* Host command response codes */ -enum ec_status { - EC_RES_SUCCESS = 0, - EC_RES_INVALID_COMMAND = 1, - EC_RES_ERROR = 2, - EC_RES_INVALID_PARAM = 3, - EC_RES_ACCESS_DENIED = 4, - EC_RES_INVALID_RESPONSE = 5, - EC_RES_INVALID_VERSION = 6, - EC_RES_INVALID_CHECKSUM = 7, - EC_RES_IN_PROGRESS = 8, /* Accepted, command in progress */ - EC_RES_UNAVAILABLE = 9, /* No response available */ - EC_RES_TIMEOUT = 10, /* We got a timeout */ - EC_RES_OVERFLOW = 11, /* Table / data overflow */ -}; - -/* - * Host event codes. Note these are 1-based, not 0-based, because ACPI query - * EC command uses code 0 to mean "no event pending". We explicitly specify - * each value in the enum listing so they won't change if we delete/insert an - * item or rearrange the list (it needs to be stable across platforms, not - * just within a single compiled instance). - */ -enum host_event_code { - EC_HOST_EVENT_LID_CLOSED = 1, - EC_HOST_EVENT_LID_OPEN = 2, - EC_HOST_EVENT_POWER_BUTTON = 3, - EC_HOST_EVENT_AC_CONNECTED = 4, - EC_HOST_EVENT_AC_DISCONNECTED = 5, - EC_HOST_EVENT_BATTERY_LOW = 6, - EC_HOST_EVENT_BATTERY_CRITICAL = 7, - EC_HOST_EVENT_BATTERY = 8, - EC_HOST_EVENT_THERMAL_THRESHOLD = 9, - EC_HOST_EVENT_THERMAL_OVERLOAD = 10, - EC_HOST_EVENT_THERMAL = 11, - EC_HOST_EVENT_USB_CHARGER = 12, - EC_HOST_EVENT_KEY_PRESSED = 13, - /* - * EC has finished initializing the host interface. The host can check - * for this event following sending a EC_CMD_REBOOT_EC command to - * determine when the EC is ready to accept subsequent commands. - */ - EC_HOST_EVENT_INTERFACE_READY = 14, - /* Keyboard recovery combo has been pressed */ - EC_HOST_EVENT_KEYBOARD_RECOVERY = 15, - - /* Shutdown due to thermal overload */ - EC_HOST_EVENT_THERMAL_SHUTDOWN = 16, - /* Shutdown due to battery level too low */ - EC_HOST_EVENT_BATTERY_SHUTDOWN = 17, - - /* - * The high bit of the event mask is not used as a host event code. If - * it reads back as set, then the entire event mask should be - * considered invalid by the host. This can happen when reading the - * raw event status via EC_MEMMAP_HOST_EVENTS but the LPC interface is - * not initialized on the EC, or improperly configured on the host. - */ - EC_HOST_EVENT_INVALID = 32 -}; -/* Host event mask */ -#define EC_HOST_EVENT_MASK(event_code) (1UL << ((event_code) - 1)) - -/* Arguments at EC_LPC_ADDR_HOST_ARGS */ -struct ec_lpc_host_args { - uint8_t flags; - uint8_t command_version; - uint8_t data_size; - /* - * Checksum; sum of command + flags + command_version + data_size + - * all params/response data bytes. - */ - uint8_t checksum; -} __packed; - -/* Flags for ec_lpc_host_args.flags */ -/* - * Args are from host. Data area at EC_LPC_ADDR_HOST_PARAM contains command - * params. - * - * If EC gets a command and this flag is not set, this is an old-style command. - * Command version is 0 and params from host are at EC_LPC_ADDR_OLD_PARAM with - * unknown length. EC must respond with an old-style response (that is, - * withouth setting EC_HOST_ARGS_FLAG_TO_HOST). - */ -#define EC_HOST_ARGS_FLAG_FROM_HOST 0x01 -/* - * Args are from EC. Data area at EC_LPC_ADDR_HOST_PARAM contains response. - * - * If EC responds to a command and this flag is not set, this is an old-style - * response. Command version is 0 and response data from EC is at - * EC_LPC_ADDR_OLD_PARAM with unknown length. - */ -#define EC_HOST_ARGS_FLAG_TO_HOST 0x02 - -/* - * Notes on commands: - * - * Each command is an 8-byte command value. Commands which take params or - * return response data specify structs for that data. If no struct is - * specified, the command does not input or output data, respectively. - * Parameter/response length is implicit in the structs. Some underlying - * communication protocols (I2C, SPI) may add length or checksum headers, but - * those are implementation-dependent and not defined here. - */ - -/*****************************************************************************/ -/* General / test commands */ - -/* - * Get protocol version, used to deal with non-backward compatible protocol - * changes. - */ -#define EC_CMD_PROTO_VERSION 0x00 - -struct ec_response_proto_version { - uint32_t version; -} __packed; - -/* - * Hello. This is a simple command to test the EC is responsive to - * commands. - */ -#define EC_CMD_HELLO 0x01 - -struct ec_params_hello { - uint32_t in_data; /* Pass anything here */ -} __packed; - -struct ec_response_hello { - uint32_t out_data; /* Output will be in_data + 0x01020304 */ -} __packed; - -/* Get version number */ -#define EC_CMD_GET_VERSION 0x02 - -enum ec_current_image { - EC_IMAGE_UNKNOWN = 0, - EC_IMAGE_RO, - EC_IMAGE_RW -}; - -struct ec_response_get_version { - /* Null-terminated version strings for RO, RW */ - char version_string_ro[32]; - char version_string_rw[32]; - char reserved[32]; /* Was previously RW-B string */ - uint32_t current_image; /* One of ec_current_image */ -} __packed; - -/* Read test */ -#define EC_CMD_READ_TEST 0x03 - -struct ec_params_read_test { - uint32_t offset; /* Starting value for read buffer */ - uint32_t size; /* Size to read in bytes */ -} __packed; - -struct ec_response_read_test { - uint32_t data[32]; -} __packed; - -/* - * Get build information - * - * Response is null-terminated string. - */ -#define EC_CMD_GET_BUILD_INFO 0x04 - -/* Get chip info */ -#define EC_CMD_GET_CHIP_INFO 0x05 - -struct ec_response_get_chip_info { - /* Null-terminated strings */ - char vendor[32]; - char name[32]; - char revision[32]; /* Mask version */ -} __packed; - -/* Get board HW version */ -#define EC_CMD_GET_BOARD_VERSION 0x06 - -struct ec_response_board_version { - uint16_t board_version; /* A monotonously incrementing number. */ -} __packed; - -/* - * Read memory-mapped data. - * - * This is an alternate interface to memory-mapped data for bus protocols - * which don't support direct-mapped memory - I2C, SPI, etc. - * - * Response is params.size bytes of data. - */ -#define EC_CMD_READ_MEMMAP 0x07 - -struct ec_params_read_memmap { - uint8_t offset; /* Offset in memmap (EC_MEMMAP_*) */ - uint8_t size; /* Size to read in bytes */ -} __packed; - -/* Read versions supported for a command */ -#define EC_CMD_GET_CMD_VERSIONS 0x08 - -struct ec_params_get_cmd_versions { - uint8_t cmd; /* Command to check */ -} __packed; - -struct ec_response_get_cmd_versions { - /* - * Mask of supported versions; use EC_VER_MASK() to compare with a - * desired version. - */ - uint32_t version_mask; -} __packed; - -/* - * Check EC communcations status (busy). This is needed on i2c/spi but not - * on lpc since it has its own out-of-band busy indicator. - * - * lpc must read the status from the command register. Attempting this on - * lpc will overwrite the args/parameter space and corrupt its data. - */ -#define EC_CMD_GET_COMMS_STATUS 0x09 - -/* Avoid using ec_status which is for return values */ -enum ec_comms_status { - EC_COMMS_STATUS_PROCESSING = 1 << 0, /* Processing cmd */ -}; - -struct ec_response_get_comms_status { - uint32_t flags; /* Mask of enum ec_comms_status */ -} __packed; - - -/*****************************************************************************/ -/* Flash commands */ - -/* Get flash info */ -#define EC_CMD_FLASH_INFO 0x10 - -struct ec_response_flash_info { - /* Usable flash size, in bytes */ - uint32_t flash_size; - /* - * Write block size. Write offset and size must be a multiple - * of this. - */ - uint32_t write_block_size; - /* - * Erase block size. Erase offset and size must be a multiple - * of this. - */ - uint32_t erase_block_size; - /* - * Protection block size. Protection offset and size must be a - * multiple of this. - */ - uint32_t protect_block_size; -} __packed; - -/* - * Read flash - * - * Response is params.size bytes of data. - */ -#define EC_CMD_FLASH_READ 0x11 - -struct ec_params_flash_read { - uint32_t offset; /* Byte offset to read */ - uint32_t size; /* Size to read in bytes */ -} __packed; - -/* Write flash */ -#define EC_CMD_FLASH_WRITE 0x12 - -struct ec_params_flash_write { - uint32_t offset; /* Byte offset to write */ - uint32_t size; /* Size to write in bytes */ - /* - * Data to write. Could really use EC_PARAM_SIZE - 8, but tidiest to - * use a power of 2 so writes stay aligned. - */ - uint8_t data[64]; -} __packed; - -/* Erase flash */ -#define EC_CMD_FLASH_ERASE 0x13 - -struct ec_params_flash_erase { - uint32_t offset; /* Byte offset to erase */ - uint32_t size; /* Size to erase in bytes */ -} __packed; - -/* - * Get/set flash protection. - * - * If mask!=0, sets/clear the requested bits of flags. Depending on the - * firmware write protect GPIO, not all flags will take effect immediately; - * some flags require a subsequent hard reset to take effect. Check the - * returned flags bits to see what actually happened. - * - * If mask=0, simply returns the current flags state. - */ -#define EC_CMD_FLASH_PROTECT 0x15 -#define EC_VER_FLASH_PROTECT 1 /* Command version 1 */ - -/* Flags for flash protection */ -/* RO flash code protected when the EC boots */ -#define EC_FLASH_PROTECT_RO_AT_BOOT (1 << 0) -/* - * RO flash code protected now. If this bit is set, at-boot status cannot - * be changed. - */ -#define EC_FLASH_PROTECT_RO_NOW (1 << 1) -/* Entire flash code protected now, until reboot. */ -#define EC_FLASH_PROTECT_ALL_NOW (1 << 2) -/* Flash write protect GPIO is asserted now */ -#define EC_FLASH_PROTECT_GPIO_ASSERTED (1 << 3) -/* Error - at least one bank of flash is stuck locked, and cannot be unlocked */ -#define EC_FLASH_PROTECT_ERROR_STUCK (1 << 4) -/* - * Error - flash protection is in inconsistent state. At least one bank of - * flash which should be protected is not protected. Usually fixed by - * re-requesting the desired flags, or by a hard reset if that fails. - */ -#define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5) -/* Entile flash code protected when the EC boots */ -#define EC_FLASH_PROTECT_ALL_AT_BOOT (1 << 6) - -struct ec_params_flash_protect { - uint32_t mask; /* Bits in flags to apply */ - uint32_t flags; /* New flags to apply */ -} __packed; - -struct ec_response_flash_protect { - /* Current value of flash protect flags */ - uint32_t flags; - /* - * Flags which are valid on this platform. This allows the caller - * to distinguish between flags which aren't set vs. flags which can't - * be set on this platform. - */ - uint32_t valid_flags; - /* Flags which can be changed given the current protection state */ - uint32_t writable_flags; -} __packed; - -/* - * Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash - * write protect. These commands may be reused with version > 0. - */ - -/* Get the region offset/size */ -#define EC_CMD_FLASH_REGION_INFO 0x16 -#define EC_VER_FLASH_REGION_INFO 1 - -enum ec_flash_region { - /* Region which holds read-only EC image */ - EC_FLASH_REGION_RO, - /* Region which holds rewritable EC image */ - EC_FLASH_REGION_RW, - /* - * Region which should be write-protected in the factory (a superset of - * EC_FLASH_REGION_RO) - */ - EC_FLASH_REGION_WP_RO, -}; - -struct ec_params_flash_region_info { - uint32_t region; /* enum ec_flash_region */ -} __packed; - -struct ec_response_flash_region_info { - uint32_t offset; - uint32_t size; -} __packed; - -/* Read/write VbNvContext */ -#define EC_CMD_VBNV_CONTEXT 0x17 -#define EC_VER_VBNV_CONTEXT 1 -#define EC_VBNV_BLOCK_SIZE 16 - -enum ec_vbnvcontext_op { - EC_VBNV_CONTEXT_OP_READ, - EC_VBNV_CONTEXT_OP_WRITE, -}; - -struct ec_params_vbnvcontext { - uint32_t op; - uint8_t block[EC_VBNV_BLOCK_SIZE]; -} __packed; - -struct ec_response_vbnvcontext { - uint8_t block[EC_VBNV_BLOCK_SIZE]; -} __packed; - -/*****************************************************************************/ -/* PWM commands */ - -/* Get fan target RPM */ -#define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x20 - -struct ec_response_pwm_get_fan_rpm { - uint32_t rpm; -} __packed; - -/* Set target fan RPM */ -#define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x21 - -struct ec_params_pwm_set_fan_target_rpm { - uint32_t rpm; -} __packed; - -/* Get keyboard backlight */ -#define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x22 - -struct ec_response_pwm_get_keyboard_backlight { - uint8_t percent; - uint8_t enabled; -} __packed; - -/* Set keyboard backlight */ -#define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x23 - -struct ec_params_pwm_set_keyboard_backlight { - uint8_t percent; -} __packed; - -/* Set target fan PWM duty cycle */ -#define EC_CMD_PWM_SET_FAN_DUTY 0x24 - -struct ec_params_pwm_set_fan_duty { - uint32_t percent; -} __packed; - -/*****************************************************************************/ -/* - * Lightbar commands. This looks worse than it is. Since we only use one HOST - * command to say "talk to the lightbar", we put the "and tell it to do X" part - * into a subcommand. We'll make separate structs for subcommands with - * different input args, so that we know how much to expect. - */ -#define EC_CMD_LIGHTBAR_CMD 0x28 - -struct rgb_s { - uint8_t r, g, b; -}; - -#define LB_BATTERY_LEVELS 4 -/* List of tweakable parameters. NOTE: It's __packed so it can be sent in a - * host command, but the alignment is the same regardless. Keep it that way. - */ -struct lightbar_params { - /* Timing */ - int google_ramp_up; - int google_ramp_down; - int s3s0_ramp_up; - int s0_tick_delay[2]; /* AC=0/1 */ - int s0a_tick_delay[2]; /* AC=0/1 */ - int s0s3_ramp_down; - int s3_sleep_for; - int s3_ramp_up; - int s3_ramp_down; - - /* Oscillation */ - uint8_t new_s0; - uint8_t osc_min[2]; /* AC=0/1 */ - uint8_t osc_max[2]; /* AC=0/1 */ - uint8_t w_ofs[2]; /* AC=0/1 */ - - /* Brightness limits based on the backlight and AC. */ - uint8_t bright_bl_off_fixed[2]; /* AC=0/1 */ - uint8_t bright_bl_on_min[2]; /* AC=0/1 */ - uint8_t bright_bl_on_max[2]; /* AC=0/1 */ - - /* Battery level thresholds */ - uint8_t battery_threshold[LB_BATTERY_LEVELS - 1]; - - /* Map [AC][battery_level] to color index */ - uint8_t s0_idx[2][LB_BATTERY_LEVELS]; /* AP is running */ - uint8_t s3_idx[2][LB_BATTERY_LEVELS]; /* AP is sleeping */ - - /* Color palette */ - struct rgb_s color[8]; /* 0-3 are Google colors */ -} __packed; - -struct ec_params_lightbar { - uint8_t cmd; /* Command (see enum lightbar_command) */ - union { - struct { - /* no args */ - } dump, off, on, init, get_seq, get_params; - - struct num { - uint8_t num; - } brightness, seq, demo; - - struct reg { - uint8_t ctrl, reg, value; - } reg; - - struct rgb { - uint8_t led, red, green, blue; - } rgb; - - struct lightbar_params set_params; - }; -} __packed; - -struct ec_response_lightbar { - union { - struct dump { - struct { - uint8_t reg; - uint8_t ic0; - uint8_t ic1; - } vals[23]; - } dump; - - struct get_seq { - uint8_t num; - } get_seq; - - struct lightbar_params get_params; - - struct { - /* no return params */ - } off, on, init, brightness, seq, reg, rgb, demo, set_params; - }; -} __packed; - -/* Lightbar commands */ -enum lightbar_command { - LIGHTBAR_CMD_DUMP = 0, - LIGHTBAR_CMD_OFF = 1, - LIGHTBAR_CMD_ON = 2, - LIGHTBAR_CMD_INIT = 3, - LIGHTBAR_CMD_BRIGHTNESS = 4, - LIGHTBAR_CMD_SEQ = 5, - LIGHTBAR_CMD_REG = 6, - LIGHTBAR_CMD_RGB = 7, - LIGHTBAR_CMD_GET_SEQ = 8, - LIGHTBAR_CMD_DEMO = 9, - LIGHTBAR_CMD_GET_PARAMS = 10, - LIGHTBAR_CMD_SET_PARAMS = 11, - LIGHTBAR_NUM_CMDS -}; - -/*****************************************************************************/ -/* Verified boot commands */ - -/* - * Note: command code 0x29 version 0 was VBOOT_CMD in Link EVT; it may be - * reused for other purposes with version > 0. - */ - -/* Verified boot hash command */ -#define EC_CMD_VBOOT_HASH 0x2A - -struct ec_params_vboot_hash { - uint8_t cmd; /* enum ec_vboot_hash_cmd */ - uint8_t hash_type; /* enum ec_vboot_hash_type */ - uint8_t nonce_size; /* Nonce size; may be 0 */ - uint8_t reserved0; /* Reserved; set 0 */ - uint32_t offset; /* Offset in flash to hash */ - uint32_t size; /* Number of bytes to hash */ - uint8_t nonce_data[64]; /* Nonce data; ignored if nonce_size=0 */ -} __packed; - -struct ec_response_vboot_hash { - uint8_t status; /* enum ec_vboot_hash_status */ - uint8_t hash_type; /* enum ec_vboot_hash_type */ - uint8_t digest_size; /* Size of hash digest in bytes */ - uint8_t reserved0; /* Ignore; will be 0 */ - uint32_t offset; /* Offset in flash which was hashed */ - uint32_t size; /* Number of bytes hashed */ - uint8_t hash_digest[64]; /* Hash digest data */ -} __packed; - -enum ec_vboot_hash_cmd { - EC_VBOOT_HASH_GET = 0, /* Get current hash status */ - EC_VBOOT_HASH_ABORT = 1, /* Abort calculating current hash */ - EC_VBOOT_HASH_START = 2, /* Start computing a new hash */ - EC_VBOOT_HASH_RECALC = 3, /* Synchronously compute a new hash */ -}; - -enum ec_vboot_hash_type { - EC_VBOOT_HASH_TYPE_SHA256 = 0, /* SHA-256 */ -}; - -enum ec_vboot_hash_status { - EC_VBOOT_HASH_STATUS_NONE = 0, /* No hash (not started, or aborted) */ - EC_VBOOT_HASH_STATUS_DONE = 1, /* Finished computing a hash */ - EC_VBOOT_HASH_STATUS_BUSY = 2, /* Busy computing a hash */ -}; - -/* - * Special values for offset for EC_VBOOT_HASH_START and EC_VBOOT_HASH_RECALC. - * If one of these is specified, the EC will automatically update offset and - * size to the correct values for the specified image (RO or RW). - */ -#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe -#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd - -/*****************************************************************************/ -/* USB charging control commands */ - -/* Set USB port charging mode */ -#define EC_CMD_USB_CHARGE_SET_MODE 0x30 - -struct ec_params_usb_charge_set_mode { - uint8_t usb_port_id; - uint8_t mode; -} __packed; - -/*****************************************************************************/ -/* Persistent storage for host */ - -/* Maximum bytes that can be read/written in a single command */ -#define EC_PSTORE_SIZE_MAX 64 - -/* Get persistent storage info */ -#define EC_CMD_PSTORE_INFO 0x40 - -struct ec_response_pstore_info { - /* Persistent storage size, in bytes */ - uint32_t pstore_size; - /* Access size; read/write offset and size must be a multiple of this */ - uint32_t access_size; -} __packed; - -/* - * Read persistent storage - * - * Response is params.size bytes of data. - */ -#define EC_CMD_PSTORE_READ 0x41 - -struct ec_params_pstore_read { - uint32_t offset; /* Byte offset to read */ - uint32_t size; /* Size to read in bytes */ -} __packed; - -/* Write persistent storage */ -#define EC_CMD_PSTORE_WRITE 0x42 - -struct ec_params_pstore_write { - uint32_t offset; /* Byte offset to write */ - uint32_t size; /* Size to write in bytes */ - uint8_t data[EC_PSTORE_SIZE_MAX]; -} __packed; - -/*****************************************************************************/ -/* Real-time clock */ - -/* RTC params and response structures */ -struct ec_params_rtc { - uint32_t time; -} __packed; - -struct ec_response_rtc { - uint32_t time; -} __packed; - -/* These use ec_response_rtc */ -#define EC_CMD_RTC_GET_VALUE 0x44 -#define EC_CMD_RTC_GET_ALARM 0x45 - -/* These all use ec_params_rtc */ -#define EC_CMD_RTC_SET_VALUE 0x46 -#define EC_CMD_RTC_SET_ALARM 0x47 - -/*****************************************************************************/ -/* Port80 log access */ - -/* Get last port80 code from previous boot */ -#define EC_CMD_PORT80_LAST_BOOT 0x48 - -struct ec_response_port80_last_boot { - uint16_t code; -} __packed; - -/*****************************************************************************/ -/* Thermal engine commands */ - -/* Set thershold value */ -#define EC_CMD_THERMAL_SET_THRESHOLD 0x50 - -struct ec_params_thermal_set_threshold { - uint8_t sensor_type; - uint8_t threshold_id; - uint16_t value; -} __packed; - -/* Get threshold value */ -#define EC_CMD_THERMAL_GET_THRESHOLD 0x51 - -struct ec_params_thermal_get_threshold { - uint8_t sensor_type; - uint8_t threshold_id; -} __packed; - -struct ec_response_thermal_get_threshold { - uint16_t value; -} __packed; - -/* Toggle automatic fan control */ -#define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52 - -/* Get TMP006 calibration data */ -#define EC_CMD_TMP006_GET_CALIBRATION 0x53 - -struct ec_params_tmp006_get_calibration { - uint8_t index; -} __packed; - -struct ec_response_tmp006_get_calibration { - float s0; - float b0; - float b1; - float b2; -} __packed; - -/* Set TMP006 calibration data */ -#define EC_CMD_TMP006_SET_CALIBRATION 0x54 - -struct ec_params_tmp006_set_calibration { - uint8_t index; - uint8_t reserved[3]; /* Reserved; set 0 */ - float s0; - float b0; - float b1; - float b2; -} __packed; - -/*****************************************************************************/ -/* MKBP - Matrix KeyBoard Protocol */ - -/* - * Read key state - * - * Returns raw data for keyboard cols; see ec_response_mkbp_info.cols for - * expected response size. - */ -#define EC_CMD_MKBP_STATE 0x60 - -/* Provide information about the matrix : number of rows and columns */ -#define EC_CMD_MKBP_INFO 0x61 - -struct ec_response_mkbp_info { - uint32_t rows; - uint32_t cols; - uint8_t switches; -} __packed; - -/* Simulate key press */ -#define EC_CMD_MKBP_SIMULATE_KEY 0x62 - -struct ec_params_mkbp_simulate_key { - uint8_t col; - uint8_t row; - uint8_t pressed; -} __packed; - -/* Configure keyboard scanning */ -#define EC_CMD_MKBP_SET_CONFIG 0x64 -#define EC_CMD_MKBP_GET_CONFIG 0x65 - -/* flags */ -enum mkbp_config_flags { - EC_MKBP_FLAGS_ENABLE = 1, /* Enable keyboard scanning */ -}; - -enum mkbp_config_valid { - EC_MKBP_VALID_SCAN_PERIOD = 1 << 0, - EC_MKBP_VALID_POLL_TIMEOUT = 1 << 1, - EC_MKBP_VALID_MIN_POST_SCAN_DELAY = 1 << 3, - EC_MKBP_VALID_OUTPUT_SETTLE = 1 << 4, - EC_MKBP_VALID_DEBOUNCE_DOWN = 1 << 5, - EC_MKBP_VALID_DEBOUNCE_UP = 1 << 6, - EC_MKBP_VALID_FIFO_MAX_DEPTH = 1 << 7, -}; - -/* Configuration for our key scanning algorithm */ -struct ec_mkbp_config { - uint32_t valid_mask; /* valid fields */ - uint8_t flags; /* some flags (enum mkbp_config_flags) */ - uint8_t valid_flags; /* which flags are valid */ - uint16_t scan_period_us; /* period between start of scans */ - /* revert to interrupt mode after no activity for this long */ - uint32_t poll_timeout_us; - /* - * minimum post-scan relax time. Once we finish a scan we check - * the time until we are due to start the next one. If this time is - * shorter this field, we use this instead. - */ - uint16_t min_post_scan_delay_us; - /* delay between setting up output and waiting for it to settle */ - uint16_t output_settle_us; - uint16_t debounce_down_us; /* time for debounce on key down */ - uint16_t debounce_up_us; /* time for debounce on key up */ - /* maximum depth to allow for fifo (0 = no keyscan output) */ - uint8_t fifo_max_depth; -} __packed; - -struct ec_params_mkbp_set_config { - struct ec_mkbp_config config; -} __packed; - -struct ec_response_mkbp_get_config { - struct ec_mkbp_config config; -} __packed; - -/* Run the key scan emulation */ -#define EC_CMD_KEYSCAN_SEQ_CTRL 0x66 - -enum ec_keyscan_seq_cmd { - EC_KEYSCAN_SEQ_STATUS = 0, /* Get status information */ - EC_KEYSCAN_SEQ_CLEAR = 1, /* Clear sequence */ - EC_KEYSCAN_SEQ_ADD = 2, /* Add item to sequence */ - EC_KEYSCAN_SEQ_START = 3, /* Start running sequence */ - EC_KEYSCAN_SEQ_COLLECT = 4, /* Collect sequence summary data */ -}; - -enum ec_collect_flags { - /* - * Indicates this scan was processed by the EC. Due to timing, some - * scans may be skipped. - */ - EC_KEYSCAN_SEQ_FLAG_DONE = 1 << 0, -}; - -struct ec_collect_item { - uint8_t flags; /* some flags (enum ec_collect_flags) */ -}; - -struct ec_params_keyscan_seq_ctrl { - uint8_t cmd; /* Command to send (enum ec_keyscan_seq_cmd) */ - union { - struct { - uint8_t active; /* still active */ - uint8_t num_items; /* number of items */ - /* Current item being presented */ - uint8_t cur_item; - } status; - struct { - /* - * Absolute time for this scan, measured from the - * start of the sequence. - */ - uint32_t time_us; - uint8_t scan[0]; /* keyscan data */ - } add; - struct { - uint8_t start_item; /* First item to return */ - uint8_t num_items; /* Number of items to return */ - } collect; - }; -} __packed; - -struct ec_result_keyscan_seq_ctrl { - union { - struct { - uint8_t num_items; /* Number of items */ - /* Data for each item */ - struct ec_collect_item item[0]; - } collect; - }; -} __packed; - -/*****************************************************************************/ -/* Temperature sensor commands */ - -/* Read temperature sensor info */ -#define EC_CMD_TEMP_SENSOR_GET_INFO 0x70 - -struct ec_params_temp_sensor_get_info { - uint8_t id; -} __packed; - -struct ec_response_temp_sensor_get_info { - char sensor_name[32]; - uint8_t sensor_type; -} __packed; - -/*****************************************************************************/ - -/* - * Note: host commands 0x80 - 0x87 are reserved to avoid conflict with ACPI - * commands accidentally sent to the wrong interface. See the ACPI section - * below. - */ - -/*****************************************************************************/ -/* Host event commands */ - -/* - * Host event mask params and response structures, shared by all of the host - * event commands below. - */ -struct ec_params_host_event_mask { - uint32_t mask; -} __packed; - -struct ec_response_host_event_mask { - uint32_t mask; -} __packed; - -/* These all use ec_response_host_event_mask */ -#define EC_CMD_HOST_EVENT_GET_B 0x87 -#define EC_CMD_HOST_EVENT_GET_SMI_MASK 0x88 -#define EC_CMD_HOST_EVENT_GET_SCI_MASK 0x89 -#define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x8d - -/* These all use ec_params_host_event_mask */ -#define EC_CMD_HOST_EVENT_SET_SMI_MASK 0x8a -#define EC_CMD_HOST_EVENT_SET_SCI_MASK 0x8b -#define EC_CMD_HOST_EVENT_CLEAR 0x8c -#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x8e -#define EC_CMD_HOST_EVENT_CLEAR_B 0x8f - -/*****************************************************************************/ -/* Switch commands */ - -/* Enable/disable LCD backlight */ -#define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x90 - -struct ec_params_switch_enable_backlight { - uint8_t enabled; -} __packed; - -/* Enable/disable WLAN/Bluetooth */ -#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91 - -struct ec_params_switch_enable_wireless { - uint8_t enabled; -} __packed; - -/*****************************************************************************/ -/* GPIO commands. Only available on EC if write protect has been disabled. */ - -/* Set GPIO output value */ -#define EC_CMD_GPIO_SET 0x92 - -struct ec_params_gpio_set { - char name[32]; - uint8_t val; -} __packed; - -/* Get GPIO value */ -#define EC_CMD_GPIO_GET 0x93 - -struct ec_params_gpio_get { - char name[32]; -} __packed; -struct ec_response_gpio_get { - uint8_t val; -} __packed; - -/*****************************************************************************/ -/* I2C commands. Only available when flash write protect is unlocked. */ - -/* Read I2C bus */ -#define EC_CMD_I2C_READ 0x94 - -struct ec_params_i2c_read { - uint16_t addr; - uint8_t read_size; /* Either 8 or 16. */ - uint8_t port; - uint8_t offset; -} __packed; -struct ec_response_i2c_read { - uint16_t data; -} __packed; - -/* Write I2C bus */ -#define EC_CMD_I2C_WRITE 0x95 - -struct ec_params_i2c_write { - uint16_t data; - uint16_t addr; - uint8_t write_size; /* Either 8 or 16. */ - uint8_t port; - uint8_t offset; -} __packed; - -/*****************************************************************************/ -/* Charge state commands. Only available when flash write protect unlocked. */ - -/* Force charge state machine to stop in idle mode */ -#define EC_CMD_CHARGE_FORCE_IDLE 0x96 - -struct ec_params_force_idle { - uint8_t enabled; -} __packed; - -/*****************************************************************************/ -/* Console commands. Only available when flash write protect is unlocked. */ - -/* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */ -#define EC_CMD_CONSOLE_SNAPSHOT 0x97 - -/* - * Read next chunk of data from saved snapshot. - * - * Response is null-terminated string. Empty string, if there is no more - * remaining output. - */ -#define EC_CMD_CONSOLE_READ 0x98 - -/*****************************************************************************/ - -/* - * Cut off battery power output if the battery supports. - * - * For unsupported battery, just don't implement this command and lets EC - * return EC_RES_INVALID_COMMAND. - */ -#define EC_CMD_BATTERY_CUT_OFF 0x99 - -/*****************************************************************************/ -/* Temporary debug commands. TODO: remove this crosbug.com/p/13849 */ - -/* - * Dump charge state machine context. - * - * Response is a binary dump of charge state machine context. - */ -#define EC_CMD_CHARGE_DUMP 0xa0 - -/* - * Set maximum battery charging current. - */ -#define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1 - -struct ec_params_current_limit { - uint32_t limit; -} __packed; - -/*****************************************************************************/ -/* System commands */ - -/* - * TODO: this is a confusing name, since it doesn't necessarily reboot the EC. - * Rename to "set image" or something similar. - */ -#define EC_CMD_REBOOT_EC 0xd2 - -/* Command */ -enum ec_reboot_cmd { - EC_REBOOT_CANCEL = 0, /* Cancel a pending reboot */ - EC_REBOOT_JUMP_RO = 1, /* Jump to RO without rebooting */ - EC_REBOOT_JUMP_RW = 2, /* Jump to RW without rebooting */ - /* (command 3 was jump to RW-B) */ - EC_REBOOT_COLD = 4, /* Cold-reboot */ - EC_REBOOT_DISABLE_JUMP = 5, /* Disable jump until next reboot */ - EC_REBOOT_HIBERNATE = 6 /* Hibernate EC */ -}; - -/* Flags for ec_params_reboot_ec.reboot_flags */ -#define EC_REBOOT_FLAG_RESERVED0 (1 << 0) /* Was recovery request */ -#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1) /* Reboot after AP shutdown */ - -struct ec_params_reboot_ec { - uint8_t cmd; /* enum ec_reboot_cmd */ - uint8_t flags; /* See EC_REBOOT_FLAG_* */ -} __packed; - -/* - * Get information on last EC panic. - * - * Returns variable-length platform-dependent panic information. See panic.h - * for details. - */ -#define EC_CMD_GET_PANIC_INFO 0xd3 - -/*****************************************************************************/ -/* - * ACPI commands - * - * These are valid ONLY on the ACPI command/data port. - */ - -/* - * ACPI Read Embedded Controller - * - * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*). - * - * Use the following sequence: - * - * - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD - * - Wait for EC_LPC_CMDR_PENDING bit to clear - * - Write address to EC_LPC_ADDR_ACPI_DATA - * - Wait for EC_LPC_CMDR_DATA bit to set - * - Read value from EC_LPC_ADDR_ACPI_DATA - */ -#define EC_CMD_ACPI_READ 0x80 - -/* - * ACPI Write Embedded Controller - * - * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*). - * - * Use the following sequence: - * - * - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD - * - Wait for EC_LPC_CMDR_PENDING bit to clear - * - Write address to EC_LPC_ADDR_ACPI_DATA - * - Wait for EC_LPC_CMDR_PENDING bit to clear - * - Write value to EC_LPC_ADDR_ACPI_DATA - */ -#define EC_CMD_ACPI_WRITE 0x81 - -/* - * ACPI Query Embedded Controller - * - * This clears the lowest-order bit in the currently pending host events, and - * sets the result code to the 1-based index of the bit (event 0x00000001 = 1, - * event 0x80000000 = 32), or 0 if no event was pending. - */ -#define EC_CMD_ACPI_QUERY_EVENT 0x84 - -/* Valid addresses in ACPI memory space, for read/write commands */ -/* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */ -#define EC_ACPI_MEM_VERSION 0x00 -/* - * Test location; writing value here updates test compliment byte to (0xff - - * value). - */ -#define EC_ACPI_MEM_TEST 0x01 -/* Test compliment; writes here are ignored. */ -#define EC_ACPI_MEM_TEST_COMPLIMENT 0x02 -/* Keyboard backlight brightness percent (0 - 100) */ -#define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03 - -/* Current version of ACPI memory address space */ -#define EC_ACPI_MEM_VERSION_CURRENT 1 - - -/*****************************************************************************/ -/* - * Special commands - * - * These do not follow the normal rules for commands. See each command for - * details. - */ - -/* - * Reboot NOW - * - * This command will work even when the EC LPC interface is busy, because the - * reboot command is processed at interrupt level. Note that when the EC - * reboots, the host will reboot too, so there is no response to this command. - * - * Use EC_CMD_REBOOT_EC to reboot the EC more politely. - */ -#define EC_CMD_REBOOT 0xd1 /* Think "die" */ - -/* - * Resend last response (not supported on LPC). - * - * Returns EC_RES_UNAVAILABLE if there is no response available - for example, - * there was no previous command, or the previous command's response was too - * big to save. - */ -#define EC_CMD_RESEND_RESPONSE 0xdb - -/* - * This header byte on a command indicate version 0. Any header byte less - * than this means that we are talking to an old EC which doesn't support - * versioning. In that case, we assume version 0. - * - * Header bytes greater than this indicate a later version. For example, - * EC_CMD_VERSION0 + 1 means we are using version 1. - * - * The old EC interface must not use commands 0dc or higher. - */ -#define EC_CMD_VERSION0 0xdc - -#endif /* !__ACPI__ */ - -#endif /* __CROS_EC_COMMANDS_H */ diff --git a/trunk/include/linux/mfd/palmas.h b/trunk/include/linux/mfd/palmas.h index 8f21daf62fb5..ecddc5173c7c 100644 --- a/trunk/include/linux/mfd/palmas.h +++ b/trunk/include/linux/mfd/palmas.h @@ -1,10 +1,9 @@ /* * TI Palmas * - * Copyright 2011-2013 Texas Instruments Inc. + * Copyright 2011 Texas Instruments Inc. * * Author: Graeme Gregory - * Author: Ian Lartey * * 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 @@ -23,15 +22,6 @@ #define PALMAS_NUM_CLIENTS 3 -/* The ID_REVISION NUMBERS */ -#define PALMAS_CHIP_OLD_ID 0x0000 -#define PALMAS_CHIP_ID 0xC035 -#define PALMAS_CHIP_CHARGER_ID 0xC036 - -#define is_palmas(a) (((a) == PALMAS_CHIP_OLD_ID) || \ - ((a) == PALMAS_CHIP_ID)) -#define is_palmas_charger(a) ((a) == PALMAS_CHIP_CHARGER_ID) - struct palmas_pmic; struct palmas_gpadc; struct palmas_resource; diff --git a/trunk/include/linux/mfd/retu.h b/trunk/include/linux/mfd/retu.h index 65471c4a3926..1e2715d5b836 100644 --- a/trunk/include/linux/mfd/retu.h +++ b/trunk/include/linux/mfd/retu.h @@ -1,5 +1,5 @@ /* - * Retu/Tahvo MFD driver interface + * Retu MFD driver interface * * 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 @@ -19,10 +19,4 @@ int retu_write(struct retu_dev *, u8, u16); #define RETU_REG_CC1 0x0d /* Common control register 1 */ #define RETU_REG_STATUS 0x16 /* Status register */ -/* Interrupt sources */ -#define TAHVO_INT_VBUS 0 /* VBUS state */ - -/* Interrupt status */ -#define TAHVO_STAT_VBUS (1 << TAHVO_INT_VBUS) - #endif /* __LINUX_MFD_RETU_H */ diff --git a/trunk/include/linux/mfd/rtsx_pci.h b/trunk/include/linux/mfd/rtsx_pci.h index 86bc635f8385..26ea7f1b7caf 100644 --- a/trunk/include/linux/mfd/rtsx_pci.h +++ b/trunk/include/linux/mfd/rtsx_pci.h @@ -500,8 +500,6 @@ #define BPP_POWER_15_PERCENT_ON 0x08 #define BPP_POWER_ON 0x00 #define BPP_POWER_MASK 0x0F -#define SD_VCC_PARTIAL_POWER_ON 0x02 -#define SD_VCC_POWER_ON 0x00 /* PWR_GATE_CTRL */ #define PWR_GATE_EN 0x01 @@ -691,40 +689,6 @@ #define IMAGE_FLAG_ADDR0 0xCE80 #define IMAGE_FLAG_ADDR1 0xCE81 -/* Phy register */ -#define PHY_PCR 0x00 -#define PHY_RCR0 0x01 -#define PHY_RCR1 0x02 -#define PHY_RCR2 0x03 -#define PHY_RTCR 0x04 -#define PHY_RDR 0x05 -#define PHY_TCR0 0x06 -#define PHY_TCR1 0x07 -#define PHY_TUNE 0x08 -#define PHY_IMR 0x09 -#define PHY_BPCR 0x0A -#define PHY_BIST 0x0B -#define PHY_RAW_L 0x0C -#define PHY_RAW_H 0x0D -#define PHY_RAW_DATA 0x0E -#define PHY_HOST_CLK_CTRL 0x0F -#define PHY_DMR 0x10 -#define PHY_BACR 0x11 -#define PHY_IER 0x12 -#define PHY_BCSR 0x13 -#define PHY_BPR 0x14 -#define PHY_BPNR2 0x15 -#define PHY_BPNR 0x16 -#define PHY_BRNR2 0x17 -#define PHY_BENR 0x18 -#define PHY_REG_REV 0x19 -#define PHY_FLD0 0x1A -#define PHY_FLD1 0x1B -#define PHY_FLD2 0x1C -#define PHY_FLD3 0x1D -#define PHY_FLD4 0x1E -#define PHY_DUM_REG 0x1F - #define rtsx_pci_init_cmd(pcr) ((pcr)->ci = 0) struct rtsx_pcr; diff --git a/trunk/include/linux/mfd/si476x-core.h b/trunk/include/linux/mfd/si476x-core.h deleted file mode 100644 index ba89b94e4a56..000000000000 --- a/trunk/include/linux/mfd/si476x-core.h +++ /dev/null @@ -1,533 +0,0 @@ -/* - * include/media/si476x-core.h -- Common definitions for si476x core - * device - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * 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; version 2 of the License. - * - * 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 SI476X_CORE_H -#define SI476X_CORE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* Command Timeouts */ -#define SI476X_DEFAULT_TIMEOUT 100000 -#define SI476X_TIMEOUT_TUNE 700000 -#define SI476X_TIMEOUT_POWER_UP 330000 -#define SI476X_STATUS_POLL_US 0 - -/* -------------------- si476x-i2c.c ----------------------- */ - -enum si476x_freq_supported_chips { - SI476X_CHIP_SI4761 = 1, - SI476X_CHIP_SI4764, - SI476X_CHIP_SI4768, -}; - -enum si476x_part_revisions { - SI476X_REVISION_A10 = 0, - SI476X_REVISION_A20 = 1, - SI476X_REVISION_A30 = 2, -}; - -enum si476x_mfd_cells { - SI476X_RADIO_CELL = 0, - SI476X_CODEC_CELL, - SI476X_MFD_CELLS, -}; - -/** - * enum si476x_power_state - possible power state of the si476x - * device. - * - * @SI476X_POWER_DOWN: In this state all regulators are turned off - * and the reset line is pulled low. The device is completely - * inactive. - * @SI476X_POWER_UP_FULL: In this state all the power regualtors are - * turned on, reset line pulled high, IRQ line is enabled(polling is - * active for polling use scenario) and device is turned on with - * POWER_UP command. The device is ready to be used. - * @SI476X_POWER_INCONSISTENT: This state indicates that previous - * power down was inconsistent, meaning some of the regulators were - * not turned down and thus use of the device, without power-cycling - * is impossible. - */ -enum si476x_power_state { - SI476X_POWER_DOWN = 0, - SI476X_POWER_UP_FULL = 1, - SI476X_POWER_INCONSISTENT = 2, -}; - -/** - * struct si476x_core - internal data structure representing the - * underlying "core" device which all the MFD cell-devices use. - * - * @client: Actual I2C client used to transfer commands to the chip. - * @chip_id: Last digit of the chip model(E.g. "1" for SI4761) - * @cells: MFD cell devices created by this driver. - * @cmd_lock: Mutex used to serialize all the requests to the core - * device. This filed should not be used directly. Instead - * si476x_core_lock()/si476x_core_unlock() should be used to get - * exclusive access to the "core" device. - * @users: Active users counter(Used by the radio cell) - * @rds_read_queue: Wait queue used to wait for RDS data. - * @rds_fifo: FIFO in which all the RDS data received from the chip is - * placed. - * @rds_fifo_drainer: Worker that drains on-chip RDS FIFO. - * @rds_drainer_is_working: Flag used for launching only one instance - * of the @rds_fifo_drainer. - * @rds_drainer_status_lock: Lock used to guard access to the - * @rds_drainer_is_working variable. - * @command: Wait queue for wainting on the command comapletion. - * @cts: Clear To Send flag set upon receiving first status with CTS - * set. - * @tuning: Wait queue used for wainting for tune/seek comand - * completion. - * @stc: Similar to @cts, but for the STC bit of the status value. - * @power_up_parameters: Parameters used as argument for POWER_UP - * command when the device is started. - * @state: Current power state of the device. - * @supplues: Structure containing handles to all power supplies used - * by the device (NULL ones are ignored). - * @gpio_reset: GPIO pin connectet to the RSTB pin of the chip. - * @pinmux: Chip's configurable pins configuration. - * @diversity_mode: Chips role when functioning in diversity mode. - * @status_monitor: Polling worker used in polling use case scenarion - * (when IRQ is not avalible). - * @revision: Chip's running firmware revision number(Used for correct - * command set support). - */ - -struct si476x_core { - struct i2c_client *client; - struct regmap *regmap; - int chip_id; - struct mfd_cell cells[SI476X_MFD_CELLS]; - - struct mutex cmd_lock; /* for serializing fm radio operations */ - atomic_t users; - - wait_queue_head_t rds_read_queue; - struct kfifo rds_fifo; - struct work_struct rds_fifo_drainer; - bool rds_drainer_is_working; - struct mutex rds_drainer_status_lock; - - wait_queue_head_t command; - atomic_t cts; - - wait_queue_head_t tuning; - atomic_t stc; - - struct si476x_power_up_args power_up_parameters; - - enum si476x_power_state power_state; - - struct regulator_bulk_data supplies[4]; - - int gpio_reset; - - struct si476x_pinmux pinmux; - enum si476x_phase_diversity_mode diversity_mode; - - atomic_t is_alive; - - struct delayed_work status_monitor; -#define SI476X_WORK_TO_CORE(w) container_of(to_delayed_work(w), \ - struct si476x_core, \ - status_monitor) - - int revision; - - int rds_fifo_depth; -}; - -static inline struct si476x_core *i2c_mfd_cell_to_core(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev->parent); - return i2c_get_clientdata(client); -} - - -/** - * si476x_core_lock() - lock the core device to get an exclusive access - * to it. - */ -static inline void si476x_core_lock(struct si476x_core *core) -{ - mutex_lock(&core->cmd_lock); -} - -/** - * si476x_core_unlock() - unlock the core device to relinquish an - * exclusive access to it. - */ -static inline void si476x_core_unlock(struct si476x_core *core) -{ - mutex_unlock(&core->cmd_lock); -} - -/* *_TUNE_FREQ family of commands accept frequency in multiples of - 10kHz */ -static inline u16 hz_to_si476x(struct si476x_core *core, int freq) -{ - u16 result; - - switch (core->power_up_parameters.func) { - default: - case SI476X_FUNC_FM_RECEIVER: - result = freq / 10000; - break; - case SI476X_FUNC_AM_RECEIVER: - result = freq / 1000; - break; - } - - return result; -} - -static inline int si476x_to_hz(struct si476x_core *core, u16 freq) -{ - int result; - - switch (core->power_up_parameters.func) { - default: - case SI476X_FUNC_FM_RECEIVER: - result = freq * 10000; - break; - case SI476X_FUNC_AM_RECEIVER: - result = freq * 1000; - break; - } - - return result; -} - -/* Since the V4L2_TUNER_CAP_LOW flag is supplied, V4L2 subsystem - * mesures frequency in 62.5 Hz units */ - -static inline int hz_to_v4l2(int freq) -{ - return (freq * 10) / 625; -} - -static inline int v4l2_to_hz(int freq) -{ - return (freq * 625) / 10; -} - -static inline u16 v4l2_to_si476x(struct si476x_core *core, int freq) -{ - return hz_to_si476x(core, v4l2_to_hz(freq)); -} - -static inline int si476x_to_v4l2(struct si476x_core *core, u16 freq) -{ - return hz_to_v4l2(si476x_to_hz(core, freq)); -} - - - -/** - * struct si476x_func_info - structure containing result of the - * FUNC_INFO command. - * - * @firmware.major: Firmware major number. - * @firmware.minor[...]: Firmware minor numbers. - * @patch_id: - * @func: Mode tuner is working in. - */ -struct si476x_func_info { - struct { - u8 major, minor[2]; - } firmware; - u16 patch_id; - enum si476x_func func; -}; - -/** - * struct si476x_power_down_args - structure used to pass parameters - * to POWER_DOWN command - * - * @xosc: true - Power down, but leav oscillator running. - * false - Full power down. - */ -struct si476x_power_down_args { - bool xosc; -}; - -/** - * enum si476x_tunemode - enum representing possible tune modes for - * the chip. - * @SI476X_TM_VALIDATED_NORMAL_TUNE: Unconditionally stay on the new - * channel after tune, tune status is valid. - * @SI476X_TM_INVALIDATED_FAST_TUNE: Unconditionally stay in the new - * channel after tune, tune status invalid. - * @SI476X_TM_VALIDATED_AF_TUNE: Jump back to previous channel if - * metric thresholds are not met. - * @SI476X_TM_VALIDATED_AF_CHECK: Unconditionally jump back to the - * previous channel. - */ -enum si476x_tunemode { - SI476X_TM_VALIDATED_NORMAL_TUNE = 0, - SI476X_TM_INVALIDATED_FAST_TUNE = 1, - SI476X_TM_VALIDATED_AF_TUNE = 2, - SI476X_TM_VALIDATED_AF_CHECK = 3, -}; - -/** - * enum si476x_smoothmetrics - enum containing the possible setting fo - * audio transitioning of the chip - * @SI476X_SM_INITIALIZE_AUDIO: Initialize audio state to match this - * new channel - * @SI476X_SM_TRANSITION_AUDIO: Transition audio state from previous - * channel values to the new values - */ -enum si476x_smoothmetrics { - SI476X_SM_INITIALIZE_AUDIO = 0, - SI476X_SM_TRANSITION_AUDIO = 1, -}; - -/** - * struct si476x_rds_status_report - the structure representing the - * response to 'FM_RD_STATUS' command - * @rdstpptyint: Traffic program flag(TP) and/or program type(PTY) - * code has changed. - * @rdspiint: Program indentifiaction(PI) code has changed. - * @rdssyncint: RDS synchronization has changed. - * @rdsfifoint: RDS was received and the RDS FIFO has at least - * 'FM_RDS_INTERRUPT_FIFO_COUNT' elements in it. - * @tpptyvalid: TP flag and PTY code are valid falg. - * @pivalid: PI code is valid flag. - * @rdssync: RDS is currently synchronized. - * @rdsfifolost: On or more RDS groups have been lost/discarded flag. - * @tp: Current channel's TP flag. - * @pty: Current channel's PTY code. - * @pi: Current channel's PI code. - * @rdsfifoused: Number of blocks remaining in the RDS FIFO (0 if - * empty). - */ -struct si476x_rds_status_report { - bool rdstpptyint, rdspiint, rdssyncint, rdsfifoint; - bool tpptyvalid, pivalid, rdssync, rdsfifolost; - bool tp; - - u8 pty; - u16 pi; - - u8 rdsfifoused; - u8 ble[4]; - - struct v4l2_rds_data rds[4]; -}; - -struct si476x_rsq_status_args { - bool primary; - bool rsqack; - bool attune; - bool cancel; - bool stcack; -}; - -enum si476x_injside { - SI476X_INJSIDE_AUTO = 0, - SI476X_INJSIDE_LOW = 1, - SI476X_INJSIDE_HIGH = 2, -}; - -struct si476x_tune_freq_args { - bool zifsr; - bool hd; - enum si476x_injside injside; - int freq; - enum si476x_tunemode tunemode; - enum si476x_smoothmetrics smoothmetrics; - int antcap; -}; - -int si476x_core_stop(struct si476x_core *, bool); -int si476x_core_start(struct si476x_core *, bool); -int si476x_core_set_power_state(struct si476x_core *, enum si476x_power_state); -bool si476x_core_has_am(struct si476x_core *); -bool si476x_core_has_diversity(struct si476x_core *); -bool si476x_core_is_a_secondary_tuner(struct si476x_core *); -bool si476x_core_is_a_primary_tuner(struct si476x_core *); -bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core); -bool si476x_core_is_powered_up(struct si476x_core *core); - -enum si476x_i2c_type { - SI476X_I2C_SEND, - SI476X_I2C_RECV -}; - -int si476x_core_i2c_xfer(struct si476x_core *, - enum si476x_i2c_type, - char *, int); - - -/* -------------------- si476x-cmd.c ----------------------- */ - -int si476x_core_cmd_func_info(struct si476x_core *, struct si476x_func_info *); -int si476x_core_cmd_set_property(struct si476x_core *, u16, u16); -int si476x_core_cmd_get_property(struct si476x_core *, u16); -int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *, - enum si476x_dclk_config, - enum si476x_dfs_config, - enum si476x_dout_config, - enum si476x_xout_config); -int si476x_core_cmd_zif_pin_cfg(struct si476x_core *, - enum si476x_iqclk_config, - enum si476x_iqfs_config, - enum si476x_iout_config, - enum si476x_qout_config); -int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *, - enum si476x_icin_config, - enum si476x_icip_config, - enum si476x_icon_config, - enum si476x_icop_config); -int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *, - enum si476x_lrout_config); -int si476x_core_cmd_intb_pin_cfg(struct si476x_core *, enum si476x_intb_config, - enum si476x_a1_config); -int si476x_core_cmd_fm_seek_start(struct si476x_core *, bool, bool); -int si476x_core_cmd_am_seek_start(struct si476x_core *, bool, bool); -int si476x_core_cmd_fm_rds_status(struct si476x_core *, bool, bool, bool, - struct si476x_rds_status_report *); -int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *, bool, - struct si476x_rds_blockcount_report *); -int si476x_core_cmd_fm_tune_freq(struct si476x_core *, - struct si476x_tune_freq_args *); -int si476x_core_cmd_am_tune_freq(struct si476x_core *, - struct si476x_tune_freq_args *); -int si476x_core_cmd_am_rsq_status(struct si476x_core *, - struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); -int si476x_core_cmd_fm_rsq_status(struct si476x_core *, - struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); -int si476x_core_cmd_power_up(struct si476x_core *, - struct si476x_power_up_args *); -int si476x_core_cmd_power_down(struct si476x_core *, - struct si476x_power_down_args *); -int si476x_core_cmd_fm_phase_div_status(struct si476x_core *); -int si476x_core_cmd_fm_phase_diversity(struct si476x_core *, - enum si476x_phase_diversity_mode); - -int si476x_core_cmd_fm_acf_status(struct si476x_core *, - struct si476x_acf_status_report *); -int si476x_core_cmd_am_acf_status(struct si476x_core *, - struct si476x_acf_status_report *); -int si476x_core_cmd_agc_status(struct si476x_core *, - struct si476x_agc_status_report *); - -enum si476x_power_grid_type { - SI476X_POWER_GRID_50HZ = 0, - SI476X_POWER_GRID_60HZ, -}; - -/* Properties */ - -enum si476x_interrupt_flags { - SI476X_STCIEN = (1 << 0), - SI476X_ACFIEN = (1 << 1), - SI476X_RDSIEN = (1 << 2), - SI476X_RSQIEN = (1 << 3), - - SI476X_ERRIEN = (1 << 6), - SI476X_CTSIEN = (1 << 7), - - SI476X_STCREP = (1 << 8), - SI476X_ACFREP = (1 << 9), - SI476X_RDSREP = (1 << 10), - SI476X_RSQREP = (1 << 11), -}; - -enum si476x_rdsint_sources { - SI476X_RDSTPPTY = (1 << 4), - SI476X_RDSPI = (1 << 3), - SI476X_RDSSYNC = (1 << 1), - SI476X_RDSRECV = (1 << 0), -}; - -enum si476x_status_response_bits { - SI476X_CTS = (1 << 7), - SI476X_ERR = (1 << 6), - /* Status response for WB receiver */ - SI476X_WB_ASQ_INT = (1 << 4), - SI476X_RSQ_INT = (1 << 3), - /* Status response for FM receiver */ - SI476X_FM_RDS_INT = (1 << 2), - SI476X_ACF_INT = (1 << 1), - SI476X_STC_INT = (1 << 0), -}; - -/* -------------------- si476x-prop.c ----------------------- */ - -enum si476x_common_receiver_properties { - SI476X_PROP_INT_CTL_ENABLE = 0x0000, - SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE = 0x0200, - SI476X_PROP_DIGITAL_IO_INPUT_FORMAT = 0x0201, - SI476X_PROP_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, - SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, - - SI476X_PROP_SEEK_BAND_BOTTOM = 0x1100, - SI476X_PROP_SEEK_BAND_TOP = 0x1101, - SI476X_PROP_SEEK_FREQUENCY_SPACING = 0x1102, - - SI476X_PROP_VALID_MAX_TUNE_ERROR = 0x2000, - SI476X_PROP_VALID_SNR_THRESHOLD = 0x2003, - SI476X_PROP_VALID_RSSI_THRESHOLD = 0x2004, -}; - -enum si476x_am_receiver_properties { - SI476X_PROP_AUDIO_PWR_LINE_FILTER = 0x0303, -}; - -enum si476x_fm_receiver_properties { - SI476X_PROP_AUDIO_DEEMPHASIS = 0x0302, - - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE = 0x4000, - SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT = 0x4001, - SI476X_PROP_FM_RDS_CONFIG = 0x4002, -}; - -enum si476x_prop_audio_pwr_line_filter_bits { - SI476X_PROP_PWR_HARMONICS_MASK = 0x001f, - SI476X_PROP_PWR_GRID_MASK = 0x0100, - SI476X_PROP_PWR_ENABLE_MASK = 0x0200, - SI476X_PROP_PWR_GRID_50HZ = 0x0000, - SI476X_PROP_PWR_GRID_60HZ = 0x0100, -}; - -enum si476x_prop_fm_rds_config_bits { - SI476X_PROP_RDSEN_MASK = 0x1, - SI476X_PROP_RDSEN = 0x1, -}; - - -struct regmap *devm_regmap_init_si476x(struct si476x_core *); - -#endif /* SI476X_CORE_H */ diff --git a/trunk/include/linux/mfd/si476x-platform.h b/trunk/include/linux/mfd/si476x-platform.h deleted file mode 100644 index 88bb93b7a9d5..000000000000 --- a/trunk/include/linux/mfd/si476x-platform.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * include/media/si476x-platform.h -- Platform data specific definitions - * - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * 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; version 2 of the License. - * - * 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 __SI476X_PLATFORM_H__ -#define __SI476X_PLATFORM_H__ - -/* It is possible to select one of the four adresses using pins A0 - * and A1 on SI476x */ -#define SI476X_I2C_ADDR_1 0x60 -#define SI476X_I2C_ADDR_2 0x61 -#define SI476X_I2C_ADDR_3 0x62 -#define SI476X_I2C_ADDR_4 0x63 - -enum si476x_iqclk_config { - SI476X_IQCLK_NOOP = 0, - SI476X_IQCLK_TRISTATE = 1, - SI476X_IQCLK_IQ = 21, -}; -enum si476x_iqfs_config { - SI476X_IQFS_NOOP = 0, - SI476X_IQFS_TRISTATE = 1, - SI476X_IQFS_IQ = 21, -}; -enum si476x_iout_config { - SI476X_IOUT_NOOP = 0, - SI476X_IOUT_TRISTATE = 1, - SI476X_IOUT_OUTPUT = 22, -}; -enum si476x_qout_config { - SI476X_QOUT_NOOP = 0, - SI476X_QOUT_TRISTATE = 1, - SI476X_QOUT_OUTPUT = 22, -}; - -enum si476x_dclk_config { - SI476X_DCLK_NOOP = 0, - SI476X_DCLK_TRISTATE = 1, - SI476X_DCLK_DAUDIO = 10, -}; - -enum si476x_dfs_config { - SI476X_DFS_NOOP = 0, - SI476X_DFS_TRISTATE = 1, - SI476X_DFS_DAUDIO = 10, -}; - -enum si476x_dout_config { - SI476X_DOUT_NOOP = 0, - SI476X_DOUT_TRISTATE = 1, - SI476X_DOUT_I2S_OUTPUT = 12, - SI476X_DOUT_I2S_INPUT = 13, -}; - -enum si476x_xout_config { - SI476X_XOUT_NOOP = 0, - SI476X_XOUT_TRISTATE = 1, - SI476X_XOUT_I2S_INPUT = 13, - SI476X_XOUT_MODE_SELECT = 23, -}; - -enum si476x_icin_config { - SI476X_ICIN_NOOP = 0, - SI476X_ICIN_TRISTATE = 1, - SI476X_ICIN_GPO1_HIGH = 2, - SI476X_ICIN_GPO1_LOW = 3, - SI476X_ICIN_IC_LINK = 30, -}; - -enum si476x_icip_config { - SI476X_ICIP_NOOP = 0, - SI476X_ICIP_TRISTATE = 1, - SI476X_ICIP_GPO2_HIGH = 2, - SI476X_ICIP_GPO2_LOW = 3, - SI476X_ICIP_IC_LINK = 30, -}; - -enum si476x_icon_config { - SI476X_ICON_NOOP = 0, - SI476X_ICON_TRISTATE = 1, - SI476X_ICON_I2S = 10, - SI476X_ICON_IC_LINK = 30, -}; - -enum si476x_icop_config { - SI476X_ICOP_NOOP = 0, - SI476X_ICOP_TRISTATE = 1, - SI476X_ICOP_I2S = 10, - SI476X_ICOP_IC_LINK = 30, -}; - - -enum si476x_lrout_config { - SI476X_LROUT_NOOP = 0, - SI476X_LROUT_TRISTATE = 1, - SI476X_LROUT_AUDIO = 2, - SI476X_LROUT_MPX = 3, -}; - - -enum si476x_intb_config { - SI476X_INTB_NOOP = 0, - SI476X_INTB_TRISTATE = 1, - SI476X_INTB_DAUDIO = 10, - SI476X_INTB_IRQ = 40, -}; - -enum si476x_a1_config { - SI476X_A1_NOOP = 0, - SI476X_A1_TRISTATE = 1, - SI476X_A1_IRQ = 40, -}; - - -struct si476x_pinmux { - enum si476x_dclk_config dclk; - enum si476x_dfs_config dfs; - enum si476x_dout_config dout; - enum si476x_xout_config xout; - - enum si476x_iqclk_config iqclk; - enum si476x_iqfs_config iqfs; - enum si476x_iout_config iout; - enum si476x_qout_config qout; - - enum si476x_icin_config icin; - enum si476x_icip_config icip; - enum si476x_icon_config icon; - enum si476x_icop_config icop; - - enum si476x_lrout_config lrout; - - enum si476x_intb_config intb; - enum si476x_a1_config a1; -}; - -enum si476x_ibias6x { - SI476X_IBIAS6X_OTHER = 0, - SI476X_IBIAS6X_RCVR1_NON_4MHZ_CLK = 1, -}; - -enum si476x_xstart { - SI476X_XSTART_MULTIPLE_TUNER = 0x11, - SI476X_XSTART_NORMAL = 0x77, -}; - -enum si476x_freq { - SI476X_FREQ_4_MHZ = 0, - SI476X_FREQ_37P209375_MHZ = 1, - SI476X_FREQ_36P4_MHZ = 2, - SI476X_FREQ_37P8_MHZ = 3, -}; - -enum si476x_xmode { - SI476X_XMODE_CRYSTAL_RCVR1 = 1, - SI476X_XMODE_EXT_CLOCK = 2, - SI476X_XMODE_CRYSTAL_RCVR2_3 = 3, -}; - -enum si476x_xbiashc { - SI476X_XBIASHC_SINGLE_RECEIVER = 0, - SI476X_XBIASHC_MULTIPLE_RECEIVER = 1, -}; - -enum si476x_xbias { - SI476X_XBIAS_RCVR2_3 = 0, - SI476X_XBIAS_4MHZ_RCVR1 = 3, - SI476X_XBIAS_RCVR1 = 7, -}; - -enum si476x_func { - SI476X_FUNC_BOOTLOADER = 0, - SI476X_FUNC_FM_RECEIVER = 1, - SI476X_FUNC_AM_RECEIVER = 2, - SI476X_FUNC_WB_RECEIVER = 3, -}; - - -/** - * @xcload: Selects the amount of additional on-chip capacitance to - * be connected between XTAL1 and gnd and between XTAL2 and - * GND. One half of the capacitance value shown here is the - * additional load capacitance presented to the xtal. The - * minimum step size is 0.277 pF. Recommended value is 0x28 - * but it will be layout dependent. Range is 0–0x3F i.e. - * (0–16.33 pF) - * @ctsien: enable CTSINT(interrupt request when CTS condition - * arises) when set - * @intsel: when set A1 pin becomes the interrupt pin; otherwise, - * INTB is the interrupt pin - * @func: selects the boot function of the device. I.e. - * SI476X_BOOTLOADER - Boot loader - * SI476X_FM_RECEIVER - FM receiver - * SI476X_AM_RECEIVER - AM receiver - * SI476X_WB_RECEIVER - Weatherband receiver - * @freq: oscillator's crystal frequency: - * SI476X_XTAL_37P209375_MHZ - 37.209375 Mhz - * SI476X_XTAL_36P4_MHZ - 36.4 Mhz - * SI476X_XTAL_37P8_MHZ - 37.8 Mhz - */ -struct si476x_power_up_args { - enum si476x_ibias6x ibias6x; - enum si476x_xstart xstart; - u8 xcload; - bool fastboot; - enum si476x_xbiashc xbiashc; - enum si476x_xbias xbias; - enum si476x_func func; - enum si476x_freq freq; - enum si476x_xmode xmode; -}; - - -/** - * enum si476x_phase_diversity_mode - possbile phase diversity modes - * for SI4764/5/6/7 chips. - * - * @SI476X_PHDIV_DISABLED: Phase diversity feature is - * disabled. - * @SI476X_PHDIV_PRIMARY_COMBINING: Tuner works as a primary tuner - * in combination with a - * secondary one. - * @SI476X_PHDIV_PRIMARY_ANTENNA: Tuner works as a primary tuner - * using only its own antenna. - * @SI476X_PHDIV_SECONDARY_ANTENNA: Tuner works as a primary tuner - * usning seconary tuner's antenna. - * @SI476X_PHDIV_SECONDARY_COMBINING: Tuner works as a secondary - * tuner in combination with the - * primary one. - */ -enum si476x_phase_diversity_mode { - SI476X_PHDIV_DISABLED = 0, - SI476X_PHDIV_PRIMARY_COMBINING = 1, - SI476X_PHDIV_PRIMARY_ANTENNA = 2, - SI476X_PHDIV_SECONDARY_ANTENNA = 3, - SI476X_PHDIV_SECONDARY_COMBINING = 5, -}; - - -/* - * Platform dependent definition - */ -struct si476x_platform_data { - int gpio_reset; /* < 0 if not used */ - - struct si476x_power_up_args power_up_parameters; - enum si476x_phase_diversity_mode diversity_mode; - - struct si476x_pinmux pinmux; -}; - - -#endif /* __SI476X_PLATFORM_H__ */ diff --git a/trunk/include/linux/mfd/si476x-reports.h b/trunk/include/linux/mfd/si476x-reports.h deleted file mode 100644 index e0b9455a79c0..000000000000 --- a/trunk/include/linux/mfd/si476x-reports.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * include/media/si476x-platform.h -- Definitions of the data formats - * returned by debugfs hooks - * - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * 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; version 2 of the License. - * - * 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 __SI476X_REPORTS_H__ -#define __SI476X_REPORTS_H__ - -/** - * struct si476x_rsq_status - structure containing received signal - * quality - * @multhint: Multipath Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_MULTIPATH_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_MULTIPATH_HIGH_THRESHOLD - * @multlint: Multipath Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_MULTIPATH_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_MULTIPATH_LOW_THRESHOLD - * @snrhint: SNR Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_SNR_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_SNR_HIGH_THRESHOLD - * @snrlint: SNR Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_SNR_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_SNR_LOW_THRESHOLD - * @rssihint: RSSI Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_RSSI_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_RSSI_HIGH_THRESHOLD - * @rssilint: RSSI Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_RSSI_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_RSSI_LOW_THRESHOLD - * @bltf: Band Limit. - * Set if seek command hits the band limit or wrapped to - * the original frequency. - * @snr_ready: SNR measurement in progress. - * @rssiready: RSSI measurement in progress. - * @afcrl: Set if FREQOFF >= MAX_TUNE_ERROR - * @valid: Set if the channel is valid - * rssi < FM_VALID_RSSI_THRESHOLD - * snr < FM_VALID_SNR_THRESHOLD - * tune_error < FM_VALID_MAX_TUNE_ERROR - * @readfreq: Current tuned frequency. - * @freqoff: Signed frequency offset. - * @rssi: Received Signal Strength Indicator(dBuV). - * @snr: RF SNR Indicator(dB). - * @lassi: - * @hassi: Low/High side Adjacent(100 kHz) Channel Strength Indicator - * @mult: Multipath indicator - * @dev: Who knows? But values may vary. - * @readantcap: Antenna tuning capacity value. - * @assi: Adjacent Channel(+/- 200kHz) Strength Indicator - * @usn: Ultrasonic Noise Inticator in -DBFS - */ -struct si476x_rsq_status_report { - __u8 multhint, multlint; - __u8 snrhint, snrlint; - __u8 rssihint, rssilint; - __u8 bltf; - __u8 snr_ready; - __u8 rssiready; - __u8 injside; - __u8 afcrl; - __u8 valid; - - __u16 readfreq; - __s8 freqoff; - __s8 rssi; - __s8 snr; - __s8 issi; - __s8 lassi, hassi; - __s8 mult; - __u8 dev; - __u16 readantcap; - __s8 assi; - __s8 usn; - - __u8 pilotdev; - __u8 rdsdev; - __u8 assidev; - __u8 strongdev; - __u16 rdspi; -} __packed; - -/** - * si476x_acf_status_report - ACF report results - * - * @blend_int: If set, indicates that stereo separation has crossed - * below the blend threshold as set by FM_ACF_BLEND_THRESHOLD - * @hblend_int: If set, indicates that HiBlend cutoff frequency is - * lower than threshold as set by FM_ACF_HBLEND_THRESHOLD - * @hicut_int: If set, indicates that HiCut cutoff frequency is lower - * than the threshold set by ACF_ - - */ -struct si476x_acf_status_report { - __u8 blend_int; - __u8 hblend_int; - __u8 hicut_int; - __u8 chbw_int; - __u8 softmute_int; - __u8 smute; - __u8 smattn; - __u8 chbw; - __u8 hicut; - __u8 hiblend; - __u8 pilot; - __u8 stblend; -} __packed; - -enum si476x_fmagc { - SI476X_FMAGC_10K_OHM = 0, - SI476X_FMAGC_800_OHM = 1, - SI476X_FMAGC_400_OHM = 2, - SI476X_FMAGC_200_OHM = 4, - SI476X_FMAGC_100_OHM = 8, - SI476X_FMAGC_50_OHM = 16, - SI476X_FMAGC_25_OHM = 32, - SI476X_FMAGC_12P5_OHM = 64, - SI476X_FMAGC_6P25_OHM = 128, -}; - -struct si476x_agc_status_report { - __u8 mxhi; - __u8 mxlo; - __u8 lnahi; - __u8 lnalo; - __u8 fmagc1; - __u8 fmagc2; - __u8 pgagain; - __u8 fmwblang; -} __packed; - -struct si476x_rds_blockcount_report { - __u16 expected; - __u16 received; - __u16 uncorrectable; -} __packed; - -#endif /* __SI476X_REPORTS_H__ */ diff --git a/trunk/include/linux/mfd/stmpe.h b/trunk/include/linux/mfd/stmpe.h index 48395a69a7e9..383ac1512a39 100644 --- a/trunk/include/linux/mfd/stmpe.h +++ b/trunk/include/linux/mfd/stmpe.h @@ -26,7 +26,6 @@ enum stmpe_partnum { STMPE801, STMPE811, STMPE1601, - STMPE1801, STMPE2401, STMPE2403, STMPE_NBR_PARTS @@ -40,7 +39,6 @@ enum { STMPE_IDX_CHIP_ID, STMPE_IDX_ICR_LSB, STMPE_IDX_IER_LSB, - STMPE_IDX_ISR_LSB, STMPE_IDX_ISR_MSB, STMPE_IDX_GPMR_LSB, STMPE_IDX_GPSR_LSB, @@ -51,7 +49,6 @@ enum { STMPE_IDX_GPFER_LSB, STMPE_IDX_GPAFR_U_MSB, STMPE_IDX_IEGPIOR_LSB, - STMPE_IDX_ISGPIOR_LSB, STMPE_IDX_ISGPIOR_MSB, STMPE_IDX_MAX, }; diff --git a/trunk/include/linux/mfd/syscon.h b/trunk/include/linux/mfd/syscon.h index b473577f36db..6aeb6b8da64d 100644 --- a/trunk/include/linux/mfd/syscon.h +++ b/trunk/include/linux/mfd/syscon.h @@ -15,11 +15,8 @@ #ifndef __LINUX_MFD_SYSCON_H__ #define __LINUX_MFD_SYSCON_H__ -struct device_node; - extern struct regmap *syscon_node_to_regmap(struct device_node *np); extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s); -extern struct regmap *syscon_regmap_lookup_by_pdevname(const char *s); extern struct regmap *syscon_regmap_lookup_by_phandle( struct device_node *np, const char *property); diff --git a/trunk/include/linux/mfd/tps65090.h b/trunk/include/linux/mfd/tps65090.h index 3f43069413e7..998628a2b08b 100644 --- a/trunk/include/linux/mfd/tps65090.h +++ b/trunk/include/linux/mfd/tps65090.h @@ -27,7 +27,6 @@ /* TPS65090 IRQs */ enum { - TPS65090_IRQ_INTERRUPT, TPS65090_IRQ_VAC_STATUS_CHANGE, TPS65090_IRQ_VSYS_STATUS_CHANGE, TPS65090_IRQ_BAT_STATUS_CHANGE, diff --git a/trunk/include/linux/module.h b/trunk/include/linux/module.h index 46f1ea01e6f6..ead1b5719a12 100644 --- a/trunk/include/linux/module.h +++ b/trunk/include/linux/module.h @@ -190,7 +190,7 @@ extern int modules_disabled; /* for sysctl */ /* Get/put a kernel symbol (calls must be symmetric) */ void *__symbol_get(const char *symbol); void *__symbol_get_gpl(const char *symbol); -#define symbol_get(x) ((typeof(&x))(__symbol_get(VMLINUX_SYMBOL_STR(x)))) +#define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x))) /* modules using other modules: kdb wants to see this. */ struct module_use { @@ -453,7 +453,7 @@ extern void __module_put_and_exit(struct module *mod, long code) #ifdef CONFIG_MODULE_UNLOAD unsigned long module_refcount(struct module *mod); void __symbol_put(const char *symbol); -#define symbol_put(x) __symbol_put(VMLINUX_SYMBOL_STR(x)) +#define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) void symbol_put_addr(void *addr); /* Sometimes we know we already have a refcount, and it's easier not diff --git a/trunk/include/linux/of.h b/trunk/include/linux/of.h index 1b671c3809b8..fb2002f3c7dc 100644 --- a/trunk/include/linux/of.h +++ b/trunk/include/linux/of.h @@ -356,11 +356,6 @@ static inline struct device_node *of_find_node_by_name(struct device_node *from, return NULL; } -static inline struct device_node *of_get_parent(const struct device_node *node) -{ - return NULL; -} - static inline bool of_have_populated_dt(void) { return false; diff --git a/trunk/include/linux/perf_event.h b/trunk/include/linux/perf_event.h index f463a46424e2..e0373d26c244 100644 --- a/trunk/include/linux/perf_event.h +++ b/trunk/include/linux/perf_event.h @@ -788,12 +788,6 @@ static inline int __perf_event_disable(void *info) { return -1; } static inline void perf_event_task_tick(void) { } #endif -#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_NO_HZ_FULL) -extern bool perf_event_can_stop_tick(void); -#else -static inline bool perf_event_can_stop_tick(void) { return true; } -#endif - #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL) extern void perf_restore_debug_store(void); #else diff --git a/trunk/include/linux/posix-timers.h b/trunk/include/linux/posix-timers.h index 7794d75ed155..60bac697a91b 100644 --- a/trunk/include/linux/posix-timers.h +++ b/trunk/include/linux/posix-timers.h @@ -123,8 +123,6 @@ void run_posix_cpu_timers(struct task_struct *task); void posix_cpu_timers_exit(struct task_struct *task); void posix_cpu_timers_exit_group(struct task_struct *task); -bool posix_cpu_timers_can_stop_tick(struct task_struct *tsk); - void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, cputime_t *newval, cputime_t *oldval); diff --git a/trunk/include/linux/rcupdate.h b/trunk/include/linux/rcupdate.h index 4ccd68e49b00..9ed2c9a4de45 100644 --- a/trunk/include/linux/rcupdate.h +++ b/trunk/include/linux/rcupdate.h @@ -1000,11 +1000,4 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) #define kfree_rcu(ptr, rcu_head) \ __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) -#ifdef CONFIG_RCU_NOCB_CPU -extern bool rcu_is_nocb_cpu(int cpu); -#else -static inline bool rcu_is_nocb_cpu(int cpu) { return false; } -#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */ - - #endif /* __LINUX_RCUPDATE_H */ diff --git a/trunk/include/linux/sched.h b/trunk/include/linux/sched.h index 4800e9d1864c..6f950048b6e9 100644 --- a/trunk/include/linux/sched.h +++ b/trunk/include/linux/sched.h @@ -231,7 +231,7 @@ extern void init_idle_bootup_task(struct task_struct *idle); extern int runqueue_is_locked(int cpu); -#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) +#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ) extern void nohz_balance_enter_idle(int cpu); extern void set_cpu_sd_state_idle(void); extern int get_nohz_timer_target(void); @@ -1764,13 +1764,13 @@ static inline int set_cpus_allowed_ptr(struct task_struct *p, } #endif -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ void calc_load_enter_idle(void); void calc_load_exit_idle(void); #else static inline void calc_load_enter_idle(void) { } static inline void calc_load_exit_idle(void) { } -#endif /* CONFIG_NO_HZ_COMMON */ +#endif /* CONFIG_NO_HZ */ #ifndef CONFIG_CPUMASK_OFFSTACK static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask) @@ -1856,17 +1856,10 @@ extern void idle_task_exit(void); static inline void idle_task_exit(void) {} #endif -#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) -extern void wake_up_nohz_cpu(int cpu); +#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) +extern void wake_up_idle_cpu(int cpu); #else -static inline void wake_up_nohz_cpu(int cpu) { } -#endif - -#ifdef CONFIG_NO_HZ_FULL -extern bool sched_can_stop_tick(void); -extern u64 scheduler_tick_max_deferment(void); -#else -static inline bool sched_can_stop_tick(void) { return false; } +static inline void wake_up_idle_cpu(int cpu) { } #endif #ifdef CONFIG_SCHED_AUTOGROUP diff --git a/trunk/include/linux/tick.h b/trunk/include/linux/tick.h index 9180f4b85e6d..553272e6af55 100644 --- a/trunk/include/linux/tick.h +++ b/trunk/include/linux/tick.h @@ -82,7 +82,7 @@ extern int tick_program_event(ktime_t expires, int force); extern void tick_setup_sched_timer(void); # endif -# if defined CONFIG_NO_HZ_COMMON || defined CONFIG_HIGH_RES_TIMERS +# if defined CONFIG_NO_HZ || defined CONFIG_HIGH_RES_TIMERS extern void tick_cancel_sched_timer(int cpu); # else static inline void tick_cancel_sched_timer(int cpu) { } @@ -123,7 +123,7 @@ static inline void tick_check_idle(int cpu) { } static inline int tick_oneshot_mode_active(void) { return 0; } #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ -# ifdef CONFIG_NO_HZ_COMMON +# ifdef CONFIG_NO_HZ DECLARE_PER_CPU(struct tick_sched, tick_cpu_sched); static inline int tick_nohz_tick_stopped(void) @@ -138,7 +138,7 @@ extern ktime_t tick_nohz_get_sleep_length(void); extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); -# else /* !CONFIG_NO_HZ_COMMON */ +# else /* !CONFIG_NO_HZ */ static inline int tick_nohz_tick_stopped(void) { return 0; @@ -155,24 +155,7 @@ static inline ktime_t tick_nohz_get_sleep_length(void) } static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; } static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; } -# endif /* !CONFIG_NO_HZ_COMMON */ - -#ifdef CONFIG_NO_HZ_FULL -extern void tick_nohz_init(void); -extern int tick_nohz_full_cpu(int cpu); -extern void tick_nohz_full_check(void); -extern void tick_nohz_full_kick(void); -extern void tick_nohz_full_kick_all(void); -extern void tick_nohz_task_switch(struct task_struct *tsk); -#else -static inline void tick_nohz_init(void) { } -static inline int tick_nohz_full_cpu(int cpu) { return 0; } -static inline void tick_nohz_full_check(void) { } -static inline void tick_nohz_full_kick(void) { } -static inline void tick_nohz_full_kick_all(void) { } -static inline void tick_nohz_task_switch(struct task_struct *tsk) { } -#endif - +# endif /* !NO_HZ */ # ifdef CONFIG_CPU_IDLE_GOV_MENU extern void menu_hrtimer_cancel(void); diff --git a/trunk/include/linux/ucb1400.h b/trunk/include/linux/ucb1400.h index 2e9ee4d1c676..d21b33c4c6ca 100644 --- a/trunk/include/linux/ucb1400.h +++ b/trunk/include/linux/ucb1400.h @@ -83,12 +83,15 @@ #define UCB_ID 0x7e #define UCB_ID_1400 0x4304 +struct ucb1400_gpio_data { + int gpio_offset; + int (*gpio_setup)(struct device *dev, int ngpio); + int (*gpio_teardown)(struct device *dev, int ngpio); +}; + struct ucb1400_gpio { struct gpio_chip gc; struct snd_ac97 *ac97; - int gpio_offset; - int (*gpio_setup)(struct device *dev, int ngpio); - int (*gpio_teardown)(struct device *dev, int ngpio); }; struct ucb1400_ts { @@ -107,9 +110,6 @@ struct ucb1400 { struct ucb1400_pdata { int irq; - int gpio_offset; - int (*gpio_setup)(struct device *dev, int ngpio); - int (*gpio_teardown)(struct device *dev, int ngpio); }; static inline u16 ucb1400_reg_read(struct snd_ac97 *ac97, u16 reg) @@ -162,4 +162,10 @@ static inline void ucb1400_adc_disable(struct snd_ac97 *ac97) unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel, int adcsync); +#ifdef CONFIG_GPIO_UCB1400 +void __init ucb1400_gpio_set_data(struct ucb1400_gpio_data *data); +#else +static inline void ucb1400_gpio_set_data(struct ucb1400_gpio_data *data) {} +#endif + #endif diff --git a/trunk/include/trace/events/kvm.h b/trunk/include/trace/events/kvm.h index 7005d1109ec9..19911dddaeb7 100644 --- a/trunk/include/trace/events/kvm.h +++ b/trunk/include/trace/events/kvm.h @@ -37,7 +37,7 @@ TRACE_EVENT(kvm_userspace_exit, __entry->errno < 0 ? -__entry->errno : __entry->reason) ); -#if defined(CONFIG_HAVE_KVM_IRQCHIP) +#if defined(__KVM_HAVE_IRQ_LINE) TRACE_EVENT(kvm_set_irq, TP_PROTO(unsigned int gsi, int level, int irq_source_id), TP_ARGS(gsi, level, irq_source_id), @@ -122,10 +122,6 @@ TRACE_EVENT(kvm_msi_set_irq, {KVM_IRQCHIP_PIC_SLAVE, "PIC slave"}, \ {KVM_IRQCHIP_IOAPIC, "IOAPIC"} -#endif /* defined(__KVM_HAVE_IOAPIC) */ - -#if defined(CONFIG_HAVE_KVM_IRQCHIP) - TRACE_EVENT(kvm_ack_irq, TP_PROTO(unsigned int irqchip, unsigned int pin), TP_ARGS(irqchip, pin), @@ -140,18 +136,14 @@ TRACE_EVENT(kvm_ack_irq, __entry->pin = pin; ), -#ifdef kvm_irqchips TP_printk("irqchip %s pin %u", __print_symbolic(__entry->irqchip, kvm_irqchips), __entry->pin) -#else - TP_printk("irqchip %d pin %u", __entry->irqchip, __entry->pin) -#endif ); -#endif /* defined(CONFIG_HAVE_KVM_IRQCHIP) */ +#endif /* defined(__KVM_HAVE_IOAPIC) */ #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 #define KVM_TRACE_MMIO_READ 1 diff --git a/trunk/include/trace/events/timer.h b/trunk/include/trace/events/timer.h index 68c2c2000f02..8d219470624f 100644 --- a/trunk/include/trace/events/timer.h +++ b/trunk/include/trace/events/timer.h @@ -323,27 +323,6 @@ TRACE_EVENT(itimer_expire, (int) __entry->pid, (unsigned long long)__entry->now) ); -#ifdef CONFIG_NO_HZ_COMMON -TRACE_EVENT(tick_stop, - - TP_PROTO(int success, char *error_msg), - - TP_ARGS(success, error_msg), - - TP_STRUCT__entry( - __field( int , success ) - __string( msg, error_msg ) - ), - - TP_fast_assign( - __entry->success = success; - __assign_str(msg, error_msg); - ), - - TP_printk("success=%s msg=%s", __entry->success ? "yes" : "no", __get_str(msg)) -); -#endif - #endif /* _TRACE_TIMER_H */ /* This part must be outside protection */ diff --git a/trunk/include/uapi/linux/kvm.h b/trunk/include/uapi/linux/kvm.h index a5c86fc34a37..3c56ba3d80c1 100644 --- a/trunk/include/uapi/linux/kvm.h +++ b/trunk/include/uapi/linux/kvm.h @@ -449,15 +449,12 @@ enum { kvm_ioeventfd_flag_nr_datamatch, kvm_ioeventfd_flag_nr_pio, kvm_ioeventfd_flag_nr_deassign, - kvm_ioeventfd_flag_nr_virtio_ccw_notify, kvm_ioeventfd_flag_nr_max, }; #define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch) #define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio) #define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign) -#define KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY \ - (1 << kvm_ioeventfd_flag_nr_virtio_ccw_notify) #define KVM_IOEVENTFD_VALID_FLAG_MASK ((1 << kvm_ioeventfd_flag_nr_max) - 1) @@ -561,7 +558,9 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_MP_STATE 14 #define KVM_CAP_COALESCED_MMIO 15 #define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */ +#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT #define KVM_CAP_DEVICE_ASSIGNMENT 17 +#endif #define KVM_CAP_IOMMU 18 #ifdef __KVM_HAVE_MSI #define KVM_CAP_DEVICE_MSI 20 @@ -577,9 +576,13 @@ struct kvm_ppc_smmu_info { #ifdef __KVM_HAVE_PIT #define KVM_CAP_REINJECT_CONTROL 24 #endif +#ifdef __KVM_HAVE_IOAPIC #define KVM_CAP_IRQ_ROUTING 25 +#endif #define KVM_CAP_IRQ_INJECT_STATUS 26 +#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT #define KVM_CAP_DEVICE_DEASSIGNMENT 27 +#endif #ifdef __KVM_HAVE_MSIX #define KVM_CAP_DEVICE_MSIX 28 #endif @@ -662,10 +665,6 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_EPR 86 #define KVM_CAP_ARM_PSCI 87 #define KVM_CAP_ARM_SET_DEVICE_ADDR 88 -#define KVM_CAP_DEVICE_CTRL 89 -#define KVM_CAP_IRQ_MPIC 90 -#define KVM_CAP_PPC_RTAS 91 -#define KVM_CAP_IRQ_XICS 92 #ifdef KVM_CAP_IRQ_ROUTING @@ -818,28 +817,6 @@ struct kvm_arm_device_addr { __u64 addr; }; -/* - * Device control API, available with KVM_CAP_DEVICE_CTRL - */ -#define KVM_CREATE_DEVICE_TEST 1 - -struct kvm_create_device { - __u32 type; /* in: KVM_DEV_TYPE_xxx */ - __u32 fd; /* out: device handle */ - __u32 flags; /* in: KVM_CREATE_DEVICE_xxx */ -}; - -struct kvm_device_attr { - __u32 flags; /* no flags currently defined */ - __u32 group; /* device-defined */ - __u64 attr; /* group-defined */ - __u64 addr; /* userspace address of attr data */ -}; - -#define KVM_DEV_TYPE_FSL_MPIC_20 1 -#define KVM_DEV_TYPE_FSL_MPIC_42 2 -#define KVM_DEV_TYPE_XICS 3 - /* * ioctls for VM fds */ @@ -927,16 +904,6 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd) /* Available with KVM_CAP_ARM_SET_DEVICE_ADDR */ #define KVM_ARM_SET_DEVICE_ADDR _IOW(KVMIO, 0xab, struct kvm_arm_device_addr) -/* Available with KVM_CAP_PPC_RTAS */ -#define KVM_PPC_RTAS_DEFINE_TOKEN _IOW(KVMIO, 0xac, struct kvm_rtas_token_args) - -/* ioctl for vm fd */ -#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device) - -/* ioctls for fds returned by KVM_CREATE_DEVICE */ -#define KVM_SET_DEVICE_ATTR _IOW(KVMIO, 0xe1, struct kvm_device_attr) -#define KVM_GET_DEVICE_ATTR _IOW(KVMIO, 0xe2, struct kvm_device_attr) -#define KVM_HAS_DEVICE_ATTR _IOW(KVMIO, 0xe3, struct kvm_device_attr) /* * ioctls for vcpu fds diff --git a/trunk/init/Kconfig b/trunk/init/Kconfig index 9d3a7887a6d3..a76d13189e47 100644 --- a/trunk/init/Kconfig +++ b/trunk/init/Kconfig @@ -302,7 +302,7 @@ choice # Kind of a stub config for the pure tick based cputime accounting config TICK_CPU_ACCOUNTING bool "Simple tick based cputime accounting" - depends on !S390 && !NO_HZ_FULL + depends on !S390 help This is the basic tick based cputime accounting that maintains statistics about user, system and idle time spent on per jiffies @@ -312,7 +312,7 @@ config TICK_CPU_ACCOUNTING config VIRT_CPU_ACCOUNTING_NATIVE bool "Deterministic task and CPU time accounting" - depends on HAVE_VIRT_CPU_ACCOUNTING && !NO_HZ_FULL + depends on HAVE_VIRT_CPU_ACCOUNTING select VIRT_CPU_ACCOUNTING help Select this option to enable more accurate task and CPU time @@ -342,7 +342,7 @@ config VIRT_CPU_ACCOUNTING_GEN config IRQ_TIME_ACCOUNTING bool "Fine granularity task level IRQ time accounting" - depends on HAVE_IRQ_TIME_ACCOUNTING && !NO_HZ_FULL + depends on HAVE_IRQ_TIME_ACCOUNTING help Select this option to enable fine granularity task irq time accounting. This is done by reading a timestamp on each @@ -576,7 +576,7 @@ config RCU_FANOUT_EXACT config RCU_FAST_NO_HZ bool "Accelerate last non-dyntick-idle CPU's grace periods" - depends on NO_HZ_COMMON && SMP + depends on NO_HZ && SMP default n help This option permits CPUs to enter dynticks-idle state even if @@ -687,7 +687,7 @@ choice config RCU_NOCB_CPU_NONE bool "No build_forced no-CBs CPUs" - depends on RCU_NOCB_CPU && !NO_HZ_FULL + depends on RCU_NOCB_CPU help This option does not force any of the CPUs to be no-CBs CPUs. Only CPUs designated by the rcu_nocbs= boot parameter will be @@ -695,7 +695,7 @@ config RCU_NOCB_CPU_NONE config RCU_NOCB_CPU_ZERO bool "CPU 0 is a build_forced no-CBs CPU" - depends on RCU_NOCB_CPU && !NO_HZ_FULL + depends on RCU_NOCB_CPU help This option forces CPU 0 to be a no-CBs CPU. Additional CPUs may be designated as no-CBs CPUs using the rcu_nocbs= boot diff --git a/trunk/init/main.c b/trunk/init/main.c index 9484f4ba88d0..ceed17aaedfd 100644 --- a/trunk/init/main.c +++ b/trunk/init/main.c @@ -544,7 +544,6 @@ asmlinkage void __init start_kernel(void) idr_init_cache(); perf_event_init(); rcu_init(); - tick_nohz_init(); radix_tree_init(); /* init some links before init_ISA_irqs() */ early_irq_init(); diff --git a/trunk/ipc/sem.c b/trunk/ipc/sem.c index 899b598b63be..4734e9c2a98a 100644 --- a/trunk/ipc/sem.c +++ b/trunk/ipc/sem.c @@ -264,13 +264,12 @@ static inline void sem_unlock(struct sem_array *sma, int locknum) struct sem *sem = sma->sem_base + locknum; spin_unlock(&sem->lock); } + rcu_read_unlock(); } /* * sem_lock_(check_) routines are called in the paths where the rw_mutex * is not held. - * - * The caller holds the RCU read lock. */ static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns, int id, struct sembuf *sops, int nsops, int *locknum) @@ -278,9 +277,12 @@ static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp; struct sem_array *sma; + rcu_read_lock(); ipcp = ipc_obtain_object(&sem_ids(ns), id); - if (IS_ERR(ipcp)) - return ERR_CAST(ipcp); + if (IS_ERR(ipcp)) { + sma = ERR_CAST(ipcp); + goto err; + } sma = container_of(ipcp, struct sem_array, sem_perm); *locknum = sem_lock(sma, sops, nsops); @@ -292,7 +294,10 @@ static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns, return container_of(ipcp, struct sem_array, sem_perm); sem_unlock(sma, *locknum); - return ERR_PTR(-EINVAL); + sma = ERR_PTR(-EINVAL); +err: + rcu_read_unlock(); + return sma; } static inline struct sem_array *sem_obtain_object(struct ipc_namespace *ns, int id) @@ -318,13 +323,15 @@ static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns static inline void sem_lock_and_putref(struct sem_array *sma) { + rcu_read_lock(); sem_lock(sma, NULL, -1); ipc_rcu_putref(sma); } static inline void sem_putref(struct sem_array *sma) { - ipc_rcu_putref(sma); + sem_lock_and_putref(sma); + sem_unlock(sma, -1); } static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s) @@ -428,7 +435,6 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) sma->sem_nsems = nsems; sma->sem_ctime = get_seconds(); sem_unlock(sma, -1); - rcu_read_unlock(); return sma->sem_perm.id; } @@ -868,7 +874,6 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) /* Remove the semaphore set from the IDR */ sem_rmid(ns, sma); sem_unlock(sma, -1); - rcu_read_unlock(); wake_up_sem_queue_do(&tasks); ns->used_sems -= sma->sem_nsems; @@ -948,8 +953,8 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, memset(&tbuf, 0, sizeof(tbuf)); - rcu_read_lock(); if (cmd == SEM_STAT) { + rcu_read_lock(); sma = sem_obtain_object(ns, semid); if (IS_ERR(sma)) { err = PTR_ERR(sma); @@ -957,6 +962,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, } id = sma->sem_perm.id; } else { + rcu_read_lock(); sma = sem_obtain_object_check(ns, semid); if (IS_ERR(sma)) { err = PTR_ERR(sma); @@ -1049,7 +1055,6 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, /* maybe some queued-up processes were waiting for this */ do_smart_update(sma, NULL, 0, 0, &tasks); sem_unlock(sma, -1); - rcu_read_unlock(); wake_up_sem_queue_do(&tasks); return 0; } @@ -1076,12 +1081,17 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, nsems = sma->sem_nsems; err = -EACCES; - if (ipcperms(ns, &sma->sem_perm, cmd == SETALL ? S_IWUGO : S_IRUGO)) - goto out_rcu_wakeup; + if (ipcperms(ns, &sma->sem_perm, + cmd == SETALL ? S_IWUGO : S_IRUGO)) { + rcu_read_unlock(); + goto out_wakeup; + } err = security_sem_semctl(sma, cmd); - if (err) - goto out_rcu_wakeup; + if (err) { + rcu_read_unlock(); + goto out_wakeup; + } err = -EACCES; switch (cmd) { @@ -1094,23 +1104,19 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, if(nsems > SEMMSL_FAST) { if (!ipc_rcu_getref(sma)) { sem_unlock(sma, -1); - rcu_read_unlock(); err = -EIDRM; goto out_free; } sem_unlock(sma, -1); - rcu_read_unlock(); sem_io = ipc_alloc(sizeof(ushort)*nsems); if(sem_io == NULL) { sem_putref(sma); return -ENOMEM; } - rcu_read_lock(); sem_lock_and_putref(sma); if (sma->sem_perm.deleted) { sem_unlock(sma, -1); - rcu_read_unlock(); err = -EIDRM; goto out_free; } @@ -1118,7 +1124,6 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, for (i = 0; i < sma->sem_nsems; i++) sem_io[i] = sma->sem_base[i].semval; sem_unlock(sma, -1); - rcu_read_unlock(); err = 0; if(copy_to_user(array, sem_io, nsems*sizeof(ushort))) err = -EFAULT; @@ -1156,11 +1161,9 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, goto out_free; } } - rcu_read_lock(); sem_lock_and_putref(sma); if (sma->sem_perm.deleted) { sem_unlock(sma, -1); - rcu_read_unlock(); err = -EIDRM; goto out_free; } @@ -1182,8 +1185,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, /* GETVAL, GETPID, GETNCTN, GETZCNT: fall-through */ } err = -EINVAL; - if (semnum < 0 || semnum >= nsems) - goto out_rcu_wakeup; + if (semnum < 0 || semnum >= nsems) { + rcu_read_unlock(); + goto out_wakeup; + } sem_lock(sma, NULL, -1); curr = &sma->sem_base[semnum]; @@ -1205,8 +1210,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, out_unlock: sem_unlock(sma, -1); -out_rcu_wakeup: - rcu_read_unlock(); +out_wakeup: wake_up_sem_queue_do(&tasks); out_free: if(sem_io != fast_sem_io) @@ -1268,7 +1272,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, err = security_sem_semctl(sma, cmd); if (err) { rcu_read_unlock(); - goto out_up; + goto out_unlock; } switch(cmd){ @@ -1291,7 +1295,6 @@ static int semctl_down(struct ipc_namespace *ns, int semid, out_unlock: sem_unlock(sma, -1); - rcu_read_unlock(); out_up: up_write(&sem_ids(ns).rw_mutex); return err; @@ -1440,11 +1443,9 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) } /* step 3: Acquire the lock on semaphore array */ - rcu_read_lock(); sem_lock_and_putref(sma); if (sma->sem_perm.deleted) { sem_unlock(sma, -1); - rcu_read_unlock(); kfree(new); un = ERR_PTR(-EIDRM); goto out; @@ -1471,6 +1472,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) success: spin_unlock(&ulp->lock); + rcu_read_lock(); sem_unlock(sma, -1); out: return un; @@ -1577,16 +1579,22 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, } error = -EFBIG; - if (max >= sma->sem_nsems) - goto out_rcu_wakeup; + if (max >= sma->sem_nsems) { + rcu_read_unlock(); + goto out_wakeup; + } error = -EACCES; - if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) - goto out_rcu_wakeup; + if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) { + rcu_read_unlock(); + goto out_wakeup; + } error = security_sem_semop(sma, sops, nsops, alter); - if (error) - goto out_rcu_wakeup; + if (error) { + rcu_read_unlock(); + goto out_wakeup; + } /* * semid identifiers are not unique - find_alloc_undo may have @@ -1640,7 +1648,6 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, sleep_again: current->state = TASK_INTERRUPTIBLE; sem_unlock(sma, locknum); - rcu_read_unlock(); if (timeout) jiffies_left = schedule_timeout(jiffies_left); @@ -1662,7 +1669,6 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, goto out_free; } - rcu_read_lock(); sma = sem_obtain_lock(ns, semid, sops, nsops, &locknum); /* @@ -1674,7 +1680,6 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, * Array removed? If yes, leave without sem_unlock(). */ if (IS_ERR(sma)) { - rcu_read_unlock(); goto out_free; } @@ -1704,8 +1709,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, out_unlock_free: sem_unlock(sma, locknum); -out_rcu_wakeup: - rcu_read_unlock(); +out_wakeup: wake_up_sem_queue_do(&tasks); out_free: if(sops != fast_sops) @@ -1797,7 +1801,6 @@ void exit_sem(struct task_struct *tsk) * exactly the same semid. Nothing to do. */ sem_unlock(sma, -1); - rcu_read_unlock(); continue; } @@ -1838,7 +1841,6 @@ void exit_sem(struct task_struct *tsk) INIT_LIST_HEAD(&tasks); do_smart_update(sma, NULL, 0, 1, &tasks); sem_unlock(sma, -1); - rcu_read_unlock(); wake_up_sem_queue_do(&tasks); kfree_rcu(un, rcu); diff --git a/trunk/kernel/Makefile b/trunk/kernel/Makefile index 271fd3119af9..d1574d47cf27 100644 --- a/trunk/kernel/Makefile +++ b/trunk/kernel/Makefile @@ -176,7 +176,7 @@ signing_key.priv signing_key.x509: x509.genkey openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ -batch -x509 -config x509.genkey \ -outform DER -out signing_key.x509 \ - -keyout signing_key.priv 2>&1 + -keyout signing_key.priv @echo "###" @echo "### Key pair generated." @echo "###" diff --git a/trunk/kernel/events/core.c b/trunk/kernel/events/core.c index 6b41c1899a8b..3820e3cefbae 100644 --- a/trunk/kernel/events/core.c +++ b/trunk/kernel/events/core.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -686,12 +685,8 @@ static void perf_pmu_rotate_start(struct pmu *pmu) WARN_ON(!irqs_disabled()); - if (list_empty(&cpuctx->rotation_list)) { - int was_empty = list_empty(head); + if (list_empty(&cpuctx->rotation_list)) list_add(&cpuctx->rotation_list, head); - if (was_empty) - tick_nohz_full_kick(); - } } static void get_ctx(struct perf_event_context *ctx) @@ -2596,16 +2591,6 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx) list_del_init(&cpuctx->rotation_list); } -#ifdef CONFIG_NO_HZ_FULL -bool perf_event_can_stop_tick(void) -{ - if (list_empty(&__get_cpu_var(rotation_list))) - return true; - else - return false; -} -#endif - void perf_event_task_tick(void) { struct list_head *head = &__get_cpu_var(rotation_list); diff --git a/trunk/kernel/events/ring_buffer.c b/trunk/kernel/events/ring_buffer.c index cd55144270b5..97fddb09762b 100644 --- a/trunk/kernel/events/ring_buffer.c +++ b/trunk/kernel/events/ring_buffer.c @@ -326,16 +326,11 @@ void rb_free(struct ring_buffer *rb) } #else -static int data_page_nr(struct ring_buffer *rb) -{ - return rb->nr_pages << page_order(rb); -} struct page * perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff) { - /* The '>' counts in the user page. */ - if (pgoff > data_page_nr(rb)) + if (pgoff > (1UL << page_order(rb))) return NULL; return vmalloc_to_page((void *)rb->user_page + pgoff * PAGE_SIZE); @@ -355,11 +350,10 @@ static void rb_free_work(struct work_struct *work) int i, nr; rb = container_of(work, struct ring_buffer, work); - nr = data_page_nr(rb); + nr = 1 << page_order(rb); base = rb->user_page; - /* The '<=' counts in the user page. */ - for (i = 0; i <= nr; i++) + for (i = 0; i < nr + 1; i++) perf_mmap_unmark_page(base + (i * PAGE_SIZE)); vfree(base); @@ -393,7 +387,7 @@ struct ring_buffer *rb_alloc(int nr_pages, long watermark, int cpu, int flags) rb->user_page = all_buf; rb->data_pages[0] = all_buf + PAGE_SIZE; rb->page_order = ilog2(nr_pages); - rb->nr_pages = !!nr_pages; + rb->nr_pages = 1; ring_buffer_init(rb, watermark, flags); diff --git a/trunk/kernel/hrtimer.c b/trunk/kernel/hrtimer.c index fd4b13b131f8..609d8ff38b74 100644 --- a/trunk/kernel/hrtimer.c +++ b/trunk/kernel/hrtimer.c @@ -172,7 +172,7 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, */ static int hrtimer_get_target(int this_cpu, int pinned) { -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu)) return get_nohz_timer_target(); #endif @@ -1125,7 +1125,7 @@ ktime_t hrtimer_get_remaining(const struct hrtimer *timer) } EXPORT_SYMBOL_GPL(hrtimer_get_remaining); -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /** * hrtimer_get_next_event - get the time until next expiry event * diff --git a/trunk/kernel/kallsyms.c b/trunk/kernel/kallsyms.c index 3127ad52cdb2..2169feeba529 100644 --- a/trunk/kernel/kallsyms.c +++ b/trunk/kernel/kallsyms.c @@ -84,11 +84,9 @@ static int is_ksym_addr(unsigned long addr) /* * Expand a compressed symbol data into the resulting uncompressed string, - * if uncompressed string is too long (>= maxlen), it will be truncated, * given the offset to where the symbol is in the compressed stream. */ -static unsigned int kallsyms_expand_symbol(unsigned int off, - char *result, size_t maxlen) +static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) { int len, skipped_first = 0; const u8 *tptr, *data; @@ -115,20 +113,15 @@ static unsigned int kallsyms_expand_symbol(unsigned int off, while (*tptr) { if (skipped_first) { - if (maxlen <= 1) - goto tail; *result = *tptr; result++; - maxlen--; } else skipped_first = 1; tptr++; } } -tail: - if (maxlen) - *result = '\0'; + *result = '\0'; /* Return to offset to the next symbol. */ return off; @@ -183,7 +176,7 @@ unsigned long kallsyms_lookup_name(const char *name) unsigned int off; for (i = 0, off = 0; i < kallsyms_num_syms; i++) { - off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); + off = kallsyms_expand_symbol(off, namebuf); if (strcmp(namebuf, name) == 0) return kallsyms_addresses[i]; @@ -202,7 +195,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, int ret; for (i = 0, off = 0; i < kallsyms_num_syms; i++) { - off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); + off = kallsyms_expand_symbol(off, namebuf); ret = fn(data, namebuf, NULL, kallsyms_addresses[i]); if (ret != 0) return ret; @@ -301,8 +294,7 @@ const char *kallsyms_lookup(unsigned long addr, pos = get_symbol_pos(addr, symbolsize, offset); /* Grab name */ - kallsyms_expand_symbol(get_symbol_offset(pos), - namebuf, KSYM_NAME_LEN); + kallsyms_expand_symbol(get_symbol_offset(pos), namebuf); if (modname) *modname = NULL; return namebuf; @@ -323,8 +315,7 @@ int lookup_symbol_name(unsigned long addr, char *symname) pos = get_symbol_pos(addr, NULL, NULL); /* Grab name */ - kallsyms_expand_symbol(get_symbol_offset(pos), - symname, KSYM_NAME_LEN); + kallsyms_expand_symbol(get_symbol_offset(pos), symname); return 0; } /* See if it's in a module. */ @@ -342,8 +333,7 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, pos = get_symbol_pos(addr, size, offset); /* Grab name */ - kallsyms_expand_symbol(get_symbol_offset(pos), - name, KSYM_NAME_LEN); + kallsyms_expand_symbol(get_symbol_offset(pos), name); modname[0] = '\0'; return 0; } @@ -473,7 +463,7 @@ static unsigned long get_ksymbol_core(struct kallsym_iter *iter) iter->type = kallsyms_get_symbol_type(off); - off = kallsyms_expand_symbol(off, iter->name, ARRAY_SIZE(iter->name)); + off = kallsyms_expand_symbol(off, iter->name); return off - iter->nameoff; } diff --git a/trunk/kernel/modsign_certificate.S b/trunk/kernel/modsign_certificate.S index 4a9a86d12c8b..246b4c6e6135 100644 --- a/trunk/kernel/modsign_certificate.S +++ b/trunk/kernel/modsign_certificate.S @@ -1,8 +1,15 @@ -#include +/* SYMBOL_PREFIX defined on commandline from CONFIG_SYMBOL_PREFIX */ +#ifndef SYMBOL_PREFIX +#define ASM_SYMBOL(sym) sym +#else +#define PASTE2(x,y) x##y +#define PASTE(x,y) PASTE2(x,y) +#define ASM_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym) +#endif #define GLOBAL(name) \ - .globl VMLINUX_SYMBOL(name); \ - VMLINUX_SYMBOL(name): + .globl ASM_SYMBOL(name); \ + ASM_SYMBOL(name): .section ".init.data","aw" diff --git a/trunk/kernel/module.c b/trunk/kernel/module.c index b049939177f6..0925c9a71975 100644 --- a/trunk/kernel/module.c +++ b/trunk/kernel/module.c @@ -1209,11 +1209,10 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, /* Since this should be found in kernel (which can't be removed), * no locking is necessary. */ - if (!find_symbol(VMLINUX_SYMBOL_STR(module_layout), NULL, + if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, &crc, true, false)) BUG(); - return check_version(sechdrs, versindex, - VMLINUX_SYMBOL_STR(module_layout), mod, crc, + return check_version(sechdrs, versindex, "module_layout", mod, crc, NULL); } @@ -1862,12 +1861,12 @@ static void free_module(struct module *mod) { trace_module_free(mod); + /* Delete from various lists */ + mutex_lock(&module_mutex); + stop_machine(__unlink_module, mod, NULL); + mutex_unlock(&module_mutex); mod_sysfs_teardown(mod); - /* We leave it in list to prevent duplicate loads, but make sure - * that noone uses it while it's being deconstructed. */ - mod->state = MODULE_STATE_UNFORMED; - /* Remove dynamic debug info */ ddebug_remove_module(mod->name); @@ -1880,11 +1879,6 @@ static void free_module(struct module *mod) /* Free any allocated parameters. */ destroy_params(mod->kp, mod->num_kp); - /* Now we can delete it from the lists */ - mutex_lock(&module_mutex); - stop_machine(__unlink_module, mod, NULL); - mutex_unlock(&module_mutex); - /* This may be NULL, but that's OK */ unset_module_init_ro_nx(mod); module_free(mod, mod->module_init); diff --git a/trunk/kernel/posix-cpu-timers.c b/trunk/kernel/posix-cpu-timers.c index 42670e9b44e0..8fd709c9bb58 100644 --- a/trunk/kernel/posix-cpu-timers.c +++ b/trunk/kernel/posix-cpu-timers.c @@ -10,8 +10,6 @@ #include #include #include -#include -#include /* * Called after updating RLIMIT_CPU to run cpu timer and update @@ -155,21 +153,6 @@ static void bump_cpu_timer(struct k_itimer *timer, } } -/** - * task_cputime_zero - Check a task_cputime struct for all zero fields. - * - * @cputime: The struct to compare. - * - * Checks @cputime to see if all fields are zero. Returns true if all fields - * are zero, false if any field is nonzero. - */ -static inline int task_cputime_zero(const struct task_cputime *cputime) -{ - if (!cputime->utime && !cputime->stime && !cputime->sum_exec_runtime) - return 1; - return 0; -} - static inline cputime_t prof_ticks(struct task_struct *p) { cputime_t utime, stime; @@ -653,37 +636,6 @@ static int cpu_timer_sample_group(const clockid_t which_clock, return 0; } -#ifdef CONFIG_NO_HZ_FULL -static void nohz_kick_work_fn(struct work_struct *work) -{ - tick_nohz_full_kick_all(); -} - -static DECLARE_WORK(nohz_kick_work, nohz_kick_work_fn); - -/* - * We need the IPIs to be sent from sane process context. - * The posix cpu timers are always set with irqs disabled. - */ -static void posix_cpu_timer_kick_nohz(void) -{ - schedule_work(&nohz_kick_work); -} - -bool posix_cpu_timers_can_stop_tick(struct task_struct *tsk) -{ - if (!task_cputime_zero(&tsk->cputime_expires)) - return false; - - if (tsk->signal->cputimer.running) - return false; - - return true; -} -#else -static inline void posix_cpu_timer_kick_nohz(void) { } -#endif - /* * Guts of sys_timer_settime for CPU timers. * This is called with the timer locked and interrupts disabled. @@ -842,8 +794,6 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int flags, sample_to_timespec(timer->it_clock, old_incr, &old->it_interval); } - if (!ret) - posix_cpu_timer_kick_nohz(); return ret; } @@ -1058,6 +1008,21 @@ static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it, } } +/** + * task_cputime_zero - Check a task_cputime struct for all zero fields. + * + * @cputime: The struct to compare. + * + * Checks @cputime to see if all fields are zero. Returns true if all fields + * are zero, false if any field is nonzero. + */ +static inline int task_cputime_zero(const struct task_cputime *cputime) +{ + if (!cputime->utime && !cputime->stime && !cputime->sum_exec_runtime) + return 1; + return 0; +} + /* * Check for any per-thread CPU timers that have fired and move them * off the tsk->*_timers list onto the firing list. Per-thread timers @@ -1371,13 +1336,6 @@ void run_posix_cpu_timers(struct task_struct *tsk) cpu_timer_fire(timer); spin_unlock(&timer->it_lock); } - - /* - * In case some timers were rescheduled after the queue got emptied, - * wake up full dynticks CPUs. - */ - if (tsk->signal->cputimer.running) - posix_cpu_timer_kick_nohz(); } /* @@ -1408,7 +1366,7 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, } if (!*newval) - goto out; + return; *newval += now.cpu; } @@ -1426,8 +1384,6 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, tsk->signal->cputime_expires.virt_exp = *newval; break; } -out: - posix_cpu_timer_kick_nohz(); } static int do_cpu_nanosleep(const clockid_t which_clock, int flags, diff --git a/trunk/kernel/rcutree.c b/trunk/kernel/rcutree.c index 16ea67925015..d8534308fd05 100644 --- a/trunk/kernel/rcutree.c +++ b/trunk/kernel/rcutree.c @@ -799,16 +799,6 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) rdp->offline_fqs++; return 1; } - - /* - * There is a possibility that a CPU in adaptive-ticks state - * might run in the kernel with the scheduling-clock tick disabled - * for an extended time period. Invoke rcu_kick_nohz_cpu() to - * force the CPU to restart the scheduling-clock tick in this - * CPU is in this state. - */ - rcu_kick_nohz_cpu(rdp->cpu); - return 0; } @@ -1830,7 +1820,7 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) { /* No-CBs CPUs do not have orphanable callbacks. */ - if (rcu_is_nocb_cpu(rdp->cpu)) + if (is_nocb_cpu(rdp->cpu)) return; /* @@ -2902,10 +2892,10 @@ static void _rcu_barrier(struct rcu_state *rsp) * corresponding CPU's preceding callbacks have been invoked. */ for_each_possible_cpu(cpu) { - if (!cpu_online(cpu) && !rcu_is_nocb_cpu(cpu)) + if (!cpu_online(cpu) && !is_nocb_cpu(cpu)) continue; rdp = per_cpu_ptr(rsp->rda, cpu); - if (rcu_is_nocb_cpu(cpu)) { + if (is_nocb_cpu(cpu)) { _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, rsp->n_barrier_done); atomic_inc(&rsp->barrier_cpu_count); diff --git a/trunk/kernel/rcutree.h b/trunk/kernel/rcutree.h index da77a8f57ff9..14ee40795d6f 100644 --- a/trunk/kernel/rcutree.h +++ b/trunk/kernel/rcutree.h @@ -530,13 +530,13 @@ static int rcu_nocb_needs_gp(struct rcu_state *rsp); static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp); static void rcu_init_one_nocb(struct rcu_node *rnp); +static bool is_nocb_cpu(int cpu); static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, bool lazy); static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, struct rcu_data *rdp); static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp); static void rcu_spawn_nocb_kthreads(struct rcu_state *rsp); -static void rcu_kick_nohz_cpu(int cpu); static bool init_nocb_callback_list(struct rcu_data *rdp); #endif /* #ifndef RCU_TREE_NONCORE */ diff --git a/trunk/kernel/rcutree_plugin.h b/trunk/kernel/rcutree_plugin.h index 170814dc418f..d084ae3f281c 100644 --- a/trunk/kernel/rcutree_plugin.h +++ b/trunk/kernel/rcutree_plugin.h @@ -28,7 +28,6 @@ #include #include #include -#include #define RCU_KTHREAD_PRIO 1 @@ -1706,7 +1705,7 @@ static void rcu_prepare_for_idle(int cpu) return; /* If this is a no-CBs CPU, no callbacks, just return. */ - if (rcu_is_nocb_cpu(cpu)) + if (is_nocb_cpu(cpu)) return; /* @@ -1748,7 +1747,7 @@ static void rcu_cleanup_after_idle(int cpu) struct rcu_data *rdp; struct rcu_state *rsp; - if (rcu_is_nocb_cpu(cpu)) + if (is_nocb_cpu(cpu)) return; rcu_try_advance_all_cbs(); for_each_rcu_flavor(rsp) { @@ -2053,7 +2052,7 @@ static void rcu_init_one_nocb(struct rcu_node *rnp) } /* Is the specified CPU a no-CPUs CPU? */ -bool rcu_is_nocb_cpu(int cpu) +static bool is_nocb_cpu(int cpu) { if (have_rcu_nocb_mask) return cpumask_test_cpu(cpu, rcu_nocb_mask); @@ -2111,7 +2110,7 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, bool lazy) { - if (!rcu_is_nocb_cpu(rdp->cpu)) + if (!is_nocb_cpu(rdp->cpu)) return 0; __call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy); if (__is_kfree_rcu_offset((unsigned long)rhp->func)) @@ -2135,7 +2134,7 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, long qll = rsp->qlen_lazy; /* If this is not a no-CBs CPU, tell the caller to do it the old way. */ - if (!rcu_is_nocb_cpu(smp_processor_id())) + if (!is_nocb_cpu(smp_processor_id())) return 0; rsp->qlen = 0; rsp->qlen_lazy = 0; @@ -2307,6 +2306,11 @@ static void rcu_init_one_nocb(struct rcu_node *rnp) { } +static bool is_nocb_cpu(int cpu) +{ + return false; +} + static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, bool lazy) { @@ -2333,20 +2337,3 @@ static bool init_nocb_callback_list(struct rcu_data *rdp) } #endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */ - -/* - * An adaptive-ticks CPU can potentially execute in kernel mode for an - * arbitrarily long period of time with the scheduling-clock tick turned - * off. RCU will be paying attention to this CPU because it is in the - * kernel, but the CPU cannot be guaranteed to be executing the RCU state - * machine because the scheduling-clock tick has been disabled. Therefore, - * if an adaptive-ticks CPU is failing to respond to the current grace - * period and has not be idle from an RCU perspective, kick it. - */ -static void rcu_kick_nohz_cpu(int cpu) -{ -#ifdef CONFIG_NO_HZ_FULL - if (tick_nohz_full_cpu(cpu)) - smp_send_reschedule(cpu); -#endif /* #ifdef CONFIG_NO_HZ_FULL */ -} diff --git a/trunk/kernel/rcutree_trace.c b/trunk/kernel/rcutree_trace.c index cf6c17412932..49099e81c87b 100644 --- a/trunk/kernel/rcutree_trace.c +++ b/trunk/kernel/rcutree_trace.c @@ -95,7 +95,7 @@ static const struct file_operations rcubarrier_fops = { .open = rcubarrier_open, .read = seq_read, .llseek = no_llseek, - .release = single_release, + .release = seq_release, }; #ifdef CONFIG_RCU_BOOST @@ -206,7 +206,7 @@ static const struct file_operations rcuexp_fops = { .open = rcuexp_open, .read = seq_read, .llseek = no_llseek, - .release = single_release, + .release = seq_release, }; #ifdef CONFIG_RCU_BOOST @@ -306,7 +306,7 @@ static const struct file_operations rcuhier_fops = { .open = rcuhier_open, .read = seq_read, .llseek = no_llseek, - .release = single_release, + .release = seq_release, }; static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp) @@ -348,7 +348,7 @@ static const struct file_operations rcugp_fops = { .open = rcugp_open, .read = seq_read, .llseek = no_llseek, - .release = single_release, + .release = seq_release, }; static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp) diff --git a/trunk/kernel/sched/core.c b/trunk/kernel/sched/core.c index 58453b8272fd..5662f58f0b69 100644 --- a/trunk/kernel/sched/core.c +++ b/trunk/kernel/sched/core.c @@ -544,7 +544,7 @@ void resched_cpu(int cpu) raw_spin_unlock_irqrestore(&rq->lock, flags); } -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* * In the semi idle case, use the nearest busy cpu for migrating timers * from an idle cpu. This is good for power-savings. @@ -582,7 +582,7 @@ int get_nohz_timer_target(void) * account when the CPU goes back to idle and evaluates the timer * wheel for the next timer event. */ -static void wake_up_idle_cpu(int cpu) +void wake_up_idle_cpu(int cpu) { struct rq *rq = cpu_rq(cpu); @@ -612,56 +612,20 @@ static void wake_up_idle_cpu(int cpu) smp_send_reschedule(cpu); } -static bool wake_up_full_nohz_cpu(int cpu) -{ - if (tick_nohz_full_cpu(cpu)) { - if (cpu != smp_processor_id() || - tick_nohz_tick_stopped()) - smp_send_reschedule(cpu); - return true; - } - - return false; -} - -void wake_up_nohz_cpu(int cpu) -{ - if (!wake_up_full_nohz_cpu(cpu)) - wake_up_idle_cpu(cpu); -} - static inline bool got_nohz_idle_kick(void) { int cpu = smp_processor_id(); return idle_cpu(cpu) && test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu)); } -#else /* CONFIG_NO_HZ_COMMON */ +#else /* CONFIG_NO_HZ */ static inline bool got_nohz_idle_kick(void) { return false; } -#endif /* CONFIG_NO_HZ_COMMON */ - -#ifdef CONFIG_NO_HZ_FULL -bool sched_can_stop_tick(void) -{ - struct rq *rq; - - rq = this_rq(); - - /* Make sure rq->nr_running update is visible after the IPI */ - smp_rmb(); - - /* More than one running task need preemption */ - if (rq->nr_running > 1) - return false; - - return true; -} -#endif /* CONFIG_NO_HZ_FULL */ +#endif /* CONFIG_NO_HZ */ void sched_avg_update(struct rq *rq) { @@ -1393,8 +1357,7 @@ static void sched_ttwu_pending(void) void scheduler_ipi(void) { - if (llist_empty(&this_rq()->wake_list) && !got_nohz_idle_kick() - && !tick_nohz_full_cpu(smp_processor_id())) + if (llist_empty(&this_rq()->wake_list) && !got_nohz_idle_kick()) return; /* @@ -1411,7 +1374,6 @@ void scheduler_ipi(void) * somewhat pessimize the simple resched case. */ irq_enter(); - tick_nohz_full_check(); sched_ttwu_pending(); /* @@ -1893,8 +1855,6 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) kprobe_flush_task(prev); put_task_struct(prev); } - - tick_nohz_task_switch(current); } #ifdef CONFIG_SMP @@ -2158,7 +2118,7 @@ calc_load(unsigned long load, unsigned long exp, unsigned long active) return load >> FSHIFT; } -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* * Handle NO_HZ for the global load-average. * @@ -2384,12 +2344,12 @@ static void calc_global_nohz(void) smp_wmb(); calc_load_idx++; } -#else /* !CONFIG_NO_HZ_COMMON */ +#else /* !CONFIG_NO_HZ */ static inline long calc_load_fold_idle(void) { return 0; } static inline void calc_global_nohz(void) { } -#endif /* CONFIG_NO_HZ_COMMON */ +#endif /* CONFIG_NO_HZ */ /* * calc_load - update the avenrun load estimates 10 ticks after the @@ -2549,7 +2509,7 @@ static void __update_cpu_load(struct rq *this_rq, unsigned long this_load, sched_avg_update(this_rq); } -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* * There is no sane way to deal with nohz on smp when using jiffies because the * cpu doing the jiffies update might drift wrt the cpu doing the jiffy reading @@ -2609,7 +2569,7 @@ void update_cpu_load_nohz(void) } raw_spin_unlock(&this_rq->lock); } -#endif /* CONFIG_NO_HZ_COMMON */ +#endif /* CONFIG_NO_HZ */ /* * Called from scheduler_tick() @@ -2736,34 +2696,7 @@ void scheduler_tick(void) rq->idle_balance = idle_cpu(cpu); trigger_load_balance(rq, cpu); #endif - rq_last_tick_reset(rq); -} - -#ifdef CONFIG_NO_HZ_FULL -/** - * scheduler_tick_max_deferment - * - * Keep at least one tick per second when a single - * active task is running because the scheduler doesn't - * yet completely support full dynticks environment. - * - * This makes sure that uptime, CFS vruntime, load - * balancing, etc... continue to move forward, even - * with a very low granularity. - */ -u64 scheduler_tick_max_deferment(void) -{ - struct rq *rq = this_rq(); - unsigned long next, now = ACCESS_ONCE(jiffies); - - next = rq->last_sched_tick + HZ; - - if (time_before_eq(next, now)) - return 0; - - return jiffies_to_usecs(next - now) * NSEC_PER_USEC; } -#endif notrace unsigned long get_parent_ip(unsigned long addr) { @@ -7018,12 +6951,9 @@ void __init sched_init(void) INIT_LIST_HEAD(&rq->cfs_tasks); rq_attach_root(rq, &def_root_domain); -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ rq->nohz_flags = 0; #endif -#ifdef CONFIG_NO_HZ_FULL - rq->last_sched_tick = 0; -#endif #endif init_rq_hrtick(rq); atomic_set(&rq->nr_iowait, 0); diff --git a/trunk/kernel/sched/fair.c b/trunk/kernel/sched/fair.c index c61a614465c8..8bf7081b1ec5 100644 --- a/trunk/kernel/sched/fair.c +++ b/trunk/kernel/sched/fair.c @@ -5355,7 +5355,7 @@ static int active_load_balance_cpu_stop(void *data) return 0; } -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* * idle load balancing details * - When one of the busy CPUs notice that there may be an idle rebalancing @@ -5572,9 +5572,9 @@ static void rebalance_domains(int cpu, enum cpu_idle_type idle) rq->next_balance = next_balance; } -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* - * In CONFIG_NO_HZ_COMMON case, the idle balance kickee will do the + * In CONFIG_NO_HZ case, the idle balance kickee will do the * rebalancing for all the cpus for whom scheduler ticks are stopped. */ static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle) @@ -5717,7 +5717,7 @@ void trigger_load_balance(struct rq *rq, int cpu) if (time_after_eq(jiffies, rq->next_balance) && likely(!on_null_domain(cpu))) raise_softirq(SCHED_SOFTIRQ); -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ if (nohz_kick_needed(rq, cpu) && likely(!on_null_domain(cpu))) nohz_balancer_kick(cpu); #endif @@ -6187,7 +6187,7 @@ __init void init_sched_fair_class(void) #ifdef CONFIG_SMP open_softirq(SCHED_SOFTIRQ, run_rebalance_domains); -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ nohz.next_balance = jiffies; zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT); cpu_notifier(sched_ilb_notifier, 0); diff --git a/trunk/kernel/sched/idle_task.c b/trunk/kernel/sched/idle_task.c index d8da01008d39..b8ce77328341 100644 --- a/trunk/kernel/sched/idle_task.c +++ b/trunk/kernel/sched/idle_task.c @@ -17,7 +17,6 @@ select_task_rq_idle(struct task_struct *p, int sd_flag, int flags) static void pre_schedule_idle(struct rq *rq, struct task_struct *prev) { idle_exit_fair(rq); - rq_last_tick_reset(rq); } static void post_schedule_idle(struct rq *rq) diff --git a/trunk/kernel/sched/sched.h b/trunk/kernel/sched/sched.h index ce39224d6155..4c225c4c7111 100644 --- a/trunk/kernel/sched/sched.h +++ b/trunk/kernel/sched/sched.h @@ -5,7 +5,6 @@ #include #include #include -#include #include "cpupri.h" #include "cpuacct.h" @@ -406,12 +405,9 @@ struct rq { #define CPU_LOAD_IDX_MAX 5 unsigned long cpu_load[CPU_LOAD_IDX_MAX]; unsigned long last_load_update_tick; -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ u64 nohz_stamp; unsigned long nohz_flags; -#endif -#ifdef CONFIG_NO_HZ_FULL - unsigned long last_sched_tick; #endif int skip_clock_update; @@ -1076,16 +1072,6 @@ static inline u64 steal_ticks(u64 steal) static inline void inc_nr_running(struct rq *rq) { rq->nr_running++; - -#ifdef CONFIG_NO_HZ_FULL - if (rq->nr_running == 2) { - if (tick_nohz_full_cpu(rq->cpu)) { - /* Order rq->nr_running write against the IPI */ - smp_wmb(); - smp_send_reschedule(rq->cpu); - } - } -#endif } static inline void dec_nr_running(struct rq *rq) @@ -1093,13 +1079,6 @@ static inline void dec_nr_running(struct rq *rq) rq->nr_running--; } -static inline void rq_last_tick_reset(struct rq *rq) -{ -#ifdef CONFIG_NO_HZ_FULL - rq->last_sched_tick = jiffies; -#endif -} - extern void update_rq_clock(struct rq *rq); extern void activate_task(struct rq *rq, struct task_struct *p, int flags); @@ -1320,7 +1299,7 @@ extern void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq); extern void account_cfs_bandwidth_used(int enabled, int was_enabled); -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ enum rq_nohz_flag_bits { NOHZ_TICK_STOPPED, NOHZ_BALANCE_KICK, diff --git a/trunk/kernel/softirq.c b/trunk/kernel/softirq.c index b5197dcb0dad..aa82723c7202 100644 --- a/trunk/kernel/softirq.c +++ b/trunk/kernel/softirq.c @@ -329,19 +329,6 @@ static inline void invoke_softirq(void) wakeup_softirqd(); } -static inline void tick_irq_exit(void) -{ -#ifdef CONFIG_NO_HZ_COMMON - int cpu = smp_processor_id(); - - /* Make sure that timer wheel updates are propagated */ - if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu)) { - if (!in_interrupt()) - tick_nohz_irq_exit(); - } -#endif -} - /* * Exit an interrupt context. Process softirqs if needed and possible: */ @@ -359,7 +346,11 @@ void irq_exit(void) if (!in_interrupt() && local_softirq_pending()) invoke_softirq(); - tick_irq_exit(); +#ifdef CONFIG_NO_HZ + /* Make sure that timer wheel updates are propagated */ + if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched()) + tick_nohz_irq_exit(); +#endif rcu_irq_exit(); } diff --git a/trunk/kernel/time/Kconfig b/trunk/kernel/time/Kconfig index e4c07b0692bb..24510d84efd7 100644 --- a/trunk/kernel/time/Kconfig +++ b/trunk/kernel/time/Kconfig @@ -64,88 +64,20 @@ config GENERIC_CMOS_UPDATE if GENERIC_CLOCKEVENTS menu "Timers subsystem" -# Core internal switch. Selected by NO_HZ_COMMON / HIGH_RES_TIMERS. This is +# Core internal switch. Selected by NO_HZ / HIGH_RES_TIMERS. This is # only related to the tick functionality. Oneshot clockevent devices # are supported independ of this. config TICK_ONESHOT bool -config NO_HZ_COMMON - bool - depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS - select TICK_ONESHOT - -choice - prompt "Timer tick handling" - default NO_HZ_IDLE if NO_HZ - -config HZ_PERIODIC - bool "Periodic timer ticks (constant rate, no dynticks)" - help - This option keeps the tick running periodically at a constant - rate, even when the CPU doesn't need it. - -config NO_HZ_IDLE - bool "Idle dynticks system (tickless idle)" - depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS - select NO_HZ_COMMON - help - This option enables a tickless idle system: timer interrupts - will only trigger on an as-needed basis when the system is idle. - This is usually interesting for energy saving. - - Most of the time you want to say Y here. - -config NO_HZ_FULL - bool "Full dynticks system (tickless)" - # NO_HZ_COMMON dependency - depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS - # We need at least one periodic CPU for timekeeping - depends on SMP - # RCU_USER_QS dependency - depends on HAVE_CONTEXT_TRACKING - # VIRT_CPU_ACCOUNTING_GEN dependency - depends on 64BIT - select NO_HZ_COMMON - select RCU_USER_QS - select RCU_NOCB_CPU - select VIRT_CPU_ACCOUNTING_GEN - select CONTEXT_TRACKING_FORCE - select IRQ_WORK - help - Adaptively try to shutdown the tick whenever possible, even when - the CPU is running tasks. Typically this requires running a single - task on the CPU. Chances for running tickless are maximized when - the task mostly runs in userspace and has few kernel activity. - - You need to fill up the nohz_full boot parameter with the - desired range of dynticks CPUs. - - This is implemented at the expense of some overhead in user <-> kernel - transitions: syscalls, exceptions and interrupts. Even when it's - dynamically off. - - Say N. - -endchoice - -config NO_HZ_FULL_ALL - bool "Full dynticks system on all CPUs by default" - depends on NO_HZ_FULL - help - If the user doesn't pass the nohz_full boot option to - define the range of full dynticks CPUs, consider that all - CPUs in the system are full dynticks by default. - Note the boot CPU will still be kept outside the range to - handle the timekeeping duty. - config NO_HZ - bool "Old Idle dynticks config" + bool "Tickless System (Dynamic Ticks)" depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS + select TICK_ONESHOT help - This is the old config entry that enables dynticks idle. - We keep it around for a little while to enforce backward - compatibility with older config files. + This option enables a tickless system: timer interrupts will + only trigger on an as-needed basis both when the system is + busy and when the system is idle. config HIGH_RES_TIMERS bool "High Resolution Timer Support" diff --git a/trunk/kernel/time/tick-broadcast.c b/trunk/kernel/time/tick-broadcast.c index 206bbfb34e09..61d00a8cdf2f 100644 --- a/trunk/kernel/time/tick-broadcast.c +++ b/trunk/kernel/time/tick-broadcast.c @@ -693,8 +693,7 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc) bc->event_handler = tick_handle_oneshot_broadcast; /* Take the do_timer update */ - if (!tick_nohz_full_cpu(cpu)) - tick_do_timer_cpu = cpu; + tick_do_timer_cpu = cpu; /* * We must be careful here. There might be other CPUs diff --git a/trunk/kernel/time/tick-common.c b/trunk/kernel/time/tick-common.c index 5d3fb100bc06..6176a3e45709 100644 --- a/trunk/kernel/time/tick-common.c +++ b/trunk/kernel/time/tick-common.c @@ -163,10 +163,7 @@ static void tick_setup_device(struct tick_device *td, * this cpu: */ if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) { - if (!tick_nohz_full_cpu(cpu)) - tick_do_timer_cpu = cpu; - else - tick_do_timer_cpu = TICK_DO_TIMER_NONE; + tick_do_timer_cpu = cpu; tick_next_period = ktime_get(); tick_period = ktime_set(0, NSEC_PER_SEC / HZ); } diff --git a/trunk/kernel/time/tick-sched.c b/trunk/kernel/time/tick-sched.c index bc67d4245e1d..225f8bf19095 100644 --- a/trunk/kernel/time/tick-sched.c +++ b/trunk/kernel/time/tick-sched.c @@ -21,15 +21,11 @@ #include #include #include -#include -#include #include #include "tick-internal.h" -#include - /* * Per cpu nohz control structure */ @@ -108,7 +104,7 @@ static void tick_sched_do_timer(ktime_t now) { int cpu = smp_processor_id(); -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* * Check if the do_timer duty was dropped. We don't care about * concurrency: This happens only when the cpu in charge went @@ -116,8 +112,7 @@ static void tick_sched_do_timer(ktime_t now) * this duty, then the jiffies update is still serialized by * jiffies_lock. */ - if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE) - && !tick_nohz_full_cpu(cpu)) + if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) tick_do_timer_cpu = cpu; #endif @@ -128,7 +123,7 @@ static void tick_sched_do_timer(ktime_t now) static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs) { -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* * When we are idle and the tick is stopped, we have to touch * the watchdog as we might not schedule for a really long @@ -147,226 +142,10 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs) profile_tick(CPU_PROFILING); } -#ifdef CONFIG_NO_HZ_FULL -static cpumask_var_t nohz_full_mask; -bool have_nohz_full_mask; - -static bool can_stop_full_tick(void) -{ - WARN_ON_ONCE(!irqs_disabled()); - - if (!sched_can_stop_tick()) { - trace_tick_stop(0, "more than 1 task in runqueue\n"); - return false; - } - - if (!posix_cpu_timers_can_stop_tick(current)) { - trace_tick_stop(0, "posix timers running\n"); - return false; - } - - if (!perf_event_can_stop_tick()) { - trace_tick_stop(0, "perf events running\n"); - return false; - } - - /* sched_clock_tick() needs us? */ -#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK - /* - * TODO: kick full dynticks CPUs when - * sched_clock_stable is set. - */ - if (!sched_clock_stable) { - trace_tick_stop(0, "unstable sched clock\n"); - return false; - } -#endif - - return true; -} - -static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now); - -/* - * Re-evaluate the need for the tick on the current CPU - * and restart it if necessary. - */ -void tick_nohz_full_check(void) -{ - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); - - if (tick_nohz_full_cpu(smp_processor_id())) { - if (ts->tick_stopped && !is_idle_task(current)) { - if (!can_stop_full_tick()) - tick_nohz_restart_sched_tick(ts, ktime_get()); - } - } -} - -static void nohz_full_kick_work_func(struct irq_work *work) -{ - tick_nohz_full_check(); -} - -static DEFINE_PER_CPU(struct irq_work, nohz_full_kick_work) = { - .func = nohz_full_kick_work_func, -}; - -/* - * Kick the current CPU if it's full dynticks in order to force it to - * re-evaluate its dependency on the tick and restart it if necessary. - */ -void tick_nohz_full_kick(void) -{ - if (tick_nohz_full_cpu(smp_processor_id())) - irq_work_queue(&__get_cpu_var(nohz_full_kick_work)); -} - -static void nohz_full_kick_ipi(void *info) -{ - tick_nohz_full_check(); -} - -/* - * Kick all full dynticks CPUs in order to force these to re-evaluate - * their dependency on the tick and restart it if necessary. - */ -void tick_nohz_full_kick_all(void) -{ - if (!have_nohz_full_mask) - return; - - preempt_disable(); - smp_call_function_many(nohz_full_mask, - nohz_full_kick_ipi, NULL, false); - preempt_enable(); -} - -/* - * Re-evaluate the need for the tick as we switch the current task. - * It might need the tick due to per task/process properties: - * perf events, posix cpu timers, ... - */ -void tick_nohz_task_switch(struct task_struct *tsk) -{ - unsigned long flags; - - local_irq_save(flags); - - if (!tick_nohz_full_cpu(smp_processor_id())) - goto out; - - if (tick_nohz_tick_stopped() && !can_stop_full_tick()) - tick_nohz_full_kick(); - -out: - local_irq_restore(flags); -} - -int tick_nohz_full_cpu(int cpu) -{ - if (!have_nohz_full_mask) - return 0; - - return cpumask_test_cpu(cpu, nohz_full_mask); -} - -/* Parse the boot-time nohz CPU list from the kernel parameters. */ -static int __init tick_nohz_full_setup(char *str) -{ - int cpu; - - alloc_bootmem_cpumask_var(&nohz_full_mask); - if (cpulist_parse(str, nohz_full_mask) < 0) { - pr_warning("NOHZ: Incorrect nohz_full cpumask\n"); - return 1; - } - - cpu = smp_processor_id(); - if (cpumask_test_cpu(cpu, nohz_full_mask)) { - pr_warning("NO_HZ: Clearing %d from nohz_full range for timekeeping\n", cpu); - cpumask_clear_cpu(cpu, nohz_full_mask); - } - have_nohz_full_mask = true; - - return 1; -} -__setup("nohz_full=", tick_nohz_full_setup); - -static int __cpuinit tick_nohz_cpu_down_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_DOWN_PREPARE: - /* - * If we handle the timekeeping duty for full dynticks CPUs, - * we can't safely shutdown that CPU. - */ - if (have_nohz_full_mask && tick_do_timer_cpu == cpu) - return -EINVAL; - break; - } - return NOTIFY_OK; -} - -/* - * Worst case string length in chunks of CPU range seems 2 steps - * separations: 0,2,4,6,... - * This is NR_CPUS + sizeof('\0') - */ -static char __initdata nohz_full_buf[NR_CPUS + 1]; - -static int tick_nohz_init_all(void) -{ - int err = -1; - -#ifdef CONFIG_NO_HZ_FULL_ALL - if (!alloc_cpumask_var(&nohz_full_mask, GFP_KERNEL)) { - pr_err("NO_HZ: Can't allocate full dynticks cpumask\n"); - return err; - } - err = 0; - cpumask_setall(nohz_full_mask); - cpumask_clear_cpu(smp_processor_id(), nohz_full_mask); - have_nohz_full_mask = true; -#endif - return err; -} - -void __init tick_nohz_init(void) -{ - int cpu; - - if (!have_nohz_full_mask) { - if (tick_nohz_init_all() < 0) - return; - } - - cpu_notifier(tick_nohz_cpu_down_callback, 0); - - /* Make sure full dynticks CPU are also RCU nocbs */ - for_each_cpu(cpu, nohz_full_mask) { - if (!rcu_is_nocb_cpu(cpu)) { - pr_warning("NO_HZ: CPU %d is not RCU nocb: " - "cleared from nohz_full range", cpu); - cpumask_clear_cpu(cpu, nohz_full_mask); - } - } - - cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask); - pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf); -} -#else -#define have_nohz_full_mask (0) -#endif - /* * NOHZ - aka dynamic tick functionality */ -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* * NO HZ enabled ? */ @@ -566,12 +345,11 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, delta_jiffies = rcu_delta_jiffies; } } - /* - * Do not stop the tick, if we are only one off (or less) - * or if the cpu is required for RCU: + * Do not stop the tick, if we are only one off + * or if the cpu is required for rcu */ - if (!ts->tick_stopped && delta_jiffies <= 1) + if (!ts->tick_stopped && delta_jiffies == 1) goto out; /* Schedule the tick, if we are at least one jiffie off */ @@ -600,13 +378,6 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, time_delta = KTIME_MAX; } -#ifdef CONFIG_NO_HZ_FULL - if (!ts->inidle) { - time_delta = min(time_delta, - scheduler_tick_max_deferment()); - } -#endif - /* * calculate the expiry time for the next timer wheel * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals @@ -650,7 +421,6 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, ts->last_tick = hrtimer_get_expires(&ts->sched_timer); ts->tick_stopped = 1; - trace_tick_stop(1, " "); } /* @@ -687,24 +457,6 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, return ret; } -static void tick_nohz_full_stop_tick(struct tick_sched *ts) -{ -#ifdef CONFIG_NO_HZ_FULL - int cpu = smp_processor_id(); - - if (!tick_nohz_full_cpu(cpu) || is_idle_task(current)) - return; - - if (!ts->tick_stopped && ts->nohz_mode == NOHZ_MODE_INACTIVE) - return; - - if (!can_stop_full_tick()) - return; - - tick_nohz_stop_sched_tick(ts, ktime_get(), cpu); -#endif -} - static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) { /* @@ -737,21 +489,6 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) return false; } - if (have_nohz_full_mask) { - /* - * Keep the tick alive to guarantee timekeeping progression - * if there are full dynticks CPUs around - */ - if (tick_do_timer_cpu == cpu) - return false; - /* - * Boot safety: make sure the timekeeping duty has been - * assigned before entering dyntick-idle mode, - */ - if (tick_do_timer_cpu == TICK_DO_TIMER_NONE) - return false; - } - return true; } @@ -831,13 +568,12 @@ void tick_nohz_irq_exit(void) { struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); - if (ts->inidle) { - /* Cancel the timer because CPU already waken up from the C-states*/ - menu_hrtimer_cancel(); - __tick_nohz_idle_enter(ts); - } else { - tick_nohz_full_stop_tick(ts); - } + if (!ts->inidle) + return; + + /* Cancel the timer because CPU already waken up from the C-states*/ + menu_hrtimer_cancel(); + __tick_nohz_idle_enter(ts); } /** @@ -1066,7 +802,7 @@ static inline void tick_check_nohz(int cpu) static inline void tick_nohz_switch_to_nohz(void) { } static inline void tick_check_nohz(int cpu) { } -#endif /* CONFIG_NO_HZ_COMMON */ +#endif /* NO_HZ */ /* * Called from irq_enter to notify about the possible interruption of idle() @@ -1151,14 +887,14 @@ void tick_setup_sched_timer(void) now = ktime_get(); } -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ if (tick_nohz_enabled) ts->nohz_mode = NOHZ_MODE_HIGHRES; #endif } #endif /* HIGH_RES_TIMERS */ -#if defined CONFIG_NO_HZ_COMMON || defined CONFIG_HIGH_RES_TIMERS +#if defined CONFIG_NO_HZ || defined CONFIG_HIGH_RES_TIMERS void tick_cancel_sched_timer(int cpu) { struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); diff --git a/trunk/kernel/timer.c b/trunk/kernel/timer.c index a860bba34412..09bca8ce9771 100644 --- a/trunk/kernel/timer.c +++ b/trunk/kernel/timer.c @@ -739,7 +739,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, cpu = smp_processor_id(); -#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) +#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) cpu = get_nohz_timer_target(); #endif @@ -931,14 +931,14 @@ void add_timer_on(struct timer_list *timer, int cpu) debug_activate(timer, timer->expires); internal_add_timer(base, timer); /* - * Check whether the other CPU is in dynticks mode and needs - * to be triggered to reevaluate the timer wheel. - * We are protected against the other CPU fiddling + * Check whether the other CPU is idle and needs to be + * triggered to reevaluate the timer wheel when nohz is + * active. We are protected against the other CPU fiddling * with the timer by holding the timer base lock. This also - * makes sure that a CPU on the way to stop its tick can not - * evaluate the timer wheel. + * makes sure that a CPU on the way to idle can not evaluate + * the timer wheel. */ - wake_up_nohz_cpu(cpu); + wake_up_idle_cpu(cpu); spin_unlock_irqrestore(&base->lock, flags); } EXPORT_SYMBOL_GPL(add_timer_on); @@ -1189,7 +1189,7 @@ static inline void __run_timers(struct tvec_base *base) spin_unlock_irq(&base->lock); } -#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_NO_HZ /* * Find out when the next timer event is due to happen. This * is used on S/390 to stop all activity when a CPU is idle. diff --git a/trunk/lib/oid_registry.c b/trunk/lib/oid_registry.c index 318f382a010d..d8de11f45908 100644 --- a/trunk/lib/oid_registry.c +++ b/trunk/lib/oid_registry.c @@ -9,7 +9,6 @@ * 2 of the Licence, or (at your option) any later version. */ -#include #include #include #include @@ -17,10 +16,6 @@ #include #include "oid_registry_data.c" -MODULE_DESCRIPTION("OID Registry"); -MODULE_AUTHOR("Red Hat, Inc."); -MODULE_LICENSE("GPL"); - /** * look_up_OID - Find an OID registration for the specified data * @data: Binary representation of the OID diff --git a/trunk/net/8021q/vlan_dev.c b/trunk/net/8021q/vlan_dev.c index 3a8c8fd63c88..8af508536d36 100644 --- a/trunk/net/8021q/vlan_dev.c +++ b/trunk/net/8021q/vlan_dev.c @@ -628,7 +628,7 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev, netdev_features_t features) { struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; - netdev_features_t old_features = features; + u32 old_features = features; features &= real_dev->vlan_features; features |= NETIF_F_RXCSUM; diff --git a/trunk/net/bridge/br_stp_timer.c b/trunk/net/bridge/br_stp_timer.c index 950663d4d330..c3530a81a33b 100644 --- a/trunk/net/bridge/br_stp_timer.c +++ b/trunk/net/bridge/br_stp_timer.c @@ -107,7 +107,7 @@ static void br_tcn_timer_expired(unsigned long arg) br_debug(br, "tcn timer expired\n"); spin_lock(&br->lock); - if (!br_is_root_bridge(br) && (br->dev->flags & IFF_UP)) { + if (br->dev->flags & IFF_UP) { br_transmit_tcn(br); mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time); diff --git a/trunk/net/core/dev.c b/trunk/net/core/dev.c index 40b1fadaf637..4040673f806a 100644 --- a/trunk/net/core/dev.c +++ b/trunk/net/core/dev.c @@ -2456,7 +2456,7 @@ EXPORT_SYMBOL(netif_skb_features); * 2. skb is fragmented and the device does not support SG. */ static inline int skb_needs_linearize(struct sk_buff *skb, - netdev_features_t features) + int features) { return skb_is_nonlinear(skb) && ((skb_has_frag_list(skb) && diff --git a/trunk/net/core/ethtool.c b/trunk/net/core/ethtool.c index 22efdaa76ebf..5a934ef90f8b 100644 --- a/trunk/net/core/ethtool.c +++ b/trunk/net/core/ethtool.c @@ -1421,7 +1421,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) void __user *useraddr = ifr->ifr_data; u32 ethcmd; int rc; - netdev_features_t old_features; + u32 old_features; if (!dev || !netif_device_present(dev)) return -ENODEV; diff --git a/trunk/net/ipv4/af_inet.c b/trunk/net/ipv4/af_inet.c index d01be2a3ae53..c61b3bb87a16 100644 --- a/trunk/net/ipv4/af_inet.c +++ b/trunk/net/ipv4/af_inet.c @@ -1293,7 +1293,6 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, SKB_GSO_DODGY | SKB_GSO_TCP_ECN | SKB_GSO_GRE | - SKB_GSO_TCPV6 | SKB_GSO_UDP_TUNNEL | 0))) goto out; diff --git a/trunk/net/ipv4/gre.c b/trunk/net/ipv4/gre.c index cc22363965d2..d2d5a99fba09 100644 --- a/trunk/net/ipv4/gre.c +++ b/trunk/net/ipv4/gre.c @@ -121,7 +121,6 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, int ghl = GRE_HEADER_SECTION; struct gre_base_hdr *greh; int mac_len = skb->mac_len; - __be16 protocol = skb->protocol; int tnl_hlen; bool csum; @@ -151,7 +150,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, /* setup inner skb. */ if (greh->protocol == htons(ETH_P_TEB)) { - struct ethhdr *eth = (struct ethhdr *)skb_inner_mac_header(skb); + struct ethhdr *eth = eth_hdr(skb); skb->protocol = eth->h_proto; } else { skb->protocol = greh->protocol; @@ -200,7 +199,6 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, skb_reset_mac_header(skb); skb_set_network_header(skb, mac_len); skb->mac_len = mac_len; - skb->protocol = protocol; } while ((skb = skb->next)); out: return segs; diff --git a/trunk/net/ipv4/udp.c b/trunk/net/ipv4/udp.c index 0ae038a4c7a8..6abbe6455129 100644 --- a/trunk/net/ipv4/udp.c +++ b/trunk/net/ipv4/udp.c @@ -2311,10 +2311,8 @@ static struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, struct sk_buff *segs = ERR_PTR(-EINVAL); int mac_len = skb->mac_len; int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); - struct ethhdr *inner_eth = (struct ethhdr *)skb_inner_mac_header(skb); - __be16 protocol = skb->protocol; - netdev_features_t enc_features; int outer_hlen; + netdev_features_t enc_features; if (unlikely(!pskb_may_pull(skb, tnl_hlen))) goto out; @@ -2324,8 +2322,6 @@ static struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, skb_reset_mac_header(skb); skb_set_network_header(skb, skb_inner_network_offset(skb)); skb->mac_len = skb_inner_network_offset(skb); - inner_eth = (struct ethhdr *)skb_mac_header(skb); - skb->protocol = inner_eth->h_proto; /* segment inner packet. */ enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); @@ -2362,7 +2358,6 @@ static struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, } skb->ip_summed = CHECKSUM_NONE; - skb->protocol = protocol; } while ((skb = skb->next)); out: return segs; diff --git a/trunk/net/packet/af_packet.c b/trunk/net/packet/af_packet.c index 8ec1bca7f859..dd5cd49b0e09 100644 --- a/trunk/net/packet/af_packet.c +++ b/trunk/net/packet/af_packet.c @@ -742,33 +742,36 @@ static void prb_open_block(struct tpacket_kbdq_core *pkc1, smp_rmb(); - /* We could have just memset this but we will lose the - * flexibility of making the priv area sticky - */ - - BLOCK_SNUM(pbd1) = pkc1->knxt_seq_num++; - BLOCK_NUM_PKTS(pbd1) = 0; - BLOCK_LEN(pbd1) = BLK_PLUS_PRIV(pkc1->blk_sizeof_priv); - - getnstimeofday(&ts); + if (likely(TP_STATUS_KERNEL == BLOCK_STATUS(pbd1))) { - h1->ts_first_pkt.ts_sec = ts.tv_sec; - h1->ts_first_pkt.ts_nsec = ts.tv_nsec; - - pkc1->pkblk_start = (char *)pbd1; - pkc1->nxt_offset = pkc1->pkblk_start + BLK_PLUS_PRIV(pkc1->blk_sizeof_priv); - - BLOCK_O2FP(pbd1) = (__u32)BLK_PLUS_PRIV(pkc1->blk_sizeof_priv); - BLOCK_O2PRIV(pbd1) = BLK_HDR_LEN; + /* We could have just memset this but we will lose the + * flexibility of making the priv area sticky + */ + BLOCK_SNUM(pbd1) = pkc1->knxt_seq_num++; + BLOCK_NUM_PKTS(pbd1) = 0; + BLOCK_LEN(pbd1) = BLK_PLUS_PRIV(pkc1->blk_sizeof_priv); + getnstimeofday(&ts); + h1->ts_first_pkt.ts_sec = ts.tv_sec; + h1->ts_first_pkt.ts_nsec = ts.tv_nsec; + pkc1->pkblk_start = (char *)pbd1; + pkc1->nxt_offset = pkc1->pkblk_start + BLK_PLUS_PRIV(pkc1->blk_sizeof_priv); + BLOCK_O2FP(pbd1) = (__u32)BLK_PLUS_PRIV(pkc1->blk_sizeof_priv); + BLOCK_O2PRIV(pbd1) = BLK_HDR_LEN; + pbd1->version = pkc1->version; + pkc1->prev = pkc1->nxt_offset; + pkc1->pkblk_end = pkc1->pkblk_start + pkc1->kblk_size; + prb_thaw_queue(pkc1); + _prb_refresh_rx_retire_blk_timer(pkc1); - pbd1->version = pkc1->version; - pkc1->prev = pkc1->nxt_offset; - pkc1->pkblk_end = pkc1->pkblk_start + pkc1->kblk_size; + smp_wmb(); - prb_thaw_queue(pkc1); - _prb_refresh_rx_retire_blk_timer(pkc1); + return; + } - smp_wmb(); + WARN(1, "ERROR block:%p is NOT FREE status:%d kactive_blk_num:%d\n", + pbd1, BLOCK_STATUS(pbd1), pkc1->kactive_blk_num); + dump_stack(); + BUG(); } /* @@ -859,6 +862,10 @@ static void prb_retire_current_block(struct tpacket_kbdq_core *pkc, prb_close_block(pkc, pbd, po, status); return; } + + WARN(1, "ERROR-pbd[%d]:%p\n", pkc->kactive_blk_num, pbd); + dump_stack(); + BUG(); } static int prb_curr_blk_in_use(struct tpacket_kbdq_core *pkc, diff --git a/trunk/net/tipc/bcast.c b/trunk/net/tipc/bcast.c index e5f3da507823..25e159c2feb4 100644 --- a/trunk/net/tipc/bcast.c +++ b/trunk/net/tipc/bcast.c @@ -584,7 +584,8 @@ static int tipc_bcbearer_send(struct sk_buff *buf, { int bp_index; - /* Prepare broadcast link message for reliable transmission, + /* + * Prepare broadcast link message for reliable transmission, * if first time trying to send it; * preparation is skipped for broadcast link protocol messages * since they are sent in an unreliable manner and don't need it @@ -610,43 +611,30 @@ static int tipc_bcbearer_send(struct sk_buff *buf, for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary; struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary; - struct tipc_bearer *b = p; - struct sk_buff *tbuf; if (!p) - break; /* No more bearers to try */ - - if (tipc_bearer_blocked(p)) { - if (!s || tipc_bearer_blocked(s)) - continue; /* Can't use either bearer */ - b = s; - } + break; /* no more bearers to try */ - tipc_nmap_diff(&bcbearer->remains, &b->nodes, - &bcbearer->remains_new); + tipc_nmap_diff(&bcbearer->remains, &p->nodes, &bcbearer->remains_new); if (bcbearer->remains_new.count == bcbearer->remains.count) - continue; /* Nothing added by bearer pair */ + continue; /* bearer pair doesn't add anything */ - if (bp_index == 0) { - /* Use original buffer for first bearer */ - tipc_bearer_send(b, buf, &b->bcast_addr); - } else { - /* Avoid concurrent buffer access */ - tbuf = pskb_copy(buf, GFP_ATOMIC); - if (!tbuf) - break; - tipc_bearer_send(b, tbuf, &b->bcast_addr); - kfree_skb(tbuf); /* Bearer keeps a clone */ - } + if (!tipc_bearer_blocked(p)) + tipc_bearer_send(p, buf, &p->bcast_addr); + else if (s && !tipc_bearer_blocked(s)) + /* unable to send on primary bearer */ + tipc_bearer_send(s, buf, &s->bcast_addr); + else + /* unable to send on either bearer */ + continue; - /* Swap bearers for next packet */ if (s) { bcbearer->bpairs[bp_index].primary = s; bcbearer->bpairs[bp_index].secondary = p; } if (bcbearer->remains_new.count == 0) - break; /* All targets reached */ + break; /* all targets reached */ bcbearer->remains = bcbearer->remains_new; } diff --git a/trunk/scripts/Makefile.build b/trunk/scripts/Makefile.build index d5d859c80729..0e801c3cdaf8 100644 --- a/trunk/scripts/Makefile.build +++ b/trunk/scripts/Makefile.build @@ -211,8 +211,7 @@ $(obj)/%.i: $(src)/%.c FORCE cmd_gensymtypes = \ $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ - $(GENKSYMS) $(if $(1), -T $(2)) \ - $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \ + $(GENKSYMS) $(if $(1), -T $(2)) -a $(ARCH) \ $(if $(KBUILD_PRESERVE),-p) \ -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) diff --git a/trunk/scripts/Makefile.lib b/trunk/scripts/Makefile.lib index 51bb3de680b6..3e73dfd838cd 100644 --- a/trunk/scripts/Makefile.lib +++ b/trunk/scripts/Makefile.lib @@ -119,6 +119,13 @@ _c_flags += $(if $(patsubst n%,, \ $(CFLAGS_GCOV)) endif +ifdef CONFIG_SYMBOL_PREFIX +_sym_flags = -DSYMBOL_PREFIX=$(patsubst "%",%,$(CONFIG_SYMBOL_PREFIX)) +_cpp_flags += $(_sym_flags) +_a_flags += $(_sym_flags) +endif + + # If building the kernel in a separate objtree expand all occurrences # of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). diff --git a/trunk/scripts/Makefile.modpost b/trunk/scripts/Makefile.modpost index 8dcdca27d836..cf82c832458f 100644 --- a/trunk/scripts/Makefile.modpost +++ b/trunk/scripts/Makefile.modpost @@ -60,8 +60,7 @@ kernelsymfile := $(objtree)/Module.symvers modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers # Step 1), find all modules listed in $(MODVERDIR)/ -MODLISTCMD := find $(MODVERDIR) -name '*.mod' | xargs -r grep -h '\.ko$$' | sort -u -__modules := $(shell $(MODLISTCMD)) +__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) # Stop after building .o files if NOFINAL is set. Makes compile tests quicker @@ -79,13 +78,12 @@ modpost = scripts/mod/modpost \ $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) -# We can go over command line length here, so be careful. quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules - cmd_modpost = $(MODLISTCMD) | sed 's/\.ko$$/.o/' | $(modpost) -s -T - + cmd_modpost = $(modpost) -s PHONY += __modpost __modpost: $(modules:.ko=.o) FORCE - $(call cmd,modpost) $(wildcard vmlinux) + $(call cmd,modpost) $(wildcard vmlinux) $(filter-out FORCE,$^) quiet_cmd_kernel-mod = MODPOST $@ cmd_kernel-mod = $(modpost) $@ diff --git a/trunk/scripts/genksyms/genksyms.c b/trunk/scripts/genksyms/genksyms.c index 88632df4381b..d25e4a118d37 100644 --- a/trunk/scripts/genksyms/genksyms.c +++ b/trunk/scripts/genksyms/genksyms.c @@ -45,6 +45,7 @@ int in_source_file; static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, flag_preserve, flag_warnings; +static const char *arch = ""; static const char *mod_prefix = ""; static int errors; @@ -730,7 +731,7 @@ static void genksyms_usage(void) { fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n" #ifdef __GNU_LIBRARY__ - " -s, --symbol-prefix Select symbol prefix\n" + " -a, --arch Select architecture\n" " -d, --debug Increment the debug level (repeatable)\n" " -D, --dump Dump expanded symbol defs (for debugging only)\n" " -r, --reference file Read reference symbols from a file\n" @@ -741,7 +742,7 @@ static void genksyms_usage(void) " -h, --help Print this message\n" " -V, --version Print the release version\n" #else /* __GNU_LIBRARY__ */ - " -s Select symbol prefix\n" + " -a Select architecture\n" " -d Increment the debug level (repeatable)\n" " -D Dump expanded symbol defs (for debugging only)\n" " -r file Read reference symbols from a file\n" @@ -762,7 +763,7 @@ int main(int argc, char **argv) #ifdef __GNU_LIBRARY__ struct option long_opts[] = { - {"symbol-prefix", 1, 0, 's'}, + {"arch", 1, 0, 'a'}, {"debug", 0, 0, 'd'}, {"warnings", 0, 0, 'w'}, {"quiet", 0, 0, 'q'}, @@ -775,14 +776,14 @@ int main(int argc, char **argv) {0, 0, 0, 0} }; - while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph", + while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph", &long_opts[0], NULL)) != EOF) #else /* __GNU_LIBRARY__ */ - while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF) + while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF) #endif /* __GNU_LIBRARY__ */ switch (o) { - case 's': - mod_prefix = optarg; + case 'a': + arch = optarg; break; case 'd': flag_debug++; @@ -825,6 +826,9 @@ int main(int argc, char **argv) genksyms_usage(); return 1; } + if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0) || + (strcmp(arch, "metag") == 0)) + mod_prefix = "_"; { extern int yydebug; extern int yy_flex_debug; diff --git a/trunk/scripts/link-vmlinux.sh b/trunk/scripts/link-vmlinux.sh index 014994936b1c..3d569d6022c2 100644 --- a/trunk/scripts/link-vmlinux.sh +++ b/trunk/scripts/link-vmlinux.sh @@ -74,8 +74,9 @@ kallsyms() info KSYM ${2} local kallsymopt; - if [ -n "${CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX}" ]; then - kallsymopt="${kallsymopt} --symbol-prefix=_" + if [ -n "${CONFIG_SYMBOL_PREFIX}" ]; then + kallsymopt="${kallsymopt} \ + --symbol-prefix=${CONFIG_SYMBOL_PREFIX}" fi if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then diff --git a/trunk/scripts/mod/modpost.c b/trunk/scripts/mod/modpost.c index a4be8e112bb6..78b30c1548e9 100644 --- a/trunk/scripts/mod/modpost.c +++ b/trunk/scripts/mod/modpost.c @@ -15,12 +15,17 @@ #include #include #include -#include -#include #include "modpost.h" #include "../../include/generated/autoconf.h" #include "../../include/linux/license.h" -#include "../../include/linux/export.h" + +/* Some toolchains use a `_' prefix for all user symbols. */ +#ifdef CONFIG_SYMBOL_PREFIX +#define MODULE_SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX +#else +#define MODULE_SYMBOL_PREFIX "" +#endif + /* Are we using CONFIG_MODVERSIONS? */ int modversions = 0; @@ -80,14 +85,6 @@ PRINTF void merror(const char *fmt, ...) va_end(arglist); } -static inline bool strends(const char *str, const char *postfix) -{ - if (strlen(str) < strlen(postfix)) - return false; - - return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; -} - static int is_vmlinux(const char *modname) { const char *myname; @@ -123,20 +120,22 @@ static struct module *find_module(char *modname) return mod; } -static struct module *new_module(const char *modname) +static struct module *new_module(char *modname) { struct module *mod; - char *p; + char *p, *s; mod = NOFAIL(malloc(sizeof(*mod))); memset(mod, 0, sizeof(*mod)); p = NOFAIL(strdup(modname)); /* strip trailing .o */ - if (strends(p, ".o")) { - p[strlen(p) - 2] = '\0'; - mod->is_dot_o = 1; - } + s = strrchr(p, '.'); + if (s != NULL) + if (strcmp(s, ".o") == 0) { + *s = '\0'; + mod->is_dot_o = 1; + } /* add to list */ mod->name = p; @@ -563,7 +562,7 @@ static void parse_elf_finish(struct elf_info *info) static int ignore_undef_symbol(struct elf_info *info, const char *symname) { /* ignore __this_module, it will be resolved shortly */ - if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0) + if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0) return 1; /* ignore global offset table */ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) @@ -584,8 +583,8 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) return 0; } -#define CRC_PFX VMLINUX_SYMBOL_STR(__crc_) -#define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_) +#define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_" +#define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_" static void handle_modversions(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname) @@ -638,15 +637,14 @@ static void handle_modversions(struct module *mod, struct elf_info *info, } #endif -#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX - if (symname[0] != '_') - break; - else - symname++; -#endif - mod->unres = alloc_symbol(symname, - ELF_ST_BIND(sym->st_info) == STB_WEAK, - mod->unres); + if (memcmp(symname, MODULE_SYMBOL_PREFIX, + strlen(MODULE_SYMBOL_PREFIX)) == 0) { + mod->unres = + alloc_symbol(symname + + strlen(MODULE_SYMBOL_PREFIX), + ELF_ST_BIND(sym->st_info) == STB_WEAK, + mod->unres); + } break; default: /* All exported symbols */ @@ -654,9 +652,9 @@ static void handle_modversions(struct module *mod, struct elf_info *info, sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, export); } - if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0) + if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) mod->has_init = 1; - if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0) + if (strcmp(symname, MODULE_SYMBOL_PREFIX "cleanup_module") == 0) mod->has_cleanup = 1; break; } @@ -1764,27 +1762,6 @@ static void read_symbols(char *modname) mod->unres = alloc_symbol("module_layout", 0, mod->unres); } -static void read_symbols_from_files(const char *filename) -{ - FILE *in = stdin; - char fname[PATH_MAX]; - - if (strcmp(filename, "-") != 0) { - in = fopen(filename, "r"); - if (!in) - fatal("Can't open filenames file %s: %m", filename); - } - - while (fgets(fname, PATH_MAX, in) != NULL) { - if (strends(fname, "\n")) - fname[strlen(fname)-1] = '\0'; - read_symbols(fname); - } - - if (in != stdin) - fclose(in); -} - #define SZ 500 /* We first write the generated file into memory using the @@ -1957,8 +1934,7 @@ static int add_versions(struct buffer *b, struct module *mod) s->name, mod->name); continue; } - buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n", - s->crc, s->name); + buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name); } buf_printf(b, "};\n"); @@ -2146,13 +2122,13 @@ int main(int argc, char **argv) struct module *mod; struct buffer buf = { }; char *kernel_read = NULL, *module_read = NULL; - char *dump_write = NULL, *files_source = NULL; + char *dump_write = NULL; int opt; int err; struct ext_sym_list *extsym_iter; struct ext_sym_list *extsym_start = NULL; - while ((opt = getopt(argc, argv, "i:I:e:msST:o:awM:K:")) != -1) { + while ((opt = getopt(argc, argv, "i:I:e:msSo:awM:K:")) != -1) { switch (opt) { case 'i': kernel_read = optarg; @@ -2184,9 +2160,6 @@ int main(int argc, char **argv) case 'S': sec_mismatch_verbose = 0; break; - case 'T': - files_source = optarg; - break; case 'w': warn_unresolved = 1; break; @@ -2209,9 +2182,6 @@ int main(int argc, char **argv) while (optind < argc) read_symbols(argv[optind++]); - if (files_source) - read_symbols_from_files(files_source); - for (mod = modules; mod; mod = mod->next) { if (mod->skip) continue; diff --git a/trunk/virt/kvm/Kconfig b/trunk/virt/kvm/Kconfig index 779262f59e25..d01b24b72c61 100644 --- a/trunk/virt/kvm/Kconfig +++ b/trunk/virt/kvm/Kconfig @@ -6,9 +6,6 @@ config HAVE_KVM config HAVE_KVM_IRQCHIP bool -config HAVE_KVM_IRQ_ROUTING - bool - config HAVE_KVM_EVENTFD bool select EVENTFD diff --git a/trunk/virt/kvm/assigned-dev.c b/trunk/virt/kvm/assigned-dev.c index 8db43701016f..3642239252b0 100644 --- a/trunk/virt/kvm/assigned-dev.c +++ b/trunk/virt/kvm/assigned-dev.c @@ -80,12 +80,11 @@ kvm_assigned_dev_raise_guest_irq(struct kvm_assigned_dev_kernel *assigned_dev, spin_lock(&assigned_dev->intx_mask_lock); if (!(assigned_dev->flags & KVM_DEV_ASSIGN_MASK_INTX)) kvm_set_irq(assigned_dev->kvm, - assigned_dev->irq_source_id, vector, 1, - false); + assigned_dev->irq_source_id, vector, 1); spin_unlock(&assigned_dev->intx_mask_lock); } else kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, - vector, 1, false); + vector, 1); } static irqreturn_t kvm_assigned_dev_thread_intx(int irq, void *dev_id) @@ -166,7 +165,7 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian) container_of(kian, struct kvm_assigned_dev_kernel, ack_notifier); - kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0, false); + kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0); spin_lock(&dev->intx_mask_lock); @@ -189,7 +188,7 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian) if (reassert) kvm_set_irq(dev->kvm, dev->irq_source_id, - dev->guest_irq, 1, false); + dev->guest_irq, 1); } spin_unlock(&dev->intx_mask_lock); @@ -203,7 +202,7 @@ static void deassign_guest_irq(struct kvm *kvm, &assigned_dev->ack_notifier); kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, - assigned_dev->guest_irq, 0, false); + assigned_dev->guest_irq, 0); if (assigned_dev->irq_source_id != -1) kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id); @@ -902,7 +901,7 @@ static int kvm_vm_ioctl_set_pci_irq_mask(struct kvm *kvm, if (match->irq_requested_type & KVM_DEV_IRQ_GUEST_INTX) { if (assigned_dev->flags & KVM_DEV_ASSIGN_MASK_INTX) { kvm_set_irq(match->kvm, match->irq_source_id, - match->guest_irq, 0, false); + match->guest_irq, 0); /* * Masking at hardware-level is performed on demand, * i.e. when an IRQ actually arrives at the host. @@ -983,6 +982,36 @@ long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl, goto out; break; } +#ifdef KVM_CAP_IRQ_ROUTING + case KVM_SET_GSI_ROUTING: { + struct kvm_irq_routing routing; + struct kvm_irq_routing __user *urouting; + struct kvm_irq_routing_entry *entries; + + r = -EFAULT; + if (copy_from_user(&routing, argp, sizeof(routing))) + goto out; + r = -EINVAL; + if (routing.nr >= KVM_MAX_IRQ_ROUTES) + goto out; + if (routing.flags) + goto out; + r = -ENOMEM; + entries = vmalloc(routing.nr * sizeof(*entries)); + if (!entries) + goto out; + r = -EFAULT; + urouting = argp; + if (copy_from_user(entries, urouting->entries, + routing.nr * sizeof(*entries))) + goto out_free_irq_routing; + r = kvm_set_irq_routing(kvm, entries, routing.nr, + routing.flags); + out_free_irq_routing: + vfree(entries); + break; + } +#endif /* KVM_CAP_IRQ_ROUTING */ #ifdef __KVM_HAVE_MSIX case KVM_ASSIGN_SET_MSIX_NR: { struct kvm_assigned_msix_nr entry_nr; diff --git a/trunk/virt/kvm/eventfd.c b/trunk/virt/kvm/eventfd.c index 64ee720b75c7..adb17f266b28 100644 --- a/trunk/virt/kvm/eventfd.c +++ b/trunk/virt/kvm/eventfd.c @@ -35,7 +35,7 @@ #include "iodev.h" -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC /* * -------------------------------------------------------------------- * irqfd: Allows an fd to be used to inject an interrupt to the guest @@ -100,13 +100,11 @@ irqfd_inject(struct work_struct *work) struct kvm *kvm = irqfd->kvm; if (!irqfd->resampler) { - kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1, - false); - kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0, - false); + kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1); + kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0); } else kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID, - irqfd->gsi, 1, false); + irqfd->gsi, 1); } /* @@ -123,7 +121,7 @@ irqfd_resampler_ack(struct kvm_irq_ack_notifier *kian) resampler = container_of(kian, struct _irqfd_resampler, notifier); kvm_set_irq(resampler->kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID, - resampler->notifier.gsi, 0, false); + resampler->notifier.gsi, 0); rcu_read_lock(); @@ -148,7 +146,7 @@ irqfd_resampler_shutdown(struct _irqfd *irqfd) list_del(&resampler->link); kvm_unregister_irq_ack_notifier(kvm, &resampler->notifier); kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID, - resampler->notifier.gsi, 0, false); + resampler->notifier.gsi, 0); kfree(resampler); } @@ -227,8 +225,7 @@ irqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key) irq = rcu_dereference(irqfd->irq_entry); /* An event has been signaled, inject an interrupt */ if (irq) - kvm_set_msi(irq, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, - false); + kvm_set_msi(irq, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1); else schedule_work(&irqfd->inject); rcu_read_unlock(); @@ -433,7 +430,7 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) void kvm_eventfd_init(struct kvm *kvm) { -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC spin_lock_init(&kvm->irqfds.lock); INIT_LIST_HEAD(&kvm->irqfds.items); INIT_LIST_HEAD(&kvm->irqfds.resampler_list); @@ -442,7 +439,7 @@ kvm_eventfd_init(struct kvm *kvm) INIT_LIST_HEAD(&kvm->ioeventfds); } -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC /* * shutdown any irqfd's that match fd+gsi */ @@ -546,7 +543,7 @@ void kvm_irq_routing_update(struct kvm *kvm, * aggregated from all vm* instances. We need our own isolated single-thread * queue to prevent deadlock against flushing the normal work-queue. */ -int kvm_irqfd_init(void) +static int __init irqfd_module_init(void) { irqfd_cleanup_wq = create_singlethread_workqueue("kvm-irqfd-cleanup"); if (!irqfd_cleanup_wq) @@ -555,10 +552,13 @@ int kvm_irqfd_init(void) return 0; } -void kvm_irqfd_exit(void) +static void __exit irqfd_module_exit(void) { destroy_workqueue(irqfd_cleanup_wq); } + +module_init(irqfd_module_init); +module_exit(irqfd_module_exit); #endif /* @@ -577,7 +577,6 @@ struct _ioeventfd { struct eventfd_ctx *eventfd; u64 datamatch; struct kvm_io_device dev; - u8 bus_idx; bool wildcard; }; @@ -670,8 +669,7 @@ ioeventfd_check_collision(struct kvm *kvm, struct _ioeventfd *p) struct _ioeventfd *_p; list_for_each_entry(_p, &kvm->ioeventfds, list) - if (_p->bus_idx == p->bus_idx && - _p->addr == p->addr && _p->length == p->length && + if (_p->addr == p->addr && _p->length == p->length && (_p->wildcard || p->wildcard || _p->datamatch == p->datamatch)) return true; @@ -679,24 +677,15 @@ ioeventfd_check_collision(struct kvm *kvm, struct _ioeventfd *p) return false; } -static enum kvm_bus ioeventfd_bus_from_flags(__u32 flags) -{ - if (flags & KVM_IOEVENTFD_FLAG_PIO) - return KVM_PIO_BUS; - if (flags & KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY) - return KVM_VIRTIO_CCW_NOTIFY_BUS; - return KVM_MMIO_BUS; -} - static int kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) { - enum kvm_bus bus_idx; + int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; + enum kvm_bus bus_idx = pio ? KVM_PIO_BUS : KVM_MMIO_BUS; struct _ioeventfd *p; struct eventfd_ctx *eventfd; int ret; - bus_idx = ioeventfd_bus_from_flags(args->flags); /* must be natural-word sized */ switch (args->len) { case 1: @@ -728,7 +717,6 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) INIT_LIST_HEAD(&p->list); p->addr = args->addr; - p->bus_idx = bus_idx; p->length = args->len; p->eventfd = eventfd; @@ -772,12 +760,12 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) static int kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) { - enum kvm_bus bus_idx; + int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; + enum kvm_bus bus_idx = pio ? KVM_PIO_BUS : KVM_MMIO_BUS; struct _ioeventfd *p, *tmp; struct eventfd_ctx *eventfd; int ret = -ENOENT; - bus_idx = ioeventfd_bus_from_flags(args->flags); eventfd = eventfd_ctx_fdget(args->fd); if (IS_ERR(eventfd)) return PTR_ERR(eventfd); @@ -787,8 +775,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) list_for_each_entry_safe(p, tmp, &kvm->ioeventfds, list) { bool wildcard = !(args->flags & KVM_IOEVENTFD_FLAG_DATAMATCH); - if (p->bus_idx != bus_idx || - p->eventfd != eventfd || + if (p->eventfd != eventfd || p->addr != args->addr || p->length != args->len || p->wildcard != wildcard) diff --git a/trunk/virt/kvm/ioapic.c b/trunk/virt/kvm/ioapic.c index 2d682977ce82..5ba005c00e2f 100644 --- a/trunk/virt/kvm/ioapic.c +++ b/trunk/virt/kvm/ioapic.c @@ -50,8 +50,7 @@ #else #define ioapic_debug(fmt, arg...) #endif -static int ioapic_deliver(struct kvm_ioapic *vioapic, int irq, - bool line_status); +static int ioapic_deliver(struct kvm_ioapic *vioapic, int irq); static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, unsigned long addr, @@ -91,80 +90,7 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, return result; } -static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic) -{ - ioapic->rtc_status.pending_eoi = 0; - bitmap_zero(ioapic->rtc_status.dest_map, KVM_MAX_VCPUS); -} - -static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu) -{ - bool new_val, old_val; - struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic; - union kvm_ioapic_redirect_entry *e; - - e = &ioapic->redirtbl[RTC_GSI]; - if (!kvm_apic_match_dest(vcpu, NULL, 0, e->fields.dest_id, - e->fields.dest_mode)) - return; - - new_val = kvm_apic_pending_eoi(vcpu, e->fields.vector); - old_val = test_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map); - - if (new_val == old_val) - return; - - if (new_val) { - __set_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map); - ioapic->rtc_status.pending_eoi++; - } else { - __clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map); - ioapic->rtc_status.pending_eoi--; - } - - WARN_ON(ioapic->rtc_status.pending_eoi < 0); -} - -void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu) -{ - struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic; - - spin_lock(&ioapic->lock); - __rtc_irq_eoi_tracking_restore_one(vcpu); - spin_unlock(&ioapic->lock); -} - -static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic) -{ - struct kvm_vcpu *vcpu; - int i; - - if (RTC_GSI >= IOAPIC_NUM_PINS) - return; - - rtc_irq_eoi_tracking_reset(ioapic); - kvm_for_each_vcpu(i, vcpu, ioapic->kvm) - __rtc_irq_eoi_tracking_restore_one(vcpu); -} - -static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu) -{ - if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map)) - --ioapic->rtc_status.pending_eoi; - - WARN_ON(ioapic->rtc_status.pending_eoi < 0); -} - -static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic) -{ - if (ioapic->rtc_status.pending_eoi > 0) - return true; /* coalesced */ - - return false; -} - -static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx, - bool line_status) +static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) { union kvm_ioapic_redirect_entry *pent; int injected = -1; @@ -172,7 +98,7 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx, pent = &ioapic->redirtbl[idx]; if (!pent->fields.mask) { - injected = ioapic_deliver(ioapic, idx, line_status); + injected = ioapic_deliver(ioapic, idx); if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) pent->fields.remote_irr = 1; } @@ -193,48 +119,41 @@ static void update_handled_vectors(struct kvm_ioapic *ioapic) smp_wmb(); } -void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap, - u32 *tmr) +void kvm_ioapic_calculate_eoi_exitmap(struct kvm_vcpu *vcpu, + u64 *eoi_exit_bitmap) { struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic; union kvm_ioapic_redirect_entry *e; + struct kvm_lapic_irq irqe; int index; spin_lock(&ioapic->lock); + /* traverse ioapic entry to set eoi exit bitmap*/ for (index = 0; index < IOAPIC_NUM_PINS; index++) { e = &ioapic->redirtbl[index]; if (!e->fields.mask && (e->fields.trig_mode == IOAPIC_LEVEL_TRIG || kvm_irq_has_notifier(ioapic->kvm, KVM_IRQCHIP_IOAPIC, - index) || index == RTC_GSI)) { - if (kvm_apic_match_dest(vcpu, NULL, 0, - e->fields.dest_id, e->fields.dest_mode)) { - __set_bit(e->fields.vector, - (unsigned long *)eoi_exit_bitmap); - if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG) - __set_bit(e->fields.vector, - (unsigned long *)tmr); - } + index))) { + irqe.dest_id = e->fields.dest_id; + irqe.vector = e->fields.vector; + irqe.dest_mode = e->fields.dest_mode; + irqe.delivery_mode = e->fields.delivery_mode << 8; + kvm_calculate_eoi_exitmap(vcpu, &irqe, eoi_exit_bitmap); } } spin_unlock(&ioapic->lock); } +EXPORT_SYMBOL_GPL(kvm_ioapic_calculate_eoi_exitmap); -#ifdef CONFIG_X86 -void kvm_vcpu_request_scan_ioapic(struct kvm *kvm) +void kvm_ioapic_make_eoibitmap_request(struct kvm *kvm) { struct kvm_ioapic *ioapic = kvm->arch.vioapic; - if (!ioapic) + if (!kvm_apic_vid_enabled(kvm) || !ioapic) return; - kvm_make_scan_ioapic_request(kvm); + kvm_make_update_eoibitmap_request(kvm); } -#else -void kvm_vcpu_request_scan_ioapic(struct kvm *kvm) -{ - return; -} -#endif static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) { @@ -276,17 +195,16 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after); if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG && ioapic->irr & (1 << index)) - ioapic_service(ioapic, index, false); - kvm_vcpu_request_scan_ioapic(ioapic->kvm); + ioapic_service(ioapic, index); + kvm_ioapic_make_eoibitmap_request(ioapic->kvm); break; } } -static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status) +static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) { union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq]; struct kvm_lapic_irq irqe; - int ret; ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " "vector=%x trig_mode=%x\n", @@ -302,19 +220,11 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status) irqe.level = 1; irqe.shorthand = 0; - if (irq == RTC_GSI && line_status) { - BUG_ON(ioapic->rtc_status.pending_eoi != 0); - ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, - ioapic->rtc_status.dest_map); - ioapic->rtc_status.pending_eoi = ret; - } else - ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL); - - return ret; + return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe); } int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, - int level, bool line_status) + int level) { u32 old_irr; u32 mask = 1 << irq; @@ -334,20 +244,13 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, ret = 1; } else { int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); - - if (irq == RTC_GSI && line_status && - rtc_irq_check_coalesced(ioapic)) { - ret = 0; /* coalesced */ - goto out; - } ioapic->irr |= mask; if ((edge && old_irr != ioapic->irr) || (!edge && !entry.fields.remote_irr)) - ret = ioapic_service(ioapic, irq, line_status); + ret = ioapic_service(ioapic, irq); else ret = 0; /* report coalesced interrupt */ } -out: trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0); spin_unlock(&ioapic->lock); @@ -364,8 +267,8 @@ void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id) spin_unlock(&ioapic->lock); } -static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, - struct kvm_ioapic *ioapic, int vector, int trigger_mode) +static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector, + int trigger_mode) { int i; @@ -375,8 +278,6 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, if (ent->fields.vector != vector) continue; - if (i == RTC_GSI) - rtc_irq_eoi(ioapic, vcpu); /* * We are dropping lock while calling ack notifiers because ack * notifier callbacks for assigned devices call into IOAPIC @@ -395,7 +296,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); ent->fields.remote_irr = 0; if (!ent->fields.mask && (ioapic->irr & (1 << i))) - ioapic_service(ioapic, i, false); + ioapic_service(ioapic, i); } } @@ -406,12 +307,12 @@ bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector) return test_bit(vector, ioapic->handled_vectors); } -void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode) +void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode) { - struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic; + struct kvm_ioapic *ioapic = kvm->arch.vioapic; spin_lock(&ioapic->lock); - __kvm_ioapic_update_eoi(vcpu, ioapic, vector, trigger_mode); + __kvm_ioapic_update_eoi(ioapic, vector, trigger_mode); spin_unlock(&ioapic->lock); } @@ -509,7 +410,7 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, break; #ifdef CONFIG_IA64 case IOAPIC_REG_EOI: - __kvm_ioapic_update_eoi(NULL, ioapic, data, IOAPIC_LEVEL_TRIG); + __kvm_ioapic_update_eoi(ioapic, data, IOAPIC_LEVEL_TRIG); break; #endif @@ -530,7 +431,6 @@ void kvm_ioapic_reset(struct kvm_ioapic *ioapic) ioapic->ioregsel = 0; ioapic->irr = 0; ioapic->id = 0; - rtc_irq_eoi_tracking_reset(ioapic); update_handled_vectors(ioapic); } @@ -596,8 +496,7 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state) spin_lock(&ioapic->lock); memcpy(ioapic, state, sizeof(struct kvm_ioapic_state)); update_handled_vectors(ioapic); - kvm_vcpu_request_scan_ioapic(kvm); - kvm_rtc_eoi_tracking_restore_all(ioapic); + kvm_ioapic_make_eoibitmap_request(kvm); spin_unlock(&ioapic->lock); return 0; } diff --git a/trunk/virt/kvm/ioapic.h b/trunk/virt/kvm/ioapic.h index 615d8c995c3c..0400a466c50c 100644 --- a/trunk/virt/kvm/ioapic.h +++ b/trunk/virt/kvm/ioapic.h @@ -34,17 +34,6 @@ struct kvm_vcpu; #define IOAPIC_INIT 0x5 #define IOAPIC_EXTINT 0x7 -#ifdef CONFIG_X86 -#define RTC_GSI 8 -#else -#define RTC_GSI -1U -#endif - -struct rtc_status { - int pending_eoi; - DECLARE_BITMAP(dest_map, KVM_MAX_VCPUS); -}; - struct kvm_ioapic { u64 base_address; u32 ioregsel; @@ -58,7 +47,6 @@ struct kvm_ioapic { void (*ack_notifier)(void *opaque, int irq); spinlock_t lock; DECLARE_BITMAP(handled_vectors, 256); - struct rtc_status rtc_status; }; #ifdef DEBUG @@ -79,25 +67,24 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm) return kvm->arch.vioapic; } -void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu); int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, int short_hand, int dest, int dest_mode); int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2); -void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, - int trigger_mode); +void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode); bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector); int kvm_ioapic_init(struct kvm *kvm); void kvm_ioapic_destroy(struct kvm *kvm); int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, - int level, bool line_status); + int level); void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id); void kvm_ioapic_reset(struct kvm_ioapic *ioapic); int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, - struct kvm_lapic_irq *irq, unsigned long *dest_map); + struct kvm_lapic_irq *irq); int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); -void kvm_vcpu_request_scan_ioapic(struct kvm *kvm); -void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap, - u32 *tmr); +void kvm_ioapic_make_eoibitmap_request(struct kvm *kvm); +void kvm_ioapic_calculate_eoi_exitmap(struct kvm_vcpu *vcpu, + u64 *eoi_exit_bitmap); + #endif diff --git a/trunk/virt/kvm/irq_comm.c b/trunk/virt/kvm/irq_comm.c index e2e6b4473a96..e9073cf4d040 100644 --- a/trunk/virt/kvm/irq_comm.c +++ b/trunk/virt/kvm/irq_comm.c @@ -35,8 +35,7 @@ #include "ioapic.h" static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level, - bool line_status) + struct kvm *kvm, int irq_source_id, int level) { #ifdef CONFIG_X86 struct kvm_pic *pic = pic_irqchip(kvm); @@ -47,12 +46,10 @@ static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, } static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level, - bool line_status) + struct kvm *kvm, int irq_source_id, int level) { struct kvm_ioapic *ioapic = kvm->arch.vioapic; - return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, irq_source_id, level, - line_status); + return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, irq_source_id, level); } inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) @@ -66,7 +63,7 @@ inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) } int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, - struct kvm_lapic_irq *irq, unsigned long *dest_map) + struct kvm_lapic_irq *irq) { int i, r = -1; struct kvm_vcpu *vcpu, *lowest = NULL; @@ -77,7 +74,7 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, irq->delivery_mode = APIC_DM_FIXED; } - if (kvm_irq_delivery_to_apic_fast(kvm, src, irq, &r, dest_map)) + if (kvm_irq_delivery_to_apic_fast(kvm, src, irq, &r)) return r; kvm_for_each_vcpu(i, vcpu, kvm) { @@ -91,7 +88,7 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, if (!kvm_is_dm_lowest_prio(irq)) { if (r < 0) r = 0; - r += kvm_apic_set_irq(vcpu, irq, dest_map); + r += kvm_apic_set_irq(vcpu, irq); } else if (kvm_lapic_enabled(vcpu)) { if (!lowest) lowest = vcpu; @@ -101,7 +98,7 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, } if (lowest) - r = kvm_apic_set_irq(lowest, irq, dest_map); + r = kvm_apic_set_irq(lowest, irq); return r; } @@ -124,7 +121,7 @@ static inline void kvm_set_msi_irq(struct kvm_kernel_irq_routing_entry *e, } int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level, bool line_status) + struct kvm *kvm, int irq_source_id, int level) { struct kvm_lapic_irq irq; @@ -133,7 +130,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, kvm_set_msi_irq(e, &irq); - return kvm_irq_delivery_to_apic(kvm, NULL, &irq, NULL); + return kvm_irq_delivery_to_apic(kvm, NULL, &irq); } @@ -145,12 +142,63 @@ static int kvm_set_msi_inatomic(struct kvm_kernel_irq_routing_entry *e, kvm_set_msi_irq(e, &irq); - if (kvm_irq_delivery_to_apic_fast(kvm, NULL, &irq, &r, NULL)) + if (kvm_irq_delivery_to_apic_fast(kvm, NULL, &irq, &r)) return r; else return -EWOULDBLOCK; } +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) +{ + struct kvm_kernel_irq_routing_entry route; + + if (!irqchip_in_kernel(kvm) || msi->flags != 0) + return -EINVAL; + + route.msi.address_lo = msi->address_lo; + route.msi.address_hi = msi->address_hi; + route.msi.data = msi->data; + + return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1); +} + +/* + * Return value: + * < 0 Interrupt was ignored (masked or not delivered for other reasons) + * = 0 Interrupt was coalesced (previous irq is still pending) + * > 0 Number of CPUs interrupt was delivered to + */ +int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level) +{ + struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS]; + int ret = -1, i = 0; + struct kvm_irq_routing_table *irq_rt; + + trace_kvm_set_irq(irq, level, irq_source_id); + + /* Not possible to detect if the guest uses the PIC or the + * IOAPIC. So set the bit in both. The guest will ignore + * writes to the unused one. + */ + rcu_read_lock(); + irq_rt = rcu_dereference(kvm->irq_routing); + if (irq < irq_rt->nr_rt_entries) + hlist_for_each_entry(e, &irq_rt->map[irq], link) + irq_set[i++] = *e; + rcu_read_unlock(); + + while(i--) { + int r; + r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level); + if (r < 0) + continue; + + ret = r + ((ret < 0) ? 0 : ret); + } + + return ret; +} + /* * Deliver an IRQ in an atomic context if we can, or return a failure, * user can retry in a process context. @@ -188,6 +236,63 @@ int kvm_set_irq_inatomic(struct kvm *kvm, int irq_source_id, u32 irq, int level) return ret; } +bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) +{ + struct kvm_irq_ack_notifier *kian; + int gsi; + + rcu_read_lock(); + gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; + if (gsi != -1) + hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, + link) + if (kian->gsi == gsi) { + rcu_read_unlock(); + return true; + } + + rcu_read_unlock(); + + return false; +} +EXPORT_SYMBOL_GPL(kvm_irq_has_notifier); + +void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) +{ + struct kvm_irq_ack_notifier *kian; + int gsi; + + trace_kvm_ack_irq(irqchip, pin); + + rcu_read_lock(); + gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; + if (gsi != -1) + hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, + link) + if (kian->gsi == gsi) + kian->irq_acked(kian); + rcu_read_unlock(); +} + +void kvm_register_irq_ack_notifier(struct kvm *kvm, + struct kvm_irq_ack_notifier *kian) +{ + mutex_lock(&kvm->irq_lock); + hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list); + mutex_unlock(&kvm->irq_lock); + kvm_ioapic_make_eoibitmap_request(kvm); +} + +void kvm_unregister_irq_ack_notifier(struct kvm *kvm, + struct kvm_irq_ack_notifier *kian) +{ + mutex_lock(&kvm->irq_lock); + hlist_del_init_rcu(&kian->link); + mutex_unlock(&kvm->irq_lock); + synchronize_rcu(); + kvm_ioapic_make_eoibitmap_request(kvm); +} + int kvm_request_irq_source_id(struct kvm *kvm) { unsigned long *bitmap = &kvm->arch.irq_sources_bitmap; @@ -271,14 +376,34 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin, rcu_read_unlock(); } -int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, - struct kvm_kernel_irq_routing_entry *e, - const struct kvm_irq_routing_entry *ue) +void kvm_free_irq_routing(struct kvm *kvm) +{ + /* Called only during vm destruction. Nobody can use the pointer + at this stage */ + kfree(kvm->irq_routing); +} + +static int setup_routing_entry(struct kvm_irq_routing_table *rt, + struct kvm_kernel_irq_routing_entry *e, + const struct kvm_irq_routing_entry *ue) { int r = -EINVAL; int delta; unsigned max_pin; + struct kvm_kernel_irq_routing_entry *ei; + /* + * Do not allow GSI to be mapped to the same irqchip more than once. + * Allow only one to one mapping between GSI and MSI. + */ + hlist_for_each_entry(ei, &rt->map[ue->gsi], link) + if (ei->type == KVM_IRQ_ROUTING_MSI || + ue->type == KVM_IRQ_ROUTING_MSI || + ue->u.irqchip.irqchip == ei->irqchip.irqchip) + return r; + + e->gsi = ue->gsi; + e->type = ue->type; switch (ue->type) { case KVM_IRQ_ROUTING_IRQCHIP: delta = 0; @@ -315,11 +440,69 @@ int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, goto out; } + hlist_add_head(&e->link, &rt->map[e->gsi]); r = 0; out: return r; } + +int kvm_set_irq_routing(struct kvm *kvm, + const struct kvm_irq_routing_entry *ue, + unsigned nr, + unsigned flags) +{ + struct kvm_irq_routing_table *new, *old; + u32 i, j, nr_rt_entries = 0; + int r; + + for (i = 0; i < nr; ++i) { + if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES) + return -EINVAL; + nr_rt_entries = max(nr_rt_entries, ue[i].gsi); + } + + nr_rt_entries += 1; + + new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head)) + + (nr * sizeof(struct kvm_kernel_irq_routing_entry)), + GFP_KERNEL); + + if (!new) + return -ENOMEM; + + new->rt_entries = (void *)&new->map[nr_rt_entries]; + + new->nr_rt_entries = nr_rt_entries; + for (i = 0; i < 3; i++) + for (j = 0; j < KVM_IOAPIC_NUM_PINS; j++) + new->chip[i][j] = -1; + + for (i = 0; i < nr; ++i) { + r = -EINVAL; + if (ue->flags) + goto out; + r = setup_routing_entry(new, &new->rt_entries[i], ue); + if (r) + goto out; + ++ue; + } + + mutex_lock(&kvm->irq_lock); + old = kvm->irq_routing; + kvm_irq_routing_update(kvm, new); + mutex_unlock(&kvm->irq_lock); + + synchronize_rcu(); + + new = old; + r = 0; + +out: + kfree(new); + return r; +} + #define IOAPIC_ROUTING_ENTRY(irq) \ { .gsi = irq, .type = KVM_IRQ_ROUTING_IRQCHIP, \ .u.irqchip.irqchip = KVM_IRQCHIP_IOAPIC, .u.irqchip.pin = (irq) } diff --git a/trunk/virt/kvm/irqchip.c b/trunk/virt/kvm/irqchip.c deleted file mode 100644 index 20dc9e4a8f6c..000000000000 --- a/trunk/virt/kvm/irqchip.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * irqchip.c: Common API for in kernel interrupt controllers - * Copyright (c) 2007, Intel Corporation. - * Copyright 2010 Red Hat, Inc. and/or its affiliates. - * Copyright (c) 2013, Alexander Graf - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - * - * This file is derived from virt/kvm/irq_comm.c. - * - * Authors: - * Yaozu (Eddie) Dong - * Alexander Graf - */ - -#include -#include -#include -#include -#include "irq.h" - -bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) -{ - struct kvm_irq_ack_notifier *kian; - int gsi; - - rcu_read_lock(); - gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; - if (gsi != -1) - hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, - link) - if (kian->gsi == gsi) { - rcu_read_unlock(); - return true; - } - - rcu_read_unlock(); - - return false; -} -EXPORT_SYMBOL_GPL(kvm_irq_has_notifier); - -void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) -{ - struct kvm_irq_ack_notifier *kian; - int gsi; - - trace_kvm_ack_irq(irqchip, pin); - - rcu_read_lock(); - gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; - if (gsi != -1) - hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, - link) - if (kian->gsi == gsi) - kian->irq_acked(kian); - rcu_read_unlock(); -} - -void kvm_register_irq_ack_notifier(struct kvm *kvm, - struct kvm_irq_ack_notifier *kian) -{ - mutex_lock(&kvm->irq_lock); - hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list); - mutex_unlock(&kvm->irq_lock); -#ifdef __KVM_HAVE_IOAPIC - kvm_vcpu_request_scan_ioapic(kvm); -#endif -} - -void kvm_unregister_irq_ack_notifier(struct kvm *kvm, - struct kvm_irq_ack_notifier *kian) -{ - mutex_lock(&kvm->irq_lock); - hlist_del_init_rcu(&kian->link); - mutex_unlock(&kvm->irq_lock); - synchronize_rcu(); -#ifdef __KVM_HAVE_IOAPIC - kvm_vcpu_request_scan_ioapic(kvm); -#endif -} - -int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) -{ - struct kvm_kernel_irq_routing_entry route; - - if (!irqchip_in_kernel(kvm) || msi->flags != 0) - return -EINVAL; - - route.msi.address_lo = msi->address_lo; - route.msi.address_hi = msi->address_hi; - route.msi.data = msi->data; - - return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, false); -} - -/* - * Return value: - * < 0 Interrupt was ignored (masked or not delivered for other reasons) - * = 0 Interrupt was coalesced (previous irq is still pending) - * > 0 Number of CPUs interrupt was delivered to - */ -int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, - bool line_status) -{ - struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS]; - int ret = -1, i = 0; - struct kvm_irq_routing_table *irq_rt; - - trace_kvm_set_irq(irq, level, irq_source_id); - - /* Not possible to detect if the guest uses the PIC or the - * IOAPIC. So set the bit in both. The guest will ignore - * writes to the unused one. - */ - rcu_read_lock(); - irq_rt = rcu_dereference(kvm->irq_routing); - if (irq < irq_rt->nr_rt_entries) - hlist_for_each_entry(e, &irq_rt->map[irq], link) - irq_set[i++] = *e; - rcu_read_unlock(); - - while(i--) { - int r; - r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level, - line_status); - if (r < 0) - continue; - - ret = r + ((ret < 0) ? 0 : ret); - } - - return ret; -} - -void kvm_free_irq_routing(struct kvm *kvm) -{ - /* Called only during vm destruction. Nobody can use the pointer - at this stage */ - kfree(kvm->irq_routing); -} - -static int setup_routing_entry(struct kvm_irq_routing_table *rt, - struct kvm_kernel_irq_routing_entry *e, - const struct kvm_irq_routing_entry *ue) -{ - int r = -EINVAL; - struct kvm_kernel_irq_routing_entry *ei; - - /* - * Do not allow GSI to be mapped to the same irqchip more than once. - * Allow only one to one mapping between GSI and MSI. - */ - hlist_for_each_entry(ei, &rt->map[ue->gsi], link) - if (ei->type == KVM_IRQ_ROUTING_MSI || - ue->type == KVM_IRQ_ROUTING_MSI || - ue->u.irqchip.irqchip == ei->irqchip.irqchip) - return r; - - e->gsi = ue->gsi; - e->type = ue->type; - r = kvm_set_routing_entry(rt, e, ue); - if (r) - goto out; - - hlist_add_head(&e->link, &rt->map[e->gsi]); - r = 0; -out: - return r; -} - -int kvm_set_irq_routing(struct kvm *kvm, - const struct kvm_irq_routing_entry *ue, - unsigned nr, - unsigned flags) -{ - struct kvm_irq_routing_table *new, *old; - u32 i, j, nr_rt_entries = 0; - int r; - - for (i = 0; i < nr; ++i) { - if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES) - return -EINVAL; - nr_rt_entries = max(nr_rt_entries, ue[i].gsi); - } - - nr_rt_entries += 1; - - new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head)) - + (nr * sizeof(struct kvm_kernel_irq_routing_entry)), - GFP_KERNEL); - - if (!new) - return -ENOMEM; - - new->rt_entries = (void *)&new->map[nr_rt_entries]; - - new->nr_rt_entries = nr_rt_entries; - for (i = 0; i < KVM_NR_IRQCHIPS; i++) - for (j = 0; j < KVM_IRQCHIP_NUM_PINS; j++) - new->chip[i][j] = -1; - - for (i = 0; i < nr; ++i) { - r = -EINVAL; - if (ue->flags) - goto out; - r = setup_routing_entry(new, &new->rt_entries[i], ue); - if (r) - goto out; - ++ue; - } - - mutex_lock(&kvm->irq_lock); - old = kvm->irq_routing; - kvm_irq_routing_update(kvm, new); - mutex_unlock(&kvm->irq_lock); - - synchronize_rcu(); - - new = old; - r = 0; - -out: - kfree(new); - return r; -} diff --git a/trunk/virt/kvm/kvm_main.c b/trunk/virt/kvm/kvm_main.c index 45f09362ee7b..f18013f09e68 100644 --- a/trunk/virt/kvm/kvm_main.c +++ b/trunk/virt/kvm/kvm_main.c @@ -217,9 +217,9 @@ void kvm_make_mclock_inprogress_request(struct kvm *kvm) make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS); } -void kvm_make_scan_ioapic_request(struct kvm *kvm) +void kvm_make_update_eoibitmap_request(struct kvm *kvm) { - make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC); + make_all_cpus_request(kvm, KVM_REQ_EOIBITMAP); } int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) @@ -244,7 +244,6 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) kvm_vcpu_set_in_spin_loop(vcpu, false); kvm_vcpu_set_dy_eligible(vcpu, false); - vcpu->preempted = false; r = kvm_arch_vcpu_init(vcpu); if (r < 0) @@ -504,7 +503,6 @@ static struct kvm *kvm_create_vm(unsigned long type) mutex_init(&kvm->irq_lock); mutex_init(&kvm->slots_lock); atomic_set(&kvm->users_count, 1); - INIT_LIST_HEAD(&kvm->devices); r = kvm_init_mmu_notifier(kvm); if (r) @@ -582,19 +580,6 @@ void kvm_free_physmem(struct kvm *kvm) kfree(kvm->memslots); } -static void kvm_destroy_devices(struct kvm *kvm) -{ - struct list_head *node, *tmp; - - list_for_each_safe(node, tmp, &kvm->devices) { - struct kvm_device *dev = - list_entry(node, struct kvm_device, vm_node); - - list_del(node); - dev->ops->destroy(dev); - } -} - static void kvm_destroy_vm(struct kvm *kvm) { int i; @@ -614,7 +599,6 @@ static void kvm_destroy_vm(struct kvm *kvm) kvm_arch_flush_shadow_all(kvm); #endif kvm_arch_destroy_vm(kvm); - kvm_destroy_devices(kvm); kvm_free_physmem(kvm); cleanup_srcu_struct(&kvm->srcu); kvm_arch_free_vm(kvm); @@ -734,6 +718,24 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm, return old_memslots; } +/* + * KVM_SET_USER_MEMORY_REGION ioctl allows the following operations: + * - create a new memory slot + * - delete an existing memory slot + * - modify an existing memory slot + * -- move it in the guest physical memory space + * -- just change its flags + * + * Since flags can be changed by some of these operations, the following + * differentiation is the best we can do for __kvm_set_memory_region(): + */ +enum kvm_mr_change { + KVM_MR_CREATE, + KVM_MR_DELETE, + KVM_MR_MOVE, + KVM_MR_FLAGS_ONLY, +}; + /* * Allocate some memory and give it an address in the guest physical address * space. @@ -743,7 +745,8 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm, * Must be called holding mmap_sem for write. */ int __kvm_set_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) + struct kvm_userspace_memory_region *mem, + bool user_alloc) { int r; gfn_t base_gfn; @@ -764,7 +767,7 @@ int __kvm_set_memory_region(struct kvm *kvm, if (mem->guest_phys_addr & (PAGE_SIZE - 1)) goto out; /* We can read the guest memory with __xxx_user() later on. */ - if ((mem->slot < KVM_USER_MEM_SLOTS) && + if (user_alloc && ((mem->userspace_addr & (PAGE_SIZE - 1)) || !access_ok(VERIFY_WRITE, (void __user *)(unsigned long)mem->userspace_addr, @@ -872,7 +875,7 @@ int __kvm_set_memory_region(struct kvm *kvm, slots = old_memslots; } - r = kvm_arch_prepare_memory_region(kvm, &new, mem, change); + r = kvm_arch_prepare_memory_region(kvm, &new, old, mem, user_alloc); if (r) goto out_slots; @@ -912,7 +915,7 @@ int __kvm_set_memory_region(struct kvm *kvm, old_memslots = install_new_memslots(kvm, slots, &new); - kvm_arch_commit_memory_region(kvm, mem, &old, change); + kvm_arch_commit_memory_region(kvm, mem, old, user_alloc); kvm_free_physmem_slot(&old, &new); kfree(old_memslots); @@ -929,23 +932,26 @@ int __kvm_set_memory_region(struct kvm *kvm, EXPORT_SYMBOL_GPL(__kvm_set_memory_region); int kvm_set_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) + struct kvm_userspace_memory_region *mem, + bool user_alloc) { int r; mutex_lock(&kvm->slots_lock); - r = __kvm_set_memory_region(kvm, mem); + r = __kvm_set_memory_region(kvm, mem, user_alloc); mutex_unlock(&kvm->slots_lock); return r; } EXPORT_SYMBOL_GPL(kvm_set_memory_region); int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem) + struct + kvm_userspace_memory_region *mem, + bool user_alloc) { if (mem->slot >= KVM_USER_MEM_SLOTS) return -EINVAL; - return kvm_set_memory_region(kvm, mem); + return kvm_set_memory_region(kvm, mem, user_alloc); } int kvm_get_dirty_log(struct kvm *kvm, @@ -1093,7 +1099,7 @@ static int kvm_read_hva_atomic(void *data, void __user *hva, int len) return __copy_from_user_inatomic(data, hva, len); } -static int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm, +int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int write, struct page **page) { int flags = FOLL_TOUCH | FOLL_NOWAIT | FOLL_HWPOISON | FOLL_GET; @@ -1713,7 +1719,6 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu) smp_send_reschedule(cpu); put_cpu(); } -EXPORT_SYMBOL_GPL(kvm_vcpu_kick); #endif /* !CONFIG_S390 */ void kvm_resched(struct kvm_vcpu *vcpu) @@ -1811,8 +1816,6 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) continue; } else if (pass && i > last_boosted_vcpu) break; - if (!ACCESS_ONCE(vcpu->preempted)) - continue; if (vcpu == me) continue; if (waitqueue_active(&vcpu->wq)) @@ -2201,119 +2204,6 @@ static long kvm_vcpu_compat_ioctl(struct file *filp, } #endif -static int kvm_device_ioctl_attr(struct kvm_device *dev, - int (*accessor)(struct kvm_device *dev, - struct kvm_device_attr *attr), - unsigned long arg) -{ - struct kvm_device_attr attr; - - if (!accessor) - return -EPERM; - - if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) - return -EFAULT; - - return accessor(dev, &attr); -} - -static long kvm_device_ioctl(struct file *filp, unsigned int ioctl, - unsigned long arg) -{ - struct kvm_device *dev = filp->private_data; - - switch (ioctl) { - case KVM_SET_DEVICE_ATTR: - return kvm_device_ioctl_attr(dev, dev->ops->set_attr, arg); - case KVM_GET_DEVICE_ATTR: - return kvm_device_ioctl_attr(dev, dev->ops->get_attr, arg); - case KVM_HAS_DEVICE_ATTR: - return kvm_device_ioctl_attr(dev, dev->ops->has_attr, arg); - default: - if (dev->ops->ioctl) - return dev->ops->ioctl(dev, ioctl, arg); - - return -ENOTTY; - } -} - -static int kvm_device_release(struct inode *inode, struct file *filp) -{ - struct kvm_device *dev = filp->private_data; - struct kvm *kvm = dev->kvm; - - kvm_put_kvm(kvm); - return 0; -} - -static const struct file_operations kvm_device_fops = { - .unlocked_ioctl = kvm_device_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = kvm_device_ioctl, -#endif - .release = kvm_device_release, -}; - -struct kvm_device *kvm_device_from_filp(struct file *filp) -{ - if (filp->f_op != &kvm_device_fops) - return NULL; - - return filp->private_data; -} - -static int kvm_ioctl_create_device(struct kvm *kvm, - struct kvm_create_device *cd) -{ - struct kvm_device_ops *ops = NULL; - struct kvm_device *dev; - bool test = cd->flags & KVM_CREATE_DEVICE_TEST; - int ret; - - switch (cd->type) { -#ifdef CONFIG_KVM_MPIC - case KVM_DEV_TYPE_FSL_MPIC_20: - case KVM_DEV_TYPE_FSL_MPIC_42: - ops = &kvm_mpic_ops; - break; -#endif -#ifdef CONFIG_KVM_XICS - case KVM_DEV_TYPE_XICS: - ops = &kvm_xics_ops; - break; -#endif - default: - return -ENODEV; - } - - if (test) - return 0; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dev->ops = ops; - dev->kvm = kvm; - - ret = ops->create(dev, cd->type); - if (ret < 0) { - kfree(dev); - return ret; - } - - ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR); - if (ret < 0) { - ops->destroy(dev); - return ret; - } - - list_add(&dev->vm_node, &kvm->devices); - kvm_get_kvm(kvm); - cd->fd = ret; - return 0; -} - static long kvm_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2335,7 +2225,7 @@ static long kvm_vm_ioctl(struct file *filp, sizeof kvm_userspace_mem)) goto out; - r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem); + r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, true); break; } case KVM_GET_DIRTY_LOG: { @@ -2414,8 +2304,7 @@ static long kvm_vm_ioctl(struct file *filp, if (copy_from_user(&irq_event, argp, sizeof irq_event)) goto out; - r = kvm_vm_ioctl_irq_line(kvm, &irq_event, - ioctl == KVM_IRQ_LINE_STATUS); + r = kvm_vm_ioctl_irq_line(kvm, &irq_event); if (r) goto out; @@ -2429,54 +2318,6 @@ static long kvm_vm_ioctl(struct file *filp, break; } #endif -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING - case KVM_SET_GSI_ROUTING: { - struct kvm_irq_routing routing; - struct kvm_irq_routing __user *urouting; - struct kvm_irq_routing_entry *entries; - - r = -EFAULT; - if (copy_from_user(&routing, argp, sizeof(routing))) - goto out; - r = -EINVAL; - if (routing.nr >= KVM_MAX_IRQ_ROUTES) - goto out; - if (routing.flags) - goto out; - r = -ENOMEM; - entries = vmalloc(routing.nr * sizeof(*entries)); - if (!entries) - goto out; - r = -EFAULT; - urouting = argp; - if (copy_from_user(entries, urouting->entries, - routing.nr * sizeof(*entries))) - goto out_free_irq_routing; - r = kvm_set_irq_routing(kvm, entries, routing.nr, - routing.flags); - out_free_irq_routing: - vfree(entries); - break; - } -#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */ - case KVM_CREATE_DEVICE: { - struct kvm_create_device cd; - - r = -EFAULT; - if (copy_from_user(&cd, argp, sizeof(cd))) - goto out; - - r = kvm_ioctl_create_device(kvm, &cd); - if (r) - goto out; - - r = -EFAULT; - if (copy_to_user(argp, &cd, sizeof(cd))) - goto out; - - r = 0; - break; - } default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); if (r == -ENOTTY) @@ -2605,12 +2446,9 @@ static long kvm_dev_ioctl_check_extension_generic(long arg) case KVM_CAP_INTERNAL_ERROR_DATA: #ifdef CONFIG_HAVE_KVM_MSI case KVM_CAP_SIGNAL_MSI: -#endif -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING - case KVM_CAP_IRQFD_RESAMPLE: #endif return 1; -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef KVM_CAP_IRQ_ROUTING case KVM_CAP_IRQ_ROUTING: return KVM_MAX_IRQ_ROUTES; #endif @@ -2780,6 +2618,14 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, return NOTIFY_OK; } + +asmlinkage void kvm_spurious_fault(void) +{ + /* Fault while not rebooting. We want the trace. */ + BUG(); +} +EXPORT_SYMBOL_GPL(kvm_spurious_fault); + static int kvm_reboot(struct notifier_block *notifier, unsigned long val, void *v) { @@ -2812,7 +2658,7 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus) kfree(bus); } -static int kvm_io_bus_sort_cmp(const void *p1, const void *p2) +int kvm_io_bus_sort_cmp(const void *p1, const void *p2) { const struct kvm_io_range *r1 = p1; const struct kvm_io_range *r2 = p2; @@ -2824,7 +2670,7 @@ static int kvm_io_bus_sort_cmp(const void *p1, const void *p2) return 0; } -static int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev, +int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev, gpa_t addr, int len) { bus->range[bus->dev_count++] = (struct kvm_io_range) { @@ -2839,7 +2685,7 @@ static int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *d return 0; } -static int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus, +int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus, gpa_t addr, int len) { struct kvm_io_range *range, key; @@ -3083,8 +2929,6 @@ struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn) static void kvm_sched_in(struct preempt_notifier *pn, int cpu) { struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); - if (vcpu->preempted) - vcpu->preempted = false; kvm_arch_vcpu_load(vcpu, cpu); } @@ -3094,8 +2938,6 @@ static void kvm_sched_out(struct preempt_notifier *pn, { struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); - if (current->state == TASK_RUNNING) - vcpu->preempted = true; kvm_arch_vcpu_put(vcpu); } @@ -3105,9 +2947,6 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, int r; int cpu; - r = kvm_irqfd_init(); - if (r) - goto out_irqfd; r = kvm_arch_init(opaque); if (r) goto out_fail; @@ -3188,8 +3027,6 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, out_free_0: kvm_arch_exit(); out_fail: - kvm_irqfd_exit(); -out_irqfd: return r; } EXPORT_SYMBOL_GPL(kvm_init); @@ -3206,7 +3043,6 @@ void kvm_exit(void) on_each_cpu(hardware_disable_nolock, NULL, 1); kvm_arch_hardware_unsetup(); kvm_arch_exit(); - kvm_irqfd_exit(); free_cpumask_var(cpus_hardware_enabled); } EXPORT_SYMBOL_GPL(kvm_exit);