* Improper TTBCR for arm 32bit kernel decompression
From: Srinivas Ramana @ 2016-09-10 8:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.20.1609091334120.14769@knanqh.ubzr>
On 09/09/2016 11:06 PM, Nicolas Pitre wrote:
> On Fri, 9 Sep 2016, Srinivas Ramana wrote:
>
>> Hello,
>>
>> While trying to boot arm-32 bit kernel, I came across a problem where TTBCR is
>> in improper state. If the bootloader uses the long descriptor format and jumps
>> to kernel decompressor code, TTBCR may not be in the right state. So, as soon
>> as the MMU is enabled, execution can not proceed further.
>>
>> Before enabling the MMU, it is required to clear the TTBCR.PD0 field to use
>> TTBR0 for translation table walks. Also, TTBCR.N should be reset to '0' to
>> indicate the correct base address width. The 'commit dbece45894d3a ("ARM:
>> 7501/1: decompressor: reset ttbcr for VMSA ARMv7 cores")' does the reset of
>> TTBCR.N, but doesn't consider all the bits for the size of TTBCR.N.
>>
>> when i tried the below change where i explicitly clear TTBCR.PD0 and use
>> correct mask for TTBCR.N, I see proper memory after MMU is enabled and
>> decompression succeeds.
>>
>> Request your comments on the change below. If it looks good, I can submit a
>> patch for inclusion.
>>
>> ---------------------8<----------------------------------
>> diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
>> index af11c2f..5769f1f 100644
>> --- a/arch/arm/boot/compressed/head.S
>> +++ b/arch/arm/boot/compressed/head.S
>> @@ -779,7 +779,8 @@ __armv7_mmu_cache_on:
>> orrne r0, r0, #1 @ MMU enabled
>> movne r1, #0xfffffffd @ domain 0 = client
>> bic r6, r6, #1 << 31 @ 32-bit translation system
>> - bic r6, r6, #3 << 0 @ use only ttbr0
>> + bic r6, r6, #7 << 0 @ width of base address field
>> + bic r6, r6, #1 << 4 @ use only ttbr0
>
> You could combine those instructions like this:
>
> bic r6, r6, #(7 << 0) | (1 << 4) @ use only ttbr0
Sure, I can do that. Thanks for the suggestion. Will send out a patch
for review.
Thanks,
-- Srinivas R
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center,
Inc., is a member of Code Aurora Forum, a Linux Foundation Collaborative
Project.
^ permalink raw reply
* [PATCH v2 0/7] arm64: Privileged Access Never using TTBR0_EL1 switching
From: Catalin Marinas @ 2016-09-10 9:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1472828533-28197-1-git-send-email-catalin.marinas@arm.com>
On Fri, Sep 02, 2016 at 04:02:06PM +0100, Catalin Marinas wrote:
> This is the second version of the arm64 PAN emulation by disabling
> TTBR0_EL1 accesses. The major change from v1 is the use of a thread_info
> member to store the real TTBR0_EL1 value. The advantage is slightly
> simpler assembler macros for uaccess_enable with the downside that
> switch_mm() must always update the saved ttbr0 even if there is no mm
> switch.
FYI, I got the Juno board rebooting in a loop with defconfig +
ARM64_TTBR0_PAN enabled. It takes about 20-40 reboots to get the panic
below on the EFI run-time services. I'll look into it on Monday (and
cc'ing Ard who I forgot to add originally). Including the full log
below:
EFI stub: Booting Linux Kernel...
EFI stub: Using DTB from configuration table
EFI stub: Exiting boot services and installing virtual address map...
[ 0.000000] Booting Linux on physical CPU 0x100
[ 0.000000] Linux version 4.8.0-rc4-00007-g07a1ca6cb00d (cmarinas at e104818-lin) (gcc version 5.3.1 20160309 (fsf-5.264) ) #1 SMP PREEMPT Fri Sep 9 18:38:47 BST 2016
[ 0.000000] Boot CPU: AArch64 Processor [410fd030]
[ 0.000000] earlycon: pl11 at MMIO 0x000000007ff80000 (options '')
[ 0.000000] bootconsole [pl11] enabled
[ 0.000000] efi: Getting EFI parameters from FDT:
[ 0.000000] efi: EFI v2.40 by ARM Juno EFI Oct 7 2014 15:05:42
[ 0.000000] efi: ACPI=0xfebdc000 ACPI 2.0=0xfebdc014
[ 0.000000] cma: Reserved 16 MiB at 0x00000000fd800000
[ 0.000000] psci: probing for conduit method from DT.
[ 0.000000] psci: PSCIv0.2 detected in firmware.
[ 0.000000] psci: Using standard PSCI v0.2 function IDs
[ 0.000000] psci: Trusted OS migration not required
[ 0.000000] percpu: Embedded 21 pages/cpu @ffff80097fea6000 s47488 r8192 d30336 u86016
[ 0.000000] Detected VIPT I-cache on CPU0
[ 0.000000] CPU features: enabling workaround for ARM errata 826319, 827319, 824069
[ 0.000000] CPU features: enabling workaround for ARM erratum 845719
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 2060048
[ 0.000000] Kernel command line: console=ttyAMA0,115200 earlycon=pl011,0x7ff80000 ip=dhcp root=/dev/nfs rw nfsroot=10.1.206.48:/srv/nfs/debian-arm64,tcp
[ 0.000000] log_buf_len individual max cpu contribution: 4096 bytes
[ 0.000000] log_buf_len total cpu_extra contributions: 20480 bytes
[ 0.000000] log_buf_len min size: 16384 bytes
[ 0.000000] log_buf_len: 65536 bytes
[ 0.000000] early log buf free: 14320(87%)
[ 0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
[ 0.000000] Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes)
[ 0.000000] Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes)
[ 0.000000] software IO TLB [mem 0xf9800000-0xfd800000] (64MB) mapped at [ffff800079800000-ffff80007d7fffff]
[ 0.000000] Memory: 8129516K/8371264K available (8636K kernel code, 796K rwdata, 3532K rodata, 960K init, 275K bss, 225364K reserved, 16384K cma-reserved)
[ 0.000000] Virtual kernel memory layout:
[ 0.000000] modules : 0xffff000000000000 - 0xffff000008000000 ( 128 MB)
[ 0.000000] vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000 (129022 GB)
[ 0.000000] .text : 0xffff000008080000 - 0xffff0000088f0000 ( 8640 KB)
[ 0.000000] .rodata : 0xffff0000088f0000 - 0xffff000008c70000 ( 3584 KB)
[ 0.000000] .init : 0xffff000008c70000 - 0xffff000008d60000 ( 960 KB)
[ 0.000000] .data : 0xffff000008d60000 - 0xffff000008e27200 ( 797 KB)
[ 0.000000] .bss : 0xffff000008e27200 - 0xffff000008e6c138 ( 276 KB)
[ 0.000000] fixed : 0xffff7dfffe7fd000 - 0xffff7dfffec00000 ( 4108 KB)
[ 0.000000] PCI I/O : 0xffff7dfffee00000 - 0xffff7dffffe00000 ( 16 MB)
[ 0.000000] vmemmap : 0xffff7e0000000000 - 0xffff800000000000 ( 2048 GB maximum)
[ 0.000000] 0xffff7e0000000000 - 0xffff7e0026000000 ( 608 MB actual)
[ 0.000000] memory : 0xffff800000000000 - 0xffff800980000000 ( 38912 MB)
[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=6, Nodes=1
[ 0.000000] Preemptible hierarchical RCU implementation.
[ 0.000000] Build-time adjustment of leaf fanout to 64.
[ 0.000000] RCU restricting CPUs from NR_CPUS=64 to nr_cpu_ids=6.
[ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=64, nr_cpu_ids=6
[ 0.000000] NR_IRQS:64 nr_irqs:64 0
[ 0.000000] GIC: Using split EOI/Deactivate mode
[ 0.000000] GICv2m: range[mem 0x2c1c0000-0x2c1c0fff], SPI[224:255]
[ 0.000000] arm_arch_timer: Architected cp15 timer(s) running at 50.00MHz (phys).
[ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0xb8812736b, max_idle_ns: 440795202655 ns
[ 0.000005] sched_clock: 56 bits at 50MHz, resolution 20ns, wraps every 4398046511100ns
[ 0.008439] clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275 ns
[ 0.018257] Failed to initialize '/smb/motherboard/iofpga at 3,00000000/timer at 120000': -22
[ 0.026339] Console: colour dummy device 80x25
[ 0.031047] Calibrating delay loop (skipped), value calculated using timer frequency.. 100.00 BogoMIPS (lpj=200000)
[ 0.041642] pid_max: default: 32768 minimum: 301
[ 0.046406] Security Framework initialized
[ 0.050607] Mount-cache hash table entries: 16384 (order: 5, 131072 bytes)
[ 0.057587] Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes)
[ 0.066233] ASID allocator initialised with 65536 entries
[ 0.096367] Remapping and enabling EFI services.
[ 0.101091] EFI remap 0x0000000008000000 => 0000000020000000
[ 0.107016] EFI remap 0x000000001c170000 => 0000000024000000
[ 0.112941] EFI remap 0x00000009faf6f000 => 000000002401f000
[ 0.118865] EFI remap 0x00000009fff6e000 => 000000002406e000
[ 0.124789] EFI remap 0x00000009fffaf000 => 00000000240af000
[ 0.155087] Detected PIPT I-cache on CPU1
[ 0.155092] CPU features: enabling workaround for ARM erratum 832075
[ 0.155094] CPU features: enabling workaround for ARM erratum 834220
[ 0.155129] CPU1: Booted secondary processor [410fd070]
[ 0.171085] Detected PIPT I-cache on CPU2
[ 0.171110] CPU2: Booted secondary processor [410fd070]
[ 0.187086] Detected VIPT I-cache on CPU3
[ 0.187127] CPU3: Booted secondary processor [410fd030]
[ 0.203127] Detected VIPT I-cache on CPU4
[ 0.203157] CPU4: Booted secondary processor [410fd030]
[ 0.219170] Detected VIPT I-cache on CPU5
[ 0.219200] CPU5: Booted secondary processor [410fd030]
[ 0.219264] Brought up 6 CPUs
[ 0.281960] SMP: Total of 6 processors activated.
[ 0.286735] CPU features: detected feature: 32-bit EL0 Support
[ 0.292670] CPU: All CPU(s) started at EL2
[ 0.296856] alternatives: patching kernel code
[ 0.307334] devtmpfs: initialized
[ 0.314498] DMI not present or invalid.
[ 0.318621] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[ 0.329272] pinctrl core: initialized pinctrl subsystem
[ 0.335640] NET: Registered protocol family 16
[ 0.364205] cpuidle: using governor menu
[ 0.368387] vdso: 2 pages (1 code @ ffff0000088f6000, 1 data @ ffff000008d64000)
[ 0.375906] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
[ 0.383492] DMA: preallocated 256 KiB pool for atomic allocations
[ 0.389926] Serial: AMBA PL011 UART driver
[ 0.396607] 7ff80000.uart: ttyAMA0 at MMIO 0x7ff80000 (irq = 24, base_baud = 0) is a PL011 rev3
[ 0.405455] console [ttyAMA0] enabled
[ 0.405455] console [ttyAMA0] enabled
[ 0.412747] bootconsole [pl11] disabled
[ 0.412747] bootconsole [pl11] disabled
[ 0.448879] HugeTLB registered 2 MB page size, pre-allocated 0 pages
[ 0.456038] ACPI: Interpreter disabled.
[ 0.460736] vgaarb: loaded
[ 0.463676] SCSI subsystem initialized
[ 0.467861] usbcore: registered new interface driver usbfs
[ 0.473364] usbcore: registered new interface driver hub
[ 0.478725] usbcore: registered new device driver usb
[ 0.484678] pps_core: LinuxPPS API ver. 1 registered
[ 0.489606] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 0.498694] PTP clock support registered
[ 0.502752] dmi: Firmware registration failed.
[ 0.507965] Advanced Linux Sound Architecture Driver Initialized.
[ 0.514808] clocksource: Switched to clocksource arch_sys_counter
[ 0.520983] VFS: Disk quotas dquot_6.6.0
[ 0.524930] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[ 0.531982] pnp: PnP ACPI: disabled
[ 0.543951] NET: Registered protocol family 2
[ 0.548779] TCP established hash table entries: 65536 (order: 7, 524288 bytes)
[ 0.556814] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes)
[ 0.565070] TCP: Hash tables configured (established 65536 bind 65536)
[ 0.571619] UDP hash table entries: 4096 (order: 5, 131072 bytes)
[ 0.577902] UDP-Lite hash table entries: 4096 (order: 5, 131072 bytes)
[ 0.584771] NET: Registered protocol family 1
[ 0.589467] RPC: Registered named UNIX socket transport module.
[ 0.595355] RPC: Registered udp transport module.
[ 0.600021] RPC: Registered tcp transport module.
[ 0.604685] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 0.611740] hw perfevents: enabled with armv8_cortex_a57 PMU driver, 7 counters available
[ 0.619970] hw perfevents: enabled with armv8_cortex_a53 PMU driver, 7 counters available
[ 0.628262] kvm [1]: IDMAP page: 808d8000
[ 0.632250] kvm [1]: HYP VA range: 800000000000:ffffffffffff
[ 0.638698] kvm [1]: 8-bit VMID
[ 0.641816] kvm [1]: Hyp mode initialized successfully
[ 0.646947] kvm [1]: vgic-v2 at 2c04f000
[ 0.650721] kvm [1]: vgic interrupt IRQ1
[ 0.654720] kvm [1]: virtual timer IRQ4
[ 0.661194] futex hash table entries: 2048 (order: 6, 262144 bytes)
[ 0.667506] audit: initializing netlink subsys (disabled)
[ 0.672915] audit: type=2000 audit(0.536:1): initialized
[ 0.678965] workingset: timestamp_bits=46 max_order=21 bucket_order=0
[ 0.696868] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[ 0.703578] NFS: Registering the id_resolver key type
[ 0.708612] Key type id_resolver registered
[ 0.712766] Key type id_legacy registered
[ 0.716752] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[ 0.723546] SGI XFS with security attributes, no debug enabled
[ 0.730934] 9p: Installing v9fs 9p2000 file system support
[ 0.738565] io scheduler noop registered
[ 0.742480] io scheduler cfq registered (default)
[ 0.747923] libphy: mdio_driver_register: phy-bcm-ns2-pci
[ 0.754326] pl061_gpio 1c1d0000.gpio: PL061 GPIO chip @0x000000001c1d0000 registered
[ 0.763984] dma-pl330 7ff00000.dma: Loaded driver for PL330 DMAC-341330
[ 0.770560] dma-pl330 7ff00000.dma: DBUFF-1024x16bytes Num_Chans-8 Num_Peri-8 Num_Events-8
[ 0.779809] xenfs: not registering filesystem on non-xen platform
[ 0.788999] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[ 0.796505] SuperH (H)SCI(F) driver initialized
[ 0.801247] msm_serial: driver initialized
[ 0.811254] loop: module loaded
[ 0.815840] libphy: Fixed MDIO Bus: probed
[ 0.820328] tun: Universal TUN/TAP device driver, 1.6
[ 0.825338] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
[ 0.831905] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
[ 0.837692] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
[ 0.843605] igb: Intel(R) Gigabit Ethernet Network Driver - version 5.3.0-k
[ 0.850507] igb: Copyright (c) 2007-2014 Intel Corporation.
[ 0.856072] igbvf: Intel(R) Gigabit Virtual Function Network Driver - version 2.0.2-k
[ 0.863833] igbvf: Copyright (c) 2009 - 2012 Intel Corporation.
[ 0.869799] sky2: driver version 1.30
[ 0.895685] libphy: smsc911x-mdio: probed
[ 0.970934] Generic PHY 18000000.etherne:01: attached PHY driver [Generic PHY] (mii_bus:phy_addr=18000000.etherne:01, irq=-1)
[ 0.982316] smsc911x 18000000.ethernet eth0: MAC Address: 00:02:f7:00:58:bb
[ 0.989404] VFIO - User Level meta-driver version: 0.3
[ 0.995517] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[ 1.001993] ehci-pci: EHCI PCI platform driver
[ 1.006432] ehci-platform: EHCI generic platform driver
[ 1.011718] ehci-platform 7ffc0000.ehci: EHCI Host Controller
[ 1.017428] ehci-platform 7ffc0000.ehci: new USB bus registered, assigned bus number 1
[ 1.025419] ehci-platform 7ffc0000.ehci: irq 27, io mem 0x7ffc0000
[ 1.046826] ehci-platform 7ffc0000.ehci: USB 2.0 started, EHCI 1.00
[ 1.053541] hub 1-0:1.0: USB hub found
[ 1.057279] hub 1-0:1.0: 1 port detected
[ 1.061448] ehci-exynos: EHCI EXYNOS driver
[ 1.065666] ehci-msm: Qualcomm On-Chip EHCI Host Controller
[ 1.071254] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[ 1.077401] ohci-pci: OHCI PCI platform driver
[ 1.081845] ohci-platform: OHCI generic platform driver
[ 1.087113] ohci-platform 7ffb0000.ohci: Generic Platform OHCI controller
[ 1.093855] ohci-platform 7ffb0000.ohci: new USB bus registered, assigned bus number 2
[ 1.101791] ohci-platform 7ffb0000.ohci: irq 26, io mem 0x7ffb0000
[ 1.187263] hub 2-0:1.0: USB hub found
[ 1.191003] hub 2-0:1.0: 1 port detected
[ 1.195133] ohci-exynos: OHCI EXYNOS driver
[ 1.199619] usbcore: registered new interface driver usb-storage
[ 1.206575] mousedev: PS/2 mouse device common for all mice
[ 1.212778] rtc-efi rtc-efi: rtc core: registered rtc-efi as rtc0
[ 1.219087] rtc-pl031 1c170000.rtc: rtc core: registered pl031 as rtc1
[ 1.225912] i2c /dev entries driver
[ 1.231598] mmci-pl18x 1c050000.mmci: mmc0: PL180 manf 41 rev0 at 0x1c050000 irq 32,0 (pio)
[ 1.239880] mmci-pl18x 1c050000.mmci: DMA channels RX none, TX none
[ 1.283106] sdhci: Secure Digital Host Controller Interface driver
[ 1.289269] sdhci: Copyright(c) Pierre Ossman
[ 1.293646] Synopsys Designware Multimedia Card Interface Driver
[ 1.300985] sdhci-pltfm: SDHCI platform and OF driver helper
[ 1.309245] leds-syscon 1c010000.apbregs:led at 08.0: registered LED vexpress:0
[ 1.316358] leds-syscon 1c010000.apbregs:led at 08.1: registered LED vexpress:1
[ 1.323550] leds-syscon 1c010000.apbregs:led at 08.2: registered LED vexpress:2
[ 1.330953] leds-syscon 1c010000.apbregs:led at 08.3: registered LED vexpress:3
[ 1.338043] leds-syscon 1c010000.apbregs:led at 08.4: registered LED vexpress:4
[ 1.345139] leds-syscon 1c010000.apbregs:led at 08.5: registered LED vexpress:5
[ 1.352224] leds-syscon 1c010000.apbregs:led at 08.6: registered LED vexpress:6
[ 1.359553] leds-syscon 1c010000.apbregs:led at 08.7: registered LED vexpress:7
[ 1.368522] ledtrig-cpu: registered to indicate activity on CPUs
[ 1.375694] usbcore: registered new interface driver usbhid
[ 1.381223] usbhid: USB HID core driver
[ 1.385921] mhu 2b1f0000.mhu: ARM MHU Mailbox registered
[ 1.392777] NET: Registered protocol family 17
[ 1.394826] usb 1-1: new high-speed USB device number 2 using ehci-platform
[ 1.404224] 9pnet: Installing 9P2000 support
[ 1.408545] Key type dns_resolver registered
[ 1.413706] registered taskstats version 1
[ 1.455390] scpi_protocol scpi: incorrect or no SCP firmware found
[ 1.461595] scpi_protocol: probe of scpi failed with error -110
[ 1.468487] input: smb:motherboard:gpio_keys as /devices/platform/smb/smb:motherboard/smb:motherboard:gpio_keys/input/input1
[ 1.480518] Unable to handle kernel paging request at virtual address 240ab2f8
[ 1.487693] pgd = ffff000008e70000
[ 1.491084] [240ab2f8] *pgd=00000009fff6d003, *pud=00000009fff6c003, *pmd=0000000000000000
[ 1.499336] Internal error: Oops: 86000004 [#1] PREEMPT SMP
[ 1.504849] Modules linked in:
[ 1.507877] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-rc4-00007-g07a1ca6cb00d #1
[ 1.515711] Hardware name: ARM Juno development board (r0) (DT)
[ 1.521569] task: ffff8009768a8000 task.stack: ffff8009768b0000
[ 1.527427] PC is at 0x240ab2f8
[ 1.530531] LR is at 0x240aaac0
[ 1.533637] pc : [<00000000240ab2f8>] lr : [<00000000240aaac0>] pstate: 60400145
[ 1.540954] sp : ffff8009768b3c50
[ 1.544230] x29: ffff8009768b3ca0 x28: 0000000000000000
[ 1.549492] x27: ffff000008d279c0 x26: ffff000008c70470
[ 1.554754] x25: ffff000008cbf230 x24: ffff000008c5fd70
[ 1.560016] x23: ffff000008e2c000 x22: ffff8009768b3cf0
[ 1.565278] x21: ffff8009768b3cf0 x20: ffff8009768b3d00
[ 1.570540] x19: 8000000000000003 x18: ffffffffffffffff
[ 1.575801] x17: 0000000000000000 x16: 0000000000000000
[ 1.581063] x15: ffff80097612f16b x14: 0000000000000000
[ 1.586323] x13: 0000000000000000 x12: 0000000000000038
[ 1.591584] x11: 0000000000000020 x10: 0101010101010101
[ 1.596846] x9 : 0000000000000000 x8 : ffffff7f7f7f7f7f
[ 1.602107] x7 : fefe7eff2f627371 x6 : 000000008080ffff
[ 1.607368] x5 : ffff8009768b3c98 x4 : 0000000000010001
[ 1.612629] x3 : 00000000ff000001 x2 : 00000000240aa3e4
[ 1.617890] x1 : ffff8009768b3c98 x0 : 0000000057d752e6
[ 1.623150]
[ 1.624622] Process swapper/0 (pid: 1, stack limit = 0xffff8009768b0028)
[ 1.631253] Stack: (0xffff8009768b3c50 to 0xffff8009768b4000)
[ 1.636941] 3c40: ffff000008e5dcd8 ffff8009768b3d00
[ 1.644694] 3c60: 0000000000000140 ffff8009768b3cf0 ffff000008e2c000 ffff000008c5fd70
[ 1.652447] 3c80: ffff00000876236c ffff8009768b3d00 ffff8009768b3da8 ffff00000855d1b4
[ 1.660201] 3ca0: ffff8009768b3cd0 ffff000008703de8 ffff8009768b3da8 ffff000008dd9ff0
[ 1.667954] 3cc0: ffff8009768b3da8 0000000000000007 ffff8009768b3d10 ffff000008700964
[ 1.675707] 3ce0: ffff8009768b3da8 ffff800976a752e8 ffff8009768b3d40 ffff0000087006a8
[ 1.683461] 3d00: ffff000008bbe958 ffff000008ca081c ffff8009768b3d30 ffff0000087009c8
[ 1.691214] 3d20: ffff800976a75000 ffff0000087006b8 ffff8009768b3d70 ffff000008ca0878
[ 1.698974] 3d40: ffff000008bbe958 ffff800976a75000 0000000000000000 0000000000000000
[ 1.706727] 3d60: ffff000008dd94b0 ffff0000083f4820 ffff8009768b3dd0 ffff000008083b40
[ 1.714480] 3d80: ffff8009768b0000 ffff000008ca081c ffff8009768b3db0 0000000000000000
[ 1.722232] 3da0: 000000001dcd6500 0000000000000000 0000000000000000 0000000000000000
[ 1.729984] 3dc0: 0000000000000000 ffff000000000000 ffff8009768b3e40 ffff000008c70d14
[ 1.737737] 3de0: 0000000000000110 ffff000008e2c000 ffff000008cbf2c0 0000000000000007
[ 1.745490] 3e00: ffff000008d27900 0000000000000000 ffff000008e2c000 ffff000008b48ac8
[ 1.753242] 3e20: 0000000700000007 0000000000000000 0000000000000000 ffff000008c5fd70
[ 1.760995] 3e40: ffff8009768b3ea0 ffff0000088d15d0 ffff0000088d15c0 0000000000000000
[ 1.768747] 3e60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.776499] 3e80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.784252] 3ea0: 0000000000000000 ffff0000080830a0 ffff0000088d15c0 0000000000000000
[ 1.792004] 3ec0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.799756] 3ee0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.807508] 3f00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.815260] 3f20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.823023] 3f40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.830775] 3f60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.838527] 3f80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.846279] 3fa0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[ 1.854031] 3fc0: 0000000000000000 0000000000000005 0000000000000000 0000000000000000
[ 1.861783] 3fe0: 0000000000000000 0000000000000000 035b4d0700426040 000f000200440000
[ 1.869531] Call trace:
[ 1.871950] Exception stack(0xffff8009768b3a80 to 0xffff8009768b3bb0)
[ 1.878327] 3a80: 8000000000000003 0001000000000000 0000000080e2b000 00000000240ab2f8
[ 1.886080] 3aa0: ffff8009768b3b00 ffff00000818bb68 ffff800976015f80 00000000024000c0
[ 1.893832] 3ac0: ffff00000818bbe4 000000000000001a ffff80097608dc10 ffff800976bd1218
[ 1.901585] 3ae0: ffff8009768b3af0 ffff0000083f2670 ffff8009768b3b70 ffff0000083f2b40
[ 1.909338] 3b00: 0000000000000000 ffff800976811b00 0000000000000000 ffff800976811a90
[ 1.917091] 3b20: 0000000057d752e6 ffff8009768b3c98 00000000240aa3e4 00000000ff000001
[ 1.924844] 3b40: 0000000000010001 ffff8009768b3c98 000000008080ffff fefe7eff2f627371
[ 1.932596] 3b60: ffffff7f7f7f7f7f 0000000000000000 0101010101010101 0000000000000020
[ 1.940349] 3b80: 0000000000000038 0000000000000000 0000000000000000 ffff80097612f16b
[ 1.948098] 3ba0: 0000000000000000 0000000000000000
[ 1.952925] [<00000000240ab2f8>] 0x240ab2f8
[ 1.957069] [<ffff000008703de8>] efi_read_time+0x28/0x78
[ 1.962329] [<ffff000008700964>] __rtc_read_time.isra.1+0x44/0x70
[ 1.968360] [<ffff0000087009c8>] rtc_read_time+0x38/0x58
[ 1.973620] [<ffff000008ca0878>] rtc_hctosys+0x5c/0xe4
[ 1.978708] [<ffff000008083b40>] do_one_initcall+0x38/0x128
[ 1.984227] [<ffff000008c70d14>] kernel_init_freeable+0x1ac/0x250
[ 1.990261] [<ffff0000088d15d0>] kernel_init+0x10/0x100
[ 1.995433] [<ffff0000080830a0>] ret_from_fork+0x10/0x30
[ 2.000691] Code: bad PC value
--
Catalin
^ permalink raw reply
* [PATCH 1/2] perf_event: remove unused DEBUG_PERF_USE_VMALLOC
From: Michael Ellerman @ 2016-09-10 10:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160830140834.6d1edf7abd9d95c02dae7820@arm.com>
Kim Phillips <kim.phillips@arm.com> writes:
> This 'DEBUG'-prefixed version of PERF_USE_VMALLOC is not used anywhere.
> It appears to be leftovers from commit 906010b "perf_event: Provide
> vmalloc() based mmap() backing" that introduced it.
>
> Not sure what commit cb30711 "perf_event: Don't allow vmalloc() backed
> perf on powerpc" was trying to do with it either.
Preventing its use on powerpc, because it doesn't work, I thought the
change log was pretty clear:
perf_event: Don't allow vmalloc() backed perf on powerpc
On powerpc the perf event interrupt is not masked when interrupts are
disabled, allowing it to function as an NMI.
This causes problems if perf is using vmalloc. If we take a page fault
on the vmalloc region the fault handler will fail the page fault because
it detects we are coming in from an NMI (see do_hash_page()).
We don't actually need or want vmalloc backed perf so just disable it on
powerpc.
If there are ARM cpus that don't want it enabled then you should
probably do a similar patch for ARM.
cheers
^ permalink raw reply
* [PATCH v2 0/7] arm64: Privileged Access Never using TTBR0_EL1 switching
From: Ard Biesheuvel @ 2016-09-10 10:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160910095154.GA21444@e104818-lin.cambridge.arm.com>
On 10 September 2016 at 10:51, Catalin Marinas <catalin.marinas@arm.com> wrote:
> On Fri, Sep 02, 2016 at 04:02:06PM +0100, Catalin Marinas wrote:
>> This is the second version of the arm64 PAN emulation by disabling
>> TTBR0_EL1 accesses. The major change from v1 is the use of a thread_info
>> member to store the real TTBR0_EL1 value. The advantage is slightly
>> simpler assembler macros for uaccess_enable with the downside that
>> switch_mm() must always update the saved ttbr0 even if there is no mm
>> switch.
>
> FYI, I got the Juno board rebooting in a loop with defconfig +
> ARM64_TTBR0_PAN enabled. It takes about 20-40 reboots to get the panic
> below on the EFI run-time services. I'll look into it on Monday (and
> cc'ing Ard who I forgot to add originally). Including the full log
> below:
>
Hi David,
Could you please try to reproduce it again, but this time with
'efi=debug' on the kernel command line? Thanks
--
Ard.
> EFI stub: Booting Linux Kernel...
> EFI stub: Using DTB from configuration table
> EFI stub: Exiting boot services and installing virtual address map...
> [ 0.000000] Booting Linux on physical CPU 0x100
> [ 0.000000] Linux version 4.8.0-rc4-00007-g07a1ca6cb00d (cmarinas at e104818-lin) (gcc version 5.3.1 20160309 (fsf-5.264) ) #1 SMP PREEMPT Fri Sep 9 18:38:47 BST 2016
> [ 0.000000] Boot CPU: AArch64 Processor [410fd030]
> [ 0.000000] earlycon: pl11 at MMIO 0x000000007ff80000 (options '')
> [ 0.000000] bootconsole [pl11] enabled
> [ 0.000000] efi: Getting EFI parameters from FDT:
> [ 0.000000] efi: EFI v2.40 by ARM Juno EFI Oct 7 2014 15:05:42
> [ 0.000000] efi: ACPI=0xfebdc000 ACPI 2.0=0xfebdc014
> [ 0.000000] cma: Reserved 16 MiB at 0x00000000fd800000
> [ 0.000000] psci: probing for conduit method from DT.
> [ 0.000000] psci: PSCIv0.2 detected in firmware.
> [ 0.000000] psci: Using standard PSCI v0.2 function IDs
> [ 0.000000] psci: Trusted OS migration not required
> [ 0.000000] percpu: Embedded 21 pages/cpu @ffff80097fea6000 s47488 r8192 d30336 u86016
> [ 0.000000] Detected VIPT I-cache on CPU0
> [ 0.000000] CPU features: enabling workaround for ARM errata 826319, 827319, 824069
> [ 0.000000] CPU features: enabling workaround for ARM erratum 845719
> [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 2060048
> [ 0.000000] Kernel command line: console=ttyAMA0,115200 earlycon=pl011,0x7ff80000 ip=dhcp root=/dev/nfs rw nfsroot=10.1.206.48:/srv/nfs/debian-arm64,tcp
> [ 0.000000] log_buf_len individual max cpu contribution: 4096 bytes
> [ 0.000000] log_buf_len total cpu_extra contributions: 20480 bytes
> [ 0.000000] log_buf_len min size: 16384 bytes
> [ 0.000000] log_buf_len: 65536 bytes
> [ 0.000000] early log buf free: 14320(87%)
> [ 0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
> [ 0.000000] Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes)
> [ 0.000000] Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes)
> [ 0.000000] software IO TLB [mem 0xf9800000-0xfd800000] (64MB) mapped at [ffff800079800000-ffff80007d7fffff]
> [ 0.000000] Memory: 8129516K/8371264K available (8636K kernel code, 796K rwdata, 3532K rodata, 960K init, 275K bss, 225364K reserved, 16384K cma-reserved)
> [ 0.000000] Virtual kernel memory layout:
> [ 0.000000] modules : 0xffff000000000000 - 0xffff000008000000 ( 128 MB)
> [ 0.000000] vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000 (129022 GB)
> [ 0.000000] .text : 0xffff000008080000 - 0xffff0000088f0000 ( 8640 KB)
> [ 0.000000] .rodata : 0xffff0000088f0000 - 0xffff000008c70000 ( 3584 KB)
> [ 0.000000] .init : 0xffff000008c70000 - 0xffff000008d60000 ( 960 KB)
> [ 0.000000] .data : 0xffff000008d60000 - 0xffff000008e27200 ( 797 KB)
> [ 0.000000] .bss : 0xffff000008e27200 - 0xffff000008e6c138 ( 276 KB)
> [ 0.000000] fixed : 0xffff7dfffe7fd000 - 0xffff7dfffec00000 ( 4108 KB)
> [ 0.000000] PCI I/O : 0xffff7dfffee00000 - 0xffff7dffffe00000 ( 16 MB)
> [ 0.000000] vmemmap : 0xffff7e0000000000 - 0xffff800000000000 ( 2048 GB maximum)
> [ 0.000000] 0xffff7e0000000000 - 0xffff7e0026000000 ( 608 MB actual)
> [ 0.000000] memory : 0xffff800000000000 - 0xffff800980000000 ( 38912 MB)
> [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=6, Nodes=1
> [ 0.000000] Preemptible hierarchical RCU implementation.
> [ 0.000000] Build-time adjustment of leaf fanout to 64.
> [ 0.000000] RCU restricting CPUs from NR_CPUS=64 to nr_cpu_ids=6.
> [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=64, nr_cpu_ids=6
> [ 0.000000] NR_IRQS:64 nr_irqs:64 0
> [ 0.000000] GIC: Using split EOI/Deactivate mode
> [ 0.000000] GICv2m: range[mem 0x2c1c0000-0x2c1c0fff], SPI[224:255]
> [ 0.000000] arm_arch_timer: Architected cp15 timer(s) running at 50.00MHz (phys).
> [ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0xb8812736b, max_idle_ns: 440795202655 ns
> [ 0.000005] sched_clock: 56 bits at 50MHz, resolution 20ns, wraps every 4398046511100ns
> [ 0.008439] clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275 ns
> [ 0.018257] Failed to initialize '/smb/motherboard/iofpga at 3,00000000/timer at 120000': -22
> [ 0.026339] Console: colour dummy device 80x25
> [ 0.031047] Calibrating delay loop (skipped), value calculated using timer frequency.. 100.00 BogoMIPS (lpj=200000)
> [ 0.041642] pid_max: default: 32768 minimum: 301
> [ 0.046406] Security Framework initialized
> [ 0.050607] Mount-cache hash table entries: 16384 (order: 5, 131072 bytes)
> [ 0.057587] Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes)
> [ 0.066233] ASID allocator initialised with 65536 entries
> [ 0.096367] Remapping and enabling EFI services.
> [ 0.101091] EFI remap 0x0000000008000000 => 0000000020000000
> [ 0.107016] EFI remap 0x000000001c170000 => 0000000024000000
> [ 0.112941] EFI remap 0x00000009faf6f000 => 000000002401f000
> [ 0.118865] EFI remap 0x00000009fff6e000 => 000000002406e000
> [ 0.124789] EFI remap 0x00000009fffaf000 => 00000000240af000
> [ 0.155087] Detected PIPT I-cache on CPU1
> [ 0.155092] CPU features: enabling workaround for ARM erratum 832075
> [ 0.155094] CPU features: enabling workaround for ARM erratum 834220
> [ 0.155129] CPU1: Booted secondary processor [410fd070]
> [ 0.171085] Detected PIPT I-cache on CPU2
> [ 0.171110] CPU2: Booted secondary processor [410fd070]
> [ 0.187086] Detected VIPT I-cache on CPU3
> [ 0.187127] CPU3: Booted secondary processor [410fd030]
> [ 0.203127] Detected VIPT I-cache on CPU4
> [ 0.203157] CPU4: Booted secondary processor [410fd030]
> [ 0.219170] Detected VIPT I-cache on CPU5
> [ 0.219200] CPU5: Booted secondary processor [410fd030]
> [ 0.219264] Brought up 6 CPUs
> [ 0.281960] SMP: Total of 6 processors activated.
> [ 0.286735] CPU features: detected feature: 32-bit EL0 Support
> [ 0.292670] CPU: All CPU(s) started at EL2
> [ 0.296856] alternatives: patching kernel code
> [ 0.307334] devtmpfs: initialized
> [ 0.314498] DMI not present or invalid.
> [ 0.318621] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
> [ 0.329272] pinctrl core: initialized pinctrl subsystem
> [ 0.335640] NET: Registered protocol family 16
> [ 0.364205] cpuidle: using governor menu
> [ 0.368387] vdso: 2 pages (1 code @ ffff0000088f6000, 1 data @ ffff000008d64000)
> [ 0.375906] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
> [ 0.383492] DMA: preallocated 256 KiB pool for atomic allocations
> [ 0.389926] Serial: AMBA PL011 UART driver
> [ 0.396607] 7ff80000.uart: ttyAMA0 at MMIO 0x7ff80000 (irq = 24, base_baud = 0) is a PL011 rev3
> [ 0.405455] console [ttyAMA0] enabled
> [ 0.405455] console [ttyAMA0] enabled
> [ 0.412747] bootconsole [pl11] disabled
> [ 0.412747] bootconsole [pl11] disabled
> [ 0.448879] HugeTLB registered 2 MB page size, pre-allocated 0 pages
> [ 0.456038] ACPI: Interpreter disabled.
> [ 0.460736] vgaarb: loaded
> [ 0.463676] SCSI subsystem initialized
> [ 0.467861] usbcore: registered new interface driver usbfs
> [ 0.473364] usbcore: registered new interface driver hub
> [ 0.478725] usbcore: registered new device driver usb
> [ 0.484678] pps_core: LinuxPPS API ver. 1 registered
> [ 0.489606] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
> [ 0.498694] PTP clock support registered
> [ 0.502752] dmi: Firmware registration failed.
> [ 0.507965] Advanced Linux Sound Architecture Driver Initialized.
> [ 0.514808] clocksource: Switched to clocksource arch_sys_counter
> [ 0.520983] VFS: Disk quotas dquot_6.6.0
> [ 0.524930] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
> [ 0.531982] pnp: PnP ACPI: disabled
> [ 0.543951] NET: Registered protocol family 2
> [ 0.548779] TCP established hash table entries: 65536 (order: 7, 524288 bytes)
> [ 0.556814] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes)
> [ 0.565070] TCP: Hash tables configured (established 65536 bind 65536)
> [ 0.571619] UDP hash table entries: 4096 (order: 5, 131072 bytes)
> [ 0.577902] UDP-Lite hash table entries: 4096 (order: 5, 131072 bytes)
> [ 0.584771] NET: Registered protocol family 1
> [ 0.589467] RPC: Registered named UNIX socket transport module.
> [ 0.595355] RPC: Registered udp transport module.
> [ 0.600021] RPC: Registered tcp transport module.
> [ 0.604685] RPC: Registered tcp NFSv4.1 backchannel transport module.
> [ 0.611740] hw perfevents: enabled with armv8_cortex_a57 PMU driver, 7 counters available
> [ 0.619970] hw perfevents: enabled with armv8_cortex_a53 PMU driver, 7 counters available
> [ 0.628262] kvm [1]: IDMAP page: 808d8000
> [ 0.632250] kvm [1]: HYP VA range: 800000000000:ffffffffffff
> [ 0.638698] kvm [1]: 8-bit VMID
> [ 0.641816] kvm [1]: Hyp mode initialized successfully
> [ 0.646947] kvm [1]: vgic-v2 at 2c04f000
> [ 0.650721] kvm [1]: vgic interrupt IRQ1
> [ 0.654720] kvm [1]: virtual timer IRQ4
> [ 0.661194] futex hash table entries: 2048 (order: 6, 262144 bytes)
> [ 0.667506] audit: initializing netlink subsys (disabled)
> [ 0.672915] audit: type=2000 audit(0.536:1): initialized
> [ 0.678965] workingset: timestamp_bits=46 max_order=21 bucket_order=0
> [ 0.696868] squashfs: version 4.0 (2009/01/31) Phillip Lougher
> [ 0.703578] NFS: Registering the id_resolver key type
> [ 0.708612] Key type id_resolver registered
> [ 0.712766] Key type id_legacy registered
> [ 0.716752] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
> [ 0.723546] SGI XFS with security attributes, no debug enabled
> [ 0.730934] 9p: Installing v9fs 9p2000 file system support
> [ 0.738565] io scheduler noop registered
> [ 0.742480] io scheduler cfq registered (default)
> [ 0.747923] libphy: mdio_driver_register: phy-bcm-ns2-pci
> [ 0.754326] pl061_gpio 1c1d0000.gpio: PL061 GPIO chip @0x000000001c1d0000 registered
> [ 0.763984] dma-pl330 7ff00000.dma: Loaded driver for PL330 DMAC-341330
> [ 0.770560] dma-pl330 7ff00000.dma: DBUFF-1024x16bytes Num_Chans-8 Num_Peri-8 Num_Events-8
> [ 0.779809] xenfs: not registering filesystem on non-xen platform
> [ 0.788999] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
> [ 0.796505] SuperH (H)SCI(F) driver initialized
> [ 0.801247] msm_serial: driver initialized
> [ 0.811254] loop: module loaded
> [ 0.815840] libphy: Fixed MDIO Bus: probed
> [ 0.820328] tun: Universal TUN/TAP device driver, 1.6
> [ 0.825338] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
> [ 0.831905] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
> [ 0.837692] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
> [ 0.843605] igb: Intel(R) Gigabit Ethernet Network Driver - version 5.3.0-k
> [ 0.850507] igb: Copyright (c) 2007-2014 Intel Corporation.
> [ 0.856072] igbvf: Intel(R) Gigabit Virtual Function Network Driver - version 2.0.2-k
> [ 0.863833] igbvf: Copyright (c) 2009 - 2012 Intel Corporation.
> [ 0.869799] sky2: driver version 1.30
> [ 0.895685] libphy: smsc911x-mdio: probed
> [ 0.970934] Generic PHY 18000000.etherne:01: attached PHY driver [Generic PHY] (mii_bus:phy_addr=18000000.etherne:01, irq=-1)
> [ 0.982316] smsc911x 18000000.ethernet eth0: MAC Address: 00:02:f7:00:58:bb
> [ 0.989404] VFIO - User Level meta-driver version: 0.3
> [ 0.995517] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
> [ 1.001993] ehci-pci: EHCI PCI platform driver
> [ 1.006432] ehci-platform: EHCI generic platform driver
> [ 1.011718] ehci-platform 7ffc0000.ehci: EHCI Host Controller
> [ 1.017428] ehci-platform 7ffc0000.ehci: new USB bus registered, assigned bus number 1
> [ 1.025419] ehci-platform 7ffc0000.ehci: irq 27, io mem 0x7ffc0000
> [ 1.046826] ehci-platform 7ffc0000.ehci: USB 2.0 started, EHCI 1.00
> [ 1.053541] hub 1-0:1.0: USB hub found
> [ 1.057279] hub 1-0:1.0: 1 port detected
> [ 1.061448] ehci-exynos: EHCI EXYNOS driver
> [ 1.065666] ehci-msm: Qualcomm On-Chip EHCI Host Controller
> [ 1.071254] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
> [ 1.077401] ohci-pci: OHCI PCI platform driver
> [ 1.081845] ohci-platform: OHCI generic platform driver
> [ 1.087113] ohci-platform 7ffb0000.ohci: Generic Platform OHCI controller
> [ 1.093855] ohci-platform 7ffb0000.ohci: new USB bus registered, assigned bus number 2
> [ 1.101791] ohci-platform 7ffb0000.ohci: irq 26, io mem 0x7ffb0000
> [ 1.187263] hub 2-0:1.0: USB hub found
> [ 1.191003] hub 2-0:1.0: 1 port detected
> [ 1.195133] ohci-exynos: OHCI EXYNOS driver
> [ 1.199619] usbcore: registered new interface driver usb-storage
> [ 1.206575] mousedev: PS/2 mouse device common for all mice
> [ 1.212778] rtc-efi rtc-efi: rtc core: registered rtc-efi as rtc0
> [ 1.219087] rtc-pl031 1c170000.rtc: rtc core: registered pl031 as rtc1
> [ 1.225912] i2c /dev entries driver
> [ 1.231598] mmci-pl18x 1c050000.mmci: mmc0: PL180 manf 41 rev0 at 0x1c050000 irq 32,0 (pio)
> [ 1.239880] mmci-pl18x 1c050000.mmci: DMA channels RX none, TX none
> [ 1.283106] sdhci: Secure Digital Host Controller Interface driver
> [ 1.289269] sdhci: Copyright(c) Pierre Ossman
> [ 1.293646] Synopsys Designware Multimedia Card Interface Driver
> [ 1.300985] sdhci-pltfm: SDHCI platform and OF driver helper
> [ 1.309245] leds-syscon 1c010000.apbregs:led at 08.0: registered LED vexpress:0
> [ 1.316358] leds-syscon 1c010000.apbregs:led at 08.1: registered LED vexpress:1
> [ 1.323550] leds-syscon 1c010000.apbregs:led at 08.2: registered LED vexpress:2
> [ 1.330953] leds-syscon 1c010000.apbregs:led at 08.3: registered LED vexpress:3
> [ 1.338043] leds-syscon 1c010000.apbregs:led at 08.4: registered LED vexpress:4
> [ 1.345139] leds-syscon 1c010000.apbregs:led at 08.5: registered LED vexpress:5
> [ 1.352224] leds-syscon 1c010000.apbregs:led at 08.6: registered LED vexpress:6
> [ 1.359553] leds-syscon 1c010000.apbregs:led at 08.7: registered LED vexpress:7
> [ 1.368522] ledtrig-cpu: registered to indicate activity on CPUs
> [ 1.375694] usbcore: registered new interface driver usbhid
> [ 1.381223] usbhid: USB HID core driver
> [ 1.385921] mhu 2b1f0000.mhu: ARM MHU Mailbox registered
> [ 1.392777] NET: Registered protocol family 17
> [ 1.394826] usb 1-1: new high-speed USB device number 2 using ehci-platform
> [ 1.404224] 9pnet: Installing 9P2000 support
> [ 1.408545] Key type dns_resolver registered
> [ 1.413706] registered taskstats version 1
> [ 1.455390] scpi_protocol scpi: incorrect or no SCP firmware found
> [ 1.461595] scpi_protocol: probe of scpi failed with error -110
> [ 1.468487] input: smb:motherboard:gpio_keys as /devices/platform/smb/smb:motherboard/smb:motherboard:gpio_keys/input/input1
> [ 1.480518] Unable to handle kernel paging request at virtual address 240ab2f8
> [ 1.487693] pgd = ffff000008e70000
> [ 1.491084] [240ab2f8] *pgd=00000009fff6d003, *pud=00000009fff6c003, *pmd=0000000000000000
> [ 1.499336] Internal error: Oops: 86000004 [#1] PREEMPT SMP
> [ 1.504849] Modules linked in:
> [ 1.507877] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-rc4-00007-g07a1ca6cb00d #1
> [ 1.515711] Hardware name: ARM Juno development board (r0) (DT)
> [ 1.521569] task: ffff8009768a8000 task.stack: ffff8009768b0000
> [ 1.527427] PC is at 0x240ab2f8
> [ 1.530531] LR is at 0x240aaac0
> [ 1.533637] pc : [<00000000240ab2f8>] lr : [<00000000240aaac0>] pstate: 60400145
> [ 1.540954] sp : ffff8009768b3c50
> [ 1.544230] x29: ffff8009768b3ca0 x28: 0000000000000000
> [ 1.549492] x27: ffff000008d279c0 x26: ffff000008c70470
> [ 1.554754] x25: ffff000008cbf230 x24: ffff000008c5fd70
> [ 1.560016] x23: ffff000008e2c000 x22: ffff8009768b3cf0
> [ 1.565278] x21: ffff8009768b3cf0 x20: ffff8009768b3d00
> [ 1.570540] x19: 8000000000000003 x18: ffffffffffffffff
> [ 1.575801] x17: 0000000000000000 x16: 0000000000000000
> [ 1.581063] x15: ffff80097612f16b x14: 0000000000000000
> [ 1.586323] x13: 0000000000000000 x12: 0000000000000038
> [ 1.591584] x11: 0000000000000020 x10: 0101010101010101
> [ 1.596846] x9 : 0000000000000000 x8 : ffffff7f7f7f7f7f
> [ 1.602107] x7 : fefe7eff2f627371 x6 : 000000008080ffff
> [ 1.607368] x5 : ffff8009768b3c98 x4 : 0000000000010001
> [ 1.612629] x3 : 00000000ff000001 x2 : 00000000240aa3e4
> [ 1.617890] x1 : ffff8009768b3c98 x0 : 0000000057d752e6
> [ 1.623150]
> [ 1.624622] Process swapper/0 (pid: 1, stack limit = 0xffff8009768b0028)
> [ 1.631253] Stack: (0xffff8009768b3c50 to 0xffff8009768b4000)
> [ 1.636941] 3c40: ffff000008e5dcd8 ffff8009768b3d00
> [ 1.644694] 3c60: 0000000000000140 ffff8009768b3cf0 ffff000008e2c000 ffff000008c5fd70
> [ 1.652447] 3c80: ffff00000876236c ffff8009768b3d00 ffff8009768b3da8 ffff00000855d1b4
> [ 1.660201] 3ca0: ffff8009768b3cd0 ffff000008703de8 ffff8009768b3da8 ffff000008dd9ff0
> [ 1.667954] 3cc0: ffff8009768b3da8 0000000000000007 ffff8009768b3d10 ffff000008700964
> [ 1.675707] 3ce0: ffff8009768b3da8 ffff800976a752e8 ffff8009768b3d40 ffff0000087006a8
> [ 1.683461] 3d00: ffff000008bbe958 ffff000008ca081c ffff8009768b3d30 ffff0000087009c8
> [ 1.691214] 3d20: ffff800976a75000 ffff0000087006b8 ffff8009768b3d70 ffff000008ca0878
> [ 1.698974] 3d40: ffff000008bbe958 ffff800976a75000 0000000000000000 0000000000000000
> [ 1.706727] 3d60: ffff000008dd94b0 ffff0000083f4820 ffff8009768b3dd0 ffff000008083b40
> [ 1.714480] 3d80: ffff8009768b0000 ffff000008ca081c ffff8009768b3db0 0000000000000000
> [ 1.722232] 3da0: 000000001dcd6500 0000000000000000 0000000000000000 0000000000000000
> [ 1.729984] 3dc0: 0000000000000000 ffff000000000000 ffff8009768b3e40 ffff000008c70d14
> [ 1.737737] 3de0: 0000000000000110 ffff000008e2c000 ffff000008cbf2c0 0000000000000007
> [ 1.745490] 3e00: ffff000008d27900 0000000000000000 ffff000008e2c000 ffff000008b48ac8
> [ 1.753242] 3e20: 0000000700000007 0000000000000000 0000000000000000 ffff000008c5fd70
> [ 1.760995] 3e40: ffff8009768b3ea0 ffff0000088d15d0 ffff0000088d15c0 0000000000000000
> [ 1.768747] 3e60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.776499] 3e80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.784252] 3ea0: 0000000000000000 ffff0000080830a0 ffff0000088d15c0 0000000000000000
> [ 1.792004] 3ec0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.799756] 3ee0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.807508] 3f00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.815260] 3f20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.823023] 3f40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.830775] 3f60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.838527] 3f80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.846279] 3fa0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> [ 1.854031] 3fc0: 0000000000000000 0000000000000005 0000000000000000 0000000000000000
> [ 1.861783] 3fe0: 0000000000000000 0000000000000000 035b4d0700426040 000f000200440000
> [ 1.869531] Call trace:
> [ 1.871950] Exception stack(0xffff8009768b3a80 to 0xffff8009768b3bb0)
> [ 1.878327] 3a80: 8000000000000003 0001000000000000 0000000080e2b000 00000000240ab2f8
> [ 1.886080] 3aa0: ffff8009768b3b00 ffff00000818bb68 ffff800976015f80 00000000024000c0
> [ 1.893832] 3ac0: ffff00000818bbe4 000000000000001a ffff80097608dc10 ffff800976bd1218
> [ 1.901585] 3ae0: ffff8009768b3af0 ffff0000083f2670 ffff8009768b3b70 ffff0000083f2b40
> [ 1.909338] 3b00: 0000000000000000 ffff800976811b00 0000000000000000 ffff800976811a90
> [ 1.917091] 3b20: 0000000057d752e6 ffff8009768b3c98 00000000240aa3e4 00000000ff000001
> [ 1.924844] 3b40: 0000000000010001 ffff8009768b3c98 000000008080ffff fefe7eff2f627371
> [ 1.932596] 3b60: ffffff7f7f7f7f7f 0000000000000000 0101010101010101 0000000000000020
> [ 1.940349] 3b80: 0000000000000038 0000000000000000 0000000000000000 ffff80097612f16b
> [ 1.948098] 3ba0: 0000000000000000 0000000000000000
> [ 1.952925] [<00000000240ab2f8>] 0x240ab2f8
> [ 1.957069] [<ffff000008703de8>] efi_read_time+0x28/0x78
> [ 1.962329] [<ffff000008700964>] __rtc_read_time.isra.1+0x44/0x70
> [ 1.968360] [<ffff0000087009c8>] rtc_read_time+0x38/0x58
> [ 1.973620] [<ffff000008ca0878>] rtc_hctosys+0x5c/0xe4
> [ 1.978708] [<ffff000008083b40>] do_one_initcall+0x38/0x128
> [ 1.984227] [<ffff000008c70d14>] kernel_init_freeable+0x1ac/0x250
> [ 1.990261] [<ffff0000088d15d0>] kernel_init+0x10/0x100
> [ 1.995433] [<ffff0000080830a0>] ret_from_fork+0x10/0x30
> [ 2.000691] Code: bad PC value
>
> --
> Catalin
^ permalink raw reply
* [PATCH -next] meson: clk: Use builtin_platform_driver to simplify the code
From: Wei Yongjun @ 2016-09-10 12:02 UTC (permalink / raw)
To: linux-arm-kernel
From: Wei Yongjun <weiyongjun1@huawei.com>
Use the builtin_platform_driver() macro to make the code simpler.
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
drivers/clk/meson/meson8b.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index e1d4aa1..aaa3e39 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -673,8 +673,4 @@ static struct platform_driver meson8b_driver = {
},
};
-static int __init meson8b_clkc_init(void)
-{
- return platform_driver_register(&meson8b_driver);
-}
-device_initcall(meson8b_clkc_init);
+builtin_platform_driver(meson8b_driver);
^ permalink raw reply related
* [PATCH -next] hwrng: st - Fix missing clk_disable_unprepare() on error in st_rng_probe()
From: Wei Yongjun @ 2016-09-10 12:03 UTC (permalink / raw)
To: linux-arm-kernel
From: Wei Yongjun <weiyongjun1@huawei.com>
Fix the missing clk_disable_unprepare() before return
from st_rng_probe() in the error handling case.
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
drivers/char/hw_random/st-rng.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/char/hw_random/st-rng.c b/drivers/char/hw_random/st-rng.c
index 7e8aa6b..938ec10 100644
--- a/drivers/char/hw_random/st-rng.c
+++ b/drivers/char/hw_random/st-rng.c
@@ -108,6 +108,7 @@ static int st_rng_probe(struct platform_device *pdev)
ret = hwrng_register(&ddata->ops);
if (ret) {
dev_err(&pdev->dev, "Failed to register HW RNG\n");
+ clk_disable_unprepare(clk);
return ret;
}
^ permalink raw reply related
* [PATCH v4 0/5] arm/arm64: vgic-new: Implement API for vGICv3 live migration
From: vijay.kilari at gmail.com @ 2016-09-10 12:22 UTC (permalink / raw)
To: linux-arm-kernel
From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
This patchset adds API for saving and restoring
of VGICv3 registers to support live migration with new vgic feature.
This API definition is as per version of VGICv3 specification
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-July/445611.html
Compatible live migration QEMU patches will be sent later.
The patch 3 & 4 are picked from the Pavel's previous implementation.
http://www.spinics.net/lists/kvm/msg122040.html
v3 => v4:
- Rebased to latest code base
- Moved vgic_uaccess() from vgic-mmio-v2.c to vgic-mmio.c
- Dropped macro REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED_UACCESS
- Dropped LE conversion for userspace access
- Introduced vgic_uaccess_write_pending() for ISPENDR write
- Change macro KVM_DEV_ARM_VGIC_V3_CPUID_MASK to KVM_DEV_ARM_VGIC_V3_MIDR_MASK
- Refactored some code as common code.
- Changed handing of ICC_* registers
- Allowed ICC_SRE_EL1 read by userspace
- Fixed KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_* macros
v2 => v3:
- Implemented separate API for ISPENDR and ICPENDR to
read soft_pending instead of pending for level triggerred interrupts
- Implemented ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO to access line level
- Rebased on top of Christoffer's patch set
http://www.spinics.net/lists/kvm/msg136840.html
NOTE: GICD_STATUSR and GICR_STATUSR are implemented as RAZ/WI.
v1 => v2:
- The init sequence change patch is no more required.
Fixed in patch 2 by using static vgic_io_dev regions structure instead
of using dynamic allocation pointer.
- Updated commit message of patch 4.
- Dropped usage of union to manage 32-bit and 64-bit access in patch 1.
Used local variable for 32-bit access.
- Updated macro __ARM64_SYS_REG and ARM64_SYS_REG in
arch/arm64/include/uapi/asm/kvm.h as per qemu requirements.
Vijaya Kumar K (5):
arm/arm64: vgic-new: Implement support for userspace access
arm/arm64: vgic-new: Add distributor and redistributor access
arm/arm64: vgic-new: Introduce find_reg_by_id()
arm/arm64: vgic-new: Implement VGICv3 CPU interface access
arm/arm64: vgic-new: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
arch/arm64/include/uapi/asm/kvm.h | 13 ++
arch/arm64/kvm/Makefile | 1 +
arch/arm64/kvm/sys_regs.c | 22 ++-
arch/arm64/kvm/sys_regs.h | 4 +
include/linux/irqchip/arm-gic-v3.h | 32 ++++-
virt/kvm/arm/vgic/vgic-kvm-device.c | 213 ++++++++++++++++++++++++++++-
virt/kvm/arm/vgic/vgic-mmio-v2.c | 57 +-------
virt/kvm/arm/vgic/vgic-mmio-v3.c | 143 +++++++++++++++++---
virt/kvm/arm/vgic/vgic-mmio.c | 199 +++++++++++++++++++++++++--
virt/kvm/arm/vgic/vgic-mmio.h | 35 +++++
virt/kvm/arm/vgic/vgic-sys-reg-v3.c | 261 ++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 4 +
virt/kvm/arm/vgic/vgic.h | 23 ++++
13 files changed, 914 insertions(+), 93 deletions(-)
create mode 100644 virt/kvm/arm/vgic/vgic-sys-reg-v3.c
--
1.9.1
^ permalink raw reply
* [PATCH v4 1/5] arm/arm64: vgic-new: Implement support for userspace access
From: vijay.kilari at gmail.com @ 2016-09-10 12:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473510138-4719-1-git-send-email-vijay.kilari@gmail.com>
From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
Read and write of some registers like ISPENDR and ICPENDR
from userspace requires special handling when compared to
guest access for these registers.
Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
for handling of ISPENDR, ICPENDR registers handling.
Add infrastructure to support guest and userspace read
and write for the required registers
Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
virt/kvm/arm/vgic/vgic-mmio-v2.c | 25 --------
virt/kvm/arm/vgic/vgic-mmio-v3.c | 42 +++++++------
virt/kvm/arm/vgic/vgic-mmio.c | 132 ++++++++++++++++++++++++++++++++++++---
virt/kvm/arm/vgic/vgic-mmio.h | 26 ++++++++
4 files changed, 174 insertions(+), 51 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index b44b359..0b32f40 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
return -ENXIO;
}
-/*
- * When userland tries to access the VGIC register handlers, we need to
- * create a usable struct vgic_io_device to be passed to the handlers and we
- * have to set up a buffer similar to what would have happened if a guest MMIO
- * access occurred, including doing endian conversions on BE systems.
- */
-static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
- bool is_write, int offset, u32 *val)
-{
- unsigned int len = 4;
- u8 buf[4];
- int ret;
-
- if (is_write) {
- vgic_data_host_to_mmio_bus(buf, len, *val);
- ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
- } else {
- ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
- if (!ret)
- *val = vgic_data_mmio_bus_to_host(buf, len);
- }
-
- return ret;
-}
-
int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *val)
{
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 90d8181..3b4d507 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -356,7 +356,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
* We take some special care here to fix the calculation of the register
* offset.
*/
-#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc) \
+#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
{ \
.reg_offset = off, \
.bits_per_irq = bpi, \
@@ -371,6 +371,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
.access_flags = acc, \
.read = rd, \
.write = wr, \
+ .uaccess_read = ur, \
+ .uaccess_write = uw, \
}
static const struct vgic_register_region vgic_v3_dist_registers[] = {
@@ -378,40 +380,42 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
- vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
+ vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
- vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
+ vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
- vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
+ vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
- vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
+ vgic_mmio_read_pending, vgic_mmio_write_spending,
+ vgic_uaccess_read_pending, vgic_uaccess_write_pending, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
- vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
+ vgic_mmio_read_pending, vgic_mmio_write_cpending,
+ vgic_uaccess_read_pending, vgic_mmio_write_wi, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
- vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
+ vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
- vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
+ vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
- vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
- VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+ vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
+ 8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
- vgic_mmio_read_config, vgic_mmio_write_config, 2,
+ vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
- vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
+ vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
@@ -449,11 +453,13 @@ static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
VGIC_ACCESS_32bit),
- REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
- vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
+ REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
+ vgic_mmio_read_pending, vgic_mmio_write_spending,
+ vgic_uaccess_read_pending, vgic_uaccess_write_pending, 4,
VGIC_ACCESS_32bit),
- REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
- vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
+ REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
+ vgic_mmio_read_pending, vgic_mmio_write_cpending,
+ vgic_uaccess_read_pending, vgic_mmio_write_wi, 4,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 3bad3c5..99d88a6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -100,6 +100,60 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
}
}
+unsigned long vgic_uaccess_read_pending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len)
+{
+ u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+ u32 value = 0;
+ int i;
+
+ /*
+ * A level triggerred interrupt pending state is latched in both
+ * "soft_pending" and "line_level" variables. Userspace will save
+ * and restore soft_pending and line_level separately.
+ * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+ * handling of ISPENDR and ICPENDR.
+ */
+ for (i = 0; i < len * 8; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
+ value |= (1U << i);
+ if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
+ value |= (1U << i);
+ }
+
+ return value;
+}
+
+void vgic_uaccess_write_pending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+ int i;
+
+ for (i = 0; i < len * 8; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+ if (test_bit(i, &val)) {
+ irq->pending = true;
+ irq->soft_pending = true;
+ vgic_queue_irq_unlock(vcpu->kvm, irq);
+ } else {
+ irq->soft_pending = false;
+ if (irq->config == VGIC_CONFIG_EDGE ||
+ (irq->config == VGIC_CONFIG_LEVEL &&
+ !irq->line_level))
+ irq->pending = false;
+ spin_unlock(&irq->irq_lock);
+ }
+
+ vgic_put_irq(vcpu->kvm, irq);
+ }
+}
+
unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len)
{
@@ -468,6 +522,73 @@ static bool check_region(const struct vgic_register_region *region,
return false;
}
+static const struct vgic_register_region *
+ vgic_get_mmio_region(struct vgic_io_device *iodev, gpa_t addr, int len)
+{
+ const struct vgic_register_region *region;
+
+ region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
+ addr - iodev->base_addr);
+ if (!region || !check_region(region, addr, len))
+ return NULL;
+
+ return region;
+}
+
+static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, u32 *val)
+{
+ struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+ const struct vgic_register_region *region;
+ struct kvm_vcpu *r_vcpu;
+
+ region = vgic_get_mmio_region(iodev, addr, sizeof(u32));
+ if (!region) {
+ *val = 0;
+ return 0;
+ }
+
+ r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+ if (region->uaccess_read)
+ *val = region->uaccess_read(r_vcpu, addr, sizeof(u32));
+ else
+ *val = region->read(r_vcpu, addr, sizeof(u32));
+
+ return 0;
+}
+
+static int vgic_uaccess_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, const u32 *val)
+{
+ struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+ const struct vgic_register_region *region;
+ struct kvm_vcpu *r_vcpu;
+
+ region = vgic_get_mmio_region(iodev, addr, sizeof(u32));
+ if (!region)
+ return 0;
+
+ r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+ if (region->uaccess_write)
+ region->uaccess_write(r_vcpu, addr, sizeof(u32), *val);
+ else
+ region->write(r_vcpu, addr, sizeof(u32), *val);
+
+ return 0;
+}
+
+/*
+ * Userland access to VGIC registers.
+ */
+int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
+ bool is_write, int offset, u32 *val)
+{
+ if (is_write)
+ return vgic_uaccess_write(vcpu, &dev->dev, offset, val);
+ else
+ return vgic_uaccess_read(vcpu, &dev->dev, offset, val);
+}
+
static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
{
@@ -475,9 +596,8 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
const struct vgic_register_region *region;
unsigned long data = 0;
- region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
- addr - iodev->base_addr);
- if (!region || !check_region(region, addr, len)) {
+ region = vgic_get_mmio_region(iodev, addr, len);
+ if (!region) {
memset(val, 0, len);
return 0;
}
@@ -508,14 +628,10 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
const struct vgic_register_region *region;
unsigned long data = vgic_data_mmio_bus_to_host(val, len);
- region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
- addr - iodev->base_addr);
+ region = vgic_get_mmio_region(iodev, addr, len);
if (!region)
return 0;
- if (!check_region(region, addr, len))
- return 0;
-
switch (iodev->iodev_type) {
case IODEV_CPUIF:
region->write(vcpu, addr, len, data);
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 0b3ecf9..3435f28 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -34,6 +34,10 @@ struct vgic_register_region {
gpa_t addr, unsigned int len,
unsigned long val);
};
+ unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
+ unsigned int len);
+ void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
+ unsigned int len, unsigned long val);
};
extern struct kvm_io_device_ops kvm_io_gic_ops;
@@ -86,6 +90,18 @@ extern struct kvm_io_device_ops kvm_io_gic_ops;
.write = wr, \
}
+#define REGISTER_DESC_WITH_LENGTH_UACCESS(off, rd, wr, urd, uwr, length, acc) \
+ { \
+ .reg_offset = off, \
+ .bits_per_irq = 0, \
+ .len = length, \
+ .access_flags = acc, \
+ .read = rd, \
+ .write = wr, \
+ .uaccess_read = urd, \
+ .uaccess_write = uwr, \
+ }
+
int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
struct vgic_register_region *reg_desc,
struct vgic_io_device *region,
@@ -122,6 +138,13 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);
+unsigned long vgic_uaccess_read_pending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len);
+
+void vgic_uaccess_write_pending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val);
+
unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len);
@@ -158,6 +181,9 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);
+int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
+ bool is_write, int offset, u32 *val);
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
--
1.9.1
^ permalink raw reply related
* [PATCH v4 2/5] arm/arm64: vgic-new: Add distributor and redistributor access
From: vijay.kilari at gmail.com @ 2016-09-10 12:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473510138-4719-1-git-send-email-vijay.kilari@gmail.com>
From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
VGICv3 Distributor and Redistributor registers are accessed using
KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_DIST_REGS
with KVM_SET_DEVICE_ATTR and KVM_GET_DEVICE_ATTR ioctls.
These registers are accessed as 32-bit and cpu mpidr
value passed along with register offset is used to identify the
cpu for redistributor registers access.
The version of VGIC v3 specification is define here
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-July/445611.html
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
arch/arm64/include/uapi/asm/kvm.h | 4 ++
virt/kvm/arm/vgic/vgic-kvm-device.c | 140 ++++++++++++++++++++++++++++++++++--
virt/kvm/arm/vgic/vgic-mmio-v2.c | 16 +----
virt/kvm/arm/vgic/vgic-mmio-v3.c | 72 +++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.c | 22 ++++++
virt/kvm/arm/vgic/vgic-mmio.h | 4 ++
virt/kvm/arm/vgic/vgic.h | 5 ++
7 files changed, 245 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 3051f86..56dc08d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -201,10 +201,14 @@ struct kvm_arch_memory_slot {
#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2
#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
+#define KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
+ (0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
+#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
/* Device Control API on vcpu fd */
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 163b057..3225388 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -320,9 +320,10 @@ static int vgic_attr_regs_access_v2(struct kvm_device *dev,
mutex_lock(&dev->kvm->lock);
- ret = vgic_init(dev->kvm);
- if (ret)
+ if (unlikely(!vgic_initialized(dev->kvm))) {
+ ret = -EBUSY;
goto out;
+ }
if (!lock_all_vcpus(dev->kvm)) {
ret = -EBUSY;
@@ -433,16 +434,144 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
#ifdef CONFIG_KVM_ARM_VGIC_V3
+static int parse_vgic_v3_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr,
+ struct vgic_reg_attr *reg_attr)
+{
+ unsigned long mpidr;
+
+ mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
+ KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
+
+ reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr);
+ if (!reg_attr->vcpu)
+ return -EINVAL;
+
+ if (reg_attr->vcpu->vcpu_id >= atomic_read(&dev->kvm->online_vcpus))
+ return -EINVAL;
+
+ reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+ return 0;
+}
+
+/*
+ * vgic_attr_regs_access_v3 - allows user space to access VGIC v3 state
+ *
+ * @dev: kvm device handle
+ * @attr: kvm device attribute
+ * @reg: address the value is read or written
+ * @is_write: true if userspace is writing a register
+ */
+static int vgic_attr_regs_access_v3(struct kvm_device *dev,
+ struct kvm_device_attr *attr,
+ u64 *reg, bool is_write)
+{
+ struct vgic_reg_attr reg_attr;
+ gpa_t addr;
+ struct kvm_vcpu *vcpu;
+ int ret;
+ u32 tmp32;
+
+ ret = parse_vgic_v3_attr(dev, attr, ®_attr);
+ if (ret)
+ return ret;
+
+ vcpu = reg_attr.vcpu;
+ addr = reg_attr.addr;
+
+ mutex_lock(&dev->kvm->lock);
+
+ if (unlikely(!vgic_initialized(dev->kvm))) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (!lock_all_vcpus(dev->kvm)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ switch (attr->group) {
+ case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+ if (is_write)
+ tmp32 = *reg;
+
+ ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
+ if (!is_write)
+ *reg = tmp32;
+ break;
+ case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+ if (is_write)
+ tmp32 = *reg;
+
+ ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
+ if (!is_write)
+ *reg = tmp32;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ unlock_all_vcpus(dev->kvm);
+out:
+ mutex_unlock(&dev->kvm->lock);
+ return ret;
+}
+
static int vgic_v3_set_attr(struct kvm_device *dev,
struct kvm_device_attr *attr)
{
- return vgic_set_common_attr(dev, attr);
+ int ret;
+
+ ret = vgic_set_common_attr(dev, attr);
+ if (ret != -ENXIO)
+ return ret;
+
+ switch (attr->group) {
+ case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+ case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
+ u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+ u32 tmp32;
+ u64 reg;
+
+ if (get_user(tmp32, uaddr))
+ return -EFAULT;
+
+ reg = tmp32;
+ return vgic_attr_regs_access_v3(dev, attr, ®, true);
+ }
+ }
+ return -ENXIO;
}
static int vgic_v3_get_attr(struct kvm_device *dev,
struct kvm_device_attr *attr)
{
- return vgic_get_common_attr(dev, attr);
+ int ret;
+
+ ret = vgic_get_common_attr(dev, attr);
+ if (ret != -ENXIO)
+ return ret;
+
+ switch (attr->group) {
+ case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+ case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
+ u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+ u64 reg;
+ u32 tmp32;
+
+ ret = vgic_attr_regs_access_v3(dev, attr, ®, false);
+ if (ret)
+ return ret;
+ tmp32 = reg;
+ ret = put_user(tmp32, uaddr);
+ return ret;
+ }
+ }
+
+ return -ENXIO;
}
static int vgic_v3_has_attr(struct kvm_device *dev,
@@ -456,6 +585,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
return 0;
}
break;
+ case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+ case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+ return vgic_v3_has_attr_regs(dev, attr);
case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
return 0;
case KVM_DEV_ARM_VGIC_GRP_CTRL:
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 0b32f40..2cb04b7 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -368,10 +368,9 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
{
- int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
const struct vgic_register_region *regions;
gpa_t addr;
- int nr_regions, i, len;
+ int nr_regions;
addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
@@ -392,18 +391,7 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
if (addr & 3)
return -ENXIO;
- for (i = 0; i < nr_regions; i++) {
- if (regions[i].bits_per_irq)
- len = (regions[i].bits_per_irq * nr_irqs) / 8;
- else
- len = regions[i].len;
-
- if (regions[i].reg_offset <= addr &&
- regions[i].reg_offset + len > addr)
- return 0;
- }
-
- return -ENXIO;
+ return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
}
int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 3b4d507..ffbe1ae 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -18,6 +18,8 @@
#include <kvm/arm_vgic.h>
#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
#include "vgic.h"
#include "vgic-mmio.h"
@@ -379,6 +381,9 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
VGIC_ACCESS_32bit),
+ REGISTER_DESC_WITH_LENGTH(GICD_STATUSR,
+ vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
+ VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
VGIC_ACCESS_32bit),
@@ -426,12 +431,18 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
VGIC_ACCESS_32bit),
+ REGISTER_DESC_WITH_LENGTH(GICR_STATUSR,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
+ VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8,
VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+ REGISTER_DESC_WITH_LENGTH(GICR_WAKER,
+ vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+ VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
vgic_mmio_read_propbase, vgic_mmio_write_propbase, 8,
VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
@@ -552,6 +563,34 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
return ret;
}
+int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+ const struct vgic_register_region *regions;
+ gpa_t addr;
+ int nr_regions;
+
+ addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+ switch (attr->group) {
+ case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+ regions = vgic_v3_dist_registers;
+ nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
+ break;
+ case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:{
+ regions = vgic_v3_rdbase_registers;
+ nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
+ break;
+ }
+ default:
+ return -ENXIO;
+ }
+
+ /* We only support aligned 32-bit accesses. */
+ if (addr & 3)
+ return -ENXIO;
+
+ return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
+}
/*
* Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
* generation register ICC_SGI1R_EL1) with a given VCPU.
@@ -658,3 +697,36 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
vgic_put_irq(vcpu->kvm, irq);
}
}
+
+int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val)
+{
+ struct vgic_io_device dev = {
+ .regions = vgic_v3_dist_registers,
+ .nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
+ };
+
+ return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
+int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val)
+{
+ struct vgic_io_device rd_dev = {
+ .regions = vgic_v3_rdbase_registers,
+ .nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers),
+ };
+
+ struct vgic_io_device sgi_dev = {
+ .regions = vgic_v3_sgibase_registers,
+ .nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers),
+ };
+
+ /* SGI_base is the next 64K frame after RD_base */
+ if (offset >= SZ_64K)
+ return vgic_uaccess(vcpu, &sgi_dev, is_write,
+ offset - SZ_64K, val);
+ else
+ return vgic_uaccess(vcpu, &rd_dev, is_write,
+ offset, val);
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 99d88a6..9294555 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -448,6 +448,28 @@ vgic_find_mmio_region(const struct vgic_register_region *region, int nr_regions,
sizeof(region[0]), match_region);
}
+/* Check if address falls within the region */
+int vgic_validate_mmio_region_addr(struct kvm_device *dev,
+ const struct vgic_register_region *regions,
+ int nr_regions, gpa_t addr)
+{
+ int i, len;
+ int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+
+ for (i = 0; i < nr_regions; i++) {
+ if (regions[i].bits_per_irq)
+ len = (regions[i].bits_per_irq * nr_irqs) / 8;
+ else
+ len = regions[i].len;
+
+ if (regions[i].reg_offset <= addr &&
+ regions[i].reg_offset + len > addr)
+ return 0;
+ }
+
+ return -ENXIO;
+}
+
/*
* kvm_mmio_read_buf() returns a value in a format where it can be converted
* to a byte array and be directly observed as the guest wanted it to appear
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 3435f28..9a0109b 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -184,6 +184,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
bool is_write, int offset, u32 *val);
+int vgic_validate_mmio_region_addr(struct kvm_device *dev,
+ const struct vgic_register_region *regions,
+ int nr_regions, gpa_t addr);
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 6c4625c..94b3479 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -89,6 +89,11 @@ bool vgic_has_its(struct kvm *kvm);
int kvm_vgic_register_its_device(void);
void vgic_enable_lpis(struct kvm_vcpu *vcpu);
int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
+int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val);
+int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ int offset, u32 *val);
#else
static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
{
--
1.9.1
^ permalink raw reply related
* [PATCH v4 3/5] arm/arm64: vgic-new: Introduce find_reg_by_id()
From: vijay.kilari at gmail.com @ 2016-09-10 12:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473510138-4719-1-git-send-email-vijay.kilari@gmail.com>
From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
In order to implement vGICv3 CPU interface access, we will need to perform
table lookup of system registers. We would need both index_to_params() and
find_reg() exported for that purpose, but instead we export a single
function which combines them both.
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
---
arch/arm64/kvm/sys_regs.c | 22 +++++++++++++++-------
arch/arm64/kvm/sys_regs.h | 4 ++++
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index e51367d..87ebe35 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1794,6 +1794,17 @@ static bool index_to_params(u64 id, struct sys_reg_params *params)
}
}
+const struct sys_reg_desc *find_reg_by_id(u64 id,
+ struct sys_reg_params *params,
+ const struct sys_reg_desc table[],
+ unsigned int num)
+{
+ if (!index_to_params(id, params))
+ return NULL;
+
+ return find_reg(params, table, num);
+}
+
/* Decode an index value, and find the sys_reg_desc entry. */
static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
u64 id)
@@ -1921,10 +1932,8 @@ static int get_invariant_sys_reg(u64 id, void __user *uaddr)
struct sys_reg_params params;
const struct sys_reg_desc *r;
- if (!index_to_params(id, ¶ms))
- return -ENOENT;
-
- r = find_reg(¶ms, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+ r = find_reg_by_id(id, ¶ms, invariant_sys_regs,
+ ARRAY_SIZE(invariant_sys_regs));
if (!r)
return -ENOENT;
@@ -1938,9 +1947,8 @@ static int set_invariant_sys_reg(u64 id, void __user *uaddr)
int err;
u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
- if (!index_to_params(id, ¶ms))
- return -ENOENT;
- r = find_reg(¶ms, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+ r = find_reg_by_id(id, ¶ms, invariant_sys_regs,
+ ARRAY_SIZE(invariant_sys_regs));
if (!r)
return -ENOENT;
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index dbbb01c..9c6ffd0 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -136,6 +136,10 @@ static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
return i1->Op2 - i2->Op2;
}
+const struct sys_reg_desc *find_reg_by_id(u64 id,
+ struct sys_reg_params *params,
+ const struct sys_reg_desc table[],
+ unsigned int num);
#define Op0(_x) .Op0 = _x
#define Op1(_x) .Op1 = _x
--
1.9.1
^ permalink raw reply related
* [PATCH v4 4/5] arm/arm64: vgic-new: Implement VGICv3 CPU interface access
From: vijay.kilari at gmail.com @ 2016-09-10 12:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473510138-4719-1-git-send-email-vijay.kilari@gmail.com>
From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
VGICv3 CPU interface registers are accessed using
KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
as 64-bit. The cpu MPIDR value is passed along with register id.
is used to identify the cpu for registers access.
The version of VGIC v3 specification is define here
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-July/445611.html
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
arch/arm64/include/uapi/asm/kvm.h | 3 +
arch/arm64/kvm/Makefile | 1 +
include/linux/irqchip/arm-gic-v3.h | 32 ++++-
virt/kvm/arm/vgic/vgic-kvm-device.c | 27 ++++
virt/kvm/arm/vgic/vgic-mmio-v2.c | 16 ---
virt/kvm/arm/vgic/vgic-mmio-v3.c | 18 +++
virt/kvm/arm/vgic/vgic-mmio.c | 16 +++
virt/kvm/arm/vgic/vgic-sys-reg-v3.c | 261 ++++++++++++++++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-v3.c | 4 +
virt/kvm/arm/vgic/vgic.h | 15 +++
10 files changed, 376 insertions(+), 17 deletions(-)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 56dc08d..91c7137 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -206,9 +206,12 @@ struct kvm_arch_memory_slot {
(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
+#define KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
+#define KVM_DEV_ARM_VGIC_CPU_SYSREGS 6
+
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
/* Device Control API on vcpu fd */
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d50a82a..1a14e29 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -32,5 +32,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-v3.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 99ac022..22ec183 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -354,6 +354,24 @@
*/
#define ICC_CTLR_EL1_EOImode_drop_dir (0U << 1)
#define ICC_CTLR_EL1_EOImode_drop (1U << 1)
+#define ICC_CTLR_EL1_CBPR_SHIFT (0)
+#define ICC_CTLR_EL1_CBPR_MASK (1 << ICC_CTLR_EL1_CBPR_SHIFT)
+#define ICC_CTLR_EL1_EOImode_SHIFT (1)
+#define ICC_CTLR_EL1_EOImode_MASK (1 << ICC_CTLR_EL1_EOImode_SHIFT)
+#define ICC_CTLR_EL1_PRI_BITS_SHIFT (8)
+#define ICC_CTLR_EL1_PRI_BITS_MASK (0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
+#define ICC_CTLR_EL1_ID_BITS_SHIFT (11)
+#define ICC_CTLR_EL1_ID_BITS_MASK (0x7 << ICC_CTLR_EL1_ID_BITS_SHIFT)
+#define ICC_PMR_EL1_SHIFT (0)
+#define ICC_PMR_EL1_MASK (0xff << ICC_PMR_EL1_SHIFT)
+#define ICC_BPR0_EL1_SHIFT (0)
+#define ICC_BPR0_EL1_MASK (0x7 << ICC_PMR_EL1_SHIFT)
+#define ICC_BPR1_EL1_SHIFT (0)
+#define ICC_BPR1_EL1_MASK (0x7 << ICC_PMR_EL1_SHIFT)
+#define ICC_IGRPEN0_EL1_SHIFT (0)
+#define ICC_IGRPEN0_EL1_MASK (1 << ICC_IGRPEN0_EL1_SHIFT)
+#define ICC_IGRPEN1_EL1_SHIFT (0)
+#define ICC_IGRPEN1_EL1_MASK (1 << ICC_IGRPEN1_EL1_SHIFT)
#define ICC_SRE_EL1_SRE (1U << 0)
/*
@@ -383,7 +401,19 @@
#define ICH_HCR_UIE (1 << 1)
#define ICH_VMCR_CTLR_SHIFT 0
-#define ICH_VMCR_CTLR_MASK (0x21f << ICH_VMCR_CTLR_SHIFT)
+#define ICH_VMCR_CTLR_MASK (0x210 << ICH_VMCR_CTLR_SHIFT)
+#define ICH_VMCR_CBPR_SHIFT 4
+#define ICH_VMCR_CBPR_MASK (1 << ICH_VMCR_CBPR_SHIFT)
+#define ICH_VMCR_EOIM_SHIFT 9
+#define ICH_VMCR_EOIM_MASK (1 << ICH_VMCR_EOIM_SHIFT)
+#define ICH_VMCR_ENG0_SHIFT 0
+#define ICH_VMCR_ENG0_MASK (1 << ICH_VMCR_ENG0_SHIFT)
+#define ICH_VMCR_ENG1_SHIFT 1
+#define ICH_VMCR_ENG1_MASK (1 << ICH_VMCR_ENG1_SHIFT)
+#define ICH_VMCR_ENG0_SHIFT 0
+#define ICH_VMCR_ENG0 (1 << ICH_VMCR_ENG0_SHIFT)
+#define ICH_VMCR_ENG1_SHIFT 1
+#define ICH_VMCR_ENG1 (1 << ICH_VMCR_ENG1_SHIFT)
#define ICH_VMCR_BPR1_SHIFT 18
#define ICH_VMCR_BPR1_MASK (7 << ICH_VMCR_BPR1_SHIFT)
#define ICH_VMCR_BPR0_SHIFT 21
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 3225388..e580b6d 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -509,6 +509,14 @@ static int vgic_attr_regs_access_v3(struct kvm_device *dev,
if (!is_write)
*reg = tmp32;
break;
+ case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+ u64 regid;
+
+ regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
+ ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write,
+ regid, reg);
+ break;
+ }
default:
ret = -EINVAL;
break;
@@ -542,6 +550,15 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
reg = tmp32;
return vgic_attr_regs_access_v3(dev, attr, ®, true);
}
+ case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+ u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+ u64 reg;
+
+ if (get_user(reg, uaddr))
+ return -EFAULT;
+
+ return vgic_attr_regs_access_v3(dev, attr, ®, true);
+ }
}
return -ENXIO;
}
@@ -569,6 +586,15 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
ret = put_user(tmp32, uaddr);
return ret;
}
+ case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+ u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+ u64 reg;
+
+ ret = vgic_attr_regs_access_v3(dev, attr, ®, false);
+ if (ret)
+ return ret;
+ return put_user(reg, uaddr);
+ }
}
return -ENXIO;
@@ -587,6 +613,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
break;
case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+ case KVM_DEV_ARM_VGIC_CPU_SYSREGS:
return vgic_v3_has_attr_regs(dev, attr);
case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
return 0;
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2cb04b7..ad353b5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
}
}
-static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
-{
- if (kvm_vgic_global_state.type == VGIC_V2)
- vgic_v2_set_vmcr(vcpu, vmcr);
- else
- vgic_v3_set_vmcr(vcpu, vmcr);
-}
-
-static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
-{
- if (kvm_vgic_global_state.type == VGIC_V2)
- vgic_v2_get_vmcr(vcpu, vmcr);
- else
- vgic_v3_get_vmcr(vcpu, vmcr);
-}
-
#define GICC_ARCH_VERSION_V2 0x2
/* These are for userland accesses only, there is no guest-facing emulation. */
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index ffbe1ae..04e0f2c 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -23,6 +23,7 @@
#include "vgic.h"
#include "vgic-mmio.h"
+#include "sys_regs.h"
/* extract @num bytes at @offset bytes offset in data */
unsigned long extract_bytes(unsigned long data, unsigned int offset,
@@ -581,6 +582,23 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
break;
}
+ case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+ u64 reg, id;
+ unsigned long mpidr;
+ struct kvm_vcpu *vcpu;
+
+ mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
+ KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
+
+ vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr);
+ if (!vcpu)
+ return -EINVAL;
+ if (vcpu->vcpu_id >= atomic_read(&dev->kvm->online_vcpus))
+ return -EINVAL;
+
+ id = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
+ return vgic_v3_has_cpu_sysregs_attr(vcpu, 0, id, ®);
+ }
default:
return -ENXIO;
}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 9294555..81d851c 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -470,6 +470,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
return -ENXIO;
}
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+ if (kvm_vgic_global_state.type == VGIC_V2)
+ vgic_v2_set_vmcr(vcpu, vmcr);
+ else
+ vgic_v3_set_vmcr(vcpu, vmcr);
+}
+
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+ if (kvm_vgic_global_state.type == VGIC_V2)
+ vgic_v2_get_vmcr(vcpu, vmcr);
+ else
+ vgic_v3_get_vmcr(vcpu, vmcr);
+}
+
/*
* kvm_mmio_read_buf() returns a value in a format where it can be converted
* to a byte array and be directly observed as the guest wanted it to appear
diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
new file mode 100644
index 0000000..437ed27
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
@@ -0,0 +1,261 @@
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/arm_vgic.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+#include "sys_regs.h"
+
+static bool access_gic_ctlr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_vmcr vmcr;
+ u64 val;
+ u32 id_bits;
+
+ vgic_get_vmcr(vcpu, &vmcr);
+ if (p->is_write) {
+ val = p->regval;
+ vmcr.ctlr &= ~(ICH_VMCR_CBPR_MASK | ICH_VMCR_EOIM_MASK);
+ vmcr.ctlr |= ((val & ICC_CTLR_EL1_CBPR_MASK) >>
+ ICC_CTLR_EL1_CBPR_SHIFT) << ICH_VMCR_CBPR_SHIFT;
+ vmcr.ctlr |= ((val & ICC_CTLR_EL1_EOImode_MASK) >>
+ ICC_CTLR_EL1_EOImode_SHIFT) << ICH_VMCR_EOIM_SHIFT;
+ vgic_set_vmcr(vcpu, &vmcr);
+ } else {
+ val = 0;
+ /* ICC_CTLR_EL1.A3V and ICC_CTRL_EL1.SEIS are not set */
+ val |= VGIC_PRI_BITS << ICC_CTLR_EL1_PRI_BITS_SHIFT;
+
+ if (vgic_has_its(vcpu->kvm))
+ id_bits = INTERRUPT_ID_BITS_ITS;
+ else
+ id_bits = INTERRUPT_ID_BITS_SPIS;
+
+ if (id_bits >= 24)
+ val |= (1 << ICC_CTLR_EL1_ID_BITS_SHIFT);
+ else
+ val |= (0 << ICC_CTLR_EL1_ID_BITS_SHIFT);
+
+ val |= ((vmcr.ctlr & ICH_VMCR_CBPR_MASK) >>
+ ICH_VMCR_CBPR_SHIFT) << ICC_CTLR_EL1_CBPR_SHIFT;
+ val |= ((vmcr.ctlr & ICH_VMCR_EOIM_MASK) >>
+ ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
+
+ p->regval = val;
+ }
+
+ return true;
+}
+
+static bool access_gic_pmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_vmcr vmcr;
+
+ vgic_get_vmcr(vcpu, &vmcr);
+ if (p->is_write) {
+ vmcr.pmr = (p->regval << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK;
+ vgic_set_vmcr(vcpu, &vmcr);
+ } else {
+ p->regval = (vmcr.pmr & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT;
+ }
+
+ return true;
+}
+
+static bool access_gic_bpr0(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_vmcr vmcr;
+
+ vgic_get_vmcr(vcpu, &vmcr);
+ if (p->is_write) {
+ vmcr.bpr = (p->regval << ICC_BPR0_EL1_SHIFT) &
+ ICC_BPR0_EL1_MASK;
+ vgic_set_vmcr(vcpu, &vmcr);
+ } else {
+ p->regval = (vmcr.bpr & ICC_BPR0_EL1_MASK) >>
+ ICC_BPR0_EL1_SHIFT;
+ }
+
+ return true;
+}
+
+static bool access_gic_bpr1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_vmcr vmcr;
+
+ vgic_get_vmcr(vcpu, &vmcr);
+ if (p->is_write) {
+ vmcr.abpr = (p->regval << ICC_BPR1_EL1_SHIFT) &
+ ICC_BPR1_EL1_MASK;
+ vgic_set_vmcr(vcpu, &vmcr);
+ } else {
+ p->regval = (vmcr.abpr & ICC_BPR1_EL1_MASK) >>
+ ICC_BPR1_EL1_SHIFT;
+ }
+
+ return true;
+}
+
+static bool access_gic_grpen0(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_vmcr vmcr;
+
+ vgic_get_vmcr(vcpu, &vmcr);
+ if (p->is_write) {
+ vmcr.grpen0 = (p->regval << ICC_IGRPEN0_EL1_SHIFT) &
+ ICC_IGRPEN0_EL1_MASK;
+ vgic_set_vmcr(vcpu, &vmcr);
+ } else {
+ p->regval = (vmcr.grpen0 & ICC_IGRPEN0_EL1_MASK) >>
+ ICC_IGRPEN0_EL1_SHIFT;
+ }
+
+ return true;
+}
+
+static bool access_gic_grpen1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_vmcr vmcr;
+
+ vgic_get_vmcr(vcpu, &vmcr);
+ if (p->is_write) {
+ vmcr.grpen1 = (p->regval << ICC_IGRPEN1_EL1_SHIFT) &
+ ICC_IGRPEN1_EL1_MASK;
+ vgic_set_vmcr(vcpu, &vmcr);
+ } else {
+ p->regval = (vmcr.grpen1 & ICC_IGRPEN1_EL1_MASK) >>
+ ICC_IGRPEN1_EL1_SHIFT;
+ }
+
+ return true;
+}
+
+static bool access_gic_ap0r(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+ u8 idx = r->Op2 & 3;
+
+ if (p->is_write)
+ vgicv3->vgic_ap0r[idx] = p->regval;
+ else
+ p->regval = vgicv3->vgic_ap0r[idx];
+
+ return true;
+}
+
+static bool access_gic_ap1r(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+ u8 idx = r->Op2 & 3;
+
+ if (p->is_write)
+ vgicv3->vgic_ap1r[idx] = p->regval;
+ else
+ p->regval = vgicv3->vgic_ap1r[idx];
+
+ return true;
+}
+
+static bool access_gic_sre(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+ /* Read only. Write ignore */
+ if (!p->is_write)
+ p->regval = vgicv3->vgic_sre;
+
+ return true;
+}
+
+static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
+ /* ICC_PMR_EL1 */
+ { Op0(3), Op1(0), CRn(4), CRm(6), Op2(0), access_gic_pmr },
+ /* ICC_BPR0_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(8), Op2(3), access_gic_bpr0 },
+ /* ICC_AP0R0_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(8), Op2(4), access_gic_ap0r },
+ /* ICC_AP0R1_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(8), Op2(5), access_gic_ap0r },
+ /* ICC_AP0R2_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(8), Op2(6), access_gic_ap0r },
+ /* ICC_AP0R3_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(8), Op2(7), access_gic_ap0r },
+ /* ICC_AP1R0_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(9), Op2(0), access_gic_ap1r },
+ /* ICC_AP1R1_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(9), Op2(1), access_gic_ap1r },
+ /* ICC_AP1R2_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(9), Op2(2), access_gic_ap1r },
+ /* ICC_AP1R3_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(9), Op2(3), access_gic_ap1r },
+ /* ICC_BPR1_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(12), Op2(3), access_gic_bpr1 },
+ /* ICC_CTLR_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(12), Op2(4), access_gic_ctlr },
+ /* ICC_SRE_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(12), Op2(5), access_gic_sre },
+ /* ICC_IGRPEN0_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(12), Op2(6), access_gic_grpen0 },
+ /* ICC_GRPEN1_EL1 */
+ { Op0(3), Op1(0), CRn(12), CRm(12), Op2(7), access_gic_grpen1 },
+};
+
+int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+ u64 *reg)
+{
+ struct sys_reg_params params;
+ u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
+
+ params.regval = *reg;
+ params.is_write = is_write;
+ params.is_aarch32 = false;
+ params.is_32bit = false;
+
+ if (find_reg_by_id(sysreg, ¶ms, gic_v3_icc_reg_descs,
+ ARRAY_SIZE(gic_v3_icc_reg_descs)))
+ return 0;
+ else
+ return -ENXIO;
+}
+
+int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+ u64 *reg)
+{
+ struct sys_reg_params params;
+ const struct sys_reg_desc *r;
+ u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
+
+ if (is_write)
+ params.regval = *reg;
+ params.is_write = is_write;
+ params.is_aarch32 = false;
+ params.is_32bit = false;
+
+ r = find_reg_by_id(sysreg, ¶ms, gic_v3_icc_reg_descs,
+ ARRAY_SIZE(gic_v3_icc_reg_descs));
+ if (!r)
+ return -ENXIO;
+
+ if (!r->access(vcpu, ¶ms, r))
+ return -EINVAL;
+
+ if (!is_write)
+ *reg = params.regval;
+
+ return 0;
+}
+
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 9f0dae3..cf34095 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -179,6 +179,8 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
+ vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
+ vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
}
@@ -191,6 +193,8 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
vmcrp->bpr = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
vmcrp->pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+ vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
+ vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
}
#define INITIAL_PENDBASER_VALUE \
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 94b3479..04a397c 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -30,11 +30,20 @@
#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
+#define KVM_DEV_ARM_VGIC_SYSREG_MASK (KVM_REG_ARM64_SYSREG_OP0_MASK | \
+ KVM_REG_ARM64_SYSREG_OP1_MASK | \
+ KVM_REG_ARM64_SYSREG_CRN_MASK | \
+ KVM_REG_ARM64_SYSREG_CRM_MASK | \
+ KVM_REG_ARM64_SYSREG_OP2_MASK)
+
struct vgic_vmcr {
u32 ctlr;
u32 abpr;
u32 bpr;
u32 pmr;
+ /* Below member variable are valid only for GICv3 */
+ u32 grpen0;
+ u32 grpen1;
};
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
@@ -94,6 +103,10 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *val);
int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *val);
+int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ u64 id, u64 *val);
+int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+ u64 *reg);
#else
static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
{
@@ -172,6 +185,8 @@ static inline int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
#endif
int kvm_register_vgic_device(unsigned long type);
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
int vgic_lazy_init(struct kvm *kvm);
int vgic_init(struct kvm *kvm);
--
1.9.1
^ permalink raw reply related
* [PATCH 5/5] arm/arm64: vgic-new: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
From: vijay.kilari at gmail.com @ 2016-09-10 12:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473510138-4719-1-git-send-email-vijay.kilari@gmail.com>
From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
Userspace requires to store and restore of line_level for
level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
arch/arm64/include/uapi/asm/kvm.h | 6 +++++
virt/kvm/arm/vgic/vgic-kvm-device.c | 48 ++++++++++++++++++++++++++++++++++++-
virt/kvm/arm/vgic/vgic-mmio-v3.c | 11 +++++++++
virt/kvm/arm/vgic/vgic-mmio.c | 29 ++++++++++++++++++++++
virt/kvm/arm/vgic/vgic-mmio.h | 5 ++++
virt/kvm/arm/vgic/vgic.h | 3 +++
6 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 91c7137..4100f8c 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
#define KVM_DEV_ARM_VGIC_CPU_SYSREGS 6
+#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
+ (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
+#define VGIC_LEVEL_INFO_LINE_LEVEL 0
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index e580b6d..41de527 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -517,6 +517,23 @@ static int vgic_attr_regs_access_v3(struct kvm_device *dev,
regid, reg);
break;
}
+ case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+ unsigned int info, intid;
+
+ info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
+ KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
+ if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
+ intid = attr->attr &
+ KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
+ ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
+ intid, &tmp32);
+ if (!is_write)
+ *reg = tmp32;
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ }
default:
ret = -EINVAL;
break;
@@ -559,6 +576,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
return vgic_attr_regs_access_v3(dev, attr, ®, true);
}
+ case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+ u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+ u64 reg;
+ u32 tmp32;
+
+ if (get_user(tmp32, uaddr))
+ return -EFAULT;
+
+ reg = tmp32;
+ return vgic_attr_regs_access_v3(dev, attr, ®, true);
+ }
}
return -ENXIO;
}
@@ -595,8 +623,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
return ret;
return put_user(reg, uaddr);
}
- }
+ case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+ u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+ u64 reg;
+ u32 tmp32;
+ ret = vgic_attr_regs_access_v3(dev, attr, ®, false);
+ if (ret)
+ return ret;
+ tmp32 = reg;
+ return put_user(tmp32, uaddr);
+ }
+ }
return -ENXIO;
}
@@ -617,11 +655,19 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
return vgic_v3_has_attr_regs(dev, attr);
case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
return 0;
+ case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+ if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
+ KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
+ VGIC_LEVEL_INFO_LINE_LEVEL)
+ return 0;
+ break;
+ }
case KVM_DEV_ARM_VGIC_GRP_CTRL:
switch (attr->attr) {
case KVM_DEV_ARM_VGIC_CTRL_INIT:
return 0;
}
+ break;
}
return -ENXIO;
}
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 04e0f2c..826c618 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -748,3 +748,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
return vgic_uaccess(vcpu, &rd_dev, is_write,
offset, val);
}
+
+int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ u32 intid, u32 *val)
+{
+ if (is_write)
+ vgic_write_irq_line_level_info(vcpu, intid, *val);
+ else
+ *val = vgic_read_irq_line_level_info(vcpu, intid);
+
+ return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 81d851c..9cc3900 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -425,6 +425,35 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
}
}
+unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
+{
+ int i;
+ unsigned long val = 0;
+
+ for (i = 0; i < 32; i++) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ if (irq->line_level)
+ val |= (1U << i);
+ }
+
+ return val;
+}
+
+void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
+ const unsigned long val)
+{
+ int i;
+
+ for_each_set_bit(i, &val, 32) {
+ struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+ spin_lock(&irq->irq_lock);
+ irq->line_level = true;
+ spin_unlock(&irq->irq_lock);
+ }
+}
+
static int match_region(const void *key, const void *elt)
{
const unsigned int offset = (unsigned long)key;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 9a0109b..83bf9f1 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -188,6 +188,11 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
const struct vgic_register_region *regions,
int nr_regions, gpa_t addr);
+unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid);
+
+void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
+ const unsigned long val);
+
unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 04a397c..52f4f71 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -107,6 +107,9 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
u64 id, u64 *val);
int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
u64 *reg);
+int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+ u32 intid, u32 *val);
+
#else
static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
{
--
1.9.1
^ permalink raw reply related
* [PATCH -next] net: ethernet: dwmac: fix non static symbol warning
From: Wei Yongjun @ 2016-09-10 12:31 UTC (permalink / raw)
To: linux-arm-kernel
From: Wei Yongjun <weiyongjun1@huawei.com>
Fixes the following sparse warning:
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c:172:1: warning:
symbol 'stm32_dwmac_pm_ops' was not declared. Should it be static?
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index 79d8b92..e5a926b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -169,7 +169,8 @@ static int stm32_dwmac_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops, stm32_dwmac_suspend, stm32_dwmac_resume);
+static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops,
+ stm32_dwmac_suspend, stm32_dwmac_resume);
static const struct of_device_id stm32_dwmac_match[] = {
{ .compatible = "st,stm32-dwmac"},
^ permalink raw reply related
* [PATCH -next] drm/mediatek: Remove redundant dev_err call in mtk_drm_probe()
From: Wei Yongjun @ 2016-09-10 12:33 UTC (permalink / raw)
To: linux-arm-kernel
From: Wei Yongjun <weiyongjun1@huawei.com>
There is a error message within devm_ioremap_resource
already, so remove the dev_err call to avoid redundant
error message.
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 72c1ae4..f4f90e8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -365,12 +365,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
private->config_regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(private->config_regs)) {
- ret = PTR_ERR(private->config_regs);
- dev_err(dev, "Failed to ioremap mmsys-config resource: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(private->config_regs))
+ return PTR_ERR(private->config_regs);
/* Iterate over sibling DISP function blocks */
for_each_child_of_node(dev->of_node->parent, node) {
^ permalink raw reply related
* [4.8.0-rc1] am335x-evm boot failure: n_tty_receive_buf_common: "Unable to handle kernel paging request.."
From: Tony Lindgren @ 2016-09-10 13:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAALWOA-e6SZEW67akn_EGnCPzfZbuw-wjwu-j1dfuucoCA5ecg@mail.gmail.com>
* Matthijs van Duin <matthijsvanduin@gmail.com> [160909 16:54]:
> On 10 September 2016 at 01:47, Tony Lindgren <tony@atomide.com> wrote:
> > Yeah. Just disable omap_l3_smx/noc driver and you should see
> > a proper stack trace. With the L3 driver we're seeing the trace
> > for L3 error interrupt.
>
> Huh what, I see a proper stack trace in his post? I'm pretty sure
> omap_l3_noc doesn't even support am335x currently.
Oh OK sorry please ignore the post, I obviously did not look at
the trace but assumed that was the case based on what I've seen.
Yeah I don't think we have L3 interrupts working for am335x.
Regards,
Tony
^ permalink raw reply
* [PATCH -next] pwm: meson: Fix missing spin_lock_init()
From: Neil Armstrong @ 2016-09-10 13:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473489518-17981-1-git-send-email-weiyj.lk@gmail.com>
Le 10/09/2016 08:38, Wei Yongjun a ?crit :
> From: Wei Yongjun <weiyongjun1@huawei.com>
>
> The driver allocates the spinlock but not initialize it.
> Use spin_lock_init() on it to initialize it correctly.
>
> This is detected by Coccinelle semantic patch.
>
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
> ---
> drivers/pwm/pwm-meson.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
> index bfbbe7f..778d088 100644
> --- a/drivers/pwm/pwm-meson.c
> +++ b/drivers/pwm/pwm-meson.c
> @@ -465,6 +465,7 @@ static int meson_pwm_probe(struct platform_device *pdev)
> if (IS_ERR(meson->base))
> return PTR_ERR(meson->base);
>
> + spin_lock_init(&meson->lock);
> meson->chip.dev = &pdev->dev;
> meson->chip.ops = &meson_pwm_ops;
> meson->chip.base = -1;
>
Thanks for the fix, but it was already posted earlier by Axel Lin <axel.lin@ingics.com>
Thierry will decide which one to merge.
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
Thanks,
Neil
^ permalink raw reply
* L3 error handling (was: Re: [4.8.0-rc1] am335x-evm boot failure: n_tty_receive_buf_common: "Unable to handle kernel paging request..")
From: Matthijs van Duin @ 2016-09-10 14:46 UTC (permalink / raw)
To: linux-arm-kernel
On 10 September 2016 at 15:10, Tony Lindgren <tony@atomide.com> wrote:
> Yeah I don't think we have L3 interrupts working for am335x.
It probably doesn't help that the L3 interconnect registers on the
am335x aren't documented in the TRM. See below for its list of
components, target IDs, address mapping, and L3 error irq routing
(obtained by mostly-automated scanning/testing).
The problem you mention of getting a useless traceback is indeed
annoying, but on a cortex-a8 it wouldn't happen for device accesses:
external aborts on device reads (and strongly-ordered reads/writes)
are synchronous and taken before the irq. If you'd hook into that
handler and grab/clear the corresponding L3 error to make the abort
more informative then the irq will never be taken. Bus errors on
device writes outside the cortex-A8 subsystem never result in an abort
reported to the cpu and by the time the irq is taken the traceback may
be less informative (although there's still good chance it's not far
from the culprit).
On the cortex-A9 I don't know what the situation is.
On the cortex-A15 I don't think your advice actually helps since all
bus errors seem to result in async aborts reported really ridiculously
late: I've seen bus errors in a userspace process actually get
reported by the L3 noc driver (complete with useless traceback),
resulting in a task switch to systemd-journald to log all that spam,
and only *then* the async abort was taken resulting in a perfectly
innocent process getting killed with a SIGBUS.
Needless to say, this is just... wrong.
Matthijs
^ permalink raw reply
* L3 error handling (was: Re: [4.8.0-rc1] am335x-evm boot failure: n_tty_receive_buf_common: "Unable to handle kernel paging request..")
From: Matthijs van Duin @ 2016-09-10 14:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAALWOA_7qGg0WyHPE3biVLka7CdLj8VgsGzf1WMG62Rt-oONkQ@mail.gmail.com>
On Sat, Sep 10, 2016 at 04:46:49PM +0200, Matthijs van Duin wrote:
> It probably doesn't help that the L3 interconnect registers on the
> am335x aren't documented in the TRM. See below for its list of
> components, target IDs, address mapping, and L3 error irq routing
> (obtained by mostly-automated scanning/testing).
Whoops, I forgot something :)
// L3F service network
extern HostAgent host_l3f; // 0x440'00'000, id 0x00, no irq
extern TargetAgent ta_hash; // 0x440'00'200, id 0x02, irq_l3f 9
extern TargetAgent ta_aes1; // 0x440'00'300, id 0x03, irq_l3f 10
extern TargetAgent ta_ocmc; // 0x440'00'400, id 0x10, irq_l3f 2
extern TargetAgent ta_aes0; // 0x440'00'500, id 0x04, irq_l3f 11
extern TargetAgent ta_exp; // 0x440'00'600, id 0x06, irq_l3f 8
extern TargetAgent ta_edmatc0; // 0x440'00'700, id 0x07, irq_l3f 3
extern TargetAgent ta_edmatc1; // 0x440'00'800, id 0x08, irq_l3f 4
extern TargetAgent ta_edmatc2; // 0x440'00'900, id 0x09, irq_l3f 5
extern TargetAgent ta_l4hs_0; // 0x440'00'a00, id 0x05, irq_l3f 12
extern TargetAgent ta_edmacc; // 0x440'00'b00, id 0x0b, irq_l3f 6
extern TargetAgent ta_sgx; // 0x440'00'c00, id 0x0e, irq_l3f 13
extern TargetAgent ta_l3instr; // 0x440'00'd00, id 0x1f, irq_l3f 7
extern TargetAgent ta_pcie; // 0x440'00'e00, id 0x0f, irq_l3f 1
extern TargetAgent ta_emif; // 0x440'00'f00, id 0x01, irq_l3f 0
extern FlagCombiner irq_l3f; // 0x440'01'000, 14 ? { app, dbg }, irq_top 0
extern FlagCombiner irq_top; // 0x440'01'100, 2 ? { app, dbg }
extern Component stats0; // 0x440'02'000, size 0x800
extern Component stats1; // 0x440'03'000, size 0x1000
extern Component stats2; // 0x440'04'000, size 0x800
extern BwRegulator bwreg0; // 0x440'05'000
// L3S service network
extern HostAgent host_l3s; // 0x448'00'000, id 0x0c, no irq
extern TargetAgent ta_l4ls_0; // 0x448'00'100, id 0x11, irq_l3s 0
extern TargetAgent ta_l4ls_1; // 0x448'00'200, id 0x12, irq_l3s 1
extern TargetAgent ta_l4ls_2; // 0x448'00'300, id 0x13, irq_l3s 2
extern TargetAgent ta_l4ls_3; // 0x448'00'400, id 0x14, irq_l3s 3
extern TargetAgent ta_adc; // 0x448'00'500, id 0x0a, irq_l3s 10
extern FlagCombiner irq_l3s; // 0x448'00'600, 13 ? { app, dbg }, irq_top 1
extern TargetAgent ta_gpmc; // 0x448'00'700, id 0x1e, irq_l3s 7
extern TargetAgent ta_mcasp0; // 0x448'00'800, id 0x20, irq_l3s 4
extern TargetAgent ta_mcasp1; // 0x448'00'900, id 0x21, irq_l3s 5
extern TargetAgent ta_mcasp2; // 0x448'00'a00, id 0x22, irq_l3s 6
extern TargetAgent ta_usb; // 0x448'00'b00, id 0x27, irq_l3s 9
extern TargetAgent ta_mmc2; // 0x448'00'c00, id 0x26, irq_l3s 12
extern TargetAgent ta_l4fw; // 0x448'00'd00, id 0x1b, irq_l3s 8
extern TargetAgent ta_l4wk_0; // 0x448'00'e00, id 0x0d, irq_l3s 11
extern Component stats3; // 0x448'04'000, size 0x800
l3ls ports 1-3 are just extrapolation since they aren't reachable from
the cortex-A8, the rest is verified.
I also have a list of initiators needed to identify them from L3 error
logs. I obtained it from info I found floating around and haven't much
validated it yet:
// L3 initiator ids
enum iid6_t {
I6_HASS_0 = 0x00, // Cortex-A8, 128-bit port 0 to RAM
I6_HASS_1 = 0x01, // Cortex-A8, 64-bit port 1 to peripherals
I6_DAP = 0x04, // Debug access port (AHB-AP)
I6_DFT = 0x05, // Device functional test / IEEE1500
I6_PRUSS_0 = 0x0e, // PRU core 0
I6_PRUSS_1 = 0x0f, // PRU core 1
I6_MEDIALB = 0x10, // Media local bus (automotive only)
// I6_WKUPM3 = 0x14, // Wakeup-M3 (connects to l4wk, not l3)
I6_EDMATC0_R = 0x18, // EDMA transfer controller 0, read port
I6_EDMATC0_W = 0x19, // EDMA transfer controller 0, write port
I6_EDMATC1_R = 0x1a, // EDMA transfer controller 1, read port
I6_EDMATC1_W = 0x1b, // EDMA transfer controller 1, write port
I6_EDMATC2_R = 0x1c, // EDMA transfer controller 2, read port
I6_EDMATC2_W = 0x1d, // EDMA transfer controller 2, write port
I6_SGX = 0x20, // SGX-530 graphics accelerator
I6_LCDC = 0x24, // LCD controller DMA
I6_EXP = 0x2c, // Expansion (not usable or non-existent)
I6_ETH = 0x30, // Ethernet DMA
I6_USB_DMA = 0x34, // USB subsystem DMA, data
I6_USB_QMGR = 0x35, // USB subsystem DMA, queue manager
// I6_PCIE = 0x3a, // PCIe bridge (non-existent)
I6_STATCOLL_0 = 0x3c, // L3 statistics collector 0
I6_STATCOLL_1 = 0x3d, // L3 statistics collector 1
I6_STATCOLL_2 = 0x3e, // L3 statistics collector 2
I6_STATCOLL_3 = 0x3f, // L3 statistics collector 3
};
I don't know yet to which initiator bwreg0 belongs, nor any details for
the statistics collectors.
Matthijs
^ permalink raw reply
* [PATCH v5 1/3] hwmon: iio_hwmon: defer probe when no channel is found
From: Jonathan Cameron @ 2016-09-10 15:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <c29e256c-7bff-ac45-6ee5-1f21a33f22b2@roeck-us.net>
On 09/09/16 05:26, Guenter Roeck wrote:
> On 09/08/2016 07:28 AM, Quentin Schulz wrote:
>> iio_channel_get_all returns -ENODEV when it cannot find either phandles and
>> properties in the Device Tree or channels whose consumer_dev_name matches
>> iio_hwmon in iio_map_list. The iio_map_list is filled in by iio drivers
>> which might be probed after iio_hwmon.
>>
>> It is better to defer the probe of iio_hwmon if such error is returned by
>> iio_channel_get_all in order to let a chance to iio drivers to expose
>> channels in iio_map_list.
>>
>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>> ---
>>
>> v5:
>> - patch re-inserted,
>>
> Grumble ... applied to -next anyway.
>
> I'll direct any complaints your way ;-)
>
> Guenter
>
Thanks. I'll try and squeeze some time to look at a more general
solution (reworking how we set the maps up in the first place) if
no one else gets to it first!
It's on the list :)
Jonathan
^ permalink raw reply
* [PATCH v5 2/3] mfd: add support for Allwinner SoCs ADC
From: Jonathan Cameron @ 2016-09-10 15:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473344917-1524-3-git-send-email-quentin.schulz@free-electrons.com>
On 08/09/16 15:28, Quentin Schulz wrote:
> The Allwinner SoCs all have an ADC that can also act as a touchscreen
> controller and a thermal sensor. For now, only the ADC and the thermal
> sensor drivers are probed by the MFD, the touchscreen controller support
> will be added later.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
I'm happy with this now.
Lee, looking for an ack from you if you want me to take this through IIO.
If you'd prefer to take this and the next patch through MFD that's
fine with me.
Acked-by: Jonathan Cameron <jic23@kernel.org>
> ---
>
> v5:
> - correct mail address,
>
> v4:
> - rename files and variables from sunxi* to sun4i*,
> - rename defines from SUNXI_* to SUN4I_* or SUN6I_*,
> - remove TP in defines name,
> - rename SUNXI_IRQ_* to SUN4I_GPADC_IRQ_* for consistency,
> - use devm functions for regmap_add_irq_chip and mfd_add_devices,
> - remove remove functions (now empty thanks to devm functions),
>
> v3:
> - use defines in regmap_irq instead of hard coded BITs,
> - use of_device_id data field to chose which MFD cells to add considering
> the compatible responsible of the MFD probe,
> - remove useless initializations,
> - disable all interrupts before adding them to regmap_irqchip,
> - add goto error label in probe,
> - correct wrapping in header license,
> - move defines from IIO driver to header,
> - use GENMASK to limit the size of the variable passed to a macro,
> - prefix register BIT defines with the name of the register,
> - reorder defines,
>
> v2:
> - add license headers,
> - reorder alphabetically includes,
> - add SUNXI_GPADC_ prefixes for defines,
>
> drivers/mfd/Kconfig | 15 ++++
> drivers/mfd/Makefile | 2 +
> drivers/mfd/sun4i-gpadc-mfd.c | 174 ++++++++++++++++++++++++++++++++++++
> include/linux/mfd/sun4i-gpadc-mfd.h | 94 +++++++++++++++++++
> 4 files changed, 285 insertions(+)
> create mode 100644 drivers/mfd/sun4i-gpadc-mfd.c
> create mode 100644 include/linux/mfd/sun4i-gpadc-mfd.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 1bcf601..95b3c3e 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -29,6 +29,21 @@ config MFD_ACT8945A
> linear regulators, along with a complete ActivePath battery
> charger.
>
> +config MFD_SUN4I_GPADC
> + tristate "Allwinner sunxi platforms' GPADC MFD driver"
> + select MFD_CORE
> + select REGMAP_MMIO
> + depends on ARCH_SUNXI || COMPILE_TEST
> + help
> + Select this to get support for Allwinner SoCs (A10, A13 and A31) ADC.
> + This driver will only map the hardware interrupt and registers, you
> + have to select individual drivers based on this MFD to be able to use
> + the ADC or the thermal sensor. This will try to probe the ADC driver
> + sun4i-gpadc-iio and the hwmon driver iio_hwmon.
> +
> + To compile this driver as a module, choose M here: the module will be
> + called sun4i-gpadc-mfd.
> +
> config MFD_AS3711
> bool "AMS AS3711"
> select MFD_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 42a66e1..3b964d7 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -205,3 +205,5 @@ intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
> intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o
> obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
> obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
> +
> +obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc-mfd.o
> diff --git a/drivers/mfd/sun4i-gpadc-mfd.c b/drivers/mfd/sun4i-gpadc-mfd.c
> new file mode 100644
> index 0000000..b499545
> --- /dev/null
> +++ b/drivers/mfd/sun4i-gpadc-mfd.c
> @@ -0,0 +1,174 @@
> +/* ADC MFD core driver for sunxi platforms
> + *
> + * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/regmap.h>
> +
> +#include <linux/mfd/sun4i-gpadc-mfd.h>
> +
> +static struct resource adc_resources[] = {
> + {
> + .name = "FIFO_DATA_PENDING",
> + .start = SUN4I_GPADC_IRQ_FIFO_DATA,
> + .end = SUN4I_GPADC_IRQ_FIFO_DATA,
> + .flags = IORESOURCE_IRQ,
> + }, {
> + .name = "TEMP_DATA_PENDING",
> + .start = SUN4I_GPADC_IRQ_TEMP_DATA,
> + .end = SUN4I_GPADC_IRQ_TEMP_DATA,
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static const struct regmap_irq sun4i_gpadc_mfd_regmap_irq[] = {
> + REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_FIFO_DATA, 0,
> + SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN),
> + REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_TEMP_DATA, 0,
> + SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN),
> +};
> +
> +static const struct regmap_irq_chip sun4i_gpadc_mfd_regmap_irq_chip = {
> + .name = "sun4i_gpadc_mfd_irq_chip",
> + .status_base = SUN4I_GPADC_INT_FIFOS,
> + .ack_base = SUN4I_GPADC_INT_FIFOS,
> + .mask_base = SUN4I_GPADC_INT_FIFOC,
> + .init_ack_masked = true,
> + .mask_invert = true,
> + .irqs = sun4i_gpadc_mfd_regmap_irq,
> + .num_irqs = ARRAY_SIZE(sun4i_gpadc_mfd_regmap_irq),
> + .num_regs = 1,
> +};
> +
> +static struct mfd_cell sun4i_gpadc_mfd_cells[] = {
> + {
> + .name = "sun4i-a10-gpadc-iio",
> + .resources = adc_resources,
> + .num_resources = ARRAY_SIZE(adc_resources),
> + }, {
> + .name = "iio_hwmon",
> + }
> +};
> +
> +static struct mfd_cell sun5i_gpadc_mfd_cells[] = {
> + {
> + .name = "sun5i-a13-gpadc-iio",
> + .resources = adc_resources,
> + .num_resources = ARRAY_SIZE(adc_resources),
> + }, {
> + .name = "iio_hwmon",
> + },
> +};
> +
> +static struct mfd_cell sun6i_gpadc_mfd_cells[] = {
> + {
> + .name = "sun6i-a31-gpadc-iio",
> + .resources = adc_resources,
> + .num_resources = ARRAY_SIZE(adc_resources),
> + }, {
> + .name = "iio_hwmon",
> + },
> +};
> +
> +static const struct regmap_config sun4i_gpadc_mfd_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .fast_io = true,
> +};
> +
> +static const struct of_device_id sun4i_gpadc_mfd_of_match[] = {
> + {
> + .compatible = "allwinner,sun4i-a10-ts",
> + .data = &sun4i_gpadc_mfd_cells,
> + }, {
> + .compatible = "allwinner,sun5i-a13-ts",
> + .data = &sun5i_gpadc_mfd_cells,
> + }, {
> + .compatible = "allwinner,sun6i-a31-ts",
> + .data = &sun6i_gpadc_mfd_cells,
> + }, { /* sentinel */ }
> +};
> +
> +static int sun4i_gpadc_mfd_probe(struct platform_device *pdev)
> +{
> + struct sun4i_gpadc_mfd_dev *mfd_dev;
> + struct resource *mem;
> + const struct of_device_id *of_id;
> + const struct mfd_cell *mfd_cells;
> + unsigned int irq;
> + int ret;
> +
> + of_id = of_match_node(sun4i_gpadc_mfd_of_match, pdev->dev.of_node);
> + if (!of_id)
> + return -EINVAL;
> +
> + mfd_dev = devm_kzalloc(&pdev->dev, sizeof(*mfd_dev), GFP_KERNEL);
> + if (!mfd_dev)
> + return -ENOMEM;
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + mfd_dev->regs = devm_ioremap_resource(&pdev->dev, mem);
> + if (IS_ERR(mfd_dev->regs))
> + return PTR_ERR(mfd_dev->regs);
> +
> + mfd_dev->dev = &pdev->dev;
> + dev_set_drvdata(mfd_dev->dev, mfd_dev);
> +
> + mfd_dev->regmap = devm_regmap_init_mmio(mfd_dev->dev, mfd_dev->regs,
> + &sun4i_gpadc_mfd_regmap_config);
> + if (IS_ERR(mfd_dev->regmap)) {
> + ret = PTR_ERR(mfd_dev->regmap);
> + dev_err(&pdev->dev, "failed to init regmap: %d\n", ret);
> + return ret;
> + }
> +
> + /* Disable all interrupts */
> + regmap_write(mfd_dev->regmap, SUN4I_GPADC_INT_FIFOC, 0);
> +
> + irq = platform_get_irq(pdev, 0);
> + ret = devm_regmap_add_irq_chip(&pdev->dev, mfd_dev->regmap, irq,
> + IRQF_ONESHOT, 0,
> + &sun4i_gpadc_mfd_regmap_irq_chip,
> + &mfd_dev->regmap_irqc);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to add irq chip: %d\n", ret);
> + return ret;
> + }
> +
> + mfd_cells = of_id->data;
> + ret = devm_mfd_add_devices(mfd_dev->dev, 0, mfd_cells, 2, NULL, 0,
> + NULL);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to add MFD devices: %d\n", ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +MODULE_DEVICE_TABLE(of, sun4i_gpadc_mfd_of_match);
> +
> +static struct platform_driver sun4i_gpadc_mfd_driver = {
> + .driver = {
> + .name = "sun4i-adc-mfd",
> + .of_match_table = of_match_ptr(sun4i_gpadc_mfd_of_match),
> + },
> + .probe = sun4i_gpadc_mfd_probe,
> +};
> +
> +module_platform_driver(sun4i_gpadc_mfd_driver);
> +
> +MODULE_DESCRIPTION("Allwinner sunxi platforms' GPADC MFD core driver");
> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mfd/sun4i-gpadc-mfd.h b/include/linux/mfd/sun4i-gpadc-mfd.h
> new file mode 100644
> index 0000000..5cc7863
> --- /dev/null
> +++ b/include/linux/mfd/sun4i-gpadc-mfd.h
> @@ -0,0 +1,94 @@
> +/* Header of ADC MFD core driver for sunxi platforms
> + *
> + * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.mfd>
> + *
> + * 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 __SUN4I_GPADC_MFD__H__
> +#define __SUN4I_GPADC_MFD__H__
> +
> +#define SUN4I_GPADC_CTRL0 0x00
> +
> +#define SUN4I_GPADC_CTRL0_ADC_FIRST_DLY(x) ((GENMASK(7, 0) & (x)) << 24)
> +#define SUN4I_GPADC_CTRL0_ADC_FIRST_DLY_MODE BIT(23)
> +#define SUN4I_GPADC_CTRL0_ADC_CLK_SELECT BIT(22)
> +#define SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(x) ((GENMASK(1, 0) & (x)) << 20)
> +#define SUN4I_GPADC_CTRL0_FS_DIV(x) ((GENMASK(3, 0) & (x)) << 16)
> +#define SUN4I_GPADC_CTRL0_T_ACQ(x) (GENMASK(15, 0) & (x))
> +
> +#define SUN4I_GPADC_CTRL1 0x04
> +
> +#define SUN4I_GPADC_CTRL1_STYLUS_UP_DEBOUNCE(x) ((GENMASK(7, 0) & (x)) << 12)
> +#define SUN4I_GPADC_CTRL1_STYLUS_UP_DEBOUNCE_EN BIT(9)
> +#define SUN4I_GPADC_CTRL1_TOUCH_PAN_CALI_EN BIT(6)
> +#define SUN4I_GPADC_CTRL1_TP_DUAL_EN BIT(5)
> +#define SUN4I_GPADC_CTRL1_TP_MODE_EN BIT(4)
> +#define SUN4I_GPADC_CTRL1_TP_ADC_SELECT BIT(3)
> +#define SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(2, 0) & (x))
> +
> +/* TP_CTRL1 bits for sun6i SOCs */
> +#define SUN6I_GPADC_CTRL1_TOUCH_PAN_CALI_EN BIT(7)
> +#define SUN6I_GPADC_CTRL1_TP_DUAL_EN BIT(6)
> +#define SUN6I_GPADC_CTRL1_TP_MODE_EN BIT(5)
> +#define SUN6I_GPADC_CTRL1_TP_ADC_SELECT BIT(4)
> +#define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(3, 0) & BIT(x))
> +
> +#define SUN4I_GPADC_CTRL2 0x08
> +
> +#define SUN4I_GPADC_CTRL2_TP_SENSITIVE_ADJUST(x) ((GENMASK(3, 0) & (x)) << 28)
> +#define SUN4I_GPADC_CTRL2_TP_MODE_SELECT(x) ((GENMASK(1, 0) & (x)) << 26)
> +#define SUN4I_GPADC_CTRL2_PRE_MEA_EN BIT(24)
> +#define SUN4I_GPADC_CTRL2_PRE_MEA_THRE_CNT(x) (GENMASK(23, 0) & (x))
> +
> +#define SUN4I_GPADC_CTRL3 0x0c
> +
> +#define SUN4I_GPADC_CTRL3_FILTER_EN BIT(2)
> +#define SUN4I_GPADC_CTRL3_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
> +
> +#define SUN4I_GPADC_TPR 0x18
> +
> +#define SUN4I_GPADC_TPR_TEMP_ENABLE BIT(16)
> +#define SUN4I_GPADC_TPR_TEMP_PERIOD(x) (GENMASK(15, 0) & (x))
> +
> +#define SUN4I_GPADC_INT_FIFOC 0x10
> +
> +#define SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN BIT(18)
> +#define SUN4I_GPADC_INT_FIFOC_TP_OVERRUN_IRQ_EN BIT(17)
> +#define SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN BIT(16)
> +#define SUN4I_GPADC_INT_FIFOC_TP_DATA_XY_CHANGE BIT(13)
> +#define SUN4I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(x) ((GENMASK(4, 0) & (x)) << 8)
> +#define SUN4I_GPADC_INT_FIFOC_TP_DATA_DRQ_EN BIT(7)
> +#define SUN4I_GPADC_INT_FIFOC_TP_FIFO_FLUSH BIT(4)
> +#define SUN4I_GPADC_INT_FIFOC_TP_UP_IRQ_EN BIT(1)
> +#define SUN4I_GPADC_INT_FIFOC_TP_DOWN_IRQ_EN BIT(0)
> +
> +#define SUN4I_GPADC_INT_FIFOS 0x14
> +
> +#define SUN4I_GPADC_INT_FIFOS_TEMP_DATA_PENDING BIT(18)
> +#define SUN4I_GPADC_INT_FIFOS_FIFO_OVERRUN_PENDING BIT(17)
> +#define SUN4I_GPADC_INT_FIFOS_FIFO_DATA_PENDING BIT(16)
> +#define SUN4I_GPADC_INT_FIFOS_TP_IDLE_FLG BIT(2)
> +#define SUN4I_GPADC_INT_FIFOS_TP_UP_PENDING BIT(1)
> +#define SUN4I_GPADC_INT_FIFOS_TP_DOWN_PENDING BIT(0)
> +
> +#define SUN4I_GPADC_CDAT 0x1c
> +#define SUN4I_GPADC_TEMP_DATA 0x20
> +#define SUN4I_GPADC_DATA 0x24
> +
> +#define SUN4I_GPADC_IRQ_FIFO_DATA 0
> +#define SUN4I_GPADC_IRQ_TEMP_DATA 1
> +
> +/* 10s delay before suspending the IP */
> +#define SUN4I_GPADC_AUTOSUSPEND_DELAY 10000
> +
> +struct sun4i_gpadc_mfd_dev {
> + struct device *dev;
> + struct regmap *regmap;
> + struct regmap_irq_chip_data *regmap_irqc;
> + void __iomem *regs;
> +};
> +
> +#endif
>
^ permalink raw reply
* [PATCH v5 3/3] iio: adc: add support for Allwinner SoCs ADC
From: Jonathan Cameron @ 2016-09-10 15:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473344917-1524-4-git-send-email-quentin.schulz@free-electrons.com>
On 08/09/16 15:28, Quentin Schulz wrote:
> The Allwinner SoCs all have an ADC that can also act as a touchscreen
> controller and a thermal sensor. This patch adds the ADC driver which is
> based on the MFD for the same SoCs ADC.
>
> This also registers the thermal adc channel in the iio map array so
> iio_hwmon could use it without modifying the Device Tree. This registers
> the driver in the thermal framework.
>
> This driver probes on three different platform_device_id to take into
> account slight differences (registers bit and temperature computation)
> between Allwinner SoCs ADCs.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
(if Lee want's to take this through MFD - if I get an Ack from him
I'll pick it up through IIO).
> ---
>
> v5:
> - correct mail address,
> - correct several typos,
> - move from const to static for sunxi_gpadc_chan_select functions,
> - rename soc_specific struct to gpadc_data,
> - rename soc_specific field to data in sun4i_gpadc_dev,
> - return error code from regmap_write in case of failure in read_raws,
> - share if condition in IIO_CHAN_INFO_RAW case,
> - add comment on why we use parent device for registering in thermal,
> - reordering remove function,
>
> v4:
> - rename files and variables from sunxi* to sun4i*,
> - shorten sunxi_gpadc_soc_specific structure to soc_specific,
> - factorize sysfs ADC and temp read_raws,
> - use cached values when read_raw times out (except before a first value
> is gotten),
> - remove mutex locks and unlocks from runtime_pm functions,
> - factorize irq initializations,
> - initialize temp_data and fifo_data values to -1 (error value),
> - "impersonate" MFD to register in thermal framework,
> - deactivate hardware interrupts one by one when probe fails or when
> removing driver instead of blindly deactivating all hardware interrupts,
> - selects THERMAL_OF in Kconfig,
>
> v3:
> - correct wrapping,
> - add comment about thermal sensor inner working,
> - move defines in mfd header,
> - use structure to define SoC specific registers or behaviour,
> - attach this structure to the device according to of_device_id of the
> platform device,
> - use new mutex instead of iio_dev mutex,
> - use atomic flags to avoid race between request_irq and disable_irq in
> probe,
> - switch from processed value to raw, offset and scale values for
> temperature ADC channel,
> - remove faulty sentinel in iio_chan_spec array,
> - add pm_runtime support,
> - register thermal sensor in thermal framework (forgotten since the
> beginning whereas it is present in current sun4i-ts driver),
> - remove useless ret variables to store return value of regmap_reads,
> - move comments on thermal sensor acquisition period in code instead of
> header,
> - adding goto label to unregister iio_map_array when failing to register
> iio_dev,
>
> v2:
> - add SUNXI_GPADC_ prefixes for defines,
> - correct typo in Kconfig,
> - reorder alphabetically includes, makefile,
> - add license header,
> - fix architecture variations not being handled in interrupt handlers or
> read raw functions,
> - fix unability to return negative values from thermal sensor,
> - add gotos to reduce code repetition,
> - fix irq variable being unsigned int instead of int,
> - remove useless dev_err and dev_info,
> - deactivate all interrupts if probe fails,
> - fix iio_device_register on NULL variable,
> - deactivate ADC in the IP when probe fails or when removing driver,
>
> drivers/iio/adc/Kconfig | 13 +
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/sun4i-gpadc-iio.c | 543 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 557 insertions(+)
> create mode 100644 drivers/iio/adc/sun4i-gpadc-iio.c
>
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 25378c5..ea36a4f 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -384,6 +384,19 @@ config ROCKCHIP_SARADC
> To compile this driver as a module, choose M here: the
> module will be called rockchip_saradc.
>
> +config SUN4I_GPADC
> + tristate "Support for the Allwinner SoCs GPADC"
> + depends on IIO
> + depends on MFD_SUN4I_GPADC
> + select THERMAL_OF
> + help
> + Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
> + GPADC. This ADC provides 4 channels which can be used as an ADC or as
> + a touchscreen input and one channel for thermal sensor.
> +
> + To compile this driver as a module, choose M here: the module will be
> + called sun4i-gpadc-iio.
> +
> config TI_ADC081C
> tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
> depends on I2C
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 38638d4..204372d 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -37,6 +37,7 @@ obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
> obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
> obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
> obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
> +obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
> obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
> obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
> obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
> new file mode 100644
> index 0000000..74383eb
> --- /dev/null
> +++ b/drivers/iio/adc/sun4i-gpadc-iio.c
> @@ -0,0 +1,543 @@
> +/* ADC driver for sunxi platforms' (A10, A13 and A31) GPADC
> + *
> + * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation.
> + *
> + * The Allwinner SoCs all have an ADC that can also act as a touchscreen
> + * controller and a thermal sensor.
> + * The thermal sensor works only when the ADC acts as a touchscreen controller
> + * and is configured to throw an interrupt every fixed periods of time (let say
> + * every X seconds).
> + * One would be tempted to disable the IP on the hardware side rather than
> + * disabling interrupts to save some power but that resets the internal clock of
> + * the IP, resulting in having to wait X seconds every time we want to read the
> + * value of the thermal sensor.
> + * This is also the reason of using autosuspend in pm_runtime. If there was no
> + * autosuspend, the thermal sensor would need X seconds after every
> + * pm_runtime_get_sync to get a value from the ADC. The autosuspend allows the
> + * thermal sensor to be requested again in a certain time span before it gets
> + * shutdown for not being used.
> + */
> +
> +#include <linux/completion.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/thermal.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/driver.h>
> +#include <linux/iio/machine.h>
> +#include <linux/mfd/sun4i-gpadc-mfd.h>
> +
> +static unsigned int sun4i_gpadc_chan_select(unsigned int chan)
> +{
> + return SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
> +}
> +
> +static unsigned int sun6i_gpadc_chan_select(unsigned int chan)
> +{
> + return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
> +}
> +
> +struct gpadc_data {
> + int temp_offset;
> + int temp_scale;
> + unsigned int tp_mode_en;
> + unsigned int tp_adc_select;
> + unsigned int (*adc_chan_select)(unsigned int chan);
> +};
> +
> +static const struct gpadc_data sun4i_gpadc_data = {
> + .temp_offset = -1932,
> + .temp_scale = 133,
> + .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
> + .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
> + .adc_chan_select = &sun4i_gpadc_chan_select,
> +};
> +
> +static const struct gpadc_data sun5i_gpadc_data = {
> + .temp_offset = -1447,
> + .temp_scale = 100,
> + .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
> + .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
> + .adc_chan_select = &sun4i_gpadc_chan_select,
> +};
> +
> +static const struct gpadc_data sun6i_gpadc_data = {
> + .temp_offset = -1623,
> + .temp_scale = 167,
> + .tp_mode_en = SUN6I_GPADC_CTRL1_TP_MODE_EN,
> + .tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
> + .adc_chan_select = &sun6i_gpadc_chan_select,
> +};
> +
> +struct sun4i_gpadc_dev {
> + struct iio_dev *indio_dev;
> + void __iomem *regs;
> + struct completion completion;
> + int temp_data;
> + u32 adc_data;
> + struct regmap *regmap;
> + unsigned int fifo_data_irq;
> + atomic_t ignore_fifo_data_irq;
> + unsigned int temp_data_irq;
> + atomic_t ignore_temp_data_irq;
> + const struct gpadc_data *data;
> + /* prevents concurrent reads of temperature and ADC */
> + struct mutex mutex;
> +};
> +
> +#define SUN4I_GPADC_ADC_CHANNEL(_channel, _name) { \
> + .type = IIO_VOLTAGE, \
> + .indexed = 1, \
> + .channel = _channel, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .datasheet_name = _name, \
> +}
> +
> +static struct iio_map sun4i_gpadc_hwmon_maps[] = {
> + {
> + .adc_channel_label = "temp_adc",
> + .consumer_dev_name = "iio_hwmon.0",
> + },
> + { /* sentinel */ },
> +};
> +
> +static const struct iio_chan_spec sun4i_gpadc_channels[] = {
> + SUN4I_GPADC_ADC_CHANNEL(0, "adc_chan0"),
> + SUN4I_GPADC_ADC_CHANNEL(1, "adc_chan1"),
> + SUN4I_GPADC_ADC_CHANNEL(2, "adc_chan2"),
> + SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
> + {
> + .type = IIO_TEMP,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> + BIT(IIO_CHAN_INFO_SCALE) |
> + BIT(IIO_CHAN_INFO_OFFSET),
> + .datasheet_name = "temp_adc",
> + },
> +};
> +
> +static int sun4i_gpadc_read(struct iio_dev *indio_dev, int channel, int *val,
> + unsigned int irq)
> +{
> + struct sun4i_gpadc_dev *info = iio_priv(indio_dev);
> + int ret = 0;
> +
> + pm_runtime_get_sync(indio_dev->dev.parent);
> + mutex_lock(&info->mutex);
> +
> + reinit_completion(&info->completion);
> +
> + ret = regmap_write(info->regmap, SUN4I_GPADC_INT_FIFOC,
> + SUN4I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(1) |
> + SUN4I_GPADC_INT_FIFOC_TP_FIFO_FLUSH);
> + if (ret)
> + return ret;
> +
> + if (irq == info->fifo_data_irq) {
> + ret = regmap_write(info->regmap, SUN4I_GPADC_CTRL1,
> + info->data->tp_mode_en |
> + info->data->tp_adc_select |
> + info->data->adc_chan_select(channel));
> + } else {
> + /*
> + * The temperature sensor returns valid data only when the ADC
> + * operates in touchscreen mode.
> + */
> + ret = regmap_write(info->regmap, SUN4I_GPADC_CTRL1,
> + info->data->tp_mode_en);
> + }
> +
> + if (ret)
> + return ret;
> +
> + enable_irq(irq);
> +
> + if (!wait_for_completion_timeout(&info->completion,
> + msecs_to_jiffies(100))) {
> + if ((irq == info->fifo_data_irq && info->adc_data == -1) ||
> + (irq == info->temp_data_irq && info->temp_data == -1)) {
> + ret = -ETIMEDOUT;
> + goto out;
> + }
> + }
> +
> + if (irq == info->fifo_data_irq)
> + *val = info->adc_data;
> + else
> + *val = info->temp_data;
> +
> + ret = 0;
> +
> +out:
> + disable_irq(irq);
> + mutex_unlock(&info->mutex);
> + pm_runtime_mark_last_busy(indio_dev->dev.parent);
> + pm_runtime_put_autosuspend(indio_dev->dev.parent);
> +
> + return ret;
> +}
> +
> +static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
> + int *val)
> +{
> + struct sun4i_gpadc_dev *info = iio_priv(indio_dev);
> +
> + return sun4i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
> +}
> +
> +static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
> +{
> + struct sun4i_gpadc_dev *info = iio_priv(indio_dev);
> +
> + return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
> +}
> +
> +static int sun4i_gpadc_temp_offset(struct iio_dev *indio_dev, int *val)
> +{
> + struct sun4i_gpadc_dev *info = iio_priv(indio_dev);
> +
> + *val = info->data->temp_offset;
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_temp_scale(struct iio_dev *indio_dev, int *val)
> +{
> + struct sun4i_gpadc_dev *info = iio_priv(indio_dev);
> +
> + *val = info->data->temp_scale;
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_OFFSET:
> + ret = sun4i_gpadc_temp_offset(indio_dev, val);
> + if (ret)
> + return ret;
> +
> + return IIO_VAL_INT;
> + case IIO_CHAN_INFO_RAW:
> + if (chan->type == IIO_VOLTAGE)
> + ret = sun4i_gpadc_adc_read(indio_dev, chan->channel,
> + val);
> + else
> + ret = sun4i_gpadc_temp_read(indio_dev, val);
> +
> + if (ret)
> + return ret;
> +
> + return IIO_VAL_INT;
> + case IIO_CHAN_INFO_SCALE:
> + ret = sun4i_gpadc_temp_scale(indio_dev, val);
> + if (ret)
> + return ret;
> +
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static const struct iio_info sun4i_gpadc_iio_info = {
> + .read_raw = sun4i_gpadc_read_raw,
> + .driver_module = THIS_MODULE,
> +};
> +
> +static irqreturn_t sun4i_gpadc_temp_data_irq_handler(int irq, void *dev_id)
> +{
> + struct sun4i_gpadc_dev *info = dev_id;
> +
> + if (atomic_read(&info->ignore_temp_data_irq))
> + return IRQ_HANDLED;
> +
> + if (!regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, &info->temp_data))
> + complete(&info->completion);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
> +{
> + struct sun4i_gpadc_dev *info = dev_id;
> +
> + if (atomic_read(&info->ignore_fifo_data_irq))
> + return IRQ_HANDLED;
> +
> + if (!regmap_read(info->regmap, SUN4I_GPADC_DATA, &info->adc_data))
> + complete(&info->completion);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int sun4i_gpadc_runtime_suspend(struct device *dev)
> +{
> + struct sun4i_gpadc_dev *info = iio_priv(dev_get_drvdata(dev));
> +
> + /* Disable the ADC on IP */
> + regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0);
> + /* Disable temperature sensor on IP */
> + regmap_write(info->regmap, SUN4I_GPADC_TPR, 0);
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_runtime_resume(struct device *dev)
> +{
> + struct sun4i_gpadc_dev *info = iio_priv(dev_get_drvdata(dev));
> +
> + /* clkin = 6MHz */
> + regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
> + SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) |
> + SUN4I_GPADC_CTRL0_FS_DIV(7) |
> + SUN4I_GPADC_CTRL0_T_ACQ(63));
> + regmap_write(info->regmap, SUN4I_GPADC_CTRL1, info->data->tp_mode_en);
> + regmap_write(info->regmap, SUN4I_GPADC_CTRL3,
> + SUN4I_GPADC_CTRL3_FILTER_EN |
> + SUN4I_GPADC_CTRL3_FILTER_TYPE(1));
> + /* period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; ~1.3s */
> + regmap_write(info->regmap, SUN4I_GPADC_TPR,
> + SUN4I_GPADC_TPR_TEMP_ENABLE |
> + SUN4I_GPADC_TPR_TEMP_PERIOD(1953));
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_get_temp(void *data, int *temp)
> +{
> + struct sun4i_gpadc_dev *info = (struct sun4i_gpadc_dev *)data;
> + int val, scale, offset;
> +
> + /* If reading temperature times out, take stored previous value. */
> + if (sun4i_gpadc_temp_read(info->indio_dev, &val))
> + val = info->temp_data;
> + sun4i_gpadc_temp_scale(info->indio_dev, &scale);
> + sun4i_gpadc_temp_offset(info->indio_dev, &offset);
> +
> + *temp = (val + offset) * scale;
> +
> + return 0;
> +}
> +
> +static const struct thermal_zone_of_device_ops sun4i_ts_tz_ops = {
> + .get_temp = &sun4i_gpadc_get_temp,
> +};
> +
> +static const struct dev_pm_ops sun4i_gpadc_pm_ops = {
> + .runtime_suspend = &sun4i_gpadc_runtime_suspend,
> + .runtime_resume = &sun4i_gpadc_runtime_resume,
> +};
> +
> +static int sun4i_irq_init(struct platform_device *pdev, const char *name,
> + irq_handler_t handler, const char *devname,
> + unsigned int *irq, atomic_t *atomic)
> +{
> + int ret;
> + struct sun4i_gpadc_mfd_dev *mfd_dev = dev_get_drvdata(pdev->dev.parent);
> + struct sun4i_gpadc_dev *info = iio_priv(dev_get_drvdata(&pdev->dev));
> +
> + /*
> + * Once the interrupt is activated, the IP continuously performs
> + * conversions thus throws interrupts. The interrupt is activated right
> + * after being requested but we want to control when these interrupts
> + * occur thus we disable it right after being requested. However, an
> + * interrupt might occur between these two instructions and we have to
> + * make sure that does not happen, by using atomic flags. We set the
> + * flag before requesting the interrupt and unset it right after
> + * disabling the interrupt. When an interrupt occurs between these two
> + * instructions, reading the atomic flag will tell us to ignore the
> + * interrupt.
> + */
> + atomic_set(atomic, 1);
> +
> + *irq = platform_get_irq_byname(pdev, name);
> + if (*irq < 0) {
> + dev_err(&pdev->dev, "no %s interrupt registered\n", name);
> + return *irq;
> + }
> +
> + *irq = regmap_irq_get_virq(mfd_dev->regmap_irqc, *irq);
> + ret = devm_request_any_context_irq(&pdev->dev, *irq, handler, 0,
> + devname, info);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "could not request %s interrupt: %d\n",
> + name, ret);
> + return ret;
> + }
> +
> + disable_irq(*irq);
> + atomic_set(atomic, 0);
> +
> + return 0;
> +}
> +
> +static int sun4i_gpadc_probe(struct platform_device *pdev)
> +{
> + struct sun4i_gpadc_dev *info;
> + struct iio_dev *indio_dev;
> + int ret;
> + struct sun4i_gpadc_mfd_dev *sun4i_gpadc_mfd_dev;
> + struct thermal_zone_device *tzd;
> +
> + sun4i_gpadc_mfd_dev = dev_get_drvdata(pdev->dev.parent);
> +
> + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + info = iio_priv(indio_dev);
> + platform_set_drvdata(pdev, indio_dev);
> +
> + mutex_init(&info->mutex);
> + info->regmap = sun4i_gpadc_mfd_dev->regmap;
> + info->indio_dev = indio_dev;
> + info->temp_data = -1;
> + info->adc_data = -1;
> + init_completion(&info->completion);
> + indio_dev->name = dev_name(&pdev->dev);
> + indio_dev->dev.parent = &pdev->dev;
> + indio_dev->dev.of_node = pdev->dev.of_node;
> + indio_dev->info = &sun4i_gpadc_iio_info;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->num_channels = ARRAY_SIZE(sun4i_gpadc_channels);
> + indio_dev->channels = sun4i_gpadc_channels;
> +
> + info->data = (struct gpadc_data *)platform_get_device_id(pdev)->driver_data;
> +
> + /*
> + * This driver is a child of an MFD which has a node in the DT but not
> + * its children. Therefore, the resulting devices of this driver do not
> + * have an of_node variable.
> + * However, its parent (the MFD driver) has an of_node variable and
> + * since devm_thermal_zone_of_sensor_register uses its first argument to
> + * match the phandle defined in the node of the thermal driver with the
> + * of_node of the device passed as first argument and the third argument
> + * to call ops from thermal_zone_of_device_ops, the solution is to use
> + * the parent device as first argument to match the phandle with its
> + * of_node, and the device from this driver as third argument to return
> + * the temperature.
> + */
> + tzd = devm_thermal_zone_of_sensor_register(pdev->dev.parent, 0, info,
> + &sun4i_ts_tz_ops);
> + if (IS_ERR(tzd)) {
> + dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
> + PTR_ERR(tzd));
> + return PTR_ERR(tzd);
> + }
> +
> + pm_runtime_set_autosuspend_delay(&pdev->dev,
> + SUN4I_GPADC_AUTOSUSPEND_DELAY);
> + pm_runtime_use_autosuspend(&pdev->dev);
> + pm_runtime_set_suspended(&pdev->dev);
> + pm_runtime_enable(&pdev->dev);
> +
> + ret = sun4i_irq_init(pdev, "TEMP_DATA_PENDING",
> + sun4i_gpadc_temp_data_irq_handler, "temp_data",
> + &info->temp_data_irq, &info->ignore_temp_data_irq);
> + if (ret < 0)
> + goto err;
> +
> + ret = sun4i_irq_init(pdev, "FIFO_DATA_PENDING",
> + sun4i_gpadc_fifo_data_irq_handler, "fifo_data",
> + &info->fifo_data_irq, &info->ignore_fifo_data_irq);
> + if (ret < 0)
> + goto err_temp_irq;
> +
> + ret = iio_map_array_register(indio_dev, sun4i_gpadc_hwmon_maps);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to register iio map array\n");
> + goto err_fifo_irq;
> + }
> +
> + ret = iio_device_register(indio_dev);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "could not register the device\n");
> + goto err_map;
> + }
> +
> + return 0;
> +
> +err_map:
> + iio_map_array_unregister(indio_dev);
> +
> +err_fifo_irq:
> + /* Disable FIFO_DATA_PENDING interrupt on hardware side. */
> + regmap_update_bits(info->regmap, SUN4I_GPADC_INT_FIFOC,
> + SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN,
> + 0);
> +
> +err_temp_irq:
> + /* Disable TEMP_DATA_PENDING interrupt on hardware side. */
> + regmap_update_bits(info->regmap, SUN4I_GPADC_INT_FIFOC,
> + SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN,
> + 0);
> +
> +err:
> + pm_runtime_put(&pdev->dev);
> + pm_runtime_disable(&pdev->dev);
> +
> + return ret;
> +}
> +
> +static int sun4i_gpadc_remove(struct platform_device *pdev)
> +{
> + struct sun4i_gpadc_dev *info;
> + struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +
> + pm_runtime_put(&pdev->dev);
> + pm_runtime_disable(&pdev->dev);
> + info = iio_priv(indio_dev);
> + /*
> + * Disable TEMP_DATA_PENDING and FIFO_DATA_PENDING interrupts on
> + * hardware side.
> + */
> + regmap_update_bits(info->regmap, SUN4I_GPADC_INT_FIFOC,
> + SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN |
> + SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN,
> + 0);
> + iio_map_array_unregister(indio_dev);
> + iio_device_unregister(indio_dev);
> +
> + return 0;
> +}
> +
> +static const struct platform_device_id sun4i_gpadc_id[] = {
> + { "sun4i-a10-gpadc-iio", (kernel_ulong_t)&sun4i_gpadc_data },
> + { "sun5i-a13-gpadc-iio", (kernel_ulong_t)&sun5i_gpadc_data },
> + { "sun6i-a31-gpadc-iio", (kernel_ulong_t)&sun6i_gpadc_data },
> + { /* sentinel */ },
> +};
> +
> +static struct platform_driver sun4i_gpadc_driver = {
> + .driver = {
> + .name = "sun4i-gpadc-iio",
> + .pm = &sun4i_gpadc_pm_ops,
> + },
> + .id_table = sun4i_gpadc_id,
> + .probe = sun4i_gpadc_probe,
> + .remove = sun4i_gpadc_remove,
> +};
> +
> +module_platform_driver(sun4i_gpadc_driver);
> +
> +MODULE_DESCRIPTION("ADC driver for sunxi platforms");
> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
> +MODULE_LICENSE("GPL v2");
>
^ permalink raw reply
* [PATCH 3/4] dt-bindings: mmc: sdhci-st: Mention the discretionary "icn" clock
From: Lee Jones @ 2016-09-10 17:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPDyKFpgo2zy6CoQS=HfZMph_zKTM=ZSxzUkNeZ4due+CsMwoA@mail.gmail.com>
On 9 September 2016 at 12:50, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 8 September 2016 at 11:11, Lee Jones <lee.jones@linaro.org> wrote:
>> The interconnect (ICN) clock is required for functional working of
>> MMC on some ST platforms. When not supplied it can result in
>> broken MMC and the following output:
>>
>> [ 13.916949] mmc0: Timeout waiting for hardware interrupt.
>> [ 13.922349] sdhci: =========== REGISTER DUMP (mmc0)===========
>> [ 13.928175] sdhci: Sys addr: 0x00000000 | Version: 0x00001002
>> [ 13.933999] sdhci: Blk size: 0x00007040 | Blk cnt: 0x00000001
>> [ 13.939825] sdhci: Argument: 0x00fffff0 | Trn mode: 0x00000013
>> [ 13.945650] sdhci: Present: 0x1fff0206 | Host ctl: 0x00000011
>> [ 13.951475] sdhci: Power: 0x0000000f | Blk gap: 0x00000080
>> [ 13.957300] sdhci: Wake-up: 0x00000000 | Clock: 0x00003f07
>> [ 13.963126] sdhci: Timeout: 0x00000004 | Int stat: 0x00000000
>> [ 13.968952] sdhci: Int enab: 0x02ff008b | Sig enab: 0x02ff008b
>> [ 13.974777] sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
>> [ 13.980602] sdhci: Caps: 0x21ed3281 | Caps_1: 0x00000000
>> [ 13.986428] sdhci: Cmd: 0x0000063a | Max curr: 0x00000000
>> [ 13.992252] sdhci: Host ctl2: 0x00000000
>> [ 13.996166] sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x7c048200
>> [ 14.001990] sdhci: ===========================================
>> [ 14.009802] mmc0: Got data interrupt 0x02000000 even though no data operation was in progress.
>>
>> Signed-off-by: Lee Jones <lee.jones@linaro.org>
>> ---
>> Documentation/devicetree/bindings/mmc/sdhci-st.txt | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/sdhci-st.txt b/Documentation/devicetree/bindings/mmc/sdhci-st.txt
>> index 88faa91..3cd4c43 100644
>> --- a/Documentation/devicetree/bindings/mmc/sdhci-st.txt
>> +++ b/Documentation/devicetree/bindings/mmc/sdhci-st.txt
>> @@ -10,7 +10,7 @@ Required properties:
>> subsystem (mmcss) inside the FlashSS (available in STiH407 SoC
>> family).
>>
>> -- clock-names: Should be "mmc".
>> +- clock-names: Should be "mmc" and "icn". (NB: The latter is not compulsory)
>> See: Documentation/devicetree/bindings/resource-names.txt
>> - clocks: Phandle to the clock.
>> See: Documentation/devicetree/bindings/clock/clock-bindings.txt
>> --
>> 2.9.3
>>
>
> This looks good to me!
>
> I am guessing you want this to go through my mmc tree, as I think
> patch 3 and patch 4 should go together. If not, tell me.
That's correct, thanks.
--
Lee Jones
Linaro ST Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH v1 0/2] Add two automotive field Evaluation boards from rockchip
From: Andy Yan @ 2016-09-10 17:40 UTC (permalink / raw)
To: linux-arm-kernel
Changes in v1:
- board rename
- add vendor prefix for i2c interfaced sensors
- use stdout-path to set the default console
Andy Yan (2):
ARM: dts: add rockchip PX3 Evaluation board
arm64: dts: rockchip: Add PX5 Evaluation board
Documentation/devicetree/bindings/arm/rockchip.txt | 8 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/rk3188-px3-evb.dts | 337 +++++++++++++++++++++
arch/arm64/boot/dts/rockchip/Makefile | 1 +
arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts | 304 +++++++++++++++++++
5 files changed, 651 insertions(+)
create mode 100644 arch/arm/boot/dts/rk3188-px3-evb.dts
create mode 100644 arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts
--
2.7.4
^ permalink raw reply
* [PATCH v1 1/2] ARM: dts: add rockchip PX3 Evaluation board
From: Andy Yan @ 2016-09-10 17:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473529249-6151-1-git-send-email-andy.yan@rock-chips.com>
PX3 EVB is designed by Rockchip for automotive field,
which intergrated with CVBS(TP2825)/MIPI DSI/LVDS/HDMI
video input/output interface, WIFI/BT/GPS(on a module
named S500 which based on MT6620), Gsensor BMA250E and
light&proximity sensor STK3410.
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
---
Changes in v1:
- board rename
- add vendor prefix for i2c interfaced sensors
- use stdout-path to set the default console
Documentation/devicetree/bindings/arm/rockchip.txt | 4 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/rk3188-px3-evb.dts | 337 +++++++++++++++++++++
3 files changed, 342 insertions(+)
create mode 100644 arch/arm/boot/dts/rk3188-px3-evb.dts
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index 6668645..6da3881 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -21,6 +21,10 @@ Rockchip platforms device tree bindings
Required root node properties:
- compatible = "radxa,rock", "rockchip,rk3188";
+- Rockchip PX3 Evaluation board:
+ Required root node properties:
+ - compatible = "rockchip,px3-evb", "rockchip,px3", "rockchip,rk3188";
+
- Radxa Rock2 Square board:
Required root node properties:
- compatible = "radxa,rock2-square", "rockchip,rk3288";
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index faacd52..88d27a2 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -620,6 +620,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rk3066a-marsboard.dtb \
rk3066a-rayeager.dtb \
rk3188-radxarock.dtb \
+ rk3188-px3-evb.dtb \
rk3228-evb.dtb \
rk3229-evb.dtb \
rk3288-evb-act8846.dtb \
diff --git a/arch/arm/boot/dts/rk3188-px3-evb.dts b/arch/arm/boot/dts/rk3188-px3-evb.dts
new file mode 100644
index 0000000..f6bc738
--- /dev/null
+++ b/arch/arm/boot/dts/rk3188-px3-evb.dts
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2016 Andy Yan <andy.yan@rock-chips.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include "rk3188.dtsi"
+
+/ {
+ model = "Rockchip PX3-EVB";
+ compatible = "rockchip,px3-evb", "rockchip,px3", "rockchip,rk3188";
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x80000000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ autorepeat;
+
+ power {
+ gpios = <&gpio0 4 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_POWER>;
+ label = "GPIO Key Power";
+ linux,input-type = <1>;
+ wakeup-source;
+ debounce-interval = <100>;
+ };
+ };
+
+ vcc_sys: vsys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vsys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ };
+};
+
+&cpu0 {
+ cpu0-supply = <&vdd_cpu>;
+};
+
+&i2c0 {
+ status = "okay";
+
+ /* Accelerometer */
+ bma250 at 18 {
+ compatible = "bosch,bma250";
+ reg = <0x18>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ stk3410 at 48 {
+ compatible = "sensortek,STK3310";
+ reg = <0x48>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&i2c1 {
+ status = "okay";
+ clock-frequency = <400000>;
+ rk808: pmic at 1c {
+ compatible = "rockchip,rk818";
+ reg = <0x1c>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ rockchip,system-power-controller;
+ wakeup-source;
+ #clock-cells = <1>;
+ clock-output-names = "xin32k", "rk808-clkout2";
+
+ vcc1-supply = <&vcc_sys>;
+ vcc2-supply = <&vcc_sys>;
+ vcc3-supply = <&vcc_sys>;
+ vcc4-supply = <&vcc_sys>;
+ vcc6-supply = <&vcc_sys>;
+ vcc7-supply = <&vcc_sys>;
+ vcc8-supply = <&vcc_io>;
+ vcc9-supply = <&vcc_io>;
+
+ regulators {
+ vdd_cpu: DCDC_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-name = "vdd_arm";
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_gpu: DCDC_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd_gpu";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_ddr";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ vcc_io: DCDC_REG4 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_io";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ vcc_cif: LDO_REG1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_cif";
+ };
+
+ vcc_jetta33: LDO_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_jetta33";
+ };
+
+ vdd_10: LDO_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vdd_10";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1000000>;
+ };
+ };
+
+ lvds_12: LDO_REG4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "lvds_12";
+ };
+
+ lvds_25: LDO_REG5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "lvds_25";
+ };
+
+ cif_18: LDO_REG6 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "cif_18";
+ };
+
+ vcc_sd: LDO_REG7 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_sd";
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <3300000>;
+ };
+ };
+
+ wl_18: LDO_REG8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "wl_18";
+ };
+
+ lcd_33: SWITCH_REG1 {
+ regulator-name = "lcd_33";
+ };
+ };
+ };
+
+};
+
+&i2c2 {
+ gsl1680: touchscreen at 40 {
+ compatible = "silead,gsl1680";
+ reg = <0x40>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
+ power-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
+ touchscreen-size-x = <800>;
+ touchscreen-size-y = <1280>;
+ silead,max-fingers = <5>;
+ };
+};
+
+&emmc {
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ disable-wp;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk>, <&emmc_cmd>, <&emmc_rst>;
+ status = "okay";
+};
+
+&mmc0 {
+ num-slots = <1>;
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
+ vmmc-supply = <&vcc_sd>;
+
+ bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
+ disable-wp;
+};
+
+&pwm1 {
+ status = "okay";
+};
+
+&pwm2 {
+ status = "okay";
+};
+
+&pwm3 {
+ status = "okay";
+};
+
+&pinctrl {
+ pcfg_output_low: pcfg-output-low {
+ output-low;
+ };
+
+ usb {
+ host_vbus_drv: host-vbus-drv {
+ rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ otg_vbus_drv: otg-vbus-drv {
+ rockchip,pins = <2 31 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+&usb_host {
+ status = "okay";
+};
+
+&usb_otg {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
--
2.7.4
^ permalink raw reply related
* [PATCH v1 2/2] arm64: dts: rockchip: Add PX5 Evaluation board
From: Andy Yan @ 2016-09-10 17:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473529249-6151-1-git-send-email-andy.yan@rock-chips.com>
PX5 EVB is designed by Rockchip for automotive field,
which intergrated with CVBS(TP2825)/MIPI DSI/CSI/LVDS
HDMI video input/output interface, audio codec ES8396,
WIFI/BT(on RTL8723BS), Gsensor BMA250E and light&proximity
sensor STK3410.
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
---
Changes in v1:
- board rename
- add vendor prefix for i2c interfaced devices
Documentation/devicetree/bindings/arm/rockchip.txt | 4 +
arch/arm64/boot/dts/rockchip/Makefile | 1 +
arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts | 304 +++++++++++++++++++++
3 files changed, 309 insertions(+)
create mode 100644 arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index 6da3881..b6f92d6 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -107,6 +107,10 @@ Rockchip platforms device tree bindings
Required root node properties:
- compatible = "rockchip,r88", "rockchip,rk3368";
+- Rockchip PX5 Evaluation board:
+ Required root node properties:
+ - compatible = "rockchip,px5-evb", "rockchip,px5", "rockchip,rk3368";
+
- Rockchip RK3228 Evaluation board:
Required root node properties:
- compatible = "rockchip,rk3228-evb", "rockchip,rk3228";
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 7037a16..86c74b2 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -1,6 +1,7 @@
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-evb-act8846.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-geekbox.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-px5-evb.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-evb.dtb
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts b/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts
new file mode 100644
index 0000000..be0e915
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3368.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Rockchip PX5 EVB";
+ compatible = "rockchip,px5-evb", "rockchip,px5", "rockchip,rk3368";
+
+ chosen {
+ stdout-path = "serial4:115200n8";
+ };
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+
+ keys: gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwr_key>;
+
+ power {
+ gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
+ label = "GPIO Power";
+ linux,code = <KEY_POWER>;
+ wakeup-source;
+ };
+ };
+
+ vcc_sys: vcc-sys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_sys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&emmc {
+ status = "okay";
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ clock-frequency = <150000000>;
+ disable-wp;
+ keep-power-in-suspend;
+ non-removable;
+ num-slots = <1>;
+ vmmc-supply = <&vcc_io>;
+ vqmmc-supply = <&vcc18_flash>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk>, <&emmc_cmd>, <&emmc_bus8>;
+};
+
+&i2c0 {
+ status = "okay";
+
+ rk808: pmic at 1b {
+ compatible = "rockchip,rk808";
+ reg = <0x1b>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int>, <&pmic_sleep>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+ rockchip,system-power-controller;
+ vcc1-supply = <&vcc_sys>;
+ vcc2-supply = <&vcc_sys>;
+ vcc3-supply = <&vcc_sys>;
+ vcc4-supply = <&vcc_sys>;
+ vcc6-supply = <&vcc_sys>;
+ vcc7-supply = <&vcc_sys>;
+ vcc8-supply = <&vcc_io>;
+ vcc9-supply = <&vcc_sys>;
+ vcc10-supply = <&vcc_sys>;
+ vcc11-supply = <&vcc_sys>;
+ vcc12-supply = <&vcc_io>;
+ clock-output-names = "xin32k", "rk808-clkout2";
+ #clock-cells = <1>;
+
+ regulators {
+ vdd_cpu: DCDC_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vdd_cpu";
+ };
+
+ vdd_log: DCDC_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vdd_log";
+ };
+
+ vcc_ddr: DCDC_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_ddr";
+ };
+
+ vcc_io: DCDC_REG4 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_io";
+ };
+
+ vcc18_flash: LDO_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc18_flash";
+ };
+
+ vcca_33: LDO_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcca_33";
+ };
+
+ vdd_10: LDO_REG3 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vdd_10";
+ };
+
+ avdd_33: LDO_REG4 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avdd_33";
+ };
+
+ vccio_sd: LDO_REG5 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vccio_sd";
+ };
+
+ vdd10_lcd: LDO_REG6 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-name = "vdd10_lcd";
+ };
+
+ vcc_18: LDO_REG7 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc_18";
+ };
+
+ vcc18_lcd: LDO_REG8 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc18_lcd";
+ };
+
+ vcc_sd: SWITCH_REG1 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc_sd";
+ };
+
+ vcc33_lcd: SWITCH_REG2 {
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-name = "vcc33_lcd";
+ };
+ };
+ };
+};
+
+&i2c1 {
+ status = "okay";
+
+ /* Accelerometer */
+ bma250 at 18 {
+ compatible = "bosch,bma250";
+ reg = <0x18>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ stk3410 at 48 {
+ compatible = "sensortek,STK3310";
+ reg = <0x48>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+
+ gsl1680: touchscreen at 40 {
+ compatible = "silead,gsl1680";
+ reg = <0x40>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <28 IRQ_TYPE_EDGE_FALLING>;
+ power-gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
+ touchscreen-size-x = <800>;
+ touchscreen-size-y = <1280>;
+ silead,max-fingers = <5>;
+ };
+};
+
+&pinctrl {
+
+ keys {
+ pwr_key: pwr-key {
+ rockchip,pins = <0 2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ pmic_sleep: pmic-sleep {
+ rockchip,pins = <0 0 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ pmic_int: pmic-int {
+ rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+};
+
+&tsadc {
+ status = "okay";
+ rockchip,hw-tshut-mode = <0>; /* CRU */
+ rockchip,hw-tshut-polarity = <1>; /* high */
+};
+
+&uart4 {
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_otg {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox