diff --git a/arm64-force-serial-to-be-active-consdev.patch b/arm64-force-serial-to-be-active-consdev.patch new file mode 100644 index 0000000..203dcef --- /dev/null +++ b/arm64-force-serial-to-be-active-consdev.patch @@ -0,0 +1,84 @@ +From rharm-kernel-patches-bounces@redhat.com Fri Nov 21 18:21:38 2014 +From: Mark Salter +To: rharm-kernel-patches@redhat.com +Subject: [PATCH] tty/pl011: make ttyAMA0 the active console device +Date: Fri, 21 Nov 2014 18:21:30 -0500 +Message-Id: <1416612090-31594-1-git-send-email-msalter@redhat.com> + +Upstream: No. Temporary workaround to avoid console= +Testing: Seattle booting with devicetree + +The pl011 uart driver doesn't register itself as a console +until device_initcall time. This allows the virtual console +driver to register the active console if no console= is +given on the cmdline. This patch allows ttyAMA0 to take +over the active console device role from any existing +console device if no console= is given on the cmdline. + +Signed-off-by: Mark Salter +--- + drivers/tty/serial/amba-pl011.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 8572f2a..454aa26 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2182,7 +2182,15 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) + } + } + ++ /* ++ * temp hack to avoid need for console= on cmdline ++ * this can go away when we switch completely to acpi ++ */ ++ if (amba_reg.cons && !console_set_on_cmdline && uap->port.line == 0) ++ amba_reg.cons->flags |= CON_CONSDEV; + ret = uart_add_one_port(&amba_reg, &uap->port); ++ if (amba_reg.cons && !console_set_on_cmdline && uap->port.line == 0) ++ amba_reg.cons->flags &= ~CON_CONSDEV; + if (ret) { + amba_ports[i] = NULL; + uart_unregister_driver(&amba_reg); +-- +1.9.3 + +From rharm-kernel-patches-bounces@redhat.com Tue Nov 18 22:09:42 2014 +From: Mark Salter +To: rharm-kernel-patches@redhat.com +Subject: [PATCH v2] tty/sbsauart: make ttySBSA the active console device +Date: Tue, 18 Nov 2014 22:09:04 -0500 +Message-Id: <1416366544-31116-2-git-send-email-msalter@redhat.com> + +The sbsauart driver doesn't register itself as a console +until module_initcall time. This allows the virtual console +driver to register the active console if no console= is +given on the cmdline. This patch allows ttySBSA to take +over the active console device role from any existing +console device if no console= is given on the cmdline. + +Upstream: No +Testing: Seattle and Foundation Model + +Signed-off-by: Mark Salter +--- + drivers/tty/sbsauart.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/tty/sbsauart.c b/drivers/tty/sbsauart.c +index 3a3ff88..e7d35d5 100644 +--- a/drivers/tty/sbsauart.c ++++ b/drivers/tty/sbsauart.c +@@ -280,6 +280,9 @@ static int sbsa_tty_probe(struct platform_device *pdev) + qtty->console.device = sbsa_tty_console_device; + qtty->console.setup = sbsa_tty_console_setup; + qtty->console.flags = CON_PRINTBUFFER; ++ /* if no console= on cmdline, make this the console device */ ++ if (!console_set_on_cmdline) ++ qtty->console.flags |= CON_CONSDEV; + qtty->console.index = pdev->id; + register_console(&qtty->console); + +-- +1.9.3 + diff --git a/kernel-arm64.patch b/kernel-arm64.patch index a05aa33..eeb1dcf 100644 --- a/kernel-arm64.patch +++ b/kernel-arm64.patch @@ -1,1335 +1,419 @@ -commit 87257d3e584fad0b47e6304da54a1932f42b11bb -Author: Mark Salter -Date: Tue Sep 30 17:19:24 2014 -0400 - - arm64: avoid need for console= to enable serial console - - Tell kernel to prefer one of the serial ports on platforms - pl011, 8250, or sbsa uarts. console= on command line will - override these assumed preferences. - - Signed-off-by: Mark Salter - -commit 56db24589d311ea3590527030ede007ec339e2d7 -Author: Tom Lendacky -Date: Tue Sep 9 23:33:17 2014 -0400 - - drivers: net: AMD Seattle XGBE PHY support for A0 silicon - - This patch modifies the upstream AMD XGBE PHY driver to support - A0 Seattle silicon in currently shipping systems. The upstream - Linux driver is targetted for Seattle B0 silicon. - - Signed-off-by: Mark Salter - -commit 75554bb2e3c433a47e172d81a0b59df58810dc01 -Author: Tom Lendacky -Date: Tue Sep 9 23:34:07 2014 -0400 - - drivers: net: AMD Seattle XGBE 10GbE support for A0 silicon - - This patch modifies the upstream AMD 10GbE XGBE Ethernet driver to - support A0 Seattle silicon in currently shipping systems. The - upstream Linux driver is targetted for Seattle B0 silicon. - - Signed-off-by: Mark Salter - -commit 41cb1b3c9e62256b8a4e92c50cd51b2a68d0c9c6 -Author: Graeme Gregory -Date: Fri Jul 26 17:55:02 2013 +0100 - - virtio-mmio: add ACPI probing - - Added the match table and pointers for ACPI probing to the driver. - - Signed-off-by: Graeme Gregory - -commit c06502fb4f00c6996c1f55cd342288508808c678 -Author: Graeme Gregory -Date: Wed Jul 24 11:29:48 2013 +0100 - - net: smc91x: add ACPI probing support. - - Add device ID LINA0003 for this device and add the match table. - - As its a platform device it needs no other code and will be probed in by - acpi_platform once device ID is added. - - Signed-off-by: Graeme Gregory - -commit aad559613ff05a13f940129675659297e7125979 -Author: Mark Salter -Date: Tue Sep 23 12:48:48 2014 -0400 - - arm64/pci: add coherency inheritance for pci devices - - Signed-off-by: Mark Salter - -commit 8d2a4226d96ccae17fbc0ef7d7d9c5a07ad8b31f -Author: Mark Salter -Date: Tue Sep 23 12:35:17 2014 -0400 - - arm64/acpi: make acpi disabled by default - - Signed-off-by: Mark Salter - -commit 0553f2b9fc94bfb0f9038003ad6f150cca196aad -Author: Wei Huang -Date: Thu Sep 18 20:32:03 2014 -0400 - - KVM: fix VTTBR_BADDR_MASK - - The following is patch from AMD to fix VTTBR_BADDR_MASK. According to - AMD, this patch is required to enable KVM on Seattle. - - The current VTTBR_BADDR_MASK only masks 39 bits, which is broken on current - systems. Rather than just add a bit it seems like a good time to also set - things at run-time instead of compile time to accomodate more hardware. - - This patch sets TCR_EL2.PS, VTCR_EL2.T0SZ and vttbr_baddr_mask in runtime, - not compile time. - - In ARMv8, EL2 physical address size (TCR_EL2.PS) and stage2 input address - size (VTCR_EL2.T0SZE) cannot be determined in compile time since they - depend on hardware capability. - - According to Table D4-23 and Table D4-25 in ARM DDI 0487A.b document, - vttbr_x is calculated using different fixed values with consideration - of T0SZ, granule size and the level of translation tables. Therefore, - vttbr_baddr_mask should be determined dynamically. - - Changes since v5: - Fixed declaration of vttbr_baddr_mask to not create multiple instances - Refactored return codes based on feedback - For 32 bit included kvm_arm.h in kvm_mmu.h to explictly pick up - VTTBR_BADDR_MASK - - Changes since v4: - More minor cleanups from review - Moved some functions into headers - Added runtime check in kvm_alloc_stage2_pgd - - Changes since v3: - Another rebase - Addressed minor comments from v2 - - Changes since v2: - Rebased on https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git next branch - - Changes since v1: - Rebased fix on Jungseok Lee's patch https://lkml.org/lkml/2014/5/12/189 to - provide better long term fix. Updated that patch to log error instead of - silently fail on unaligned vttbr. - - Cc: Marc Zyngier - Cc: Christoffer Dall - Cc: Sungjinn Chung - Signed-off-by: Jungseok Lee - Signed-off-by: Joel Schopp - - Signed-off-by: Wei Huang - -commit f53d1278fe445b7130f1ff76b2f453b453368284 -Author: Wei Huang -Date: Thu Sep 18 20:02:57 2014 -0400 - - KVM/ACPI: Enable ACPI support for KVM virt GIC - - This patches enables ACPI support for KVM virtual GIC. KVM parses - ACPI table for virt GIC related information when DT table is not - present. This is done by retrieving the information defined in - generic_interrupt entry of MADT table. - - Note: Alexander Spyridakis from Virtual Open System posts a - _very_ similar patch to enable acpi-kvm. This patch borrows some - ideas from his patch. - - Signed-off-by: Wei Huang - -commit ba63e452ff5b09cc0314f94e163a51c3279b9ca7 -Author: Wei Huang -Date: Thu Sep 18 20:02:56 2014 -0400 - - KVM/ACPI: Enable ACPI support for virt arch timer - - This patches enables ACPI support for KVM virtual arch_timer. It - allows KVM to parse ACPI table for virt arch_timer PPI when DT table - is not present. This is done by retrieving the information from - arch_timer_ppi array in arm_arch_timer driver. - - Signed-off-by: Wei Huang - -commit dd3f6094c2142786f40a3bc4d69c60b430ecc675 -Author: Wei Huang -Date: Thu Sep 18 20:02:55 2014 -0400 - - KVM/ACPI: Add kernel parameter kvmacpi to enable KVM ACPI support - - This patch addes a new kernel parameter, kvmacpi, to turn on ACPI - support for KVM. Users can enable it using "kvmacpi=on" in command - line. When it is on, KVM will will parse ACPI tables to configure related - components. By default this option is off. - - Note that DT will be probed first, no matter kvmacpi is ON or OFF. - This is because many platforms, such qemu/kvm, still supports - DT only. We still want to support Acadia kernel on such platforms. - - Signed-off-by: Wei Huang - -commit cdfc19f1fbe88c1610db790ad55318d55ab00ee9 -Author: Mark Salter -Date: Thu Sep 18 21:13:05 2014 -0400 - - arm64/pci: fix dma coherency inheritance for PCI devices - - The default dma_ops for devices on arm64 systems are noncoherent in - nature and rely upon special operations and bounce buffers to - perform a device DMA operation to/from memory. Some drivers rely - upon coherent operations involving suitably capable hardware. In - this case, a "dma-coherent" property will exist on the corresponding - Device Tree node for the bridge device, or one of its ancestors. - This patch adds support for applying a DMA coherent dma_ops for - PCI devices in the case of such a property. - - Signed-off-by: Mark Salter - -commit c8a62324eba5718fb43a94a168de7a81787aa94d -Author: Mark Salter -Date: Thu Sep 18 15:05:23 2014 -0400 - - arm64: add sev to parking protocol - - Parking protocol wakes secondary cores with an interrupt. - This patch adds an additional sev() to send an event. This - is a temporary hack for APM Mustang board and not intended - for upstream. - - Signed-off-by: Mark Salter - -commit e5f4ba1223515c46f1875597e77d5c32a37829ee -Author: Mark Salter -Date: Sun Sep 14 09:44:44 2014 -0400 - - Revert "ahci_xgene: Skip the PHY and clock initialization if already configured by the firmware." - - This reverts commit 0bed13bebd6c99d097796d2ca6c4f10fb5b2eabc. - - Temporarily revert for backwards compatibility with rh-0.12-1 firmware - -commit aeff595a5d57264e5f01add5c43f584d88be6a92 -Author: Mark Salter -Date: Mon Aug 11 13:46:43 2014 -0400 - - xgene: add support for ACPI-probed serial port - -commit 02429d239f5ae917d870a7611a9d838b7822df1a -Author: Mark Salter -Date: Sat Aug 9 12:01:20 2014 -0400 - - sata/xgene: support acpi probing - - Signed-off-by: Mark Salter - -commit 774385f250ebb7448ca3eeb344a064ac989c4988 -Author: Hanjun Guo -Date: Thu Aug 28 14:26:16 2014 -0400 - - ARM64 / ACPI: Introduce some PCI functions when PCI is enabled - - Introduce some PCI functions to make ACPI can be compiled when - CONFIG_PCI is enabled, these functions should be revisited when - implemented on ARM64. - - Signed-off-by: Hanjun Guo - [fixed up for 3.17-rc] - Signed-off-by: Mark Salter - -commit 6f711c98b37f1b0a42c4a523d0380d47ed2f95b9 -Author: Al Stone -Date: Thu Aug 28 13:14:16 2014 -0400 - - Fix arm64 compilation error in PNP code - - Signed-off-by: Mark Salter - -commit f874873b7cb10f827bb7f8e08fa282878f740e77 -Author: Bob Moore -Date: Tue Sep 2 08:27:40 2014 +0800 - - ACPICA: Update version to 20140828. - - Version 20140828. - - Signed-off-by: Bob Moore - Signed-off-by: Lv Zheng - -commit 26f9b7b90576cf808a50edf1ec86ceece9349c9f -Author: Bob Moore -Date: Tue Sep 2 08:27:27 2014 +0800 - - ACPICA: Disassembler: Fix for gpio_int interrupt polarity flags. - - The field is actually 2 bits, not 1. - - Signed-off-by: Bob Moore - Signed-off-by: Lv Zheng - -commit 6e1eddc48f6f9b948be4126dd38841f6f70da080 -Author: Hanjun Guo -Date: Tue Sep 2 08:27:19 2014 +0800 - - ACPICA: Headers: Add GTDT flag definitions for the timer subtable. - - Mostly by Hanjun Guo - - Signed-off-by: Hanjun Guo - Signed-off-by: Bob Moore - Signed-off-by: Lv Zheng - -commit 1091460efb5542ba87f40ef20daff44215587f26 -Author: Hanjun Guo -Date: Tue Sep 2 08:27:12 2014 +0800 - - ACPICA: ACPI 5.1/Disassembler: Add GICC affinity subtable to SRAT table. - - Update template for SRAT. - Add clock_domain to standard CPU affinity subtable. - - Mostly by Hanjun Guo - - Signed-off-by: Hanjun Guo - Signed-off-by: Bob Moore - Signed-off-by: Lv Zheng - -commit 02ba5e067dbb83b0f481db821d05851e9623c401 -Author: Bob Moore -Date: Tue Sep 2 08:27:05 2014 +0800 - - ACPICA: Add _PSx names to the METHOD_NAME list. - - Will be used by iASL. - - Signed-off-by: Bob Moore - Signed-off-by: Lv Zheng - -commit f2ecef6608a1f74b236df4f93da9b7b5aba4d3fd -Author: Mark Salter -Date: Tue Sep 9 22:59:48 2014 -0400 - - arm64: add parking protocol support - - This is a first-cut effort at parking protocol support. It is - very much a work in progress (as is the spec it is based on). - This code deviates from the current spec in a number of ways - to work around current firmware issues and issues with kernels - using 64K page sizes. - - caveat utilitor - - Signed-off-by: Mark Salter - -commit 63e220c94f072f10bfae2e1ed375af9dbc017571 -Author: Suravee Suthikulpanit -Date: Tue Sep 9 15:37:15 2014 -0500 - - ata: ahci_platform: Add ACPI support for AMD Seattle SATA controller - - This patch adds ACPI support for non-PCI SATA contoller in ahci_platform driver. - It adds ACPI matching table in ahci_platform to support AMD Seattle SATA controller - with following ASL structure in DSDT: - - Device (SATA0) - { - Name(_HID, "AMDI0600") // Seattle AHSATA - Name (_CCA, 1) // Cache-coherent controller - Name (_CRS, ResourceTemplate () - { - Memory32Fixed (ReadWrite, 0xE0300000, 0x00010000) - Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive,,,) { 387 } - }) - } - - Since ATA driver should not require PCI support for ATA_ACPI, - this patch also removes dependency in the driver/ata/Kconfig. - - Signed-off-by: Suravee Suthikulpanit - -commit d9d7224bd65fb3c1490f06d635b7aceb035acb1e -Author: Graeme Gregory -Date: Wed Aug 13 13:47:18 2014 +0100 - - tty: SBSA compatible UART - - This is a subset of pl011 UART which does not supprt DMA or baud rate - changing. It does, however, provide earlycon support (i.e., using - "earlycon=ttySBSA" on the kernel command line). - - It is specified in the Server Base System Architecture document from - ARM. - - Signed-off-by: Graeme Gregory - -commit 4c67296fce53fed671a78b698d4552636f499b7f -Author: Mark Salter -Date: Thu Aug 14 13:17:37 2014 -0400 - - arm64: set dma coherency ops for ACPI probed devices - - Search for a _CCA object and set the correct dma ops based - on device coherency attribute and architecture default. - - Signed-off-by: Mark Salter - -commit 959c571815c440150b2f290bf3d13b2fbadbee70 -Author: Mark Salter -Date: Thu Aug 14 12:32:13 2014 -0400 - - acpi: add utility to test for device dma coherency - - ACPI 5.1 adds a _CCA object to indicate memory coherency - of a bus master device. It is an integer with zero meaning - non-coherent and one meaning coherent. This attribute may - be inherited from a parent device. It may also be missing - entirely, in which case, an architecture-specific default - is assumed. - - This patch adds a utility function to parse a device handle - (and its parents) for a _CCA object and return the coherency - attribute if found. - - Signed-off-by: Mark Salter - -commit 0dbac48379d3aace2fd7468d83044116f176b4c9 -Author: Mark Salter -Date: Mon Sep 8 11:58:46 2014 -0400 - - acpi: fix acpi_os_ioremap for arm64 - - The acpi_os_ioremap() function may be used to map normal RAM or IO - regions. The current implementation simply uses ioremap_cache(). This - will work for some architectures, but arm64 ioremap_cache() cannot be - used to map IO regions which don't support caching. So for arm64, use - ioremap() for non-RAM regions. - - Signed-off-by: Mark Salter - -commit c9eab819c2107e0c95cf57233de4de5404851ab6 -Author: Graeme Gregory -Date: Mon Sep 8 10:36:44 2014 -0400 - - acpi: add arm to the platforms that use ioremap - - Now with the base changes to the arm memory mapping it is safe - to convert to using ioremap to map in the tables. - - Signed-off-by: Al Stone - Signed-off-by: Graeme Gregory - -commit 7e772a485f980b826a58ecd9c39fbe82085c55fa -Author: Mark Salter -Date: Mon Sep 8 17:04:28 2014 -0400 - - acpi/arm64: NOT FOR UPSTREAM - remove EXPERT dependency - - For convenience to keep existing configs working, remove - CONFIG_EXPERT dependency from ACPI for ARM64. This shouldn't - go upstream just yet. - - Signed-off-by: Mark Salter - -commit b42e8f7901e58b86a1cb3ffdf14cb2455fd91ede -Author: Graeme Gregory -Date: Fri Sep 12 22:00:16 2014 +0800 - - Documentation: ACPI for ARM64 - - Add documentation for the guidelines of how to use ACPI - on ARM64. - - Signed-off-by: Graeme Gregory - Signed-off-by: Hanjun Guo - -commit 57dc75b87d5663181e1c19802297e72e51a324ba -Author: Graeme Gregory -Date: Fri Sep 12 22:00:15 2014 +0800 - - ARM64 / ACPI: Enable ARM64 in Kconfig - - Add Kconfigs to build ACPI on ARM64, and make ACPI available on ARM64. - - acpi_idle driver is x86/IA64 dependent now, so make CONFIG_ACPI_PROCESSOR - depend on X86 || IA64, and implement it on ARM64 in the future. - - Reviewed-by: Grant Likely - Signed-off-by: Graeme Gregory - Signed-off-by: Al Stone - Signed-off-by: Hanjun Guo - -commit 106c5cb3caff13c91cb6056f88a1c0e710b8e0eb -Author: Al Stone -Date: Fri Sep 12 22:00:14 2014 +0800 - - ARM64 / ACPI: Select ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64 - - ACPI reduced hardware mode is disabled by default, but ARM64 - can only run properly in ACPI hardware reduced mode, so select - ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64. - - Reviewed-by: Grant Likely - Signed-off-by: Al Stone - Signed-off-by: Hanjun Guo - -commit 73f4aca21985ace8989b6fc8af503940c469f1d7 -Author: Hanjun Guo -Date: Fri Sep 12 22:00:13 2014 +0800 - - ARM64 / ACPI: Parse GTDT to initialize arch timer - - Using the information presented by GTDT to initialize the arch - timer (not memory-mapped). - - Originally-by: Amit Daniel Kachhap - Signed-off-by: Hanjun Guo - -commit 5efba15fb24c25139dd621a417f2b9cbe2e675f5 -Author: Tomasz Nowicki -Date: Fri Sep 12 22:00:12 2014 +0800 - - ARM64 / ACPI: Add GICv2 specific ACPI boot support - - ACPI kernel uses MADT table for proper GIC initialization. It needs to - parse GIC related subtables, collect CPU interface and distributor - addresses and call driver initialization function (which is hardware - abstraction agnostic). In a similar way, FDT initialize GICv1/2. - - NOTE: This commit allow to initialize GICv1/2 basic functionality. - GICv2 vitalization extension, GICv3/4 and ITS are considered as next - steps. - - Signed-off-by: Tomasz Nowicki - Signed-off-by: Hanjun Guo - -commit e060d9d74cecff59ea96d6124ffb1c9c044a4f9d -Author: Hanjun Guo -Date: Fri Sep 12 22:00:11 2014 +0800 - - ARM64 / ACPI: Introduce ACPI_IRQ_MODEL_GIC and register device's gsi - - Introduce ACPI_IRQ_MODEL_GIC which is needed for ARM64 as GIC is - used, and then register device's gsi with the core IRQ subsystem. - - acpi_register_gsi() is similar to DT based irq_of_parse_and_map(), - since gsi is unique in the system, so use hwirq number directly - for the mapping. - - Originally-by: Amit Daniel Kachhap - Signed-off-by: Hanjun Guo - -commit c25e8f66c630713107967076933b5f349655ea6a -Author: Hanjun Guo -Date: Fri Sep 12 22:00:10 2014 +0800 - - ACPI / processor: Make it possible to get CPU hardware ID via GICC - - Introduce a new function map_gicc_mpidr() to allow MPIDRs to be obtained - from the GICC Structure introduced by ACPI 5.1. - - MPIDR is the CPU hardware ID as local APIC ID on x86 platform, so we use - MPIDR not the GIC CPU interface ID to identify CPUs. - - Signed-off-by: Hanjun Guo - -commit 5ce1c3ff91aa9d8012324518789363bb4ded33d4 -Author: Hanjun Guo -Date: Fri Sep 12 22:00:09 2014 +0800 - - ARM64 / ACPI: Parse MADT for SMP initialization - - MADT contains the information for MPIDR which is essential for - SMP initialization, parse the GIC cpu interface structures to - get the MPIDR value and map it to cpu_logical_map(), and add - enabled cpu with valid MPIDR into cpu_possible_map. - - ACPI 5.1 only has two explicit methods to boot up SMP, PSCI and - Parking protocol, but the Parking protocol is only specified for - ARMv7 now, so make PSCI as the only way for the SMP boot protocol - before some updates for the ACPI spec or the Parking protocol spec. - - Signed-off-by: Hanjun Guo - Signed-off-by: Tomasz Nowicki - -commit 8634cf0fcc8294c355d7cecb55da017ba9ff3ff7 -Author: Hanjun Guo -Date: Fri Sep 12 22:00:08 2014 +0800 - - ACPI / table: Print GIC information when MADT is parsed - - When MADT is parsed, print GIC information to make the boot - log look pretty. - - Signed-off-by: Hanjun Guo - Signed-off-by: Tomasz Nowicki - -commit 05facef9c824235c82d8d9c2ae03fe7a729ceef8 -Author: Hanjun Guo -Date: Fri Sep 12 22:00:07 2014 +0800 - - ARM64 / ACPI: Parse FADT table to get PSCI flags for PSCI init - - There are two flags: PSCI_COMPLIANT and PSCI_USE_HVC. When set, - the former signals to the OS that the firmware is PSCI compliant. - The latter selects the appropriate conduit for PSCI calls by - toggling between Hypervisor Calls (HVC) and Secure Monitor Calls - (SMC). - - FADT table contains such information, parse FADT to get the flags - for PSCI init. Since ACPI 5.1 doesn't support self defined PSCI - function IDs, which means that only PSCI 0.2+ is supported in ACPI. - - At the same time, only ACPI 5.1 or higher verison supports PSCI, - and FADT Major.Minor version was introduced in ACPI 5.1, so we - will check the version and only parse FADT table with version >= 5.1. - - If firmware provides ACPI tables with ACPI version less than 5.1, - OS will be messed up with those information and have no way to init - smp and GIC, so disable ACPI if we get an FADT table with version - less that 5.1. - - Signed-off-by: Hanjun Guo - Signed-off-by: Graeme Gregory - Signed-off-by: Tomasz Nowicki - -commit a13a8c748b6170a8a3f4876163ff74e460bd889f -Author: Hanjun Guo -Date: Fri Sep 12 22:00:06 2014 +0800 - - ARM64 / ACPI: Make PCI optional for ACPI on ARM64 - - As PCI for ARM64 is not ready, so introduce some stub functions - to make PCI optional for ACPI, and make ACPI core run without - CONFIG_PCI on ARM64. - - Since ACPI on X86 and IA64 depends on PCI and this patch only makes - PCI optional for ARM64, it will not break anything on X86 and IA64. - - Signed-off-by: Hanjun Guo - -commit a6bf98355490142fc3f6e9c0839af128e326f16d -Author: Graeme Gregory -Date: Fri Sep 12 22:00:05 2014 +0800 - - ARM64 / ACPI: If we chose to boot from acpi then disable FDT - - If the early boot methods of acpi are happy that we have valid ACPI - tables and acpi=off has not been passed. Then do not unflat - devicetree effectively disabling further hardware probing from DT. - - Signed-off-by: Graeme Gregory - Signed-off-by: Hanjun Guo - -commit e3b9886532d1e13ddb68e4955ad776a8623f9766 -Author: Al Stone -Date: Fri Sep 12 22:00:04 2014 +0800 - - ARM64 / ACPI: Introduce early_param for "acpi" - - Introduce one early parameters "off" for "acpi" to disable ACPI on - ARM64. - - This ensures the kernel uses the DT on a platform that provides both - ACPI tables and DT. - - Signed-off-by: Al Stone - Signed-off-by: Graeme Gregory - Signed-off-by: Hanjun Guo - -commit cf1cbe39385d417286a98e3abd7ea3456be2e88c -Author: Graeme Gregory -Date: Fri Sep 12 22:00:03 2014 +0800 - - ARM64 / ACPI: Introduce sleep-arm.c - - ACPI 5.1 does not currently support S states for ARM64 hardware but - ACPI code will call acpi_target_system_state() for device power - managment, so introduce sleep-arm.c to allow other drivers to function - until S states are defined. - - Signed-off-by: Graeme Gregory - Signed-off-by: Tomasz Nowicki - Signed-off-by: Hanjun Guo - -commit 90e5cfbaf183d0eb92f1977c24da20c4e0a2f6be -Author: Al Stone -Date: Fri Sep 12 22:00:02 2014 +0800 - - ARM64 / ACPI: Get RSDP and ACPI boot-time tables - - As we want to get ACPI tables to parse and then use the information - for system initialization, we should get the RSDP (Root System - Description Pointer) first, it then locates Extended Root Description - Table (XSDT) which contains all the 64-bit physical address that - pointer to other boot-time tables. - - Introduce acpi.c and its related head file in this patch to provide - fundamental needs of extern variables and functions for ACPI core, - and then get boot-time tables as needed. - - asm/acenv.h for arch specific ACPICA environments and - implementation, It is needed unconditionally by ACPI core; - - asm/acpi.h for arch specific variables and functions needed by - ACPI driver core; - - acpi.c for ARM64 related ACPI implementation for ACPI driver - core; - - acpi_boot_table_init() is introduced to get RSDP and boot-time tables, - it will be called in setup_arch() before paging_init(), so we should - use eary_memremap() mechanism here to get the RSDP and all the table - pointers. - - Signed-off-by: Al Stone - Signed-off-by: Graeme Gregory - Signed-off-by: Tomasz Nowicki - Signed-off-by: Hanjun Guo - -commit 2fe5d24887dea3f1bffabf04e364fa9f355ed553 -Author: Tomasz Nowicki -Date: Fri Sep 12 22:00:01 2014 +0800 - - ACPI / table: Count matched and successfully parsed entries without specifying max entries - - It is very useful to traverse all available table entries without max - number of expected entries type. Current acpi_parse_entries() - implementation gives that feature but it does not count those entries, - it returns 0 instead, so fix it to count matched and successfully - entries and return it. - - NOTE: This change has no impact to x86 and ia64 archs since existing code - checks for error occurrence only (acpi_parse_entries(...,0) < 0). - - Signed-off-by: Tomasz Nowicki - Signed-off-by: Hanjun Guo - -commit 8c278c76231f0ba0110e755678eefdd6d077f5da -Author: Ashwin Chaugule -Date: Fri Sep 12 22:00:00 2014 +0800 - - ACPI / table: Add new function to get table entries - - The acpi_table_parse() function has a callback that - passes a pointer to a table_header. Add a new function - which takes this pointer and parses its entries. This - eliminates the need to re-traverse all the tables for - each call. e.g. as in acpi_table_parse_madt() which is - normally called after acpi_table_parse(). - - Signed-off-by: Ashwin Chaugule - Signed-off-by: Tomasz Nowicki - Signed-off-by: Hanjun Guo - -commit 651ab5ff6804fa0f516715b4d47399e587944de0 -Author: Hanjun Guo -Date: Fri Sep 12 21:59:59 2014 +0800 - - ARM64: Move the init of cpu_logical_map(0) before unflatten_device_tree() - - It always make sense to initialize CPU0's logical map entry from the - hardware values, so move the initialization of cpu_logical_map(0) - before unflatten_device_tree() which is needed by ACPI code later. - - Signed-off-by: Hanjun Guo - -commit b91246f1a7120de6de8fe630ed01e9a0d0415e88 -Author: Tanmay Inamdar -Date: Fri Sep 26 14:08:27 2014 -0700 - - MAINTAINERS: entry for APM X-Gene PCIe host driver - - Add entry for AppliedMicro X-Gene PCIe host driver. - - Signed-off-by: Tanmay Inamdar - -commit d20b104083718058b599a5ca1a925d8c5243e2e1 -Author: Tanmay Inamdar -Date: Fri Sep 26 14:08:26 2014 -0700 - - dt-bindings: pci: xgene pcie device tree bindings - - This patch adds the bindings for X-Gene PCIe driver. The driver resides - under 'drivers/pci/host/pci-xgene.c' file. - - Signed-off-by: Tanmay Inamdar - -commit 9c429c919b77a3a63ac2843e9e0e2e50e59d28f3 -Author: Tanmay Inamdar -Date: Fri Sep 26 14:08:25 2014 -0700 - - arm64: dts: APM X-Gene PCIe device tree nodes - - This patch adds the device tree nodes for APM X-Gene PCIe host controller and - PCIe clock interface. Since X-Gene SOC supports maximum 5 ports, 5 dts - nodes are added. - - Signed-off-by: Tanmay Inamdar - -commit 3aa4f71932b67e648aff4ae0dc5ace7162d74c1c -Author: Tanmay Inamdar -Date: Fri Sep 26 14:08:24 2014 -0700 - - pci:host: APM X-Gene PCIe host controller driver - - This patch adds the AppliedMicro X-Gene SOC PCIe host controller driver. - X-Gene PCIe controller supports maximum up to 8 lanes and GEN3 speed. - X-Gene SOC supports maximum 5 PCIe ports. - - Reviewed-by: Liviu Dudau - Tested-by: Ming Lei - Tested-by: Dann Frazier - Signed-off-by: Tanmay Inamdar - -commit f3c00bd4ae49b19923049f0f4f9d6a95eaa61b1e -Author: Liviu Dudau -Date: Tue Sep 23 20:01:14 2014 +0100 - - arm64: Add architectural support for PCI - - Use the generic PCI domain and OF functions to provide support for PCI - on arm64. - - [bhelgaas: Change comments to use generic PCI, not just PCIe. Nothing at - this level is PCIe-specific.] - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - Acked-by: Catalin Marinas - -commit 497220defa08534526ad7b20a9c7eb2d0d903ca4 -Author: Liviu Dudau -Date: Tue Sep 23 20:01:13 2014 +0100 - - PCI: Add pci_remap_iospace() to map bus I/O resources - - Add pci_remap_iospace() to map bus I/O resources into the CPU virtual - address space. Architectures with special needs may provide their own - version, but most should be able to use this one. - - This function is useful for PCI host bridge drivers that need to map the - PCI I/O resources into virtual memory space. - - [bhelgaas: phys_addr description, drop temporary "err" variable] - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - Reviewed-by: Rob Herring - Reviewed-by: Catalin Marinas - CC: Arnd Bergmann - -commit 7a46ace11cf09b3713dcdc2ef4a17130a738f856 -Author: Liviu Dudau -Date: Tue Sep 23 20:01:12 2014 +0100 - - PCI: Assign unassigned bus resources in pci_scan_root_bus() - - If the firmware has not assigned all the bus resources and we are not just - probing the PCI buses, it makes sense to assign the unassigned resources - in pci_scan_root_bus(). - - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - CC: Arnd Bergmann - CC: Jason Gunthorpe - CC: Rob Herring - -commit fe33bc876010c3ef700c863099f2c3c1a5e2c18b -Author: Liviu Dudau -Date: Wed Sep 24 11:27:33 2014 -0600 - - of/pci: Add support for parsing PCI host bridge resources from DT - - Provide a function to parse the PCI DT ranges that can be used to create a - pci_host_bridge structure together with its associated bus. - - Signed-off-by: Liviu Dudau - [make io_base parameter optional] - Signed-off-by: Robert Richter - Signed-off-by: Bjorn Helgaas - CC: Arnd Bergmann - CC: Grant Likely - CC: Rob Herring - CC: Catalin Marinas - -commit 71094afda69ac873bb3d6486307e3048e21e912c -Author: Liviu Dudau -Date: Tue Sep 23 20:01:10 2014 +0100 - - of/pci: Add of_pci_get_domain_nr() and of_get_pci_domain_nr() - - Add pci_get_new_domain_nr() to allocate a new domain number and - of_get_pci_domain_nr() to retrieve the PCI domain number of a given device - from DT. Host bridge drivers or architecture-specific code can choose to - implement their PCI domain number policy using these two functions. - - Using of_get_pci_domain_nr() guarantees a stable PCI domain number on every - boot provided that all host bridge controllers are assigned a number in the - device tree using "linux,pci-domain" property. Mixing use of - pci_get_new_domain_nr() and of_get_pci_domain_nr() is not recommended as it - can lead to potentially conflicting domain numbers being assigned to root - buses behind different host bridges. - - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - CC: Arnd Bergmann - CC: Grant Likely - CC: Rob Herring - CC: Catalin Marinas - -commit 6b385455f18d15da6b5d60a3b67fdb846ae1a3b1 -Author: Catalin Marinas -Date: Tue Sep 23 20:01:09 2014 +0100 - - PCI: Add generic domain handling - - The handling of PCI domains (or PCI segments in ACPI speak) is usually a - straightforward affair but its implementation is currently left to the - architectural code, with pci_domain_nr(b) querying the value of the domain - associated with bus b. - - This patch introduces CONFIG_PCI_DOMAINS_GENERIC as an option that can be - selected if an architecture wants a simple implementation where the value - of the domain associated with a bus is stored in struct pci_bus. - - The architectures that select CONFIG_PCI_DOMAINS_GENERIC will then have to - implement pci_bus_assign_domain_nr() as a way of setting the domain number - associated with a root bus. All child buses except the root bus will - inherit the domain_nr value from their parent. - - Signed-off-by: Catalin Marinas - [Renamed pci_set_domain_nr() to pci_bus_assign_domain_nr()] - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - CC: Arnd Bergmann - -commit 04b36e0e1da5a96a58dec4f1b393090f00e5b635 -Author: Liviu Dudau -Date: Tue Sep 23 20:01:08 2014 +0100 - - PCI: Create pci_host_bridge before root bus - - Before 7b5436635800 ("PCI: add generic device into pci_host_bridge - struct"), the pci_host_bridge was created before the root bus. Revert the - order of creation as we are going to depend on the pci_host_bridge - structure to retrieve the domain number of the root bus. - - [bhelgaas: changelog] - Tested-by: Tanmay Inamdar - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - Reviewed-by: Catalin Marinas - Acked-by: Grant Likely - -commit 7569c510218798bd7e5216bf14a42c656f14e891 -Author: Liviu Dudau -Date: Tue Sep 23 20:01:07 2014 +0100 - - of/pci: Fix the conversion of IO ranges into IO resources - - The ranges property for a host bridge controller in DT describes the - mapping between the PCI bus address and the CPU physical address. The - resources framework however expects that the IO resources start at a pseudo - "port" address 0 (zero) and have a maximum size of IO_SPACE_LIMIT. The - conversion from PCI ranges to resources failed to take that into account, - returning a CPU physical address instead of a port number. - - Also fix all the drivers that depend on the old behaviour by fetching the - CPU physical address based on the port number where it is being needed. - - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - Acked-by: Linus Walleij - CC: Grant Likely - CC: Rob Herring - CC: Arnd Bergmann - CC: Thierry Reding - CC: Simon Horman - CC: Catalin Marinas - -commit 1b381671c9dd2c82cd6f04bc1588d0fc4e1aea59 -Author: Liviu Dudau -Date: Tue Sep 23 20:01:06 2014 +0100 - - of/pci: Move of_pci_range_to_resources() to of/address.c - - We need to enhance of_pci_range_to_resources() enough that it won't make - sense for it to be inline anymore. Move it to drivers/of/address.c, - keeping it under #ifdef CONFIG_PCI. - - [bhelgaas: drop extra detail from changelog, move def under CONFIG_PCI] - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - CC: Grant Likely - CC: Rob Herring - CC: Arnd Bergmann - CC: Catalin Marinas - -commit eedd8f88d4895d5c6bc46cf3ddeb114a0fafb7c3 -Author: Bjorn Helgaas -Date: Tue Sep 23 17:27:42 2014 -0600 - - of/pci: Define of_pci_range_to_resource() only when CONFIG_PCI=y - - of_pci_range_to_resource() was previously defined always, but it's only - used by PCI code, so move the definition inside the CONFIG_OF_ADDRESS && - CONFIG_PCI block. - - Signed-off-by: Bjorn Helgaas - -commit 4ac73f8ded507537318717bb2b5b6c765db633cd -Author: Liviu Dudau -Date: Tue Sep 23 20:01:05 2014 +0100 - - ARM: Define PCI_IOBASE as the base of virtual PCI IO space - - This is needed for calls into OF code that parses PCI ranges. It signals - support for memory mapped PCI I/O accesses that are described by device - trees. - - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - Reviewed-by: Catalin Marinas - Acked-by: Arnd Bergmann - CC: Russell King - CC: Rob Herring - -commit ce7af33b6db857c95ac3b65fef37e589e839cc79 -Author: Liviu Dudau -Date: Tue Sep 23 20:01:04 2014 +0100 - - of/pci: Add pci_register_io_range() and pci_pio_to_address() - - Some architectures do not have a simple view of the PCI I/O space and - instead use a range of CPU addresses that map to bus addresses. For some - architectures these ranges will be expressed by OF bindings in a device - tree file. - - This patch introduces a pci_register_io_range() helper function with a - generic implementation that can be used by such architectures to keep track - of the I/O ranges described by the PCI bindings. If the PCI_IOBASE macro - is not defined, that signals lack of support for PCI and we return an - error. - - In order to retrieve the CPU address associated with an I/O port, a new - helper function pci_pio_to_address() is introduced. This will search in - the list of ranges registered with pci_register_io_range() and return the - CPU address that corresponds to the given port. - - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - Reviewed-by: Catalin Marinas - Acked-by: Rob Herring - CC: Grant Likely - CC: Arnd Bergmann - -commit c5d57f95901af49149ebf6dfc3d7518157e41bfa -Author: Liviu Dudau -Date: Tue Sep 23 20:01:03 2014 +0100 - - asm-generic/io.h: Fix ioport_map() for !CONFIG_GENERIC_IOMAP - - The !CONFIG_GENERIC_IOMAP version of ioport_map() is wrong. It returns a - mapped, i.e., virtual, address that can start from zero and completely - ignores the PCI_IOBASE and IO_SPACE_LIMIT that most architectures that use - !CONFIG_GENERIC_MAP define. - - Tested-by: Tanmay Inamdar - Signed-off-by: Liviu Dudau - Signed-off-by: Bjorn Helgaas - Reviewed-by: Catalin Marinas - Acked-by: Arnd Bergmann - -commit a65e51156bec2c8d690b924bbddf1a740309e543 -Author: Mark Salter -Date: Tue Jun 24 09:50:28 2014 -0400 - - arm64: use EFI as last resort for reboot and poweroff - - Wire in support for EFI reboot and poweroff functions. We use these - only if no other mechanism has been registered with arm_pm_reboot - and/or pm_power_off respectively. - - Signed-off-by: Mark Salter - -commit c6b81122978c39e52021cc7308edafff88c8b87a -Author: Ard Biesheuvel -Date: Wed Jul 30 11:59:04 2014 +0100 - - arm64/efi: efistub: don't abort if base of DRAM is occupied - - If we cannot relocate the kernel Image to its preferred offset of base of DRAM - plus TEXT_OFFSET, instead relocate it to the lowest available 2 MB boundary plus - TEXT_OFFSET. We may lose a bit of memory at the low end, but we can still - proceed normally otherwise. - - Acked-by: Mark Salter - Acked-by: Mark Rutland - Acked-by: Leif Lindholm - Tested-by: Leif Lindholm - Signed-off-by: Ard Biesheuvel - Signed-off-by: Will Deacon - -commit 81fd1d315f3c5b13f9dcf71cce51dfd3a10331c3 -Author: Ard Biesheuvel -Date: Wed Jul 30 11:59:03 2014 +0100 - - arm64/efi: efistub: cover entire static mem footprint in PE/COFF .text - - The static memory footprint of a kernel Image at boot is larger than the - Image file itself. Things like .bss data and initial page tables are allocated - statically but populated dynamically so their content is not contained in the - Image file. - - However, if EFI (or GRUB) has loaded the Image at precisely the desired offset - of base of DRAM + TEXT_OFFSET, the Image will be booted in place, and we have - to make sure that the allocation done by the PE/COFF loader is large enough. - - Fix this by growing the PE/COFF .text section to cover the entire static - memory footprint. The part of the section that is not covered by the payload - will be zero initialised by the PE/COFF loader. - - Acked-by: Mark Salter - Acked-by: Mark Rutland - Acked-by: Leif Lindholm - Tested-by: Leif Lindholm - Signed-off-by: Ard Biesheuvel - Signed-off-by: Will Deacon - -commit 8f5f73c2117c2dc4e8903d162023c34177327ae3 -Author: Mark Rutland -Date: Wed Jul 30 11:59:02 2014 +0100 - - arm64: spin-table: handle unmapped cpu-release-addrs - - In certain cases the cpu-release-addr of a CPU may not fall in the - linear mapping (e.g. when the kernel is loaded above this address due to - the presence of other images in memory). This is problematic for the - spin-table code as it assumes that it can trivially convert a - cpu-release-addr to a valid VA in the linear map. - - This patch modifies the spin-table code to use a temporary cached - mapping to write to a given cpu-release-addr, enabling us to support - addresses regardless of whether they are covered by the linear mapping. - - Acked-by: Leif Lindholm - Tested-by: Leif Lindholm - Tested-by: Mark Salter - Signed-off-by: Mark Rutland - [ardb: added (__force void *) cast] - Signed-off-by: Ard Biesheuvel - Signed-off-by: Will Deacon - -commit b00c56bff1ffb6c77655479fb350ee3d5c8bcf63 -Author: Mark Salter -Date: Tue Jun 24 23:16:45 2014 -0400 - - perf: fix arm64 build error - - I'm seeing the following build error on arm64: - - In file included from util/event.c:3:0: - util/event.h:95:17: error: 'PERF_REGS_MAX' undeclared here (not in a function) - u64 cache_regs[PERF_REGS_MAX]; - ^ - - This patch adds a PEFF_REGS_MAX definition for arm64. - - Signed-off-by: Mark Salter - -commit f440dcb067bf1367719e8a41b96a2a83c1232690 -Author: Mark Salter -Date: Thu Jul 17 13:34:50 2014 -0400 - - ahci_xgene: add errata workaround for ATA_CMD_SMART - - commit 2a0bdff6b958d1b2: - - ahci_xgene: fix the dma state machine lockup for the IDENTIFY DEVICE PIO mode command. - - added a workaround for X-Gene AHCI controller errata. This was done - for all ATA_CMD_ID_ATA commands. The errata also appears to affect - ATA_CMD_SMART commands as well. This was discovered when running - smartd or just smartctl -x. This patch adds a dma engine restart for - ATA_CMD_SMART commands which clears up the issues seen with smartd. - - Signed-off-by: Mark Salter - -commit 93b44dc9e1d73d4864a9350888509792f25e4210 -Author: Kyle McMartin -Date: Tue May 13 22:25:26 2014 -0400 - - arm64: don't set READ_IMPLIES_EXEC for EM_AARCH64 ELF objects - - Message-id: <20140513222526.GC26038@redacted.bos.redhat.com> - Patchwork-id: 79789 - O-Subject: [ACADIA PATCH] arm64: don't set READ_IMPLIES_EXEC for EM_AARCH64 ELF objects - Bugzilla: 1085528 - - BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1085528 - Upstream: submitted soon - - [Sadly this isn't (yet) sufficient... but it fixes at least one issue - here... cat /proc/$$/personality shows READ_IMPLIES_EXEC before. I'll - try to figure the rest out tomorrow.] - - Currently, we're accidentally ending up with executable stacks on - AArch64 when the ABI says we shouldn't be, and relying on glibc to fix - things up for us when we're loaded. However, SELinux will deny us - mucking with the stack, and hit us with execmem AVCs. - - The reason this is happening is somewhat complex: - - fs/binfmt_elf.c:load_elf_binary() - - initializes executable_stack = EXSTACK_DEFAULT implying the - architecture should make up its mind. - - does a pile of loading goo - - runs through the program headers, looking for PT_GNU_STACK - and setting (or unsetting) executable_stack if it finds it. - - This is our first problem, we won't generate these unless an - executable stack is explicitly requested. - - - more ELF loading goo - - sets whether we're a compat task or not (TIF_32BIT) based on compat.h - - for compat reasons (pre-GNU_STACK) checks if the READ_IMPLIES_EXEC - flag should be set for ancient toolchains - - Here's our second problem, we test if read_implies_exec based on - stk != EXSTACK_DISABLE_X, which is true since stk == EXSTACK_DEFAULT. - - So we set current->personality |= READ_IMPLIES_EXEC like a broken - legacy toolchain would want. - - - Now we call setup_arg_pages to set up the stack... - - fs/exec.c:setup_arg_pages() - - lots of magic happens here - - vm_flags gets initialized to VM_STACK_FLAGS - - Here's our third problem, VM_STACK_FLAGS on arm64 is - VM_DEFAULT_DATA_FLAG which tests READ_IMPLIES_EXEC and sets VM_EXEC - if it's true. So we end up with an executable stack mapping, since we - don't have executable_stack set (it's still EXSTACK_DEFAULT at this - point) to unset it anywhere. - - Bang. execstack AVC when the program starts running. - - The easiest way I can see to fix this is to test if we're a legacy task - and fix it up there. But that's not as simple as it sounds, because - the 32-bit ABI depends on what revision of the CPU we've enabled (not - that it matters since we're ARMv8...) Regardless, in the compat case, - set READ_IMPLIES_EXEC if we've found a GNU_STACK header which explicitly - requested it as in arch/arm/kernel/elf.c:arm_elf_read_implies_exec(). - - Signed-off-by: Kyle McMartin - Signed-off-by: Donald Dutile - - Documentation/arm64/arm-acpi.txt | 218 +++++++ - .../devicetree/bindings/pci/xgene-pci.txt | 57 ++ - Documentation/kernel-parameters.txt | 3 +- - MAINTAINERS | 8 + - arch/arm/include/asm/io.h | 1 + - arch/arm/include/asm/kvm_mmu.h | 13 + - arch/arm/kvm/arm.c | 23 +- - arch/arm/mach-integrator/pci_v3.c | 23 +- - arch/arm64/Kconfig | 28 +- - arch/arm64/Makefile | 1 + - arch/arm64/boot/dts/apm-mustang.dts | 8 + - arch/arm64/boot/dts/apm-storm.dtsi | 165 ++++++ - arch/arm64/include/asm/Kbuild | 1 + - arch/arm64/include/asm/acenv.h | 18 + - arch/arm64/include/asm/acpi.h | 99 ++++ - arch/arm64/include/asm/cpu_ops.h | 1 + - arch/arm64/include/asm/elf.h | 3 +- - arch/arm64/include/asm/io.h | 3 +- - arch/arm64/include/asm/kvm_arm.h | 17 +- - arch/arm64/include/asm/kvm_mmu.h | 75 +++ - arch/arm64/include/asm/pci.h | 37 ++ - arch/arm64/include/asm/pgtable.h | 2 + - arch/arm64/include/asm/psci.h | 3 +- - arch/arm64/include/asm/smp.h | 10 +- - arch/arm64/kernel/Makefile | 5 +- - arch/arm64/kernel/acpi.c | 397 +++++++++++++ - arch/arm64/kernel/cpu_ops.c | 8 +- - arch/arm64/kernel/efi-stub.c | 16 +- - arch/arm64/kernel/efi.c | 11 + - arch/arm64/kernel/head.S | 6 +- - arch/arm64/kernel/pci.c | 70 +++ - arch/arm64/kernel/process.c | 6 + - arch/arm64/kernel/psci.c | 78 ++- - arch/arm64/kernel/setup.c | 64 +- - arch/arm64/kernel/smp.c | 2 +- - arch/arm64/kernel/smp_parking_protocol.c | 110 ++++ - arch/arm64/kernel/smp_spin_table.c | 22 +- - arch/arm64/kernel/time.c | 7 + - arch/arm64/kvm/hyp-init.S | 20 +- - arch/arm64/mm/dma-mapping.c | 65 ++ - arch/arm64/pci/Makefile | 1 + - arch/arm64/pci/pci.c | 28 + - drivers/acpi/Kconfig | 6 +- - drivers/acpi/Makefile | 6 +- - drivers/acpi/acpica/utresrc.c | 4 +- - drivers/acpi/bus.c | 3 + - drivers/acpi/internal.h | 5 + - drivers/acpi/osl.c | 6 +- - drivers/acpi/processor_core.c | 37 ++ - drivers/acpi/sleep-arm.c | 28 + - drivers/acpi/tables.c | 115 +++- - drivers/acpi/utils.c | 26 + - drivers/ata/Kconfig | 2 +- - drivers/ata/ahci_platform.c | 13 + - drivers/ata/ahci_xgene.c | 30 +- - drivers/clocksource/arm_arch_timer.c | 120 +++- - drivers/irqchip/irq-gic-v3.c | 10 + - drivers/irqchip/irq-gic.c | 116 ++++ - drivers/irqchip/irqchip.c | 3 + - drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 12 + - drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 3 + - drivers/net/ethernet/amd/xgbe/xgbe-main.c | 1 + - drivers/net/ethernet/amd/xgbe/xgbe.h | 3 + - drivers/net/ethernet/smsc/smc91x.c | 10 + - drivers/net/phy/amd-xgbe-phy.c | 408 +++++++------ - drivers/of/address.c | 154 +++++ - drivers/of/of_pci.c | 142 +++++ - drivers/pci/host/Kconfig | 10 + - drivers/pci/host/Makefile | 1 + - drivers/pci/host/pci-tegra.c | 10 +- - drivers/pci/host/pci-xgene.c | 659 +++++++++++++++++++++ - drivers/pci/host/pcie-rcar.c | 21 +- - drivers/pci/pci.c | 40 ++ - drivers/pci/probe.c | 46 +- - drivers/pnp/resource.c | 2 + - drivers/tty/Kconfig | 6 + - drivers/tty/Makefile | 1 + - drivers/tty/sbsauart.c | 355 +++++++++++ - drivers/tty/serial/8250/8250_dw.c | 9 + - drivers/virtio/virtio_mmio.c | 12 +- - include/acpi/acnames.h | 4 + - include/acpi/acpi_bus.h | 2 + - include/acpi/acpi_io.h | 6 + - include/acpi/acpixf.h | 2 +- - include/acpi/actbl1.h | 19 +- - include/acpi/actbl3.h | 9 +- - include/asm-generic/io.h | 2 +- - include/asm-generic/pgtable.h | 4 + - include/kvm/arm_vgic.h | 20 +- - include/linux/acpi.h | 5 + - include/linux/clocksource.h | 6 + - include/linux/irqchip/arm-gic-acpi.h | 31 + - include/linux/irqchip/arm-gic.h | 2 + - include/linux/of_address.h | 17 +- - include/linux/of_pci.h | 13 + - include/linux/pci.h | 64 +- - tools/perf/arch/arm64/include/perf_regs.h | 2 + - virt/kvm/arm/arch_timer.c | 108 ++-- - virt/kvm/arm/vgic-v2.c | 75 ++- - virt/kvm/arm/vgic-v3.c | 8 +- - virt/kvm/arm/vgic.c | 32 +- - 101 files changed, 4112 insertions(+), 487 deletions(-) - +diff --git a/Documentation/acpi/properties.txt b/Documentation/acpi/properties.txt +new file mode 100644 +index 0000000..13a93c5 +--- /dev/null ++++ b/Documentation/acpi/properties.txt +@@ -0,0 +1,410 @@ ++ACPI device properties ++====================== ++This document describes the format and interfaces of ACPI device ++properties as specified in "Device Properties UUID For _DSD" available ++here: ++ ++http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf ++ ++1. Introduction ++--------------- ++In systems that use ACPI and want to take advantage of device specific ++properties, there needs to be a standard way to return and extract ++name-value pairs for a given ACPI device. ++ ++An ACPI device that wants to export its properties must implement a ++static name called _DSD that takes no arguments and returns a package of ++packages: ++ ++ Name (_DSD, Package () { ++ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), ++ Package () { ++ Package () {"name1", }, ++ Package () {"name2", } ++ } ++ }) ++ ++The UUID identifies contents of the following package. In case of ACPI ++device properties it is daffd814-6eba-4d8c-8a91-bc9bbf4aa301. ++ ++In each returned package, the first item is the name and must be a string. ++The corresponding value can be a string, integer, reference, or package. If ++a package it may only contain strings, integers, and references. ++ ++An example device where we might need properties is a device that uses ++GPIOs. In addition to the GpioIo/GpioInt resources the driver needs to ++know which GPIO is used for which purpose. ++ ++To solve this we add the following ACPI device properties to the device: ++ ++ Device (DEV0) ++ { ++ Name (_CRS, ResourceTemplate () { ++ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly, ++ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {0} ++ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly, ++ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {1} ++ ... ++ }) ++ ++ Name (_DSD, Package () { ++ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), ++ Package () { ++ Package () {"reset-gpio", {^DEV0, 0, 0, 0}}, ++ Package () {"shutdown-gpio", {^DEV0, 1, 0, 0}}, ++ } ++ }) ++ } ++ ++Now the device driver can reference the GPIOs using names instead of ++using indexes. ++ ++If there is an existing Device Tree binding for a device, it is expected ++that the same bindings are used with ACPI properties, so that the driver ++dealing with the device needs only minor modifications if any. ++ ++2. Formal definition of properties ++---------------------------------- ++The following chapters define the currently supported properties. For ++these there exists a helper function that can be used to extract the ++property value. ++ ++2.1 Integer types ++----------------- ++ACPI integers are always 64-bit. However, for drivers the full range is ++typically not needed so we provide a set of functions which convert the ++64-bit integer to a smaller Linux integer type. ++ ++An integer property looks like this: ++ ++ Package () {"i2c-sda-hold-time-ns", 300}, ++ Package () {"clock-frequency", 400000}, ++ ++To read a property value, use a unified property accessor as shown ++below: ++ ++ u32 val; ++ int ret; ++ ++ ret = device_property_read_u32(dev, "clock-frequency", &val); ++ if (ret) ++ /* Handle error */ ++ ++The function returns 0 if the property is copied to 'val' or negative ++errno if something went wrong (or the property does not exist). ++ ++2.2 Integer arrays ++------------------ ++An integer array is a package holding only integers. Arrays can be used to ++represent different things like Linux input key codes to GPIO mappings, pin ++control settings, dma request lines, etc. ++ ++An integer array looks like this: ++ ++ Package () { ++ "max8952,dvs-mode-microvolt", ++ Package () { ++ 1250000, ++ 1200000, ++ 1050000, ++ 950000, ++ } ++ } ++ ++The above array property can be accessed like: ++ ++ u32 voltages[4]; ++ int ret; ++ ++ ret = device_property_read_u32_array(dev, "max8952,dvs-mode-microvolt", ++ voltages, ARRAY_SIZE(voltages)); ++ if (ret) ++ /* Handle error */ ++ ++ ++All functions copy the resulting values cast to a requested type to the ++caller supplied array. If you pass NULL in the value pointer ('voltages' in ++this case), the function returns number of items in the array. This can be ++useful if caller does not know size of the array beforehand. ++ ++2.3 Strings ++----------- ++String properties can be used to describe many things like labels for GPIO ++buttons, compability ids, etc. ++ ++A string property looks like this: ++ ++ Package () {"pwm-names", "backlight"}, ++ Package () {"label", "Status-LED"}, ++ ++You can use device_property_read_string() to extract strings: ++ ++ const char *val; ++ int ret; ++ ++ ret = device_property_read_string(dev, "label", &val); ++ if (ret) ++ /* Handle error */ ++ ++Note that the function does not copy the returned string but instead the ++value is modified to point to the string property itself. ++ ++The memory is owned by the associated ACPI device object and released ++when it is removed. The user need not free the associated memory. ++ ++2.4 String arrays ++----------------- ++String arrays can be useful in describing a list of labels, names for ++DMA channels, etc. ++ ++A string array property looks like this: ++ ++ Package () {"dma-names", Package () {"tx", "rx", "rx-tx"}}, ++ Package () {"clock-output-names", Package () {"pll", "pll-switched"}}, ++ ++And these can be read in similar way that the integer arrrays: ++ ++ const char *dma_names[3]; ++ int ret; ++ ++ ret = device_property_read_string_array(dev, "dma-names", dma_names, ++ ARRAY_SIZE(dma_names)); ++ if (ret) ++ /* Handle error */ ++ ++The memory management rules follow what is specified for single strings. ++Specifically the returned pointers should be treated as constant and not to ++be freed. That is done automatically when the correspondig ACPI device ++object is released. ++ ++2.5 Object references ++--------------------- ++An ACPI object reference is used to refer to some object in the ++namespace. For example, if a device has dependencies with some other ++object, an object reference can be used. ++ ++An object reference looks like this: ++ ++ Package () {"dev0", \_SB.DEV0}, ++ ++At the time of writing this, there is no unified device_property_* accessor ++for references so one needs to use the following ACPI helper function: ++ ++ int acpi_dev_get_property_reference(struct acpi_device *adev, ++ const char *name, ++ const char *size_prop, int index, ++ struct acpi_reference_args *args); ++ ++The referenced ACPI device is returned in args->adev if found. ++ ++In addition to simple object references it is also possible to have object ++references with arguments. These are represented in ASL as follows: ++ ++ Device (\_SB.PCI0.PWM) ++ { ++ Name (_DSD, Package () { ++ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), ++ Package () { ++ Package () {"#pwm-cells", 2} ++ } ++ }) ++ } ++ ++ Device (\_SB.PCI0.BL) ++ { ++ Name (_DSD, Package () { ++ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), ++ Package () { ++ Package () { ++ "pwms", ++ Package () { ++ \_SB.PCI0.PWM, 0, 5000000, ++ \_SB.PCI0.PWM, 1, 4500000, ++ } ++ } ++ } ++ }) ++ } ++ ++In the above example, the referenced device declares a property that ++returns the number of expected arguments (here it is "#pwm-cells"). If ++no such property is given we assume that all the integers following the ++reference are arguments. ++ ++In the above example PWM device expects 2 additional arguments. This ++will be validated by the ACPI property core. ++ ++The additional arguments must be integers. Nothing else is supported. ++ ++It is possible, as in the above example, to have multiple references ++with varying number of integer arguments. It is up to the referenced ++device to declare how many arguments it expects. The 'index' parameter ++selects which reference is returned. ++ ++One can use acpi_dev_get_property_reference() as well to extract the ++information in additional parameters: ++ ++ struct acpi_reference_args args; ++ struct acpi_device *adev = /* this will point to the BL device */ ++ int ret; ++ ++ /* extract the first reference */ ++ acpi_dev_get_property_reference(adev, "pwms", "#pwm-cells", 0, &args); ++ ++ BUG_ON(args.nargs != 2); ++ BUG_ON(args.args[0] != 0); ++ BUG_ON(args.args[1] != 5000000); ++ ++ /* extract the second reference */ ++ acpi_dev_get_property_reference(adev, "pwms", "#pwm-cells", 1, &args); ++ ++ BUG_ON(args.nargs != 2); ++ BUG_ON(args.args[0] != 1); ++ BUG_ON(args.args[1] != 4500000); ++ ++In addition to arguments, args.adev now points to the ACPI device that ++corresponds to \_SB.PCI0.PWM. ++ ++It is intended that this function is not used directly but instead ++subsystems like pwm implement their ACPI support on top of this function ++in such way that it is hidden from the client drivers, such as via ++pwm_get(). ++ ++3. Device property hierarchies ++------------------------------ ++Devices are organized in a tree within the Linux kernel. It follows that ++the configuration data would also be hierarchical. In order to reach ++equivalence with Device Tree, the ACPI mechanism must also provide some ++sort of tree-like representation. Fortunately, the ACPI namespace is ++already such a structure. ++ ++For example, we could have the following device in ACPI namespace. The ++KEYS device is much like gpio_keys_polled.c in that it includes "pseudo" ++devices for each GPIO: ++ ++ Device (KEYS) ++ { ++ Name (_CRS, ResourceTemplate () { ++ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly, ++ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {0} ++ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly, ++ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {1} ++ ... ++ }) ++ ++ // "pseudo" devices declared under the parent device ++ Device (BTN0) { ++ Name (_DSD, Package () { ++ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), ++ Package () { ++ Package () {"label", "minnow_btn0"} ++ Package () {"gpios", Package () {^KEYS, 0, 0, 1}} ++ } ++ }) ++ } ++ ++ Device (BTN1) { ++ Name (_DSD, Package () { ++ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), ++ Package () { ++ Package () {"label", "minnow_btn1"} ++ Package () {"gpios", Package () {^KEYS, 1, 0, 1}} ++ } ++ }) ++ } ++ } ++ ++We can extract the above in gpio_keys_polled.c like: ++ ++ static int gpio_keys_polled_create_button(struct device *dev, void *child, ++ void *data) ++ { ++ struct button_data *bdata = data; ++ const char *label = NULL; ++ ++ /* ++ * We need to use device_child_ variant here to access ++ * properties of the child. ++ */ ++ device_child_property_read_string(dev, child, "label", &label); ++ /* and so on */ ++ } ++ ++ static void gpio_keys_polled_probe(struct device *dev) ++ { ++ /* Properties for the KEYS device itself */ ++ device_property_read(dev, ...); ++ ++ /* ++ * Iterate over button devices and extract their ++ * firmware configuration. ++ */ ++ ret = device_for_each_child_node(dev, gpio_keys_polled_create_button, ++ &bdata); ++ if (ret) ++ /* Handle error */ ++ } ++ ++Note that you still need proper error handling which is omitted in the ++above example. ++ ++4. Existing Device Tree enabled drivers ++--------------------------------------- ++At the time of writing this, there are ~250 existing DT enabled drivers. ++Allocating _HID/_CID for each would not be feasible. To make sure that ++those drivers can still be used on ACPI systems, we provide an ++alternative way to get these matched. ++ ++There is a special _HID "PRP0001" which means that use the DT bindings ++for matching this device to a driver. The driver needs to have ++.of_match_table filled in even when !CONFIG_OF. ++ ++An example device would be leds that can be controlled via GPIOs. This ++is represented as "leds-gpio" device and looks like this in the ACPI ++namespace: ++ ++ Device (LEDS) ++ { ++ Name (_DSD, Package () { ++ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), ++ Package () { ++ Package () {"compatible", Package () {"gpio-leds"}}, ++ } ++ }) ++ ... ++ } ++ ++In order to get the existing drivers/leds/leds-gpio.c bound to this ++device, we take advantage of "PRP0001": ++ ++ /* Following already exists in the driver */ ++ static const struct of_device_id of_gpio_leds_match[] = { ++ { .compatible = "gpio-leds", }, ++ {}, ++ }; ++ MODULE_DEVICE_TABLE(of, of_gpio_leds_match); ++ ++ /* This we add to the driver to get it probed */ ++ static const struct acpi_device_id acpi_gpio_leds_match[] = { ++ { "PRP0001" }, /* Device Tree shoehorned into ACPI */ ++ {}, ++ }; ++ MODULE_DEVICE_TABLE(acpi, acpi_gpio_leds_match); ++ ++ static struct platform_driver gpio_led_driver = { ++ .driver = { ++ /* ++ * No of_match_ptr() here because we want this ++ * table to be visible even when !CONFIG_OF to ++ * match against "compatible" in _DSD. ++ */ ++ .of_match_table = of_gpio_leds_match, ++ .acpi_match_table = acpi_gpio_leds_match, ++ }, ++ }; ++ ++Once ACPI core sees "PRP0001" and that the device has "compatible" ++property it will do the match using .of_match_table instead. ++ ++It is preferred that new devices get a proper _HID allocated for them ++instead of inventing new DT "compatible" devices. diff --git a/Documentation/arm64/arm-acpi.txt b/Documentation/arm64/arm-acpi.txt new file mode 100644 index 0000000..b7dc826 @@ -1639,10 +723,10 @@ index 10d51c2..9464c6d 100644 See also Documentation/power/runtime_pm.txt, pci=noacpi diff --git a/MAINTAINERS b/MAINTAINERS -index 3705430..f6b49e4 100644 +index f10ed39..a8c9b14 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -6940,6 +6940,14 @@ L: linux-pci@vger.kernel.org +@@ -6946,6 +6946,14 @@ L: linux-pci@vger.kernel.org S: Maintained F: drivers/pci/host/*spear* @@ -1658,14 +742,14 @@ index 3705430..f6b49e4 100644 P: Linux PCMCIA Team L: linux-pcmcia@lists.infradead.org diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h -index 3d23418..22b7529 100644 +index 3d23418..1805674 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -178,6 +178,7 @@ static inline void __iomem *__typesafe_io(unsigned long addr) /* PCI fixed i/o mapping */ #define PCI_IO_VIRT_BASE 0xfee00000 -+#define PCI_IOBASE PCI_IO_VIRT_BASE ++#define PCI_IOBASE ((void __iomem *)PCI_IO_VIRT_BASE) #if defined(CONFIG_PCI) void pci_ioremap_set_mem_type(int mem_type); @@ -3146,6 +2230,126 @@ index 0000000..ce5836c + bus->domain_nr = domain; +} +#endif +diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c +index baf5afb..a0fb686 100644 +--- a/arch/arm64/kernel/perf_event.c ++++ b/arch/arm64/kernel/perf_event.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1304,6 +1305,107 @@ static int __init register_pmu_driver(void) + } + device_initcall(register_pmu_driver); + ++#ifdef CONFIG_ACPI ++struct acpi_pmu_irq { ++ int gsi; ++ int trigger; ++}; ++ ++static struct acpi_pmu_irq acpi_pmu_irqs[NR_CPUS] __initdata; ++ ++static int __init ++acpi_parse_pmu_irqs(struct acpi_subtable_header *header, ++ const unsigned long end) ++{ ++ struct acpi_madt_generic_interrupt *gic; ++ int cpu; ++ u64 mpidr; ++ ++ gic = (struct acpi_madt_generic_interrupt *)header; ++ if (BAD_MADT_ENTRY(gic, end)) ++ return -EINVAL; ++ ++ mpidr = gic->arm_mpidr & MPIDR_HWID_BITMASK; ++ ++ for_each_possible_cpu(cpu) { ++ if (cpu_logical_map(cpu) != mpidr) ++ continue; ++ ++ acpi_pmu_irqs[cpu].gsi = gic->performance_interrupt; ++ if (gic->flags & ACPI_MADT_PERFORMANCE_IRQ_MODE) ++ acpi_pmu_irqs[cpu].trigger = ACPI_EDGE_SENSITIVE; ++ else ++ acpi_pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int __init pmu_acpi_init(void) ++{ ++ struct platform_device *pdev; ++ struct acpi_pmu_irq *pirq = acpi_pmu_irqs; ++ struct resource *res, *r; ++ int err = -ENOMEM; ++ int i, count, irq; ++ ++ if (acpi_disabled) ++ return 0; ++ ++ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, ++ acpi_parse_pmu_irqs, num_possible_cpus()); ++ /* Must have irq for boot boot cpu, at least */ ++ if (count <= 0 || pirq->gsi == 0) ++ return -EINVAL; ++ ++ irq = acpi_register_gsi(NULL, pirq->gsi, pirq->trigger, ++ ACPI_ACTIVE_HIGH); ++ ++ if (irq_is_percpu(irq)) ++ count = 1; ++ ++ pdev = platform_device_alloc("arm-pmu", -1); ++ if (!pdev) ++ return err; ++ ++ res = kcalloc(count, sizeof(*res), GFP_KERNEL); ++ if (!res) ++ goto err_free_device; ++ ++ for (i = 0, r = res; i < count; i++, pirq++, r++) { ++ if (i) ++ irq = acpi_register_gsi(NULL, pirq->gsi, pirq->trigger, ++ ACPI_ACTIVE_HIGH); ++ r->start = r->end = irq; ++ r->flags = IORESOURCE_IRQ; ++ if (pirq->trigger == ACPI_EDGE_SENSITIVE) ++ r->flags |= IORESOURCE_IRQ_HIGHEDGE; ++ else ++ r->flags |= IORESOURCE_IRQ_HIGHLEVEL; ++ } ++ ++ err = platform_device_add_resources(pdev, res, count); ++ if (err) ++ goto err_free_res; ++ ++ err = platform_device_add(pdev); ++ if (err) ++ goto err_free_res; ++ ++ return 0; ++ ++err_free_res: ++ kfree(res); ++ ++err_free_device: ++ platform_device_put(pdev); ++ return err; ++} ++arch_initcall(pmu_acpi_init); ++ ++#endif /* ACPI */ ++ + static struct pmu_hw_events *armpmu_get_cpu_events(void) + { + return this_cpu_ptr(&cpu_hw_events); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 29d4869..c0427bc 100644 --- a/arch/arm64/kernel/process.c @@ -3832,7 +3036,7 @@ index d0f3265..3343080 100644 help This driver creates entries in /sys/bus/pci/slots/ for all PCI diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile -index 505d4d7..6f3a74d 100644 +index 505d4d7..252d0ff 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -23,7 +23,11 @@ acpi-y += nvs.o @@ -3847,7 +3051,7 @@ index 505d4d7..6f3a74d 100644 acpi-y += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o -@@ -39,7 +43,7 @@ acpi-y += processor_core.o +@@ -39,13 +43,14 @@ acpi-y += processor_core.o acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o @@ -3856,6 +3060,13 @@ index 505d4d7..6f3a74d 100644 acpi-y += acpi_lpss.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o + acpi-y += power.o + acpi-y += event.o + acpi-y += sysfs.o ++acpi-y += property.o + acpi-$(CONFIG_X86) += acpi_cmos_rtc.o + acpi-$(CONFIG_DEBUG_FS) += debugfs.o + acpi-$(CONFIG_ACPI_NUMA) += numa.o diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index 14cb6c0..5cd017c 100644 --- a/drivers/acpi/acpica/utresrc.c @@ -3886,7 +3097,7 @@ index 8b67bd0..c412fdb 100644 message = "platform specific model"; break; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h -index 4c5cf77..e1e6487 100644 +index 4c5cf77..926ca5c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -26,8 +26,13 @@ @@ -3903,6 +3114,17 @@ index 4c5cf77..e1e6487 100644 void acpi_processor_init(void); void acpi_platform_init(void); void acpi_pnp_init(void); +@@ -181,4 +186,10 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev); + bool acpi_osi_is_win8(void); + #endif + ++/*-------------------------------------------------------------------------- ++ Device properties ++ -------------------------------------------------------------------------- */ ++void acpi_init_properties(struct acpi_device *adev); ++void acpi_free_properties(struct acpi_device *adev); ++ + #endif /* _ACPI_INTERNAL_H_ */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 3abe9b2..c50757b 100644 --- a/drivers/acpi/osl.c @@ -3984,93 +3206,811 @@ index e32321c..4007313 100644 } exit: -diff --git a/drivers/acpi/sleep-arm.c b/drivers/acpi/sleep-arm.c +diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c new file mode 100644 -index 0000000..54578ef +index 0000000..ff53eb8 --- /dev/null -+++ b/drivers/acpi/sleep-arm.c -@@ -0,0 +1,28 @@ ++++ b/drivers/acpi/property.c +@@ -0,0 +1,586 @@ +/* -+ * ARM64 Specific Sleep Functionality ++ * ACPI device specific properties support. + * -+ * Copyright (C) 2013-2014, Linaro Ltd. -+ * Author: Graeme Gregory ++ * Copyright (C) 2014, Intel Corporation ++ * All rights reserved. + * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. ++ * Authors: Mika Westerberg ++ * Darren Hart ++ * Rafael J. Wysocki ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. + */ + +#include ++#include ++#include + -+/* -+ * Currently the ACPI 5.1 standard does not define S states in a -+ * manner which is usable for ARM64. These two stubs are sufficient -+ * that system initialises and device PM works. -+ */ -+u32 acpi_target_system_state(void) ++#include "internal.h" ++ ++/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */ ++static const u8 prp_uuid[16] = { ++ 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d, ++ 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01 ++}; ++ ++static bool acpi_property_value_ok(const union acpi_object *value) +{ -+ return ACPI_STATE_S0; ++ int j; ++ ++ /* ++ * The value must be an integer, a string, a reference, or a package ++ * whose every element must be an integer, a string, or a reference. ++ */ ++ switch (value->type) { ++ case ACPI_TYPE_INTEGER: ++ case ACPI_TYPE_STRING: ++ case ACPI_TYPE_LOCAL_REFERENCE: ++ return true; ++ ++ case ACPI_TYPE_PACKAGE: ++ for (j = 0; j < value->package.count; j++) ++ switch (value->package.elements[j].type) { ++ case ACPI_TYPE_INTEGER: ++ case ACPI_TYPE_STRING: ++ case ACPI_TYPE_LOCAL_REFERENCE: ++ continue; ++ ++ default: ++ return false; ++ } ++ ++ return true; ++ } ++ return false; +} -+EXPORT_SYMBOL_GPL(acpi_target_system_state); + -+int __init acpi_sleep_init(void) ++static bool acpi_properties_format_valid(const union acpi_object *properties) +{ -+ return -ENOSYS; -+} -diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c -index 6d5a6cd..47f36d4 100644 ---- a/drivers/acpi/tables.c -+++ b/drivers/acpi/tables.c -@@ -183,6 +183,49 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) - } - break; - -+ case ACPI_MADT_TYPE_GENERIC_INTERRUPT: -+ { -+ struct acpi_madt_generic_interrupt *p = -+ (struct acpi_madt_generic_interrupt *)header; -+ pr_info("GICC (acpi_id[0x%04x] address[%p] MPDIR[0x%llx] %s)\n", -+ p->uid, (void *)(unsigned long)p->base_address, -+ p->arm_mpidr, -+ (p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); ++ int i; + -+ } -+ break; ++ for (i = 0; i < properties->package.count; i++) { ++ const union acpi_object *property; + -+ case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: -+ { -+ struct acpi_madt_generic_distributor *p = -+ (struct acpi_madt_generic_distributor *)header; -+ pr_info("GIC Distributor (gic_id[0x%04x] address[%p] gsi_base[%d])\n", -+ p->gic_id, -+ (void *)(unsigned long)p->base_address, -+ p->global_irq_base); -+ } -+ break; ++ property = &properties->package.elements[i]; ++ /* ++ * Only two elements allowed, the first one must be a string and ++ * the second one has to satisfy certain conditions. ++ */ ++ if (property->package.count != 2 ++ || property->package.elements[0].type != ACPI_TYPE_STRING ++ || !acpi_property_value_ok(&property->package.elements[1])) ++ return false; ++ } ++ return true; ++} + -+ case ACPI_MADT_TYPE_GENERIC_MSI_FRAME: -+ { -+ struct acpi_madt_generic_msi_frame *p = -+ (struct acpi_madt_generic_msi_frame *)header; -+ pr_info("GIC MSI Frame (msi_fame_id[%d] address[%p])\n", -+ p->msi_frame_id, -+ (void *)(unsigned long)p->base_address); -+ } -+ break; ++static void acpi_init_of_compatible(struct acpi_device *adev) ++{ ++ const union acpi_object *of_compatible; ++ struct acpi_hardware_id *hwid; ++ bool acpi_of = false; + -+ case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: -+ { -+ struct acpi_madt_generic_redistributor *p = -+ (struct acpi_madt_generic_redistributor *)header; -+ pr_info("GIC Redistributor (address[%p] region_size[0x%x])\n", -+ (void *)(unsigned long)p->base_address, -+ p->length); ++ /* ++ * Check if the special PRP0001 ACPI ID is present and in that ++ * case we fill in Device Tree compatible properties for this ++ * device. ++ */ ++ list_for_each_entry(hwid, &adev->pnp.ids, list) { ++ if (!strcmp(hwid->id, "PRP0001")) { ++ acpi_of = true; ++ break; + } -+ break; ++ } + - default: - pr_warn("Found unsupported MADT entry (type = 0x%x)\n", ++ if (!acpi_of) ++ return; ++ ++ if (acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING, ++ &of_compatible)) { ++ acpi_handle_warn(adev->handle, ++ "PRP0001 requires compatible property\n"); ++ return; ++ } ++ ++ adev->data.of_compatible = of_compatible; ++} ++ ++void acpi_init_properties(struct acpi_device *adev) ++{ ++ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; ++ const union acpi_object *desc; ++ acpi_status status; ++ int i; ++ ++ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf, ++ ACPI_TYPE_PACKAGE); ++ if (ACPI_FAILURE(status)) ++ return; ++ ++ desc = buf.pointer; ++ if (desc->package.count % 2) ++ goto fail; ++ ++ /* Look for the device properties UUID. */ ++ for (i = 0; i < desc->package.count; i += 2) { ++ const union acpi_object *uuid, *properties; ++ ++ uuid = &desc->package.elements[i]; ++ properties = &desc->package.elements[i + 1]; ++ ++ /* ++ * The first element must be a UUID and the second one must be ++ * a package. ++ */ ++ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16 ++ || properties->type != ACPI_TYPE_PACKAGE) ++ break; ++ ++ if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid))) ++ continue; ++ ++ /* ++ * We found the matching UUID. Now validate the format of the ++ * package immediately following it. ++ */ ++ if (!acpi_properties_format_valid(properties)) ++ break; ++ ++ adev->data.pointer = buf.pointer; ++ adev->data.properties = properties; ++ ++ acpi_init_of_compatible(adev); ++ return; ++ } ++ ++ fail: ++ dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n"); ++ ACPI_FREE(buf.pointer); ++} ++ ++void acpi_free_properties(struct acpi_device *adev) ++{ ++ ACPI_FREE((void *)adev->data.pointer); ++ adev->data.of_compatible = NULL; ++ adev->data.pointer = NULL; ++ adev->data.properties = NULL; ++} ++ ++/** ++ * acpi_dev_get_property - return an ACPI property with given name ++ * @adev: ACPI device to get property ++ * @name: Name of the property ++ * @type: Expected property type ++ * @obj: Location to store the property value (if not %NULL) ++ * ++ * Look up a property with @name and store a pointer to the resulting ACPI ++ * object at the location pointed to by @obj if found. ++ * ++ * Callers must not attempt to free the returned objects. These objects will be ++ * freed by the ACPI core automatically during the removal of @adev. ++ * ++ * Return: %0 if property with @name has been found (success), ++ * %-EINVAL if the arguments are invalid, ++ * %-ENODATA if the property doesn't exist, ++ * %-EPROTO if the property value type doesn't match @type. ++ */ ++int acpi_dev_get_property(struct acpi_device *adev, const char *name, ++ acpi_object_type type, const union acpi_object **obj) ++{ ++ const union acpi_object *properties; ++ int i; ++ ++ if (!adev || !name) ++ return -EINVAL; ++ ++ if (!adev->data.pointer || !adev->data.properties) ++ return -ENODATA; ++ ++ properties = adev->data.properties; ++ for (i = 0; i < properties->package.count; i++) { ++ const union acpi_object *propname, *propvalue; ++ const union acpi_object *property; ++ ++ property = &properties->package.elements[i]; ++ ++ propname = &property->package.elements[0]; ++ propvalue = &property->package.elements[1]; ++ ++ if (!strcmp(name, propname->string.pointer)) { ++ if (type != ACPI_TYPE_ANY && propvalue->type != type) ++ return -EPROTO; ++ else if (obj) ++ *obj = propvalue; ++ ++ return 0; ++ } ++ } ++ return -ENODATA; ++} ++EXPORT_SYMBOL_GPL(acpi_dev_get_property); ++ ++/** ++ * acpi_dev_get_property_array - return an ACPI array property with given name ++ * @adev: ACPI device to get property ++ * @name: Name of the property ++ * @type: Expected type of array elements ++ * @obj: Location to store a pointer to the property value (if not NULL) ++ * ++ * Look up an array property with @name and store a pointer to the resulting ++ * ACPI object at the location pointed to by @obj if found. ++ * ++ * Callers must not attempt to free the returned objects. Those objects will be ++ * freed by the ACPI core automatically during the removal of @adev. ++ * ++ * Return: %0 if array property (package) with @name has been found (success), ++ * %-EINVAL if the arguments are invalid, ++ * %-ENODATA if the property doesn't exist, ++ * %-EPROTO if the property is not a package or the type of its elements ++ * doesn't match @type. ++ */ ++int acpi_dev_get_property_array(struct acpi_device *adev, const char *name, ++ acpi_object_type type, ++ const union acpi_object **obj) ++{ ++ const union acpi_object *prop; ++ int ret, i; ++ ++ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop); ++ if (ret) ++ return ret; ++ ++ if (type != ACPI_TYPE_ANY) { ++ /* Check that all elements are of correct type. */ ++ for (i = 0; i < prop->package.count; i++) ++ if (prop->package.elements[i].type != type) ++ return -EPROTO; ++ } ++ if (obj) ++ *obj = prop; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(acpi_dev_get_property_array); ++ ++/** ++ * acpi_dev_get_property_reference - returns handle to the referenced object ++ * @adev: ACPI device to get property ++ * @name: Name of the property ++ * @size_prop: Name of the "size" property in referenced object ++ * @index: Index of the reference to return ++ * @args: Location to store the returned reference with optional arguments ++ * ++ * Find property with @name, verifify that it is a package containing at least ++ * one object reference and if so, store the ACPI device object pointer to the ++ * target object in @args->adev. ++ * ++ * If the reference includes arguments (@size_prop is not %NULL) follow the ++ * reference and check whether or not there is an integer property @size_prop ++ * under the target object and if so, whether or not its value matches the ++ * number of arguments that follow the reference. If there's more than one ++ * reference in the property value package, @index is used to select the one to ++ * return. ++ * ++ * Return: %0 on success, negative error code on failure. ++ */ ++int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name, ++ const char *size_prop, size_t index, ++ struct acpi_reference_args *args) ++{ ++ const union acpi_object *element, *end; ++ const union acpi_object *obj; ++ struct acpi_device *device; ++ int ret, idx = 0; ++ ++ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj); ++ if (ret) ++ return ret; ++ ++ /* ++ * The simplest case is when the value is a single reference. Just ++ * return that reference then. ++ */ ++ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) { ++ if (size_prop || index) ++ return -EINVAL; ++ ++ ret = acpi_bus_get_device(obj->reference.handle, &device); ++ if (ret) ++ return ret; ++ ++ args->adev = device; ++ args->nargs = 0; ++ return 0; ++ } ++ ++ /* ++ * If it is not a single reference, then it is a package of ++ * references followed by number of ints as follows: ++ * ++ * Package () { REF, INT, REF, INT, INT } ++ * ++ * The index argument is then used to determine which reference ++ * the caller wants (along with the arguments). ++ */ ++ if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count) ++ return -EPROTO; ++ ++ element = obj->package.elements; ++ end = element + obj->package.count; ++ ++ while (element < end) { ++ u32 nargs, i; ++ ++ if (element->type != ACPI_TYPE_LOCAL_REFERENCE) ++ return -EPROTO; ++ ++ ret = acpi_bus_get_device(element->reference.handle, &device); ++ if (ret) ++ return -ENODEV; ++ ++ element++; ++ nargs = 0; ++ ++ if (size_prop) { ++ const union acpi_object *prop; ++ ++ /* ++ * Find out how many arguments the refenced object ++ * expects by reading its size_prop property. ++ */ ++ ret = acpi_dev_get_property(device, size_prop, ++ ACPI_TYPE_INTEGER, &prop); ++ if (ret) ++ return ret; ++ ++ nargs = prop->integer.value; ++ if (nargs > MAX_ACPI_REFERENCE_ARGS ++ || element + nargs > end) ++ return -EPROTO; ++ ++ /* ++ * Skip to the start of the arguments and verify ++ * that they all are in fact integers. ++ */ ++ for (i = 0; i < nargs; i++) ++ if (element[i].type != ACPI_TYPE_INTEGER) ++ return -EPROTO; ++ } else { ++ /* assume following integer elements are all args */ ++ for (i = 0; element + i < end; i++) { ++ int type = element[i].type; ++ ++ if (type == ACPI_TYPE_INTEGER) ++ nargs++; ++ else if (type == ACPI_TYPE_LOCAL_REFERENCE) ++ break; ++ else ++ return -EPROTO; ++ } ++ } ++ ++ if (idx++ == index) { ++ args->adev = device; ++ args->nargs = nargs; ++ for (i = 0; i < nargs; i++) ++ args->args[i] = element[i].integer.value; ++ ++ return 0; ++ } ++ ++ element += nargs; ++ } ++ ++ return -EPROTO; ++} ++EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference); ++ ++int acpi_dev_prop_get(struct acpi_device *adev, const char *propname, ++ void **valptr) ++{ ++ return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY, ++ (const union acpi_object **)valptr); ++} ++ ++int acpi_dev_prop_read(struct acpi_device *adev, const char *propname, ++ enum dev_prop_type proptype, void *val) ++{ ++ const union acpi_object *obj; ++ int ret = -EINVAL; ++ ++ if (!val) ++ return -EINVAL; ++ ++ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) { ++ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj); ++ if (ret) ++ return ret; ++ ++ switch (proptype) { ++ case DEV_PROP_U8: ++ if (obj->integer.value > U8_MAX) ++ return -EOVERFLOW; ++ *(u8 *)val = obj->integer.value; ++ break; ++ case DEV_PROP_U16: ++ if (obj->integer.value > U16_MAX) ++ return -EOVERFLOW; ++ *(u16 *)val = obj->integer.value; ++ break; ++ case DEV_PROP_U32: ++ if (obj->integer.value > U32_MAX) ++ return -EOVERFLOW; ++ *(u32 *)val = obj->integer.value; ++ break; ++ default: ++ *(u64 *)val = obj->integer.value; ++ break; ++ } ++ } else if (proptype == DEV_PROP_STRING) { ++ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj); ++ if (ret) ++ return ret; ++ ++ *(char **)val = obj->string.pointer; ++ } ++ return ret; ++} ++ ++static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val, ++ size_t nval) ++{ ++ int i; ++ ++ for (i = 0; i < nval; i++) { ++ if (items[i].type != ACPI_TYPE_INTEGER) ++ return -EPROTO; ++ if (items[i].integer.value > U8_MAX) ++ return -EOVERFLOW; ++ ++ val[i] = items[i].integer.value; ++ } ++ return 0; ++} ++ ++static int acpi_copy_property_array_u16(const union acpi_object *items, ++ u16 *val, size_t nval) ++{ ++ int i; ++ ++ for (i = 0; i < nval; i++) { ++ if (items[i].type != ACPI_TYPE_INTEGER) ++ return -EPROTO; ++ if (items[i].integer.value > U16_MAX) ++ return -EOVERFLOW; ++ ++ val[i] = items[i].integer.value; ++ } ++ return 0; ++} ++ ++static int acpi_copy_property_array_u32(const union acpi_object *items, ++ u32 *val, size_t nval) ++{ ++ int i; ++ ++ for (i = 0; i < nval; i++) { ++ if (items[i].type != ACPI_TYPE_INTEGER) ++ return -EPROTO; ++ if (items[i].integer.value > U32_MAX) ++ return -EOVERFLOW; ++ ++ val[i] = items[i].integer.value; ++ } ++ return 0; ++} ++ ++static int acpi_copy_property_array_u64(const union acpi_object *items, ++ u64 *val, size_t nval) ++{ ++ int i; ++ ++ for (i = 0; i < nval; i++) { ++ if (items[i].type != ACPI_TYPE_INTEGER) ++ return -EPROTO; ++ ++ val[i] = items[i].integer.value; ++ } ++ return 0; ++} ++ ++static int acpi_copy_property_array_string(const union acpi_object *items, ++ char **val, size_t nval) ++{ ++ int i; ++ ++ for (i = 0; i < nval; i++) { ++ if (items[i].type != ACPI_TYPE_STRING) ++ return -EPROTO; ++ ++ val[i] = items[i].string.pointer; ++ } ++ return 0; ++} ++ ++int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname, ++ enum dev_prop_type proptype, void *val, ++ size_t nval) ++{ ++ const union acpi_object *obj; ++ const union acpi_object *items; ++ int ret; ++ ++ ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj); ++ if (ret) ++ return ret; ++ ++ if (!val) ++ return obj->package.count; ++ ++ if (nval > obj->package.count) ++ nval = obj->package.count; ++ ++ items = obj->package.elements; ++ switch (proptype) { ++ case DEV_PROP_U8: ++ ret = acpi_copy_property_array_u8(items, (u8 *)val, nval); ++ break; ++ case DEV_PROP_U16: ++ ret = acpi_copy_property_array_u16(items, (u16 *)val, nval); ++ break; ++ case DEV_PROP_U32: ++ ret = acpi_copy_property_array_u32(items, (u32 *)val, nval); ++ break; ++ case DEV_PROP_U64: ++ ret = acpi_copy_property_array_u64(items, (u64 *)val, nval); ++ break; ++ case DEV_PROP_STRING: ++ ret = acpi_copy_property_array_string(items, (char **)val, nval); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++int acpi_for_each_child_node(struct device *dev, ++ int (*fn)(struct device *dev, void *child, void *data), ++ void *data) ++{ ++ struct acpi_device *adev = ACPI_COMPANION(dev); ++ struct acpi_device *child; ++ int ret = 0; ++ ++ if (!adev) ++ return -EINVAL; ++ ++ list_for_each_entry(child, &adev->children, node) { ++ ret = fn(dev, child, data); ++ if (ret) ++ break; ++ } ++ return ret; ++} +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index ae44d86..4da55d8 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -124,17 +124,43 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, + if (list_empty(&acpi_dev->pnp.ids)) + return 0; + +- len = snprintf(modalias, size, "acpi:"); +- size -= len; ++ /* ++ * If the device has PRP0001 we expose DT compatible modalias ++ * instead. ++ */ ++ if (acpi_dev->data.of_compatible) { ++ const union acpi_object *of_compatible, *obj; ++ int i; ++ ++ len = snprintf(modalias, size, "of:Nprp0001Tacpi"); ++ ++ of_compatible = acpi_dev->data.of_compatible; ++ for (i = 0; i < of_compatible->package.count; i++) { ++ obj = &of_compatible->package.elements[i]; + +- list_for_each_entry(id, &acpi_dev->pnp.ids, list) { +- count = snprintf(&modalias[len], size, "%s:", id->id); +- if (count < 0) +- return -EINVAL; +- if (count >= size) +- return -ENOMEM; +- len += count; +- size -= count; ++ count = snprintf(&modalias[len], size, "C%s", ++ obj->string.pointer); ++ if (count < 0) ++ return -EINVAL; ++ if (count >= size) ++ return -ENOMEM; ++ ++ len += count; ++ size -= count; ++ } ++ } else { ++ len = snprintf(modalias, size, "acpi:"); ++ size -= len; ++ ++ list_for_each_entry(id, &acpi_dev->pnp.ids, list) { ++ count = snprintf(&modalias[len], size, "%s:", id->id); ++ if (count < 0) ++ return -EINVAL; ++ if (count >= size) ++ return -ENOMEM; ++ len += count; ++ size -= count; ++ } + } + + modalias[len] = '\0'; +@@ -864,6 +890,51 @@ int acpi_match_device_ids(struct acpi_device *device, + } + EXPORT_SYMBOL(acpi_match_device_ids); + ++/* Performs match for special "PRP0001" shoehorn ACPI ID */ ++static bool acpi_of_driver_match_device(struct device *dev, ++ const struct device_driver *drv) ++{ ++ struct acpi_device *adev = ACPI_COMPANION(dev); ++ const union acpi_object *of_compatible; ++ int i; ++ ++ /* ++ * If the ACPI device does not have corresponding compatible ++ * property or the driver in question does not have DT matching ++ * table we consider the match succesful (matches the ACPI ID). ++ */ ++ of_compatible = adev->data.of_compatible; ++ if (!drv->of_match_table || !of_compatible) ++ return true; ++ ++ /* Now we can look for the driver DT compatible strings */ ++ for (i = 0; i < of_compatible->package.count; i++) { ++ const struct of_device_id *id; ++ const union acpi_object *obj; ++ ++ obj = &of_compatible->package.elements[i]; ++ ++ for (id = drv->of_match_table; id->compatible[0]; id++) ++ if (!strcasecmp(obj->string.pointer, id->compatible)) ++ return true; ++ } ++ ++ return false; ++} ++ ++bool acpi_driver_match_device(struct device *dev, ++ const struct device_driver *drv) ++{ ++ const struct acpi_device_id *id; ++ ++ id = acpi_match_device(drv->acpi_match_table, dev); ++ if (!id) ++ return false; ++ ++ return acpi_of_driver_match_device(dev, drv); ++} ++EXPORT_SYMBOL_GPL(acpi_driver_match_device); ++ + static void acpi_free_power_resources_lists(struct acpi_device *device) + { + int i; +@@ -884,6 +955,7 @@ static void acpi_device_release(struct device *dev) + { + struct acpi_device *acpi_dev = to_acpi_device(dev); + ++ acpi_free_properties(acpi_dev); + acpi_free_pnp_ids(&acpi_dev->pnp); + acpi_free_power_resources_lists(acpi_dev); + kfree(acpi_dev); +@@ -1888,6 +1960,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, + acpi_set_device_status(device, sta); + acpi_device_get_busid(device); + acpi_set_pnp_ids(handle, &device->pnp, type); ++ acpi_init_properties(device); + acpi_bus_get_flags(device); + device->flags.match_driver = false; + device->flags.initialized = true; +diff --git a/drivers/acpi/sleep-arm.c b/drivers/acpi/sleep-arm.c +new file mode 100644 +index 0000000..54578ef +--- /dev/null ++++ b/drivers/acpi/sleep-arm.c +@@ -0,0 +1,28 @@ ++/* ++ * ARM64 Specific Sleep Functionality ++ * ++ * Copyright (C) 2013-2014, Linaro Ltd. ++ * Author: Graeme Gregory ++ * ++ * 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 ++ ++/* ++ * Currently the ACPI 5.1 standard does not define S states in a ++ * manner which is usable for ARM64. These two stubs are sufficient ++ * that system initialises and device PM works. ++ */ ++u32 acpi_target_system_state(void) ++{ ++ return ACPI_STATE_S0; ++} ++EXPORT_SYMBOL_GPL(acpi_target_system_state); ++ ++int __init acpi_sleep_init(void) ++{ ++ return -ENOSYS; ++} +diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c +index 6d5a6cd..47f36d4 100644 +--- a/drivers/acpi/tables.c ++++ b/drivers/acpi/tables.c +@@ -183,6 +183,49 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) + } + break; + ++ case ACPI_MADT_TYPE_GENERIC_INTERRUPT: ++ { ++ struct acpi_madt_generic_interrupt *p = ++ (struct acpi_madt_generic_interrupt *)header; ++ pr_info("GICC (acpi_id[0x%04x] address[%p] MPDIR[0x%llx] %s)\n", ++ p->uid, (void *)(unsigned long)p->base_address, ++ p->arm_mpidr, ++ (p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); ++ ++ } ++ break; ++ ++ case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: ++ { ++ struct acpi_madt_generic_distributor *p = ++ (struct acpi_madt_generic_distributor *)header; ++ pr_info("GIC Distributor (gic_id[0x%04x] address[%p] gsi_base[%d])\n", ++ p->gic_id, ++ (void *)(unsigned long)p->base_address, ++ p->global_irq_base); ++ } ++ break; ++ ++ case ACPI_MADT_TYPE_GENERIC_MSI_FRAME: ++ { ++ struct acpi_madt_generic_msi_frame *p = ++ (struct acpi_madt_generic_msi_frame *)header; ++ pr_info("GIC MSI Frame (msi_fame_id[%d] address[%p])\n", ++ p->msi_frame_id, ++ (void *)(unsigned long)p->base_address); ++ } ++ break; ++ ++ case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: ++ { ++ struct acpi_madt_generic_redistributor *p = ++ (struct acpi_madt_generic_redistributor *)header; ++ pr_info("GIC Redistributor (address[%p] region_size[0x%x])\n", ++ (void *)(unsigned long)p->base_address, ++ p->length); ++ } ++ break; ++ + default: + pr_warn("Found unsupported MADT entry (type = 0x%x)\n", header->type); @@ -192,17 +235,14 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) @@ -4328,34 +4268,288 @@ index f03aab1..b02ba9d 100644 xgene_ahci_hw_init(hpriv); -skip_clk_phy: + - hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ; - - rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info); -@@ -527,6 +516,16 @@ disable_resources: - return rc; - } - -+#ifdef CONFIG_ACPI -+static const struct acpi_device_id xgene_ahci_acpi_match[] = { -+ { "APMC0D00", }, -+ { "APMC0D0D", }, -+ { "APMC0D09", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match); -+#endif + hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ; + + rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info); +@@ -527,6 +516,16 @@ disable_resources: + return rc; + } + ++#ifdef CONFIG_ACPI ++static const struct acpi_device_id xgene_ahci_acpi_match[] = { ++ { "APMC0D00", }, ++ { "APMC0D0D", }, ++ { "APMC0D09", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match); ++#endif ++ + static const struct of_device_id xgene_ahci_of_match[] = { + {.compatible = "apm,xgene-ahci"}, + {}, +@@ -540,6 +539,7 @@ static struct platform_driver xgene_ahci_driver = { + .name = "xgene-ahci", + .owner = THIS_MODULE, + .of_match_table = xgene_ahci_of_match, ++ .acpi_match_table = ACPI_PTR(xgene_ahci_acpi_match), + }, + }; + +diff --git a/drivers/base/Makefile b/drivers/base/Makefile +index 4aab26e..0d801cf 100644 +--- a/drivers/base/Makefile ++++ b/drivers/base/Makefile +@@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ + driver.o class.o platform.o \ + cpu.o firmware.o init.o map.o devres.o \ + attribute_container.o transport_class.o \ +- topology.o container.o ++ topology.o container.o property.o + obj-$(CONFIG_DEVTMPFS) += devtmpfs.o + obj-$(CONFIG_DMA_CMA) += dma-contiguous.o + obj-y += power/ +diff --git a/drivers/base/property.c b/drivers/base/property.c +new file mode 100644 +index 0000000..7bf5708 +--- /dev/null ++++ b/drivers/base/property.c +@@ -0,0 +1,235 @@ ++/* ++ * property.c - Unified device property interface. ++ * ++ * Copyright (C) 2014, Intel Corporation ++ * Authors: Rafael J. Wysocki ++ * Mika Westerberg ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/** ++ * device_get_property - return a raw property of a device ++ * @dev: Device get the property of ++ * @propname: Name of the property ++ * @valptr: The raw property value is stored here ++ * ++ * Function reads property @propname from the device firmware description and ++ * stores the raw value into @valptr if found. Otherwise returns a negative ++ * errno as specified below. ++ * ++ * Return: %0 if the property was found (success), ++ * %-EINVAL if given arguments are not valid, ++ * %-ENODATA if the property does not exist. ++ */ ++int device_get_property(struct device *dev, const char *propname, void **valptr) ++{ ++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) ++ return of_dev_prop_get(dev->of_node, propname, valptr); ++ ++ return acpi_dev_prop_get(ACPI_COMPANION(dev), propname, valptr); ++} ++EXPORT_SYMBOL_GPL(device_get_property); ++ ++/** ++ * device_get_child_property - return a raw property of a device's child ++ * @dev: Parent device ++ * @child: Child to get a property of ++ * @propname: Name of the property ++ * @valptr: The raw property value is stored here ++ * ++ * Function reads property @propname from the firmware description of @child and ++ * stores the raw value into @valptr if found. Otherwise returns a negative ++ * errno as specified below. ++ * ++ * Return: %0 if the property was found (success), ++ * %-EINVAL if given arguments are not valid, ++ * %-ENODATA if the property does not exist. ++ */ ++int device_get_child_property(struct device *dev, void *child, ++ const char *propname, void **valptr) ++{ ++ if (!child) ++ return -EINVAL; ++ ++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) ++ return of_dev_prop_get(child, propname, valptr); ++ else if (ACPI_COMPANION(dev)) ++ return acpi_dev_prop_get(child, propname, valptr); ++ ++ return -ENODATA; ++} ++EXPORT_SYMBOL_GPL(device_get_child_property); ++ ++/** ++ * device_read_property - read a typed property of a device ++ * @dev: Device to get the property of ++ * @propname: Name of the property ++ * @proptype: Type of the property ++ * @val: The value is stored here ++ * ++ * Function reads property @propname from the device firmware description and ++ * stores the value into @val if found. The value is checked to be of type ++ * @proptype. ++ * ++ * Return: %0 if the property was found (success), ++ * %-EINVAL if given arguments are not valid, ++ * %-ENODATA if the property does not exist, ++ * %-EPROTO if the property type does not match @proptype, ++ * %-EOVERFLOW if the property value is out of bounds of @proptype. ++ */ ++int device_read_property(struct device *dev, const char *propname, ++ enum dev_prop_type proptype, void *val) ++{ ++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) ++ return of_dev_prop_read(dev->of_node, propname, proptype, val); ++ ++ return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, proptype, val); ++} ++EXPORT_SYMBOL_GPL(device_read_property); ++ ++/** ++ * device_read_child_property - read a typed property of a device's child ++ * @dev: Parent device ++ * @child: Child to read a property of ++ * @propname: Name of the property ++ * @proptype: Type of the property ++ * @val: The value is stored here ++ * ++ * Function reads property @propname from the firmware description of @child and ++ * stores the value into @val if found. The value is checked to be of type ++ * @proptype. ++ * ++ * Return: %0 if the property was found (success), ++ * %-EINVAL if given arguments are not valid, ++ * %-ENODATA if the property does not exist, ++ * %-EPROTO if the property type does not match @proptype, ++ * %-EOVERFLOW if the property value is out of bounds of @proptype. ++ */ ++int device_read_child_property(struct device *dev, void *child, ++ const char *propname, enum dev_prop_type proptype, ++ void *val) ++{ ++ if (!child) ++ return -EINVAL; ++ ++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) ++ return of_dev_prop_read(child, propname, proptype, val); ++ else if (ACPI_COMPANION(dev)) ++ return acpi_dev_prop_read(child, propname, proptype, val); ++ ++ return -ENODATA; ++} ++EXPORT_SYMBOL_GPL(device_read_child_property); ++ ++/** ++ * device_read_property_array - read an array property of a device ++ * @dev: Device to get the property of ++ * @propname: Name of the property ++ * @proptype: Type of the property ++ * @val: The values are stored here ++ * @nval: Size of the @val array ++ * ++ * Function reads an array of properties with @propname from the device ++ * firmware description and stores them to @val if found. All the values ++ * in the array must be of type @proptype. ++ * ++ * Return: %0 if the property was found (success), ++ * %-EINVAL if given arguments are not valid, ++ * %-ENODATA if the property does not exist, ++ * %-EPROTO if the property type does not match @proptype, ++ * %-EOVERFLOW if the property value is out of bounds of @proptype. ++ */ ++int device_read_property_array(struct device *dev, const char *propname, ++ enum dev_prop_type proptype, void *val, ++ size_t nval) ++{ ++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) ++ return of_dev_prop_read_array(dev->of_node, propname, proptype, ++ val, nval); ++ ++ return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname, proptype, ++ val, nval); ++} ++EXPORT_SYMBOL_GPL(device_read_property_array); ++ ++/** ++ * device_read_child_property_array - read an array property of a device's child ++ * @dev: Parent device ++ * @child: Child to get the property of ++ * @propname: Name of the property ++ * @proptype: Type of the property ++ * @val: The values are stored here ++ * @nval: Size of the @val array ++ * ++ * Function reads an array of properties with @propname from the firmware ++ * description of @child and stores them to @val if found. All the values ++ * in the array must be of type @proptype. ++ * ++ * Return: %0 if the property was found (success), ++ * %-EINVAL if given arguments are not valid, ++ * %-ENODATA if the property does not exist, ++ * %-EPROTO if the property type does not match @proptype, ++ * %-EOVERFLOW if the property value is out of bounds of @proptype. ++ */ ++int device_read_child_property_array(struct device *dev, void *child, ++ const char *propname, ++ enum dev_prop_type proptype, void *val, ++ size_t nval) ++{ ++ if (!child) ++ return -EINVAL; ++ ++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) ++ return of_dev_prop_read_array(child, propname, proptype, ++ val, nval); ++ else if (ACPI_COMPANION(dev)) ++ return acpi_dev_prop_read_array(child, propname, proptype, ++ val, nval); ++ ++ return -ENODATA; ++} ++EXPORT_SYMBOL_GPL(device_read_child_property_array); ++ ++/** ++ * device_for_each_child_node - execute function for each child node of device ++ * @dev: Device to run the function for ++ * @fn: Function to run ++ * @data: Additional data to pass to the function ++ */ ++int device_for_each_child_node(struct device *dev, ++ int (*fn)(struct device *dev, void *child, void *data), ++ void *data) ++{ ++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) ++ return of_for_each_child_node(dev, fn, data); ++ ++ return acpi_for_each_child_node(dev, fn, data); ++} ++EXPORT_SYMBOL_GPL(device_for_each_child_node); ++ ++static int increment_count(struct device *dev, void *child, void *data) ++{ ++ *((unsigned int *)data) += 1; ++ return 0; ++} ++ ++/** ++ * device_get_child_node_count - return the number of child nodes for device ++ * @dev: Device to cound the child nodes for ++ */ ++unsigned int device_get_child_node_count(struct device *dev) ++{ ++ unsigned int count = 0; + - static const struct of_device_id xgene_ahci_of_match[] = { - {.compatible = "apm,xgene-ahci"}, - {}, -@@ -540,6 +539,7 @@ static struct platform_driver xgene_ahci_driver = { - .name = "xgene-ahci", - .owner = THIS_MODULE, - .of_match_table = xgene_ahci_of_match, -+ .acpi_match_table = ACPI_PTR(xgene_ahci_acpi_match), - }, - }; - ++ device_for_each_child_node(dev, increment_count, &count); ++ return count; ++} ++EXPORT_SYMBOL_GPL(device_get_child_node_count); diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 5163ec1..1bec05b 100644 --- a/drivers/clocksource/arm_arch_timer.c @@ -4419,110 +4613,1074 @@ index 5163ec1..1bec05b 100644 } } -- arch_timer_c3stop = !of_property_read_bool(np, "always-on"); +- arch_timer_c3stop = !of_property_read_bool(np, "always-on"); +- + arch_timer_register(); + arch_timer_common_init(); + } +-CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); +-CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); ++ ++static void __init arch_timer_of_init(struct device_node *np) ++{ ++ int i; ++ ++ if (arch_timers_present & ARCH_CP15_TIMER) { ++ pr_warn("arch_timer: multiple nodes in dt, skipping\n"); ++ return; ++ } ++ ++ arch_timers_present |= ARCH_CP15_TIMER; ++ for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) ++ arch_timer_ppi[i] = irq_of_parse_and_map(np, i); ++ ++ arch_timer_detect_rate(NULL, np); ++ ++ arch_timer_c3stop = !of_property_read_bool(np, "always-on"); ++ ++ arch_timer_init(); ++} ++CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); ++CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); + + static void __init arch_timer_mem_init(struct device_node *np) + { +@@ -740,3 +752,71 @@ static void __init arch_timer_mem_init(struct device_node *np) + } + CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", + arch_timer_mem_init); ++ ++#ifdef CONFIG_ACPI ++static int __init ++map_generic_timer_interrupt(u32 interrupt, u32 flags) ++{ ++ int trigger, polarity; ++ ++ if (!interrupt) ++ return 0; ++ ++ trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE ++ : ACPI_LEVEL_SENSITIVE; ++ ++ polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW ++ : ACPI_ACTIVE_HIGH; ++ ++ return acpi_register_gsi(NULL, interrupt, trigger, polarity); ++} ++ ++/* Initialize per-processor generic timer */ ++static int __init arch_timer_acpi_init(struct acpi_table_header *table) ++{ ++ struct acpi_table_gtdt *gtdt; ++ ++ if (arch_timers_present & ARCH_CP15_TIMER) { ++ pr_warn("arch_timer: already initialized, skipping\n"); ++ return -EINVAL; ++ } ++ ++ gtdt = container_of(table, struct acpi_table_gtdt, header); ++ ++ arch_timers_present |= ARCH_CP15_TIMER; ++ ++ arch_timer_ppi[PHYS_SECURE_PPI] = ++ map_generic_timer_interrupt(gtdt->secure_el1_interrupt, ++ gtdt->secure_el1_flags); ++ ++ arch_timer_ppi[PHYS_NONSECURE_PPI] = ++ map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt, ++ gtdt->non_secure_el1_flags); ++ ++ arch_timer_ppi[VIRT_PPI] = ++ map_generic_timer_interrupt(gtdt->virtual_timer_interrupt, ++ gtdt->virtual_timer_flags); ++ ++ arch_timer_ppi[HYP_PPI] = ++ map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt, ++ gtdt->non_secure_el2_flags); ++ ++ /* Get the frequency from CNTFRQ */ ++ arch_timer_detect_rate(NULL, NULL); ++ ++ /* Always-on capability */ ++ arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON); ++ ++ arch_timer_init(); ++ return 0; ++} ++ ++/* Initialize all the generic timers presented in GTDT */ ++void __init acpi_generic_timer_init(void) ++{ ++ if (acpi_disabled) ++ return; ++ ++ acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init); ++} ++#endif +diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c +index 954b9f6..a1f7e55 100644 +--- a/drivers/gpio/devres.c ++++ b/drivers/gpio/devres.c +@@ -109,6 +109,40 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, + EXPORT_SYMBOL(__devm_gpiod_get_index); + + /** ++ * devm_get_named_gpiod_from_child - managed dev_get_named_gpiod_from_child() ++ * @dev: GPIO consumer ++ * @child: firmware node (child of @dev) ++ * @propname: name of the firmware property ++ * @index: index of the GPIO in the property value in case of many ++ * ++ * GPIO descriptors returned from this function are automatically disposed on ++ * driver detach. ++ */ ++struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child, ++ const char *propname, int index) ++{ ++ struct gpio_desc **dr; ++ struct gpio_desc *desc; ++ ++ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), ++ GFP_KERNEL); ++ if (!dr) ++ return ERR_PTR(-ENOMEM); ++ ++ desc = dev_get_named_gpiod_from_child(dev, child, propname, index); ++ if (IS_ERR(desc)) { ++ devres_free(dr); ++ return desc; ++ } ++ ++ *dr = desc; ++ devres_add(dev, dr); ++ ++ return desc; ++} ++EXPORT_SYMBOL(devm_get_named_gpiod_from_child); ++ ++/** + * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer +diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c +index 41e91d7..99720c8 100644 +--- a/drivers/gpio/gpio-sch.c ++++ b/drivers/gpio/gpio-sch.c +@@ -29,290 +29,221 @@ + + #include + +-static DEFINE_SPINLOCK(gpio_lock); +- +-#define CGEN (0x00) +-#define CGIO (0x04) +-#define CGLV (0x08) +- +-#define RGEN (0x20) +-#define RGIO (0x24) +-#define RGLV (0x28) +- +-static unsigned short gpio_ba; +- +-static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num) +-{ +- u8 curr_dirs; +- unsigned short offset, bit; +- +- spin_lock(&gpio_lock); +- +- offset = CGIO + gpio_num / 8; +- bit = gpio_num % 8; +- +- curr_dirs = inb(gpio_ba + offset); +- +- if (!(curr_dirs & (1 << bit))) +- outb(curr_dirs | (1 << bit), gpio_ba + offset); ++#define GEN 0x00 ++#define GIO 0x04 ++#define GLV 0x08 ++ ++struct sch_gpio { ++ struct gpio_chip chip; ++ spinlock_t lock; ++ unsigned short iobase; ++ unsigned short core_base; ++ unsigned short resume_base; ++}; + +- spin_unlock(&gpio_lock); +- return 0; +-} ++#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip) + +-static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num) ++static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio, ++ unsigned reg) + { +- int res; +- unsigned short offset, bit; ++ unsigned base = 0; + +- offset = CGLV + gpio_num / 8; +- bit = gpio_num % 8; ++ if (gpio >= sch->resume_base) { ++ gpio -= sch->resume_base; ++ base += 0x20; ++ } + +- res = !!(inb(gpio_ba + offset) & (1 << bit)); +- return res; ++ return base + reg + gpio / 8; + } + +-static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val) ++static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio) + { +- u8 curr_vals; +- unsigned short offset, bit; +- +- spin_lock(&gpio_lock); +- +- offset = CGLV + gpio_num / 8; +- bit = gpio_num % 8; +- +- curr_vals = inb(gpio_ba + offset); +- +- if (val) +- outb(curr_vals | (1 << bit), gpio_ba + offset); +- else +- outb((curr_vals & ~(1 << bit)), gpio_ba + offset); +- spin_unlock(&gpio_lock); ++ if (gpio >= sch->resume_base) ++ gpio -= sch->resume_base; ++ return gpio % 8; + } + +-static int sch_gpio_core_direction_out(struct gpio_chip *gc, +- unsigned gpio_num, int val) ++static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio) + { +- u8 curr_dirs; + unsigned short offset, bit; ++ u8 enable; + +- spin_lock(&gpio_lock); ++ spin_lock(&sch->lock); + +- offset = CGIO + gpio_num / 8; +- bit = gpio_num % 8; +- +- curr_dirs = inb(gpio_ba + offset); +- if (curr_dirs & (1 << bit)) +- outb(curr_dirs & ~(1 << bit), gpio_ba + offset); ++ offset = sch_gpio_offset(sch, gpio, GEN); ++ bit = sch_gpio_bit(sch, gpio); + +- spin_unlock(&gpio_lock); ++ enable = inb(sch->iobase + offset); ++ if (!(enable & (1 << bit))) ++ outb(enable | (1 << bit), sch->iobase + offset); + +- /* +- * according to the datasheet, writing to the level register has no +- * effect when GPIO is programmed as input. +- * Actually the the level register is read-only when configured as input. +- * Thus presetting the output level before switching to output is _NOT_ possible. +- * Hence we set the level after configuring the GPIO as output. +- * But we cannot prevent a short low pulse if direction is set to high +- * and an external pull-up is connected. +- */ +- sch_gpio_core_set(gc, gpio_num, val); +- return 0; ++ spin_unlock(&sch->lock); + } + +-static struct gpio_chip sch_gpio_core = { +- .label = "sch_gpio_core", +- .owner = THIS_MODULE, +- .direction_input = sch_gpio_core_direction_in, +- .get = sch_gpio_core_get, +- .direction_output = sch_gpio_core_direction_out, +- .set = sch_gpio_core_set, +-}; +- +-static int sch_gpio_resume_direction_in(struct gpio_chip *gc, +- unsigned gpio_num) ++static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) + { ++ struct sch_gpio *sch = to_sch_gpio(gc); + u8 curr_dirs; + unsigned short offset, bit; + +- spin_lock(&gpio_lock); ++ spin_lock(&sch->lock); + +- offset = RGIO + gpio_num / 8; +- bit = gpio_num % 8; ++ offset = sch_gpio_offset(sch, gpio_num, GIO); ++ bit = sch_gpio_bit(sch, gpio_num); + +- curr_dirs = inb(gpio_ba + offset); ++ curr_dirs = inb(sch->iobase + offset); + + if (!(curr_dirs & (1 << bit))) +- outb(curr_dirs | (1 << bit), gpio_ba + offset); ++ outb(curr_dirs | (1 << bit), sch->iobase + offset); + +- spin_unlock(&gpio_lock); ++ spin_unlock(&sch->lock); + return 0; + } + +-static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num) ++static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num) + { ++ struct sch_gpio *sch = to_sch_gpio(gc); ++ int res; + unsigned short offset, bit; + +- offset = RGLV + gpio_num / 8; +- bit = gpio_num % 8; ++ offset = sch_gpio_offset(sch, gpio_num, GLV); ++ bit = sch_gpio_bit(sch, gpio_num); ++ ++ res = !!(inb(sch->iobase + offset) & (1 << bit)); + +- return !!(inb(gpio_ba + offset) & (1 << bit)); ++ return res; + } + +-static void sch_gpio_resume_set(struct gpio_chip *gc, +- unsigned gpio_num, int val) ++static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val) + { ++ struct sch_gpio *sch = to_sch_gpio(gc); + u8 curr_vals; + unsigned short offset, bit; + +- spin_lock(&gpio_lock); ++ spin_lock(&sch->lock); + +- offset = RGLV + gpio_num / 8; +- bit = gpio_num % 8; ++ offset = sch_gpio_offset(sch, gpio_num, GLV); ++ bit = sch_gpio_bit(sch, gpio_num); + +- curr_vals = inb(gpio_ba + offset); ++ curr_vals = inb(sch->iobase + offset); + + if (val) +- outb(curr_vals | (1 << bit), gpio_ba + offset); ++ outb(curr_vals | (1 << bit), sch->iobase + offset); + else +- outb((curr_vals & ~(1 << bit)), gpio_ba + offset); ++ outb((curr_vals & ~(1 << bit)), sch->iobase + offset); + +- spin_unlock(&gpio_lock); ++ spin_unlock(&sch->lock); + } + +-static int sch_gpio_resume_direction_out(struct gpio_chip *gc, +- unsigned gpio_num, int val) ++static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num, ++ int val) + { ++ struct sch_gpio *sch = to_sch_gpio(gc); + u8 curr_dirs; + unsigned short offset, bit; + +- offset = RGIO + gpio_num / 8; +- bit = gpio_num % 8; ++ spin_lock(&sch->lock); + +- spin_lock(&gpio_lock); ++ offset = sch_gpio_offset(sch, gpio_num, GIO); ++ bit = sch_gpio_bit(sch, gpio_num); + +- curr_dirs = inb(gpio_ba + offset); ++ curr_dirs = inb(sch->iobase + offset); + if (curr_dirs & (1 << bit)) +- outb(curr_dirs & ~(1 << bit), gpio_ba + offset); ++ outb(curr_dirs & ~(1 << bit), sch->iobase + offset); + +- spin_unlock(&gpio_lock); ++ spin_unlock(&sch->lock); + + /* +- * according to the datasheet, writing to the level register has no +- * effect when GPIO is programmed as input. +- * Actually the the level register is read-only when configured as input. +- * Thus presetting the output level before switching to output is _NOT_ possible. +- * Hence we set the level after configuring the GPIO as output. +- * But we cannot prevent a short low pulse if direction is set to high +- * and an external pull-up is connected. +- */ +- sch_gpio_resume_set(gc, gpio_num, val); ++ * according to the datasheet, writing to the level register has no ++ * effect when GPIO is programmed as input. ++ * Actually the the level register is read-only when configured as input. ++ * Thus presetting the output level before switching to output is _NOT_ possible. ++ * Hence we set the level after configuring the GPIO as output. ++ * But we cannot prevent a short low pulse if direction is set to high ++ * and an external pull-up is connected. ++ */ ++ sch_gpio_set(gc, gpio_num, val); + return 0; + } + +-static struct gpio_chip sch_gpio_resume = { +- .label = "sch_gpio_resume", ++static struct gpio_chip sch_gpio_chip = { ++ .label = "sch_gpio", + .owner = THIS_MODULE, +- .direction_input = sch_gpio_resume_direction_in, +- .get = sch_gpio_resume_get, +- .direction_output = sch_gpio_resume_direction_out, +- .set = sch_gpio_resume_set, ++ .direction_input = sch_gpio_direction_in, ++ .get = sch_gpio_get, ++ .direction_output = sch_gpio_direction_out, ++ .set = sch_gpio_set, + }; + + static int sch_gpio_probe(struct platform_device *pdev) + { ++ struct sch_gpio *sch; + struct resource *res; +- int err, id; + +- id = pdev->id; +- if (!id) +- return -ENODEV; ++ sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL); ++ if (!sch) ++ return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) + return -EBUSY; + +- if (!request_region(res->start, resource_size(res), pdev->name)) ++ if (!devm_request_region(&pdev->dev, res->start, resource_size(res), ++ pdev->name)) + return -EBUSY; + +- gpio_ba = res->start; ++ spin_lock_init(&sch->lock); ++ sch->iobase = res->start; ++ sch->chip = sch_gpio_chip; ++ sch->chip.label = dev_name(&pdev->dev); ++ sch->chip.dev = &pdev->dev; + +- switch (id) { ++ switch (pdev->id) { + case PCI_DEVICE_ID_INTEL_SCH_LPC: +- sch_gpio_core.base = 0; +- sch_gpio_core.ngpio = 10; +- sch_gpio_resume.base = 10; +- sch_gpio_resume.ngpio = 4; ++ sch->core_base = 0; ++ sch->resume_base = 10; ++ sch->chip.ngpio = 14; ++ + /* + * GPIO[6:0] enabled by default + * GPIO7 is configured by the CMC as SLPIOVR + * Enable GPIO[9:8] core powered gpios explicitly + */ +- outb(0x3, gpio_ba + CGEN + 1); ++ sch_gpio_enable(sch, 8); ++ sch_gpio_enable(sch, 9); + /* + * SUS_GPIO[2:0] enabled by default + * Enable SUS_GPIO3 resume powered gpio explicitly + */ +- outb(0x8, gpio_ba + RGEN); ++ sch_gpio_enable(sch, 13); + break; + + case PCI_DEVICE_ID_INTEL_ITC_LPC: +- sch_gpio_core.base = 0; +- sch_gpio_core.ngpio = 5; +- sch_gpio_resume.base = 5; +- sch_gpio_resume.ngpio = 9; ++ sch->core_base = 0; ++ sch->resume_base = 5; ++ sch->chip.ngpio = 14; + break; + + case PCI_DEVICE_ID_INTEL_CENTERTON_ILB: +- sch_gpio_core.base = 0; +- sch_gpio_core.ngpio = 21; +- sch_gpio_resume.base = 21; +- sch_gpio_resume.ngpio = 9; ++ sch->core_base = 0; ++ sch->resume_base = 21; ++ sch->chip.ngpio = 30; + break; + + default: +- err = -ENODEV; +- goto err_sch_gpio_core; ++ return -ENODEV; + } + +- sch_gpio_core.dev = &pdev->dev; +- sch_gpio_resume.dev = &pdev->dev; +- +- err = gpiochip_add(&sch_gpio_core); +- if (err < 0) +- goto err_sch_gpio_core; ++ platform_set_drvdata(pdev, sch); + +- err = gpiochip_add(&sch_gpio_resume); +- if (err < 0) +- goto err_sch_gpio_resume; +- +- return 0; +- +-err_sch_gpio_resume: +- gpiochip_remove(&sch_gpio_core); +- +-err_sch_gpio_core: +- release_region(res->start, resource_size(res)); +- gpio_ba = 0; +- +- return err; ++ return gpiochip_add(&sch->chip); + } + + static int sch_gpio_remove(struct platform_device *pdev) + { +- struct resource *res; +- if (gpio_ba) { +- +- gpiochip_remove(&sch_gpio_core); +- gpiochip_remove(&sch_gpio_resume); +- +- res = platform_get_resource(pdev, IORESOURCE_IO, 0); +- +- release_region(res->start, resource_size(res)); +- gpio_ba = 0; +- } ++ struct sch_gpio *sch = platform_get_drvdata(pdev); + ++ gpiochip_remove(&sch->chip); + return 0; + } + +diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c +index 687476f..b14c045 100644 +--- a/drivers/gpio/gpiolib-acpi.c ++++ b/drivers/gpio/gpiolib-acpi.c +@@ -293,6 +293,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) + struct acpi_gpio_lookup { + struct acpi_gpio_info info; + int index; ++ int pin_index; + struct gpio_desc *desc; + int n; + }; +@@ -306,13 +307,24 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) + + if (lookup->n++ == lookup->index && !lookup->desc) { + const struct acpi_resource_gpio *agpio = &ares->data.gpio; ++ int pin_index = lookup->pin_index; ++ ++ if (pin_index >= agpio->pin_table_length) ++ return 1; + + lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, +- agpio->pin_table[0]); ++ agpio->pin_table[pin_index]); + lookup->info.gpioint = + agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; +- lookup->info.active_low = +- agpio->polarity == ACPI_ACTIVE_LOW; ++ ++ /* ++ * ActiveLow is only specified for GpioInt resource. If ++ * GpioIo is used then the only way to set the flag is ++ * to use _DSD "gpios" property. ++ */ ++ if (lookup->info.gpioint) ++ lookup->info.active_low = ++ agpio->polarity == ACPI_ACTIVE_LOW; + } + + return 1; +@@ -320,40 +332,75 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) + + /** + * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources +- * @dev: pointer to a device to get GPIO from ++ * @adev: pointer to a ACPI device to get GPIO from ++ * @propname: Property name of the GPIO (optional) + * @index: index of GpioIo/GpioInt resource (starting from %0) + * @info: info pointer to fill in (optional) + * +- * Function goes through ACPI resources for @dev and based on @index looks ++ * Function goes through ACPI resources for @adev and based on @index looks + * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor, + * and returns it. @index matches GpioIo/GpioInt resources only so if there + * are total %3 GPIO resources, the index goes from %0 to %2. + * ++ * If @propname is specified the GPIO is looked using device property. In ++ * that case @index is used to select the GPIO entry in the property value ++ * (in case of multiple). ++ * + * If the GPIO cannot be translated or there is an error an ERR_PTR is + * returned. + * + * Note: if the GPIO resource has multiple entries in the pin list, this + * function only returns the first. + */ +-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, ++struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, ++ const char *propname, int index, + struct acpi_gpio_info *info) + { + struct acpi_gpio_lookup lookup; + struct list_head resource_list; +- struct acpi_device *adev; +- acpi_handle handle; ++ bool active_low = false; + int ret; + +- if (!dev) +- return ERR_PTR(-EINVAL); - - arch_timer_register(); - arch_timer_common_init(); - } --CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); --CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); -+ -+static void __init arch_timer_of_init(struct device_node *np) -+{ -+ int i; +- handle = ACPI_HANDLE(dev); +- if (!handle || acpi_bus_get_device(handle, &adev)) ++ if (!adev) + return ERR_PTR(-ENODEV); + + memset(&lookup, 0, sizeof(lookup)); + lookup.index = index; + ++ if (propname) { ++ struct acpi_reference_args args; + -+ if (arch_timers_present & ARCH_CP15_TIMER) { -+ pr_warn("arch_timer: multiple nodes in dt, skipping\n"); -+ return; -+ } ++ dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname); + -+ arch_timers_present |= ARCH_CP15_TIMER; -+ for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) -+ arch_timer_ppi[i] = irq_of_parse_and_map(np, i); ++ memset(&args, 0, sizeof(args)); ++ ret = acpi_dev_get_property_reference(adev, propname, NULL, ++ index, &args); ++ if (ret) ++ return ERR_PTR(ret); + -+ arch_timer_detect_rate(NULL, np); ++ /* ++ * The property was found and resolved so need to ++ * lookup the GPIO based on returned args instead. ++ */ ++ adev = args.adev; ++ if (args.nargs >= 2) { ++ lookup.index = args.args[0]; ++ lookup.pin_index = args.args[1]; ++ /* ++ * 3rd argument, if present is used to ++ * specify active_low. ++ */ ++ if (args.nargs >= 3) ++ active_low = !!args.args[2]; ++ } + -+ arch_timer_c3stop = !of_property_read_bool(np, "always-on"); ++ dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n", ++ dev_name(&adev->dev), args.nargs, ++ args.args[0], args.args[1], args.args[2]); ++ } else { ++ dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index); ++ } + -+ arch_timer_init(); -+} -+CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); -+CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, + &lookup); +@@ -362,8 +409,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, - static void __init arch_timer_mem_init(struct device_node *np) - { -@@ -740,3 +752,71 @@ static void __init arch_timer_mem_init(struct device_node *np) + acpi_dev_free_resource_list(&resource_list); + +- if (lookup.desc && info) ++ if (lookup.desc && info) { + *info = lookup.info; ++ if (active_low) ++ info->active_low = active_low; ++ } + + return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); } - CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", - arch_timer_mem_init); +diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c +index c68d037..344bc12 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -1487,14 +1487,36 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, + enum gpio_lookup_flags *flags) + { ++ static const char * const suffixes[] = { "gpios", "gpio" }; ++ struct acpi_device *adev = ACPI_COMPANION(dev); + struct acpi_gpio_info info; + struct gpio_desc *desc; ++ char propname[32]; ++ int i; + +- desc = acpi_get_gpiod_by_index(dev, idx, &info); +- if (IS_ERR(desc)) +- return desc; ++ /* Try first from _DSD */ ++ for (i = 0; i < ARRAY_SIZE(suffixes); i++) { ++ if (con_id && strcmp(con_id, "gpios")) { ++ snprintf(propname, sizeof(propname), "%s-%s", ++ con_id, suffixes[i]); ++ } else { ++ snprintf(propname, sizeof(propname), "%s", ++ suffixes[i]); ++ } + -+#ifdef CONFIG_ACPI -+static int __init -+map_generic_timer_interrupt(u32 interrupt, u32 flags) ++ desc = acpi_get_gpiod_by_index(adev, propname, 0, &info); ++ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) ++ break; ++ } + +- if (info.gpioint && info.active_low) ++ /* Then from plain _CRS GPIOs */ ++ if (IS_ERR(desc)) { ++ desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); ++ if (IS_ERR(desc)) ++ return desc; ++ } ++ ++ if (info.active_low) + *flags |= GPIO_ACTIVE_LOW; + + return desc; +@@ -1695,6 +1717,62 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, + EXPORT_SYMBOL_GPL(__gpiod_get_index); + + /** ++ * dev_get_named_gpiod_from_child - obtain a GPIO from firmware node ++ * @dev: parent device ++ * @child: firmware node (child of @dev) ++ * @propname: name of the firmware property ++ * @idx: index of the GPIO in the property value in case of many ++ * ++ * This function can be used for drivers that get their configuration ++ * from firmware in such a way that some properties are described as child ++ * nodes for the parent device in DT or ACPI. ++ * ++ * Function properly finds the corresponding GPIO using whatever is the ++ * underlying firmware interface and then makes sure that the GPIO ++ * descriptor is requested before it is returned to the caller. ++ * ++ * In case of error an ERR_PTR() is returned. ++ */ ++struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child, ++ const char *propname, int index) +{ -+ int trigger, polarity; ++ struct gpio_desc *desc = ERR_PTR(-ENODEV); ++ bool active_low = false; ++ int ret; + -+ if (!interrupt) -+ return 0; ++ if (!child) ++ return ERR_PTR(-EINVAL); + -+ trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE -+ : ACPI_LEVEL_SENSITIVE; ++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) { ++ enum of_gpio_flags flags; + -+ polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW -+ : ACPI_ACTIVE_HIGH; ++ desc = of_get_named_gpiod_flags(child, propname, index, &flags); ++ if (!IS_ERR(desc)) ++ active_low = flags & OF_GPIO_ACTIVE_LOW; ++ } else if (ACPI_COMPANION(dev)) { ++ struct acpi_gpio_info info; + -+ return acpi_register_gsi(NULL, interrupt, trigger, polarity); ++ desc = acpi_get_gpiod_by_index(child, propname, index, &info); ++ if (!IS_ERR(desc)) ++ active_low = info.active_low; ++ } ++ ++ if (IS_ERR(desc)) ++ return desc; ++ ++ ret = gpiod_request(desc, NULL); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ /* Only value flag can be set from both DT and ACPI is active_low */ ++ if (active_low) ++ set_bit(FLAG_ACTIVE_LOW, &desc->flags); ++ ++ return desc; +} ++EXPORT_SYMBOL_GPL(dev_get_named_gpiod_from_child); + -+/* Initialize per-processor generic timer */ -+static int __init arch_timer_acpi_init(struct acpi_table_header *table) ++/** + * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO + * function + * @dev: GPIO consumer, can be NULL for system-global GPIOs +diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h +index 9db2b6a..e3a5211 100644 +--- a/drivers/gpio/gpiolib.h ++++ b/drivers/gpio/gpiolib.h +@@ -34,7 +34,8 @@ void acpi_gpiochip_remove(struct gpio_chip *chip); + void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); + void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); + +-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, ++struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, ++ const char *propname, int index, + struct acpi_gpio_info *info); + #else + static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } +@@ -47,8 +48,8 @@ static inline void + acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } + + static inline struct gpio_desc * +-acpi_get_gpiod_by_index(struct device *dev, int index, +- struct acpi_gpio_info *info) ++acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, ++ int index, struct acpi_gpio_info *info) + { + return ERR_PTR(-ENOSYS); + } +diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c +index 432d363..3563850 100644 +--- a/drivers/input/keyboard/gpio_keys_polled.c ++++ b/drivers/input/keyboard/gpio_keys_polled.c +@@ -23,10 +23,9 @@ + #include + #include + #include ++#include + #include +-#include +-#include +-#include ++#include + + #define DRV_NAME "gpio-keys-polled" + +@@ -51,15 +50,14 @@ static void gpio_keys_polled_check_state(struct input_dev *input, + int state; + + if (bdata->can_sleep) +- state = !!gpio_get_value_cansleep(button->gpio); ++ state = !!gpiod_get_value_cansleep(button->gpiod); + else +- state = !!gpio_get_value(button->gpio); ++ state = !!gpiod_get_value(button->gpiod); + + if (state != bdata->last_state) { + unsigned int type = button->type ?: EV_KEY; + +- input_event(input, type, button->code, +- !!(state ^ button->active_low)); ++ input_event(input, type, button->code, state); + input_sync(input); + bdata->count = 0; + bdata->last_state = state; +@@ -102,21 +100,57 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev) + pdata->disable(bdev->dev); + } + +-#ifdef CONFIG_OF ++static int gpio_keys_polled_get_button(struct device *dev, void *child, ++ void *data) +{ -+ struct acpi_table_gtdt *gtdt; -+ -+ if (arch_timers_present & ARCH_CP15_TIMER) { -+ pr_warn("arch_timer: already initialized, skipping\n"); -+ return -EINVAL; -+ } ++ struct gpio_keys_platform_data *pdata = data; ++ struct gpio_keys_button *button; ++ struct gpio_desc *desc; + -+ gtdt = container_of(table, struct acpi_table_gtdt, header); ++ desc = devm_get_named_gpiod_from_child(dev, child, "gpios", 0); ++ if (IS_ERR(desc)) { ++ int err = PTR_ERR(desc); + -+ arch_timers_present |= ARCH_CP15_TIMER; ++ if (err != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get gpio flags, error: %d\n", ++ err); ++ return err; ++ } + -+ arch_timer_ppi[PHYS_SECURE_PPI] = -+ map_generic_timer_interrupt(gtdt->secure_el1_interrupt, -+ gtdt->secure_el1_flags); ++ button = &pdata->buttons[pdata->nbuttons++]; ++ button->gpiod = desc; + -+ arch_timer_ppi[PHYS_NONSECURE_PPI] = -+ map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt, -+ gtdt->non_secure_el1_flags); ++ if (device_child_property_read_u32(dev, child, "linux,code", ++ &button->code)) { ++ dev_err(dev, "Button without keycode: %d\n", ++ pdata->nbuttons - 1); ++ return -EINVAL; ++ } + -+ arch_timer_ppi[VIRT_PPI] = -+ map_generic_timer_interrupt(gtdt->virtual_timer_interrupt, -+ gtdt->virtual_timer_flags); ++ device_child_property_read_string(dev, child, "label", &button->desc); + -+ arch_timer_ppi[HYP_PPI] = -+ map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt, -+ gtdt->non_secure_el2_flags); ++ if (device_child_property_read_u32(dev, child, "linux,input-type", ++ &button->type)) ++ button->type = EV_KEY; + -+ /* Get the frequency from CNTFRQ */ -+ arch_timer_detect_rate(NULL, NULL); ++ button->wakeup = !device_get_child_property(dev, child, ++ "gpio-key,wakeup", NULL); + -+ /* Always-on capability */ -+ arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON); ++ if (device_child_property_read_u32(dev, child, "debounce-interval", ++ &button->debounce_interval)) ++ button->debounce_interval = 5; + -+ arch_timer_init(); + return 0; +} + -+/* Initialize all the generic timers presented in GTDT */ -+void __init acpi_generic_timer_init(void) -+{ -+ if (acpi_disabled) -+ return; + static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev) + { +- struct device_node *node, *pp; + struct gpio_keys_platform_data *pdata; + struct gpio_keys_button *button; + int error; + int nbuttons; +- int i; +- +- node = dev->of_node; +- if (!node) +- return NULL; + +- nbuttons = of_get_child_count(node); ++ nbuttons = device_get_child_node_count(dev); + if (nbuttons == 0) + return NULL; + +@@ -126,54 +160,14 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct + return ERR_PTR(-ENOMEM); + + pdata->buttons = (struct gpio_keys_button *)(pdata + 1); +- pdata->nbuttons = nbuttons; + +- pdata->rep = !!of_get_property(node, "autorepeat", NULL); +- of_property_read_u32(node, "poll-interval", &pdata->poll_interval); ++ pdata->rep = !device_get_property(dev, "autorepeat", NULL); ++ device_property_read_u32(dev, "poll-interval", &pdata->poll_interval); + +- i = 0; +- for_each_child_of_node(node, pp) { +- int gpio; +- enum of_gpio_flags flags; +- +- if (!of_find_property(pp, "gpios", NULL)) { +- pdata->nbuttons--; +- dev_warn(dev, "Found button without gpios\n"); +- continue; +- } +- +- gpio = of_get_gpio_flags(pp, 0, &flags); +- if (gpio < 0) { +- error = gpio; +- if (error != -EPROBE_DEFER) +- dev_err(dev, +- "Failed to get gpio flags, error: %d\n", +- error); +- return ERR_PTR(error); +- } +- +- button = &pdata->buttons[i++]; +- +- button->gpio = gpio; +- button->active_low = flags & OF_GPIO_ACTIVE_LOW; +- +- if (of_property_read_u32(pp, "linux,code", &button->code)) { +- dev_err(dev, "Button without keycode: 0x%x\n", +- button->gpio); +- return ERR_PTR(-EINVAL); +- } +- +- button->desc = of_get_property(pp, "label", NULL); +- +- if (of_property_read_u32(pp, "linux,input-type", &button->type)) +- button->type = EV_KEY; +- +- button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); +- +- if (of_property_read_u32(pp, "debounce-interval", +- &button->debounce_interval)) +- button->debounce_interval = 5; +- } ++ error = device_for_each_child_node(dev, gpio_keys_polled_get_button, ++ pdata); ++ if (error) ++ return ERR_PTR(error); + + if (pdata->nbuttons == 0) + return ERR_PTR(-EINVAL); +@@ -187,14 +181,11 @@ static const struct of_device_id gpio_keys_polled_of_match[] = { + }; + MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match); + +-#else +- +-static inline struct gpio_keys_platform_data * +-gpio_keys_polled_get_devtree_pdata(struct device *dev) +-{ +- return NULL; +-} +-#endif ++static const struct acpi_device_id gpio_keys_polled_acpi_match[] = { ++ { "PRP0001" }, /* Device Tree shoehorned into ACPI */ ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, gpio_keys_polled_acpi_match); + + static int gpio_keys_polled_probe(struct platform_device *pdev) + { +@@ -259,7 +250,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + struct gpio_keys_button_data *bdata = &bdev->data[i]; +- unsigned int gpio = button->gpio; + unsigned int type = button->type ?: EV_KEY; + + if (button->wakeup) { +@@ -267,15 +257,31 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) + return -EINVAL; + } + +- error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN, +- button->desc ? : DRV_NAME); +- if (error) { +- dev_err(dev, "unable to claim gpio %u, err=%d\n", +- gpio, error); +- return error; ++ /* ++ * Legacy GPIO number so request the GPIO here and ++ * convert it to descriptor. ++ */ ++ if (!button->gpiod && gpio_is_valid(button->gpio)) { ++ unsigned flags = 0; ++ ++ if (button->active_low) ++ flags |= GPIOF_ACTIVE_LOW; ++ ++ error = devm_gpio_request_one(&pdev->dev, button->gpio, ++ flags, button->desc ? : DRV_NAME); ++ if (error) { ++ dev_err(dev, "unable to claim gpio %u, err=%d\n", ++ button->gpio, error); ++ return error; ++ } + -+ acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init); -+} -+#endif ++ button->gpiod = gpio_to_desc(button->gpio); + } + +- bdata->can_sleep = gpio_cansleep(gpio); ++ if (IS_ERR(button->gpiod)) ++ return PTR_ERR(button->gpiod); ++ ++ bdata->can_sleep = gpiod_cansleep(button->gpiod); + bdata->last_state = -1; + bdata->threshold = DIV_ROUND_UP(button->debounce_interval, + pdata->poll_interval); +@@ -308,7 +314,8 @@ static struct platform_driver gpio_keys_polled_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +- .of_match_table = of_match_ptr(gpio_keys_polled_of_match), ++ .of_match_table = gpio_keys_polled_of_match, ++ .acpi_match_table = gpio_keys_polled_acpi_match, + }, + }; + module_platform_driver(gpio_keys_polled_driver); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index a0698b4..d2da911 100644 --- a/drivers/irqchip/irq-gic-v3.c @@ -4688,39 +5846,498 @@ index dda6dbc..5d9bdd3 100644 + return -ENOMEM; + } + -+ /* -+ * Initialize zero GIC instance (no multi-GIC support). Also, set GIC -+ * as default IRQ domain to allow for GSI registration and GSI to IRQ -+ * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()). -+ */ -+ gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); -+ irq_set_default_host(gic_data[0].domain); -+ return 0; ++ /* ++ * Initialize zero GIC instance (no multi-GIC support). Also, set GIC ++ * as default IRQ domain to allow for GSI registration and GSI to IRQ ++ * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()). ++ */ ++ gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); ++ irq_set_default_host(gic_data[0].domain); ++ return 0; ++} ++#endif +diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c +index 0fe2f71..9106c6d 100644 +--- a/drivers/irqchip/irqchip.c ++++ b/drivers/irqchip/irqchip.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + /* + * This special of_device_id is the sentinel at the end of the +@@ -26,4 +27,6 @@ extern struct of_device_id __irqchip_of_table[]; + void __init irqchip_init(void) + { + of_irq_init(__irqchip_of_table); ++ ++ acpi_gic_init(); + } +diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c +index 57ff20f..681efd5 100644 +--- a/drivers/leds/leds-gpio.c ++++ b/drivers/leds/leds-gpio.c +@@ -13,22 +13,20 @@ + #include + #include + #include ++#include + #include +-#include +-#include +-#include + #include + #include + #include + #include ++#include + + struct gpio_led_data { + struct led_classdev cdev; +- unsigned gpio; ++ struct gpio_desc *gpiod; + struct work_struct work; + u8 new_level; + u8 can_sleep; +- u8 active_low; + u8 blinking; + int (*platform_gpio_blink_set)(unsigned gpio, int state, + unsigned long *delay_on, unsigned long *delay_off); +@@ -40,12 +38,16 @@ static void gpio_led_work(struct work_struct *work) + container_of(work, struct gpio_led_data, work); + + if (led_dat->blinking) { +- led_dat->platform_gpio_blink_set(led_dat->gpio, +- led_dat->new_level, +- NULL, NULL); ++ int gpio = desc_to_gpio(led_dat->gpiod); ++ int level = led_dat->new_level; ++ ++ if (gpiod_is_active_low(led_dat->gpiod)) ++ level = !level; ++ ++ led_dat->platform_gpio_blink_set(gpio, level, NULL, NULL); + led_dat->blinking = 0; + } else +- gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level); ++ gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level); + } + + static void gpio_led_set(struct led_classdev *led_cdev, +@@ -60,9 +62,6 @@ static void gpio_led_set(struct led_classdev *led_cdev, + else + level = 1; + +- if (led_dat->active_low) +- level = !level; +- + /* Setting GPIOs with I2C/etc requires a task context, and we don't + * seem to have a reliable way to know if we're already in one; so + * let's just assume the worst. +@@ -72,11 +71,16 @@ static void gpio_led_set(struct led_classdev *led_cdev, + schedule_work(&led_dat->work); + } else { + if (led_dat->blinking) { +- led_dat->platform_gpio_blink_set(led_dat->gpio, level, +- NULL, NULL); ++ int gpio = desc_to_gpio(led_dat->gpiod); ++ ++ if (gpiod_is_active_low(led_dat->gpiod)) ++ level = !level; ++ ++ led_dat->platform_gpio_blink_set(gpio, level, NULL, ++ NULL); + led_dat->blinking = 0; + } else +- gpio_set_value(led_dat->gpio, level); ++ gpiod_set_value(led_dat->gpiod, level); + } + } + +@@ -85,9 +89,10 @@ static int gpio_blink_set(struct led_classdev *led_cdev, + { + struct gpio_led_data *led_dat = + container_of(led_cdev, struct gpio_led_data, cdev); ++ int gpio = desc_to_gpio(led_dat->gpiod); + + led_dat->blinking = 1; +- return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK, ++ return led_dat->platform_gpio_blink_set(gpio, GPIO_LED_BLINK, + delay_on, delay_off); + } + +@@ -97,24 +102,33 @@ static int create_gpio_led(const struct gpio_led *template, + { + int ret, state; + +- led_dat->gpio = -1; ++ if (!template->gpiod) { ++ unsigned long flags = 0; + +- /* skip leds that aren't available */ +- if (!gpio_is_valid(template->gpio)) { +- dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n", +- template->gpio, template->name); +- return 0; +- } ++ /* skip leds that aren't available */ ++ if (!gpio_is_valid(template->gpio)) { ++ dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n", ++ template->gpio, template->name); ++ return 0; ++ } + +- ret = devm_gpio_request(parent, template->gpio, template->name); +- if (ret < 0) +- return ret; ++ if (template->active_low) ++ flags |= GPIOF_ACTIVE_LOW; ++ ++ ret = devm_gpio_request_one(parent, template->gpio, flags, ++ template->name); ++ if (ret < 0) ++ return ret; ++ ++ led_dat->gpiod = gpio_to_desc(template->gpio); ++ if (IS_ERR(led_dat->gpiod)) ++ return PTR_ERR(led_dat->gpiod); ++ } + + led_dat->cdev.name = template->name; + led_dat->cdev.default_trigger = template->default_trigger; +- led_dat->gpio = template->gpio; +- led_dat->can_sleep = gpio_cansleep(template->gpio); +- led_dat->active_low = template->active_low; ++ led_dat->gpiod = template->gpiod; ++ led_dat->can_sleep = gpiod_cansleep(template->gpiod); + led_dat->blinking = 0; + if (blink_set) { + led_dat->platform_gpio_blink_set = blink_set; +@@ -122,30 +136,24 @@ static int create_gpio_led(const struct gpio_led *template, + } + led_dat->cdev.brightness_set = gpio_led_set; + if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) +- state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low; ++ state = !!gpiod_get_value_cansleep(led_dat->gpiod); + else + state = (template->default_state == LEDS_GPIO_DEFSTATE_ON); + led_dat->cdev.brightness = state ? LED_FULL : LED_OFF; + if (!template->retain_state_suspended) + led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; + +- ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state); ++ ret = gpiod_direction_output(led_dat->gpiod, state); + if (ret < 0) + return ret; + + INIT_WORK(&led_dat->work, gpio_led_work); + +- ret = led_classdev_register(parent, &led_dat->cdev); +- if (ret < 0) +- return ret; +- +- return 0; ++ return led_classdev_register(parent, &led_dat->cdev); + } + + static void delete_gpio_led(struct gpio_led_data *led) + { +- if (!gpio_is_valid(led->gpio)) +- return; + led_classdev_unregister(&led->cdev); + cancel_work_sync(&led->work); + } +@@ -161,65 +169,59 @@ static inline int sizeof_gpio_leds_priv(int num_leds) + (sizeof(struct gpio_led_data) * num_leds); + } + +-/* Code to create from OpenFirmware platform devices */ +-#ifdef CONFIG_OF_GPIO +-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) ++static int gpio_leds_create_led(struct device *dev, void *child, void *data) ++{ ++ struct gpio_leds_priv *priv = data; ++ struct gpio_led led = {}; ++ const char *state = NULL; ++ ++ led.gpiod = devm_get_named_gpiod_from_child(dev, child, "gpios", 0); ++ if (IS_ERR(led.gpiod)) ++ return PTR_ERR(led.gpiod); ++ ++ device_child_property_read_string(dev, child, "label", &led.name); ++ device_child_property_read_string(dev, child, "linux,default-trigger", ++ &led.default_trigger); ++ ++ device_child_property_read_string(dev, child, "linux,default_state", ++ &state); ++ if (state) { ++ if (!strcmp(state, "keep")) ++ led.default_state = LEDS_GPIO_DEFSTATE_KEEP; ++ else if (!strcmp(state, "on")) ++ led.default_state = LEDS_GPIO_DEFSTATE_ON; ++ else ++ led.default_state = LEDS_GPIO_DEFSTATE_OFF; ++ } ++ ++ if (!device_get_child_property(dev, child, "retain-state-suspended", NULL)) ++ led.retain_state_suspended = 1; ++ ++ return create_gpio_led(&led, &priv->leds[priv->num_leds++], dev, NULL); +} -+#endif -diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c -index 0fe2f71..9106c6d 100644 ---- a/drivers/irqchip/irqchip.c -+++ b/drivers/irqchip/irqchip.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include ++ ++static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) + { +- struct device_node *np = pdev->dev.of_node, *child; + struct gpio_leds_priv *priv; +- int count, ret; ++ int ret, count; + +- /* count LEDs in this device, so we know how much to allocate */ +- count = of_get_available_child_count(np); ++ count = device_get_child_node_count(&pdev->dev); + if (!count) + return ERR_PTR(-ENODEV); + +- for_each_available_child_of_node(np, child) +- if (of_get_gpio(child, 0) == -EPROBE_DEFER) +- return ERR_PTR(-EPROBE_DEFER); +- + priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count), + GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + +- for_each_available_child_of_node(np, child) { +- struct gpio_led led = {}; +- enum of_gpio_flags flags; +- const char *state; +- +- led.gpio = of_get_gpio_flags(child, 0, &flags); +- led.active_low = flags & OF_GPIO_ACTIVE_LOW; +- led.name = of_get_property(child, "label", NULL) ? : child->name; +- led.default_trigger = +- of_get_property(child, "linux,default-trigger", NULL); +- state = of_get_property(child, "default-state", NULL); +- if (state) { +- if (!strcmp(state, "keep")) +- led.default_state = LEDS_GPIO_DEFSTATE_KEEP; +- else if (!strcmp(state, "on")) +- led.default_state = LEDS_GPIO_DEFSTATE_ON; +- else +- led.default_state = LEDS_GPIO_DEFSTATE_OFF; +- } +- +- if (of_get_property(child, "retain-state-suspended", NULL)) +- led.retain_state_suspended = 1; +- +- ret = create_gpio_led(&led, &priv->leds[priv->num_leds++], +- &pdev->dev, NULL); +- if (ret < 0) { +- of_node_put(child); +- goto err; +- } ++ ret = device_for_each_child_node(&pdev->dev, gpio_leds_create_led, priv); ++ if (ret) { ++ for (count = priv->num_leds - 2; count >= 0; count--) ++ delete_gpio_led(&priv->leds[count]); ++ return ERR_PTR(ret); + } + + return priv; +- +-err: +- for (count = priv->num_leds - 2; count >= 0; count--) +- delete_gpio_led(&priv->leds[count]); +- return ERR_PTR(-ENODEV); + } + + static const struct of_device_id of_gpio_leds_match[] = { +@@ -228,13 +230,13 @@ static const struct of_device_id of_gpio_leds_match[] = { + }; + + MODULE_DEVICE_TABLE(of, of_gpio_leds_match); +-#else /* CONFIG_OF_GPIO */ +-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) +-{ +- return ERR_PTR(-ENODEV); +-} +-#endif /* CONFIG_OF_GPIO */ + ++static const struct acpi_device_id acpi_gpio_leds_match[] = { ++ { "PRP0001" }, /* Device Tree shoehorned into ACPI */ ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(acpi, acpi_gpio_leds_match); + + static int gpio_led_probe(struct platform_device *pdev) + { +@@ -263,7 +265,7 @@ static int gpio_led_probe(struct platform_device *pdev) + } + } + } else { +- priv = gpio_leds_create_of(pdev); ++ priv = gpio_leds_create(pdev); + if (IS_ERR(priv)) + return PTR_ERR(priv); + } +@@ -290,7 +292,8 @@ static struct platform_driver gpio_led_driver = { + .driver = { + .name = "leds-gpio", + .owner = THIS_MODULE, +- .of_match_table = of_match_ptr(of_gpio_leds_match), ++ .of_match_table = of_gpio_leds_match, ++ .acpi_match_table = acpi_gpio_leds_match, + }, + }; + +diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c +index 634f729..1a760cd 100644 +--- a/drivers/misc/eeprom/at25.c ++++ b/drivers/misc/eeprom/at25.c +@@ -18,7 +18,7 @@ + + #include + #include +-#include ++#include /* - * This special of_device_id is the sentinel at the end of the -@@ -26,4 +27,6 @@ extern struct of_device_id __irqchip_of_table[]; - void __init irqchip_init(void) + * NOTE: this is an *EEPROM* driver. The vagaries of product naming +@@ -301,35 +301,33 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf, + + /*-------------------------------------------------------------------------*/ + +-static int at25_np_to_chip(struct device *dev, +- struct device_node *np, +- struct spi_eeprom *chip) ++static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip) { - of_irq_init(__irqchip_of_table); -+ -+ acpi_gic_init(); - } + u32 val; + + memset(chip, 0, sizeof(*chip)); +- strncpy(chip->name, np->name, sizeof(chip->name)); ++ strncpy(chip->name, "at25", sizeof(chip->name)); + +- if (of_property_read_u32(np, "size", &val) == 0 || +- of_property_read_u32(np, "at25,byte-len", &val) == 0) { ++ if (device_property_read_u32(dev, "size", &val) == 0 || ++ device_property_read_u32(dev, "at25,byte-len", &val) == 0) { + chip->byte_len = val; + } else { + dev_err(dev, "Error: missing \"size\" property\n"); + return -ENODEV; + } + +- if (of_property_read_u32(np, "pagesize", &val) == 0 || +- of_property_read_u32(np, "at25,page-size", &val) == 0) { ++ if (device_property_read_u32(dev, "pagesize", &val) == 0 || ++ device_property_read_u32(dev, "at25,page-size", &val) == 0) { + chip->page_size = (u16)val; + } else { + dev_err(dev, "Error: missing \"pagesize\" property\n"); + return -ENODEV; + } + +- if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) { ++ if (device_property_read_u32(dev, "at25,addr-mode", &val) == 0) { + chip->flags = (u16)val; + } else { +- if (of_property_read_u32(np, "address-width", &val)) { ++ if (device_property_read_u32(dev, "address-width", &val)) { + dev_err(dev, + "Error: missing \"address-width\" property\n"); + return -ENODEV; +@@ -350,7 +348,7 @@ static int at25_np_to_chip(struct device *dev, + val); + return -ENODEV; + } +- if (of_find_property(np, "read-only", NULL)) ++ if (!device_get_property(dev, "read-only", NULL)) + chip->flags |= EE_READONLY; + } + return 0; +@@ -360,21 +358,15 @@ static int at25_probe(struct spi_device *spi) + { + struct at25_data *at25 = NULL; + struct spi_eeprom chip; +- struct device_node *np = spi->dev.of_node; + int err; + int sr; + int addrlen; + + /* Chip description */ + if (!spi->dev.platform_data) { +- if (np) { +- err = at25_np_to_chip(&spi->dev, np, &chip); +- if (err) +- return err; +- } else { +- dev_err(&spi->dev, "Error: no chip description\n"); +- return -ENODEV; +- } ++ err = at25_fw_to_chip(&spi->dev, &chip); ++ if (err) ++ return err; + } else + chip = *(struct spi_eeprom *)spi->dev.platform_data; + +@@ -467,11 +459,18 @@ static const struct of_device_id at25_of_match[] = { + }; + MODULE_DEVICE_TABLE(of, at25_of_match); + ++static const struct acpi_device_id at25_acpi_match[] = { ++ { "PRP0001" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, at25_acpi_match); ++ + static struct spi_driver at25_driver = { + .driver = { + .name = "at25", + .owner = THIS_MODULE, + .of_match_table = at25_of_match, ++ .acpi_match_table = at25_acpi_match, + }, + .probe = at25_probe, + .remove = at25_remove, +diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig +index 8319c99..6feb6ef3 100644 +--- a/drivers/net/ethernet/amd/Kconfig ++++ b/drivers/net/ethernet/amd/Kconfig +@@ -179,7 +179,7 @@ config SUNLANCE + + config AMD_XGBE + tristate "AMD 10GbE Ethernet driver" +- depends on OF_NET ++ depends on OF_NET || ACPI + select PHYLIB + select AMD_XGBE_PHY + select BITREVERSE diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c -index ea27383..d0d3ab5 100644 +index ea27383..fd61489 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +@@ -131,7 +131,7 @@ static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata, + + DBGPR("-->xgbe_usec_to_riwt\n"); + +- rate = clk_get_rate(pdata->sysclk); ++ rate = pdata->sysclk_rate; + + /* + * Convert the input usec value to the watchdog timer value. Each +@@ -154,7 +154,7 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata, + + DBGPR("-->xgbe_riwt_to_usec\n"); + +- rate = clk_get_rate(pdata->sysclk); ++ rate = pdata->sysclk_rate; + + /* + * Convert the input watchdog timer value to the usec value. Each @@ -696,6 +696,18 @@ static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad, else mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff); @@ -4754,23 +6371,491 @@ index b26d758..ca7895c 100644 DBGPR("<--xgbe_get_all_hw_features\n"); } -diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c -index bdf9cfa..ba53e41 100644 ---- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c -+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c -@@ -533,6 +533,7 @@ static int xgbe_resume(struct device *dev) - #endif /* CONFIG_PM */ +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c +index bdf9cfa..7ab57fd 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c +@@ -124,6 +124,7 @@ + #include + #include + #include ++#include + + #include "xgbe.h" + #include "xgbe-common.h" +@@ -216,6 +217,210 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata) + xgbe_init_function_ptrs_desc(&pdata->desc_if); + } + ++static int xgbe_map_resources(struct xgbe_prv_data *pdata) ++{ ++ struct platform_device *pdev = pdata->pdev; ++ struct device *dev = pdata->dev; ++ struct resource *res; ++ ++ /* Obtain the mmio areas for the device */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pdata->xgmac_regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pdata->xgmac_regs)) { ++ dev_err(dev, "xgmac ioremap failed\n"); ++ return PTR_ERR(pdata->xgmac_regs); ++ } ++ DBGPR(" xgmac_regs = %p\n", pdata->xgmac_regs); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ pdata->xpcs_regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pdata->xpcs_regs)) { ++ dev_err(dev, "xpcs ioremap failed\n"); ++ return PTR_ERR(pdata->xpcs_regs); ++ } ++ DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_ACPI ++static int xgbe_acpi_support(struct xgbe_prv_data *pdata) ++{ ++ struct acpi_device *adev = pdata->adev; ++ struct device *dev = pdata->dev; ++ const union acpi_object *property; ++ acpi_status status; ++ u64 cca; ++ unsigned int i; ++ int ret; ++ ++ /* Map the memory resources */ ++ ret = xgbe_map_resources(pdata); ++ if (ret) ++ return ret; ++ ++ /* Obtain the system clock setting */ ++ ret = acpi_dev_get_property(adev, XGBE_ACPI_DMA_FREQ, ACPI_TYPE_INTEGER, ++ &property); ++ if (ret) { ++ dev_err(dev, "unable to obtain %s acpi property\n", ++ XGBE_ACPI_DMA_FREQ); ++ return ret; ++ } ++ pdata->sysclk_rate = property->integer.value; ++ ++ /* Obtain the PTP clock setting */ ++ ret = acpi_dev_get_property(adev, XGBE_ACPI_PTP_FREQ, ACPI_TYPE_INTEGER, ++ &property); ++ if (ret) { ++ dev_err(dev, "unable to obtain %s acpi property\n", ++ XGBE_ACPI_PTP_FREQ); ++ return ret; ++ } ++ pdata->ptpclk_rate = property->integer.value; ++ ++ /* Retrieve the MAC address */ ++ ret = acpi_dev_get_property_array(adev, XGBE_ACPI_MAC_ADDR, ++ ACPI_TYPE_INTEGER, &property); ++ if (ret) { ++ dev_err(dev, "unable to obtain %s acpi property\n", ++ XGBE_ACPI_MAC_ADDR); ++ return ret; ++ } ++ if (property->package.count != 6) { ++ dev_err(dev, "invalid %s acpi property\n", ++ XGBE_ACPI_MAC_ADDR); ++ return -EINVAL; ++ } ++ for (i = 0; i < property->package.count; i++) { ++ union acpi_object *obj = &property->package.elements[i]; ++ ++ pdata->mac_addr[i] = (u8)obj->integer.value; ++ } ++ if (!is_valid_ether_addr(pdata->mac_addr)) { ++ dev_err(dev, "invalid %s acpi property\n", ++ XGBE_ACPI_MAC_ADDR); ++#if 0 ++ return -EINVAL; ++#else ++ dev_err(dev, "invalid MAC address, using random address\n"); ++ eth_random_addr(pdata->mac_addr); ++#endif ++ } ++ ++ /* Retrieve the PHY mode - it must be "xgmii" */ ++ ret = acpi_dev_get_property(adev, XGBE_ACPI_PHY_MODE, ACPI_TYPE_STRING, ++ &property); ++ if (ret) { ++ dev_err(dev, "unable to obtain %s acpi property\n", ++ XGBE_ACPI_PHY_MODE); ++ return ret; ++ } ++ if (strcmp(property->string.pointer, ++ phy_modes(PHY_INTERFACE_MODE_XGMII))) { ++ dev_err(dev, "invalid %s acpi property\n", ++ XGBE_ACPI_PHY_MODE); ++ return -EINVAL; ++ } ++ pdata->phy_mode = PHY_INTERFACE_MODE_XGMII; ++ ++#ifndef METHOD_NAME__CCA ++#define METHOD_NAME__CCA "_CCA" ++#endif ++ /* Set the device cache coherency values */ ++ if (acpi_has_method(adev->handle, METHOD_NAME__CCA)) { ++ status = acpi_evaluate_integer(adev->handle, METHOD_NAME__CCA, ++ NULL, &cca); ++ if (ACPI_FAILURE(status)) { ++ dev_err(dev, "error obtaining acpi _CCA method\n"); ++ return -EINVAL; ++ } ++ } else { ++ cca = 0; ++ } ++ ++ if (cca) { ++ pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; ++ pdata->arcache = XGBE_DMA_OS_ARCACHE; ++ pdata->awcache = XGBE_DMA_OS_AWCACHE; ++ } else { ++ pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; ++ pdata->arcache = XGBE_DMA_SYS_ARCACHE; ++ pdata->awcache = XGBE_DMA_SYS_AWCACHE; ++ } ++ ++ return 0; ++} ++#else /* CONFIG_ACPI */ ++static int xgbe_acpi_support(struct xgbe_prv_data *pdata) ++{ ++ return -EINVAL; ++} ++#endif /* CONFIG_ACPI */ ++ ++#ifdef CONFIG_OF ++static int xgbe_of_support(struct xgbe_prv_data *pdata) ++{ ++ struct device *dev = pdata->dev; ++ const u8 *mac_addr; ++ int ret; ++ ++ /* Map the memory resources */ ++ ret = xgbe_map_resources(pdata); ++ if (ret) ++ return ret; ++ ++ /* Obtain the system clock setting */ ++ pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); ++ if (IS_ERR(pdata->sysclk)) { ++ dev_err(dev, "dma devm_clk_get failed\n"); ++ return PTR_ERR(pdata->sysclk); ++ } ++ pdata->sysclk_rate = clk_get_rate(pdata->sysclk); ++ ++ /* Obtain the PTP clock setting */ ++ pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); ++ if (IS_ERR(pdata->ptpclk)) { ++ dev_err(dev, "ptp devm_clk_get failed\n"); ++ return PTR_ERR(pdata->ptpclk); ++ } ++ pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk); ++ ++ /* Retrieve the MAC address */ ++ mac_addr = of_get_mac_address(dev->of_node); ++ if (!mac_addr) { ++ dev_err(dev, "invalid mac address for this device\n"); ++ return -EINVAL; ++ } ++ memcpy(pdata->mac_addr, mac_addr, ETH_ALEN); ++ ++ /* Retrieve the PHY mode - it must be "xgmii" */ ++ pdata->phy_mode = of_get_phy_mode(dev->of_node); ++ if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { ++ dev_err(dev, "invalid phy-mode specified for this device\n"); ++ return -EINVAL; ++ } ++ ++ /* Set the device cache coherency values */ ++ if (of_property_read_bool(dev->of_node, "dma-coherent")) { ++ pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; ++ pdata->arcache = XGBE_DMA_OS_ARCACHE; ++ pdata->awcache = XGBE_DMA_OS_AWCACHE; ++ } else { ++ pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; ++ pdata->arcache = XGBE_DMA_SYS_ARCACHE; ++ pdata->awcache = XGBE_DMA_SYS_AWCACHE; ++ } ++ ++ return 0; ++} ++#else /* CONFIG_OF */ ++static int xgbe_of_support(struct xgbe_prv_data *pdata) ++{ ++ return -EINVAL; ++} ++#endif /*CONFIG_OF */ ++ + static int xgbe_probe(struct platform_device *pdev) + { + struct xgbe_prv_data *pdata; +@@ -223,8 +428,6 @@ static int xgbe_probe(struct platform_device *pdev) + struct xgbe_desc_if *desc_if; + struct net_device *netdev; + struct device *dev = &pdev->dev; +- struct resource *res; +- const u8 *mac_addr; + int ret; + + DBGPR("--> xgbe_probe\n"); +@@ -240,6 +443,7 @@ static int xgbe_probe(struct platform_device *pdev) + pdata = netdev_priv(netdev); + pdata->netdev = netdev; + pdata->pdev = pdev; ++ pdata->adev = ACPI_COMPANION(dev); + pdata->dev = dev; + platform_set_drvdata(pdev, netdev); + +@@ -265,40 +469,13 @@ static int xgbe_probe(struct platform_device *pdev) + goto err_io; + } + +- /* Obtain the system clock setting */ +- pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); +- if (IS_ERR(pdata->sysclk)) { +- dev_err(dev, "dma devm_clk_get failed\n"); +- ret = PTR_ERR(pdata->sysclk); +- goto err_io; +- } +- +- /* Obtain the PTP clock setting */ +- pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); +- if (IS_ERR(pdata->ptpclk)) { +- dev_err(dev, "ptp devm_clk_get failed\n"); +- ret = PTR_ERR(pdata->ptpclk); +- goto err_io; +- } +- +- /* Obtain the mmio areas for the device */ +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- pdata->xgmac_regs = devm_ioremap_resource(dev, res); +- if (IS_ERR(pdata->xgmac_regs)) { +- dev_err(dev, "xgmac ioremap failed\n"); +- ret = PTR_ERR(pdata->xgmac_regs); +- goto err_io; +- } +- DBGPR(" xgmac_regs = %p\n", pdata->xgmac_regs); +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- pdata->xpcs_regs = devm_ioremap_resource(dev, res); +- if (IS_ERR(pdata->xpcs_regs)) { +- dev_err(dev, "xpcs ioremap failed\n"); +- ret = PTR_ERR(pdata->xpcs_regs); ++ /* Obtain device settings */ ++ if (pdata->adev && !acpi_disabled) ++ ret = xgbe_acpi_support(pdata); ++ else ++ ret = xgbe_of_support(pdata); ++ if (ret) + goto err_io; +- } +- DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs); + + /* Set the DMA mask */ + if (!dev->dma_mask) +@@ -309,23 +486,16 @@ static int xgbe_probe(struct platform_device *pdev) + goto err_io; + } + +- if (of_property_read_bool(dev->of_node, "dma-coherent")) { +- pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; +- pdata->arcache = XGBE_DMA_OS_ARCACHE; +- pdata->awcache = XGBE_DMA_OS_AWCACHE; +- } else { +- pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; +- pdata->arcache = XGBE_DMA_SYS_ARCACHE; +- pdata->awcache = XGBE_DMA_SYS_AWCACHE; +- } +- ++ /* Get the device interrupt */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "platform_get_irq failed\n"); + goto err_io; + } ++ + netdev->irq = ret; + netdev->base_addr = (unsigned long)pdata->xgmac_regs; ++ memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len); + + /* Set all the function pointers */ + xgbe_init_all_fptrs(pdata); +@@ -338,23 +508,6 @@ static int xgbe_probe(struct platform_device *pdev) + /* Populate the hardware features */ + xgbe_get_all_hw_features(pdata); + +- /* Retrieve the MAC address */ +- mac_addr = of_get_mac_address(dev->of_node); +- if (!mac_addr) { +- dev_err(dev, "invalid mac address for this device\n"); +- ret = -EINVAL; +- goto err_io; +- } +- memcpy(netdev->dev_addr, mac_addr, netdev->addr_len); +- +- /* Retrieve the PHY mode - it must be "xgmii" */ +- pdata->phy_mode = of_get_phy_mode(dev->of_node); +- if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { +- dev_err(dev, "invalid phy-mode specified for this device\n"); +- ret = -EINVAL; +- goto err_io; +- } +- + /* Set default configuration data */ + xgbe_default_config(pdata); + +@@ -532,10 +685,22 @@ static int xgbe_resume(struct device *dev) + } + #endif /* CONFIG_PM */ + ++#ifdef CONFIG_ACPI ++static const struct acpi_device_id xgbe_acpi_match[] = { ++ { "AMDI8000", 0 }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match); ++#endif ++ ++#ifdef CONFIG_OF + static const struct of_device_id xgbe_of_match[] = { ++ { .compatible = "amd,xgbe-seattle-v0a", }, + { .compatible = "amd,xgbe-seattle-v1a", }, + {}, + }; ++#endif + + MODULE_DEVICE_TABLE(of, xgbe_of_match); + static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume); +@@ -543,7 +708,12 @@ static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume); + static struct platform_driver xgbe_driver = { + .driver = { + .name = "amd-xgbe", ++#ifdef CONFIG_ACPI ++ .acpi_match_table = xgbe_acpi_match, ++#endif ++#ifdef CONFIG_OF + .of_match_table = xgbe_of_match, ++#endif + .pm = &xgbe_pm_ops, + }, + .probe = xgbe_probe, +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +index 6d2221e..095e70a 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +@@ -119,6 +119,7 @@ + #include + #include + #include ++#include + + #include "xgbe.h" + #include "xgbe-common.h" +@@ -206,25 +207,16 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) + + int xgbe_mdio_register(struct xgbe_prv_data *pdata) + { +- struct device_node *phy_node; + struct mii_bus *mii; + struct phy_device *phydev; + int ret = 0; + + DBGPR("-->xgbe_mdio_register\n"); + +- /* Retrieve the phy-handle */ +- phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0); +- if (!phy_node) { +- dev_err(pdata->dev, "unable to parse phy-handle\n"); +- return -EINVAL; +- } +- + mii = mdiobus_alloc(); + if (mii == NULL) { + dev_err(pdata->dev, "mdiobus_alloc failed\n"); +- ret = -ENOMEM; +- goto err_node_get; ++ return -ENOMEM; + } + + /* Register on the MDIO bus (don't probe any PHYs) */ +@@ -253,12 +245,9 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) + request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, + MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS])); + +- of_node_get(phy_node); +- phydev->dev.of_node = phy_node; + ret = phy_device_register(phydev); + if (ret) { + dev_err(pdata->dev, "phy_device_register failed\n"); +- of_node_put(phy_node); + goto err_phy_device; + } + +@@ -284,8 +273,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) + + pdata->phydev = phydev; + +- of_node_put(phy_node); +- + DBGPHY_REGS(pdata); + + DBGPR("<--xgbe_mdio_register\n"); +@@ -301,9 +288,6 @@ err_mdiobus_register: + err_mdiobus_alloc: + mdiobus_free(mii); + +-err_node_get: +- of_node_put(phy_node); +- + return ret; + } + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +index 37e64cf..2d1e84b 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +@@ -240,7 +240,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) + snprintf(info->name, sizeof(info->name), "%s", + netdev_name(pdata->netdev)); + info->owner = THIS_MODULE; +- info->max_adj = clk_get_rate(pdata->ptpclk); ++ info->max_adj = pdata->ptpclk_rate; + info->adjfreq = xgbe_adjfreq; + info->adjtime = xgbe_adjtime; + info->gettime = xgbe_gettime; +@@ -261,7 +261,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) + */ + dividend = 50000000; + dividend <<= 32; +- pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk)); ++ pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); - static const struct of_device_id xgbe_of_match[] = { -+ { .compatible = "amd,xgbe-seattle-v0a", }, - { .compatible = "amd,xgbe-seattle-v1a", }, - {}, - }; + /* Setup the timecounter */ + cc->read = xgbe_cc_read; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h -index e9fe6e6..389bfec 100644 +index e9fe6e6..78deed9 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h -@@ -187,8 +187,11 @@ +@@ -173,6 +173,12 @@ + #define XGBE_DMA_CLOCK "dma_clk" + #define XGBE_PTP_CLOCK "ptp_clk" + ++/* ACPI property names */ ++#define XGBE_ACPI_MAC_ADDR "mac-address" ++#define XGBE_ACPI_PHY_MODE "phy-mode" ++#define XGBE_ACPI_DMA_FREQ "amd,dma-freq" ++#define XGBE_ACPI_PTP_FREQ "amd,ptp-freq" ++ + /* Timestamp support - values based on 50MHz PTP clock + * 50MHz => 20 nsec + */ +@@ -187,8 +193,11 @@ #define XGBE_FIFO_SIZE_B(x) (x) #define XGBE_FIFO_SIZE_KB(x) (x * 1024) @@ -4782,6 +6867,330 @@ index e9fe6e6..389bfec 100644 /* Helper macro for descriptor handling * Always use XGBE_GET_DESC_DATA to access the descriptor data * since the index is free-running and needs to be and-ed +@@ -571,6 +580,7 @@ struct xgbe_hw_features { + struct xgbe_prv_data { + struct net_device *netdev; + struct platform_device *pdev; ++ struct acpi_device *adev; + struct device *dev; + + /* XGMAC/XPCS related mmio registers */ +@@ -651,6 +661,7 @@ struct xgbe_prv_data { + unsigned int phy_rx_pause; + + /* Netdev related settings */ ++ unsigned char mac_addr[MAX_ADDR_LEN]; + netdev_features_t netdev_features; + struct napi_struct napi; + struct xgbe_mmc_stats mmc_stats; +@@ -660,7 +671,9 @@ struct xgbe_prv_data { + + /* Device clocks */ + struct clk *sysclk; ++ unsigned long sysclk_rate; + struct clk *ptpclk; ++ unsigned long ptpclk_rate; + + /* Timestamp support */ + spinlock_t tstamp_lock; +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +index 812d8d6..0fb2971 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +@@ -580,9 +580,11 @@ void xgene_enet_reset(struct xgene_enet_pdata *pdata) + { + u32 val; + +- clk_prepare_enable(pdata->clk); +- clk_disable_unprepare(pdata->clk); +- clk_prepare_enable(pdata->clk); ++ if (pdata->clk) { ++ clk_prepare_enable(pdata->clk); ++ clk_disable_unprepare(pdata->clk); ++ clk_prepare_enable(pdata->clk); ++ } + xgene_enet_ecc_init(pdata); + xgene_enet_config_ring_if_assoc(pdata); + +@@ -648,15 +650,20 @@ static int xgene_enet_phy_connect(struct net_device *ndev) + struct phy_device *phy_dev; + struct device *dev = &pdata->pdev->dev; + +- phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); +- if (!phy_np) { +- netdev_dbg(ndev, "No phy-handle found\n"); +- return -ENODEV; ++ if (dev->of_node) { ++ phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); ++ if (!phy_np) { ++ netdev_dbg(ndev, "No phy-handle found in DT\n"); ++ return -ENODEV; ++ } ++ pdata->phy_dev = of_phy_find_device(phy_np); + } + +- phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, +- 0, pdata->phy_mode); +- if (!phy_dev) { ++ phy_dev = pdata->phy_dev; ++ ++ if (phy_dev == NULL || ++ phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, ++ pdata->phy_mode)) { + netdev_err(ndev, "Could not connect to PHY\n"); + return -ENODEV; + } +@@ -666,11 +673,52 @@ static int xgene_enet_phy_connect(struct net_device *ndev) + ~SUPPORTED_100baseT_Half & + ~SUPPORTED_1000baseT_Half; + phy_dev->advertising = phy_dev->supported; +- pdata->phy_dev = phy_dev; + + return 0; + } + ++#ifdef CONFIG_ACPI ++static int xgene_acpi_mdiobus_register(struct xgene_enet_pdata *pdata, ++ struct mii_bus *mdio) ++{ ++ struct device *dev = &pdata->pdev->dev; ++ struct phy_device *phy; ++ int i, ret; ++ u32 phy_id; ++ ++ /* Mask out all PHYs from auto probing. */ ++ mdio->phy_mask = ~0; ++ ++ /* Clear all the IRQ properties */ ++ if (mdio->irq) ++ for (i = 0; i < PHY_MAX_ADDR; i++) ++ mdio->irq[i] = PHY_POLL; ++ ++ /* Register the MDIO bus */ ++ ret = mdiobus_register(mdio); ++ if (ret) ++ return ret; ++ ++ ret = device_property_read_u32(dev, "phy-channel", &phy_id); ++ if (ret) ++ return -EINVAL; ++ ++ phy = get_phy_device(mdio, phy_id, true); ++ if (!phy || IS_ERR(phy)) ++ return -EIO; ++ ++ ret = phy_device_register(phy); ++ if (ret) ++ phy_device_free(phy); ++ else ++ pdata->phy_dev = phy; ++ ++ return ret; ++} ++#else ++#define xgene_acpi_mdiobus_register(a, b) -1 ++#endif ++ + int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) + { + struct net_device *ndev = pdata->ndev; +@@ -687,7 +735,7 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) + } + } + +- if (!mdio_np) { ++ if (dev->of_node && !mdio_np) { + netdev_dbg(ndev, "No mdio node in the dts\n"); + return -ENXIO; + } +@@ -705,7 +753,10 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) + mdio_bus->priv = pdata; + mdio_bus->parent = &ndev->dev; + +- ret = of_mdiobus_register(mdio_bus, mdio_np); ++ if (dev->of_node) ++ ret = of_mdiobus_register(mdio_bus, mdio_np); ++ else ++ ret = xgene_acpi_mdiobus_register(pdata, mdio_bus); + if (ret) { + netdev_err(ndev, "Failed to register MDIO bus\n"); + mdiobus_free(mdio_bus); +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +index e4222af..06f8252 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -739,6 +739,42 @@ static const struct net_device_ops xgene_ndev_ops = { + .ndo_set_mac_address = xgene_enet_set_mac_address, + }; + ++#ifdef CONFIG_ACPI ++static int acpi_get_mac_address(struct device *dev, ++ unsigned char *addr) ++{ ++ int ret; ++ ++ ret = device_property_read_u8_array(dev, "mac-address", addr, 6); ++ if (ret) ++ return 0; ++ ++ return 6; ++} ++ ++static int acpi_get_phy_mode(struct device *dev) ++{ ++ int i, ret, phy_mode; ++ char *modestr; ++ ++ ret = device_property_read_string(dev, "phy-mode", &modestr); ++ if (ret) ++ return -1; ++ ++ phy_mode = -1; ++ for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) { ++ if (!strcasecmp(modestr, phy_modes(i))) { ++ phy_mode = i; ++ break; ++ } ++ } ++ return phy_mode; ++} ++#else ++#define acpi_get_mac_address(a, b, c) 0 ++#define acpi_get_phy_mode(a) -1 ++#endif ++ + static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + { + struct platform_device *pdev; +@@ -754,6 +790,8 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + ndev = pdata->ndev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr"); ++ if (!res) ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Resource enet_csr not defined\n"); + return -ENODEV; +@@ -765,6 +803,8 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr"); ++ if (!res) ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(dev, "Resource ring_csr not defined\n"); + return -ENODEV; +@@ -776,6 +816,8 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd"); ++ if (!res) ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (!res) { + dev_err(dev, "Resource ring_cmd not defined\n"); + return -ENODEV; +@@ -783,7 +825,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + pdata->ring_cmd_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(pdata->ring_cmd_addr)) { + dev_err(dev, "Unable to retrieve ENET Ring command region\n"); +- return PTR_ERR(pdata->ring_cmd_addr); ++ return PTR_ERR(pdata->ring_cmd_addr); + } + + ret = platform_get_irq(pdev, 0); +@@ -797,22 +839,25 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + mac = of_get_mac_address(dev->of_node); + if (mac) + memcpy(ndev->dev_addr, mac, ndev->addr_len); +- else ++ else if (!acpi_get_mac_address(dev, ndev->dev_addr)) + eth_hw_addr_random(ndev); + memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); + + pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); ++ if (pdata->phy_mode < 0) ++ pdata->phy_mode = acpi_get_phy_mode(dev); + if (pdata->phy_mode < 0) { + dev_err(dev, "Incorrect phy-connection-type in DTS\n"); + return -EINVAL; + } + + pdata->clk = devm_clk_get(&pdev->dev, NULL); +- ret = IS_ERR(pdata->clk); + if (IS_ERR(pdata->clk)) { +- dev_err(&pdev->dev, "can't get clock\n"); +- ret = PTR_ERR(pdata->clk); +- return ret; ++ /* ++ * Not necessarily an error. Firmware may have ++ * set up the clock already. ++ */ ++ pdata->clk = NULL; + } + + base_addr = pdata->base_addr; +@@ -824,7 +869,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) + pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; + pdata->rx_buff_cnt = NUM_PKT_BUF; + +- return ret; ++ return 0; + } + + static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) +@@ -855,7 +900,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) + dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); + xgene_enet_cle_bypass(pdata, dst_ring_num, buf_pool->id); + +- return ret; ++ return 0; + } + + static int xgene_enet_probe(struct platform_device *pdev) +@@ -895,7 +940,7 @@ static int xgene_enet_probe(struct platform_device *pdev) + goto err; + } + +- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) { + netdev_err(ndev, "No usable DMA configuration\n"); + goto err; +@@ -936,6 +981,14 @@ static int xgene_enet_remove(struct platform_device *pdev) + return 0; + } + ++#ifdef CONFIG_ACPI ++static const struct acpi_device_id xgene_enet_acpi_match[] = { ++ { "APMC0D05", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match); ++#endif ++ + static struct of_device_id xgene_enet_match[] = { + {.compatible = "apm,xgene-enet",}, + {}, +@@ -947,6 +1000,7 @@ static struct platform_driver xgene_enet_driver = { + .driver = { + .name = "xgene-enet", + .of_match_table = xgene_enet_match, ++ .acpi_match_table = ACPI_PTR(xgene_enet_acpi_match), + }, + .probe = xgene_enet_probe, + .remove = xgene_enet_remove, +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +index 0815866..60375cc 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include "xgene_enet_hw.h" + + #define XGENE_DRV_VERSION "v1.0" diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index bcaa41a..ebad872 100644 --- a/drivers/net/ethernet/smsc/smc91x.c @@ -4817,11 +7226,29 @@ index bcaa41a..ebad872 100644 }, }; +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 65de0ca..360f9a2 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -26,7 +26,7 @@ config AMD_PHY + + config AMD_XGBE_PHY + tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs" +- depends on OF ++ depends on OF || ACPI + ---help--- + Currently supports the AMD 10GbE PHY + diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c -index f3230ee..90145d9 100644 +index f3230ee..d852c6e 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c -@@ -78,12 +78,14 @@ +@@ -74,16 +74,19 @@ + #include + #include + #include ++#include + MODULE_AUTHOR("Tom Lendacky "); MODULE_LICENSE("Dual BSD/GPL"); @@ -4838,7 +7265,7 @@ index f3230ee..90145d9 100644 #define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set" #define XGBE_AN_INT_CMPLT 0x01 -@@ -118,77 +120,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); +@@ -118,77 +121,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) #endif @@ -4916,7 +7343,7 @@ index f3230ee..90145d9 100644 #define GET_BITS(_var, _index, _width) \ (((_var) >> (_index)) & ((0x1 << (_width)) - 1)) -@@ -198,71 +129,12 @@ do { \ +@@ -198,71 +130,12 @@ do { \ (_var) |= (((_val) & ((0x1 << (_width)) - 1)) << (_index)); \ } while (0) @@ -4929,9 +7356,7 @@ index f3230ee..90145d9 100644 - SET_BITS((_var), \ - _prefix##_##_field##_INDEX, \ - _prefix##_##_field##_WIDTH, (_val)) -+#define XCMU_IOREAD(_priv, _reg) \ -+ ioread16((_priv)->cmu_regs + _reg) - +- -/* Macros for reading or writing SerDes integration registers - * The ioread macros will get bit fields or full values using the - * register definitions formed using the input names @@ -4941,9 +7366,7 @@ index f3230ee..90145d9 100644 - */ -#define XSIR0_IOREAD(_priv, _reg) \ - ioread16((_priv)->sir0_regs + _reg) -+#define XCMU_IOWRITE(_priv, _reg, _val) \ -+ iowrite16((_val), (_priv)->cmu_regs + _reg) - +- -#define XSIR0_IOREAD_BITS(_priv, _reg, _field) \ - GET_BITS(XSIR0_IOREAD((_priv), _reg), \ - _reg##_##_field##_INDEX, \ @@ -4980,8 +7403,12 @@ index f3230ee..90145d9 100644 - _reg##_##_field##_WIDTH, (_val)); \ - XSIR1_IOWRITE((_priv), _reg, reg_val); \ -} while (0) -- -- ++#define XCMU_IOREAD(_priv, _reg) \ ++ ioread16((_priv)->cmu_regs + _reg) + ++#define XCMU_IOWRITE(_priv, _reg, _val) \ ++ iowrite16((_val), (_priv)->cmu_regs + _reg) + -/* Macros for reading or writing SerDes RxTx registers - * The ioread macros will get bit fields or full values using the - * register definitions formed using the input names @@ -4992,7 +7419,7 @@ index f3230ee..90145d9 100644 #define XRXTX_IOREAD(_priv, _reg) \ ioread16((_priv)->rxtx_regs + _reg) -@@ -283,6 +155,77 @@ do { \ +@@ -283,6 +156,77 @@ do { \ XRXTX_IOWRITE((_priv), _reg, reg_val); \ } while (0) @@ -5070,7 +7497,21 @@ index f3230ee..90145d9 100644 enum amd_xgbe_phy_an { AMD_XGBE_AN_READY = 0, -@@ -321,18 +264,18 @@ struct amd_xgbe_phy_priv { +@@ -309,30 +253,31 @@ enum amd_xgbe_phy_mode { + }; + + enum amd_xgbe_phy_speedset { +- AMD_XGBE_PHY_SPEEDSET_1000_10000, ++ AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0, + AMD_XGBE_PHY_SPEEDSET_2500_10000, + }; + + struct amd_xgbe_phy_priv { + struct platform_device *pdev; ++ struct acpi_device *adev; + struct device *dev; + + struct phy_device *phydev; /* SerDes related mmio resources */ struct resource *rxtx_res; @@ -5094,7 +7535,7 @@ index f3230ee..90145d9 100644 /* Auto-negotiation state machine support */ struct mutex an_mutex; -@@ -394,33 +337,51 @@ static int amd_xgbe_phy_pcs_power_cycle(struct phy_device *phydev) +@@ -394,33 +339,51 @@ static int amd_xgbe_phy_pcs_power_cycle(struct phy_device *phydev) static void amd_xgbe_phy_serdes_start_ratechange(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; @@ -5157,7 +7598,7 @@ index f3230ee..90145d9 100644 } static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) -@@ -428,8 +389,8 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) +@@ -428,8 +391,8 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) struct amd_xgbe_phy_priv *priv = phydev->priv; int ret; @@ -5168,7 +7609,7 @@ index f3230ee..90145d9 100644 if (ret < 0) return ret; -@@ -455,19 +416,30 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) +@@ -455,19 +418,30 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) return ret; /* Set SerDes to 10G speed */ @@ -5206,7 +7647,7 @@ index f3230ee..90145d9 100644 priv->mode = AMD_XGBE_MODE_KR; return 0; -@@ -505,19 +477,30 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) +@@ -505,19 +479,30 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) return ret; /* Set SerDes to 2.5G speed */ @@ -5223,12 +7664,12 @@ index f3230ee..90145d9 100644 + XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_WORD_MODE, RXTX_10BIT_WORD); + + XRXTX_IOWRITE_BITS(priv, RXTX_REG5, TXAMP_CNTL, RXTX_1G_TX_AMP); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_HALF_RATE); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_10BIT_WORD); - XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_2500_BLWC); - XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_2500_PQ); -+ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_HALF_RATE); -+ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_10BIT_WORD); -+ + XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, 1); + + XRXTX_IOWRITE_BITS(priv, RXTX_REG53, RX_PLLSELECT, RXTX_1G_PLL); @@ -5244,7 +7685,7 @@ index f3230ee..90145d9 100644 priv->mode = AMD_XGBE_MODE_KX; return 0; -@@ -555,19 +538,30 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) +@@ -555,19 +540,30 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) return ret; /* Set SerDes to 1G speed */ @@ -5261,12 +7702,12 @@ index f3230ee..90145d9 100644 + XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_WORD_MODE, RXTX_10BIT_WORD); + + XRXTX_IOWRITE_BITS(priv, RXTX_REG5, TXAMP_CNTL, RXTX_1G_TX_AMP); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_FIFTH_RATE); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_10BIT_WORD); - XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_1000_BLWC); - XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1000_PQ); -+ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_FIFTH_RATE); -+ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_10BIT_WORD); -+ + XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, 1); + + XRXTX_IOWRITE_BITS(priv, RXTX_REG53, RX_PLLSELECT, RXTX_1G_PLL); @@ -5282,7 +7723,7 @@ index f3230ee..90145d9 100644 priv->mode = AMD_XGBE_MODE_KX; return 0; -@@ -639,13 +633,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, +@@ -639,13 +635,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, if (ret < 0) return AMD_XGBE_AN_ERROR; @@ -5296,20 +7737,32 @@ index f3230ee..90145d9 100644 return AMD_XGBE_AN_EVENT; } -@@ -1291,21 +1281,33 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) - goto err_priv; - } +@@ -1248,29 +1240,188 @@ unlock: + return ret; + } -- priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -- priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res); -- if (IS_ERR(priv->sir0_regs)) { -- dev_err(dev, "sir0 ioremap failed\n"); -- ret = PTR_ERR(priv->sir0_regs); ++static int amd_xgbe_phy_map_resources(struct amd_xgbe_phy_priv *priv, ++ struct platform_device *phy_pdev, ++ unsigned int phy_resnum) ++{ ++ struct device *dev = priv->dev; ++ int ret; ++ ++ /* Get the device mmio areas */ ++ priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, ++ phy_resnum++); ++ priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); ++ if (IS_ERR(priv->rxtx_regs)) { ++ dev_err(dev, "rxtx ioremap failed\n"); ++ return PTR_ERR(priv->rxtx_regs); ++ } ++ + /* All xgbe phy devices share the CMU registers so retrieve + * the resource and do the ioremap directly rather than + * the devm_ioremap_resource call + */ -+ priv->cmu_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ priv->cmu_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, ++ phy_resnum++); + if (!priv->cmu_res) { + dev_err(dev, "cmu invalid resource\n"); + ret = -EINVAL; @@ -5320,33 +7773,233 @@ index f3230ee..90145d9 100644 + if (!priv->cmu_regs) { + dev_err(dev, "cmu ioremap failed\n"); + ret = -ENOMEM; - goto err_rxtx; ++ goto err_rxtx; ++ } ++ ++ return 0; ++ ++err_rxtx: ++ devm_iounmap(dev, priv->rxtx_regs); ++ devm_release_mem_region(dev, priv->rxtx_res->start, ++ resource_size(priv->rxtx_res)); ++ ++ return ret; ++} ++ ++static void amd_xgbe_phy_unmap_resources(struct amd_xgbe_phy_priv *priv) ++{ ++ struct device *dev = priv->dev; ++ ++ devm_iounmap(dev, priv->cmu_regs); ++ ++ devm_iounmap(dev, priv->rxtx_regs); ++ devm_release_mem_region(dev, priv->rxtx_res->start, ++ resource_size(priv->rxtx_res)); ++} ++ ++#ifdef CONFIG_ACPI ++static int amd_xgbe_phy_acpi_support(struct amd_xgbe_phy_priv *priv) ++{ ++ struct platform_device *phy_pdev = priv->pdev; ++ struct acpi_device *adev = priv->adev; ++ struct device *dev = priv->dev; ++ const union acpi_object *property; ++ int ret; ++ ++ /* Map the memory resources */ ++ ret = amd_xgbe_phy_map_resources(priv, phy_pdev, 2); ++ if (ret) ++ return ret; ++ ++ /* Get the device serdes channel property */ ++ ret = acpi_dev_get_property(adev, XGBE_PHY_CHANNEL_PROPERTY, ++ ACPI_TYPE_INTEGER, &property); ++ if (ret) { ++ dev_err(dev, "unable to obtain %s acpi property\n", ++ XGBE_PHY_CHANNEL_PROPERTY); ++ goto err_resources; ++ } ++ priv->serdes_channel = property->integer.value; ++ ++ /* Get the device speed set property */ ++ ret = acpi_dev_get_property(adev, XGBE_PHY_SPEEDSET_PROPERTY, ++ ACPI_TYPE_INTEGER, &property); ++ if (ret) { ++ dev_err(dev, "unable to obtain %s acpi property\n", ++ XGBE_PHY_SPEEDSET_PROPERTY); ++ goto err_resources; ++ } ++ priv->speed_set = property->integer.value; ++ ++ return 0; ++ ++err_resources: ++ amd_xgbe_phy_unmap_resources(priv); ++ ++ return ret; ++} ++#else /* CONFIG_ACPI */ ++static int amd_xgbe_phy_acpi_support(struct amd_xgbe_phy_priv *priv) ++{ ++ return -EINVAL; ++} ++#endif /* CONFIG_ACPI */ ++ ++#ifdef CONFIG_OF ++static int amd_xgbe_phy_of_support(struct amd_xgbe_phy_priv *priv) ++{ ++ struct platform_device *phy_pdev; ++ struct device_node *bus_node; ++ struct device_node *phy_node; ++ struct device *dev = priv->dev; ++ const __be32 *property; ++ int ret; ++ ++ bus_node = priv->dev->of_node; ++ phy_node = of_parse_phandle(bus_node, "phy-handle", 0); ++ if (!phy_node) { ++ dev_err(dev, "unable to parse phy-handle\n"); ++ return -EINVAL; ++ } ++ ++ phy_pdev = of_find_device_by_node(phy_node); ++ if (!phy_pdev) { ++ dev_err(dev, "unable to obtain phy device\n"); ++ ret = -EINVAL; ++ goto err_put; ++ } ++ ++ /* Map the memory resources */ ++ ret = amd_xgbe_phy_map_resources(priv, phy_pdev, 0); ++ if (ret) ++ goto err_put; ++ ++ /* Get the device serdes channel property */ ++ property = of_get_property(phy_node, XGBE_PHY_CHANNEL_PROPERTY, NULL); ++ if (!property) { ++ dev_err(dev, "unable to obtain %s property\n", ++ XGBE_PHY_CHANNEL_PROPERTY); ++ ret = -EINVAL; ++ goto err_resources; ++ } ++ priv->serdes_channel = be32_to_cpu(*property); ++ ++ /* Get the device speed set property */ ++ property = of_get_property(phy_node, XGBE_PHY_SPEEDSET_PROPERTY, NULL); ++ if (property) ++ priv->speed_set = be32_to_cpu(*property); ++ ++ of_node_put(phy_node); ++ ++ return 0; ++ ++err_resources: ++ amd_xgbe_phy_unmap_resources(priv); ++ ++err_put: ++ of_node_put(phy_node); ++ ++ return ret; ++} ++#else /* CONFIG_OF */ ++static int amd_xgbe_phy_of_support(struct amd_xgbe_phy_priv *priv) ++{ ++ return -EINVAL; ++} ++#endif /* CONFIG_OF */ ++ + static int amd_xgbe_phy_probe(struct phy_device *phydev) + { + struct amd_xgbe_phy_priv *priv; +- struct platform_device *pdev; + struct device *dev; + char *wq_name; +- const __be32 *property; +- unsigned int speed_set; + int ret; + +- if (!phydev->dev.of_node) ++ if (!phydev->bus || !phydev->bus->parent) + return -EINVAL; + +- pdev = of_find_device_by_node(phydev->dev.of_node); +- if (!pdev) +- return -EINVAL; +- dev = &pdev->dev; ++ dev = phydev->bus->parent; + + wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name); +- if (!wq_name) { +- ret = -ENOMEM; +- goto err_pdev; +- } ++ if (!wq_name) ++ return -ENOMEM; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { +@@ -1278,60 +1429,33 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) + goto err_name; } +- priv->pdev = pdev; ++ priv->pdev = to_platform_device(dev); ++ priv->adev = ACPI_COMPANION(dev); + priv->dev = dev; + priv->phydev = phydev; + +- /* Get the device mmio areas */ +- priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); +- if (IS_ERR(priv->rxtx_regs)) { +- dev_err(dev, "rxtx ioremap failed\n"); +- ret = PTR_ERR(priv->rxtx_regs); ++ if (priv->adev && !acpi_disabled) ++ ret = amd_xgbe_phy_acpi_support(priv); ++ else ++ ret = amd_xgbe_phy_of_support(priv); ++ if (ret) + goto err_priv; +- } +- +- priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res); +- if (IS_ERR(priv->sir0_regs)) { +- dev_err(dev, "sir0 ioremap failed\n"); +- ret = PTR_ERR(priv->sir0_regs); +- goto err_rxtx; +- } + - priv->sir1_res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res); - if (IS_ERR(priv->sir1_regs)) { - dev_err(dev, "sir1 ioremap failed\n"); - ret = PTR_ERR(priv->sir1_regs); - goto err_sir0; -+ /* Get the device serdes channel property */ -+ property = of_get_property(dev->of_node, XGBE_PHY_CHANNEL_PROPERTY, -+ NULL); -+ if (!property) { -+ dev_err(dev, "unable to obtain serdes_channel property\n"); -+ ret = -EINVAL; -+ goto err_cmu; - } -+ priv->serdes_channel = be32_to_cpu(*property); - - /* Get the device speed set property */ - speed_set = 0; -@@ -1324,14 +1326,14 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) +- } +- +- /* Get the device speed set property */ +- speed_set = 0; +- property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, +- NULL); +- if (property) +- speed_set = be32_to_cpu(*property); +- +- switch (speed_set) { +- case 0: +- priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000; +- break; +- case 1: +- priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000; ++ switch (priv->speed_set) { ++ case AMD_XGBE_PHY_SPEEDSET_1000_10000: ++ case AMD_XGBE_PHY_SPEEDSET_2500_10000: + break; default: dev_err(dev, "invalid amd,speed-set property\n"); ret = -EINVAL; - goto err_sir1; -+ goto err_cmu; ++ goto err_resources; } priv->link = 1; @@ -5354,20 +8007,22 @@ index f3230ee..90145d9 100644 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); if (ret < 0) - goto err_sir1; -+ goto err_cmu; ++ goto err_resources; if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR) priv->mode = AMD_XGBE_MODE_KR; else -@@ -1342,7 +1344,7 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) +@@ -1342,30 +1466,17 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) priv->an_workqueue = create_singlethread_workqueue(wq_name); if (!priv->an_workqueue) { ret = -ENOMEM; - goto err_sir1; -+ goto err_cmu; ++ goto err_resources; } phydev->priv = priv; -@@ -1352,15 +1354,8 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) + + kfree(wq_name); +- of_dev_put(pdev); return 0; @@ -5380,12 +8035,27 @@ index f3230ee..90145d9 100644 - devm_iounmap(dev, priv->sir0_regs); - devm_release_mem_region(dev, priv->sir0_res->start, - resource_size(priv->sir0_res)); -+err_cmu: -+ devm_iounmap(dev, priv->cmu_regs); +- +-err_rxtx: +- devm_iounmap(dev, priv->rxtx_regs); +- devm_release_mem_region(dev, priv->rxtx_res->start, +- resource_size(priv->rxtx_res)); ++err_resources: ++ amd_xgbe_phy_unmap_resources(priv); + + err_priv: + devm_kfree(dev, priv); +@@ -1373,9 +1484,6 @@ err_priv: + err_name: + kfree(wq_name); + +-err_pdev: +- of_dev_put(pdev); +- + return ret; + } - err_rxtx: - devm_iounmap(dev, priv->rxtx_regs); -@@ -1392,14 +1387,7 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev) +@@ -1392,18 +1500,7 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev) flush_workqueue(priv->an_workqueue); destroy_workqueue(priv->an_workqueue); @@ -5397,10 +8067,14 @@ index f3230ee..90145d9 100644 - devm_iounmap(dev, priv->sir0_regs); - devm_release_mem_region(dev, priv->sir0_res->start, - resource_size(priv->sir0_res)); -+ devm_iounmap(dev, priv->cmu_regs); +- +- devm_iounmap(dev, priv->rxtx_regs); +- devm_release_mem_region(dev, priv->rxtx_res->start, +- resource_size(priv->rxtx_res)); ++ amd_xgbe_phy_unmap_resources(priv); - devm_iounmap(dev, priv->rxtx_regs); - devm_release_mem_region(dev, priv->rxtx_res->start, + devm_kfree(dev, priv); + } diff --git a/drivers/of/address.c b/drivers/of/address.c index e371825..afdb782 100644 --- a/drivers/of/address.c @@ -5586,6 +8260,164 @@ index e371825..afdb782 100644 } static int __of_address_to_resource(struct device_node *dev, +diff --git a/drivers/of/base.c b/drivers/of/base.c +index 293ed4b..270837b 100644 +--- a/drivers/of/base.c ++++ b/drivers/of/base.c +@@ -1247,6 +1247,39 @@ int of_property_read_u64(const struct device_node *np, const char *propname, + EXPORT_SYMBOL_GPL(of_property_read_u64); + + /** ++ * of_property_read_u64_array - Find and read an array of 64 bit integers ++ * from a property. ++ * ++ * @np: device node from which the property value is to be read. ++ * @propname: name of the property to be searched. ++ * @out_values: pointer to return value, modified only if return value is 0. ++ * @sz: number of array elements to read ++ * ++ * Search for a property in a device node and read 64-bit value(s) from ++ * it. Returns 0 on success, -EINVAL if the property does not exist, ++ * -ENODATA if property does not have a value, and -EOVERFLOW if the ++ * property data isn't large enough. ++ * ++ * The out_values is modified only if a valid u64 value can be decoded. ++ */ ++int of_property_read_u64_array(const struct device_node *np, ++ const char *propname, u64 *out_values, ++ size_t sz) ++{ ++ const __be32 *val = of_find_property_value_of_size(np, propname, ++ (sz * sizeof(*out_values))); ++ ++ if (IS_ERR(val)) ++ return PTR_ERR(val); ++ ++ while (sz--) { ++ *out_values++ = of_read_number(val, 2); ++ val += 2; ++ } ++ return 0; ++} ++ ++/** + * of_property_read_string - Find and read a string from a property + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. +@@ -2183,3 +2259,113 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node) + return of_get_next_parent(np); + } + EXPORT_SYMBOL(of_graph_get_remote_port); ++ ++int of_dev_prop_get(struct device_node *dn, const char *propname, void **valptr) ++{ ++ struct property *pp = of_find_property(dn, propname, NULL); ++ ++ if (!pp) ++ return -ENODATA; ++ ++ if (valptr) ++ *valptr = pp->value; ++ return 0; ++} ++ ++int of_dev_prop_read(struct device_node *dn, const char *propname, ++ enum dev_prop_type proptype, void *val) ++{ ++ void *value; ++ int ret = of_dev_prop_get(dn, propname, &value); ++ ++ if (ret) ++ return ret; ++ ++ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) { ++ switch (proptype) { ++ case DEV_PROP_U8: { ++ *(u8 *)val = *(u8 *)value; ++ break; ++ } ++ case DEV_PROP_U16: ++ *(u16 *)val = *(u16 *)value; ++ break; ++ case DEV_PROP_U32: ++ *(u32 *)val = *(u32 *)value; ++ break; ++ default: ++ *(u64 *)val = *(u64 *)value; ++ break; ++ } ++ } else if (proptype == DEV_PROP_STRING) { ++ *(char **)val = value; ++ } ++ return ret; ++ ++} ++ ++int of_dev_prop_read_array(struct device_node *dn, const char *propname, ++ enum dev_prop_type proptype, void *val, size_t nval) ++{ ++ int ret, elem_size; ++ ++ if (!val) { ++ switch (proptype) { ++ case DEV_PROP_U8: ++ elem_size = sizeof(u8); ++ break; ++ case DEV_PROP_U16: ++ elem_size = sizeof(u16); ++ break; ++ case DEV_PROP_U32: ++ elem_size = sizeof(u32); ++ break; ++ case DEV_PROP_U64: ++ elem_size = sizeof(u64); ++ break; ++ case DEV_PROP_STRING: ++ return of_property_count_strings(dn, propname); ++ default: ++ return -EINVAL; ++ } ++ return of_property_count_elems_of_size(dn, propname, elem_size); ++ } ++ ++ switch (proptype) { ++ case DEV_PROP_U8: ++ ret = of_property_read_u8_array(dn, propname, (u8 *)val, nval); ++ break; ++ case DEV_PROP_U16: ++ ret = of_property_read_u16_array(dn, propname, (u16 *)val, nval); ++ break; ++ case DEV_PROP_U32: ++ ret = of_property_read_u32_array(dn, propname, (u32 *)val, nval); ++ break; ++ case DEV_PROP_U64: ++ ret = of_property_read_u64_array(dn, propname, (u64 *)val, nval); ++ break; ++ case DEV_PROP_STRING: ++ ret = of_property_read_string_array(dn, propname, ++ (char **)val, nval); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++int of_for_each_child_node(struct device *dev, ++ int (*fn)(struct device *dev, void *child, void *data), ++ void *data) ++{ ++ struct device_node *child; ++ int ret = 0; ++ ++ for_each_child_of_node(dev->of_node, child) { ++ ret = fn(dev, child, data); ++ if (ret) ++ break; ++ } ++ return ret; ++} diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 8481996..8882b46 100644 --- a/drivers/of/of_pci.c @@ -6601,7 +9433,7 @@ index 2c9ac70..6e994fc 100644 * pci_ext_cfg_avail - can we access extended PCI config space? * diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c -index 4170113..c3cec34 100644 +index 4170113..ff44f5a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -485,7 +485,7 @@ void pci_read_bridge_bases(struct pci_bus *child) @@ -6624,26 +9456,7 @@ index 4170113..c3cec34 100644 return b; } -@@ -515,7 +519,7 @@ static void pci_release_host_bridge_dev(struct device *dev) - kfree(bridge); - } - --static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) -+static struct pci_host_bridge *pci_alloc_host_bridge(void) - { - struct pci_host_bridge *bridge; - -@@ -524,7 +528,8 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) - return NULL; - - INIT_LIST_HEAD(&bridge->windows); -- bridge->bus = b; -+ bridge->dev.release = pci_release_host_bridge_dev; -+ - return bridge; - } - -@@ -671,7 +676,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, +@@ -671,7 +675,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, /* * Allocate a new bus, and inherit stuff from the parent.. */ @@ -6652,22 +9465,15 @@ index 4170113..c3cec34 100644 if (!child) return NULL; -@@ -1751,37 +1756,37 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, +@@ -1751,13 +1755,14 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, char bus_addr[64]; char *fmt; - b = pci_alloc_bus(); -- if (!b) -+ bridge = pci_alloc_host_bridge(); -+ if (!bridge) ++ b = pci_alloc_bus(NULL); + if (!b) return NULL; -+ bridge->dev.parent = parent; -+ -+ b = pci_alloc_bus(NULL); -+ if (!b) -+ goto err_out; -+ b->sysdata = sysdata; b->ops = ops; b->number = b->busn_res.start = bus; @@ -6675,47 +9481,7 @@ index 4170113..c3cec34 100644 b2 = pci_find_bus(pci_domain_nr(b), bus); if (b2) { /* If we already got to this bus through a different bridge, ignore it */ - dev_dbg(&b2->dev, "bus already known\n"); -- goto err_out; -+ goto err_bus_out; - } - -- bridge = pci_alloc_host_bridge(b); -- if (!bridge) -- goto err_out; -- -- bridge->dev.parent = parent; -- bridge->dev.release = pci_release_host_bridge_dev; -+ bridge->bus = b; - dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); - error = pcibios_root_bridge_prepare(bridge); -- if (error) { -- kfree(bridge); -+ if (error) - goto err_out; -- } - - error = device_register(&bridge->dev); - if (error) { - put_device(&bridge->dev); -- goto err_out; -+ goto err_bus_out; - } - b->bridge = get_device(&bridge->dev); - device_enable_async_suspend(b->bridge); -@@ -1838,8 +1843,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, - class_dev_reg_err: - put_device(&bridge->dev); - device_unregister(&bridge->dev); --err_out: -+err_bus_out: - kfree(b); -+err_out: -+ kfree(bridge); - return NULL; - } - -@@ -1936,6 +1943,9 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, +@@ -1936,6 +1941,9 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, if (!found) pci_bus_update_busn_res_end(b, max); @@ -7216,7 +9982,7 @@ index c728113..f97804b 100644 #define METHOD_NAME__SB_ "_SB_" #define METHOD_NAME__SEG "_SEG" diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h -index 57ee052..a483e61 100644 +index 57ee052..a1ef42f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -68,6 +68,8 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs); @@ -7228,6 +9994,28 @@ index 57ee052..a483e61 100644 static inline union acpi_object * acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, int rev, int func, union acpi_object *argv4, acpi_object_type type) +@@ -337,6 +339,13 @@ struct acpi_device_physical_node { + bool put_online:1; + }; + ++/* ACPI Device Specific Data (_DSD) */ ++struct acpi_device_data { ++ const union acpi_object *pointer; ++ const union acpi_object *properties; ++ const union acpi_object *of_compatible; ++}; ++ + /* Device */ + struct acpi_device { + int device_type; +@@ -353,6 +362,7 @@ struct acpi_device { + struct acpi_device_wakeup wakeup; + struct acpi_device_perf performance; + struct acpi_device_dir dir; ++ struct acpi_device_data data; + struct acpi_scan_handler *handler; + struct acpi_hotplug_context *hp; + struct acpi_driver *driver; diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h index 444671e..9d573db 100644 --- a/include/acpi/acpi_io.h @@ -7330,7 +10118,7 @@ index 787bcc8..5480cb2 100644 /* 1: SBSA Generic Watchdog Structure */ diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h -index 975e1cc..2e2161b 100644 +index 975e1cc..b8fdc57 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -331,7 +331,7 @@ static inline void iounmap(void __iomem *addr) @@ -7338,7 +10126,7 @@ index 975e1cc..2e2161b 100644 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) { - return (void __iomem *) port; -+ return (void __iomem *)(PCI_IOBASE + (port & IO_SPACE_LIMIT)); ++ return PCI_IOBASE + (port & IO_SPACE_LIMIT); } static inline void ioport_unmap(void __iomem *p) @@ -7391,10 +10179,18 @@ index 35b0c12..d98e96b 100644 return -ENODEV; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h -index 807cbc4..4615eb1 100644 +index 807cbc4..ecb9e25 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h -@@ -71,6 +71,7 @@ enum acpi_irq_model_id { +@@ -28,6 +28,7 @@ + #include + #include /* for struct resource */ + #include ++#include + + #ifndef _LINUX + #define _LINUX +@@ -71,6 +72,7 @@ enum acpi_irq_model_id { ACPI_IRQ_MODEL_IOAPIC, ACPI_IRQ_MODEL_IOSAPIC, ACPI_IRQ_MODEL_PLATFORM, @@ -7402,7 +10198,7 @@ index 807cbc4..4615eb1 100644 ACPI_IRQ_MODEL_COUNT }; -@@ -123,6 +124,10 @@ int acpi_numa_init (void); +@@ -123,6 +125,10 @@ int acpi_numa_init (void); int acpi_table_init (void); int acpi_table_parse(char *id, acpi_tbl_table_handler handler); @@ -7413,6 +10209,107 @@ index 807cbc4..4615eb1 100644 int __init acpi_table_parse_entries(char *id, unsigned long table_size, int entry_id, acpi_tbl_entry_handler handler, +@@ -423,12 +429,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), + const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, + const struct device *dev); + +-static inline bool acpi_driver_match_device(struct device *dev, +- const struct device_driver *drv) +-{ +- return !!acpi_match_device(drv->acpi_match_table, dev); +-} +- ++extern bool acpi_driver_match_device(struct device *dev, ++ const struct device_driver *drv); + int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); + int acpi_device_modalias(struct device *, char *, int); + +@@ -660,4 +662,85 @@ do { \ + #endif + #endif + ++/* Device properties */ ++ ++#define MAX_ACPI_REFERENCE_ARGS 8 ++struct acpi_reference_args { ++ struct acpi_device *adev; ++ size_t nargs; ++ u64 args[MAX_ACPI_REFERENCE_ARGS]; ++}; ++ ++#ifdef CONFIG_ACPI ++int acpi_dev_get_property(struct acpi_device *adev, const char *name, ++ acpi_object_type type, const union acpi_object **obj); ++int acpi_dev_get_property_array(struct acpi_device *adev, const char *name, ++ acpi_object_type type, ++ const union acpi_object **obj); ++int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name, ++ const char *cells_name, size_t index, ++ struct acpi_reference_args *args); ++ ++int acpi_dev_prop_get(struct acpi_device *adev, const char *propname, ++ void **valptr); ++int acpi_dev_prop_read(struct acpi_device *adev, const char *propname, ++ enum dev_prop_type proptype, void *val); ++int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname, ++ enum dev_prop_type proptype, void *val, ++ size_t nval); ++int acpi_for_each_child_node(struct device *dev, ++ int (*fn)(struct device *dev, void *child, void *data), ++ void *data); ++#else ++static inline int acpi_dev_get_property(struct acpi_device *adev, ++ const char *name, acpi_object_type type, ++ const union acpi_object **obj) ++{ ++ return -ENXIO; ++} ++static inline int acpi_dev_get_property_array(struct acpi_device *adev, ++ const char *name, ++ acpi_object_type type, ++ const union acpi_object **obj) ++{ ++ return -ENXIO; ++} ++static inline int acpi_dev_get_property_reference(struct acpi_device *adev, ++ const char *name, const char *cells_name, ++ size_t index, struct acpi_reference_args *args) ++{ ++ return -ENXIO; ++} ++ ++static inline int acpi_dev_prop_get(struct acpi_device *adev, ++ const char *propname, ++ void **valptr) ++{ ++ return -ENXIO; ++} ++ ++static inline int acpi_dev_prop_read(struct acpi_device *adev, ++ const char *propname, ++ enum dev_prop_type proptype, void *val) ++{ ++ return -ENXIO; ++} ++ ++static inline int acpi_dev_prop_read_array(struct acpi_device *adev, ++ const char *propname, ++ enum dev_prop_type proptype, ++ void *val, size_t nval) ++{ ++ return -ENXIO; ++} ++ ++static inline int acpi_for_each_child_node(struct device *dev, ++ int (*fn)(struct device *dev, void *child, void *data), ++ void *data) ++{ ++ return -ENXIO; ++} ++ ++#endif ++ + #endif /*_LINUX_ACPI_H*/ diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 653f0e2..5839f98 100644 --- a/include/linux/clocksource.h @@ -7428,6 +10325,50 @@ index 653f0e2..5839f98 100644 +#endif + #endif /* _LINUX_CLOCKSOURCE_H */ +diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h +index 12f146f..033d2fd 100644 +--- a/include/linux/gpio/consumer.h ++++ b/include/linux/gpio/consumer.h +@@ -94,6 +94,11 @@ int gpiod_to_irq(const struct gpio_desc *desc); + struct gpio_desc *gpio_to_desc(unsigned gpio); + int desc_to_gpio(const struct gpio_desc *desc); + ++/* Child properties interface */ ++struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child, ++ const char *propname, int index); ++struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child, ++ const char *propname, int index); + #else /* CONFIG_GPIOLIB */ + + static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev, +diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h +index 8b62246..ee2d8c6 100644 +--- a/include/linux/gpio_keys.h ++++ b/include/linux/gpio_keys.h +@@ -2,6 +2,7 @@ + #define _GPIO_KEYS_H + + struct device; ++struct gpio_desc; + + /** + * struct gpio_keys_button - configuration parameters +@@ -17,6 +18,7 @@ struct device; + * disable button via sysfs + * @value: axis value for %EV_ABS + * @irq: Irq number in case of interrupt keys ++ * @gpiod: GPIO descriptor + */ + struct gpio_keys_button { + unsigned int code; +@@ -29,6 +31,7 @@ struct gpio_keys_button { + bool can_disable; + int value; + unsigned int irq; ++ struct gpio_desc *gpiod; + }; + + /** diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ad5b577 @@ -7478,6 +10419,80 @@ index 45e2d8c..2b0f246 100644 #define GICH_HCR 0x0 #define GICH_VTR 0x4 #define GICH_VMCR 0x8 +diff --git a/include/linux/leds.h b/include/linux/leds.h +index e436864..879a113 100644 +--- a/include/linux/leds.h ++++ b/include/linux/leds.h +@@ -246,6 +246,7 @@ struct led_platform_data { + struct gpio_led { + const char *name; + const char *default_trigger; ++ struct gpio_desc *gpiod; + unsigned gpio; + unsigned active_low : 1; + unsigned retain_state_suspended : 1; +diff --git a/include/linux/of.h b/include/linux/of.h +index 6c4363b..a9ee42d 100644 +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -355,6 +356,15 @@ const char *of_prop_next_string(struct property *prop, const char *cur); + + bool of_console_check(struct device_node *dn, char *name, int index); + ++int of_dev_prop_get(struct device_node *dn, const char *propname, void **valptr); ++int of_dev_prop_read(struct device_node *dn, const char *propname, ++ enum dev_prop_type proptype, void *val); ++int of_dev_prop_read_array(struct device_node *dn, const char *propname, ++ enum dev_prop_type proptype, void *val, size_t nval); ++int of_for_each_child_node(struct device *dev, ++ int (*fn)(struct device *dev, void *child, void *data), ++ void *data); ++ + #else /* CONFIG_OF */ + + static inline const char* of_node_full_name(const struct device_node *np) +@@ -582,6 +592,33 @@ static inline const char *of_prop_next_string(struct property *prop, + return NULL; + } + ++static inline int of_dev_prop_get(struct device_node *dn, const char *propname, ++ void **valptr) ++{ ++ return -ENXIO; ++} ++ ++static inline int of_dev_prop_read(struct device_node *dn, const char *propname, ++ enum dev_prop_type proptype, void *val) ++{ ++ return -ENXIO; ++} ++ ++static inline int of_dev_prop_read_array(struct device_node *dn, ++ const char *propname, ++ enum dev_prop_type proptype, ++ void *val, size_t nval) ++{ ++ return -ENXIO; ++} ++ ++static inline int of_for_each_child_node(struct device *dev, ++ int (*fn)(struct device *dev, void *child, void *data), ++ void *data) ++{ ++ return -ENXIO; ++} ++ + #define of_match_ptr(_ptr) NULL + #define of_match_node(_matches, _node) NULL + #endif /* CONFIG_OF */ diff --git a/include/linux/of_address.h b/include/linux/of_address.h index fb7b722..7ebb877 100644 --- a/include/linux/of_address.h @@ -7679,6 +10694,219 @@ index 96453f9..6d540b9 100644 #ifdef CONFIG_HIBERNATE_CALLBACKS extern struct dev_pm_ops pcibios_pm_ops; +diff --git a/include/linux/property.h b/include/linux/property.h +new file mode 100644 +index 0000000..1a42878 +--- /dev/null ++++ b/include/linux/property.h +@@ -0,0 +1,207 @@ ++/* ++ * property.h - Unified device property interface. ++ * ++ * Copyright (C) 2014, Intel Corporation ++ * Authors: Rafael J. Wysocki ++ * Mika Westerberg ++ * ++ * 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 _LINUX_PROPERTY_H_ ++#define _LINUX_PROPERTY_H_ ++ ++#include ++ ++enum dev_prop_type { ++ DEV_PROP_U8, ++ DEV_PROP_U16, ++ DEV_PROP_U32, ++ DEV_PROP_U64, ++ DEV_PROP_STRING, ++ DEV_PROP_MAX, ++}; ++ ++int device_get_property(struct device *dev, const char *propname, ++ void **valptr); ++int device_read_property(struct device *dev, const char *propname, ++ enum dev_prop_type proptype, void *val); ++int device_read_property_array(struct device *dev, const char *propname, ++ enum dev_prop_type proptype, void *val, ++ size_t nval); ++int device_get_child_property(struct device *dev, void *child, ++ const char *propname, void **valptr); ++int device_read_child_property(struct device *dev, void *child, ++ const char *propname, ++ enum dev_prop_type proptype, void *val); ++int device_read_child_property_array(struct device *dev, void *child, ++ const char *propname, ++ enum dev_prop_type proptype, void *val, ++ size_t nval); ++int device_for_each_child_node(struct device *dev, ++ int (*fn)(struct device *dev, void *child, void *data), ++ void *data); ++unsigned int device_get_child_node_count(struct device *dev); ++ ++static inline int device_property_read_u8(struct device *dev, ++ const char *propname, u8 *out_value) ++{ ++ return device_read_property(dev, propname, DEV_PROP_U8, out_value); ++} ++ ++static inline int device_property_read_u16(struct device *dev, ++ const char *propname, u16 *out_value) ++{ ++ return device_read_property(dev, propname, DEV_PROP_U16, out_value); ++} ++ ++static inline int device_property_read_u32(struct device *dev, ++ const char *propname, u32 *out_value) ++{ ++ return device_read_property(dev, propname, DEV_PROP_U32, out_value); ++} ++ ++static inline int device_property_read_u64(struct device *dev, ++ const char *propname, u64 *out_value) ++{ ++ return device_read_property(dev, propname, DEV_PROP_U64, out_value); ++} ++ ++static inline int device_property_read_u8_array(struct device *dev, ++ const char *propname, ++ u8 *val, size_t nval) ++{ ++ return device_read_property_array(dev, propname, DEV_PROP_U8, val, ++ nval); ++} ++ ++static inline int device_property_read_u16_array(struct device *dev, ++ const char *propname, ++ u16 *val, size_t nval) ++{ ++ return device_read_property_array(dev, propname, DEV_PROP_U16, val, ++ nval); ++} ++ ++static inline int device_property_read_u32_array(struct device *dev, ++ const char *propname, ++ u32 *val, size_t nval) ++{ ++ return device_read_property_array(dev, propname, DEV_PROP_U32, val, ++ nval); ++} ++ ++static inline int device_property_read_u64_array(struct device *dev, ++ const char *propname, ++ u64 *val, size_t nval) ++{ ++ return device_read_property_array(dev, propname, DEV_PROP_U64, val, ++ nval); ++} ++ ++static inline int device_property_read_string(struct device *dev, ++ const char *propname, ++ const char **out_string) ++{ ++ return device_read_property(dev, propname, DEV_PROP_STRING, out_string); ++} ++ ++static inline int device_property_read_string_array(struct device *dev, ++ const char *propname, ++ const char **out_strings, ++ size_t nstrings) ++{ ++ return device_read_property_array(dev, propname, DEV_PROP_STRING, ++ out_strings, nstrings); ++} ++ ++static inline int device_child_property_read_u8(struct device *dev, void *child, ++ const char *propname, ++ u8 *out_value) ++{ ++ return device_read_child_property(dev, child, propname, DEV_PROP_U8, ++ out_value); ++} ++ ++static inline int device_child_property_read_u16(struct device *dev, void *child, ++ const char *propname, ++ u16 *out_value) ++{ ++ return device_read_child_property(dev, child, propname, DEV_PROP_U16, ++ out_value); ++} ++ ++static inline int device_child_property_read_u32(struct device *dev, void *child, ++ const char *propname, ++ u32 *out_value) ++{ ++ return device_read_child_property(dev, child, propname, DEV_PROP_U32, ++ out_value); ++} ++ ++static inline int device_child_property_read_u64(struct device *dev, void *child, ++ const char *propname, ++ u64 *out_value) ++{ ++ return device_read_child_property(dev, child, propname, DEV_PROP_U64, ++ out_value); ++} ++ ++static inline int device_child_property_read_u8_array(struct device *dev, ++ void *child, ++ const char *propname, ++ u8 *val, size_t nval) ++{ ++ return device_read_child_property_array(dev, child, propname, ++ DEV_PROP_U8, val, nval); ++} ++ ++static inline int device_child_property_read_u16_array(struct device *dev, ++ void *child, ++ const char *propname, ++ u16 *val, size_t nval) ++{ ++ return device_read_child_property_array(dev, child, propname, ++ DEV_PROP_U16, val, nval); ++} ++ ++static inline int device_child_property_read_u32_array(struct device *dev, ++ void *child, ++ const char *propname, ++ u32 *val, size_t nval) ++{ ++ return device_read_child_property_array(dev, child, propname, ++ DEV_PROP_U32, val, nval); ++} ++ ++static inline int device_child_property_read_u64_array(struct device *dev, ++ void *child, ++ const char *propname, ++ u64 *val, size_t nval) ++{ ++ return device_read_child_property_array(dev, child, propname, ++ DEV_PROP_U64, val, nval); ++} ++ ++static inline int device_child_property_read_string(struct device *dev, ++ void *child, ++ const char *propname, ++ const char **out_string) ++{ ++ return device_read_child_property(dev, child, propname, DEV_PROP_STRING, ++ out_string); ++} ++ ++static inline int device_child_property_read_string_array(struct device *dev, ++ void *child, ++ const char *propname, ++ const char **out_strings, ++ size_t nstrings) ++{ ++ return device_read_child_property_array(dev, child, propname, ++ DEV_PROP_STRING, ++ out_strings, nstrings); ++} ++#endif /* _LINUX_PROPERTY_H_ */ diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h index e9441b9..1d3f39c 100644 --- a/tools/perf/arch/arm64/include/perf_regs.h diff --git a/kernel.spec b/kernel.spec index 1ecd022..174767f 100644 --- a/kernel.spec +++ b/kernel.spec @@ -42,7 +42,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 301 +%global baserelease 302 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -571,6 +571,7 @@ Patch15000: watchdog-Disable-watchdog-on-virtual-machines.patch # PPC Patch18000: ppc64-fixtools.patch # ARM64 +Patch20000: arm64-force-serial-to-be-active-consdev.patch # ARMv7 Patch21020: ARM-tegra-usb-no-reset.patch @@ -1375,6 +1376,10 @@ ApplyPatch drm-i915-Ignore-long-hpds-on-eDP-ports.patch ApplyPatch kernel-arm64.patch %ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does. ApplyPatch kernel-arm64.patch -R +%else +# arm64-force-serial-to-be-active-consdev.patch: not for upstream +# solved with SPCR in future +ApplyPatch arm64-force-serial-to-be-active-consdev.patch %endif %endif @@ -2239,6 +2244,12 @@ fi # ||----w | # || || %changelog +* Thu Dec 04 2014 Kyle McMartin - 3.17.4-302 +- kernel-arm64.patch: update. +- arm64-force-serial-to-be-active-consdev.patch: force serial consoles + to be the primary console device instead of defaulting to tty0. No + changes to drivers outside of ARM-land. + * Mon Dec 01 2014 Josh Boyer - Add patch to quiet i915 driver on long hdps - Add patch to fix oops when using xpad (rhbz 1094048)