summaryrefslogtreecommitdiffstats
path: root/freed-ora/current
diff options
context:
space:
mode:
Diffstat (limited to 'freed-ora/current')
-rw-r--r--freed-ora/current/f20/acpi-video-add-disable_native_backlight_quirk_for_samsung_510r.patch39
-rw-r--r--freed-ora/current/f20/kernel-arm64.patch20298
-rw-r--r--freed-ora/current/f20/kernel.spec15
-rw-r--r--freed-ora/current/f20/sources2
4 files changed, 11796 insertions, 8558 deletions
diff --git a/freed-ora/current/f20/acpi-video-add-disable_native_backlight_quirk_for_samsung_510r.patch b/freed-ora/current/f20/acpi-video-add-disable_native_backlight_quirk_for_samsung_510r.patch
new file mode 100644
index 000000000..9a123dd45
--- /dev/null
+++ b/freed-ora/current/f20/acpi-video-add-disable_native_backlight_quirk_for_samsung_510r.patch
@@ -0,0 +1,39 @@
+From b29c0d36da67a64f5de1fe167c0b807815aa1da4 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 4 Feb 2015 14:44:51 +0100
+Subject: [PATCH 2/2] acpi-video: Add disable_native_backlight quirk for
+ Samsung 510R
+
+Backlight control through the native intel interface does not work properly
+on the Samsung 510R, where as using the acpi_video interface does work, add
+a quirk for this.
+
+BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1186097
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/acpi/video.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
+index 497d986..88a4f99 100644
+--- a/drivers/acpi/video.c
++++ b/drivers/acpi/video.c
+@@ -523,6 +523,15 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
+ },
+ },
+ {
++ /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
++ .callback = video_disable_native_backlight,
++ .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "3570R/370R/470R/450R/510R/4450RV"),
++ },
++ },
++ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
+ .callback = video_disable_native_backlight,
+ .ident = "SAMSUNG 730U3E/740U3E",
+--
+2.1.0
+
diff --git a/freed-ora/current/f20/kernel-arm64.patch b/freed-ora/current/f20/kernel-arm64.patch
index 25f0479c8..e98d10a4d 100644
--- a/freed-ora/current/f20/kernel-arm64.patch
+++ b/freed-ora/current/f20/kernel-arm64.patch
@@ -1,767 +1,1348 @@
-commit db044807ca763c21bae298388239be6177c6ccec
-Merge: 649c9e3 26bcd8b
-Author: Kyle McMartin <kmcmarti@redhat.com>
-Date: Wed Jul 30 14:31:24 2014 -0400
+commit 0335b5034b998e978bf9343da77246bcbad33981
+Author: Mark Salter <msalter@redhat.com>
+Date: Wed Nov 19 10:32:11 2014 -0500
- Merge branch 'master' into devel
+ arm64: explicitly set noncoherent ops for _CCA handling
- Conflicts:
- virt/kvm/arm/vgic.c
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 649c9e3a45e81852daf80c126a332297b75cb109
-Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
-Date: Tue Jul 29 12:49:10 2014 +0200
+commit 4a2d43442e20a24b78594d12914706deddc119de
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Nov 10 17:09:29 2014 -0500
- arm64/efi: efistub: don't abort if base of DRAM is occupied
+ DO NOT UPSTREAM - pci/xgene: Provide fixup for ACPI MCFG support
- 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.
+ Xgene doesn't decode bus bits of mmconfig region and only
+ supports devfn 0 of bus 0. For other buses/devices, some
+ internal registers need to be poked. This patch provides
+ a fixup to support ACPI MCFG tables. This is a horrible
+ hack allowing the hardware to be used for PCI testing, but
+ it is not intended to be a long term patch.
- Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 5102fd06b12467a0518537061805483a759bc856
-Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
-Date: Tue Jul 29 12:49:09 2014 +0200
+commit b93f804830d9ef6d572dd6be9734108199141b87
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Nov 10 17:33:18 2014 -0500
- arm64/efi: efistub: cover entire static mem footprint in PE/COFF .text
+ DO NOT UPSTREAM - provide hook for MCFG fixups
- 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.
+ This is a temprary mechanism needed by at least one early
+ arm64 hardware platform with broken MCFG support. This is
+ not intended for upstream and will go away as soon as newer
+ hardware with fully compliant ECAM becomes available.
- 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.
-
- Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 3b4dfb00a401b7fecf01d3c89b154907167dff52
-Author: Mark Rutland <mark.rutland@arm.com>
-Date: Tue Jul 29 12:49:08 2014 +0200
+commit 2d76cb937a6c0010d1de181d0142f0822df5071d
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Nov 10 17:30:25 2014 -0500
- arm64: spin-table: handle unmapped cpu-release-addrs
+ arm64/pci/acpi: initial support for ACPI probing of PCI
- 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.
+ Signed-off-by: Mark Salter <msalter@redhat.com>
+
+commit a438ff7be0140738b1224d5ade6345a9febad279
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Nov 10 17:23:57 2014 -0500
+
+ arm64/acpi/pci: add support for parsing MCFG table
- 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.
+ Add support for parsing MCFG table and provide functions to read/write
+ PCI configuration space based on the parsed info. This provides the
+ low-level raw_pci_read/raw_pci_write functionality.
- Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit a49ad891b2e91338587dc5576c9da73b249a9d13
+commit 814b22167d35b18fc3de745277a2190ff0841585
Author: Mark Salter <msalter@redhat.com>
-Date: Mon Jul 14 15:52:06 2014 -0400
+Date: Mon Nov 10 16:42:14 2014 -0500
- pci/xgene: use pci_remap_iospace() instead of pci_ioremap_io()
+ DO NOT UPSTREAM - pci/xgene: workaround CRS issue
+
+ CRS is not behaving properly for some reason. Until this
+ gets diagnosed properly, pretend not to support it in order
+ to prevent hangs in 3.18 kernel.
Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 1a958ec71db226d35ed51756b7164142bb0a60a3
-Author: Tanmay Inamdar <tinamdar@apm.com>
-Date: Wed Mar 19 16:12:42 2014 -0700
+commit b90d000000801b473ed4c69757d3be9e433b6c5e
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Nov 10 16:31:05 2014 -0500
- MAINTAINERS: entry for APM X-Gene PCIe host driver
+ iommu/arm-smmu: fix NULL dereference with ACPI PCI devices
- Add entry for AppliedMicro X-Gene PCIe host driver.
+ Fix a NULL dereference in find_mmu_master which occurs when
+ booting with ACPI. In that case, PCI bridges with not have
+ an of_node. Add a check for NULL of_node and bail out if that
+ is the case.
- Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 03dc92f35b8f8be898ca12e3dc7c15961f414907
-Author: Tanmay Inamdar <tinamdar@apm.com>
-Date: Wed Mar 19 16:12:41 2014 -0700
+commit 243e5c1dc198958ce862e39d33efc798a47b339a
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Nov 10 21:35:11 2014 -0500
- dt-bindings: pci: xgene pcie device tree bindings
+ DO NOT UPSTREAM - arm64: fix dma_ops for ACPI and PCI devices
+
+ Commit 2189064795dc3fb4101e5:
- This patch adds the bindings for X-Gene PCIe driver. The driver resides
- under 'drivers/pci/host/pci-xgene.c' file.
+ arm64: Implement set_arch_dma_coherent_ops() to replace bus notifiers
- Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
+ removed the bus notifiers from dma-mapping.c. This patch
+ adds the notifier back for ACPI and PCI devices until a
+ better permanent solution is worked out.
+
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 1f8d894f2066d9db2b251d512f6f6f772ae7147f
-Author: Tanmay Inamdar <tinamdar@apm.com>
-Date: Wed Mar 19 16:12:40 2014 -0700
+commit 612eea3ae291b28f7ed50ccf50bd1685a2a7f753
+Author: Mark Salter <msalter@redhat.com>
+Date: Thu Aug 14 12:32:13 2014 -0400
- arm64: dts: APM X-Gene PCIe device tree nodes
+ 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 the device tree nodes for APM X-Gene PCIe controller and
- PCIe clock interface. Since X-Gene SOC supports maximum 5 ports, 5 dts
- nodes are added.
+ 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: Tanmay Inamdar <tinamdar@apm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit c0855fcf0cc9adcb1ba5e6b1318536c56244796d
-Author: Tanmay Inamdar <tinamdar@apm.com>
-Date: Wed Mar 19 16:12:39 2014 -0700
+commit 3d509a508c6fd70eb0fb2f0e82d08d92cc96568c
+Author: Mark Salter <msalter@redhat.com>
+Date: Sat Nov 22 12:08:53 2014 -0500
- pci: APM X-Gene PCIe controller driver
+ DO NOT UPSTREAM - arm64: kvm: Change vgic resource size error to info
- This patch adds the AppliedMicro X-Gene SOC PCIe controller driver.
- X-Gene PCIe controller supports maximum up to 8 lanes and GEN3 speed.
- X-Gene SOC supports maximum 5 PCIe ports.
+ From: Donald Dutile <ddutile@redhat.com>
- Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
+ A new check was added to upstream to ensure a full
+ kernel page was allocated to the vgic. The check failed
+ kvm configuration if the condition wasn't met. An arm64
+ kernel with 64K pagesize and certain early firmware will
+ fail this test. Change error to info & continue configuration
+ for now.
+
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 1cc0c322237d3b58b08fe39e79e6c2e2f90a8c98
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:44:00 2014 +0100
+commit 2b5dd4609e947b418afbbeae95da7f34594bc048
+Author: Wei Huang <wei@redhat.com>
+Date: Sat Nov 22 10:38:45 2014 -0500
- arm64: Add architectural support for PCI
+ KVM/ACPI: Enable ACPI support for KVM virt GIC
- Use the generic host bridge functions to provide support for
- PCI Express on arm64.
+ 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.
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
+ 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 <wei@redhat.com>
+ [combined with subsequent patch to use acpi_disabled]
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit aba1eca911a87959eb4be515110f7a6b8692e9a4
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:43:34 2014 +0100
+commit 756fc31666a4a3094727da5274fc0705a05f13a3
+Author: Wei Huang <wei@redhat.com>
+Date: Sat Nov 22 10:18:57 2014 -0500
- pci: Remap I/O bus resources into CPU space with pci_remap_iospace()
+ KVM/ACPI: Enable ACPI support for virt arch timer
- Introduce a default implementation for remapping PCI bus I/O resources
- onto the CPU address space. Architectures with special needs may
- provide their own version, but most should be able to use this one.
+ 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: Liviu Dudau <Liviu.Dudau@arm.com>
+ Signed-off-by: Wei Huang <wei@redhat.com>
+ [combined with subsequent patch to use acpi_disabled]
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit e1eacc3da10ca19eff1f88fb342a13586092b613
-Author: Liviu Dudau <liviu@dudau.co.uk>
-Date: Tue Jul 1 21:50:50 2014 +0100
+commit b189108603f6db4a11e0c30050e840e8bb36f098
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Tue Nov 18 21:52:34 2014 +0100
- pci: Add support for creating a generic host_bridge from device tree
+ arm, arm64: KVM: handle potential incoherency of readonly memslots
+
+ Upstream posting:
+ http://thread.gmane.org/gmane.comp.emulators.kvm.devel/129475/focus=129477
+
+ Readonly memslots are often used to implement emulation of ROMs and
+ NOR flashes, in which case the guest may legally map these regions as
+ uncached.
+ To deal with the incoherency associated with uncached guest mappings,
+ treat all readonly memslots as incoherent, and ensure that pages that
+ belong to regions tagged as such are flushed to DRAM before being passed
+ to the guest.
+
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+ Acadia backport notes:
- Several platforms use a rather generic version of parsing
- the device tree to find the host bridge ranges. Move the common code
- into the generic PCI code and use it to create a pci_host_bridge
- structure that can be used by arch code.
+ - we have a few more conflicts here. The main thing is that our
+ kvm_arch_prepare_memory_region() is "empty" at the moment; in upstream
+ Ard introduced performance related, host device related code there, in
+ commit 8eef91239.
- Based on early attempts by Andrew Murray to unify the code.
- Used powerpc and microblaze PCI code as starting point.
+ What we certainly need to grab from commit 8eef91239 is the acquiring of
+ "kvm->mmu_lock" (which is visible in the upstream patch context too),
+ and the filtering against
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
- Tested-by: Tanmay Inamdar <tinamdar@apm.com>
+ (change != KVM_MR_CREATE && change != KVM_MR_MOVE)
+
+ near the top of the function (which is not visible in the upstream patch
+ context). (If (change == KVM_MR_DELETE), then the caller has set up
+ "memslot" in such a way that calling stage2_flush_memslot() on it is
+ invalid, and it would actually crash the host -- speaking from
+ experience. :))
+
+ - The hunk that seems to matter in practice, in my testing on Mustang, is
+ the "fault_ipa_uncached" assignment one (which affects the the
+ demand-paged case, ie. the coherent_cache_guest_page() function,
+ modified in the previous patch).
+
+ The kvm_arch_prepare_memory_region() hunk exists for completeness of
+ implementation, and while it could certainly make a difference, I've
+ never seen it make one, in my testing. We should pick it up nonetheless.
+
+ Signed-off-by: Laszlo Ersek <lersek@redhat.com>
-commit aee55d507eb451223b51b52e6617b06b8e518ea6
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:43:32 2014 +0100
+commit 8ab19d68b49c2f6a9f0e6226c51bf9b2fe553022
+Author: Laszlo Ersek <lersek@redhat.com>
+Date: Tue Nov 18 21:52:33 2014 +0100
- pci: of: Parse and map the IRQ when adding the PCI device.
+ arm, arm64: KVM: allow forced dcache flush on page faults
- Enhance the default implementation of pcibios_add_device() to
- parse and map the IRQ of the device if a DT binding is available.
+ Upstream posting:
+ http://thread.gmane.org/gmane.comp.emulators.kvm.devel/129475/focus=129476
+
+ From: Laszlo Ersek <lersek@redhat.com>
+
+ To allow handling of incoherent memslots in a subsequent patch, this
+ patch adds a paramater 'ipa_uncached' to cache_coherent_guest_page()
+ so that we can instruct it to flush the page's contents to DRAM even
+ if the guest has caching globally enabled.
+
+ Signed-off-by: Laszlo Ersek <lersek@redhat.com>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
+ Acadia backport notes:
+ - minimal context conflict in user_mem_abort(): upstream passes
+
+ pgprot_val(mem_type) == pgprot_val(PAGE_S2_DEVICE)
+
+ as last parameter of stage2_set_pte(), while we do a direct comparison.
+
+ (See upstream commit 3d08c629, "arm: kvm: STRICT_MM_TYPECHECKS fix for
+ user_mem_abort".)
+
+ Signed-off-by: Laszlo Ersek <lersek@redhat.com>
-commit 0cf0470962f0498b598ff44e0c671407df54b22e
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:43:31 2014 +0100
+commit 1ac87393dff5d6fb10edfba84dfff89f57a7224a
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Tue Nov 18 21:52:32 2014 +0100
- pci: Introduce a domain number for pci_host_bridge.
+ kvm: add a memslot flag for incoherent memory regions
+
+ Upstream posting:
+ http://thread.gmane.org/gmane.comp.emulators.kvm.devel/129475
- Make it easier to discover the domain number of a bus by storing
- the number in pci_host_bridge for the root bus. Several architectures
- have their own way of storing this information, so it makes sense
- to try to unify the code. While at this, add a new function that
- creates a root bus in a given domain and make pci_create_root_bus()
- a wrapper around this function.
+ Memory regions may be incoherent with the caches, typically when the
+ guest has mapped a host system RAM backed memory region as uncached.
+ Add a flag KVM_MEMSLOT_INCOHERENT so that we can tag these memslots
+ and handle them appropriately when mapping them.
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
- Tested-by: Tanmay Inamdar <tinamdar@apm.com>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ Signed-off-by: Laszlo Ersek <lersek@redhat.com>
-commit 1bc8fcf01469c202b4aea5f1d0a3a75c9302f3e2
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:43:30 2014 +0100
+commit 2a0a5cbf98c94e2906d9a357a63fbbb153488e1c
+Author: Tom Lendacky <thomas.lendacky@amd.com>
+Date: Mon Sep 15 17:02:52 2014 -0600
- pci: Create pci_host_bridge before its associated bus in pci_create_root_bus.
+ amd-xgbe: AMD 10GbE driver APCI support for A0
- Before commit 7b5436635800 the pci_host_bridge was created before the root bus.
- As that commit has added a needless dependency on the bus for pci_alloc_host_bridge()
- the creation order has been changed for no good reason. 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.
+ This patch provides ACPI support for the AMD 10GbE device driver
+ and AMD 10GbE phy driver.
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
- Acked-by: Grant Likely <grant.likely@linaro.org>
- Tested-by: Tanmay Inamdar <tinamdar@apm.com>
+ Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
-commit 55353327169dc08c1047d994e00b8a38630f5a8d
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:43:29 2014 +0100
+commit 807e95abb96e7868e1c8e863a92298937a69d437
+Author: Mark Salter <msalter@redhat.com>
+Date: Tue Oct 7 12:54:08 2014 -0400
+
+ xgene acpi network - first cut
- pci: OF: Fix the conversion of IO ranges into IO resources.
+commit bdecd2af5d4234ed50042ab28a21736edcec6d41
+Author: Geert Uytterhoeven <geert+renesas@glider.be>
+Date: Thu Nov 6 12:23:23 2014 +0100
+
+ leds: leds-gpio: Fix legacy GPIO number case
+
+ In the legacy case, led_dat->gpiod is initialized correctly, but
+ overwritten later by template->gpiod, which is NULL, causing leds-gpio
+ to fail with:
- 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.
+ gpiod_direction_output: invalid GPIO
+ leds-gpio: probe of leds-gpio failed with error -22
- In the process move the function into drivers/of/address.c as it now
- depends on pci_address_to_pio() code and make it return an error message.
+ Move the initialization of led_dat->gpiod from template->gpiod up, and
+ always use led_dat->gpiod later, to fix this.
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
- Tested-by: Tanmay Inamdar <tinamdar@apm.com>
+ Fixes: 5c51277a9ababfa4 (leds: leds-gpio: Add support for GPIO descriptors)
+ Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+ Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-commit 34079a20796d5c74e2984c37a99baef4871709a6
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:43:28 2014 +0100
+commit 42b0d1b64cdf1c8d37e69ff7cff45852f7a16f65
+Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Date: Wed Nov 5 00:29:07 2014 +0100
- pci: Introduce pci_register_io_range() helper function.
-
- 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.
+ ACPI / property: Drop size_prop from acpi_dev_get_property_reference()
+
+ The size_prop argument of the recently added function
+ acpi_dev_get_property_reference() is not used by the only current
+ caller of that function and is very unlikely to be used at any time
+ going forward.
+
+ Namely, for a property whose value is a list of items each containing
+ a references to a device object possibly accompanied by some integers,
+ the number of items in the list can always be computed as the number
+ of elements of type ACPI_TYPE_LOCAL_REFERENCE in the property package.
+ Thus it should never be necessary to provide an additional "cells"
+ property with a value equal to the number of items in that list. It
+ also should never be necessary to provide a "cells" property specifying
+ how many integers are supposed to be following each reference.
+
+ For this reason, drop the size_prop argument from
+ acpi_dev_get_property_reference() and update its caller accordingly.
+
+ Link: http://marc.info/?l=linux-kernel&m=141511255610556&w=2
+ Suggested-by: Grant Likely <grant.likely@linaro.org>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit c3f29cda7420da6a721d40d116f369cfc1533d38
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Fri Oct 31 13:40:58 2014 +0200
+
+ leds: leds-gpio: Convert gpio_blink_set() to use GPIO descriptors
+
+ Commit 21f2aae91e902aad ("leds: leds-gpio: Add support for GPIO
+ descriptors") already converted most of the driver to use GPIO descriptors.
+ What is still missing is the platform specific hook gpio_blink_set() and
+ board files which pass legacy GPIO numbers to this driver in platform data.
+
+ In this patch we handle the former and convert gpio_blink_set() to take
+ GPIO descriptor instead. In order to do this we convert the existing four
+ users to accept GPIO descriptor and translate it to legacy GPIO number in
+ the platform code. This effectively "pushes" legacy GPIO number usage from
+ the driver to platforms.
+
+ Also add comment to the remaining block describing that it is legacy code
+ path and we are getting rid of it eventually.
+
+ Suggested-by: Linus Walleij <linus.walleij@linaro.org>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Andrew Lunn <andrew@lunn.ch>
+ Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+ Acked-by: Alexandre Courbot <acourbot@nvidia.com>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit 4117b39d39f59d2497ceac1091ec54aa3056cb4f
+Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Date: Mon Nov 3 23:39:57 2014 +0100
+
+ ACPI / GPIO: Document ACPI GPIO mappings API
- Introduce 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.
+ Document the previously introduced method that can be used by device
+ drivers to provide the GPIO subsystem with mappings between GPIO names
+ (connection IDs) and GpioIo()/GpioInt() resources in _CRS.
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-commit a81abc095ab4b9b90e446ddbd59247e23df9d4ad
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:43:27 2014 +0100
+commit d9345c86ad290bb4ca98b37520f94fc8075b2b94
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Mon Oct 27 12:15:14 2014 +0200
- pci: Export find_pci_host_bridge() function.
+ net: rfkill: gpio: Add default GPIO driver mappings for ACPI
+
+ The driver uses devm_gpiod_get_index(..., index) so that the index refers
+ directly to the GpioIo resource under the ACPI device. The problem with
+ this is that if the ordering changes we get wrong GPIOs.
+
+ With ACPI 5.1 _DSD we can now use names instead to reference GPIOs
+ analogous to Device Tree. However, we still have systems out there that do
+ not provide _DSD at all. These systems must be supported as well.
+
+ Luckily we now have acpi_dev_add_driver_gpios() that can be used to provide
+ mappings for systems where _DSD is not provided and still take advantage of
+ _DSD if it exists.
- This is a useful function and we should make it visible outside the
- generic PCI code. Export it as a GPL symbol.
+ This patch changes the driver to create default GPIO mappings if we are
+ running on ACPI system.
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
- Tested-by: Tanmay Inamdar <tinamdar@apm.com>
+ While there we can drop the indices completely and use devm_gpiod_get()
+ with name instead.
+
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
+ Acked-by: John W. Linville <linville@tuxdriver.com>
+ Acked-by: Linus Walleij <linus.walleij@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit 22cb8c44e198b7e3f3299324edbcaa1389016d52
+Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Date: Mon Nov 3 23:39:41 2014 +0100
-commit 78361698444e81bedbf30ec2b7aae1afd110d11f
-Author: Liviu Dudau <Liviu.Dudau@arm.com>
-Date: Tue Jul 1 19:43:26 2014 +0100
+ ACPI / GPIO: Driver GPIO mappings for ACPI GPIOs
+
+ Provide a way for device drivers using GPIOs described by ACPI
+ GpioIo resources in _CRS to tell the GPIO subsystem what names
+ (connection IDs) to associate with specific GPIO pins defined
+ in there.
+
+ To do that, a driver needs to define a mapping table as a
+ NULL-terminated array of struct acpi_gpio_mapping objects
+ that each contain a name, a pointer to an array of line data
+ (struct acpi_gpio_params) objects and the size of that array.
+
+ Each struct acpi_gpio_params object consists of three fields,
+ crs_entry_index, line_index, active_low, representing the index of
+ the target GpioIo()/GpioInt() resource in _CRS starting from zero,
+ the index of the target line in that resource starting from zero,
+ and the active-low flag for that line, respectively.
+
+ Next, the mapping table needs to be passed as the second
+ argument to acpi_dev_add_driver_gpios() that will register it with
+ the ACPI device object pointed to by its first argument. That
+ should be done in the driver's .probe() routine.
+
+ On removal, the driver should unregister its GPIO mapping table
+ by calling acpi_dev_remove_driver_gpios() on the ACPI device
+ object where that table was previously registered.
+
+ Included are fixes from Mika Westerberg.
+
+ Acked-by: Alexandre Courbot <acourbot@nvidia.com>
+ Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- Fix ioport_map() for !CONFIG_GENERIC_IOMAP cases.
+commit c70e2807a8bacbdfed992b58ca24eb152a778a01
+Author: Aaron Lu <aaron.lu@intel.com>
+Date: Tue Oct 21 13:34:00 2014 +0200
+
+ input: gpio_keys_polled: Make use of device property API
- The inline version of ioport_map() that gets used when !CONFIG_GENERIC_IOMAP
- 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.
+ Make use of device property API in this driver so that both OF based
+ system and ACPI based system can use this driver.
- Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
- Acked-by: Arnd Bergmann <arnd@arndb.de>
- Tested-by: Tanmay Inamdar <tinamdar@apm.com>
+ Signed-off-by: Aaron Lu <aaron.lu@intel.com>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-commit 5540bbe2eca72e37be2e6a1c18e2fc7e73f0eab6
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:50 2014 +0100
+commit 29257e751014d0d43f78bcfecd9a56a603096c95
+Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Date: Mon Oct 27 23:30:10 2014 +0100
- arm64: KVM: vgic: enable GICv2 emulation on top on GICv3 hardware
+ leds: leds-gpio: Make use of device property API
+
+ Make use of device property API in this driver so that both OF and ACPI
+ based system can use the same driver.
- Add the last missing bits that enable GICv2 emulation on top of
- GICv3 hardware.
+ This change contains material from Max Eliaser and Mika Westerberg.
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Bryan Wu <cooloney@gmail.com>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit 08ddbc9678ce8465f17acc8e1b1b67442593d1b5
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Tue Oct 21 13:33:59 2014 +0200
-commit f057aaf81a7df641bcaa992965a257e3260ad36e
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:49 2014 +0100
+ gpio: Support for unified device properties interface
+
+ Some drivers need to deal with only firmware representation of its
+ GPIOs. An example would be a GPIO button array driver where each button
+ is described as a separate firmware node in device tree. Typically these
+ child nodes do not have physical representation in the Linux device
+ model.
+
+ In order to help device drivers to handle such firmware child nodes we
+ add dev[m]_get_named_gpiod_from_child() that takes a child firmware
+ node pointer as its second argument (the first one is the parent device
+ itself), finds the GPIO using whatever is the underlying firmware
+ method, and requests the GPIO properly.
+
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Alexandre Courbot <acourbot@nvidia.com>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit 880614f83402ae8b408f33cb252505da0760f3e5
+Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Date: Tue Nov 4 14:03:59 2014 +0100
+
+ Driver core: Unified interface for firmware node properties
+
+ Add new generic routines are provided for retrieving properties from
+ device description objects in the platform firmware in case there are
+ no struct device objects for them (either those objects have not been
+ created yet or they do not exist at all).
+
+ The following functions are provided:
+
+ fwnode_property_present()
+ fwnode_property_read_u8()
+ fwnode_property_read_u16()
+ fwnode_property_read_u32()
+ fwnode_property_read_u64()
+ fwnode_property_read_string()
+ fwnode_property_read_u8_array()
+ fwnode_property_read_u16_array()
+ fwnode_property_read_u32_array()
+ fwnode_property_read_u64_array()
+ fwnode_property_read_string_array()
+
+ in analogy with the corresponding functions for struct device added
+ previously. For all of them, the first argument is a pointer to struct
+ fwnode_handle (new type) that allows a device description object
+ (depending on what platform firmware interface is in use) to be
+ obtained.
+
+ Add a new macro device_for_each_child_node() for iterating over the
+ children of the device description object associated with a given
+ device and a new function device_get_child_node_count() returning the
+ number of a given device's child nodes.
+
+ The interface covers both ACPI and Device Trees.
+
+ Suggested-by: Grant Likely <grant.likely@linaro.org>
+ Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- arm64: KVM: vgic: add GICv3 world switch
+commit b5923f9dc379c1861a70d8836c7d9976d9521390
+Author: Aaron Lu <aaron.lu@intel.com>
+Date: Tue Oct 21 23:30:25 2014 +0200
+
+ input: gpio_keys_polled: Add support for GPIO descriptors
+
+ GPIO descriptors are the preferred way over legacy GPIO numbers
+ nowadays. Convert the driver to use GPIO descriptors internally but
+ still allow passing legacy GPIO numbers from platform data to support
+ existing platforms.
+
+ Signed-off-by: Aaron Lu <aaron.lu@intel.com>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Alexandre Courbot <acourbot@nvidia.com>
+ Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+ Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit 5c3c4fe36a05672113646f8fb839e4c91256ef5d
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Mon Oct 27 23:29:32 2014 +0100
+
+ leds: leds-gpio: Add support for GPIO descriptors
- Introduce the GICv3 world switch code used to save/restore the
- GICv3 context.
+ GPIO descriptors are the preferred way over legacy GPIO numbers
+ nowadays. Convert the driver to use GPIO descriptors internally but
+ still allow passing legacy GPIO numbers from platform data to support
+ existing platforms.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Alexandre Courbot <acourbot@nvidia.com>
+ Acked-by: Bryan Wu <cooloney@gmail.com>
+ Acked-by: Arnd Bergmann <arnd@arndb.de>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-commit 7f1b8a791bb375933fdc8420cd08f127d07dd259
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:48 2014 +0100
+commit 8105c03352f32060c765837cbb7d619e075289d9
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Tue Oct 21 13:33:56 2014 +0200
- KVM: ARM: vgic: add the GICv3 backend
+ gpio: sch: Consolidate core and resume banks
- Introduce the support code for emulating a GICv2 on top of GICv3
- hardware.
+ This is actually a single device with two sets of identical registers,
+ which just happen to start from a different offset. Instead of having
+ separate GPIO chips created we consolidate them to be single GPIO chip.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ In addition having a single GPIO chip allows us to handle ACPI GPIO
+ translation in the core in a more generic way, since the two GPIO chips
+ share the same parent ACPI device.
+
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Linus Walleij <linus.walleij@linaro.org>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit ce0e2672808ce2805d0aadfd12d94e2dd6be5ab9
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Wed Oct 29 15:41:01 2014 +0100
+
+ gpio / ACPI: Add support for _DSD device properties
+
+ With release of ACPI 5.1 and _DSD method we can finally name GPIOs (and
+ other things as well) returned by _CRS. Previously we were only able to
+ use integer index to find the corresponding GPIO, which is pretty error
+ prone if the order changes.
+
+ With _DSD we can now query GPIOs using name instead of an integer index,
+ like the below example shows:
+
+ // Bluetooth device with reset and shutdown GPIOs
+ Device (BTH)
+ {
+ Name (_HID, ...)
+
+ Name (_CRS, ResourceTemplate ()
+ {
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.GPO0", 0, ResourceConsumer) {15}
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
+ })
+
+ Name (_DSD, Package ()
+ {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
+ Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
+ }
+ })
+ }
+
+ The format of the supported GPIO property is:
+
+ Package () { "name", Package () { ref, index, pin, active_low }}
+
+ ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
+ typically this is the device itself (BTH in our case).
+ index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
+ pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
+ active_low - If 1 the GPIO is marked as active_low.
+
+ Since ACPI GpioIo() resource does not have field saying whether it is
+ active low or high, the "active_low" argument can be used here. Setting
+ it to 1 marks the GPIO as active low.
+
+ In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
+ resource, second pin in that resource with the GPIO number of 31.
+
+ This patch implements necessary support to gpiolib for extracting GPIOs
+ using _DSD device properties.
+
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Linus Walleij <linus.walleij@linaro.org>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-commit 74428905c3b450eab53a21bee74236501629a443
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:47 2014 +0100
+commit e072a051ef3a5d612949dc22ca71e40dbe978ed1
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Tue Oct 21 13:33:56 2014 +0200
- arm64: KVM: move HCR_EL2.{IMO, FMO} manipulation into the vgic switch code
+ misc: at25: Make use of device property API
- GICv3 requires the IMO and FMO bits to be tightly coupled with some
- of the interrupt controller's register switch.
+ Make use of device property API in this driver so that both DT and ACPI
+ based systems can use this driver.
- In order to have similar code paths, move the manipulation of these
- bits to the GICv2 switch code.
+ In addition we hard-code the name of the chip to be "at25" for the
+ reason that there is no common mechanism to fetch name of the firmware
+ node. The only existing user (arch/arm/boot/dts/phy3250.dts) uses the
+ same name so it should continue to work.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-commit b691c1f97f1fb5b29c3ae4cc836fdbefe61a11ff
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:46 2014 +0100
+commit e176d66bf1a8e613e501dae1fc6798e1a42b7062
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Tue Oct 21 13:33:56 2014 +0200
- arm64: KVM: split GICv2 world switch from hyp code
+ ACPI: Allow drivers to match using Device Tree compatible property
- Move the GICv2 world switch code into its own file, and add the
- necessary indirection to the arm64 switch code.
+ We have lots of existing Device Tree enabled drivers and allocating
+ separate _HID for each is not feasible. Instead we allocate special _HID
+ "PRP0001" that means that the match should be done using Device Tree
+ compatible property using driver's .of_match_table instead if the driver
+ is missing .acpi_match_table.
- Also introduce a new type field to the vgic_params structure.
+ If there is a need to distinguish from where the device is enumerated
+ (DT/ACPI) driver can check dev->of_node or ACPI_COMPATION(dev).
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+commit e30b98eab5645fa42d372cc1be44e22db5f5e9b8
+Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Date: Tue Nov 4 01:28:56 2014 +0100
-commit d3f4563f1bebed7f60f714bdab640e477a081c4b
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:45 2014 +0100
+ Driver core: Unified device properties interface for platform firmware
+
+ Add a uniform interface by which device drivers can request device
+ properties from the platform firmware by providing a property name
+ and the corresponding data type. The purpose of it is to help to
+ write portable code that won't depend on any particular platform
+ firmware interface.
+
+ The following general helper functions are added:
+
+ device_property_present()
+ device_property_read_u8()
+ device_property_read_u16()
+ device_property_read_u32()
+ device_property_read_u64()
+ device_property_read_string()
+ device_property_read_u8_array()
+ device_property_read_u16_array()
+ device_property_read_u32_array()
+ device_property_read_u64_array()
+ device_property_read_string_array()
+
+ The first one allows the caller to check if the given property is
+ present. The next 5 of them allow single-valued properties of
+ various types to be retrieved in a uniform way. The remaining 5 are
+ for reading properties with multiple values (arrays of either numbers
+ or strings).
+
+ The interface covers both ACPI and Device Trees.
+
+ This change set includes material from Mika Westerberg and Aaron Lu.
+
+ Signed-off-by: Aaron Lu <aaron.lu@intel.com>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- arm64: KVM: remove __kvm_hyp_code_{start, end} from hyp.S
+commit a8762c178234b62dce5e55df8de8528857a47bb7
+Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Tue Oct 21 13:33:55 2014 +0200
+
+ ACPI: Add support for device specific properties
+
+ Device Tree is used in many embedded systems to describe the system
+ configuration to the OS. It supports attaching properties or name-value
+ pairs to the devices it describe. With these properties one can pass
+ additional information to the drivers that would not be available
+ otherwise.
+
+ ACPI is another configuration mechanism (among other things) typically
+ seen, but not limited to, x86 machines. ACPI allows passing arbitrary
+ data from methods but there has not been mechanism equivalent to Device
+ Tree until the introduction of _DSD in the recent publication of the
+ ACPI 5.1 specification.
+
+ In order to facilitate ACPI usage in systems where Device Tree is
+ typically used, it would be beneficial to standardize a way to retrieve
+ Device Tree style properties from ACPI devices, which is what we do in
+ this patch.
+
+ If a given device described in ACPI namespace wants to export properties it
+ must implement _DSD method (Device Specific Data, introduced with ACPI 5.1)
+ that returns the properties in a package of packages. For example:
+
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"name1", <VALUE1>},
+ Package () {"name2", <VALUE2>},
+ ...
+ }
+ })
- We already have __hyp_text_{start,end} to express the boundaries
- of the HYP text section, and __kvm_hyp_code_{start,end} are getting
- in the way of a more modular world switch code.
+ The UUID reserved for properties is daffd814-6eba-4d8c-8a91-bc9bbf4aa301
+ and is documented in the ACPI 5.1 companion document called "_DSD
+ Implementation Guide" [1], [2].
- Just turn __kvm_hyp_code_{start,end} into #defines mapping the
- linker-emited symbols.
+ We add several helper functions that can be used to extract these
+ properties and convert them to different Linux data types.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ The ultimate goal is that we only have one device property API that
+ retrieves the requested properties from Device Tree or from ACPI
+ transparent to the caller.
+
+ [1] http://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-toplevel.htm
+ [2] http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+
+ Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
+ Reviewed-by: Josh Triplett <josh@joshtriplett.org>
+ Reviewed-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Darren Hart <dvhart@linux.intel.com>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-commit 8ede261e09ad25ab8229d5efb476d5b4f6dc6434
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:44 2014 +0100
+commit a9240791b83abd372e4efb77f20444c27a56ebae
+Author: Mark Salter <msalter@redhat.com>
+Date: Tue Sep 30 17:19:24 2014 -0400
- KVM: ARM: vgic: revisit implementation of irqchip_in_kernel
+ arm64: avoid need for console= to enable serial console
- So far, irqchip_in_kernel() was implemented by testing the value of
- vctrl_base, which worked fine with GICv2.
+ 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. This is just a hack to
+ get the behavior we want from SPCR table support. Once SPCR
+ is supported, we can drop this.
- With GICv3, this field is useless, as we're using system registers
- instead of a emmory mapped interface. To solve this, add a boolean
- flag indicating if the we're using a vgic or not.
+ Signed-off-by: Mark Salter <msalter@redhat.com>
+
+commit 6fee3b2bd2ad6349e7bb3082393bf6355e01ce6f
+Author: Tom Lendacky <thomas.lendacky@amd.com>
+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.
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit ff7faf70feb47e5f1cf1e0f0d02e0f2807da11f5
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:43 2014 +0100
+commit 0a0eea6d358d51ab381e2945c0e9db2f6cc06157
+Author: Tom Lendacky <thomas.lendacky@amd.com>
+Date: Tue Sep 9 23:34:07 2014 -0400
- KVM: ARM: vgic: split GICv2 backend from the main vgic code
+ drivers: net: AMD Seattle XGBE 10GbE support for A0 silicon
- Brutally hack the innocent vgic code, and move the GICv2 specific code
- to its own file, using vgic_ops and vgic_params as a way to pass
- information between the two blocks.
+ 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.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 63480283c0e1dc92f506e5e5306be0ac9b239499
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:42 2014 +0100
+commit ff93b53f3ca8748529855d421bf79329086544cd
+Author: Graeme Gregory <graeme.gregory@linaro.org>
+Date: Fri Jul 26 17:55:02 2013 +0100
- KVM: ARM: introduce vgic_params structure
+ virtio-mmio: add ACPI probing
- Move all the data specific to a given GIC implementation into its own
- little structure.
+ Added the match table and pointers for ACPI probing to the driver.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
-commit dcb20f9b66d5615a3e7e492424fa7953c1fe9f01
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:41 2014 +0100
+commit 5315cb5a532e900612ac1202507551761e8bd13c
+Author: Graeme Gregory <graeme.gregory@linaro.org>
+Date: Wed Jul 24 11:29:48 2013 +0100
- KVM: ARM: vgic: introduce vgic_enable
+ net: smc91x: add ACPI probing support.
- Move the code dealing with enabling the VGIC on to vgic_ops.
+ Add device ID LINA0003 for this device and add the match table.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ 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 <graeme.gregory@linaro.org>
-commit 67e3bcf8dd823eec79c74bc993fa62fb08b1acea
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:40 2014 +0100
+commit 640f607f1fa10c7c0cd6025dde8883d02fc9b411
+Author: Mark Salter <msalter@redhat.com>
+Date: Sun Sep 14 09:44:44 2014 -0400
- KVM: ARM: vgic: abstract VMCR access
+ Revert "ahci_xgene: Skip the PHY and clock initialization if already configured by the firmware."
- Instead of directly messing with with the GICH_VMCR bits for the CPU
- interface save/restore code, add accessors that encode/decode the
- entire set of registers exposed by VMCR.
+ This reverts commit 0bed13bebd6c99d097796d2ca6c4f10fb5b2eabc.
- Not the most efficient thing, but given that this code is only used
- by the save/restore code, performance is far from being critical.
+ Temporarily revert for backwards compatibility with rh-0.12-1 firmware
+
+commit e8afbea7e3e11f37c234770d72725894f92de415
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Aug 11 13:46:43 2014 -0400
+
+ xgene: add support for ACPI-probed serial port
+
+commit 3d0ad3e452a81a32842d85dbb88078b74582efb5
+Author: Mark Salter <msalter@redhat.com>
+Date: Sat Aug 9 12:01:20 2014 -0400
+
+ sata/xgene: support acpi probing
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 67caf34f138a4f2516a2afcd5657add2eaaf0ab4
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:39 2014 +0100
+commit a42353df5a2f741e8d2e356c3f053aac8d3eff0e
+Author: Mark Salter <msalter@redhat.com>
+Date: Thu Sep 18 15:05:23 2014 -0400
- KVM: ARM: vgic: move underflow handling to vgic_ops
+ arm64: add sev to parking protocol
- Move the code dealing with LR underflow handling to its own functions,
- and make them accessible through vgic_ops.
+ 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.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 30acb0a340d388135ae89bed7e248bad203ec876
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:38 2014 +0100
+commit d81f088880b9d763a7006e40dff6bb526c534255
+Author: Mark Salter <msalter@redhat.com>
+Date: Tue Sep 9 22:59:48 2014 -0400
- KVM: ARM: vgic: abstract MISR decoding
+ arm64: add parking protocol support
- Instead of directly dealing with the GICH_MISR bits, move the code to
- its own function and use a couple of public flags to represent the
- actual state.
+ 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.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ caveat utilitor
+
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 464cbe47011e07b654d161ab4d4bdd05b4d025b3
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:37 2014 +0100
+commit 475b6ce1555e1146761b53c550f2ac019311739f
+Author: Hanjun Guo <hanjun.guo@linaro.org>
+Date: Thu Aug 28 14:26:16 2014 -0400
- KVM: ARM: vgic: abstract EISR bitmap access
+ ARM64 / ACPI: Introduce some PCI functions when PCI is enabled
- Move the GICH_EISR access to its own function.
+ Introduce some PCI functions to make ACPI can be compiled when
+ CONFIG_PCI is enabled, these functions should be revisited when
+ implemented on ARM64.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
+ [fixed up for 3.17-rc]
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 33930dc5f401e9fc2268c2f128853eb5275e7ab1
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:36 2014 +0100
+commit cb6ebe40936adc5c3154abbec6f89ccb8a0536b7
+Author: Al Stone <ahs3@redhat.com>
+Date: Thu Aug 28 13:14:16 2014 -0400
- KVM: ARM: vgic: abstract access to the ELRSR bitmap
+ Fix arm64 compilation error in PNP code
- Move the GICH_ELRSR access to its own functions, and add them to
- the vgic_ops structure.
+ Signed-off-by: Mark Salter <msalter@redhat.com>
+
+commit b7fc0378e13207a53a3e8466ba6329cfbcaa0526
+Author: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
+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 <Suravee.Suthikulpanit@amd.com>
+
+commit c5b655e6af273a61e7ec3653deb3550ae4f7abf1
+Author: Mark Salter <msalter@redhat.com>
+Date: Wed Nov 19 10:08:29 2014 -0500
+
+ tty/sbsauart: make ttySBSA the active console device
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.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.
+
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 0dca962ccd5b96fb7174880c1bc25085dcc09927
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:35 2014 +0100
+commit 6bee52af3d281d91b871f6876138fa51a41f0472
+Author: Graeme Gregory <graeme.gregory@linaro.org>
+Date: Wed Aug 13 13:47:18 2014 +0100
- KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
+ 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).
- In order to split the various register manipulation from the main vgic
- code, introduce a vgic_ops structure, and start by abstracting the
- LR manipulation code with a couple of accessors.
+ It is specified in the Server Base System Architecture document from
+ ARM.
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
-commit e66aa6cbdaa25764c58ba8d21da8d1b7d75e7570
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:34 2014 +0100
+commit a66f13e7c17cf7283b9987da2349c0a5c204fa4b
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Sep 8 11:58:46 2014 -0400
- KVM: arm/arm64: vgic: move GICv2 registers to their own structure
+ acpi: fix acpi_os_ioremap for arm64
- In order to make way for the GICv3 registers, move the v2-specific
- registers to their own structure.
+ 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.
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit b04259737c6bb38592c02c93e939fd53909dad04
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:33 2014 +0100
+commit b00f36975b651c0afbddee49e84109694e610f43
+Author: Graeme Gregory <graeme.gregory@linaro.org>
+Date: Mon Sep 8 10:36:44 2014 -0400
- arm64: boot protocol documentation update for GICv3
+ acpi: add arm to the platforms that use ioremap
- Linux has some requirements that must be satisfied in order to boot
- on a system built with a GICv3.
+ Now with the base changes to the arm memory mapping it is safe
+ to convert to using ioremap to map in the tables.
- Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Al Stone <al.stone@linaro.org>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
-commit a864693311bd4305214d966b7ca0e0015216c2c4
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:32 2014 +0100
+commit 4f6ca522fc13d8c13c844a2c2f9eafe091a336a9
+Author: Mark Salter <msalter@redhat.com>
+Date: Mon Sep 8 17:04:28 2014 -0400
- arm64: GICv3 device tree binding documentation
+ acpi/arm64: NOT FOR UPSTREAM - remove EXPERT dependency
- Add the necessary documentation to support GICv3.
+ For convenience to keep existing configs working, remove
+ CONFIG_EXPERT dependency from ACPI for ARM64. This shouldn't
+ go upstream just yet.
- Cc: Thomas Gleixner <tglx@linutronix.de>
- Cc: Mark Rutland <mark.rutland@arm.com>
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Acked-by: Rob Herring <robh@kernel.org>
- Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-
-commit af3035d3ddddb6e19bac9295f0c785bb2c8e718c
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:31 2014 +0100
-
- irqchip: arm64: Initial support for GICv3
-
- The Generic Interrupt Controller (version 3) offers services that are
- similar to GICv2, with a number of additional features:
- - Affinity routing based on the CPU MPIDR (ARE)
- - System register for the CPU interfaces (SRE)
- - Support for more that 8 CPUs
- - Locality-specific Peripheral Interrupts (LPIs)
- - Interrupt Translation Services (ITS)
-
- This patch adds preliminary support for GICv3 with ARE and SRE,
- non-secure mode only. It relies on higher exception levels to grant ARE
- and SRE access.
-
- Support for LPI and ITS will be added at a later time.
-
- Cc: Thomas Gleixner <tglx@linutronix.de>
- Cc: Jason Cooper <jason@lakedaemon.net>
- Reviewed-by: Zi Shen Lim <zlim@broadcom.com>
- Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
- Reviewed-by: Tirumalesh Chalamarla <tchalamarla@cavium.com>
- Reviewed-by: Yun Wu <wuyun.wu@huawei.com>
- Reviewed-by: Zhen Lei <thunder.leizhen@huawei.com>
- Tested-by: Tirumalesh Chalamarla<tchalamarla@cavium.com>
- Tested-by: Radha Mohan Chintakuntla <rchintakuntla@cavium.com>
- Acked-by: Radha Mohan Chintakuntla <rchintakuntla@cavium.com>
- Acked-by: Catalin Marinas <catalin.marinas@arm.com>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Mark Salter <msalter@redhat.com>
-commit c50b02761c3ad5d37ce8fffe7c0bf6b46d23109e
-Author: Marc Zyngier <marc.zyngier@arm.com>
-Date: Mon Jun 30 16:01:30 2014 +0100
+commit 91eaa3c5387ebcf698b070a4c21e39e5240699ba
+Author: Graeme Gregory <graeme.gregory@linaro.org>
+Date: Fri Oct 17 21:37:14 2014 +0800
- irqchip: ARM: GIC: Move some bits of GICv2 to a library-type file
+ Documentation: ACPI for ARM64
- A few GICv2 low-level function are actually very useful to GICv3,
- and it makes some sense to share them across the two drivers.
- They end-up in their own file, with an additional parameter used
- to ensure an optional synchronization (unused on GICv2).
+ Add documentation for the guidelines of how to use ACPI
+ on ARM64.
- Cc: Thomas Gleixner <tglx@linutronix.de>
- Cc: Jason Cooper <jason@lakedaemon.net>
- Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
- Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
+ Signed-off-by: Al Stone <al.stone@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 6a6033cdcbf6022c2848e2181ed6d8b7545af02e
-Author: Mark Salter <msalter@redhat.com>
-Date: Tue Jun 24 23:16:45 2014 -0400
+commit ef17919599275fd58edb255ecf69807653cdd763
+Author: Graeme Gregory <graeme.gregory@linaro.org>
+Date: Fri Oct 17 21:37:13 2014 +0800
- perf: fix arm64 build error
+ ARM64 / ACPI: Enable ARM64 in Kconfig
- I'm seeing the following build error on arm64:
+ Add Kconfigs to build ACPI on ARM64, and make ACPI available 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];
- ^
+ 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.
- This patch adds a PEFF_REGS_MAX definition for arm64.
+ Reviewed-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
+ Signed-off-by: Al Stone <al.stone@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
+
+commit 7d78ff059af78cc5a80576314c38584834557fc1
+Author: Al Stone <al.stone@linaro.org>
+Date: Fri Oct 17 21:37:12 2014 +0800
+
+ ARM64 / ACPI: Select ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64
- Signed-off-by: Mark Salter <msalter@redhat.com>
+ 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 <grant.likely@linaro.org>
+ Signed-off-by: Al Stone <al.stone@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 1de8987fa549d421576c1b61282c4041c8c78a5f
-Author: Mark Salter <msalter@redhat.com>
-Date: Tue Jun 24 09:50:28 2014 -0400
+commit 8a387ea5071c9d8bdaf5305320130022ec1d4f7d
+Author: Hanjun Guo <hanjun.guo@linaro.org>
+Date: Fri Oct 17 21:37:11 2014 +0800
- arm64: use EFI as last resort for reboot and poweroff
+ ARM64 / ACPI: Parse GTDT to initialize arch timer
- 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.
+ Using the information presented by GTDT to initialize the arch
+ timer (not memory-mapped).
- Signed-off-by: Mark Salter <msalter@redhat.com>
+ Originally-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 1c973051e86625be7ffb3db90d4a70b9ca4199c6
-Author: Matt Fleming <matt.fleming@intel.com>
-Date: Fri Jun 13 12:39:55 2014 +0100
+commit 7523c8b3b0d23629781c4581272c0647fa543af5
+Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+Date: Fri Oct 17 21:37:10 2014 +0800
- x86/reboot: Add EFI reboot quirk for ACPI Hardware Reduced flag
+ ARM64 / ACPI: Add GICv2 specific ACPI boot support
- It appears that the BayTrail-T class of hardware requires EFI in order
- to powerdown and reboot and no other reliable method exists.
+ 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.
- This quirk is generally applicable to all hardware that has the ACPI
- Hardware Reduced bit set, since usually ACPI would be the preferred
- method.
+ NOTE: This commit allow to initialize GICv1/2 basic functionality.
+ GICv2 vitalization extension, GICv3/4 and ITS are considered as next
+ steps.
- Cc: Len Brown <len.brown@intel.com>
- Cc: Mark Salter <msalter@redhat.com>
- Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
- Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+ Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 621b2a0f1df86bd2f147799303b94575f3acee95
-Author: Matt Fleming <matt.fleming@intel.com>
-Date: Fri Jun 13 12:35:21 2014 +0100
+commit 743691994f2fb03bc05f539a42ba6ccccb5d18b8
+Author: Hanjun Guo <hanjun.guo@linaro.org>
+Date: Fri Oct 17 21:37:09 2014 +0800
- efi/reboot: Allow powering off machines using EFI
+ ARM64 / ACPI: Introduce ACPI_IRQ_MODEL_GIC and register device's gsi
- Not only can EfiResetSystem() be used to reboot, it can also be used to
- power down machines.
+ 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.
- By and large, this functionality doesn't work very well across the range
- of EFI machines in the wild, so it should definitely only be used as a
- last resort. In an ideal world, this wouldn't be needed at all.
+ 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.
- Unfortunately, we're starting to see machines where EFI is the *only*
- reliable way to power down, and nothing else, not PCI, not ACPI, works.
+ Originally-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
+
+commit 0c4d9983cb7b50351aad0aa32e8b6134adaabb0d
+Author: Hanjun Guo <hanjun.guo@linaro.org>
+Date: Fri Oct 17 21:37:08 2014 +0800
+
+ ACPI / processor: Make it possible to get CPU hardware ID via GICC
- efi_poweroff_required() should be implemented on a per-architecture
- basis, since exactly when we should be using EFI runtime services is a
- platform-specific decision. There's no analogue for reboot because each
- architecture handles reboot very differently - the x86 code in
- particular is pretty complex.
+ Introduce a new function map_gicc_mpidr() to allow MPIDRs to be obtained
+ from the GICC Structure introduced by ACPI 5.1.
- Patches to enable this for specific classes of hardware will be
- submitted separately.
+ 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.
- Cc: Mark Salter <msalter@redhat.com>
- Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 6b2e219b20933cad5d5ba34f7af4efc5317c0fb9
-Author: Matt Fleming <matt.fleming@intel.com>
-Date: Fri Jun 13 12:22:22 2014 +0100
+commit cb6b980abe388e25e357f73c5780aa1cf1b2e337
+Author: Hanjun Guo <hanjun.guo@linaro.org>
+Date: Fri Oct 17 21:37:07 2014 +0800
- efi/reboot: Add generic wrapper around EfiResetSystem()
+ ARM64 / ACPI: Parse MADT for SMP initialization
- Implement efi_reboot(), which is really just a wrapper around the
- EfiResetSystem() EFI runtime service, but it does at least allow us to
- funnel all callers through a single location.
+ 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.
- It also simplifies the callsites since users no longer need to check to
- see whether EFI_RUNTIME_SERVICES are enabled.
+ 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.
- Cc: Tony Luck <tony.luck@intel.com>
- Cc: Mark Salter <msalter@redhat.com>
- Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
+ Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
-commit d0d41b99122d97f81ad05868dff38ccf0a3ffd33
-Author: Saurabh Tangri <saurabh.tangri@intel.com>
-Date: Mon Jun 2 05:18:35 2014 -0700
+commit 74a72e003ae388f460294a0910a536aced8ce93c
+Author: Hanjun Guo <hanjun.guo@linaro.org>
+Date: Fri Oct 17 21:37:06 2014 +0800
- x86/efi: Move all workarounds to a separate file quirks.c
+ ACPI / table: Print GIC information when MADT is parsed
+
+ When MADT is parsed, print GIC information to make the boot
+ log look pretty:
- Currently, it's difficult to find all the workarounds that are
- applied when running on EFI, because they're littered throughout
- various code paths. This change moves all of them into a separate
- file with the hope that it will be come the single location for all
- our well documented quirks.
+ ACPI: GICC (acpi_id[0x0000] address[00000000e112f000] MPDIR[0x0] enabled)
+ ACPI: GICC (acpi_id[0x0001] address[00000000e112f000] MPDIR[0x1] enabled)
+ ...
+ ACPI: GICC (acpi_id[0x0201] address[00000000e112f000] MPDIR[0x201] enabled)
- Signed-off-by: Saurabh Tangri <saurabh.tangri@intel.com>
- Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+ These information will be very helpful to bring up early systems to
+ see if acpi_id and MPIDR are matched or not as spec defined.
+
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
+ Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+
+commit 059facbd0f0664aaaf6d732ce02b2f56ea6ad98f
+Author: Hanjun Guo <hanjun.guo@linaro.org>
+Date: Fri Oct 17 21:37:05 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 <hanjun.guo@linaro.org>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
+ Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
-commit b5e3a1e8825abb0406ead0e85436df4df20ddcdb
-Author: Don Dutile <ddutile@redhat.com>
-Date: Tue Mar 25 20:22:26 2014 -0400
+commit 7ec63267bb1630c62e5f7fd2eb75a9a31131c89a
+Author: Hanjun Guo <hanjun.guo@linaro.org>
+Date: Fri Oct 17 21:37:04 2014 +0800
- pmu: Adding support for Xgene PMUs
+ ARM64 / ACPI: Make PCI optional for ACPI on ARM64
- Message-id: <1395778948-47814-2-git-send-email-ddutile@redhat.com>
- Patchwork-id: 78602
- O-Subject: [PATCH 1/3] pmu: Adding support for Xgene PMUs
- Bugzilla: 1079110
+ 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.
- Backport of these two posted (but not upstream) patches.
- Combined into single patch due to gic-patch dependency.
+ 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: Donald Dutile <ddutile@redhat.com>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 9f4c27693bb120a3134e3e7e8d452fb02d023e2b
-Author: Mark Salter <msalter@redhat.com>
-Date: Sun Jun 15 09:06:55 2014 -0400
+commit 2f1dd91e7866f2b617af29e9973b88b2cc2e00d6
+Author: Graeme Gregory <graeme.gregory@linaro.org>
+Date: Fri Oct 17 21:37:03 2014 +0800
- arm64: fix up APM Mustang devicetree
+ ARM64 / ACPI: If we chose to boot from acpi then disable FDT
- These are changes needed when loading device tree blob built with
- kernel. i.e. with grub. These are not needed when using devicetree
- from Tianocore which will be fixed up at tianocore runtime.
+ If the early boot methods of acpi are happy that we have valid ACPI
+ tables and acpi=force has been passed, then do not unflat devicetree
+ effectively disabling further hardware probing from DT.
- Signed-off-by: Mark Salter <msalter@redhat.com>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 1f3a5b228be88be3f734d7a43db3b3f81e160443
-Author: Iyappan Subramanian <isubramanian@apm.com>
-Date: Mon Jul 14 15:18:05 2014 -0700
+commit 6941a3cced9ca3d29e6e9c8b0f43917526b74789
+Author: Al Stone <al.stone@linaro.org>
+Date: Fri Oct 17 21:37:02 2014 +0800
- drivers: net: Add APM X-Gene SoC ethernet driver support.
+ ARM64 / ACPI: Introduce early_param for "acpi" and pass acpi=force to enable ACPI
+
+ Introduce one early parameters "off" and "force" for "acpi", acpi=off
+ will be the default behavior for ARM64, so introduce acpi=force to
+ enable ACPI on ARM64.
- This patch adds network driver for APM X-Gene SoC ethernet.
+ Disable ACPI before early parameters parsed, and enable it to pass
+ "acpi=force" if people want use ACPI on ARM64. This ensures DT be
+ the prefer one if ACPI table and DT both are provided at this moment.
- Signed-off-by: Iyappan Subramanian <isubramanian@apm.com>
- Signed-off-by: Ravi Patel <rapatel@apm.com>
- Signed-off-by: Keyur Chudgar <kchudgar@apm.com>
+ Signed-off-by: Al Stone <al.stone@linaro.org>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 54b3fe04c4a953eeb6907ffe9f57aae282f59457
-Author: Iyappan Subramanian <isubramanian@apm.com>
-Date: Mon Jul 14 15:18:04 2014 -0700
+commit 8764d6bd07827a2a29eaaa382fc397527ad1ba19
+Author: Graeme Gregory <graeme.gregory@linaro.org>
+Date: Fri Oct 17 21:37:01 2014 +0800
- dts: Add bindings for APM X-Gene SoC ethernet driver
+ ARM64 / ACPI: Introduce sleep-arm.c
- This patch adds bindings for APM X-Gene SoC ethernet driver.
+ 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: Iyappan Subramanian <isubramanian@apm.com>
- Signed-off-by: Ravi Patel <rapatel@apm.com>
- Signed-off-by: Keyur Chudgar <kchudgar@apm.com>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
+ Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
+
+commit 37144fd61ca68e9d542e875187739c982c8d3662
+Author: Al Stone <al.stone@linaro.org>
+Date: Fri Oct 17 21:37:00 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 <al.stone@linaro.org>
+ Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
+ Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 85125c4e1c1b1ef53d6cb77966efa89062540f43
-Author: Iyappan Subramanian <isubramanian@apm.com>
-Date: Mon Jul 14 15:18:03 2014 -0700
+commit a4f035d2876b41b6f224321da6b6278de577d4c5
+Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+Date: Fri Oct 17 21:36:59 2014 +0800
- Documentation: dts: Add bindings for APM X-Gene SoC ethernet driver
+ ACPI / table: Count matched and successfully parsed entries without specifying max entries
- This patch adds documentation for APM X-Gene SoC ethernet DTS binding.
+ 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.
- Signed-off-by: Iyappan Subramanian <isubramanian@apm.com>
- Signed-off-by: Ravi Patel <rapatel@apm.com>
- Signed-off-by: Keyur Chudgar <kchudgar@apm.com>
+ NOTE: This change has no impact to x86 and ia64 archs since existing code
+ checks for error occurrence only (acpi_parse_entries(...,0) < 0).
+
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit fe8ec437eedc45384c23e1e12a09baa82d24fa16
-Author: Iyappan Subramanian <isubramanian@apm.com>
-Date: Mon Jul 14 15:18:02 2014 -0700
+commit b3055f38d52f5be0103b436a1b04fbf3947aaa39
+Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
+Date: Fri Oct 17 21:36:58 2014 +0800
- MAINTAINERS: Add entry for APM X-Gene SoC ethernet driver
+ ACPI / table: Add new function to get table entries
- This patch adds a MAINTAINERS entry for APM X-Gene SoC
- ethernet driver.
+ 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: Iyappan Subramanian <isubramanian@apm.com>
- Signed-off-by: Ravi Patel <rapatel@apm.com>
- Signed-off-by: Keyur Chudgar <kchudgar@apm.com>
+ Acked-by: Grant Likely <grant.likely@linaro.org>
+ Signed-off-by: Ashwin Chaugule <ashwin.chaugule@linaro.org>
+ Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
-commit 237639e43c3d6587985a736f33264e129123d7a5
+commit fff62dfc1d7ab6ad3d528b008413fd116d208150
Author: Mark Salter <msalter@redhat.com>
-Date: Fri Jul 25 15:14:32 2014 -0400
+Date: Sat Nov 8 22:25:48 2014 -0500
- arm/kvm: WIP fix for stage2 pgd memory leak
+ arm64: use UEFI for reboot
+
+ Wire in support for UEFI reboot. We want UEFI reboot to have
+ highest priority for capsule support.
Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 0794e2900e5e4be4b7aa0b389e6b0bf8b55c5cd7
+commit 997a0488adb3f525aedb678b584f2733f43e248e
+Author: Mark Salter <msalter@redhat.com>
+Date: Sat Nov 8 15:25:41 2014 -0500
+
+ arm64: use UEFI as last resort for poweroff
+
+ Wire in support for poweroff via UEFI.
+
+ Signed-off-by: Mark Salter <msalter@redhat.com>
+
+commit 5b823d4bf52286f97dc76683b533ae5c08763897
Author: Mark Salter <msalter@redhat.com>
Date: Thu Jul 17 13:34:50 2014 -0400
@@ -779,24 +1360,7 @@ Date: Thu Jul 17 13:34:50 2014 -0400
Signed-off-by: Mark Salter <msalter@redhat.com>
-commit 7adf85b63608b8bea1148f2faa84f475252a9e43
-Author: Mark Salter <msalter@redhat.com>
-Date: Fri Jul 25 15:32:05 2014 -0400
-
- rtc: ia64: allow other architectures to use EFI RTC
-
- Currently, the rtc-efi driver is restricted to ia64 only. Newer
- architectures with EFI support may want to also use that driver. This
- patch moves the platform device setup from ia64 into drivers/rtc and allow
- any architecture with CONFIG_EFI=y to use the rtc-efi driver.
-
- Signed-off-by: Mark Salter <msalter@redhat.com>
- Cc: Alessandro Zummo <a.zummo@towertech.it>
- Cc: Tony Luck <tony.luck@intel.com>
- Cc: Fenghua Yu <fenghua.yu@intel.com>
- Cc: Andrew Morton <akpm@linux-foundation.org>
-
-commit 3b2f96c7a6bfbd46e7dee1d7000081422a7983ce
+commit f866806e1ca75a0efc62cda59559286faa7c9926
Author: Kyle McMartin <kmcmarti@redhat.com>
Date: Tue May 13 22:25:26 2014 -0400
@@ -866,2882 +1430,3190 @@ Date: Tue May 13 22:25:26 2014 -0400
Signed-off-by: Kyle McMartin <kmcmarti@redhat.com>
Signed-off-by: Donald Dutile <ddutile@redhat.com>
-commit 4b866971e92b925a44da8d876cb57864942a90b8
-Author: Mark Salter <msalter@redhat.com>
-Date: Thu Jul 24 15:56:15 2014 +0100
-
- arm64: fix soft lockup due to large tlb flush range
-
- Under certain loads, this soft lockup has been observed:
-
- BUG: soft lockup - CPU#2 stuck for 22s! [ip6tables:1016]
- Modules linked in: ip6t_rpfilter ip6t_REJECT cfg80211 rfkill xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw vfat fat efivarfs xfs libcrc32c
-
- CPU: 2 PID: 1016 Comm: ip6tables Not tainted 3.13.0-0.rc7.30.sa2.aarch64 #1
- task: fffffe03e81d1400 ti: fffffe03f01f8000 task.ti: fffffe03f01f8000
- PC is at __cpu_flush_kern_tlb_range+0xc/0x40
- LR is at __purge_vmap_area_lazy+0x28c/0x3ac
- pc : [<fffffe000009c5cc>] lr : [<fffffe0000182710>] pstate: 80000145
- sp : fffffe03f01fbb70
- x29: fffffe03f01fbb70 x28: fffffe03f01f8000
- x27: fffffe0000b19000 x26: 00000000000000d0
- x25: 000000000000001c x24: fffffe03f01fbc50
- x23: fffffe03f01fbc58 x22: fffffe03f01fbc10
- x21: fffffe0000b2a3f8 x20: 0000000000000802
- x19: fffffe0000b2a3c8 x18: 000003fffdf52710
- x17: 000003ff9d8bb910 x16: fffffe000050fbfc
- x15: 0000000000005735 x14: 000003ff9d7e1a5c
- x13: 0000000000000000 x12: 000003ff9d7e1a5c
- x11: 0000000000000007 x10: fffffe0000c09af0
- x9 : fffffe0000ad1000 x8 : 000000000000005c
- x7 : fffffe03e8624000 x6 : 0000000000000000
- x5 : 0000000000000000 x4 : 0000000000000000
- x3 : fffffe0000c09cc8 x2 : 0000000000000000
- x1 : 000fffffdfffca80 x0 : 000fffffcd742150
-
- The __cpu_flush_kern_tlb_range() function looks like:
-
- ENTRY(__cpu_flush_kern_tlb_range)
- dsb sy
- lsr x0, x0, #12
- lsr x1, x1, #12
- 1: tlbi vaae1is, x0
- add x0, x0, #1
- cmp x0, x1
- b.lo 1b
- dsb sy
- isb
- ret
- ENDPROC(__cpu_flush_kern_tlb_range)
-
- The above soft lockup shows the PC at tlbi insn with:
-
- x0 = 0x000fffffcd742150
- x1 = 0x000fffffdfffca80
-
- So __cpu_flush_kern_tlb_range has 0x128ba930 tlbi flushes left
- after it has already been looping for 23 seconds!.
-
- Looking up one frame at __purge_vmap_area_lazy(), there is:
-
- ...
- list_for_each_entry_rcu(va, &vmap_area_list, list) {
- if (va->flags & VM_LAZY_FREE) {
- if (va->va_start < *start)
- *start = va->va_start;
- if (va->va_end > *end)
- *end = va->va_end;
- nr += (va->va_end - va->va_start) >> PAGE_SHIFT;
- list_add_tail(&va->purge_list, &valist);
- va->flags |= VM_LAZY_FREEING;
- va->flags &= ~VM_LAZY_FREE;
- }
- }
- ...
- if (nr || force_flush)
- flush_tlb_kernel_range(*start, *end);
-
- So if two areas are being freed, the range passed to
- flush_tlb_kernel_range() may be as large as the vmalloc
- space. For arm64, this is ~240GB for 4k pagesize and ~2TB
- for 64kpage size.
-
- This patch works around this problem by adding a loop limit.
- If the range is larger than the limit, use flush_tlb_all()
- rather than flushing based on individual pages. The limit
- chosen is arbitrary as the TLB size is implementation
- specific and not accessible in an architected way. The aim
- of the arbitrary limit is to avoid soft lockup.
+commit a68d368ceb495cabafe82cdd0b83ec1e271a7f9d
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Fri Nov 7 14:12:34 2014 +0000
+
+ arm64: kvm: eliminate literal pool entries
- Signed-off-by: Mark Salter <msalter@redhat.com>
- [catalin.marinas@arm.com: commit log update]
- [catalin.marinas@arm.com: marginal optimisation]
- [catalin.marinas@arm.com: changed to MAX_TLB_RANGE and added comment]
- Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-
-diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
-index 37fc4f6..da1d4bf 100644
---- a/Documentation/arm64/booting.txt
-+++ b/Documentation/arm64/booting.txt
-@@ -141,6 +141,14 @@ Before jumping into the kernel, the following conditions must be met:
- the kernel image will be entered must be initialised by software at a
- higher exception level to prevent execution in an UNKNOWN state.
-
-+ For systems with a GICv3 interrupt controller:
-+ - If EL3 is present:
-+ ICC_SRE_EL3.Enable (bit 3) must be initialiased to 0b1.
-+ ICC_SRE_EL3.SRE (bit 0) must be initialised to 0b1.
-+ - If the kernel is entered at EL1:
-+ ICC.SRE_EL2.Enable (bit 3) must be initialised to 0b1
-+ ICC_SRE_EL2.SRE (bit 0) must be initialised to 0b1.
-+
- The requirements described above for CPU mode, caches, MMUs, architected
- timers, coherency and system registers apply to all CPUs. All CPUs must
- enter the kernel in the same exception level.
-diff --git a/Documentation/devicetree/bindings/arm/gic-v3.txt b/Documentation/devicetree/bindings/arm/gic-v3.txt
+ Replace two instances of 'ldr xN, =(constant)' in the world switch
+ hot path with 'mov' instructions.
+
+ Acked-by: Marc Zyngier <marc.zyngier@arm.com>
+ Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ Signed-off-by: Will Deacon <will.deacon@arm.com>
+
+commit 246a31b3a8f065e831a6d8d9fd96f3a8e17dbdb9
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Fri Nov 7 14:12:33 2014 +0000
+
+ arm64: ftrace: eliminate literal pool entries
+
+ Replace ldr xN, =<symbol> with adrp/add or adrp/ldr [as appropriate]
+ in the implementation of _mcount(), which may be called very often.
+
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ Signed-off-by: Will Deacon <will.deacon@arm.com>
+
+commit ecd0f8e21514e8ac758ed16a188faaa4c5ef75c7
+Author: Mark Rutland <mark.rutland@arm.com>
+Date: Tue Nov 4 10:50:16 2014 +0000
+
+ arm64: log physical ID of boot CPU
+
+ In certain debugging scenarios it's useful to know the physical ID (i.e.
+ the MPIDR_EL1.Aff* fields) of the boot CPU, but we don't currently log
+ this as we do for 32-bit ARM kernels.
+
+ This patch makes the kernel log the physical ID of the boot CPU early in
+ the boot process. The CPU logical map initialisation is folded in to
+ smp_setup_processor_id (which contrary to its name is also called by UP
+ kernels). This is called before setup_arch, so should not adversely
+ affect existing cpu_logical_map users.
+
+ Acked-by: Sudeep Holla <sudeep.holla@arm.com>
+ Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+ Acked-by: Lorenzo Pieralisis <lorenzo.pieralisi@arm.com>
+ Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+ Signed-off-by: Will Deacon <will.deacon@arm.com>
+
+commit 2899d6ea451eb0037427bbf430069f73cb76becc
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Mon Nov 3 16:50:01 2014 +0000
+
+ arm64/crypto: use crypto instructions to generate AES key schedule
+
+ This patch implements the AES key schedule generation using ARMv8
+ Crypto Instructions. It replaces the table based C implementation
+ in aes_generic.ko, which means we can drop the dependency on that
+ module.
+
+ Tested-by: Steve Capper <steve.capper@linaro.org>
+ Acked-by: Steve Capper <steve.capper@linaro.org>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ Signed-off-by: Will Deacon <will.deacon@arm.com>
+
+commit 67b1122c25f0c7a9a126ebabcd2085ef99640c13
+Author: Geoff Levand <geoff@infradead.org>
+Date: Fri Oct 31 23:06:47 2014 +0000
+
+ arm64/kvm: Fix assembler compatibility of macros
+
+ Some of the macros defined in kvm_arm.h are useful in assembly files, but are
+ not compatible with the assembler. Change any C language integer constant
+ definitions using appended U, UL, or ULL to the UL() preprocessor macro. Also,
+ add a preprocessor include of the asm/memory.h file which defines the UL()
+ macro.
+
+ Fixes build errors like these when using kvm_arm.h in assembly
+ source files:
+
+ Error: unexpected characters following instruction at operand 3 -- `and x0,x1,#((1U<<25)-1)'
+
+ Acked-by: Mark Rutland <mark.rutland@arm.com>
+ Signed-off-by: Geoff Levand <geoff@infradead.org>
+ Signed-off-by: Will Deacon <will.deacon@arm.com>
+
+commit 6a3c07e9aa03b7fbec14ab8bc21fce8590f12d83
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Tue Oct 28 12:24:20 2014 +0000
+
+ arm64/dt: add machine name to kernel call stack dump output
+
+ This installs the machine name as recorded by setup_machine_fdt()
+ as dump stack arch description. This results in the string to be
+ included in call stack dumps, as is shown here:
+
+ ...
+ Bad mode in Synchronous Abort handler detected, code 0x84000005
+ CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.18.0-rc2+ #548
+ > Hardware name: linux,dummy-virt (DT)
+ task: ffffffc07c870000 ti: ffffffc07c878000 task.ti: ffffffc07c878000
+ PC is at 0x0
+ ...
+
+ Note that systems that support DMI/SMBIOS may override this later.
+
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ Signed-off-by: Will Deacon <will.deacon@arm.com>
+
+commit 7c0569a739d0f1dd8ffd709cf37c53bb42143687
+Author: Steve Capper <steve.capper@linaro.org>
+Date: Fri Oct 24 13:22:20 2014 +0100
+
+ arm64: xchg: Implement cmpxchg_double
+
+ The arm64 architecture has the ability to exclusively load and store
+ a pair of registers from an address (ldxp/stxp). Also the SLUB can take
+ advantage of a cmpxchg_double implementation to avoid taking some
+ locks.
+
+ This patch provides an implementation of cmpxchg_double for 64-bit
+ pairs, and activates the logic required for the SLUB to use these
+ functions (HAVE_ALIGNED_STRUCT_PAGE and HAVE_CMPXCHG_DOUBLE).
+
+ Also definitions of this_cpu_cmpxchg_8 and this_cpu_cmpxchg_double_8
+ are wired up to cmpxchg_local and cmpxchg_double_local (rather than the
+ stock implementations that perform non-atomic operations with
+ interrupts disabled) as they are used by the SLUB.
+
+ On a Juno platform running on only the A57s I get quite a noticeable
+ performance improvement with 5 runs of hackbench on v3.17:
+
+ Baseline | With Patch
+ -----------------+-----------
+ Mean 119.2312 | 106.1782
+ StdDev 0.4919 | 0.4494
+
+ (times taken to complete `./hackbench 100 process 1000', in seconds)
+
+ Signed-off-by: Steve Capper <steve.capper@linaro.org>
+ Signed-off-by: Will Deacon <will.deacon@arm.com>
+
+commit 7acf53bfb80c2823d233c14d33cfd2d119713b89
+Author: Joonwoo Park <joonwoop@codeaurora.org>
+Date: Tue Oct 21 01:59:03 2014 +0100
+
+ arm64: optimize memcpy_{from,to}io() and memset_io()
+
+ Optimize memcpy_{from,to}io() and memset_io() by transferring in 64 bit
+ as much as possible with minimized barrier usage. This simplest
+ optimization brings faster throughput compare to current byte-by-byte read
+ and write with barrier in the loop. Code's skeleton is taken from the
+ powerpc.
+
+ Link: http://lkml.kernel.org/p/20141020133304.GH23751@e104818-lin.cambridge.arm.com
+ Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+ Reviewed-by: Trilok Soni <tsoni@codeaurora.org>
+ Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
+ Signed-off-by: Will Deacon <will.deacon@arm.com>
+
+commit 1971c19fb2a38a1d94cedada404760a917c36cd4
+Author: Mark Rutland <mark.rutland@arm.com>
+Date: Thu Oct 23 16:33:33 2014 +0100
+
+ efi: efi-stub: notify on DTB absence
+
+ In the absence of a DTB configuration table, the EFI stub will happily
+ continue attempting to boot a kernel, despite the fact that this kernel
+ may not function without a description of the hardware. In this case, as
+ with a typo'd "dtb=" option (e.g. "dbt=") or many other possible
+ failures, the only output seen by the user will be the rather terse
+ output from the EFI stub:
+
+ EFI stub: Booting Linux Kernel...
+
+ To aid those attempting to debug such failures, this patch adds a notice
+ when no DTB is found, making the output more helpful:
+
+ EFI stub: Booting Linux Kernel...
+ EFI stub: Generating empty DTB
+
+ Additionally, a positive acknowledgement is added when a user-specified
+ DTB is in use:
+
+ EFI stub: Booting Linux Kernel...
+ EFI stub: Using DTB from command line
+
+ Similarly, a positive acknowledgement is added when a DTB from a
+ configuration table is in use:
+
+ EFI stub: Booting Linux Kernel...
+ EFI stub: Using DTB from configuration table
+
+ Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+ Acked-by: Leif Lindholm <leif.lindholm@linaro.org>
+ Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ Acked-by: Roy Franz <roy.franz@linaro.org>
+ Acked-by: Matt Fleming <matt.fleming@intel.com>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit 7652016ff98e614ed2e3abac19b996af02434293
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Wed Oct 15 09:36:50 2014 +0200
+
+ arm64: dmi: set DMI string as dump stack arch description
+
+ This sets the DMI string, containing system type, serial number,
+ firmware version etc. as dump stack arch description, so that oopses
+ and other kernel stack dumps automatically have this information
+ included, if available.
+
+ Tested-by: Leif Lindholm <leif.lindholm@linaro.org>
+ Acked-by: Leif Lindholm <leif.lindholm@linaro.org>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit 2586f232bd388d2223f3c7bcba446b2bd25d8e3d
+Author: Yi Li <yi.li@linaro.org>
+Date: Sat Oct 4 23:46:43 2014 +0800
+
+ arm64: dmi: Add SMBIOS/DMI support
+
+ SMBIOS is important for server hardware vendors. It implements a spec for
+ providing descriptive information about the platform. Things like serial
+ numbers, physical layout of the ports, build configuration data, and the like.
+
+ Signed-off-by: Yi Li <yi.li@linaro.org>
+ Tested-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+ Tested-by: Leif Lindholm <leif.lindholm@linaro.org>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit 16b52b24f3d7a4f1555e4233398172b32306c1e4
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Tue Oct 14 16:41:27 2014 +0200
+
+ dmi: add support for SMBIOS 3.0 64-bit entry point
+
+ The DMTF SMBIOS reference spec v3.0.0 defines a new 64-bit entry point,
+ which enables support for SMBIOS structure tables residing at a physical
+ offset over 4 GB. This is especially important for upcoming arm64
+ platforms whose system RAM resides entirely above the 4 GB boundary.
+
+ For the UEFI case, this code attempts to detect the new SMBIOS 3.0
+ header magic at the offset passed in the SMBIOS3_TABLE_GUID UEFI
+ configuration table. If this configuration table is not provided, or
+ if we fail to parse the header, we fall back to using the legacy
+ SMBIOS_TABLE_GUID configuration table. This is in line with the spec,
+ that allows both configuration tables to be provided, but mandates that
+ they must point to the same structure table, unless the version pointed
+ to by the 64-bit entry point is a superset of the 32-bit one.
+
+ For the non-UEFI case, the detection logic is modified to look for the
+ SMBIOS 3.0 header magic before it looks for the legacy header magic.
+
+ Note that this patch is based on version 3.0.0d [draft] of the
+ specification, which is expected not to deviate from the final version
+ in ways that would affect the correctness of this implementation.
+
+ Tested-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+ Acked-by: Leif Lindholm <leif.lindholm@linaro.org>
+ Tested-by: Leif Lindholm <leif.lindholm@linaro.org>
+ Cc: Andrew Morton <akpm@linux-foundation.org>
+ Cc: Tony Luck <tony.luck@intel.com>
+ Acked-by: Matt Fleming <matt.fleming@intel.com>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit 016f4b4f5cee9ddd8c243a36c220a65bdfb82dc8
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Tue Oct 14 16:34:47 2014 +0200
+
+ efi: dmi: add support for SMBIOS 3.0 UEFI configuration table
+
+ This adds support to the UEFI side for detecting the presence of
+ a SMBIOS 3.0 64-bit entry point. This allows the actual SMBIOS
+ structure table to reside at a physical offset over 4 GB, which
+ cannot be supported by the legacy SMBIOS 32-bit entry point.
+
+ Since the firmware can legally provide both entry points, store
+ the SMBIOS 3.0 entry point in a separate variable, and let the
+ DMI decoding layer decide which one will be used.
+
+ Tested-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+ Acked-by: Leif Lindholm <leif.lindholm@linaro.org>
+ Acked-by: Matt Fleming <matt.fleming@intel.com>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit ac627ea950e853f0a3f91607fb16cb9477f434d7
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Fri Oct 17 12:44:11 2014 +0200
+
+ arm64/efi: drop redundant set_bit(EFI_CONFIG_TABLES)
+
+ The EFI_CONFIG_TABLES bit already gets set by efi_config_init(),
+ so there is no reason to set it again after this function returns
+ successfully.
+
+ Acked-by: Will Deacon <will.deacon@arm.com>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit 850ba08a3f4756a8340edadd4fdeccd881813ba5
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Mon Oct 20 15:31:57 2014 +0200
+
+ arm64/efi: invert UEFI memory region reservation logic
+
+ Instead of reserving the memory regions based on which types we know
+ need to be reserved, consider only regions of the following types as
+ free for general use by the OS:
+
+ EFI_LOADER_CODE
+ EFI_LOADER_DATA
+ EFI_BOOT_SERVICES_CODE
+ EFI_BOOT_SERVICES_DATA
+ EFI_CONVENTIONAL_MEMORY
+
+ Note that this also fixes a problem with the original code, which would
+ misidentify a EFI_RUNTIME_SERVICES_DATA region as not reserved if it
+ does not have the EFI_MEMORY_RUNTIME attribute set. However, it is
+ perfectly legal for the firmware not to request a virtual mapping for
+ EFI_RUNTIME_SERVICES_DATA regions that contain configuration tables, in
+ which case the EFI_MEMORY_RUNTIME attribute would not be set.
+
+ Acked-by: Roy Franz <roy.franz@linaro.org>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit 2787807ca4f5f7df82a5c54312753b157e8c052e
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Fri Oct 10 18:42:55 2014 +0200
+
+ arm64/efi: set PE/COFF file alignment to 512 bytes
+
+ Change our PE/COFF header to use the minimum file alignment of
+ 512 bytes (0x200), as mandated by the PE/COFF spec v8.3
+
+ Also update the linker script so that the Image file itself is also a
+ round multiple of FileAlignment.
+
+ Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+ Acked-by: Roy Franz <roy.franz@linaro.org>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit 7bd0585d9ab62d9787c389d3b62141b76319e5f7
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Fri Oct 10 11:25:24 2014 +0200
+
+ arm64/efi: set PE/COFF section alignment to 4 KB
+
+ Position independent AArch64 code needs to be linked and loaded at the
+ same relative offset from a 4 KB boundary, or adrp/add and adrp/ldr
+ pairs will not work correctly. (This is how PC relative symbol
+ references with a 4 GB reach are emitted)
+
+ We need to declare this in the PE/COFF header, otherwise the PE/COFF
+ loader may load the Image and invoke the stub at an offset which
+ violates this rule.
+
+ Reviewed-by: Roy Franz <roy.franz@linaro.org>
+ Acked-by: Mark Rutland <mark.rutland@arm.com>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+commit 5a0edb2dbdf9327322ae57e8e16d162c2a371318
+Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Wed Oct 8 16:11:27 2014 +0200
+
+ arm64/efi: efistub: jump to 'stext' directly, not through the header
+
+ After the EFI stub has done its business, it jumps into the kernel by
+ branching to offset #0 of the loaded Image, which is where it expects
+ to find the header containing a 'branch to stext' instruction.
+
+ However, the UEFI spec 2.1.1 states the following regarding PE/COFF
+ image loading:
+ "A UEFI image is loaded into memory through the LoadImage() Boot
+ Service. This service loads an image with a PE32+ format into memory.
+ This PE32+ loader is required to load all sections of the PE32+ image
+ into memory."
+
+ In other words, it is /not/ required to load parts of the image that are
+ not covered by a PE/COFF section, so it may not have loaded the header
+ at the expected offset, as it is not covered by any PE/COFF section.
+
+ So instead, jump to 'stext' directly, which is at the base of the
+ PE/COFF .text section, by supplying a symbol 'stext_offset' to
+ efi-entry.o which contains the relative offset of stext into the Image.
+ Also replace other open coded calculations of the same value with a
+ reference to 'stext_offset'
+
+ Acked-by: Mark Rutland <mark.rutland@arm.com>
+ Acked-by: Roy Franz <roy.franz@linaro.org>
+ Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+ Documentation/acpi/gpio-properties.txt | 96 +++
+ Documentation/arm64/arm-acpi.txt | 323 ++++++++++
+ Documentation/gpio/consumer.txt | 18 +
+ Documentation/kernel-parameters.txt | 3 +-
+ arch/arm/include/asm/kvm_mmu.h | 5 +-
+ arch/arm/kvm/mmu.c | 22 +-
+ arch/arm/mach-s3c24xx/h1940-bluetooth.c | 4 +-
+ arch/arm/mach-s3c24xx/h1940.h | 4 +-
+ arch/arm/mach-s3c24xx/mach-h1940.c | 3 +-
+ arch/arm/mach-s3c24xx/mach-rx1950.c | 3 +-
+ arch/arm/plat-orion/gpio.c | 3 +-
+ arch/arm/plat-orion/include/plat/orion-gpio.h | 5 +-
+ arch/arm64/Kconfig | 22 +
+ arch/arm64/Makefile | 1 +
+ arch/arm64/crypto/Kconfig | 5 +-
+ arch/arm64/crypto/aes-ce-ccm-glue.c | 4 +-
+ arch/arm64/crypto/aes-ce-cipher.c | 112 +++-
+ arch/arm64/crypto/aes-ce-setkey.h | 5 +
+ arch/arm64/crypto/aes-glue.c | 18 +-
+ arch/arm64/include/asm/acenv.h | 18 +
+ arch/arm64/include/asm/acpi.h | 102 +++
+ arch/arm64/include/asm/cmpxchg.h | 71 +++
+ arch/arm64/include/asm/cpu_ops.h | 1 +
+ arch/arm64/include/asm/dmi.h | 31 +
+ arch/arm64/include/asm/elf.h | 3 +-
+ arch/arm64/include/asm/kvm_arm.h | 21 +-
+ arch/arm64/include/asm/kvm_mmu.h | 5 +-
+ arch/arm64/include/asm/pci.h | 51 ++
+ arch/arm64/include/asm/psci.h | 3 +-
+ arch/arm64/include/asm/smp.h | 10 +-
+ arch/arm64/kernel/Makefile | 4 +-
+ arch/arm64/kernel/acpi.c | 398 ++++++++++++
+ arch/arm64/kernel/cpu_ops.c | 8 +-
+ arch/arm64/kernel/efi-entry.S | 3 +-
+ arch/arm64/kernel/efi.c | 74 ++-
+ arch/arm64/kernel/entry-ftrace.S | 21 +-
+ arch/arm64/kernel/head.S | 24 +-
+ arch/arm64/kernel/io.c | 66 +-
+ arch/arm64/kernel/pci.c | 97 ++-
+ arch/arm64/kernel/psci.c | 78 ++-
+ arch/arm64/kernel/setup.c | 51 +-
+ arch/arm64/kernel/smp.c | 2 +-
+ arch/arm64/kernel/smp_parking_protocol.c | 110 ++++
+ arch/arm64/kernel/time.c | 7 +
+ arch/arm64/kernel/vmlinux.lds.S | 17 +
+ arch/arm64/kvm/hyp.S | 4 +-
+ arch/arm64/mm/dma-mapping.c | 112 ++++
+ arch/arm64/pci/Makefile | 2 +
+ arch/arm64/pci/mmconfig.c | 292 +++++++++
+ arch/arm64/pci/pci.c | 461 ++++++++++++++
+ drivers/acpi/Kconfig | 6 +-
+ drivers/acpi/Makefile | 7 +-
+ drivers/acpi/bus.c | 3 +
+ drivers/acpi/internal.h | 11 +
+ drivers/acpi/osl.c | 6 +-
+ drivers/acpi/processor_core.c | 37 ++
+ drivers/acpi/property.c | 551 ++++++++++++++++
+ drivers/acpi/scan.c | 129 +++-
+ 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/base/Makefile | 2 +-
+ drivers/base/property.c | 431 +++++++++++++
+ drivers/clocksource/arm_arch_timer.c | 120 +++-
+ drivers/firmware/dmi_scan.c | 79 ++-
+ drivers/firmware/efi/efi.c | 4 +
+ drivers/firmware/efi/libstub/arm-stub.c | 11 +-
+ drivers/gpio/devres.c | 32 +
+ drivers/gpio/gpio-sch.c | 293 ++++-----
+ drivers/gpio/gpiolib-acpi.c | 117 +++-
+ drivers/gpio/gpiolib.c | 85 ++-
+ drivers/gpio/gpiolib.h | 7 +-
+ drivers/input/keyboard/gpio_keys_polled.c | 112 ++--
+ drivers/iommu/arm-smmu.c | 8 +-
+ drivers/irqchip/irq-gic-v3.c | 10 +
+ drivers/irqchip/irq-gic.c | 116 ++++
+ drivers/irqchip/irqchip.c | 3 +
+ drivers/leds/leds-gpio.c | 140 ++--
+ drivers/misc/eeprom/at25.c | 34 +-
+ drivers/net/ethernet/amd/Kconfig | 2 +-
+ drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 16 +-
+ drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 3 +
+ drivers/net/ethernet/amd/xgbe/xgbe-main.c | 289 +++++++--
+ drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 20 +-
+ drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 4 +-
+ drivers/net/ethernet/amd/xgbe/xgbe.h | 13 +
+ drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 69 +-
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 68 +-
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 1 +
+ drivers/net/ethernet/smsc/smc91x.c | 10 +
+ drivers/net/phy/Kconfig | 2 +-
+ drivers/net/phy/amd-xgbe-phy.c | 777 ++++++++++++-----------
+ drivers/of/base.c | 33 +
+ drivers/pci/host/pci-xgene.c | 167 +++++
+ drivers/pnp/resource.c | 2 +
+ drivers/tty/Kconfig | 6 +
+ drivers/tty/Makefile | 1 +
+ drivers/tty/sbsauart.c | 358 +++++++++++
+ drivers/tty/serial/8250/8250_dw.c | 9 +
+ drivers/virtio/virtio_mmio.c | 12 +-
+ drivers/xen/efi.c | 1 +
+ include/acpi/acpi_bus.h | 30 +
+ include/acpi/acpi_io.h | 6 +
+ include/asm-generic/vmlinux.lds.h | 7 +
+ include/kvm/arm_vgic.h | 20 +-
+ include/linux/acpi.h | 141 +++-
+ include/linux/clocksource.h | 6 +
+ include/linux/efi.h | 6 +-
+ include/linux/gpio/consumer.h | 7 +
+ include/linux/gpio_keys.h | 3 +
+ include/linux/irqchip/arm-gic-acpi.h | 31 +
+ include/linux/irqchip/arm-gic.h | 2 +
+ include/linux/kvm_host.h | 1 +
+ include/linux/leds.h | 3 +-
+ include/linux/of.h | 34 +
+ include/linux/pci.h | 37 +-
+ include/linux/property.h | 143 +++++
+ net/rfkill/rfkill-gpio.c | 18 +-
+ virt/kvm/arm/arch_timer.c | 107 ++--
+ virt/kvm/arm/vgic-v2.c | 86 ++-
+ virt/kvm/arm/vgic-v3.c | 8 +-
+ virt/kvm/arm/vgic.c | 30 +-
+ 125 files changed, 6843 insertions(+), 1117 deletions(-)
+
+diff --git a/Documentation/acpi/gpio-properties.txt b/Documentation/acpi/gpio-properties.txt
new file mode 100644
-index 0000000..33cd05e
+index 0000000..ae36fcf
--- /dev/null
-+++ b/Documentation/devicetree/bindings/arm/gic-v3.txt
-@@ -0,0 +1,79 @@
-+* ARM Generic Interrupt Controller, version 3
-+
-+AArch64 SMP cores are often associated with a GICv3, providing Private
-+Peripheral Interrupts (PPI), Shared Peripheral Interrupts (SPI),
-+Software Generated Interrupts (SGI), and Locality-specific Peripheral
-+Interrupts (LPI).
-+
-+Main node required properties:
-+
-+- compatible : should at least contain "arm,gic-v3".
-+- interrupt-controller : Identifies the node as an interrupt controller
-+- #interrupt-cells : Specifies the number of cells needed to encode an
-+ interrupt source. Must be a single cell with a value of at least 3.
-+
-+ The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
-+ interrupts. Other values are reserved for future use.
-+
-+ The 2nd cell contains the interrupt number for the interrupt type.
-+ SPI interrupts are in the range [0-987]. PPI interrupts are in the
-+ range [0-15].
-+
-+ The 3rd cell is the flags, encoded as follows:
-+ bits[3:0] trigger type and level flags.
-+ 1 = edge triggered
-+ 4 = level triggered
-+
-+ Cells 4 and beyond are reserved for future use. When the 1st cell
-+ has a value of 0 or 1, cells 4 and beyond act as padding, and may be
-+ ignored. It is recommended that padding cells have a value of 0.
-+
-+- reg : Specifies base physical address(s) and size of the GIC
-+ registers, in the following order:
-+ - GIC Distributor interface (GICD)
-+ - GIC Redistributors (GICR), one range per redistributor region
-+ - GIC CPU interface (GICC)
-+ - GIC Hypervisor interface (GICH)
-+ - GIC Virtual CPU interface (GICV)
-+
-+ GICC, GICH and GICV are optional.
-+
-+- interrupts : Interrupt source of the VGIC maintenance interrupt.
-+
-+Optional
-+
-+- redistributor-stride : If using padding pages, specifies the stride
-+ of consecutive redistributors. Must be a multiple of 64kB.
-+
-+- #redistributor-regions: The number of independent contiguous regions
-+ occupied by the redistributors. Required if more than one such
-+ region is present.
-+
-+Examples:
-+
-+ gic: interrupt-controller@2cf00000 {
-+ compatible = "arm,gic-v3";
-+ #interrupt-cells = <3>;
-+ interrupt-controller;
-+ reg = <0x0 0x2f000000 0 0x10000>, // GICD
-+ <0x0 0x2f100000 0 0x200000>, // GICR
-+ <0x0 0x2c000000 0 0x2000>, // GICC
-+ <0x0 0x2c010000 0 0x2000>, // GICH
-+ <0x0 0x2c020000 0 0x2000>; // GICV
-+ interrupts = <1 9 4>;
-+ };
++++ b/Documentation/acpi/gpio-properties.txt
+@@ -0,0 +1,96 @@
++_DSD Device Properties Related to GPIO
++--------------------------------------
++
++With the release of ACPI 5.1 and the _DSD configuration objecte names
++can finally be given to GPIOs (and other things as well) returned by
++_CRS. Previously, we were only able to use an integer index to find
++the corresponding GPIO, which is pretty error prone (it depends on
++the _CRS output ordering, for example).
++
++With _DSD we can now query GPIOs using a name instead of an integer
++index, like the ASL example below shows:
++
++ // Bluetooth device with reset and shutdown GPIOs
++ Device (BTH)
++ {
++ Name (_HID, ...)
++
++ Name (_CRS, ResourceTemplate ()
++ {
++ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
++ "\\_SB.GPO0", 0, ResourceConsumer) {15}
++ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
++ "\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
++ })
++
++ Name (_DSD, Package ()
++ {
++ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
++ Package ()
++ {
++ Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
++ Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
++ }
++ })
++ }
++
++The format of the supported GPIO property is:
++
++ Package () { "name", Package () { ref, index, pin, active_low }}
++
++ ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
++ typically this is the device itself (BTH in our case).
++ index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
++ pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
++ active_low - If 1 the GPIO is marked as active_low.
++
++Since ACPI GpioIo() resource does not have a field saying whether it is
++active low or high, the "active_low" argument can be used here. Setting
++it to 1 marks the GPIO as active low.
++
++In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
++resource, second pin in that resource with the GPIO number of 31.
++
++ACPI GPIO Mappings Provided by Drivers
++--------------------------------------
++
++There are systems in which the ACPI tables do not contain _DSD but provide _CRS
++with GpioIo()/GpioInt() resources and device drivers still need to work with
++them.
++
++In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV,
++available to the driver can be used to identify the device and that is supposed
++to be sufficient to determine the meaning and purpose of all of the GPIO lines
++listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words,
++the driver is supposed to know what to use the GpioIo()/GpioInt() resources for
++once it has identified the device. Having done that, it can simply assign names
++to the GPIO lines it is going to use and provide the GPIO subsystem with a
++mapping between those names and the ACPI GPIO resources corresponding to them.
++
++To do that, the driver needs to define a mapping table as a NULL-terminated
++array of struct acpi_gpio_mapping objects that each contain a name, a pointer
++to an array of line data (struct acpi_gpio_params) objects and the size of that
++array. Each struct acpi_gpio_params object consists of three fields,
++crs_entry_index, line_index, active_low, representing the index of the target
++GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target
++line in that resource starting from zero, and the active-low flag for that line,
++respectively, in analogy with the _DSD GPIO property format specified above.
++
++For the example Bluetooth device discussed previously the data structures in
++question would look like this:
++
++static const struct acpi_gpio_params reset_gpio = { 1, 1, false };
++static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
++
++static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
++ { "reset-gpio", &reset_gpio, 1 },
++ { "shutdown-gpio", &shutdown_gpio, 1 },
++ { },
++};
+
-+ gic: interrupt-controller@2c010000 {
-+ compatible = "arm,gic-v3";
-+ #interrupt-cells = <3>;
-+ interrupt-controller;
-+ redistributor-stride = <0x0 0x40000>; // 256kB stride
-+ #redistributor-regions = <2>;
-+ reg = <0x0 0x2c010000 0 0x10000>, // GICD
-+ <0x0 0x2d000000 0 0x800000>, // GICR 1: CPUs 0-31
-+ <0x0 0x2e000000 0 0x800000>; // GICR 2: CPUs 32-63
-+ <0x0 0x2c040000 0 0x2000>, // GICC
-+ <0x0 0x2c060000 0 0x2000>, // GICH
-+ <0x0 0x2c080000 0 0x2000>; // GICV
-+ interrupts = <1 9 4>;
-+ };
-diff --git a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt
++Next, the mapping table needs to be passed as the second argument to
++acpi_dev_add_driver_gpios() that will register it with the ACPI device object
++pointed to by its first argument. That should be done in the driver's .probe()
++routine. On removal, the driver should unregister its GPIO mapping table by
++calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
++table was previously registered.
+diff --git a/Documentation/arm64/arm-acpi.txt b/Documentation/arm64/arm-acpi.txt
new file mode 100644
-index 0000000..3e2a295
+index 0000000..17cf96d
--- /dev/null
-+++ b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt
-@@ -0,0 +1,72 @@
-+APM X-Gene SoC Ethernet nodes
-+
-+Ethernet nodes are defined to describe on-chip ethernet interfaces in
-+APM X-Gene SoC.
-+
-+Required properties:
-+- compatible: Should be "apm,xgene-enet"
-+- reg: Address and length of the register set for the device. It contains the
-+ information of registers in the same order as described by reg-names
-+- reg-names: Should contain the register set names
-+ "enet_csr": Ethernet control and status register address space
-+ "ring_csr": Descriptor ring control and status register address space
-+ "ring_cmd": Descriptor ring command register address space
-+- interrupts: Ethernet main interrupt
-+- clocks: Reference to the clock entry.
-+- local-mac-address: MAC address assigned to this device
-+- phy-connection-type: Interface type between ethernet device and PHY device
-+- phy-handle: Reference to a PHY node connected to this device
-+
-+- mdio: Device tree subnode with the following required
-+ properties:
-+
-+ - compatible: Must be "apm,xgene-mdio".
-+ - #address-cells: Must be <1>.
-+ - #size-cells: Must be <0>.
-+
-+ For the phy on the mdio bus, there must be a node with the following
-+ fields:
-+
-+ - compatible: PHY identifier. Please refer ./phy.txt for the format.
-+ - reg: The ID number for the phy.
-+
-+Optional properties:
-+- status : Should be "ok" or "disabled" for enabled/disabled.
-+ Default is "ok".
-+
-+
-+Example:
-+ menetclk: menetclk {
-+ compatible = "apm,xgene-device-clock";
-+ clock-output-names = "menetclk";
-+ status = "ok";
-+ };
++++ b/Documentation/arm64/arm-acpi.txt
+@@ -0,0 +1,323 @@
++ACPI on ARMv8 Servers
++---------------------
++ACPI can be used for ARMv8 general purpose servers designed to follow
++the ARM SBSA (Server Base System Architecture) specification, currently
++available to those with an ARM login at http://silver.arm.com.
+
-+ menet: ethernet@17020000 {
-+ compatible = "apm,xgene-enet";
-+ status = "disabled";
-+ reg = <0x0 0x17020000 0x0 0xd100>,
-+ <0x0 0X17030000 0x0 0X400>,
-+ <0x0 0X10000000 0x0 0X200>;
-+ reg-names = "enet_csr", "ring_csr", "ring_cmd";
-+ interrupts = <0x0 0x3c 0x4>;
-+ clocks = <&menetclk 0>;
-+ local-mac-address = [00 01 73 00 00 01];
-+ phy-connection-type = "rgmii";
-+ phy-handle = <&menetphy>;
-+ mdio {
-+ compatible = "apm,xgene-mdio";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ menetphy: menetphy@3 {
-+ compatible = "ethernet-phy-id001c.c915";
-+ reg = <0x3>;
-+ };
-+
-+ };
-+ };
++The ARMv8 kernel implements the reduced hardware model of ACPI version
++5.1 and its corresponding errata. Links to the specification and all
++external documents it refers to are managed by the UEFI Forum. The
++specification is available at http://www.uefi.org/specifications and
++external documents can be found via http://www.uefi.org/acpi.
+
-+/* Board-specific peripheral configurations */
-+&menet {
-+ status = "ok";
-+};
-diff --git a/Documentation/devicetree/bindings/pci/xgene-pci.txt b/Documentation/devicetree/bindings/pci/xgene-pci.txt
-new file mode 100644
-index 0000000..e19fdb8
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pci/xgene-pci.txt
-@@ -0,0 +1,52 @@
-+* AppliedMicro X-Gene PCIe interface
-+
-+Required properties:
-+- device_type: set to "pci"
-+- compatible: should contain "apm,xgene-pcie" to identify the core.
-+- reg: A list of physical base address and length for each set of controller
-+ registers. Must contain an entry for each entry in the reg-names
-+ property.
-+- reg-names: Must include the following entries:
-+ "csr": controller configuration registers.
-+ "cfg": pcie configuration space registers.
-+- #address-cells: set to <3>
-+- #size-cells: set to <2>
-+- ranges: ranges for the outbound memory, I/O regions.
-+- dma-ranges: ranges for the inbound memory regions.
-+- #interrupt-cells: set to <1>
-+- interrupt-map-mask and interrupt-map: standard PCI properties
-+ to define the mapping of the PCIe interface to interrupt
-+ numbers.
-+- clocks: from common clock binding: handle to pci clock.
-+
-+Optional properties:
-+- status: Either "ok" or "disabled".
-+
-+Example:
-+
-+SoC specific DT Entry:
-+ pcie0: pcie@1f2b0000 {
-+ status = "disabled";
-+ device_type = "pci";
-+ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
-+ #interrupt-cells = <1>;
-+ #size-cells = <2>;
-+ #address-cells = <3>;
-+ reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
-+ 0xe0 0xd0000000 0x0 0x00200000>; /* PCI config space */
-+ reg-names = "csr", "cfg";
-+ ranges = <0x01000000 0x00 0x00000000 0xe0 0x00000000 0x00 0x00010000 /* io */
-+ 0x02000000 0x00 0x10000000 0xe0 0x10000000 0x00 0x80000000>; /* mem */
-+ dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
-+ 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
-+ 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
-+ 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
-+ clocks = <&pcie0clk 0>;
-+ };
++If an ARMv8 system does not meet the requirements of the SBSA, or cannot
++be described using the mechanisms defined in the required ACPI specifications,
++then it is likely that Device Tree (DT) is more suitable than ACPI for the
++hardware.
+
-+Board specific DT Entry:
-+ &pcie0 {
-+ status = "ok";
-+ };
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 86efa7e..14a3ef1 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -699,6 +699,14 @@ S: Maintained
- F: drivers/net/appletalk/
- F: net/appletalk/
-
-+APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
-+M: Iyappan Subramanian <isubramanian@apm.com>
-+M: Keyur Chudgar <kchudgar@apm.com>
-+M: Ravi Patel <rapatel@apm.com>
-+S: Supported
-+F: drivers/net/ethernet/apm/xgene/
-+F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
-+
- APTINA CAMERA SENSOR PLL
- M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
- L: linux-media@vger.kernel.org
-@@ -6851,6 +6859,13 @@ S: Maintained
- F: Documentation/devicetree/bindings/pci/host-generic-pci.txt
- F: drivers/pci/host/pci-host-generic.c
-
-+PCI DRIVER FOR APPLIEDMICRO XGENE
-+M: Tanmay Inamdar <tinamdar@apm.com>
-+L: linux-pci@vger.kernel.org
-+L: linux-arm-kernel@lists.infradead.org
-+S: Maintained
-+F: drivers/pci/host/pci-xgene.c
-+
- PCMCIA SUBSYSTEM
- P: Linux PCMCIA Team
- L: linux-pcmcia@lists.infradead.org
-diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
-index 193ceaf..d6d5227 100644
---- a/arch/arm/include/asm/kvm_host.h
-+++ b/arch/arm/include/asm/kvm_host.h
-@@ -225,6 +225,11 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext)
- return 0;
- }
-
-+static inline void vgic_arch_setup(const struct vgic_params *vgic)
-+{
-+ BUG_ON(vgic->type != VGIC_V2);
-+}
-+
- int kvm_perf_init(void);
- int kvm_perf_teardown(void);
-
-diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
-index 85598b5..713e807 100644
---- a/arch/arm/kernel/asm-offsets.c
-+++ b/arch/arm/kernel/asm-offsets.c
-@@ -182,13 +182,13 @@ int main(void)
- DEFINE(VCPU_HYP_PC, offsetof(struct kvm_vcpu, arch.fault.hyp_pc));
- #ifdef CONFIG_KVM_ARM_VGIC
- DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
-- DEFINE(VGIC_CPU_HCR, offsetof(struct vgic_cpu, vgic_hcr));
-- DEFINE(VGIC_CPU_VMCR, offsetof(struct vgic_cpu, vgic_vmcr));
-- DEFINE(VGIC_CPU_MISR, offsetof(struct vgic_cpu, vgic_misr));
-- DEFINE(VGIC_CPU_EISR, offsetof(struct vgic_cpu, vgic_eisr));
-- DEFINE(VGIC_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_elrsr));
-- DEFINE(VGIC_CPU_APR, offsetof(struct vgic_cpu, vgic_apr));
-- DEFINE(VGIC_CPU_LR, offsetof(struct vgic_cpu, vgic_lr));
-+ DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
-+ DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
-+ DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
-+ DEFINE(VGIC_V2_CPU_EISR, offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
-+ DEFINE(VGIC_V2_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
-+ DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
-+ DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
- DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
- #ifdef CONFIG_KVM_ARM_TIMER
- DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
-diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
-index 789bca9..f7057ed 100644
---- a/arch/arm/kvm/Makefile
-+++ b/arch/arm/kvm/Makefile
-@@ -21,4 +21,5 @@ obj-y += kvm-arm.o init.o interrupts.o
- obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
- obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
- obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
-+obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
- obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
-diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
-index 76af9302..e4eaf30 100644
---- a/arch/arm/kvm/interrupts_head.S
-+++ b/arch/arm/kvm/interrupts_head.S
-@@ -421,14 +421,14 @@ vcpu .req r0 @ vcpu pointer always in r0
- ldr r9, [r2, #GICH_ELRSR1]
- ldr r10, [r2, #GICH_APR]
-
-- str r3, [r11, #VGIC_CPU_HCR]
-- str r4, [r11, #VGIC_CPU_VMCR]
-- str r5, [r11, #VGIC_CPU_MISR]
-- str r6, [r11, #VGIC_CPU_EISR]
-- str r7, [r11, #(VGIC_CPU_EISR + 4)]
-- str r8, [r11, #VGIC_CPU_ELRSR]
-- str r9, [r11, #(VGIC_CPU_ELRSR + 4)]
-- str r10, [r11, #VGIC_CPU_APR]
-+ str r3, [r11, #VGIC_V2_CPU_HCR]
-+ str r4, [r11, #VGIC_V2_CPU_VMCR]
-+ str r5, [r11, #VGIC_V2_CPU_MISR]
-+ str r6, [r11, #VGIC_V2_CPU_EISR]
-+ str r7, [r11, #(VGIC_V2_CPU_EISR + 4)]
-+ str r8, [r11, #VGIC_V2_CPU_ELRSR]
-+ str r9, [r11, #(VGIC_V2_CPU_ELRSR + 4)]
-+ str r10, [r11, #VGIC_V2_CPU_APR]
-
- /* Clear GICH_HCR */
- mov r5, #0
-@@ -436,7 +436,7 @@ vcpu .req r0 @ vcpu pointer always in r0
-
- /* Save list registers */
- add r2, r2, #GICH_LR0
-- add r3, r11, #VGIC_CPU_LR
-+ add r3, r11, #VGIC_V2_CPU_LR
- ldr r4, [r11, #VGIC_CPU_NR_LR]
- 1: ldr r6, [r2], #4
- str r6, [r3], #4
-@@ -463,9 +463,9 @@ vcpu .req r0 @ vcpu pointer always in r0
- add r11, vcpu, #VCPU_VGIC_CPU
-
- /* We only restore a minimal set of registers */
-- ldr r3, [r11, #VGIC_CPU_HCR]
-- ldr r4, [r11, #VGIC_CPU_VMCR]
-- ldr r8, [r11, #VGIC_CPU_APR]
-+ ldr r3, [r11, #VGIC_V2_CPU_HCR]
-+ ldr r4, [r11, #VGIC_V2_CPU_VMCR]
-+ ldr r8, [r11, #VGIC_V2_CPU_APR]
-
- str r3, [r2, #GICH_HCR]
- str r4, [r2, #GICH_VMCR]
-@@ -473,7 +473,7 @@ vcpu .req r0 @ vcpu pointer always in r0
-
- /* Restore list registers */
- add r2, r2, #GICH_LR0
-- add r3, r11, #VGIC_CPU_LR
-+ add r3, r11, #VGIC_V2_CPU_LR
- ldr r4, [r11, #VGIC_CPU_NR_LR]
- 1: ldr r6, [r3], #4
- str r6, [r2], #4
-diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
-index 839f48c..23871dd 100644
---- a/arch/arm64/Kconfig
-+++ b/arch/arm64/Kconfig
-@@ -11,6 +11,7 @@ config ARM64
- select ARM_AMBA
- select ARM_ARCH_TIMER
- select ARM_GIC
-+ select ARM_GIC_V3
- select BUILDTIME_EXTABLE_SORT
- select CLONE_BACKWARDS
- select COMMON_CLK
-@@ -76,7 +77,7 @@ config MMU
- def_bool y
-
- config NO_IOPORT_MAP
-- def_bool y
-+ def_bool y if !PCI
-
- config STACKTRACE_SUPPORT
- def_bool y
-@@ -151,6 +152,23 @@ menu "Bus support"
- config ARM_AMBA
- bool
-
-+config PCI
-+ bool "PCI support"
-+ help
-+ This feature enables support for PCIe bus system. If you say Y
-+ here, the kernel will include drivers and infrastructure code
-+ to support PCIe bus devices.
+
-+config PCI_DOMAINS
-+ def_bool PCI
++Relationship with Device Tree
++-----------------------------
++ACPI support in drivers and subsystems for ARMv8 should never be mutually
++exclusive with DT support at compile time.
+
-+config PCI_SYSCALL
-+ def_bool PCI
++At boot time the kernel will only use one description method depending on
++parameters passed from the bootloader (including kernel bootargs).
+
-+source "drivers/pci/Kconfig"
-+source "drivers/pci/pcie/Kconfig"
-+source "drivers/pci/hotplug/Kconfig"
++Regardless of whether DT or ACPI is used, the kernel must always be capable
++of booting with either scheme (in kernels with both schemes enabled at compile
++time).
+
- endmenu
-
- menu "Kernel Features"
-diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts
-index 6541962..0cb67fc 100644
---- a/arch/arm64/boot/dts/apm-mustang.dts
-+++ b/arch/arm64/boot/dts/apm-mustang.dts
-@@ -28,3 +28,15 @@
- &serial0 {
- status = "ok";
- };
++When booting using ACPI tables, the /chosen node in DT will still be parsed
++to extract the kernel command line and initrd path. No other section of the
++DT will be used.
++
++
++Booting using ACPI tables
++-------------------------
++The only defined method for passing ACPI tables to the kernel on ARMv8
++is via the UEFI system configuration table.
++
++Processing of ACPI tables may be disabled by passing acpi=off on the kernel
++command line; this is the default behavior. If acpi=force is used, the kernel
++will ONLY use device configuration information contained in the ACPI tables.
++
++In order for the kernel to load and use ACPI tables, the UEFI implementation
++MUST set the ACPI_20_TABLE_GUID to point to the RSDP table (the table with
++the ACPI signature "RSD PTR "). If this pointer is incorrect and acpi=force
++is used, the kernel will disable ACPI and try to use DT to boot.
++
++If the pointer to the RSDP table is correct, the table will be mapped into
++the kernel by the ACPI core, using the address provided by UEFI.
++
++The ACPI core will then locate and map in all other ACPI tables provided by
++using the addresses in the RSDP table to find the XSDT (eXtended System
++Description Table). The XSDT in turn provides the addresses to all other
++ACPI tables provided by the system firmware; the ACPI core will then traverse
++this table and map in the tables listed.
++
++The ACPI core will ignore any provided RSDT (Root System Description Table).
++RSDTs have been deprecated and are ignored on arm64 since they only allow
++for 32-bit addresses.
++
++Further, the ACPI core will only use the 64-bit address fields in the FADT
++(Fixed ACPI Description Table). Any 32-bit address fields in the FADT will
++be ignored on arm64.
++
++Hardware reduced mode (see Section 4.1 of the ACPI 5.1 specification) will
++be enforced by the ACPI core on arm64. Doing so allows the ACPI core to
++run less complex code since it no longer has to provide support for legacy
++hardware from other architectures.
++
++For the ACPI core to operate properly, and in turn provide the information
++the kernel needs to configure devices, it expects to find the following
++tables (all section numbers refer to the ACPI 5.1 specfication):
++
++ -- RSDP (Root System Description Pointer), section 5.2.5
++
++ -- XSDT (eXtended System Description Table), section 5.2.8
++
++ -- FACS (Firmware ACPI Control Structure), section 5.2.10
++
++ -- FADT (Fixed ACPI Description Table), section 5.2.9
++
++ -- DSDT (Differentiated System Description Table), section
++ 5.2.11.1
++
++ -- MADT (Multiple APIC Description Table), section 5.2.12
++
++ -- GTDT (Generic Timer Description Table), section 5.2.24
++
++ -- If PCI is supported, the MCFG (Memory mapped ConFiGuration
++ Table), section 5.2.6, specifically Table 5-31.
++
++If the above tables are not all present, the kernel may or may not be
++able to boot properly since it may not be able to configure all of the
++devices available.
++
++
++ACPI Detection
++--------------
++Drivers should determine their probe() type by checking for a null
++value for ACPI_HANDLE, or checking .of_node, or other information in
++the device structure. This is detailed further in the "Driver
++Recommendations" section.
++
++In non-driver code, if the presence of ACPI needs to be detected at
++runtime, then check the value of acpi_disabled. If CONFIG_ACPI is not
++set, acpi_disabled will always be 1.
++
++
++Device Enumeration
++------------------
++Device descriptions in ACPI should use standard recognized ACPI interfaces.
++These can contain less information than is typically provided via a Device
++Tree description for the same device. This is also one of the reasons that
++ACPI can be useful -- the driver takes into account that it may have less
++detailed information about the device and uses sensible defaults instead.
++If done properly in the driver, the hardware can change and improve over
++time without the driver having to change at all.
++
++Clocks provide an excellent example. In DT, clocks need to be specified
++and the drivers need to take them into account. In ACPI, the assumption
++is that UEFI will leave the device in a reasonable default state, including
++any clock settings. If for some reason the driver needs to change a clock
++value, this can be done in an ACPI method; all the driver needs to do is
++invoke the method and not concern itself with what the method needs to do
++to change the clock. Changing the hardware can then take place over time
++by changing what the ACPI method does, and not the driver.
++
++ACPI drivers should only look at one specific ASL object -- the _DSD object
++-- for device driver parameters (known in DT as "bindings", or "Device
++Properties" in ACPI). Not all DT bindings will be recognized. The UEFI
++Forum provides a mechanism for registering such bindings [URL TBD by ASWG]
++so that they may be used on any operating system supporting ACPI. Device
++properties that have not been registered with the UEFI Forum should not be
++used.
++
++Drivers should look for device properties in the _DSD object ONLY; the _DSD
++object is described in the ACPI specification section 6.2.5, but more
++specifically, use the _DSD Device Properties UUID:
++
++ -- UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301
++
++ -- http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf)
++
++The kernel has an interface for looking up device properties in a manner
++independent of whether DT or ACPI is being used and that interface should
++be used; it can eliminate some duplication of code paths in driver probing
++functions and discourage divergence between DT bindings and ACPI device
++properties.
++
++ACPI tables are described with a formal language called ASL, the ACPI
++Source Language (section 19 of the specification). This means that there
++are always multiple ways to describe the same thing -- including device
++properties. For example, device properties could use an ASL construct
++that looks like this: Name(KEY0, "value0"). An ACPI device driver would
++then retrieve the value of the property by evaluating the KEY0 object.
++However, using Name() this way has multiple problems: (1) ACPI limits
++names ("KEY0") to four characters unlike DT; (2) there is no industry
++wide registry that maintains a list of names, minimzing re-use; (3)
++there is also no registry for the definition of property values ("value0"),
++again making re-use difficult; and (4) how does one maintain backward
++compatibility as new hardware comes out? The _DSD method was created
++to solve precisely these sorts of problems; Linux drivers should ALWAYS
++use the _DSD method for device properties and nothing else.
++
++The _DSM object (ACPI Section 9.14.1) could also be used for conveying
++device properties to a driver. Linux drivers should only expect it to
++be used if _DSD cannot represent the data required, and there is no way
++to create a new UUID for the _DSD object. Note that there is even less
++regulation of the use of _DSM than there is of _DSD. Drivers that depend
++on the contents of _DSM objects will be more difficult to maintain over
++time because of this.
++
++The _DSD object is a very flexible mechanism in ACPI, as are the registered
++Device Properties. This flexibility allows _DSD to cover more than just the
++generic server case and care should be taken in device drivers not to expect
++it to replicate highly specific embedded behaviour from DT.
++
++Both DT bindings and ACPI device properties for device drivers have review
++processes. Use them. And, before creating new device properties, check to
++be sure that they have not been defined before and either registered in the
++Linux kernel documentation or the UEFI Forum. If the device drivers supports
++ACPI and DT, please make sure the device properties are consistent in both
++places.
++
++
++Programmable Power Control Resources
++------------------------------------
++Programmable power control resources include such resources as voltage/current
++providers (regulators) and clock sources.
++
++The kernel assumes that power control of these resources is represented with
++Power Resource Objects (ACPI section 7.1). The ACPI core will then handle
++correctly enabling and disabling resources as they are needed. In order to
++get that to work, ACPI assumes each device has defined D-states and that these
++can be controlled through the optional ACPI methods _PS0, _PS1, _PS2, and _PS3;
++in ACPI, _PS0 is the method to invoke to turn a device full on, and _PS3 is for
++turning a device full off.
++
++The kernel ACPI code will also assume that the _PS? methods follow the normal
++ACPI rules for such methods:
++
++ -- If either _PS0 or _PS3 is implemented, then the other method must also
++ be implemented.
++
++ -- If a device requires usage or setup of a power resource when on, the ASL
++ should organize that it is allocated/enabled using the _PS0 method.
++
++ -- Resources allocated or enabled in the _PS0 method should be disabled
++ or de-allocated in the _PS3 method.
++
++ -- Firmware will leave the resources in a reasonable state before handing
++ over control to the kernel.
++
++Such code in _PS? methods will of course be very platform specific. But,
++this allows the driver to abstract out the interface for operating the device
++and avoid having to read special non-standard values from ACPI tables. Further,
++abstracting the use of these resources allows the hardware to change over time
++without requiring updates to the driver.
++
++
++Clocks
++------
++ACPI makes the assumption that clocks are initialized by the firmware --
++UEFI, in this case -- to some working value before control is handed over
++to the kernel. This has implications for devices such as UARTs, or SoC
++driven LCD displays, for example.
++
++When the kernel boots, the clock is assumed to be set to reasonable
++working value. If for some reason the frequency needs to change -- e.g.,
++throttling for power management -- the device driver should expect that
++process to be abstracted out into some ACPI method that can be invoked
++(please see the ACPI specification for further recommendations on standard
++methods to be expected). If is not, there is no direct way for ACPI to
++control the clocks.
++
++
++Driver Recommendations
++----------------------
++DO NOT remove any DT handling when adding ACPI support for a driver. The
++same device may be used on many different systems.
++
++DO try to structure the driver so that it is data driven. That is, set up
++a struct containing internal per-device state based on defaults and whatever
++else must be discovered by the driver probe function. Then, have the rest
++of the driver operate off of the contents of that struct. Doing so should
++allow most divergence between ACPI and DT functionality to be kept local to
++the probe function instead of being scattered throughout the driver. For
++example:
++
++static int device_probe_dt(struct platform_device *pdev)
++{
++ /* DT specific functionality */
++ ...
++}
++
++static int device_probe_acpi(struct platform_device *pdev)
++{
++ /* ACPI specific functionality */
++ ...
++}
+
-+&menet {
-+ status = "ok";
-+};
++static int device_probe(stuct platform_device *pdev)
++{
++ ...
++ struct device_node node = pdev->dev.of_node;
++ ...
++
++ if (node)
++ ret = device_probe_dt(pdev);
++ else if (ACPI_HANDLE(&pdev->dev))
++ ret = device_probe_acpi(pdev);
++ else
++ /* other initialization */
++ ...
++ /* Continue with any generic probe operations */
++ ...
++}
++
++DO keep the MODULE_DEVICE_TABLE entries together in the driver to make it
++clear the different names the driver is probed for, both from DT and from
++ACPI:
+
-+&pcie0clk {
-+ status = "ok";
++static struct of_device_id virtio_mmio_match[] = {
++ { .compatible = "virtio,mmio", },
++ { }
+};
++MODULE_DEVICE_TABLE(of, virtio_mmio_match);
+
-+&pcie0 {
-+ status = "ok";
++static const struct acpi_device_id virtio_mmio_acpi_match[] = {
++ { "LNRO0005", },
++ { }
+};
-diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
-index 40aa96c..fb2ee54 100644
---- a/arch/arm64/boot/dts/apm-storm.dtsi
-+++ b/arch/arm64/boot/dts/apm-storm.dtsi
-@@ -24,56 +24,56 @@
- compatible = "apm,potenza", "arm,armv8";
- reg = <0x0 0x000>;
- enable-method = "spin-table";
-- cpu-release-addr = <0x1 0x0000fff8>;
-+ cpu-release-addr = <0x40 0x0000f000>;
- };
- cpu@001 {
- device_type = "cpu";
- compatible = "apm,potenza", "arm,armv8";
- reg = <0x0 0x001>;
- enable-method = "spin-table";
-- cpu-release-addr = <0x1 0x0000fff8>;
-+ cpu-release-addr = <0x40 0x0000f000>;
- };
- cpu@100 {
- device_type = "cpu";
- compatible = "apm,potenza", "arm,armv8";
- reg = <0x0 0x100>;
- enable-method = "spin-table";
-- cpu-release-addr = <0x1 0x0000fff8>;
-+ cpu-release-addr = <0x40 0x0000f000>;
- };
- cpu@101 {
- device_type = "cpu";
- compatible = "apm,potenza", "arm,armv8";
- reg = <0x0 0x101>;
- enable-method = "spin-table";
-- cpu-release-addr = <0x1 0x0000fff8>;
-+ cpu-release-addr = <0x40 0x0000f000>;
- };
- cpu@200 {
- device_type = "cpu";
- compatible = "apm,potenza", "arm,armv8";
- reg = <0x0 0x200>;
- enable-method = "spin-table";
-- cpu-release-addr = <0x1 0x0000fff8>;
-+ cpu-release-addr = <0x40 0x0000f000>;
- };
- cpu@201 {
- device_type = "cpu";
- compatible = "apm,potenza", "arm,armv8";
- reg = <0x0 0x201>;
- enable-method = "spin-table";
-- cpu-release-addr = <0x1 0x0000fff8>;
-+ cpu-release-addr = <0x40 0x0000f000>;
- };
- cpu@300 {
- device_type = "cpu";
- compatible = "apm,potenza", "arm,armv8";
- reg = <0x0 0x300>;
- enable-method = "spin-table";
-- cpu-release-addr = <0x1 0x0000fff8>;
-+ cpu-release-addr = <0x40 0x0000f000>;
- };
- cpu@301 {
- device_type = "cpu";
- compatible = "apm,potenza", "arm,armv8";
- reg = <0x0 0x301>;
- enable-method = "spin-table";
-- cpu-release-addr = <0x1 0x0000fff8>;
-+ cpu-release-addr = <0x40 0x0000f000>;
- };
- };
-
-@@ -97,6 +97,11 @@
- clock-frequency = <50000000>;
- };
-
-+ pmu {
-+ compatible = "arm,armv8-pmuv3";
-+ interrupts = <1 12 0xff04>;
-+ };
++MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match);
++
++
++ASWG
++----
++The following areas are not yet fully defined for ARM in the 5.1 version
++of the ACPI specification and are expected to be worked through in the
++UEFI ACPI Specification Working Group (ASWG):
++
++ -- ACPI based CPU topology
++ -- ACPI based Power management
++ -- CPU idle control based on PSCI
++ -- CPU performance control (CPPC)
++ -- ACPI based SMMU
++ -- ITS support for GIC in MADT
++
++Participation in this group is open to all UEFI members. Please see
++http://www.uefi.org/workinggroup for details on group membership.
++
++It is the intent of the ARMv8 ACPI kernel code to follow the ACPI specification
++as closely as possible, and to only implement functionality that complies with
++the released standards from UEFI ASWG. As a practical matter, there will be
++vendors that provide bad ACPI tables or violate the standards in some way.
++If this is because of errors, quirks and fixups may be necessary, but will
++be avoided if possible. If there are features missing from ACPI that preclude
++it from being used on a platform, ECRs (Engineering Change Requests) should be
++submitted to ASWG and go through the normal approval process; for those that
++are not UEFI members, many other members of the Linux community are and would
++likely be willing to assist in submitting ECRs.
+diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt
+index 6ce5441..859918d 100644
+--- a/Documentation/gpio/consumer.txt
++++ b/Documentation/gpio/consumer.txt
+@@ -219,6 +219,24 @@ part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are system wakeup
+ capabilities.
+
+
++GPIOs and ACPI
++==============
++
++On ACPI systems, GPIOs are described by GpioIo()/GpioInt() resources listed by
++the _CRS configuration objects of devices. Those resources do not provide
++connection IDs (names) for GPIOs, so it is necessary to use an additional
++mechanism for this purpose.
++
++Systems compliant with ACPI 5.1 or newer may provide a _DSD configuration object
++which, among other things, may be used to provide connection IDs for specific
++GPIOs described by the GpioIo()/GpioInt() resources in _CRS. If that is the
++case, it will be handled by the GPIO subsystem automatically. However, if the
++_DSD is not present, the mappings between GpioIo()/GpioInt() resources and GPIO
++connection IDs need to be provided by device drivers.
++
++For details refer to Documentation/acpi/gpio-properties.txt
++
++
+ Interacting With the Legacy GPIO Subsystem
+ ==========================================
+ Many kernel subsystems still handle GPIOs using the legacy integer-based
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 479f332..6187d9b 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -165,7 +165,7 @@ multipliers 'Kilo', 'Mega', and 'Giga', equalling 2^10, 2^20, and 2^30
+ bytes respectively. Such letter suffixes can also be entirely omitted.
+
+
+- acpi= [HW,ACPI,X86]
++ acpi= [HW,ACPI,X86,ARM64]
+ Advanced Configuration and Power Interface
+ Format: { force | off | strict | noirq | rsdt }
+ force -- enable ACPI if default was off
+@@ -175,6 +175,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
+ strictly ACPI specification compliant.
+ rsdt -- prefer RSDT over (default) XSDT
+ copy_dsdt -- copy DSDT to memory
++ For ARM64, ONLY "acpi=off" or "acpi=force" are available
+
+ See also Documentation/power/runtime_pm.txt, pci=noacpi
+
+diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
+index acb0d57..f867060 100644
+--- a/arch/arm/include/asm/kvm_mmu.h
++++ b/arch/arm/include/asm/kvm_mmu.h
+@@ -161,9 +161,10 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
+ }
+
+ static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
+- unsigned long size)
++ unsigned long size,
++ bool ipa_uncached)
+ {
+- if (!vcpu_has_cache_enabled(vcpu))
++ if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
+ kvm_flush_dcache_to_poc((void *)hva, size);
+
+ /*
+diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
+index 8664ff1..8fa2060 100644
+--- a/arch/arm/kvm/mmu.c
++++ b/arch/arm/kvm/mmu.c
+@@ -853,6 +853,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ struct vm_area_struct *vma;
+ pfn_t pfn;
+ pgprot_t mem_type = PAGE_S2;
++ bool fault_ipa_uncached;
+
+ write_fault = kvm_is_write_fault(vcpu);
+ if (fault_status == FSC_PERM && !write_fault) {
+@@ -919,6 +920,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ if (!hugetlb && !force_pte)
+ hugetlb = transparent_hugepage_adjust(&pfn, &fault_ipa);
+
++ fault_ipa_uncached = memslot->flags & KVM_MEMSLOT_INCOHERENT;
++
+ if (hugetlb) {
+ pmd_t new_pmd = pfn_pmd(pfn, mem_type);
+ new_pmd = pmd_mkhuge(new_pmd);
+@@ -926,7 +929,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ kvm_set_s2pmd_writable(&new_pmd);
+ kvm_set_pfn_dirty(pfn);
+ }
+- coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE);
++ coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE,
++ fault_ipa_uncached);
+ ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
+ } else {
+ pte_t new_pte = pfn_pte(pfn, mem_type);
+@@ -934,7 +938,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ kvm_set_s2pte_writable(&new_pte);
+ kvm_set_pfn_dirty(pfn);
+ }
+- coherent_cache_guest_page(vcpu, hva, PAGE_SIZE);
++ coherent_cache_guest_page(vcpu, hva, PAGE_SIZE,
++ fault_ipa_uncached);
+ ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte,
+ pgprot_val(mem_type) == pgprot_val(PAGE_S2_DEVICE));
+ }
+@@ -1245,6 +1250,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
+ (KVM_PHYS_SIZE >> PAGE_SHIFT))
+ return -EFAULT;
+
++ spin_lock(&kvm->mmu_lock);
++ stage2_flush_memslot(kvm, memslot);
++ spin_unlock(&kvm->mmu_lock);
+
- soc {
- compatible = "simple-bus";
- #address-cells = <2>;
-@@ -167,14 +172,13 @@
- clock-output-names = "ethclk";
- };
-
-- eth8clk: eth8clk {
-+ menetclk: menetclk {
- compatible = "apm,xgene-device-clock";
- #clock-cells = <1>;
- clocks = <&ethclk 0>;
-- clock-names = "eth8clk";
- reg = <0x0 0x1702C000 0x0 0x1000>;
- reg-names = "csr-reg";
-- clock-output-names = "eth8clk";
-+ clock-output-names = "menetclk";
- };
-
- sataphy1clk: sataphy1clk@1f21c000 {
-@@ -270,6 +274,161 @@
- enable-mask = <0x2>;
- clock-output-names = "rtcclk";
- };
-+
-+ pcie0clk: pcie0clk@1f2bc000 {
-+ status = "disabled";
-+ compatible = "apm,xgene-device-clock";
-+ #clock-cells = <1>;
-+ clocks = <&socplldiv2 0>;
-+ reg = <0x0 0x1f2bc000 0x0 0x1000>;
-+ reg-names = "csr-reg";
-+ clock-output-names = "pcie0clk";
-+ };
-+
-+ pcie1clk: pcie1clk@1f2cc000 {
-+ status = "disabled";
-+ compatible = "apm,xgene-device-clock";
-+ #clock-cells = <1>;
-+ clocks = <&socplldiv2 0>;
-+ reg = <0x0 0x1f2cc000 0x0 0x1000>;
-+ reg-names = "csr-reg";
-+ clock-output-names = "pcie1clk";
-+ };
-+
-+ pcie2clk: pcie2clk@1f2dc000 {
-+ status = "disabled";
-+ compatible = "apm,xgene-device-clock";
-+ #clock-cells = <1>;
-+ clocks = <&socplldiv2 0>;
-+ reg = <0x0 0x1f2dc000 0x0 0x1000>;
-+ reg-names = "csr-reg";
-+ clock-output-names = "pcie2clk";
-+ };
-+
-+ pcie3clk: pcie3clk@1f50c000 {
-+ status = "disabled";
-+ compatible = "apm,xgene-device-clock";
-+ #clock-cells = <1>;
-+ clocks = <&socplldiv2 0>;
-+ reg = <0x0 0x1f50c000 0x0 0x1000>;
-+ reg-names = "csr-reg";
-+ clock-output-names = "pcie3clk";
-+ };
-+
-+ pcie4clk: pcie4clk@1f51c000 {
-+ status = "disabled";
-+ compatible = "apm,xgene-device-clock";
-+ #clock-cells = <1>;
-+ clocks = <&socplldiv2 0>;
-+ reg = <0x0 0x1f51c000 0x0 0x1000>;
-+ reg-names = "csr-reg";
-+ clock-output-names = "pcie4clk";
-+ };
-+ };
-+
-+ pcie0: pcie@1f2b0000 {
-+ status = "disabled";
-+ device_type = "pci";
-+ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
-+ #interrupt-cells = <1>;
-+ #size-cells = <2>;
-+ #address-cells = <3>;
-+ reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
-+ 0xe0 0xd0000000 0x0 0x00200000>; /* PCI config space */
-+ reg-names = "csr", "cfg";
-+ ranges = <0x01000000 0x00 0x00000000 0xe0 0x00000000 0x00 0x00010000 /* io */
-+ 0x02000000 0x00 0x10000000 0xe0 0x10000000 0x00 0x80000000>; /* mem */
-+ dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
-+ 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
-+ 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
-+ 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
-+ clocks = <&pcie0clk 0>;
-+ };
-+
-+ pcie1: pcie@1f2c0000 {
-+ status = "disabled";
-+ device_type = "pci";
-+ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
-+ #interrupt-cells = <1>;
-+ #size-cells = <2>;
-+ #address-cells = <3>;
-+ reg = < 0x00 0x1f2c0000 0x0 0x00010000 /* Controller registers */
-+ 0xd0 0xd0000000 0x0 0x00200000>; /* PCI config space */
-+ reg-names = "csr", "cfg";
-+ ranges = <0x01000000 0x0 0x00000000 0xd0 0x00000000 0x00 0x00010000 /* io */
-+ 0x02000000 0x0 0x10000000 0xd0 0x10000000 0x00 0x80000000>; /* mem */
-+ dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1
-+ 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1
-+ 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1
-+ 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>;
-+ clocks = <&pcie1clk 0>;
-+ };
-+
-+ pcie2: pcie@1f2d0000 {
-+ status = "disabled";
-+ device_type = "pci";
-+ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
-+ #interrupt-cells = <1>;
-+ #size-cells = <2>;
-+ #address-cells = <3>;
-+ reg = < 0x00 0x1f2d0000 0x0 0x00010000 /* Controller registers */
-+ 0x90 0xd0000000 0x0 0x00200000>; /* PCI config space */
-+ reg-names = "csr", "cfg";
-+ ranges = <0x01000000 0x0 0x00000000 0x90 0x00000000 0x0 0x00010000 /* io */
-+ 0x02000000 0x0 0x10000000 0x90 0x10000000 0x0 0x80000000>; /* mem */
-+ dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1
-+ 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1
-+ 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1
-+ 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>;
-+ clocks = <&pcie2clk 0>;
-+ };
-+
-+ pcie3: pcie@1f500000 {
-+ status = "disabled";
-+ device_type = "pci";
-+ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
-+ #interrupt-cells = <1>;
-+ #size-cells = <2>;
-+ #address-cells = <3>;
-+ reg = < 0x00 0x1f500000 0x0 0x00010000 /* Controller registers */
-+ 0xa0 0xd0000000 0x0 0x00200000>; /* PCI config space */
-+ reg-names = "csr", "cfg";
-+ ranges = <0x01000000 0x0 0x00000000 0xa0 0x00000000 0x0 0x00010000 /* io */
-+ 0x02000000 0x0 0x10000000 0xa0 0x10000000 0x0 0x80000000>; /* mem */
-+ dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1
-+ 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1
-+ 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1
-+ 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>;
-+ clocks = <&pcie3clk 0>;
-+ };
-+
-+ pcie4: pcie@1f510000 {
-+ status = "disabled";
-+ device_type = "pci";
-+ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
-+ #interrupt-cells = <1>;
-+ #size-cells = <2>;
-+ #address-cells = <3>;
-+ reg = < 0x00 0x1f510000 0x0 0x00010000 /* Controller registers */
-+ 0xc0 0xd0000000 0x0 0x00200000>; /* PCI config space */
-+ reg-names = "csr", "cfg";
-+ ranges = <0x01000000 0x0 0x00000000 0xc0 0x00000000 0x0 0x00010000 /* io */
-+ 0x02000000 0x0 0x10000000 0xc0 0x10000000 0x0 0x80000000>; /* mem */
-+ dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1
-+ 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1
-+ 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1
-+ 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>;
-+ clocks = <&pcie4clk 0>;
- };
-
- serial0: serial@1c020000 {
-@@ -278,7 +437,7 @@
- compatible = "ns16550a";
- reg = <0 0x1c020000 0x0 0x1000>;
- reg-shift = <2>;
-- clock-frequency = <10000000>; /* Updated by bootloader */
-+ clock-frequency = <50000000>; /* Updated by bootloader */
- interrupt-parent = <&gic>;
- interrupts = <0x0 0x4c 0x4>;
- };
-@@ -397,5 +556,30 @@
- #clock-cells = <1>;
- clocks = <&rtcclk 0>;
- };
-+
-+ menet: ethernet@17020000 {
-+ compatible = "apm,xgene-enet";
-+ status = "disabled";
-+ reg = <0x0 0x17020000 0x0 0xd100>,
-+ <0x0 0X17030000 0x0 0X400>,
-+ <0x0 0X10000000 0x0 0X200>;
-+ reg-names = "enet_csr", "ring_csr", "ring_cmd";
-+ interrupts = <0x0 0x3c 0x4>;
-+ dma-coherent;
-+ clocks = <&menetclk 0>;
-+ local-mac-address = [00 00 00 00 00 00];
-+ phy-connection-type = "rgmii";
-+ phy-handle = <&menetphy>;
-+ mdio {
-+ compatible = "apm,xgene-mdio";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ menetphy: menetphy@3 {
-+ compatible = "ethernet-phy-id001c.c915";
-+ reg = <0x3>;
-+ };
-+
-+ };
-+ };
- };
- };
-diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
-index 0b3fcf8..07cb417 100644
---- a/arch/arm64/include/asm/Kbuild
-+++ b/arch/arm64/include/asm/Kbuild
-@@ -29,6 +29,7 @@ generic-y += mman.h
- generic-y += msgbuf.h
- generic-y += mutex.h
- generic-y += pci.h
-+generic-y += pci-bridge.h
- generic-y += poll.h
- generic-y += preempt.h
- generic-y += resource.h
-diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
-index 01d3aab..8186df6 100644
---- a/arch/arm64/include/asm/elf.h
-+++ b/arch/arm64/include/asm/elf.h
-@@ -114,7 +114,8 @@ typedef struct user_fpsimd_state elf_fpregset_t;
- */
- #define elf_check_arch(x) ((x)->e_machine == EM_AARCH64)
+ /*
+ * A memory region could potentially cover multiple VMAs, and any holes
+ * between them, so iterate over all of them to find out if we can map
+@@ -1310,6 +1319,15 @@ void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
+ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
+ unsigned long npages)
+ {
++ /*
++ * Readonly memslots are not incoherent with the caches by definition,
++ * but in practice, they are used mostly to emulate ROMs or NOR flashes
++ * that the guest may consider devices and hence map as uncached.
++ * To prevent incoherency issues in these cases, tag all readonly
++ * regions as incoherent.
++ */
++ if (slot->flags & KVM_MEM_READONLY)
++ slot->flags |= KVM_MEMSLOT_INCOHERENT;
+ return 0;
+ }
--#define elf_read_implies_exec(ex,stk) (stk != EXSTACK_DISABLE_X)
-+#define elf_read_implies_exec(ex,stk) (test_thread_flag(TIF_32BIT) \
-+ ? (stk == EXSTACK_ENABLE_X) : 0)
+diff --git a/arch/arm/mach-s3c24xx/h1940-bluetooth.c b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
+index b4d14b8..9c8b127 100644
+--- a/arch/arm/mach-s3c24xx/h1940-bluetooth.c
++++ b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
+@@ -41,7 +41,7 @@ static void h1940bt_enable(int on)
+ mdelay(10);
+ gpio_set_value(S3C2410_GPH(1), 0);
- #define CORE_DUMP_USE_REGSET
- #define ELF_EXEC_PAGESIZE PAGE_SIZE
-diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
-index e0ecdcf..dc34039 100644
---- a/arch/arm64/include/asm/io.h
-+++ b/arch/arm64/include/asm/io.h
-@@ -121,7 +121,8 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
- /*
- * I/O port access primitives.
- */
--#define IO_SPACE_LIMIT 0xffff
-+#define arch_has_dev_port() (1)
-+#define IO_SPACE_LIMIT 0x1ffffff
- #define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_32M))
+- h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL);
++ h1940_led_blink_set(NULL, GPIO_LED_BLINK, NULL, NULL);
+ }
+ else {
+ gpio_set_value(S3C2410_GPH(1), 1);
+@@ -50,7 +50,7 @@ static void h1940bt_enable(int on)
+ mdelay(10);
+ gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
+
+- h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
++ h1940_led_blink_set(NULL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
+ }
+ }
- static inline u8 inb(unsigned long addr)
-diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
-index 3d69030..cc83520 100644
---- a/arch/arm64/include/asm/kvm_arm.h
-+++ b/arch/arm64/include/asm/kvm_arm.h
-@@ -76,9 +76,10 @@
- */
- #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
- HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
-- HCR_AMO | HCR_IMO | HCR_FMO | \
-- HCR_SWIO | HCR_TIDCP | HCR_RW)
-+ HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW)
- #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
-+#define HCR_INT_OVERRIDE (HCR_FMO | HCR_IMO)
-+
-
- /* Hyp System Control Register (SCTLR_EL2) bits */
- #define SCTLR_EL2_EE (1 << 25)
-diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
-index 9fcd54b..a28c35b 100644
---- a/arch/arm64/include/asm/kvm_asm.h
-+++ b/arch/arm64/include/asm/kvm_asm.h
-@@ -18,6 +18,8 @@
- #ifndef __ARM_KVM_ASM_H__
- #define __ARM_KVM_ASM_H__
-
-+#include <asm/virt.h>
-+
- /*
- * 0 is reserved as an invalid value.
- * Order *must* be kept in sync with the hyp switch code.
-@@ -96,13 +98,21 @@ extern char __kvm_hyp_init_end[];
+diff --git a/arch/arm/mach-s3c24xx/h1940.h b/arch/arm/mach-s3c24xx/h1940.h
+index 2950cc4..596d9f6 100644
+--- a/arch/arm/mach-s3c24xx/h1940.h
++++ b/arch/arm/mach-s3c24xx/h1940.h
+@@ -19,8 +19,10 @@
+ #define H1940_SUSPEND_RESUMEAT (0x30081000)
+ #define H1940_SUSPEND_CHECK (0x30080000)
+
++struct gpio_desc;
++
+ extern void h1940_pm_return(void);
+-extern int h1940_led_blink_set(unsigned gpio, int state,
++extern int h1940_led_blink_set(struct gpio_desc *desc, int state,
+ unsigned long *delay_on,
+ unsigned long *delay_off);
+
+diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
+index d35ddc1..d40d4f5 100644
+--- a/arch/arm/mach-s3c24xx/mach-h1940.c
++++ b/arch/arm/mach-s3c24xx/mach-h1940.c
+@@ -359,10 +359,11 @@ static struct platform_device h1940_battery = {
+
+ static DEFINE_SPINLOCK(h1940_blink_spin);
+
+-int h1940_led_blink_set(unsigned gpio, int state,
++int h1940_led_blink_set(struct gpio_desc *desc, int state,
+ unsigned long *delay_on, unsigned long *delay_off)
+ {
+ int blink_gpio, check_gpio1, check_gpio2;
++ int gpio = desc ? desc_to_gpio(desc) : -EINVAL;
+
+ switch (gpio) {
+ case H1940_LATCH_LED_GREEN:
+diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
+index c3f2682..1d35ff3 100644
+--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
++++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
+@@ -250,9 +250,10 @@ static void rx1950_disable_charger(void)
+
+ static DEFINE_SPINLOCK(rx1950_blink_spin);
+
+-static int rx1950_led_blink_set(unsigned gpio, int state,
++static int rx1950_led_blink_set(struct gpio_desc *desc, int state,
+ unsigned long *delay_on, unsigned long *delay_off)
+ {
++ int gpio = desc_to_gpio(desc);
+ int blink_gpio, check_gpio;
- extern char __kvm_hyp_vector[];
+ switch (gpio) {
+diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
+index e048f61..e53fc8d 100644
+--- a/arch/arm/plat-orion/gpio.c
++++ b/arch/arm/plat-orion/gpio.c
+@@ -306,9 +306,10 @@ EXPORT_SYMBOL(orion_gpio_set_blink);
--extern char __kvm_hyp_code_start[];
--extern char __kvm_hyp_code_end[];
-+#define __kvm_hyp_code_start __hyp_text_start
-+#define __kvm_hyp_code_end __hyp_text_end
+ #define ORION_BLINK_HALF_PERIOD 100 /* ms */
- extern void __kvm_flush_vm_context(void);
- extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
+-int orion_gpio_led_blink_set(unsigned gpio, int state,
++int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
+ unsigned long *delay_on, unsigned long *delay_off)
+ {
++ unsigned gpio = desc_to_gpio(desc);
+
+ if (delay_on && delay_off && !*delay_on && !*delay_off)
+ *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
+diff --git a/arch/arm/plat-orion/include/plat/orion-gpio.h b/arch/arm/plat-orion/include/plat/orion-gpio.h
+index e763988..e856b07 100644
+--- a/arch/arm/plat-orion/include/plat/orion-gpio.h
++++ b/arch/arm/plat-orion/include/plat/orion-gpio.h
+@@ -14,12 +14,15 @@
+ #include <linux/init.h>
+ #include <linux/types.h>
+ #include <linux/irqdomain.h>
++
++struct gpio_desc;
++
+ /*
+ * Orion-specific GPIO API extensions.
+ */
+ void orion_gpio_set_unused(unsigned pin);
+ void orion_gpio_set_blink(unsigned pin, int blink);
+-int orion_gpio_led_blink_set(unsigned gpio, int state,
++int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
+ unsigned long *delay_on, unsigned long *delay_off);
- extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+ #define GPIO_INPUT_OK (1 << 0)
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index 9532f8d..80a82ac 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -4,6 +4,7 @@ config ARM64
+ select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+ select ARCH_HAS_SG_CHAIN
+ select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
++ select ACPI_REDUCED_HARDWARE_ONLY if ACPI
+ select ARCH_USE_CMPXCHG_LOCKREF
+ select ARCH_SUPPORTS_ATOMIC_RMW
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+@@ -34,6 +35,7 @@ config ARM64
+ select GENERIC_TIME_VSYSCALL
+ select HANDLE_DOMAIN_IRQ
+ select HARDIRQS_SW_RESEND
++ select HAVE_ALIGNED_STRUCT_PAGE if SLUB
+ select HAVE_ARCH_AUDITSYSCALL
+ select HAVE_ARCH_JUMP_LABEL
+ select HAVE_ARCH_KGDB
+@@ -41,6 +43,7 @@ config ARM64
+ select HAVE_BPF_JIT
+ select HAVE_C_RECORDMCOUNT
+ select HAVE_CC_STACKPROTECTOR
++ select HAVE_CMPXCHG_DOUBLE
+ select HAVE_DEBUG_BUGVERBOSE
+ select HAVE_DEBUG_KMEMLEAK
+ select HAVE_DMA_API_DEBUG
+@@ -185,6 +188,9 @@ config PCI_DOMAINS_GENERIC
+ config PCI_SYSCALL
+ def_bool PCI
+
++config PCI_MMCONFIG
++ def_bool y if PCI && ACPI
++
+ source "drivers/pci/Kconfig"
+ source "drivers/pci/pcie/Kconfig"
+ source "drivers/pci/hotplug/Kconfig"
+@@ -268,6 +274,9 @@ config SMP
+
+ If you don't know what to do here, say N.
+
++config ARM_PARKING_PROTOCOL
++ def_bool y if SMP
++
+ config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on SMP
+@@ -401,6 +410,17 @@ config EFI
+ allow the kernel to be booted as an EFI application. This
+ is only useful on systems that have UEFI firmware.
+
++config DMI
++ bool "Enable support for SMBIOS (DMI) tables"
++ depends on EFI
++ default y
++ help
++ This enables SMBIOS/DMI feature for systems.
+
-+extern u64 __vgic_v3_get_ich_vtr_el2(void);
++ This option is only useful on systems that have UEFI firmware.
++ However, even with this option, the resultant kernel should
++ continue to boot on existing non-UEFI platforms.
+
-+extern char __save_vgic_v2_state[];
-+extern char __restore_vgic_v2_state[];
-+extern char __save_vgic_v3_state[];
-+extern char __restore_vgic_v3_state[];
+ endmenu
+
+ menu "Userspace binary formats"
+@@ -454,6 +474,8 @@ source "drivers/Kconfig"
+
+ source "drivers/firmware/Kconfig"
+
++source "drivers/acpi/Kconfig"
++
+ source "fs/Kconfig"
+
+ source "arch/arm64/kvm/Kconfig"
+diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
+index 20901ff..983d72a 100644
+--- a/arch/arm64/Makefile
++++ b/arch/arm64/Makefile
+@@ -49,6 +49,7 @@ core-$(CONFIG_NET) += arch/arm64/net/
+ core-$(CONFIG_KVM) += arch/arm64/kvm/
+ core-$(CONFIG_XEN) += arch/arm64/xen/
+ core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
++drivers-$(CONFIG_PCI) += arch/arm64/pci/
+ libs-y := arch/arm64/lib/ $(libs-y)
+ libs-y += $(LIBGCC)
+ libs-$(CONFIG_EFI_STUB) += drivers/firmware/efi/libstub/
+diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig
+index 5562652..a38b02c 100644
+--- a/arch/arm64/crypto/Kconfig
++++ b/arch/arm64/crypto/Kconfig
+@@ -27,20 +27,19 @@ config CRYPTO_AES_ARM64_CE
+ tristate "AES core cipher using ARMv8 Crypto Extensions"
+ depends on ARM64 && KERNEL_MODE_NEON
+ select CRYPTO_ALGAPI
+- select CRYPTO_AES
+
+ config CRYPTO_AES_ARM64_CE_CCM
+ tristate "AES in CCM mode using ARMv8 Crypto Extensions"
+ depends on ARM64 && KERNEL_MODE_NEON
+ select CRYPTO_ALGAPI
+- select CRYPTO_AES
++ select CRYPTO_AES_ARM64_CE
+ select CRYPTO_AEAD
+
+ config CRYPTO_AES_ARM64_CE_BLK
+ tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions"
+ depends on ARM64 && KERNEL_MODE_NEON
+ select CRYPTO_BLKCIPHER
+- select CRYPTO_AES
++ select CRYPTO_AES_ARM64_CE
+ select CRYPTO_ABLK_HELPER
+
+ config CRYPTO_AES_ARM64_NEON_BLK
+diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c
+index 9e6cdde..0ac73b8 100644
+--- a/arch/arm64/crypto/aes-ce-ccm-glue.c
++++ b/arch/arm64/crypto/aes-ce-ccm-glue.c
+@@ -16,6 +16,8 @@
+ #include <linux/crypto.h>
+ #include <linux/module.h>
+
++#include "aes-ce-setkey.h"
+
- #endif
+ static int num_rounds(struct crypto_aes_ctx *ctx)
+ {
+ /*
+@@ -48,7 +50,7 @@ static int ccm_setkey(struct crypto_aead *tfm, const u8 *in_key,
+ struct crypto_aes_ctx *ctx = crypto_aead_ctx(tfm);
+ int ret;
- #endif /* __ARM_KVM_ASM_H__ */
-diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
-index 92242ce..4ae9213 100644
---- a/arch/arm64/include/asm/kvm_host.h
-+++ b/arch/arm64/include/asm/kvm_host.h
-@@ -200,4 +200,32 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
- hyp_stack_ptr, vector_ptr);
+- ret = crypto_aes_expand_key(ctx, in_key, key_len);
++ ret = ce_aes_expandkey(ctx, in_key, key_len);
+ if (!ret)
+ return 0;
+
+diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-cipher.c
+index 2075e1a..ce47792 100644
+--- a/arch/arm64/crypto/aes-ce-cipher.c
++++ b/arch/arm64/crypto/aes-ce-cipher.c
+@@ -14,6 +14,8 @@
+ #include <linux/crypto.h>
+ #include <linux/module.h>
+
++#include "aes-ce-setkey.h"
++
+ MODULE_DESCRIPTION("Synchronous AES cipher using ARMv8 Crypto Extensions");
+ MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+ MODULE_LICENSE("GPL v2");
+@@ -124,6 +126,114 @@ static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[])
+ kernel_neon_end();
}
-+struct vgic_sr_vectors {
-+ void *save_vgic;
-+ void *restore_vgic;
-+};
++/*
++ * aes_sub() - use the aese instruction to perform the AES sbox substitution
++ * on each byte in 'input'
++ */
++static u32 aes_sub(u32 input)
++{
++ u32 ret;
++
++ __asm__("dup v1.4s, %w[in] ;"
++ "movi v0.16b, #0 ;"
++ "aese v0.16b, v1.16b ;"
++ "umov %w[out], v0.4s[0] ;"
++
++ : [out] "=r"(ret)
++ : [in] "r"(input)
++ : "v0","v1");
+
-+static inline void vgic_arch_setup(const struct vgic_params *vgic)
++ return ret;
++}
++
++int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
++ unsigned int key_len)
+{
-+ extern struct vgic_sr_vectors __vgic_sr_vectors;
++ /*
++ * The AES key schedule round constants
++ */
++ static u8 const rcon[] = {
++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
++ };
+
-+ switch(vgic->type)
-+ {
-+ case VGIC_V2:
-+ __vgic_sr_vectors.save_vgic = __save_vgic_v2_state;
-+ __vgic_sr_vectors.restore_vgic = __restore_vgic_v2_state;
-+ break;
++ u32 kwords = key_len / sizeof(u32);
++ struct aes_block *key_enc, *key_dec;
++ int i, j;
+
-+#ifdef CONFIG_ARM_GIC_V3
-+ case VGIC_V3:
-+ __vgic_sr_vectors.save_vgic = __save_vgic_v3_state;
-+ __vgic_sr_vectors.restore_vgic = __restore_vgic_v3_state;
-+ break;
-+#endif
++ if (key_len != AES_KEYSIZE_128 &&
++ key_len != AES_KEYSIZE_192 &&
++ key_len != AES_KEYSIZE_256)
++ return -EINVAL;
+
-+ default:
-+ BUG();
++ memcpy(ctx->key_enc, in_key, key_len);
++ ctx->key_length = key_len;
++
++ kernel_neon_begin_partial(2);
++ for (i = 0; i < sizeof(rcon); i++) {
++ u32 *rki = ctx->key_enc + (i * kwords);
++ u32 *rko = rki + kwords;
++
++ rko[0] = ror32(aes_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0];
++ rko[1] = rko[0] ^ rki[1];
++ rko[2] = rko[1] ^ rki[2];
++ rko[3] = rko[2] ^ rki[3];
++
++ if (key_len == AES_KEYSIZE_192) {
++ if (i >= 7)
++ break;
++ rko[4] = rko[3] ^ rki[4];
++ rko[5] = rko[4] ^ rki[5];
++ } else if (key_len == AES_KEYSIZE_256) {
++ if (i >= 6)
++ break;
++ rko[4] = aes_sub(rko[3]) ^ rki[4];
++ rko[5] = rko[4] ^ rki[5];
++ rko[6] = rko[5] ^ rki[6];
++ rko[7] = rko[6] ^ rki[7];
++ }
+ }
++
++ /*
++ * Generate the decryption keys for the Equivalent Inverse Cipher.
++ * This involves reversing the order of the round keys, and applying
++ * the Inverse Mix Columns transformation on all but the first and
++ * the last one.
++ */
++ key_enc = (struct aes_block *)ctx->key_enc;
++ key_dec = (struct aes_block *)ctx->key_dec;
++ j = num_rounds(ctx);
++
++ key_dec[0] = key_enc[j];
++ for (i = 1, j--; j > 0; i++, j--)
++ __asm__("ld1 {v0.16b}, %[in] ;"
++ "aesimc v1.16b, v0.16b ;"
++ "st1 {v1.16b}, %[out] ;"
++
++ : [out] "=Q"(key_dec[i])
++ : [in] "Q"(key_enc[j])
++ : "v0","v1");
++ key_dec[i] = key_enc[0];
++
++ kernel_neon_end();
++ return 0;
+}
++EXPORT_SYMBOL(ce_aes_expandkey);
+
- #endif /* __ARM64_KVM_HOST_H__ */
-diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
-index 7d29847..d7f77ff 100644
---- a/arch/arm64/include/asm/kvm_mmu.h
-+++ b/arch/arm64/include/asm/kvm_mmu.h
-@@ -122,8 +122,16 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
- }
-
- #define kvm_pgd_addr_end(addr, end) pgd_addr_end(addr, end)
--#define kvm_pud_addr_end(addr, end) pud_addr_end(addr, end)
--#define kvm_pmd_addr_end(addr, end) pmd_addr_end(addr, end)
++int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,
++ unsigned int key_len)
++{
++ struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
++ int ret;
+
-+#define kvm_pud_addr_end(addr, end) \
-+({ unsigned long __boundary = ((addr) + PUD_SIZE) & PUD_MASK; \
-+ (__boundary - 1 < (end) - 1)? __boundary: (end); \
-+})
++ ret = ce_aes_expandkey(ctx, in_key, key_len);
++ if (!ret)
++ return 0;
+
-+#define kvm_pmd_addr_end(addr, end) \
-+({ unsigned long __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \
-+ (__boundary - 1 < (end) - 1)? __boundary: (end); \
-+})
-
- struct kvm;
-
-diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
++ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
++ return -EINVAL;
++}
++EXPORT_SYMBOL(ce_aes_setkey);
++
+ static struct crypto_alg aes_alg = {
+ .cra_name = "aes",
+ .cra_driver_name = "aes-ce",
+@@ -135,7 +245,7 @@ static struct crypto_alg aes_alg = {
+ .cra_cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+- .cia_setkey = crypto_aes_set_key,
++ .cia_setkey = ce_aes_setkey,
+ .cia_encrypt = aes_cipher_encrypt,
+ .cia_decrypt = aes_cipher_decrypt
+ }
+diff --git a/arch/arm64/crypto/aes-ce-setkey.h b/arch/arm64/crypto/aes-ce-setkey.h
new file mode 100644
-index 0000000..3f7856e
+index 0000000..f08a647
--- /dev/null
-+++ b/arch/arm64/include/asm/pci.h
-@@ -0,0 +1,49 @@
-+#ifndef __ASM_PCI_H
-+#define __ASM_PCI_H
-+#ifdef __KERNEL__
-+
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/dma-mapping.h>
++++ b/arch/arm64/crypto/aes-ce-setkey.h
+@@ -0,0 +1,5 @@
+
-+#include <asm/io.h>
-+#include <asm-generic/pci-bridge.h>
-+#include <asm-generic/pci-dma-compat.h>
++int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,
++ unsigned int key_len);
++int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
++ unsigned int key_len);
+diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c
+index 79cd911..801aae3 100644
+--- a/arch/arm64/crypto/aes-glue.c
++++ b/arch/arm64/crypto/aes-glue.c
+@@ -16,9 +16,13 @@
+ #include <linux/module.h>
+ #include <linux/cpufeature.h>
+
++#include "aes-ce-setkey.h"
++
+ #ifdef USE_V8_CRYPTO_EXTENSIONS
+ #define MODE "ce"
+ #define PRIO 300
++#define aes_setkey ce_aes_setkey
++#define aes_expandkey ce_aes_expandkey
+ #define aes_ecb_encrypt ce_aes_ecb_encrypt
+ #define aes_ecb_decrypt ce_aes_ecb_decrypt
+ #define aes_cbc_encrypt ce_aes_cbc_encrypt
+@@ -30,6 +34,8 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions");
+ #else
+ #define MODE "neon"
+ #define PRIO 200
++#define aes_setkey crypto_aes_set_key
++#define aes_expandkey crypto_aes_expand_key
+ #define aes_ecb_encrypt neon_aes_ecb_encrypt
+ #define aes_ecb_decrypt neon_aes_ecb_decrypt
+ #define aes_cbc_encrypt neon_aes_cbc_encrypt
+@@ -79,10 +85,10 @@ static int xts_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ struct crypto_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+- ret = crypto_aes_expand_key(&ctx->key1, in_key, key_len / 2);
++ ret = aes_expandkey(&ctx->key1, in_key, key_len / 2);
+ if (!ret)
+- ret = crypto_aes_expand_key(&ctx->key2, &in_key[key_len / 2],
+- key_len / 2);
++ ret = aes_expandkey(&ctx->key2, &in_key[key_len / 2],
++ key_len / 2);
+ if (!ret)
+ return 0;
+
+@@ -288,7 +294,7 @@ static struct crypto_alg aes_algs[] = { {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+- .setkey = crypto_aes_set_key,
++ .setkey = aes_setkey,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ },
+@@ -306,7 +312,7 @@ static struct crypto_alg aes_algs[] = { {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+- .setkey = crypto_aes_set_key,
++ .setkey = aes_setkey,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ },
+@@ -324,7 +330,7 @@ static struct crypto_alg aes_algs[] = { {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+- .setkey = crypto_aes_set_key,
++ .setkey = aes_setkey,
+ .encrypt = ctr_encrypt,
+ .decrypt = ctr_encrypt,
+ },
+diff --git a/arch/arm64/include/asm/acenv.h b/arch/arm64/include/asm/acenv.h
+new file mode 100644
+index 0000000..b49166f
+--- /dev/null
++++ b/arch/arm64/include/asm/acenv.h
+@@ -0,0 +1,18 @@
++/*
++ * ARM64 specific ACPICA environments and implementation
++ *
++ * Copyright (C) 2014, Linaro Ltd.
++ * Author: Hanjun Guo <hanjun.guo@linaro.org>
++ * Author: Graeme Gregory <graeme.gregory@linaro.org>
++ *
++ * 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.
++ */
+
-+#define PCIBIOS_MIN_IO 0x1000
-+#define PCIBIOS_MIN_MEM 0
++#ifndef _ASM_ACENV_H
++#define _ASM_ACENV_H
+
-+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);
++/* It is required unconditionally by ACPI core, update it when needed. */
+
++#endif /* _ASM_ACENV_H */
+diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
+new file mode 100644
+index 0000000..6e692f4
+--- /dev/null
++++ b/arch/arm64/include/asm/acpi.h
+@@ -0,0 +1,102 @@
+/*
-+ * Set to 1 if the kernel should re-assign all PCI bus numbers
++ * Copyright (C) 2013-2014, Linaro Ltd.
++ * Author: Al Stone <al.stone@linaro.org>
++ * Author: Graeme Gregory <graeme.gregory@linaro.org>
++ * Author: Hanjun Guo <hanjun.guo@linaro.org>
++ *
++ * 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;
+ */
-+#define pcibios_assign_all_busses() \
-+ (pci_has_flag(PCI_REASSIGN_ALL_BUS))
+
-+/*
-+ * PCI address space differs from physical memory address space
-+ */
-+#define PCI_DMA_BUS_IS_PHYS (0)
++#ifndef _ASM_ACPI_H
++#define _ASM_ACPI_H
+
-+extern int isa_dma_bridge_buggy;
++#include <asm/smp_plat.h>
+
-+#ifdef CONFIG_PCI
-+static inline int pci_domain_nr(struct pci_bus *bus)
++/* Basic configuration for ACPI */
++#ifdef CONFIG_ACPI
++#define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */
++extern int acpi_disabled;
++extern int acpi_noirq;
++extern int acpi_pci_disabled;
++
++/* 1 to indicate PSCI 0.2+ is implemented */
++static inline bool acpi_psci_present(void)
+{
-+ struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
++ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
++}
+
-+ if (bridge)
-+ return bridge->domain_nr;
++/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */
++static inline bool acpi_psci_use_hvc(void)
++{
++ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
++}
+
-+ return 0;
++static inline void disable_acpi(void)
++{
++ acpi_disabled = 1;
++ acpi_pci_disabled = 1;
++ acpi_noirq = 1;
+}
+
-+static inline int pci_proc_domain(struct pci_bus *bus)
++static inline void enable_acpi(void)
+{
-+ return 1;
++ acpi_disabled = 0;
++ acpi_pci_disabled = 0;
++ acpi_noirq = 0;
+}
-+#endif /* CONFIG_PCI */
+
-+#endif /* __KERNEL__ */
-+#endif /* __ASM_PCI_H */
-diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
-index b9349c4..ecbd081 100644
---- a/arch/arm64/include/asm/tlbflush.h
-+++ b/arch/arm64/include/asm/tlbflush.h
-@@ -98,8 +98,8 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
- dsb(ish);
- }
-
--static inline void flush_tlb_range(struct vm_area_struct *vma,
-- unsigned long start, unsigned long end)
-+static inline void __flush_tlb_range(struct vm_area_struct *vma,
-+ unsigned long start, unsigned long end)
- {
- unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48;
- unsigned long addr;
-@@ -112,7 +112,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
- dsb(ish);
- }
-
--static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-+static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long end)
- {
- unsigned long addr;
- start >>= 12;
-@@ -125,6 +125,29 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
- }
-
- /*
-+ * This is meant to avoid soft lock-ups on large TLB flushing ranges and not
-+ * necessarily a performance improvement.
++/* MPIDR value provided in GICC structure is 64 bits, but the
++ * existing apic_id (CPU hardware ID) using in acpi processor
++ * driver is 32-bit, to conform to the same datatype we need
++ * to repack the GICC structure MPIDR.
++ *
++ * Only 32 bits of MPIDR are used:
++ *
++ * Bits [0:7] Aff0;
++ * Bits [8:15] Aff1;
++ * Bits [16:23] Aff2;
++ * Bits [32:39] Aff3;
+ */
-+#define MAX_TLB_RANGE (1024UL << PAGE_SHIFT)
-+
-+static inline void flush_tlb_range(struct vm_area_struct *vma,
-+ unsigned long start, unsigned long end)
++static inline u32 pack_mpidr(u64 mpidr)
+{
-+ if ((end - start) <= MAX_TLB_RANGE)
-+ __flush_tlb_range(vma, start, end);
-+ else
-+ flush_tlb_mm(vma->vm_mm);
++ return (u32) ((mpidr & 0xff00000000) >> 8) | mpidr;
+}
+
-+static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
++/*
++ * The ACPI processor driver for ACPI core code needs this macro
++ * to find out this cpu was already mapped (mapping from CPU hardware
++ * ID to CPU logical ID) or not.
++ *
++ * cpu_logical_map(cpu) is the mapping of MPIDR and the logical cpu,
++ * and MPIDR is the cpu hardware ID we needed to pack.
++ */
++#define cpu_physical_id(cpu) pack_mpidr(cpu_logical_map(cpu))
++
++/*
++ * It's used from ACPI core in kdump to boot UP system with SMP kernel,
++ * with this check the ACPI core will not override the CPU index
++ * obtained from GICC with 0 and not print some error message as well.
++ * Since MADT must provide at least one GICC structure for GIC
++ * initialization, CPU will be always available in MADT on ARM64.
++ */
++static inline bool acpi_has_cpu_in_madt(void)
+{
-+ if ((end - start) <= MAX_TLB_RANGE)
-+ __flush_tlb_kernel_range(start, end);
-+ else
-+ flush_tlb_all();
++ return true;
+}
+
-+/*
- * On AArch64, the cache coherency is handled via the set_pte_at() function.
- */
- static inline void update_mmu_cache(struct vm_area_struct *vma,
-diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
-index 215ad46..7a5df52 100644
---- a/arch/arm64/include/asm/virt.h
-+++ b/arch/arm64/include/asm/virt.h
-@@ -50,6 +50,10 @@ static inline bool is_hyp_mode_mismatched(void)
- return __boot_cpu_mode[0] != __boot_cpu_mode[1];
- }
-
-+/* The section containing the hypervisor text */
-+extern char __hyp_text_start[];
-+extern char __hyp_text_end[];
++static inline void arch_fix_phys_package_id(int num, u32 slot) { }
++void __init acpi_smp_init_cpus(void);
+
- #endif /* __ASSEMBLY__ */
-
- #endif /* ! __ASM__VIRT_H */
-diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
-index cdaedad..36b117a 100644
---- a/arch/arm64/kernel/Makefile
-+++ b/arch/arm64/kernel/Makefile
-@@ -29,6 +29,7 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
- arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
- arm64-obj-$(CONFIG_KGDB) += kgdb.o
- arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
-+arm64-obj-$(CONFIG_PCI) += pci.o
++extern int acpi_get_cpu_parked_address(int cpu, u64 *addr);
++
++#else
++static inline void disable_acpi(void) { }
++static inline bool acpi_psci_present(void) { return false; }
++static inline bool acpi_psci_use_hvc(void) { return false; }
++static inline void acpi_smp_init_cpus(void) { }
++static inline int acpi_get_cpu_parked_address(int cpu, u64 *addr) { return -EOPNOTSUPP; }
++#endif /* CONFIG_ACPI */
++
++#endif /*_ASM_ACPI_H*/
+diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
+index ddb9d78..89e397b 100644
+--- a/arch/arm64/include/asm/cmpxchg.h
++++ b/arch/arm64/include/asm/cmpxchg.h
+@@ -19,6 +19,7 @@
+ #define __ASM_CMPXCHG_H
- obj-y += $(arm64-obj-y) vdso/
- obj-m += $(arm64-obj-m)
-diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
-index 646f888..e74654c 100644
---- a/arch/arm64/kernel/asm-offsets.c
-+++ b/arch/arm64/kernel/asm-offsets.c
-@@ -129,13 +129,24 @@ int main(void)
- DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
- DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
- DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
-- DEFINE(VGIC_CPU_HCR, offsetof(struct vgic_cpu, vgic_hcr));
-- DEFINE(VGIC_CPU_VMCR, offsetof(struct vgic_cpu, vgic_vmcr));
-- DEFINE(VGIC_CPU_MISR, offsetof(struct vgic_cpu, vgic_misr));
-- DEFINE(VGIC_CPU_EISR, offsetof(struct vgic_cpu, vgic_eisr));
-- DEFINE(VGIC_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_elrsr));
-- DEFINE(VGIC_CPU_APR, offsetof(struct vgic_cpu, vgic_apr));
-- DEFINE(VGIC_CPU_LR, offsetof(struct vgic_cpu, vgic_lr));
-+ DEFINE(VGIC_SAVE_FN, offsetof(struct vgic_sr_vectors, save_vgic));
-+ DEFINE(VGIC_RESTORE_FN, offsetof(struct vgic_sr_vectors, restore_vgic));
-+ DEFINE(VGIC_SR_VECTOR_SZ, sizeof(struct vgic_sr_vectors));
-+ DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
-+ DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
-+ DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
-+ DEFINE(VGIC_V2_CPU_EISR, offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
-+ DEFINE(VGIC_V2_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
-+ DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
-+ DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
-+ DEFINE(VGIC_V3_CPU_HCR, offsetof(struct vgic_cpu, vgic_v3.vgic_hcr));
-+ DEFINE(VGIC_V3_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr));
-+ DEFINE(VGIC_V3_CPU_MISR, offsetof(struct vgic_cpu, vgic_v3.vgic_misr));
-+ DEFINE(VGIC_V3_CPU_EISR, offsetof(struct vgic_cpu, vgic_v3.vgic_eisr));
-+ DEFINE(VGIC_V3_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v3.vgic_elrsr));
-+ DEFINE(VGIC_V3_CPU_AP0R, offsetof(struct vgic_cpu, vgic_v3.vgic_ap0r));
-+ DEFINE(VGIC_V3_CPU_AP1R, offsetof(struct vgic_cpu, vgic_v3.vgic_ap1r));
-+ DEFINE(VGIC_V3_CPU_LR, offsetof(struct vgic_cpu, vgic_v3.vgic_lr));
- DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
- DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
- DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
-diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
-index e786e6c..320ef48 100644
---- a/arch/arm64/kernel/efi-stub.c
-+++ b/arch/arm64/kernel/efi-stub.c
-@@ -58,20 +58,16 @@ static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
- kernel_size = _edata - _text;
- if (*image_addr != (dram_base + TEXT_OFFSET)) {
- kernel_memsize = kernel_size + (_end - _edata);
-- status = efi_relocate_kernel(sys_table, image_addr,
-- kernel_size, kernel_memsize,
-- dram_base + TEXT_OFFSET,
-- PAGE_SIZE);
-+ status = efi_low_alloc(sys_table, kernel_memsize + TEXT_OFFSET,
-+ SZ_2M, reserve_addr);
- if (status != EFI_SUCCESS) {
- pr_efi_err(sys_table, "Failed to relocate kernel\n");
- return status;
- }
-- if (*image_addr != (dram_base + TEXT_OFFSET)) {
-- pr_efi_err(sys_table, "Failed to alloc kernel memory\n");
-- efi_free(sys_table, kernel_memsize, *image_addr);
-- return EFI_ERROR;
-- }
-- *image_size = kernel_memsize;
-+ memcpy((void *)*reserve_addr + TEXT_OFFSET, (void *)*image_addr,
-+ kernel_size);
-+ *image_addr = *reserve_addr + TEXT_OFFSET;
-+ *reserve_size = kernel_memsize + TEXT_OFFSET;
- }
+ #include <linux/bug.h>
++#include <linux/mmdebug.h>
+ #include <asm/barrier.h>
-diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
-index 14db1f6..453b7f8 100644
---- a/arch/arm64/kernel/efi.c
-+++ b/arch/arm64/kernel/efi.c
-@@ -467,3 +467,14 @@ static int __init arm64_enter_virtual_mode(void)
- return 0;
+@@ -152,6 +153,51 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+ return oldval;
}
- early_initcall(arm64_enter_virtual_mode);
+
++#define system_has_cmpxchg_double() 1
+
-+/*
-+ * If nothing else is handling pm_power_off, use EFI
-+ *
-+ * This is called from a late_initcall after other mechanisms
-+ * have had a chance to register a handler.
-+ */
-+bool efi_poweroff_required(void)
++static inline int __cmpxchg_double(volatile void *ptr1, volatile void *ptr2,
++ unsigned long old1, unsigned long old2,
++ unsigned long new1, unsigned long new2, int size)
+{
-+ return pm_power_off == NULL;
++ unsigned long loop, lost;
++
++ switch (size) {
++ case 8:
++ VM_BUG_ON((unsigned long *)ptr2 - (unsigned long *)ptr1 != 1);
++ do {
++ asm volatile("// __cmpxchg_double8\n"
++ " ldxp %0, %1, %2\n"
++ " eor %0, %0, %3\n"
++ " eor %1, %1, %4\n"
++ " orr %1, %0, %1\n"
++ " mov %w0, #0\n"
++ " cbnz %1, 1f\n"
++ " stxp %w0, %5, %6, %2\n"
++ "1:\n"
++ : "=&r"(loop), "=&r"(lost), "+Q" (*(u64 *)ptr1)
++ : "r" (old1), "r"(old2), "r"(new1), "r"(new2));
++ } while (loop);
++ break;
++ default:
++ BUILD_BUG();
++ }
++
++ return !lost;
+}
-diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
-index a2c1195..8df59be 100644
---- a/arch/arm64/kernel/head.S
-+++ b/arch/arm64/kernel/head.S
-@@ -22,6 +22,7 @@
-
- #include <linux/linkage.h>
- #include <linux/init.h>
-+#include <linux/irqchip/arm-gic-v3.h>
-
- #include <asm/assembler.h>
- #include <asm/ptrace.h>
-@@ -156,7 +157,7 @@ optional_header:
- .short 0x20b // PE32+ format
- .byte 0x02 // MajorLinkerVersion
- .byte 0x14 // MinorLinkerVersion
-- .long _edata - stext // SizeOfCode
-+ .long _end - stext // SizeOfCode
- .long 0 // SizeOfInitializedData
- .long 0 // SizeOfUninitializedData
- .long efi_stub_entry - efi_head // AddressOfEntryPoint
-@@ -174,7 +175,7 @@ extra_header_fields:
- .short 0 // MinorSubsystemVersion
- .long 0 // Win32VersionValue
-
-- .long _edata - efi_head // SizeOfImage
-+ .long _end - efi_head // SizeOfImage
-
- // Everything before the kernel image is considered part of the header
- .long stext - efi_head // SizeOfHeaders
-@@ -221,7 +222,7 @@ section_table:
- .byte 0
- .byte 0
- .byte 0 // end of 0 padding of section name
-- .long _edata - stext // VirtualSize
-+ .long _end - stext // VirtualSize
- .long stext - efi_head // VirtualAddress
- .long _edata - stext // SizeOfRawData
- .long stext - efi_head // PointerToRawData
-@@ -295,6 +296,23 @@ CPU_LE( bic x0, x0, #(3 << 24) ) // Clear the EE and E0E bits for EL1
- msr cnthctl_el2, x0
- msr cntvoff_el2, xzr // Clear virtual offset
-
-+#ifdef CONFIG_ARM_GIC_V3
-+ /* GICv3 system register access */
-+ mrs x0, id_aa64pfr0_el1
-+ ubfx x0, x0, #24, #4
-+ cmp x0, #1
-+ b.ne 3f
-+
-+ mrs x0, ICC_SRE_EL2
-+ orr x0, x0, #ICC_SRE_EL2_SRE // Set ICC_SRE_EL2.SRE==1
-+ orr x0, x0, #ICC_SRE_EL2_ENABLE // Set ICC_SRE_EL2.Enable==1
-+ msr ICC_SRE_EL2, x0
-+ isb // Make sure SRE is now set
-+ msr ICH_HCR_EL2, xzr // Reset ICC_HCR_EL2 to defaults
-+
-+3:
-+#endif
+
- /* Populate ID registers. */
- mrs x0, midr_el1
- mrs x1, mpidr_el1
-diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
-index 0959611..a272f33 100644
---- a/arch/arm64/kernel/hyp-stub.S
-+++ b/arch/arm64/kernel/hyp-stub.S
-@@ -19,6 +19,7 @@
++static inline int __cmpxchg_double_mb(volatile void *ptr1, volatile void *ptr2,
++ unsigned long old1, unsigned long old2,
++ unsigned long new1, unsigned long new2, int size)
++{
++ int ret;
++
++ smp_mb();
++ ret = __cmpxchg_double(ptr1, ptr2, old1, old2, new1, new2, size);
++ smp_mb();
++
++ return ret;
++}
++
+ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
+ unsigned long new, int size)
+ {
+@@ -182,6 +228,31 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
+ __ret; \
+ })
+
++#define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \
++({\
++ int __ret;\
++ __ret = __cmpxchg_double_mb((ptr1), (ptr2), (unsigned long)(o1), \
++ (unsigned long)(o2), (unsigned long)(n1), \
++ (unsigned long)(n2), sizeof(*(ptr1)));\
++ __ret; \
++})
++
++#define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \
++({\
++ int __ret;\
++ __ret = __cmpxchg_double((ptr1), (ptr2), (unsigned long)(o1), \
++ (unsigned long)(o2), (unsigned long)(n1), \
++ (unsigned long)(n2), sizeof(*(ptr1)));\
++ __ret; \
++})
++
++#define this_cpu_cmpxchg_8(ptr, o, n) \
++ cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
++
++#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
++ cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \
++ o1, o2, n1, n2)
++
+ #define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n))
+ #define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n))
- #include <linux/init.h>
- #include <linux/linkage.h>
-+#include <linux/irqchip/arm-gic-v3.h>
+diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h
+index 6f8e2ef..978f567 100644
+--- a/arch/arm64/include/asm/cpu_ops.h
++++ b/arch/arm64/include/asm/cpu_ops.h
+@@ -64,6 +64,7 @@ struct cpu_operations {
+ };
- #include <asm/assembler.h>
- #include <asm/ptrace.h>
-diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
+ extern const struct cpu_operations *cpu_ops[NR_CPUS];
++const struct cpu_operations *cpu_get_ops(const char *name);
+ int __init cpu_read_ops(struct device_node *dn, int cpu);
+ void __init cpu_read_bootcpu_ops(void);
+
+diff --git a/arch/arm64/include/asm/dmi.h b/arch/arm64/include/asm/dmi.h
new file mode 100644
-index 0000000..955d6d1
+index 0000000..69d37d8
--- /dev/null
-+++ b/arch/arm64/kernel/pci.c
-@@ -0,0 +1,38 @@
++++ b/arch/arm64/include/asm/dmi.h
+@@ -0,0 +1,31 @@
+/*
-+ * Code borrowed from powerpc/kernel/pci-common.c
++ * arch/arm64/include/asm/dmi.h
+ *
-+ * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
-+ * Copyright (C) 2014 ARM Ltd.
++ * Copyright (C) 2013 Linaro Limited.
++ * Written by: Yi Li (yi.li@linaro.org)
+ *
-+ * 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.
++ * based on arch/ia64/include/asm/dmi.h
+ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
+ */
+
-+#include <linux/init.h>
++#ifndef __ASM_DMI_H
++#define __ASM_DMI_H
++
+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/of_pci.h>
-+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
-+#include <asm/pci-bridge.h>
-+
+/*
-+ * Called after each bus is probed, but before its children are examined
++ * According to section 2.3.6 of the UEFI spec, the firmware should not
++ * request a virtual mapping for configuration tables such as SMBIOS.
++ * This means we have to map them before use.
+ */
-+void pcibios_fixup_bus(struct pci_bus *bus)
-+{
-+ /* nothing to do, expected to be removed in the future */
-+}
++#define dmi_early_remap(x, l) ioremap_cache(x, l)
++#define dmi_early_unmap(x, l) iounmap(x)
++#define dmi_remap(x, l) ioremap_cache(x, l)
++#define dmi_unmap(x) iounmap(x)
++#define dmi_alloc(l) kzalloc(l, GFP_KERNEL)
+
-+/*
-+ * We don't have to worry about legacy ISA devices, so nothing to do here
-+ */
-+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-+ resource_size_t size, resource_size_t align)
-+{
-+ return res->start;
-+}
-diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
-index 43b7c34..ec5cbbe 100644
---- a/arch/arm64/kernel/process.c
-+++ b/arch/arm64/kernel/process.c
-@@ -43,6 +43,7 @@
- #include <linux/hw_breakpoint.h>
- #include <linux/personality.h>
- #include <linux/notifier.h>
-+#include <linux/efi.h>
-
- #include <asm/compat.h>
- #include <asm/cacheflush.h>
-@@ -176,6 +177,11 @@ void machine_restart(char *cmd)
- arm_pm_restart(reboot_mode, cmd);
++#endif
+diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
+index 1f65be3..c0f89a0 100644
+--- a/arch/arm64/include/asm/elf.h
++++ b/arch/arm64/include/asm/elf.h
+@@ -114,7 +114,8 @@ typedef struct user_fpsimd_state elf_fpregset_t;
+ */
+ #define elf_check_arch(x) ((x)->e_machine == EM_AARCH64)
- /*
-+ * If all else fails, try EFI
-+ */
-+ efi_reboot(reboot_mode, cmd);
-+
-+ /*
- * Whoops - the architecture was unable to reboot.
- */
- printk("Reboot failed -- System halted\n");
-diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
-index 0347d38..70181c1 100644
---- a/arch/arm64/kernel/smp_spin_table.c
-+++ b/arch/arm64/kernel/smp_spin_table.c
-@@ -20,6 +20,7 @@
- #include <linux/init.h>
- #include <linux/of.h>
- #include <linux/smp.h>
-+#include <linux/types.h>
+-#define elf_read_implies_exec(ex,stk) (stk != EXSTACK_DISABLE_X)
++#define elf_read_implies_exec(ex,stk) (test_thread_flag(TIF_32BIT) \
++ ? (stk == EXSTACK_ENABLE_X) : 0)
- #include <asm/cacheflush.h>
- #include <asm/cpu_ops.h>
-@@ -65,12 +66,21 @@ static int smp_spin_table_cpu_init(struct device_node *dn, unsigned int cpu)
+ #define CORE_DUMP_USE_REGSET
+ #define ELF_EXEC_PAGESIZE PAGE_SIZE
+diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
+index 7fd3e27..8afb863 100644
+--- a/arch/arm64/include/asm/kvm_arm.h
++++ b/arch/arm64/include/asm/kvm_arm.h
+@@ -18,6 +18,7 @@
+ #ifndef __ARM64_KVM_ARM_H__
+ #define __ARM64_KVM_ARM_H__
- static int smp_spin_table_cpu_prepare(unsigned int cpu)
- {
-- void **release_addr;
-+ __le64 __iomem *release_addr;
++#include <asm/memory.h>
+ #include <asm/types.h>
- if (!cpu_release_addr[cpu])
- return -ENODEV;
+ /* Hyp Configuration Register (HCR) bits */
+@@ -160,9 +161,9 @@
+ #endif
-- release_addr = __va(cpu_release_addr[cpu]);
-+ /*
-+ * The cpu-release-addr may or may not be inside the linear mapping.
-+ * As ioremap_cache will either give us a new mapping or reuse the
-+ * existing linear mapping, we can use it to cover both cases. In
-+ * either case the memory will be MT_NORMAL.
-+ */
-+ release_addr = ioremap_cache(cpu_release_addr[cpu],
-+ sizeof(*release_addr));
-+ if (!release_addr)
-+ return -ENOMEM;
+ #define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
+-#define VTTBR_BADDR_MASK (((1LLU << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
+-#define VTTBR_VMID_SHIFT (48LLU)
+-#define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT)
++#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
++#define VTTBR_VMID_SHIFT (UL(48))
++#define VTTBR_VMID_MASK (UL(0xFF) << VTTBR_VMID_SHIFT)
+
+ /* Hyp System Trap Register */
+ #define HSTR_EL2_TTEE (1 << 16)
+@@ -185,13 +186,13 @@
+
+ /* Exception Syndrome Register (ESR) bits */
+ #define ESR_EL2_EC_SHIFT (26)
+-#define ESR_EL2_EC (0x3fU << ESR_EL2_EC_SHIFT)
+-#define ESR_EL2_IL (1U << 25)
++#define ESR_EL2_EC (UL(0x3f) << ESR_EL2_EC_SHIFT)
++#define ESR_EL2_IL (UL(1) << 25)
+ #define ESR_EL2_ISS (ESR_EL2_IL - 1)
+ #define ESR_EL2_ISV_SHIFT (24)
+-#define ESR_EL2_ISV (1U << ESR_EL2_ISV_SHIFT)
++#define ESR_EL2_ISV (UL(1) << ESR_EL2_ISV_SHIFT)
+ #define ESR_EL2_SAS_SHIFT (22)
+-#define ESR_EL2_SAS (3U << ESR_EL2_SAS_SHIFT)
++#define ESR_EL2_SAS (UL(3) << ESR_EL2_SAS_SHIFT)
+ #define ESR_EL2_SSE (1 << 21)
+ #define ESR_EL2_SRT_SHIFT (16)
+ #define ESR_EL2_SRT_MASK (0x1f << ESR_EL2_SRT_SHIFT)
+@@ -205,16 +206,16 @@
+ #define ESR_EL2_FSC_TYPE (0x3c)
+
+ #define ESR_EL2_CV_SHIFT (24)
+-#define ESR_EL2_CV (1U << ESR_EL2_CV_SHIFT)
++#define ESR_EL2_CV (UL(1) << ESR_EL2_CV_SHIFT)
+ #define ESR_EL2_COND_SHIFT (20)
+-#define ESR_EL2_COND (0xfU << ESR_EL2_COND_SHIFT)
++#define ESR_EL2_COND (UL(0xf) << ESR_EL2_COND_SHIFT)
+
+
+ #define FSC_FAULT (0x04)
+ #define FSC_PERM (0x0c)
+
+ /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
+-#define HPFAR_MASK (~0xFUL)
++#define HPFAR_MASK (~UL(0xf))
+
+ #define ESR_EL2_EC_UNKNOWN (0x00)
+ #define ESR_EL2_EC_WFI (0x01)
+diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
+index 0caf7a5..123b521 100644
+--- a/arch/arm64/include/asm/kvm_mmu.h
++++ b/arch/arm64/include/asm/kvm_mmu.h
+@@ -243,9 +243,10 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
+ }
- /*
- * We write the release address as LE regardless of the native
-@@ -79,15 +89,16 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu)
- * boot-loader's endianess before jumping. This is mandated by
- * the boot protocol.
- */
-- release_addr[0] = (void *) cpu_to_le64(__pa(secondary_holding_pen));
--
-- __flush_dcache_area(release_addr, sizeof(release_addr[0]));
-+ writeq_relaxed(__pa(secondary_holding_pen), release_addr);
-+ __flush_dcache_area(release_addr, sizeof(*release_addr));
+ static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
+- unsigned long size)
++ unsigned long size,
++ bool ipa_uncached)
+ {
+- if (!vcpu_has_cache_enabled(vcpu))
++ if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
+ kvm_flush_dcache_to_poc((void *)hva, size);
- /*
- * Send an event to wake up the secondary CPU.
- */
- sev();
+ if (!icache_is_aliasing()) { /* PIPT */
+diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
+index 872ba93..2f287a6 100644
+--- a/arch/arm64/include/asm/pci.h
++++ b/arch/arm64/include/asm/pci.h
+@@ -33,5 +33,56 @@ static inline int pci_proc_domain(struct pci_bus *bus)
+ }
+ #endif /* CONFIG_PCI */
-+ iounmap(release_addr);
++/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
++#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
+
- return 0;
- }
++#define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20)
++
++struct acpi_device;
++
++struct pci_sysdata {
++ int domain; /* PCI domain */
++ int node; /* NUMA node */
++ struct acpi_device *companion; /* ACPI companion device */
++ void *iommu; /* IOMMU private data */
++};
++
++struct acpi_pci_root;
++struct pci_mmcfg_region;
++
++typedef int (*acpi_mcfg_fixup_t)(struct acpi_pci_root *root,
++ struct pci_mmcfg_region *cfg);
++
++struct pci_mmcfg_region {
++ struct list_head list;
++ struct resource res;
++ int (*read)(struct pci_mmcfg_region *cfg, unsigned int bus,
++ unsigned int devfn, int reg, int len, u32 *value);
++ int (*write)(struct pci_mmcfg_region *cfg, unsigned int bus,
++ unsigned int devfn, int reg, int len, u32 value);
++ acpi_mcfg_fixup_t fixup;
++ void *data;
++ u64 address;
++ char __iomem *virt;
++ u16 segment;
++ u8 start_bus;
++ u8 end_bus;
++ char name[PCI_MMCFG_RESOURCE_NAME_LEN];
++};
++
++struct acpi_mcfg_fixup {
++ char oem_id[7];
++ char oem_table_id[9];
++ acpi_mcfg_fixup_t hook;
++};
++
++/* Designate a routine to fix up buggy MCFG */
++#define DECLARE_ACPI_MCFG_FIXUP(oem_id, table_id, hook) \
++ static const struct acpi_mcfg_fixup __acpi_fixup_##hook __used \
++ __attribute__((__section__(".acpi_fixup_mcfg"), aligned((sizeof(void *))))) \
++ = { {oem_id}, {table_id}, hook };
++
++extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
++
+ #endif /* __KERNEL__ */
+ #endif /* __ASM_PCI_H */
+diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
+index e5312ea..2454bc5 100644
+--- a/arch/arm64/include/asm/psci.h
++++ b/arch/arm64/include/asm/psci.h
+@@ -14,6 +14,7 @@
+ #ifndef __ASM_PSCI_H
+ #define __ASM_PSCI_H
+
+-int psci_init(void);
++int psci_dt_init(void);
++int psci_acpi_init(void);
+
+ #endif /* __ASM_PSCI_H */
+diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
+index 780f82c..3411561 100644
+--- a/arch/arm64/include/asm/smp.h
++++ b/arch/arm64/include/asm/smp.h
+@@ -39,9 +39,10 @@ extern void show_ipi_list(struct seq_file *p, int prec);
+ extern void handle_IPI(int ipinr, struct pt_regs *regs);
-diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
-index 72a9fd5..32a0961 100644
---- a/arch/arm64/kvm/Makefile
-+++ b/arch/arm64/kvm/Makefile
-@@ -20,4 +20,8 @@ kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
- kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o
-
- kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
-+kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
-+kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o
-+kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o
-+kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v3-switch.o
- kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
-diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
-index b0d1512..5945f3b 100644
---- a/arch/arm64/kvm/hyp.S
-+++ b/arch/arm64/kvm/hyp.S
-@@ -16,7 +16,6 @@
+ /*
+- * Setup the set of possible CPUs (via set_cpu_possible)
++ * Discover the set of possible CPUs and determine their
++ * SMP operations.
*/
-
- #include <linux/linkage.h>
--#include <linux/irqchip/arm-gic.h>
-
- #include <asm/assembler.h>
- #include <asm/memory.h>
-@@ -36,9 +35,6 @@
- .pushsection .hyp.text, "ax"
- .align PAGE_SHIFT
-
--__kvm_hyp_code_start:
-- .globl __kvm_hyp_code_start
--
- .macro save_common_regs
- // x2: base address for cpu context
- // x3: tmp register
-@@ -339,11 +335,8 @@ __kvm_hyp_code_start:
- .endm
-
- .macro activate_traps
-- ldr x2, [x0, #VCPU_IRQ_LINES]
-- ldr x1, [x0, #VCPU_HCR_EL2]
-- orr x2, x2, x1
-- msr hcr_el2, x2
--
-+ ldr x2, [x0, #VCPU_HCR_EL2]
-+ msr hcr_el2, x2
- ldr x2, =(CPTR_EL2_TTA)
- msr cptr_el2, x2
-
-@@ -379,100 +372,33 @@ __kvm_hyp_code_start:
- .endm
+-extern void smp_init_cpus(void);
++extern void of_smp_init_cpus(void);
/*
-- * Save the VGIC CPU state into memory
-- * x0: Register pointing to VCPU struct
-- * Do not corrupt x1!!!
-+ * Call into the vgic backend for state saving
- */
- .macro save_vgic_state
-- /* Get VGIC VCTRL base into x2 */
-- ldr x2, [x0, #VCPU_KVM]
-- kern_hyp_va x2
-- ldr x2, [x2, #KVM_VGIC_VCTRL]
-- kern_hyp_va x2
-- cbz x2, 2f // disabled
--
-- /* Compute the address of struct vgic_cpu */
-- add x3, x0, #VCPU_VGIC_CPU
--
-- /* Save all interesting registers */
-- ldr w4, [x2, #GICH_HCR]
-- ldr w5, [x2, #GICH_VMCR]
-- ldr w6, [x2, #GICH_MISR]
-- ldr w7, [x2, #GICH_EISR0]
-- ldr w8, [x2, #GICH_EISR1]
-- ldr w9, [x2, #GICH_ELRSR0]
-- ldr w10, [x2, #GICH_ELRSR1]
-- ldr w11, [x2, #GICH_APR]
--CPU_BE( rev w4, w4 )
--CPU_BE( rev w5, w5 )
--CPU_BE( rev w6, w6 )
--CPU_BE( rev w7, w7 )
--CPU_BE( rev w8, w8 )
--CPU_BE( rev w9, w9 )
--CPU_BE( rev w10, w10 )
--CPU_BE( rev w11, w11 )
--
-- str w4, [x3, #VGIC_CPU_HCR]
-- str w5, [x3, #VGIC_CPU_VMCR]
-- str w6, [x3, #VGIC_CPU_MISR]
-- str w7, [x3, #VGIC_CPU_EISR]
-- str w8, [x3, #(VGIC_CPU_EISR + 4)]
-- str w9, [x3, #VGIC_CPU_ELRSR]
-- str w10, [x3, #(VGIC_CPU_ELRSR + 4)]
-- str w11, [x3, #VGIC_CPU_APR]
--
-- /* Clear GICH_HCR */
-- str wzr, [x2, #GICH_HCR]
--
-- /* Save list registers */
-- add x2, x2, #GICH_LR0
-- ldr w4, [x3, #VGIC_CPU_NR_LR]
-- add x3, x3, #VGIC_CPU_LR
--1: ldr w5, [x2], #4
--CPU_BE( rev w5, w5 )
-- str w5, [x3], #4
-- sub w4, w4, #1
-- cbnz w4, 1b
--2:
-+ adr x24, __vgic_sr_vectors
-+ ldr x24, [x24, VGIC_SAVE_FN]
-+ kern_hyp_va x24
-+ blr x24
-+ mrs x24, hcr_el2
-+ mov x25, #HCR_INT_OVERRIDE
-+ neg x25, x25
-+ and x24, x24, x25
-+ msr hcr_el2, x24
- .endm
+ * Provide a function to raise an IPI cross call on CPUs in callmap.
+@@ -51,6 +52,11 @@ extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int));
+ extern void (*__smp_cross_call)(const struct cpumask *, unsigned int);
/*
-- * Restore the VGIC CPU state from memory
-- * x0: Register pointing to VCPU struct
-+ * Call into the vgic backend for state restoring
++ * Provide a function to signal a parked secondary CPU.
++ */
++extern void set_smp_boot_wakeup_call(void (*)(int cpu));
++
++/*
+ * Called from the secondary holding pen, this is the secondary CPU entry point.
*/
- .macro restore_vgic_state
-- /* Get VGIC VCTRL base into x2 */
-- ldr x2, [x0, #VCPU_KVM]
-- kern_hyp_va x2
-- ldr x2, [x2, #KVM_VGIC_VCTRL]
-- kern_hyp_va x2
-- cbz x2, 2f // disabled
--
-- /* Compute the address of struct vgic_cpu */
-- add x3, x0, #VCPU_VGIC_CPU
--
-- /* We only restore a minimal set of registers */
-- ldr w4, [x3, #VGIC_CPU_HCR]
-- ldr w5, [x3, #VGIC_CPU_VMCR]
-- ldr w6, [x3, #VGIC_CPU_APR]
--CPU_BE( rev w4, w4 )
--CPU_BE( rev w5, w5 )
--CPU_BE( rev w6, w6 )
--
-- str w4, [x2, #GICH_HCR]
-- str w5, [x2, #GICH_VMCR]
-- str w6, [x2, #GICH_APR]
--
-- /* Restore list registers */
-- add x2, x2, #GICH_LR0
-- ldr w4, [x3, #VGIC_CPU_NR_LR]
-- add x3, x3, #VGIC_CPU_LR
--1: ldr w5, [x3], #4
--CPU_BE( rev w5, w5 )
-- str w5, [x2], #4
-- sub w4, w4, #1
-- cbnz w4, 1b
--2:
-+ mrs x24, hcr_el2
-+ ldr x25, [x0, #VCPU_IRQ_LINES]
-+ orr x24, x24, #HCR_INT_OVERRIDE
-+ orr x24, x24, x25
-+ msr hcr_el2, x24
-+ adr x24, __vgic_sr_vectors
-+ ldr x24, [x24, #VGIC_RESTORE_FN]
-+ kern_hyp_va x24
-+ blr x24
- .endm
-
- .macro save_timer_state
-@@ -653,6 +579,12 @@ ENTRY(__kvm_flush_vm_context)
- ret
- ENDPROC(__kvm_flush_vm_context)
-
-+ // struct vgic_sr_vectors __vgi_sr_vectors;
-+ .align 3
-+ENTRY(__vgic_sr_vectors)
-+ .skip VGIC_SR_VECTOR_SZ
-+ENDPROC(__vgic_sr_vectors)
-+
- __kvm_hyp_panic:
- // Guess the context by looking at VTTBR:
- // If zero, then we're already a host.
-@@ -880,7 +812,4 @@ ENTRY(__kvm_hyp_vector)
- ventry el1_error_invalid // Error 32-bit EL1
- ENDPROC(__kvm_hyp_vector)
-
--__kvm_hyp_code_end:
-- .globl __kvm_hyp_code_end
--
- .popsection
-diff --git a/arch/arm64/kvm/vgic-v2-switch.S b/arch/arm64/kvm/vgic-v2-switch.S
+ asmlinkage void secondary_start_kernel(void);
+diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
+index 5bd029b..f4ba4fe 100644
+--- a/arch/arm64/kernel/Makefile
++++ b/arch/arm64/kernel/Makefile
+@@ -21,7 +21,8 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
+ sys_compat.o
+ arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
+ arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
+-arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o
++arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o \
++ smp_parking_protocol.o
+ arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
+ arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
+ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
+@@ -31,6 +32,7 @@ arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+ arm64-obj-$(CONFIG_KGDB) += kgdb.o
+ arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
+ arm64-obj-$(CONFIG_PCI) += pci.o
++arm64-obj-$(CONFIG_ACPI) += acpi.o
+
+ obj-y += $(arm64-obj-y) vdso/
+ obj-m += $(arm64-obj-m)
+diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
new file mode 100644
-index 0000000..ae21177
+index 0000000..06a96be
--- /dev/null
-+++ b/arch/arm64/kvm/vgic-v2-switch.S
-@@ -0,0 +1,133 @@
++++ b/arch/arm64/kernel/acpi.c
+@@ -0,0 +1,398 @@
+/*
-+ * Copyright (C) 2012,2013 - ARM Ltd
-+ * Author: Marc Zyngier <marc.zyngier@arm.com>
++ * ARM64 Specific Low-Level ACPI Boot Support
+ *
-+ * 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.
++ * Copyright (C) 2013-2014, Linaro Ltd.
++ * Author: Al Stone <al.stone@linaro.org>
++ * Author: Graeme Gregory <graeme.gregory@linaro.org>
++ * Author: Hanjun Guo <hanjun.guo@linaro.org>
++ * Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
++ * Author: Naresh Bhat <naresh.bhat@linaro.org>
+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
+ */
+
-+#include <linux/linkage.h>
-+#include <linux/irqchip/arm-gic.h>
++#define pr_fmt(fmt) "ACPI: " fmt
+
-+#include <asm/assembler.h>
-+#include <asm/memory.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/kvm.h>
-+#include <asm/kvm_asm.h>
-+#include <asm/kvm_arm.h>
-+#include <asm/kvm_mmu.h>
++#include <linux/init.h>
++#include <linux/acpi.h>
++#include <linux/cpumask.h>
++#include <linux/memblock.h>
++#include <linux/irq.h>
++#include <linux/irqdomain.h>
++#include <linux/bootmem.h>
++#include <linux/smp.h>
++#include <linux/irqchip/arm-gic-acpi.h>
++
++#include <asm/cputype.h>
++#include <asm/cpu_ops.h>
++
++int acpi_noirq; /* skip ACPI IRQ initialization */
++int acpi_disabled;
++EXPORT_SYMBOL(acpi_disabled);
+
-+ .text
-+ .pushsection .hyp.text, "ax"
++int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */
++EXPORT_SYMBOL(acpi_pci_disabled);
++
++static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */
++
++static char *boot_method;
++static u64 parked_address[NR_CPUS];
+
+/*
-+ * Save the VGIC CPU state into memory
-+ * x0: Register pointing to VCPU struct
-+ * Do not corrupt x1!!!
++ * Since we're on ARM, the default interrupt routing model
++ * clearly has to be GIC.
+ */
-+ENTRY(__save_vgic_v2_state)
-+__save_vgic_v2_state:
-+ /* Get VGIC VCTRL base into x2 */
-+ ldr x2, [x0, #VCPU_KVM]
-+ kern_hyp_va x2
-+ ldr x2, [x2, #KVM_VGIC_VCTRL]
-+ kern_hyp_va x2
-+ cbz x2, 2f // disabled
-+
-+ /* Compute the address of struct vgic_cpu */
-+ add x3, x0, #VCPU_VGIC_CPU
-+
-+ /* Save all interesting registers */
-+ ldr w4, [x2, #GICH_HCR]
-+ ldr w5, [x2, #GICH_VMCR]
-+ ldr w6, [x2, #GICH_MISR]
-+ ldr w7, [x2, #GICH_EISR0]
-+ ldr w8, [x2, #GICH_EISR1]
-+ ldr w9, [x2, #GICH_ELRSR0]
-+ ldr w10, [x2, #GICH_ELRSR1]
-+ ldr w11, [x2, #GICH_APR]
-+CPU_BE( rev w4, w4 )
-+CPU_BE( rev w5, w5 )
-+CPU_BE( rev w6, w6 )
-+CPU_BE( rev w7, w7 )
-+CPU_BE( rev w8, w8 )
-+CPU_BE( rev w9, w9 )
-+CPU_BE( rev w10, w10 )
-+CPU_BE( rev w11, w11 )
-+
-+ str w4, [x3, #VGIC_V2_CPU_HCR]
-+ str w5, [x3, #VGIC_V2_CPU_VMCR]
-+ str w6, [x3, #VGIC_V2_CPU_MISR]
-+ str w7, [x3, #VGIC_V2_CPU_EISR]
-+ str w8, [x3, #(VGIC_V2_CPU_EISR + 4)]
-+ str w9, [x3, #VGIC_V2_CPU_ELRSR]
-+ str w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)]
-+ str w11, [x3, #VGIC_V2_CPU_APR]
-+
-+ /* Clear GICH_HCR */
-+ str wzr, [x2, #GICH_HCR]
-+
-+ /* Save list registers */
-+ add x2, x2, #GICH_LR0
-+ ldr w4, [x3, #VGIC_CPU_NR_LR]
-+ add x3, x3, #VGIC_V2_CPU_LR
-+1: ldr w5, [x2], #4
-+CPU_BE( rev w5, w5 )
-+ str w5, [x3], #4
-+ sub w4, w4, #1
-+ cbnz w4, 1b
-+2:
-+ ret
-+ENDPROC(__save_vgic_v2_state)
++enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC;
+
+/*
-+ * Restore the VGIC CPU state from memory
-+ * x0: Register pointing to VCPU struct
++ * __acpi_map_table() will be called before page_init(), so early_ioremap()
++ * or early_memremap() should be called here to for ACPI table mapping.
+ */
-+ENTRY(__restore_vgic_v2_state)
-+__restore_vgic_v2_state:
-+ /* Get VGIC VCTRL base into x2 */
-+ ldr x2, [x0, #VCPU_KVM]
-+ kern_hyp_va x2
-+ ldr x2, [x2, #KVM_VGIC_VCTRL]
-+ kern_hyp_va x2
-+ cbz x2, 2f // disabled
-+
-+ /* Compute the address of struct vgic_cpu */
-+ add x3, x0, #VCPU_VGIC_CPU
-+
-+ /* We only restore a minimal set of registers */
-+ ldr w4, [x3, #VGIC_V2_CPU_HCR]
-+ ldr w5, [x3, #VGIC_V2_CPU_VMCR]
-+ ldr w6, [x3, #VGIC_V2_CPU_APR]
-+CPU_BE( rev w4, w4 )
-+CPU_BE( rev w5, w5 )
-+CPU_BE( rev w6, w6 )
-+
-+ str w4, [x2, #GICH_HCR]
-+ str w5, [x2, #GICH_VMCR]
-+ str w6, [x2, #GICH_APR]
-+
-+ /* Restore list registers */
-+ add x2, x2, #GICH_LR0
-+ ldr w4, [x3, #VGIC_CPU_NR_LR]
-+ add x3, x3, #VGIC_V2_CPU_LR
-+1: ldr w5, [x3], #4
-+CPU_BE( rev w5, w5 )
-+ str w5, [x2], #4
-+ sub w4, w4, #1
-+ cbnz w4, 1b
-+2:
-+ ret
-+ENDPROC(__restore_vgic_v2_state)
-+
-+ .popsection
-diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S
-new file mode 100644
-index 0000000..21e68f6
---- /dev/null
-+++ b/arch/arm64/kvm/vgic-v3-switch.S
-@@ -0,0 +1,267 @@
-+/*
-+ * Copyright (C) 2012,2013 - ARM Ltd
-+ * Author: Marc Zyngier <marc.zyngier@arm.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
++char *__init __acpi_map_table(unsigned long phys, unsigned long size)
++{
++ if (!phys || !size)
++ return NULL;
++
++ return early_memremap(phys, size);
++}
++
++void __init __acpi_unmap_table(char *map, unsigned long size)
++{
++ if (!map || !size)
++ return;
++
++ early_memunmap(map, size);
++}
++
++/**
++ * acpi_map_gic_cpu_interface - generates a logical cpu number
++ * and map to MPIDR represented by GICC structure
++ * @mpidr: CPU's hardware id to register, MPIDR represented in MADT
++ * @enabled: this cpu is enabled or not
+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ * Returns the logical cpu number which maps to MPIDR
+ */
++static int acpi_map_gic_cpu_interface(u64 mpidr, u64 parked_addr, u8 enabled)
++{
++ int cpu;
+
-+#include <linux/linkage.h>
-+#include <linux/irqchip/arm-gic-v3.h>
++ if (mpidr == INVALID_HWID) {
++ pr_info("Skip MADT cpu entry with invalid MPIDR\n");
++ return -EINVAL;
++ }
+
-+#include <asm/assembler.h>
-+#include <asm/memory.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/kvm.h>
-+#include <asm/kvm_asm.h>
-+#include <asm/kvm_arm.h>
++ total_cpus++;
++ if (!enabled)
++ return -EINVAL;
++
++ if (enabled_cpus >= NR_CPUS) {
++ pr_warn("NR_CPUS limit of %d reached, Processor %d/0x%llx ignored.\n",
++ NR_CPUS, total_cpus, mpidr);
++ return -EINVAL;
++ }
++
++ /* No need to check duplicate MPIDRs for the first CPU */
++ if (enabled_cpus) {
++ /*
++ * Duplicate MPIDRs are a recipe for disaster. Scan
++ * all initialized entries and check for
++ * duplicates. If any is found just ignore the CPU.
++ */
++ for_each_possible_cpu(cpu) {
++ if (cpu_logical_map(cpu) == mpidr) {
++ pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
++ mpidr);
++ return -EINVAL;
++ }
++ }
++
++ /* allocate a logical cpu id for the new comer */
++ cpu = cpumask_next_zero(-1, cpu_possible_mask);
++ } else {
++ /*
++ * First GICC entry must be BSP as ACPI spec said
++ * in section 5.2.12.15
++ */
++ if (cpu_logical_map(0) != mpidr) {
++ pr_err("First GICC entry with MPIDR 0x%llx is not BSP\n",
++ mpidr);
++ return -EINVAL;
++ }
++
++ /*
++ * boot_cpu_init() already hold bit 0 in cpu_present_mask
++ * for BSP, no need to allocate again.
++ */
++ cpu = 0;
++ }
++
++ parked_address[cpu] = parked_addr;
++
++ /* CPU 0 was already initialized */
++ if (cpu) {
++ cpu_ops[cpu] = cpu_get_ops(boot_method);
++ if (!cpu_ops[cpu])
++ return -EINVAL;
++
++ if (cpu_ops[cpu]->cpu_init(NULL, cpu))
++ return -EOPNOTSUPP;
++
++ /* map the logical cpu id to cpu MPIDR */
++ cpu_logical_map(cpu) = mpidr;
++
++ set_cpu_possible(cpu, true);
++ } else {
++ /* get cpu0's ops, no need to return if ops is null */
++ cpu_ops[0] = cpu_get_ops(boot_method);
++ }
++
++ enabled_cpus++;
++ return cpu;
++}
++
++static int __init
++acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
++ const unsigned long end)
++{
++ struct acpi_madt_generic_interrupt *processor;
++
++ processor = (struct acpi_madt_generic_interrupt *)header;
++
++ if (BAD_MADT_ENTRY(processor, end))
++ return -EINVAL;
++
++ acpi_table_print_madt_entry(header);
++
++ acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK,
++ processor->parked_address, processor->flags & ACPI_MADT_ENABLED);
++
++ return 0;
++}
+
-+ .text
-+ .pushsection .hyp.text, "ax"
++/* Parse GIC cpu interface entries in MADT for SMP init */
++void __init acpi_smp_init_cpus(void)
++{
++ int count;
++
++ /*
++ * do a partial walk of MADT to determine how many CPUs
++ * we have including disabled CPUs, and get information
++ * we need for SMP init
++ */
++ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
++ acpi_parse_gic_cpu_interface, 0);
++
++ if (!count) {
++ pr_err("No GIC CPU interface entries present\n");
++ return;
++ } else if (count < 0) {
++ pr_err("Error parsing GIC CPU interface entry\n");
++ return;
++ }
++
++ /* Make boot-up look pretty */
++ pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus);
++}
++
++int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
++{
++ *irq = irq_find_mapping(NULL, gsi);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
+
+/*
-+ * We store LRs in reverse order to let the CPU deal with streaming
-+ * access. Use this macro to make it look saner...
++ * success: return IRQ number (>0)
++ * failure: return =< 0
+ */
-+#define LR_OFFSET(n) (VGIC_V3_CPU_LR + (15 - n) * 8)
++int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
++{
++ unsigned int irq;
++ unsigned int irq_type;
++
++ /*
++ * ACPI have no bindings to indicate SPI or PPI, so we
++ * use different mappings from DT in ACPI.
++ *
++ * For FDT
++ * PPI interrupt: in the range [0, 15];
++ * SPI interrupt: in the range [0, 987];
++ *
++ * For ACPI, GSI should be unique so using
++ * the hwirq directly for the mapping:
++ * PPI interrupt: in the range [16, 31];
++ * SPI interrupt: in the range [32, 1019];
++ */
++
++ if (trigger == ACPI_EDGE_SENSITIVE &&
++ polarity == ACPI_ACTIVE_LOW)
++ irq_type = IRQ_TYPE_EDGE_FALLING;
++ else if (trigger == ACPI_EDGE_SENSITIVE &&
++ polarity == ACPI_ACTIVE_HIGH)
++ irq_type = IRQ_TYPE_EDGE_RISING;
++ else if (trigger == ACPI_LEVEL_SENSITIVE &&
++ polarity == ACPI_ACTIVE_LOW)
++ irq_type = IRQ_TYPE_LEVEL_LOW;
++ else if (trigger == ACPI_LEVEL_SENSITIVE &&
++ polarity == ACPI_ACTIVE_HIGH)
++ irq_type = IRQ_TYPE_LEVEL_HIGH;
++ else
++ irq_type = IRQ_TYPE_NONE;
++
++ /*
++ * Since only one GIC is supported in ACPI 5.0, we can
++ * create mapping refer to the default domain
++ */
++ irq = irq_create_mapping(NULL, gsi);
++ if (!irq)
++ return irq;
++
++ /* Set irq type if specified and different than the current one */
++ if (irq_type != IRQ_TYPE_NONE &&
++ irq_type != irq_get_trigger_type(irq))
++ irq_set_irq_type(irq, irq_type);
++ return irq;
++}
++EXPORT_SYMBOL_GPL(acpi_register_gsi);
++
++void acpi_unregister_gsi(u32 gsi)
++{
++}
++EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
++
++static int __init acpi_parse_fadt(struct acpi_table_header *table)
++{
++ struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
++
++ /*
++ * Revision in table header is the FADT Major revision,
++ * and there is a minor revision of FADT which was introduced
++ * by ACPI 5.1, we only deal with ACPI 5.1 or newer revision
++ * to get arm boot flags, or we will disable ACPI.
++ */
++ if (table->revision > 5 ||
++ (table->revision == 5 && fadt->minor_revision >= 1)) {
++ /*
++ * 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.
++ */
++ if (acpi_psci_present())
++ boot_method = "psci";
++ else if (IS_ENABLED(CONFIG_ARM_PARKING_PROTOCOL))
++ boot_method = "parking-protocol";
++
++ if (!boot_method)
++ pr_warn("No boot method, will not bring up secondary CPUs\n");
++ return -EOPNOTSUPP;
++ }
++
++ pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n",
++ table->revision, fadt->minor_revision);
++ disable_acpi();
++
++ return -EINVAL;
++}
+
+/*
-+ * Save the VGIC CPU state into memory
-+ * x0: Register pointing to VCPU struct
-+ * Do not corrupt x1!!!
++ * acpi_boot_table_init() called from setup_arch(), always.
++ * 1. find RSDP and get its address, and then find XSDT
++ * 2. extract all tables and checksums them all
++ * 3. check ACPI FADT revisoin
++ *
++ * We can parse ACPI boot-time tables such as MADT after
++ * this function is called.
+ */
-+.macro save_vgic_v3_state
-+ // Compute the address of struct vgic_cpu
-+ add x3, x0, #VCPU_VGIC_CPU
-+
-+ // Make sure stores to the GIC via the memory mapped interface
-+ // are now visible to the system register interface
-+ dsb st
-+
-+ // Save all interesting registers
-+ mrs x4, ICH_HCR_EL2
-+ mrs x5, ICH_VMCR_EL2
-+ mrs x6, ICH_MISR_EL2
-+ mrs x7, ICH_EISR_EL2
-+ mrs x8, ICH_ELSR_EL2
-+
-+ str w4, [x3, #VGIC_V3_CPU_HCR]
-+ str w5, [x3, #VGIC_V3_CPU_VMCR]
-+ str w6, [x3, #VGIC_V3_CPU_MISR]
-+ str w7, [x3, #VGIC_V3_CPU_EISR]
-+ str w8, [x3, #VGIC_V3_CPU_ELRSR]
-+
-+ msr ICH_HCR_EL2, xzr
-+
-+ mrs x21, ICH_VTR_EL2
-+ mvn w22, w21
-+ ubfiz w23, w22, 2, 4 // w23 = (15 - ListRegs) * 4
-+
-+ adr x24, 1f
-+ add x24, x24, x23
-+ br x24
-+
-+1:
-+ mrs x20, ICH_LR15_EL2
-+ mrs x19, ICH_LR14_EL2
-+ mrs x18, ICH_LR13_EL2
-+ mrs x17, ICH_LR12_EL2
-+ mrs x16, ICH_LR11_EL2
-+ mrs x15, ICH_LR10_EL2
-+ mrs x14, ICH_LR9_EL2
-+ mrs x13, ICH_LR8_EL2
-+ mrs x12, ICH_LR7_EL2
-+ mrs x11, ICH_LR6_EL2
-+ mrs x10, ICH_LR5_EL2
-+ mrs x9, ICH_LR4_EL2
-+ mrs x8, ICH_LR3_EL2
-+ mrs x7, ICH_LR2_EL2
-+ mrs x6, ICH_LR1_EL2
-+ mrs x5, ICH_LR0_EL2
-+
-+ adr x24, 1f
-+ add x24, x24, x23
-+ br x24
-+
-+1:
-+ str x20, [x3, #LR_OFFSET(15)]
-+ str x19, [x3, #LR_OFFSET(14)]
-+ str x18, [x3, #LR_OFFSET(13)]
-+ str x17, [x3, #LR_OFFSET(12)]
-+ str x16, [x3, #LR_OFFSET(11)]
-+ str x15, [x3, #LR_OFFSET(10)]
-+ str x14, [x3, #LR_OFFSET(9)]
-+ str x13, [x3, #LR_OFFSET(8)]
-+ str x12, [x3, #LR_OFFSET(7)]
-+ str x11, [x3, #LR_OFFSET(6)]
-+ str x10, [x3, #LR_OFFSET(5)]
-+ str x9, [x3, #LR_OFFSET(4)]
-+ str x8, [x3, #LR_OFFSET(3)]
-+ str x7, [x3, #LR_OFFSET(2)]
-+ str x6, [x3, #LR_OFFSET(1)]
-+ str x5, [x3, #LR_OFFSET(0)]
-+
-+ tbnz w21, #29, 6f // 6 bits
-+ tbz w21, #30, 5f // 5 bits
-+ // 7 bits
-+ mrs x20, ICH_AP0R3_EL2
-+ str w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
-+ mrs x19, ICH_AP0R2_EL2
-+ str w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
-+6: mrs x18, ICH_AP0R1_EL2
-+ str w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
-+5: mrs x17, ICH_AP0R0_EL2
-+ str w17, [x3, #VGIC_V3_CPU_AP0R]
-+
-+ tbnz w21, #29, 6f // 6 bits
-+ tbz w21, #30, 5f // 5 bits
-+ // 7 bits
-+ mrs x20, ICH_AP1R3_EL2
-+ str w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
-+ mrs x19, ICH_AP1R2_EL2
-+ str w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
-+6: mrs x18, ICH_AP1R1_EL2
-+ str w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
-+5: mrs x17, ICH_AP1R0_EL2
-+ str w17, [x3, #VGIC_V3_CPU_AP1R]
-+
-+ // Restore SRE_EL1 access and re-enable SRE at EL1.
-+ mrs x5, ICC_SRE_EL2
-+ orr x5, x5, #ICC_SRE_EL2_ENABLE
-+ msr ICC_SRE_EL2, x5
-+ isb
-+ mov x5, #1
-+ msr ICC_SRE_EL1, x5
-+.endm
++void __init acpi_boot_table_init(void)
++{
++ /* If acpi_disabled, bail out */
++ if (acpi_disabled)
++ return;
++
++ /* Initialize the ACPI boot-time table parser. */
++ if (acpi_table_init()) {
++ disable_acpi();
++ return;
++ }
++
++ if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt))
++ pr_err("Can't find FADT or error happened during parsing FADT\n");
++}
++
++void __init acpi_gic_init(void)
++{
++ struct acpi_table_header *table;
++ acpi_status status;
++ acpi_size tbl_size;
++ int err;
++
++ status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size);
++ if (ACPI_FAILURE(status)) {
++ const char *msg = acpi_format_exception(status);
++
++ pr_err("Failed to get MADT table, %s\n", msg);
++ return;
++ }
++
++ err = gic_v2_acpi_init(table);
++ if (err)
++ pr_err("Failed to initialize GIC IRQ controller");
++
++ early_acpi_os_unmap_memory((char *)table, tbl_size);
++}
+
+/*
-+ * Restore the VGIC CPU state from memory
-+ * x0: Register pointing to VCPU struct
++ * Parked Address in ACPI GIC structure will be used as the CPU
++ * release address
+ */
-+.macro restore_vgic_v3_state
-+ // Disable SRE_EL1 access. Necessary, otherwise
-+ // ICH_VMCR_EL2.VFIQEn becomes one, and FIQ happens...
-+ msr ICC_SRE_EL1, xzr
-+ isb
-+
-+ // Compute the address of struct vgic_cpu
-+ add x3, x0, #VCPU_VGIC_CPU
-+
-+ // Restore all interesting registers
-+ ldr w4, [x3, #VGIC_V3_CPU_HCR]
-+ ldr w5, [x3, #VGIC_V3_CPU_VMCR]
-+
-+ msr ICH_HCR_EL2, x4
-+ msr ICH_VMCR_EL2, x5
-+
-+ mrs x21, ICH_VTR_EL2
-+
-+ tbnz w21, #29, 6f // 6 bits
-+ tbz w21, #30, 5f // 5 bits
-+ // 7 bits
-+ ldr w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
-+ msr ICH_AP1R3_EL2, x20
-+ ldr w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
-+ msr ICH_AP1R2_EL2, x19
-+6: ldr w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
-+ msr ICH_AP1R1_EL2, x18
-+5: ldr w17, [x3, #VGIC_V3_CPU_AP1R]
-+ msr ICH_AP1R0_EL2, x17
-+
-+ tbnz w21, #29, 6f // 6 bits
-+ tbz w21, #30, 5f // 5 bits
-+ // 7 bits
-+ ldr w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
-+ msr ICH_AP0R3_EL2, x20
-+ ldr w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
-+ msr ICH_AP0R2_EL2, x19
-+6: ldr w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
-+ msr ICH_AP0R1_EL2, x18
-+5: ldr w17, [x3, #VGIC_V3_CPU_AP0R]
-+ msr ICH_AP0R0_EL2, x17
-+
-+ and w22, w21, #0xf
-+ mvn w22, w21
-+ ubfiz w23, w22, 2, 4 // w23 = (15 - ListRegs) * 4
-+
-+ adr x24, 1f
-+ add x24, x24, x23
-+ br x24
-+
-+1:
-+ ldr x20, [x3, #LR_OFFSET(15)]
-+ ldr x19, [x3, #LR_OFFSET(14)]
-+ ldr x18, [x3, #LR_OFFSET(13)]
-+ ldr x17, [x3, #LR_OFFSET(12)]
-+ ldr x16, [x3, #LR_OFFSET(11)]
-+ ldr x15, [x3, #LR_OFFSET(10)]
-+ ldr x14, [x3, #LR_OFFSET(9)]
-+ ldr x13, [x3, #LR_OFFSET(8)]
-+ ldr x12, [x3, #LR_OFFSET(7)]
-+ ldr x11, [x3, #LR_OFFSET(6)]
-+ ldr x10, [x3, #LR_OFFSET(5)]
-+ ldr x9, [x3, #LR_OFFSET(4)]
-+ ldr x8, [x3, #LR_OFFSET(3)]
-+ ldr x7, [x3, #LR_OFFSET(2)]
-+ ldr x6, [x3, #LR_OFFSET(1)]
-+ ldr x5, [x3, #LR_OFFSET(0)]
-+
-+ adr x24, 1f
-+ add x24, x24, x23
-+ br x24
-+
-+1:
-+ msr ICH_LR15_EL2, x20
-+ msr ICH_LR14_EL2, x19
-+ msr ICH_LR13_EL2, x18
-+ msr ICH_LR12_EL2, x17
-+ msr ICH_LR11_EL2, x16
-+ msr ICH_LR10_EL2, x15
-+ msr ICH_LR9_EL2, x14
-+ msr ICH_LR8_EL2, x13
-+ msr ICH_LR7_EL2, x12
-+ msr ICH_LR6_EL2, x11
-+ msr ICH_LR5_EL2, x10
-+ msr ICH_LR4_EL2, x9
-+ msr ICH_LR3_EL2, x8
-+ msr ICH_LR2_EL2, x7
-+ msr ICH_LR1_EL2, x6
-+ msr ICH_LR0_EL2, x5
-+
-+ // Ensure that the above will have reached the
-+ // (re)distributors. This ensure the guest will read
-+ // the correct values from the memory-mapped interface.
-+ isb
-+ dsb sy
-+
-+ // Prevent the guest from touching the GIC system registers
-+ mrs x5, ICC_SRE_EL2
-+ and x5, x5, #~ICC_SRE_EL2_ENABLE
-+ msr ICC_SRE_EL2, x5
-+.endm
-+
-+ENTRY(__save_vgic_v3_state)
-+ save_vgic_v3_state
-+ ret
-+ENDPROC(__save_vgic_v3_state)
-+
-+ENTRY(__restore_vgic_v3_state)
-+ restore_vgic_v3_state
-+ ret
-+ENDPROC(__restore_vgic_v3_state)
-+
-+ENTRY(__vgic_v3_get_ich_vtr_el2)
-+ mrs x0, ICH_VTR_EL2
-+ ret
-+ENDPROC(__vgic_v3_get_ich_vtr_el2)
-+
-+ .popsection
-diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
-index 55d4ba4..deed6fa 100644
---- a/arch/ia64/kernel/process.c
-+++ b/arch/ia64/kernel/process.c
-@@ -662,7 +662,7 @@ void
- machine_restart (char *restart_cmd)
- {
- (void) notify_die(DIE_MACHINE_RESTART, restart_cmd, NULL, 0, 0, 0);
-- (*efi.reset_system)(EFI_RESET_WARM, 0, 0, NULL);
-+ efi_reboot(REBOOT_WARM, NULL);
- }
-
- void
-diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
-index 71c52bc..a149c67 100644
---- a/arch/ia64/kernel/time.c
-+++ b/arch/ia64/kernel/time.c
-@@ -384,21 +384,6 @@ static struct irqaction timer_irqaction = {
- .name = "timer"
- };
-
--static struct platform_device rtc_efi_dev = {
-- .name = "rtc-efi",
-- .id = -1,
--};
--
--static int __init rtc_init(void)
--{
-- if (platform_device_register(&rtc_efi_dev) < 0)
-- printk(KERN_ERR "unable to register rtc device...\n");
--
-- /* not necessarily an error */
-- return 0;
--}
--module_init(rtc_init);
--
- void read_persistent_clock(struct timespec *ts)
- {
- efi_gettimeofday(ts);
-diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
-index 1eb5f64..5d71d0e 100644
---- a/arch/x86/include/asm/efi.h
-+++ b/arch/x86/include/asm/efi.h
-@@ -104,6 +104,8 @@ extern void __init runtime_code_page_mkexec(void);
- extern void __init efi_runtime_mkexec(void);
- extern void __init efi_dump_pagetable(void);
- extern void __init efi_apply_memmap_quirks(void);
-+extern int __init efi_reuse_config(u64 tables, int nr_tables);
-+extern void efi_delete_dummy_variable(void);
-
- struct efi_setup_data {
- u64 fw_vendor;
-@@ -156,6 +158,8 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(
- return EFI_SUCCESS;
- }
- #endif /* CONFIG_EFI_MIXED */
++int acpi_get_cpu_parked_address(int cpu, u64 *addr)
++{
++ if (!addr || !parked_address[cpu])
++ return -EINVAL;
+
-+extern bool efi_reboot_required(void);
- #else
- /*
- * IF EFI is not configured, have the EFI calls return -ENOSYS.
-@@ -168,6 +172,10 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(
- #define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS)
- #define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS)
- static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {}
-+static inline bool efi_reboot_required(void)
++ *addr = parked_address[cpu];
++
++ return 0;
++}
++
++static int __init parse_acpi(char *arg)
+{
-+ return false;
++ if (!arg)
++ return -EINVAL;
++
++ /* "acpi=off" disables both ACPI table parsing and interpreter */
++ if (strcmp(arg, "off") == 0)
++ disable_acpi();
++ else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
++ enable_acpi();
++ else
++ return -EINVAL; /* Core will print when we return error */
++
++ return 0;
+}
- #endif /* CONFIG_EFI */
-
- #endif /* _ASM_X86_EFI_H */
-diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
-index 52b1157..17962e6 100644
---- a/arch/x86/kernel/reboot.c
-+++ b/arch/x86/kernel/reboot.c
-@@ -28,6 +28,7 @@
- #include <linux/mc146818rtc.h>
- #include <asm/realmode.h>
- #include <asm/x86_init.h>
-+#include <asm/efi.h>
-
- /*
- * Power off function, if any
-@@ -401,12 +402,25 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
-
- static int __init reboot_init(void)
- {
-+ int rv;
++early_param("acpi", parse_acpi);
+
- /*
- * Only do the DMI check if reboot_type hasn't been overridden
- * on the command line
- */
-- if (reboot_default)
-- dmi_check_system(reboot_dmi_table);
-+ if (!reboot_default)
-+ return 0;
++int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
++{
++ return -1;
++}
+
-+ /*
-+ * The DMI quirks table takes precedence. If no quirks entry
-+ * matches and the ACPI Hardware Reduced bit is set, force EFI
-+ * reboot.
-+ */
-+ rv = dmi_check_system(reboot_dmi_table);
++int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
++{
++ /* TBD */
++ return -EINVAL;
++}
++EXPORT_SYMBOL(acpi_register_ioapic);
+
-+ if (!rv && efi_reboot_required())
-+ reboot_type = BOOT_EFI;
++int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
++{
++ /* TBD */
++ return -EINVAL;
++}
++EXPORT_SYMBOL(acpi_unregister_ioapic);
+
- return 0;
- }
- core_initcall(reboot_init);
-@@ -528,11 +542,7 @@ static void native_machine_emergency_restart(void)
- break;
-
- case BOOT_EFI:
-- if (efi_enabled(EFI_RUNTIME_SERVICES))
-- efi.reset_system(reboot_mode == REBOOT_WARM ?
-- EFI_RESET_WARM :
-- EFI_RESET_COLD,
-- EFI_SUCCESS, 0, NULL);
-+ efi_reboot(reboot_mode, NULL);
- reboot_type = BOOT_BIOS;
- break;
-
-diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
-index d51045a..2846aaa 100644
---- a/arch/x86/platform/efi/Makefile
-+++ b/arch/x86/platform/efi/Makefile
-@@ -1,4 +1,4 @@
--obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
-+obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o
- obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
- obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
- obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o
-diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
-index 87fc96b..f852443 100644
---- a/arch/x86/platform/efi/efi.c
-+++ b/arch/x86/platform/efi/efi.c
-@@ -56,13 +56,6 @@
-
- #define EFI_DEBUG
-
--#define EFI_MIN_RESERVE 5120
--
--#define EFI_DUMMY_GUID \
-- EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9)
--
--static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
--
- struct efi_memory_map memmap;
+diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c
+index cce9524..1d90f31 100644
+--- a/arch/arm64/kernel/cpu_ops.c
++++ b/arch/arm64/kernel/cpu_ops.c
+@@ -23,19 +23,23 @@
+ #include <linux/string.h>
- static struct efi efi_phys __initdata;
-@@ -95,15 +88,6 @@ static int __init setup_add_efi_memmap(char *arg)
- }
- early_param("add_efi_memmap", setup_add_efi_memmap);
+ extern const struct cpu_operations smp_spin_table_ops;
++extern const struct cpu_operations smp_parking_protocol_ops;
+ extern const struct cpu_operations cpu_psci_ops;
--static bool efi_no_storage_paranoia;
--
--static int __init setup_storage_paranoia(char *arg)
--{
-- efi_no_storage_paranoia = true;
-- return 0;
--}
--early_param("efi_no_storage_paranoia", setup_storage_paranoia);
--
- static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
- {
- unsigned long flags;
-@@ -392,37 +376,6 @@ static void __init print_efi_memmap(void)
- #endif /* EFI_DEBUG */
- }
+ const struct cpu_operations *cpu_ops[NR_CPUS];
--void __init efi_reserve_boot_services(void)
--{
-- void *p;
--
-- for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-- efi_memory_desc_t *md = p;
-- u64 start = md->phys_addr;
-- u64 size = md->num_pages << EFI_PAGE_SHIFT;
--
-- if (md->type != EFI_BOOT_SERVICES_CODE &&
-- md->type != EFI_BOOT_SERVICES_DATA)
-- continue;
-- /* Only reserve where possible:
-- * - Not within any already allocated areas
-- * - Not over any memory area (really needed, if above?)
-- * - Not within any part of the kernel
-- * - Not the bios reserved area
-- */
-- if ((start + size > __pa_symbol(_text)
-- && start <= __pa_symbol(_end)) ||
-- !e820_all_mapped(start, start+size, E820_RAM) ||
-- memblock_is_region_reserved(start, size)) {
-- /* Could not reserve, skip it */
-- md->num_pages = 0;
-- memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n",
-- start, start+size-1);
-- } else
-- memblock_reserve(start, size);
-- }
--}
--
- void __init efi_unmap_memmap(void)
- {
- clear_bit(EFI_MEMMAP, &efi.flags);
-@@ -432,29 +385,6 @@ void __init efi_unmap_memmap(void)
- }
- }
+-static const struct cpu_operations *supported_cpu_ops[] __initconst = {
++static const struct cpu_operations *supported_cpu_ops[] = {
+ #ifdef CONFIG_SMP
+ &smp_spin_table_ops,
++#ifdef CONFIG_ARM_PARKING_PROTOCOL
++ &smp_parking_protocol_ops,
++#endif
+ #endif
+ &cpu_psci_ops,
+ NULL,
+ };
--void __init efi_free_boot_services(void)
--{
-- void *p;
--
-- for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-- efi_memory_desc_t *md = p;
-- unsigned long long start = md->phys_addr;
-- unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
--
-- if (md->type != EFI_BOOT_SERVICES_CODE &&
-- md->type != EFI_BOOT_SERVICES_DATA)
-- continue;
--
-- /* Could not reserve boot area */
-- if (!size)
-- continue;
--
-- free_bootmem_late(start, size);
-- }
--
-- efi_unmap_memmap();
--}
--
- static int __init efi_systab_init(void *phys)
+-static const struct cpu_operations * __init cpu_get_ops(const char *name)
++const struct cpu_operations *cpu_get_ops(const char *name)
{
- if (efi_enabled(EFI_64BIT)) {
-@@ -649,62 +579,6 @@ static int __init efi_memmap_init(void)
- return 0;
- }
+ const struct cpu_operations **ops = supported_cpu_ops;
--/*
-- * A number of config table entries get remapped to virtual addresses
-- * after entering EFI virtual mode. However, the kexec kernel requires
-- * their physical addresses therefore we pass them via setup_data and
-- * correct those entries to their respective physical addresses here.
-- *
-- * Currently only handles smbios which is necessary for some firmware
-- * implementation.
-- */
--static int __init efi_reuse_config(u64 tables, int nr_tables)
--{
-- int i, sz, ret = 0;
-- void *p, *tablep;
-- struct efi_setup_data *data;
--
-- if (!efi_setup)
-- return 0;
--
-- if (!efi_enabled(EFI_64BIT))
-- return 0;
--
-- data = early_memremap(efi_setup, sizeof(*data));
-- if (!data) {
-- ret = -ENOMEM;
-- goto out;
-- }
--
-- if (!data->smbios)
-- goto out_memremap;
--
-- sz = sizeof(efi_config_table_64_t);
--
-- p = tablep = early_memremap(tables, nr_tables * sz);
-- if (!p) {
-- pr_err("Could not map Configuration table!\n");
-- ret = -ENOMEM;
-- goto out_memremap;
-- }
--
-- for (i = 0; i < efi.systab->nr_tables; i++) {
-- efi_guid_t guid;
--
-- guid = ((efi_config_table_64_t *)p)->guid;
--
-- if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID))
-- ((efi_config_table_64_t *)p)->table = data->smbios;
-- p += sz;
-- }
-- early_iounmap(tablep, nr_tables * sz);
--
--out_memremap:
-- early_iounmap(data, sizeof(*data));
--out:
-- return ret;
--}
--
- void __init efi_init(void)
- {
- efi_char16_t *c16;
-@@ -1057,11 +931,7 @@ static void __init kexec_enter_virtual_mode(void)
- runtime_code_page_mkexec();
-
- /* clean DUMMY object */
-- efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
-- EFI_VARIABLE_NON_VOLATILE |
-- EFI_VARIABLE_BOOTSERVICE_ACCESS |
-- EFI_VARIABLE_RUNTIME_ACCESS,
-- 0, NULL);
-+ efi_delete_dummy_variable();
- #endif
- }
+diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
+index d18a449..8ce9b05 100644
+--- a/arch/arm64/kernel/efi-entry.S
++++ b/arch/arm64/kernel/efi-entry.S
+@@ -61,7 +61,8 @@ ENTRY(efi_stub_entry)
+ */
+ mov x20, x0 // DTB address
+ ldr x0, [sp, #16] // relocated _text address
+- mov x21, x0
++ ldr x21, =stext_offset
++ add x21, x0, x21
-@@ -1179,11 +1049,7 @@ static void __init __efi_enter_virtual_mode(void)
- free_pages((unsigned long)new_memmap, pg_shift);
+ /*
+ * Calculate size of the kernel Image (same for original and copy).
+diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
+index 95c49eb..f9de195 100644
+--- a/arch/arm64/kernel/efi.c
++++ b/arch/arm64/kernel/efi.c
+@@ -11,6 +11,7 @@
+ *
+ */
- /* clean DUMMY object */
-- efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
-- EFI_VARIABLE_NON_VOLATILE |
-- EFI_VARIABLE_BOOTSERVICE_ACCESS |
-- EFI_VARIABLE_RUNTIME_ACCESS,
-- 0, NULL);
-+ efi_delete_dummy_variable();
- }
++#include <linux/dmi.h>
+ #include <linux/efi.h>
+ #include <linux/export.h>
+ #include <linux/memblock.h>
+@@ -112,8 +113,6 @@ static int __init uefi_init(void)
+ efi.systab->hdr.revision & 0xffff, vendor);
- void __init efi_enter_virtual_mode(void)
-@@ -1230,86 +1096,6 @@ u64 efi_mem_attributes(unsigned long phys_addr)
- return 0;
- }
+ retval = efi_config_init(NULL);
+- if (retval == 0)
+- set_bit(EFI_CONFIG_TABLES, &efi.flags);
--/*
-- * Some firmware implementations refuse to boot if there's insufficient space
-- * in the variable store. Ensure that we never use more than a safe limit.
-- *
-- * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
-- * store.
-- */
--efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
--{
-- efi_status_t status;
-- u64 storage_size, remaining_size, max_size;
--
-- if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
-- return 0;
--
-- status = efi.query_variable_info(attributes, &storage_size,
-- &remaining_size, &max_size);
-- if (status != EFI_SUCCESS)
-- return status;
--
-- /*
-- * We account for that by refusing the write if permitting it would
-- * reduce the available space to under 5KB. This figure was provided by
-- * Samsung, so should be safe.
-- */
-- if ((remaining_size - size < EFI_MIN_RESERVE) &&
-- !efi_no_storage_paranoia) {
--
-- /*
-- * Triggering garbage collection may require that the firmware
-- * generate a real EFI_OUT_OF_RESOURCES error. We can force
-- * that by attempting to use more space than is available.
-- */
-- unsigned long dummy_size = remaining_size + 1024;
-- void *dummy = kzalloc(dummy_size, GFP_ATOMIC);
--
-- if (!dummy)
-- return EFI_OUT_OF_RESOURCES;
--
-- status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
-- EFI_VARIABLE_NON_VOLATILE |
-- EFI_VARIABLE_BOOTSERVICE_ACCESS |
-- EFI_VARIABLE_RUNTIME_ACCESS,
-- dummy_size, dummy);
--
-- if (status == EFI_SUCCESS) {
-- /*
-- * This should have failed, so if it didn't make sure
-- * that we delete it...
-- */
-- efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
-- EFI_VARIABLE_NON_VOLATILE |
-- EFI_VARIABLE_BOOTSERVICE_ACCESS |
-- EFI_VARIABLE_RUNTIME_ACCESS,
-- 0, dummy);
-- }
--
-- kfree(dummy);
--
-- /*
-- * The runtime code may now have triggered a garbage collection
-- * run, so check the variable info again
-- */
-- status = efi.query_variable_info(attributes, &storage_size,
-- &remaining_size, &max_size);
--
-- if (status != EFI_SUCCESS)
-- return status;
+ out:
+ early_memunmap(efi.systab, sizeof(efi_system_table_t));
+@@ -125,17 +124,17 @@ out:
+ */
+ static __init int is_reserve_region(efi_memory_desc_t *md)
+ {
+- if (!is_normal_ram(md))
++ switch (md->type) {
++ case EFI_LOADER_CODE:
++ case EFI_LOADER_DATA:
++ case EFI_BOOT_SERVICES_CODE:
++ case EFI_BOOT_SERVICES_DATA:
++ case EFI_CONVENTIONAL_MEMORY:
+ return 0;
-
-- /*
-- * There still isn't enough room, so return an error
-- */
-- if (remaining_size - size < EFI_MIN_RESERVE)
-- return EFI_OUT_OF_RESOURCES;
-- }
+- if (md->attribute & EFI_MEMORY_RUNTIME)
+- return 1;
-
-- return EFI_SUCCESS;
--}
--EXPORT_SYMBOL_GPL(efi_query_variable_store);
+- if (md->type == EFI_ACPI_RECLAIM_MEMORY ||
+- md->type == EFI_RESERVED_TYPE)
+- return 1;
-
- static int __init parse_efi_cmdline(char *str)
- {
- if (*str == '=')
-@@ -1321,22 +1107,3 @@ static int __init parse_efi_cmdline(char *str)
- return 0;
+- return 0;
++ default:
++ break;
++ }
++ return is_normal_ram(md);
}
- early_param("efi", parse_efi_cmdline);
--
--void __init efi_apply_memmap_quirks(void)
--{
-- /*
-- * Once setup is done earlier, unmap the EFI memory map on mismatched
-- * firmware/kernel architectures since there is no support for runtime
-- * services.
-- */
-- if (!efi_runtime_supported()) {
-- pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
-- efi_unmap_memmap();
-- }
--
-- /*
-- * UV doesn't support the new EFI pagetable mapping yet.
-- */
-- if (is_uv_system())
-- set_bit(EFI_OLD_MEMMAP, &efi.flags);
--}
-diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
-new file mode 100644
-index 0000000..1b9c4c3
---- /dev/null
-+++ b/arch/x86/platform/efi/quirks.c
-@@ -0,0 +1,290 @@
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/time.h>
-+#include <linux/types.h>
-+#include <linux/efi.h>
-+#include <linux/slab.h>
-+#include <linux/memblock.h>
-+#include <linux/bootmem.h>
-+#include <linux/acpi.h>
-+#include <asm/efi.h>
-+#include <asm/uv/uv.h>
-+
-+#define EFI_MIN_RESERVE 5120
-+
-+#define EFI_DUMMY_GUID \
-+ EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9)
-+
-+static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
+
+ static __init void reserve_regions(void)
+@@ -471,3 +470,54 @@ err_unmap:
+ return -1;
+ }
+ early_initcall(arm64_enter_virtual_mode);
+
-+static bool efi_no_storage_paranoia;
++static int __init arm64_dmi_init(void)
++{
++ /*
++ * On arm64, DMI depends on UEFI, and dmi_scan_machine() needs to
++ * be called early because dmi_id_init(), which is an arch_initcall
++ * itself, depends on dmi_scan_machine() having been called already.
++ */
++ dmi_scan_machine();
++ if (dmi_available)
++ dmi_set_dump_stack_arch_desc();
++ return 0;
++}
++core_initcall(arm64_dmi_init);
+
+/*
-+ * Some firmware implementations refuse to boot if there's insufficient
-+ * space in the variable store. The implementation of garbage collection
-+ * in some FW versions causes stale (deleted) variables to take up space
-+ * longer than intended and space is only freed once the store becomes
-+ * almost completely full.
-+ *
-+ * Enabling this option disables the space checks in
-+ * efi_query_variable_store() and forces garbage collection.
++ * If nothing else is handling pm_power_off, use EFI
+ *
-+ * Only enable this option if deleting EFI variables does not free up
-+ * space in your variable store, e.g. if despite deleting variables
-+ * you're unable to create new ones.
++ * When Guenter Roeck's power-off handler call chain patches land,
++ * we just need to return true unconditionally.
+ */
-+static int __init setup_storage_paranoia(char *arg)
++bool efi_poweroff_required(void)
+{
-+ efi_no_storage_paranoia = true;
-+ return 0;
++ return pm_power_off == NULL;
+}
-+early_param("efi_no_storage_paranoia", setup_storage_paranoia);
+
-+/*
-+ * Deleting the dummy variable which kicks off garbage collection
-+*/
-+void efi_delete_dummy_variable(void)
++static int arm64_efi_restart(struct notifier_block *this,
++ unsigned long mode, void *cmd)
+{
-+ efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
-+ EFI_VARIABLE_NON_VOLATILE |
-+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
-+ EFI_VARIABLE_RUNTIME_ACCESS,
-+ 0, NULL);
++ efi_reboot(reboot_mode, cmd);
++ return NOTIFY_DONE;
+}
+
-+/*
-+ * Some firmware implementations refuse to boot if there's insufficient space
-+ * in the variable store. Ensure that we never use more than a safe limit.
-+ *
-+ * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
-+ * store.
-+ */
-+efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
-+{
-+ efi_status_t status;
-+ u64 storage_size, remaining_size, max_size;
++static struct notifier_block arm64_efi_restart_nb = {
++ .notifier_call = arm64_efi_restart,
++ .priority = INT_MAX,
++};
+
-+ if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
-+ return 0;
++static int __init arm64_register_efi_restart(void)
++{
++ int ret = 0;
+
-+ status = efi.query_variable_info(attributes, &storage_size,
-+ &remaining_size, &max_size);
-+ if (status != EFI_SUCCESS)
-+ return status;
++ if (efi_enabled(EFI_RUNTIME_SERVICES)) {
++ ret = register_restart_handler(&arm64_efi_restart_nb);
++ if (ret)
++ pr_err("%s: cannot register restart handler, %d\n",
++ __func__, ret);
++ }
++ return ret;
++}
++late_initcall(arm64_register_efi_restart);
+diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S
+index 38e704e..08cafc5 100644
+--- a/arch/arm64/kernel/entry-ftrace.S
++++ b/arch/arm64/kernel/entry-ftrace.S
+@@ -98,8 +98,8 @@
+ ENTRY(_mcount)
+ mcount_enter
+
+- ldr x0, =ftrace_trace_function
+- ldr x2, [x0]
++ adrp x0, ftrace_trace_function
++ ldr x2, [x0, #:lo12:ftrace_trace_function]
+ adr x0, ftrace_stub
+ cmp x0, x2 // if (ftrace_trace_function
+ b.eq skip_ftrace_call // != ftrace_stub) {
+@@ -115,14 +115,15 @@ skip_ftrace_call: // return;
+ mcount_exit // return;
+ // }
+ skip_ftrace_call:
+- ldr x1, =ftrace_graph_return
+- ldr x2, [x1] // if ((ftrace_graph_return
+- cmp x0, x2 // != ftrace_stub)
+- b.ne ftrace_graph_caller
+-
+- ldr x1, =ftrace_graph_entry // || (ftrace_graph_entry
+- ldr x2, [x1] // != ftrace_graph_entry_stub))
+- ldr x0, =ftrace_graph_entry_stub
++ adrp x1, ftrace_graph_return
++ ldr x2, [x1, #:lo12:ftrace_graph_return]
++ cmp x0, x2 // if ((ftrace_graph_return
++ b.ne ftrace_graph_caller // != ftrace_stub)
++
++ adrp x1, ftrace_graph_entry // || (ftrace_graph_entry
++ adrp x0, ftrace_graph_entry_stub // != ftrace_graph_entry_stub))
++ ldr x2, [x1, #:lo12:ftrace_graph_entry]
++ add x0, x0, #:lo12:ftrace_graph_entry_stub
+ cmp x0, x2
+ b.ne ftrace_graph_caller // ftrace_graph_caller();
+
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index 0a6e4f9..5a76e3a 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -132,6 +132,8 @@ efi_head:
+ #endif
+
+ #ifdef CONFIG_EFI
++ .globl stext_offset
++ .set stext_offset, stext - efi_head
+ .align 3
+ pe_header:
+ .ascii "PE"
+@@ -155,12 +157,12 @@ optional_header:
+ .long 0 // SizeOfInitializedData
+ .long 0 // SizeOfUninitializedData
+ .long efi_stub_entry - efi_head // AddressOfEntryPoint
+- .long stext - efi_head // BaseOfCode
++ .long stext_offset // BaseOfCode
+
+ extra_header_fields:
+ .quad 0 // ImageBase
+- .long 0x20 // SectionAlignment
+- .long 0x8 // FileAlignment
++ .long 0x1000 // SectionAlignment
++ .long PECOFF_FILE_ALIGNMENT // FileAlignment
+ .short 0 // MajorOperatingSystemVersion
+ .short 0 // MinorOperatingSystemVersion
+ .short 0 // MajorImageVersion
+@@ -172,7 +174,7 @@ extra_header_fields:
+ .long _end - efi_head // SizeOfImage
+
+ // Everything before the kernel image is considered part of the header
+- .long stext - efi_head // SizeOfHeaders
++ .long stext_offset // SizeOfHeaders
+ .long 0 // CheckSum
+ .short 0xa // Subsystem (EFI application)
+ .short 0 // DllCharacteristics
+@@ -217,16 +219,24 @@ section_table:
+ .byte 0
+ .byte 0 // end of 0 padding of section name
+ .long _end - stext // VirtualSize
+- .long stext - efi_head // VirtualAddress
++ .long stext_offset // VirtualAddress
+ .long _edata - stext // SizeOfRawData
+- .long stext - efi_head // PointerToRawData
++ .long stext_offset // PointerToRawData
+
+ .long 0 // PointerToRelocations (0 for executables)
+ .long 0 // PointerToLineNumbers (0 for executables)
+ .short 0 // NumberOfRelocations (0 for executables)
+ .short 0 // NumberOfLineNumbers (0 for executables)
+ .long 0xe0500020 // Characteristics (section flags)
+- .align 5
+
+ /*
-+ * We account for that by refusing the write if permitting it would
-+ * reduce the available space to under 5KB. This figure was provided by
-+ * Samsung, so should be safe.
++ * EFI will load stext onwards at the 4k section alignment
++ * described in the PE/COFF header. To ensure that instruction
++ * sequences using an adrp and a :lo12: immediate will function
++ * correctly at this alignment, we must ensure that stext is
++ * placed at a 4k boundary in the Image to begin with.
+ */
-+ if ((remaining_size - size < EFI_MIN_RESERVE) &&
-+ !efi_no_storage_paranoia) {
-+
-+ /*
-+ * Triggering garbage collection may require that the firmware
-+ * generate a real EFI_OUT_OF_RESOURCES error. We can force
-+ * that by attempting to use more space than is available.
-+ */
-+ unsigned long dummy_size = remaining_size + 1024;
-+ void *dummy = kzalloc(dummy_size, GFP_ATOMIC);
++ .align 12
+ #endif
+
+ ENTRY(stext)
+diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c
+index 7d37ead..354be2a 100644
+--- a/arch/arm64/kernel/io.c
++++ b/arch/arm64/kernel/io.c
+@@ -25,12 +25,26 @@
+ */
+ void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
+ {
+- unsigned char *t = to;
+- while (count) {
++ while (count && (!IS_ALIGNED((unsigned long)from, 8) ||
++ !IS_ALIGNED((unsigned long)to, 8))) {
++ *(u8 *)to = __raw_readb(from);
++ from++;
++ to++;
+ count--;
+- *t = readb(from);
+- t++;
++ }
+
-+ if (!dummy)
-+ return EFI_OUT_OF_RESOURCES;
++ while (count >= 8) {
++ *(u64 *)to = __raw_readq(from);
++ from += 8;
++ to += 8;
++ count -= 8;
++ }
+
-+ status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
-+ EFI_VARIABLE_NON_VOLATILE |
-+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
-+ EFI_VARIABLE_RUNTIME_ACCESS,
-+ dummy_size, dummy);
++ while (count) {
++ *(u8 *)to = __raw_readb(from);
+ from++;
++ to++;
++ count--;
+ }
+ }
+ EXPORT_SYMBOL(__memcpy_fromio);
+@@ -40,12 +54,26 @@ EXPORT_SYMBOL(__memcpy_fromio);
+ */
+ void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
+ {
+- const unsigned char *f = from;
+- while (count) {
++ while (count && (!IS_ALIGNED((unsigned long)to, 8) ||
++ !IS_ALIGNED((unsigned long)from, 8))) {
++ __raw_writeb(*(volatile u8 *)from, to);
++ from++;
++ to++;
+ count--;
+- writeb(*f, to);
+- f++;
++ }
+
-+ if (status == EFI_SUCCESS) {
-+ /*
-+ * This should have failed, so if it didn't make sure
-+ * that we delete it...
-+ */
-+ efi_delete_dummy_variable();
-+ }
++ while (count >= 8) {
++ __raw_writeq(*(volatile u64 *)from, to);
++ from += 8;
++ to += 8;
++ count -= 8;
++ }
+
-+ kfree(dummy);
++ while (count) {
++ __raw_writeb(*(volatile u8 *)from, to);
++ from++;
+ to++;
++ count--;
+ }
+ }
+ EXPORT_SYMBOL(__memcpy_toio);
+@@ -55,10 +83,28 @@ EXPORT_SYMBOL(__memcpy_toio);
+ */
+ void __memset_io(volatile void __iomem *dst, int c, size_t count)
+ {
+- while (count) {
++ u64 qc = (u8)c;
++
++ qc |= qc << 8;
++ qc |= qc << 16;
++ qc |= qc << 32;
++
++ while (count && !IS_ALIGNED((unsigned long)dst, 8)) {
++ __raw_writeb(c, dst);
++ dst++;
+ count--;
+- writeb(c, dst);
++ }
+
-+ /*
-+ * The runtime code may now have triggered a garbage collection
-+ * run, so check the variable info again
-+ */
-+ status = efi.query_variable_info(attributes, &storage_size,
-+ &remaining_size, &max_size);
++ while (count >= 8) {
++ __raw_writeq(qc, dst);
++ dst += 8;
++ count -= 8;
++ }
+
-+ if (status != EFI_SUCCESS)
-+ return status;
++ while (count) {
++ __raw_writeb(c, dst);
+ dst++;
++ count--;
+ }
+ }
+ EXPORT_SYMBOL(__memset_io);
+diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
+index ce5836c..978cd21 100644
+--- a/arch/arm64/kernel/pci.c
++++ b/arch/arm64/kernel/pci.c
+@@ -17,6 +17,8 @@
+ #include <linux/of_pci.h>
+ #include <linux/of_platform.h>
+ #include <linux/slab.h>
++#include <linux/acpi.h>
++#include <linux/pci-acpi.h>
+
+ #include <asm/pci-bridge.h>
+
+@@ -37,34 +39,99 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+ return res->start;
+ }
+
++int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
++{
++ struct pci_sysdata *sd;
+
-+ /*
-+ * There still isn't enough room, so return an error
-+ */
-+ if (remaining_size - size < EFI_MIN_RESERVE)
-+ return EFI_OUT_OF_RESOURCES;
++ if (!acpi_disabled) {
++ sd = bridge->bus->sysdata;
++ ACPI_COMPANION_SET(&bridge->dev, sd->companion);
+ }
++ return 0;
++}
+
-+ return EFI_SUCCESS;
+ /*
+ * Try to assign the IRQ number from DT when adding a new device
+ */
+ int pcibios_add_device(struct pci_dev *dev)
+ {
+- dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
++ if (acpi_disabled)
++ dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+
+ return 0;
+ }
+
++void pcibios_add_bus(struct pci_bus *bus)
++{
++ if (!acpi_disabled)
++ acpi_pci_add_bus(bus);
++}
+
+-#ifdef CONFIG_PCI_DOMAINS_GENERIC
+-static bool dt_domain_found = false;
++void pcibios_remove_bus(struct pci_bus *bus)
++{
++ if (!acpi_disabled)
++ acpi_pci_remove_bus(bus);
+}
-+EXPORT_SYMBOL_GPL(efi_query_variable_store);
+
-+/*
-+ * The UEFI specification makes it clear that the operating system is free to do
-+ * whatever it wants with boot services code after ExitBootServices() has been
-+ * called. Ignoring this recommendation a significant bunch of EFI implementations
-+ * continue calling into boot services code (SetVirtualAddressMap). In order to
-+ * work around such buggy implementations we reserve boot services region during
-+ * EFI init and make sure it stays executable. Then, after SetVirtualAddressMap(), it
-+* is discarded.
-+*/
-+void __init efi_reserve_boot_services(void)
-+{
-+ void *p;
-+
-+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-+ efi_memory_desc_t *md = p;
-+ u64 start = md->phys_addr;
-+ u64 size = md->num_pages << EFI_PAGE_SHIFT;
-+
-+ if (md->type != EFI_BOOT_SERVICES_CODE &&
-+ md->type != EFI_BOOT_SERVICES_DATA)
-+ continue;
-+ /* Only reserve where possible:
-+ * - Not within any already allocated areas
-+ * - Not over any memory area (really needed, if above?)
-+ * - Not within any part of the kernel
-+ * - Not the bios reserved area
-+ */
-+ if ((start + size > __pa_symbol(_text)
-+ && start <= __pa_symbol(_end)) ||
-+ !e820_all_mapped(start, start+size, E820_RAM) ||
-+ memblock_is_region_reserved(start, size)) {
-+ /* Could not reserve, skip it */
-+ md->num_pages = 0;
-+ memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n",
-+ start, start+size-1);
-+ } else
-+ memblock_reserve(start, size);
-+ }
-+}
-+
-+void __init efi_free_boot_services(void)
-+{
-+ void *p;
-+
-+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-+ efi_memory_desc_t *md = p;
-+ unsigned long long start = md->phys_addr;
-+ unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
-+
-+ if (md->type != EFI_BOOT_SERVICES_CODE &&
-+ md->type != EFI_BOOT_SERVICES_DATA)
-+ continue;
++int pcibios_enable_irq(struct pci_dev *dev)
++{
++ if (!acpi_disabled && !pci_dev_msi_enabled(dev))
++ acpi_pci_irq_enable(dev);
++ return 0;
++}
+
-+ /* Could not reserve boot area */
-+ if (!size)
-+ continue;
++int pcibios_disable_irq(struct pci_dev *dev)
++{
++ if (!acpi_disabled && !pci_dev_msi_enabled(dev))
++ acpi_pci_irq_disable(dev);
++ return 0;
++}
+
++int pcibios_enable_device(struct pci_dev *dev, int bars)
++{
++ int err;
+
-+ free_bootmem_late(start, size);
-+ }
++ err = pci_enable_resources(dev, bars);
++ if (err < 0)
++ return err;
+
-+ efi_unmap_memmap();
++ if (!pci_dev_msi_enabled(dev))
++ return pcibios_enable_irq(dev);
++ return 0;
+}
+
-+/*
-+ * A number of config table entries get remapped to virtual addresses
-+ * after entering EFI virtual mode. However, the kexec kernel requires
-+ * their physical addresses therefore we pass them via setup_data and
-+ * correct those entries to their respective physical addresses here.
-+ *
-+ * Currently only handles smbios which is necessary for some firmware
-+ * implementation.
-+ */
-+int __init efi_reuse_config(u64 tables, int nr_tables)
-+{
-+ int i, sz, ret = 0;
-+ void *p, *tablep;
-+ struct efi_setup_data *data;
++#ifdef CONFIG_PCI_DOMAINS_GENERIC
+ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+ {
+- int domain = of_get_pci_domain_nr(parent->of_node);
+-
+- if (domain >= 0) {
+- dt_domain_found = true;
+- } else if (dt_domain_found == true) {
+- dev_err(parent, "Node %s is missing \"linux,pci-domain\" property in DT\n",
+- parent->of_node->full_name);
+- return;
+- } else {
+- domain = pci_get_new_domain_nr();
+- }
++ int domain = -1;
+
+- bus->domain_nr = domain;
++ if (acpi_disabled)
++ domain = of_get_pci_domain_nr(parent->of_node);
++ else {
++ struct pci_sysdata *sd = bus->sysdata;
+
-+ if (!efi_setup)
-+ return 0;
++ domain = sd->domain;
++ }
++ if (domain >= 0)
++ bus->domain_nr = domain;
+ }
+ #endif
+
-+ if (!efi_enabled(EFI_64BIT))
++static int __init pcibios_assign_resources(void)
++{
++ struct pci_bus *root_bus;
++
++ if (acpi_disabled)
+ return 0;
+
-+ data = early_memremap(efi_setup, sizeof(*data));
-+ if (!data) {
-+ ret = -ENOMEM;
-+ goto out;
++ list_for_each_entry(root_bus, &pci_root_buses, node) {
++ pcibios_resource_survey_bus(root_bus);
++ pci_assign_unassigned_root_bus_resources(root_bus);
+ }
++ return 0;
++}
++/*
++ * fs_initcall comes after subsys_initcall, so we know acpi scan
++ * has run.
++ */
++fs_initcall(pcibios_assign_resources);
+diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
+index 663da77..2d0deda 100644
+--- a/arch/arm64/kernel/psci.c
++++ b/arch/arm64/kernel/psci.c
+@@ -15,6 +15,7 @@
+
+ #define pr_fmt(fmt) "psci: " fmt
+
++#include <linux/acpi.h>
+ #include <linux/init.h>
+ #include <linux/of.h>
+ #include <linux/smp.h>
+@@ -24,6 +25,7 @@
+ #include <linux/slab.h>
+ #include <uapi/linux/psci.h>
+
++#include <asm/acpi.h>
+ #include <asm/compiler.h>
+ #include <asm/cpu_ops.h>
+ #include <asm/errno.h>
+@@ -304,6 +306,33 @@ static void psci_sys_poweroff(void)
+ invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
+ }
+
++static void psci_0_2_set_functions(void)
++{
++ pr_info("Using standard PSCI v0.2 function IDs\n");
++ psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
++ psci_ops.cpu_suspend = psci_cpu_suspend;
+
-+ if (!data->smbios)
-+ goto out_memremap;
++ psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
++ psci_ops.cpu_off = psci_cpu_off;
+
-+ sz = sizeof(efi_config_table_64_t);
++ psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
++ psci_ops.cpu_on = psci_cpu_on;
+
-+ p = tablep = early_memremap(tables, nr_tables * sz);
-+ if (!p) {
-+ pr_err("Could not map Configuration table!\n");
-+ ret = -ENOMEM;
-+ goto out_memremap;
-+ }
++ psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
++ psci_ops.migrate = psci_migrate;
+
-+ for (i = 0; i < efi.systab->nr_tables; i++) {
-+ efi_guid_t guid;
++ psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
++ psci_ops.affinity_info = psci_affinity_info;
+
-+ guid = ((efi_config_table_64_t *)p)->guid;
++ psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
++ PSCI_0_2_FN_MIGRATE_INFO_TYPE;
++ psci_ops.migrate_info_type = psci_migrate_info_type;
+
-+ if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID))
-+ ((efi_config_table_64_t *)p)->table = data->smbios;
-+ p += sz;
-+ }
-+ early_iounmap(tablep, nr_tables * sz);
++ arm_pm_restart = psci_sys_reset;
+
-+out_memremap:
-+ early_iounmap(data, sizeof(*data));
-+out:
-+ return ret;
++ pm_power_off = psci_sys_poweroff;
+}
+
-+void __init efi_apply_memmap_quirks(void)
+ /*
+ * PSCI Function IDs for v0.2+ are well defined so use
+ * standard values.
+@@ -337,29 +366,7 @@ static int __init psci_0_2_init(struct device_node *np)
+ }
+ }
+
+- pr_info("Using standard PSCI v0.2 function IDs\n");
+- psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
+- psci_ops.cpu_suspend = psci_cpu_suspend;
+-
+- psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
+- psci_ops.cpu_off = psci_cpu_off;
+-
+- psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
+- psci_ops.cpu_on = psci_cpu_on;
+-
+- psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
+- psci_ops.migrate = psci_migrate;
+-
+- psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
+- psci_ops.affinity_info = psci_affinity_info;
+-
+- psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
+- PSCI_0_2_FN_MIGRATE_INFO_TYPE;
+- psci_ops.migrate_info_type = psci_migrate_info_type;
+-
+- arm_pm_restart = psci_sys_reset;
+-
+- pm_power_off = psci_sys_poweroff;
++ psci_0_2_set_functions();
+
+ out_put_node:
+ of_node_put(np);
+@@ -412,7 +419,7 @@ static const struct of_device_id psci_of_match[] __initconst = {
+ {},
+ };
+
+-int __init psci_init(void)
++int __init psci_dt_init(void)
+ {
+ struct device_node *np;
+ const struct of_device_id *matched_np;
+@@ -427,6 +434,29 @@ int __init psci_init(void)
+ return init_fn(np);
+ }
+
++/*
++ * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
++ * explicitly clarified in SBBR
++ */
++int __init psci_acpi_init(void)
+{
-+ /*
-+ * Once setup is done earlier, unmap the EFI memory map on mismatched
-+ * firmware/kernel architectures since there is no support for runtime
-+ * services.
-+ */
-+ if (!efi_runtime_supported()) {
-+ pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
-+ efi_unmap_memmap();
++ if (!acpi_psci_present()) {
++ pr_info("is not implemented in ACPI.\n");
++ return -EOPNOTSUPP;
+ }
+
-+ /*
-+ * UV doesn't support the new EFI pagetable mapping yet.
-+ */
-+ if (is_uv_system())
-+ set_bit(EFI_OLD_MEMMAP, &efi.flags);
-+}
++ pr_info("probing for conduit method from ACPI.\n");
+
-+/*
-+ * For most modern platforms the preferred method of powering off is via
-+ * ACPI. However, there are some that are known to require the use of
-+ * EFI runtime services and for which ACPI does not work at all.
-+ *
-+ * Using EFI is a last resort, to be used only if no other option
-+ * exists.
-+ */
-+bool efi_reboot_required(void)
-+{
-+ if (!acpi_gbl_reduced_hardware)
-+ return false;
++ if (acpi_psci_use_hvc())
++ invoke_psci_fn = __invoke_psci_fn_hvc;
++ else
++ invoke_psci_fn = __invoke_psci_fn_smc;
+
-+ efi_reboot_quirk_mode = EFI_RESET_WARM;
-+ return true;
-+}
++ psci_0_2_set_functions();
+
-+bool efi_poweroff_required(void)
-+{
-+ return !!acpi_gbl_reduced_hardware;
++ return 0;
+}
-diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
-index ee3a365..f9431b4 100644
---- a/drivers/ata/ahci_xgene.c
-+++ b/drivers/ata/ahci_xgene.c
-@@ -131,7 +131,8 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
- struct xgene_ahci_context *ctx = hpriv->plat_data;
- int rc = 0;
++
+ #ifdef CONFIG_SMP
-- if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA))
-+ if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA ||
-+ ctx->last_cmd[ap->port_no] == ATA_CMD_SMART))
- xgene_ahci_restart_engine(ap);
+ static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu)
+diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
+index 2437196..914287d 100644
+--- a/arch/arm64/kernel/setup.c
++++ b/arch/arm64/kernel/setup.c
+@@ -43,6 +43,7 @@
+ #include <linux/of_fdt.h>
+ #include <linux/of_platform.h>
+ #include <linux/efi.h>
++#include <linux/acpi.h>
+ #include <linux/personality.h>
- rc = ahci_qc_issue(qc);
-diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
-index 9553496..c135154 100644
---- a/drivers/firmware/efi/Makefile
-+++ b/drivers/firmware/efi/Makefile
-@@ -1,7 +1,7 @@
- #
- # Makefile for linux kernel
- #
--obj-$(CONFIG_EFI) += efi.o vars.o
-+obj-$(CONFIG_EFI) += efi.o vars.o reboot.o
- obj-$(CONFIG_EFI_VARS) += efivars.o
- obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
- obj-$(CONFIG_UEFI_CPER) += cper.o
-diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c
-new file mode 100644
-index 0000000..f94fb95
---- /dev/null
-+++ b/drivers/firmware/efi/reboot.c
-@@ -0,0 +1,55 @@
-+/*
-+ * Copyright (C) 2014 Intel Corporation; author Matt Fleming
-+ */
-+#include <linux/efi.h>
-+#include <linux/reboot.h>
-+
-+int efi_reboot_quirk_mode = -1;
+ #include <asm/fixmap.h>
+@@ -59,6 +60,7 @@
+ #include <asm/memblock.h>
+ #include <asm/psci.h>
+ #include <asm/efi.h>
++#include <asm/acpi.h>
+
+ unsigned int processor_id;
+ EXPORT_SYMBOL(processor_id);
+@@ -116,12 +118,16 @@ void __init early_print(const char *str, ...)
+
+ void __init smp_setup_processor_id(void)
+ {
++ u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
++ cpu_logical_map(0) = mpidr;
+
-+void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
-+{
-+ int efi_mode;
+ /*
+ * clear __my_cpu_offset on boot CPU to avoid hang caused by
+ * using percpu variable early, for example, lockdep will
+ * access percpu variable inside lock_release
+ */
+ set_my_cpu_offset(0);
++ pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr);
+ }
+
+ bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+@@ -312,6 +318,7 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
+ while (true)
+ cpu_relax();
+ }
++ dump_stack_set_arch_desc("%s (DT)", machine_name);
+ }
+
+ /*
+@@ -378,6 +385,8 @@ void __init setup_arch(char **cmdline_p)
+
+ early_ioremap_init();
+
++ disable_acpi();
+
-+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
-+ return;
+ parse_early_param();
+
+ /*
+@@ -389,19 +398,27 @@ void __init setup_arch(char **cmdline_p)
+ efi_init();
+ arm64_memblock_init();
+
++ /* Parse the ACPI tables for possible boot-time configuration */
++ acpi_boot_table_init();
+
-+ switch (reboot_mode) {
-+ case REBOOT_WARM:
-+ case REBOOT_SOFT:
-+ efi_mode = EFI_RESET_WARM;
-+ break;
-+ default:
-+ efi_mode = EFI_RESET_COLD;
-+ break;
+ paging_init();
+ request_standard_resources();
+
+ efi_idmap_init();
+ early_ioremap_reset();
+
+- unflatten_device_tree();
+-
+- psci_init();
++ if (acpi_disabled) {
++ unflatten_device_tree();
++ psci_dt_init();
++ cpu_read_bootcpu_ops();
++#ifdef CONFIG_SMP
++ of_smp_init_cpus();
++#endif
++ } else {
++ psci_acpi_init();
++ acpi_smp_init_cpus();
+ }
+
+- cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
+- cpu_read_bootcpu_ops();
+ #ifdef CONFIG_SMP
+- smp_init_cpus();
+ smp_build_mpidr_hash();
+ #endif
+
+@@ -506,3 +523,25 @@ const struct seq_operations cpuinfo_op = {
+ .stop = c_stop,
+ .show = c_show
+ };
+
-+ /*
-+ * If a quirk forced an EFI reset mode, always use that.
-+ */
-+ if (efi_reboot_quirk_mode != -1)
-+ efi_mode = efi_reboot_quirk_mode;
-+
-+ efi.reset_system(efi_mode, EFI_SUCCESS, 0, NULL);
-+}
-+
-+bool __weak efi_poweroff_required(void)
++/*
++ * Temporary hack to avoid need for console= on command line
++ */
++static int __init arm64_console_setup(void)
+{
-+ return false;
-+}
++ /* Allow cmdline to override our assumed preferences */
++ if (console_set_on_cmdline)
++ return 0;
+
-+static void efi_power_off(void)
-+{
-+ efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
-+}
++ if (IS_ENABLED(CONFIG_SBSAUART_TTY))
++ add_preferred_console("ttySBSA", 0, "115200");
+
-+static int __init efi_shutdown_init(void)
-+{
-+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
-+ return -ENODEV;
++ if (IS_ENABLED(CONFIG_SERIAL_AMBA_PL011))
++ add_preferred_console("ttyAMA", 0, "115200");
+
-+ if (efi_poweroff_required())
-+ pm_power_off = efi_power_off;
++ if (IS_ENABLED(CONFIG_SERIAL_8250))
++ add_preferred_console("ttyS", 0, "115200");
+
+ return 0;
+}
-+late_initcall(efi_shutdown_init);
-diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
-index bbb746e..7f0c2a3 100644
---- a/drivers/irqchip/Kconfig
-+++ b/drivers/irqchip/Kconfig
-@@ -10,6 +10,11 @@ config ARM_GIC
- config GIC_NON_BANKED
- bool
-
-+config ARM_GIC_V3
-+ bool
-+ select IRQ_DOMAIN
-+ select MULTI_IRQ_HANDLER
-+
- config ARM_NVIC
- bool
- select IRQ_DOMAIN
-diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
-index 62a13e5..c57e642 100644
---- a/drivers/irqchip/Makefile
-+++ b/drivers/irqchip/Makefile
-@@ -15,7 +15,8 @@ obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
- obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
- obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o
- obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
--obj-$(CONFIG_ARM_GIC) += irq-gic.o
-+obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o
-+obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o
- obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
- obj-$(CONFIG_ARM_VIC) += irq-vic.o
- obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o
-diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
++early_initcall(arm64_console_setup);
+diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
+index b06d1d9..2988829 100644
+--- a/arch/arm64/kernel/smp.c
++++ b/arch/arm64/kernel/smp.c
+@@ -321,7 +321,7 @@ void __init smp_prepare_boot_cpu(void)
+ * cpu logical map array containing MPIDR values related to logical
+ * cpus. Assumes that cpu_logical_map(0) has already been initialized.
+ */
+-void __init smp_init_cpus(void)
++void __init of_smp_init_cpus(void)
+ {
+ struct device_node *dn = NULL;
+ unsigned int i, cpu = 1;
+diff --git a/arch/arm64/kernel/smp_parking_protocol.c b/arch/arm64/kernel/smp_parking_protocol.c
new file mode 100644
-index 0000000..60ac704
+index 0000000..e1153ce
--- /dev/null
-+++ b/drivers/irqchip/irq-gic-common.c
-@@ -0,0 +1,115 @@
++++ b/arch/arm64/kernel/smp_parking_protocol.c
+@@ -0,0 +1,110 @@
+/*
-+ * Copyright (C) 2002 ARM Limited, All Rights Reserved.
++ * Parking Protocol SMP initialisation
++ *
++ * Based largely on spin-table method.
++ *
++ * Copyright (C) 2013 ARM Ltd.
+ *
+ * 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
@@ -3755,4017 +4627,6933 @@ index 0000000..60ac704
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/of.h>
++#include <linux/smp.h>
++#include <linux/types.h>
++#include <linux/acpi.h>
+
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/irq.h>
-+#include <linux/irqchip/arm-gic.h>
++#include <asm/cacheflush.h>
++#include <asm/cpu_ops.h>
++#include <asm/cputype.h>
++#include <asm/smp_plat.h>
+
-+#include "irq-gic-common.h"
++static phys_addr_t cpu_mailbox_addr[NR_CPUS];
+
-+void gic_configure_irq(unsigned int irq, unsigned int type,
-+ void __iomem *base, void (*sync_access)(void))
-+{
-+ u32 enablemask = 1 << (irq % 32);
-+ u32 enableoff = (irq / 32) * 4;
-+ u32 confmask = 0x2 << ((irq % 16) * 2);
-+ u32 confoff = (irq / 16) * 4;
-+ bool enabled = false;
-+ u32 val;
++static void (*__smp_boot_wakeup)(int cpu);
+
-+ /*
-+ * Read current configuration register, and insert the config
-+ * for "irq", depending on "type".
-+ */
-+ val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
-+ if (type == IRQ_TYPE_LEVEL_HIGH)
-+ val &= ~confmask;
-+ else if (type == IRQ_TYPE_EDGE_RISING)
-+ val |= confmask;
++void set_smp_boot_wakeup_call(void (*fn)(int cpu))
++{
++ __smp_boot_wakeup = fn;
++}
+
++static int smp_parking_protocol_cpu_init(struct device_node *dn,
++ unsigned int cpu)
++{
+ /*
-+ * As recommended by the spec, disable the interrupt before changing
-+ * the configuration
++ * Determine the mailbox address.
+ */
-+ if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
-+ writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
-+ if (sync_access)
-+ sync_access();
-+ enabled = true;
++ if (!acpi_get_cpu_parked_address(cpu, &cpu_mailbox_addr[cpu])) {
++ pr_info("%s: ACPI parked addr=%llx\n",
++ __func__, cpu_mailbox_addr[cpu]);
++ return 0;
+ }
+
-+ /*
-+ * Write back the new configuration, and possibly re-enable
-+ * the interrupt.
-+ */
-+ writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
++ pr_err("CPU %d: missing or invalid parking protocol mailbox\n", cpu);
+
-+ if (enabled)
-+ writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
++ return -1;
++}
+
-+ if (sync_access)
-+ sync_access();
++static int smp_parking_protocol_cpu_prepare(unsigned int cpu)
++{
++ return 0;
+}
+
-+void __init gic_dist_config(void __iomem *base, int gic_irqs,
-+ void (*sync_access)(void))
++struct parking_protocol_mailbox {
++ __le32 cpu_id;
++ __le32 reserved;
++ __le64 entry_point;
++};
++
++static int smp_parking_protocol_cpu_boot(unsigned int cpu)
+{
-+ unsigned int i;
++ struct parking_protocol_mailbox __iomem *mailbox;
++
++ if (!cpu_mailbox_addr[cpu] || !__smp_boot_wakeup)
++ return -ENODEV;
+
+ /*
-+ * Set all global interrupts to be level triggered, active low.
++ * The mailbox may or may not be inside the linear mapping.
++ * As ioremap_cache will either give us a new mapping or reuse the
++ * existing linear mapping, we can use it to cover both cases. In
++ * either case the memory will be MT_NORMAL.
+ */
-+ for (i = 32; i < gic_irqs; i += 16)
-+ writel_relaxed(0, base + GIC_DIST_CONFIG + i / 4);
++ mailbox = ioremap_cache(cpu_mailbox_addr[cpu], sizeof(*mailbox));
++ if (!mailbox)
++ return -ENOMEM;
+
+ /*
-+ * Set priority on all global interrupts.
++ * We write the entry point and cpu id as LE regardless of the
++ * native endianess of the kernel. Therefore, any boot-loaders
++ * that read this address need to convert this address to the
++ * Boot-Loader's endianess before jumping.
+ */
-+ for (i = 32; i < gic_irqs; i += 4)
-+ writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i);
++ writeq(__pa(secondary_entry), &mailbox->entry_point);
++ writel(cpu, &mailbox->cpu_id);
++ __flush_dcache_area(mailbox, sizeof(*mailbox));
++ __smp_boot_wakeup(cpu);
++
++ /* temp hack for broken firmware */
++ sev();
+
++ iounmap(mailbox);
++
++ return 0;
++}
++
++const struct cpu_operations smp_parking_protocol_ops = {
++ .name = "parking-protocol",
++ .cpu_init = smp_parking_protocol_cpu_init,
++ .cpu_prepare = smp_parking_protocol_cpu_prepare,
++ .cpu_boot = smp_parking_protocol_cpu_boot,
++};
+diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
+index 1a7125c..42f9195 100644
+--- a/arch/arm64/kernel/time.c
++++ b/arch/arm64/kernel/time.c
+@@ -35,6 +35,7 @@
+ #include <linux/delay.h>
+ #include <linux/clocksource.h>
+ #include <linux/clk-provider.h>
++#include <linux/acpi.h>
+
+ #include <clocksource/arm_arch_timer.h>
+
+@@ -72,6 +73,12 @@ void __init time_init(void)
+
+ tick_setup_hrtimer_broadcast();
+
+ /*
-+ * Disable all interrupts. Leave the PPI and SGIs alone
-+ * as they are enabled by redistributor registers.
++ * Since ACPI or FDT will only one be available in the system,
++ * we can use acpi_generic_timer_init() here safely
+ */
-+ for (i = 32; i < gic_irqs; i += 32)
-+ writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i / 8);
++ acpi_generic_timer_init();
++
+ arch_timer_rate = arch_timer_get_rate();
+ if (!arch_timer_rate)
+ panic("Unable to initialise architected timer.\n");
+diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
+index edf8715..4596f46 100644
+--- a/arch/arm64/kernel/vmlinux.lds.S
++++ b/arch/arm64/kernel/vmlinux.lds.S
+@@ -32,6 +32,22 @@ jiffies = jiffies_64;
+ *(.hyp.text) \
+ VMLINUX_SYMBOL(__hyp_text_end) = .;
+
++/*
++ * The size of the PE/COFF section that covers the kernel image, which
++ * runs from stext to _edata, must be a round multiple of the PE/COFF
++ * FileAlignment, which we set to its minimum value of 0x200. 'stext'
++ * itself is 4 KB aligned, so padding out _edata to a 0x200 aligned
++ * boundary should be sufficient.
++ */
++PECOFF_FILE_ALIGNMENT = 0x200;
+
-+ if (sync_access)
-+ sync_access();
-+}
++#ifdef CONFIG_EFI
++#define PECOFF_EDATA_PADDING \
++ .pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); }
++#else
++#define PECOFF_EDATA_PADDING
++#endif
+
-+void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
+ SECTIONS
+ {
+ /*
+@@ -103,6 +119,7 @@ SECTIONS
+ _data = .;
+ _sdata = .;
+ RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE)
++ PECOFF_EDATA_PADDING
+ _edata = .;
+
+ BSS_SECTION(0, 0, 0)
+diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
+index b72aa9f..fbe909f 100644
+--- a/arch/arm64/kvm/hyp.S
++++ b/arch/arm64/kvm/hyp.S
+@@ -761,10 +761,10 @@
+ .macro activate_traps
+ ldr x2, [x0, #VCPU_HCR_EL2]
+ msr hcr_el2, x2
+- ldr x2, =(CPTR_EL2_TTA)
++ mov x2, #CPTR_EL2_TTA
+ msr cptr_el2, x2
+
+- ldr x2, =(1 << 15) // Trap CP15 Cr=15
++ mov x2, #(1 << 15) // Trap CP15 Cr=15
+ msr hstr_el2, x2
+
+ mrs x2, mdcr_el2
+diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
+index d920942..cf890e3 100644
+--- a/arch/arm64/mm/dma-mapping.c
++++ b/arch/arm64/mm/dma-mapping.c
+@@ -23,8 +23,14 @@
+ #include <linux/genalloc.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dma-contiguous.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
+ #include <linux/vmalloc.h>
+ #include <linux/swiotlb.h>
++#include <linux/amba/bus.h>
++#include <linux/acpi.h>
++#include <linux/pci.h>
+
+ #include <asm/cacheflush.h>
+
+@@ -423,10 +429,116 @@ out:
+ return -ENOMEM;
+ }
+
++#ifdef CONFIG_PCI
++static void arm64_of_set_dma_ops(void *_dev)
+{
-+ int i;
++ struct device *dev = _dev;
+
+ /*
-+ * Deal with the banked PPI and SGI interrupts - disable all
-+ * PPI interrupts, ensure all SGI interrupts are enabled.
++ * PCI devices won't have an ACPI handle but the bridge will.
++ * Search up the device chain until we find an of_node
++ * to check.
+ */
-+ writel_relaxed(0xffff0000, base + GIC_DIST_ENABLE_CLEAR);
-+ writel_relaxed(0x0000ffff, base + GIC_DIST_ENABLE_SET);
++ while (dev) {
++ if (dev->of_node) {
++ if (of_dma_is_coherent(dev->of_node))
++ set_dma_ops(_dev, &coherent_swiotlb_dma_ops);
++ break;
++ }
++ dev = dev->parent;
++ }
++}
++#else
++static inline arm64_of_set_dma_ops(void *_dev) {}
++#endif
++
++
++#ifdef CONFIG_ACPI
++static void arm64_acpi_set_dma_ops(void *_dev)
++{
++ struct device *dev = _dev;
+
+ /*
-+ * Set priority on PPI and SGI interrupts
++ * Kernel defaults to noncoherent ops but ACPI 5.1 spec says arm64
++ * defaults to coherent. For PCI devices, the _CCA is only a default
++ * setting. Individual devices on a PCIe bus may set transaction
++ * ordering and caching attributes individually. Such drivers will
++ * also be resonsible for using the correct DMA ops for the cache
++ * conherence used.
++ *
++ * PCI devices won't have a handle but the bridge will.
++ * Search up the device chain until we find an ACPI handle
++ * to check.
+ */
-+ for (i = 0; i < 32; i += 4)
-+ writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
++ while (dev) {
++ if (ACPI_HANDLE(dev)) {
++ acpi_status status;
++ int coherent;
++ struct dma_map_ops *ops;
++
++ status = acpi_check_coherency(ACPI_HANDLE(dev),
++ &coherent);
++ if (ACPI_FAILURE(status) || coherent)
++ ops = &coherent_swiotlb_dma_ops;
++ else
++ ops = &noncoherent_swiotlb_dma_ops;
++
++ set_dma_ops(_dev, ops);
++ break;
++ }
++ dev = dev->parent;
++ }
++}
++#else
++static inline arm64_acpi_set_dma_ops(void *_dev) {}
++#endif
++
++static int dma_bus_notifier(struct notifier_block *nb,
++ unsigned long event, void *_dev)
++{
++ if (event != BUS_NOTIFY_ADD_DEVICE)
++ return NOTIFY_DONE;
++
++ if (acpi_disabled)
++ arm64_of_set_dma_ops(_dev);
++ else
++ arm64_acpi_set_dma_ops(_dev);
+
-+ if (sync_access)
-+ sync_access();
++ return NOTIFY_OK;
+}
-diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
-new file mode 100644
-index 0000000..b41f024
---- /dev/null
-+++ b/drivers/irqchip/irq-gic-common.h
-@@ -0,0 +1,29 @@
-+/*
-+ * Copyright (C) 2002 ARM Limited, All Rights Reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
+
-+#ifndef _IRQ_GIC_COMMON_H
-+#define _IRQ_GIC_COMMON_H
++#ifdef CONFIG_ACPI
++static struct notifier_block platform_bus_nb = {
++ .notifier_call = dma_bus_notifier,
++};
+
-+#include <linux/of.h>
-+#include <linux/irqdomain.h>
++static struct notifier_block amba_bus_nb = {
++ .notifier_call = dma_bus_notifier,
++};
++#endif
+
-+void gic_configure_irq(unsigned int irq, unsigned int type,
-+ void __iomem *base, void (*sync_access)(void));
-+void gic_dist_config(void __iomem *base, int gic_irqs,
-+ void (*sync_access)(void));
-+void gic_cpu_config(void __iomem *base, void (*sync_access)(void));
++#ifdef CONFIG_PCI
++static struct notifier_block pci_bus_nb = {
++ .notifier_call = dma_bus_notifier,
++};
++#endif
+
-+#endif /* _IRQ_GIC_COMMON_H */
-diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
+ static int __init swiotlb_late_init(void)
+ {
+ size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
+
++ /*
++ * These must be registered before of_platform_populate().
++ */
++#ifdef CONFIG_ACPI
++ bus_register_notifier(&platform_bus_type, &platform_bus_nb);
++ bus_register_notifier(&amba_bustype, &amba_bus_nb);
++#endif
++
++#ifdef CONFIG_PCI
++ bus_register_notifier(&pci_bus_type, &pci_bus_nb);
++#endif
++
+ dma_ops = &noncoherent_swiotlb_dma_ops;
+
+ return swiotlb_late_init_with_default_size(swiotlb_size);
+diff --git a/arch/arm64/pci/Makefile b/arch/arm64/pci/Makefile
new file mode 100644
-index 0000000..81519ba
+index 0000000..7038b51
--- /dev/null
-+++ b/drivers/irqchip/irq-gic-v3.c
-@@ -0,0 +1,692 @@
++++ b/arch/arm64/pci/Makefile
+@@ -0,0 +1,2 @@
++obj-y += pci.o
++obj-$(CONFIG_ACPI) += mmconfig.o
+diff --git a/arch/arm64/pci/mmconfig.c b/arch/arm64/pci/mmconfig.c
+new file mode 100644
+index 0000000..e83e0d5
+--- /dev/null
++++ b/arch/arm64/pci/mmconfig.c
+@@ -0,0 +1,292 @@
+/*
-+ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
-+ * Author: Marc Zyngier <marc.zyngier@arm.com>
++ * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ * Borrowed heavily from x86
+ */
+
-+#include <linux/cpu.h>
-+#include <linux/delay.h>
-+#include <linux/interrupt.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/percpu.h>
++#include <linux/pci.h>
++#include <linux/acpi.h>
++#include <linux/init.h>
++#include <linux/bitmap.h>
++#include <linux/dmi.h>
+#include <linux/slab.h>
++#include <linux/mutex.h>
++#include <linux/rculist.h>
++#include <linux/rcupdate.h>
+
-+#include <linux/irqchip/arm-gic-v3.h>
++#define PREFIX "PCI: "
+
-+#include <asm/cputype.h>
-+#include <asm/exception.h>
-+#include <asm/smp_plat.h>
++/* Indicate if the mmcfg resources have been placed into the resource table. */
++static bool pci_mmcfg_running_state;
++static bool pci_mmcfg_arch_init_failed;
++static DEFINE_MUTEX(pci_mmcfg_lock);
+
-+#include "irq-gic-common.h"
-+#include "irqchip.h"
-+
-+struct gic_chip_data {
-+ void __iomem *dist_base;
-+ void __iomem **redist_base;
-+ void __percpu __iomem **rdist;
-+ struct irq_domain *domain;
-+ u64 redist_stride;
-+ u32 redist_regions;
-+ unsigned int irq_nr;
-+};
++LIST_HEAD(pci_mmcfg_list);
+
-+static struct gic_chip_data gic_data __read_mostly;
++struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
++{
++ struct pci_mmcfg_region *cfg;
+
-+#define gic_data_rdist() (this_cpu_ptr(gic_data.rdist))
-+#define gic_data_rdist_rd_base() (*gic_data_rdist())
-+#define gic_data_rdist_sgi_base() (gic_data_rdist_rd_base() + SZ_64K)
++ list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
++ if (cfg->segment == segment &&
++ cfg->start_bus <= bus && bus <= cfg->end_bus)
++ return cfg;
+
-+/* Our default, arbitrary priority value. Linux only uses one anyway. */
-+#define DEFAULT_PMR_VALUE 0xf0
++ return NULL;
++}
+
-+static inline unsigned int gic_irq(struct irq_data *d)
++static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
+{
-+ return d->hwirq;
++ void __iomem *addr;
++ u64 start, size;
++ int num_buses;
++
++ start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
++ num_buses = cfg->end_bus - cfg->start_bus + 1;
++ size = PCI_MMCFG_BUS_OFFSET(num_buses);
++ addr = ioremap_nocache(start, size);
++ if (addr)
++ addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
++ return addr;
+}
+
-+static inline int gic_irq_in_rdist(struct irq_data *d)
++void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
+{
-+ return gic_irq(d) < 32;
++ if (cfg && cfg->virt) {
++ iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
++ cfg->virt = NULL;
++ }
+}
+
-+static inline void __iomem *gic_dist_base(struct irq_data *d)
++void __init pci_mmcfg_arch_free(void)
+{
-+ if (gic_irq_in_rdist(d)) /* SGI+PPI -> SGI_base for this CPU */
-+ return gic_data_rdist_sgi_base();
++ struct pci_mmcfg_region *cfg;
+
-+ if (d->hwirq <= 1023) /* SPI -> dist_base */
-+ return gic_data.dist_base;
-+
-+ if (d->hwirq >= 8192)
-+ BUG(); /* LPI Detected!!! */
-+
-+ return NULL;
++ list_for_each_entry(cfg, &pci_mmcfg_list, list)
++ pci_mmcfg_arch_unmap(cfg);
+}
+
-+static void gic_do_wait_for_rwp(void __iomem *base)
++int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
+{
-+ u32 count = 1000000; /* 1s! */
++ cfg->virt = mcfg_ioremap(cfg);
++ if (!cfg->virt) {
++ pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
++ return -ENOMEM;
++ }
+
-+ while (readl_relaxed(base + GICD_CTLR) & GICD_CTLR_RWP) {
-+ count--;
-+ if (!count) {
-+ pr_err_ratelimited("RWP timeout, gone fishing\n");
-+ return;
-+ }
-+ cpu_relax();
-+ udelay(1);
-+ };
++ return 0;
+}
+
-+/* Wait for completion of a distributor change */
-+static void gic_dist_wait_for_rwp(void)
++static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
+{
-+ gic_do_wait_for_rwp(gic_data.dist_base);
++ if (cfg->res.parent)
++ release_resource(&cfg->res);
++ list_del(&cfg->list);
++ kfree(cfg);
+}
+
-+/* Wait for completion of a redistributor change */
-+static void gic_redist_wait_for_rwp(void)
++static void __init free_all_mmcfg(void)
+{
-+ gic_do_wait_for_rwp(gic_data_rdist_rd_base());
++ struct pci_mmcfg_region *cfg, *tmp;
++
++ pci_mmcfg_arch_free();
++ list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list)
++ pci_mmconfig_remove(cfg);
+}
+
-+/* Low level accessors */
-+static u64 gic_read_iar(void)
++static void list_add_sorted(struct pci_mmcfg_region *new)
+{
-+ u64 irqstat;
++ struct pci_mmcfg_region *cfg;
+
-+ asm volatile("mrs %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
-+ return irqstat;
++ /* keep list sorted by segment and starting bus number */
++ list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
++ if (cfg->segment > new->segment ||
++ (cfg->segment == new->segment &&
++ cfg->start_bus >= new->start_bus)) {
++ list_add_tail_rcu(&new->list, &cfg->list);
++ return;
++ }
++ }
++ list_add_tail_rcu(&new->list, &pci_mmcfg_list);
+}
+
-+static void gic_write_pmr(u64 val)
++static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
++ int end, u64 addr)
+{
-+ asm volatile("msr " __stringify(ICC_PMR_EL1) ", %0" : : "r" (val));
-+}
++ struct pci_mmcfg_region *new;
++ struct resource *res;
+
-+static void gic_write_ctlr(u64 val)
-+{
-+ asm volatile("msr " __stringify(ICC_CTLR_EL1) ", %0" : : "r" (val));
-+ isb();
-+}
++ if (addr == 0)
++ return NULL;
+
-+static void gic_write_grpen1(u64 val)
-+{
-+ asm volatile("msr " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" (val));
-+ isb();
-+}
++ new = kzalloc(sizeof(*new), GFP_KERNEL);
++ if (!new)
++ return NULL;
+
-+static void gic_write_sgi1r(u64 val)
-+{
-+ asm volatile("msr " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val));
++ new->address = addr;
++ new->segment = segment;
++ new->start_bus = start;
++ new->end_bus = end;
++
++ res = &new->res;
++ res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
++ res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
++ snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
++ "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
++ res->name = new->name;
++
++ return new;
+}
+
-+static void gic_enable_sre(void)
++static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
++ int end, u64 addr)
+{
-+ u64 val;
++ struct pci_mmcfg_region *new;
+
-+ asm volatile("mrs %0, " __stringify(ICC_SRE_EL1) : "=r" (val));
-+ val |= ICC_SRE_EL1_SRE;
-+ asm volatile("msr " __stringify(ICC_SRE_EL1) ", %0" : : "r" (val));
-+ isb();
++ new = pci_mmconfig_alloc(segment, start, end, addr);
++ if (new) {
++ mutex_lock(&pci_mmcfg_lock);
++ list_add_sorted(new);
++ mutex_unlock(&pci_mmcfg_lock);
+
-+ /*
-+ * Need to check that the SRE bit has actually been set. If
-+ * not, it means that SRE is disabled at EL2. We're going to
-+ * die painfully, and there is nothing we can do about it.
-+ *
-+ * Kindly inform the luser.
-+ */
-+ asm volatile("mrs %0, " __stringify(ICC_SRE_EL1) : "=r" (val));
-+ if (!(val & ICC_SRE_EL1_SRE))
-+ pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n");
++ pr_info(PREFIX
++ "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
++ "(base %#lx)\n",
++ segment, start, end, &new->res, (unsigned long)addr);
++ }
++
++ return new;
+}
+
-+static void gic_enable_redist(void)
++extern struct acpi_mcfg_fixup __start_acpi_mcfg_fixups[];
++extern struct acpi_mcfg_fixup __end_acpi_mcfg_fixups[];
++
++static int __init pci_parse_mcfg(struct acpi_table_header *header)
+{
-+ void __iomem *rbase;
-+ u32 count = 1000000; /* 1s! */
-+ u32 val;
++ struct acpi_table_mcfg *mcfg;
++ struct acpi_mcfg_allocation *cfg_table, *cfg;
++ struct acpi_mcfg_fixup *fixup;
++ struct pci_mmcfg_region *new;
++ unsigned long i;
++ int entries;
+
-+ rbase = gic_data_rdist_rd_base();
++ if (!header)
++ return -EINVAL;
+
-+ /* Wake up this CPU redistributor */
-+ val = readl_relaxed(rbase + GICR_WAKER);
-+ val &= ~GICR_WAKER_ProcessorSleep;
-+ writel_relaxed(val, rbase + GICR_WAKER);
++ mcfg = (struct acpi_table_mcfg *)header;
+
-+ while (readl_relaxed(rbase + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) {
-+ count--;
-+ if (!count) {
-+ pr_err_ratelimited("redist didn't wake up...\n");
-+ return;
-+ }
-+ cpu_relax();
-+ udelay(1);
-+ };
-+}
++ /* how many config structures do we have */
++ free_all_mmcfg();
++ entries = 0;
++ i = header->length - sizeof(struct acpi_table_mcfg);
++ while (i >= sizeof(struct acpi_mcfg_allocation)) {
++ entries++;
++ i -= sizeof(struct acpi_mcfg_allocation);
++ }
++ if (entries == 0) {
++ pr_err(PREFIX "MMCONFIG has no entries\n");
++ return -ENODEV;
++ }
+
-+/*
-+ * Routines to disable, enable, EOI and route interrupts
-+ */
-+static void gic_poke_irq(struct irq_data *d, u32 offset)
-+{
-+ u32 mask = 1 << (gic_irq(d) % 32);
-+ void (*rwp_wait)(void);
-+ void __iomem *base;
++ fixup = __start_acpi_mcfg_fixups;
++ while (fixup < __end_acpi_mcfg_fixups) {
++ if (!strncmp(fixup->oem_id, header->oem_id, 6) &&
++ !strncmp(fixup->oem_table_id, header->oem_table_id, 8))
++ break;
++ ++fixup;
++ }
+
-+ if (gic_irq_in_rdist(d)) {
-+ base = gic_data_rdist_sgi_base();
-+ rwp_wait = gic_redist_wait_for_rwp;
-+ } else {
-+ base = gic_data.dist_base;
-+ rwp_wait = gic_dist_wait_for_rwp;
++ cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
++ for (i = 0; i < entries; i++) {
++ cfg = &cfg_table[i];
++
++ new = pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
++ cfg->end_bus_number, cfg->address);
++ if (!new) {
++ pr_warn(PREFIX "no memory for MCFG entries\n");
++ free_all_mmcfg();
++ return -ENOMEM;
++ }
++ if (fixup < __end_acpi_mcfg_fixups)
++ new->fixup = fixup->hook;
+ }
+
-+ writel_relaxed(mask, base + offset + (gic_irq(d) / 32) * 4);
-+ rwp_wait();
++ return 0;
+}
+
-+static int gic_peek_irq(struct irq_data *d, u32 offset)
++int __init pci_mmcfg_arch_init(void)
+{
-+ u32 mask = 1 << (gic_irq(d) % 32);
-+ void __iomem *base;
++ struct pci_mmcfg_region *cfg;
+
-+ if (gic_irq_in_rdist(d))
-+ base = gic_data_rdist_sgi_base();
-+ else
-+ base = gic_data.dist_base;
++ list_for_each_entry(cfg, &pci_mmcfg_list, list)
++ if (pci_mmcfg_arch_map(cfg)) {
++ pci_mmcfg_arch_free();
++ return 0;
++ }
+
-+ return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask);
++ return 1;
+}
+
-+static void gic_mask_irq(struct irq_data *d)
++static void __init __pci_mmcfg_init(int early)
+{
-+ gic_poke_irq(d, GICD_ICENABLER);
++ if (list_empty(&pci_mmcfg_list)) {
++ pr_info("No MCFG table found!\n");
++ pci_mmcfg_arch_init_failed = true;
++ return;
++ }
++
++ if (!pci_mmcfg_arch_init()) {
++ pr_info("pci_mmcfg_arch_init failed!\n");
++ free_all_mmcfg();
++ pci_mmcfg_arch_init_failed = true;
++ }
+}
+
-+static void gic_unmask_irq(struct irq_data *d)
++void __init pci_mmcfg_early_init(void)
+{
-+ gic_poke_irq(d, GICD_ISENABLER);
++ acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
++
++ __pci_mmcfg_init(1);
+}
+
-+static void gic_eoi_irq(struct irq_data *d)
++static int __init pci_mmcfg_init(void)
+{
-+ gic_write_eoir(gic_irq(d));
++ pci_mmcfg_early_init();
++ return 0;
+}
++arch_initcall(pci_mmcfg_init);
+
-+static int gic_set_type(struct irq_data *d, unsigned int type)
++void __init pci_mmcfg_late_init(void)
+{
-+ unsigned int irq = gic_irq(d);
-+ void (*rwp_wait)(void);
-+ void __iomem *base;
-+
-+ /* Interrupt configuration for SGIs can't be changed */
-+ if (irq < 16)
-+ return -EINVAL;
++ /* MMCONFIG hasn't been enabled yet, try again */
++ if (pci_mmcfg_arch_init_failed) {
++ acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
++ __pci_mmcfg_init(0);
++ }
++}
+
-+ if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
-+ return -EINVAL;
++static int __init pci_mmcfg_late_insert_resources(void)
++{
++ struct pci_mmcfg_region *cfg;
+
-+ if (gic_irq_in_rdist(d)) {
-+ base = gic_data_rdist_sgi_base();
-+ rwp_wait = gic_redist_wait_for_rwp;
-+ } else {
-+ base = gic_data.dist_base;
-+ rwp_wait = gic_dist_wait_for_rwp;
-+ }
++ pci_mmcfg_running_state = true;
+
-+ gic_configure_irq(irq, type, base, rwp_wait);
++ /*
++ * Attempt to insert the mmcfg resources but not with the busy flag
++ * marked so it won't cause request errors when __request_region is
++ * called.
++ */
++ list_for_each_entry(cfg, &pci_mmcfg_list, list)
++ if (!cfg->res.parent)
++ insert_resource(&iomem_resource, &cfg->res);
+
+ return 0;
+}
+
-+static u64 gic_mpidr_to_affinity(u64 mpidr)
-+{
-+ u64 aff;
++/*
++ * Perform MMCONFIG resource insertion after PCI initialization to allow for
++ * misprogrammed MCFG tables that state larger sizes but actually conflict
++ * with other system resources.
++ */
++late_initcall(pci_mmcfg_late_insert_resources);
+diff --git a/arch/arm64/pci/pci.c b/arch/arm64/pci/pci.c
+new file mode 100644
+index 0000000..0166475
+--- /dev/null
++++ b/arch/arm64/pci/pci.c
+@@ -0,0 +1,461 @@
++#include <linux/acpi.h>
++#include <linux/of_address.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
+
-+ aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
-+ MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
-+ MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
-+ MPIDR_AFFINITY_LEVEL(mpidr, 0));
++struct pci_root_info {
++ struct acpi_device *bridge;
++ char name[16];
++ unsigned int res_num;
++ struct resource *res;
++ resource_size_t *res_offset;
++ struct pci_sysdata sd;
++ u16 segment;
++ u8 start_bus;
++ u8 end_bus;
++};
+
-+ return aff;
++static char __iomem *pci_dev_base(struct pci_mmcfg_region *cfg,
++ unsigned int bus, unsigned int devfn)
++{
++ return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
+}
+
-+static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
++static int __raw_pci_read(struct pci_mmcfg_region *cfg, unsigned int bus,
++ unsigned int devfn, int reg, int len, u32 *value)
+{
-+ u64 irqnr;
-+
-+ do {
-+ irqnr = gic_read_iar();
++ char __iomem *addr = pci_dev_base(cfg, bus, devfn) + (reg & ~3);
++ int shift = (reg & 3) * 8;
++ u32 v;
+
-+ if (likely(irqnr > 15 && irqnr < 1020)) {
-+ u64 irq = irq_find_mapping(gic_data.domain, irqnr);
-+ if (likely(irq)) {
-+ handle_IRQ(irq, regs);
-+ continue;
-+ }
-+
-+ WARN_ONCE(true, "Unexpected SPI received!\n");
-+ gic_write_eoir(irqnr);
-+ }
-+ if (irqnr < 16) {
-+ gic_write_eoir(irqnr);
-+#ifdef CONFIG_SMP
-+ handle_IPI(irqnr, regs);
-+#else
-+ WARN_ONCE(true, "Unexpected SGI received!\n");
-+#endif
-+ continue;
-+ }
-+ } while (irqnr != ICC_IAR1_EL1_SPURIOUS);
++ v = readl(addr) >> shift;
++ switch (len) {
++ case 1:
++ *value = v & 0xff;
++ break;
++ case 2:
++ *value = v & 0xffff;
++ break;
++ case 4:
++ *value = v;
++ break;
++ }
++ return 0;
+}
+
-+static void __init gic_dist_init(void)
++static int __raw_pci_write(struct pci_mmcfg_region *cfg, unsigned int bus,
++ unsigned int devfn, int reg, int len, u32 value)
+{
-+ unsigned int i;
-+ u64 affinity;
-+ void __iomem *base = gic_data.dist_base;
++ char __iomem *addr = pci_dev_base(cfg, bus, devfn) + (reg & ~3);
++ int mask = 0, shift = (reg & 3) * 8;
++ u32 v;
+
-+ /* Disable the distributor */
-+ writel_relaxed(0, base + GICD_CTLR);
-+ gic_dist_wait_for_rwp();
-+
-+ gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
++ switch (len) {
++ case 1:
++ mask = 0xff << shift;
++ break;
++ case 2:
++ mask = 0xffff << shift;
++ break;
++ }
+
-+ /* Enable distributor with ARE, Group1 */
-+ writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
-+ base + GICD_CTLR);
++ if (mask) {
++ v = readl(addr) & ~mask;
++ writel(v | (value << shift), addr);
++ } else
++ writel(value, addr);
+
-+ /*
-+ * Set all global interrupts to the boot CPU only. ARE must be
-+ * enabled.
-+ */
-+ affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
-+ for (i = 32; i < gic_data.irq_nr; i++)
-+ writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
++ return 0;
+}
+
-+static int gic_populate_rdist(void)
++/*
++ * raw_pci_read/write - Platform-specific PCI config space access.
++ */
++int raw_pci_read(unsigned int domain, unsigned int bus,
++ unsigned int devfn, int reg, int len, u32 *val)
+{
-+ u64 mpidr = cpu_logical_map(smp_processor_id());
-+ u64 typer;
-+ u32 aff;
-+ int i;
-+
-+ /*
-+ * Convert affinity to a 32bit value that can be matched to
-+ * GICR_TYPER bits [63:32].
-+ */
-+ aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
-+ MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
-+ MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
-+ MPIDR_AFFINITY_LEVEL(mpidr, 0));
-+
-+ for (i = 0; i < gic_data.redist_regions; i++) {
-+ void __iomem *ptr = gic_data.redist_base[i];
-+ u32 reg;
-+
-+ reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
-+ if (reg != GIC_PIDR2_ARCH_GICv3 &&
-+ reg != GIC_PIDR2_ARCH_GICv4) { /* We're in trouble... */
-+ pr_warn("No redistributor present @%p\n", ptr);
-+ break;
-+ }
++ struct pci_mmcfg_region *cfg;
++ int ret;
+
-+ do {
-+ typer = readq_relaxed(ptr + GICR_TYPER);
-+ if ((typer >> 32) == aff) {
-+ gic_data_rdist_rd_base() = ptr;
-+ pr_info("CPU%d: found redistributor %llx @%p\n",
-+ smp_processor_id(),
-+ (unsigned long long)mpidr, ptr);
-+ return 0;
-+ }
++ if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
++err: *val = -1;
++ return -EINVAL;
++ }
+
-+ if (gic_data.redist_stride) {
-+ ptr += gic_data.redist_stride;
-+ } else {
-+ ptr += SZ_64K * 2; /* Skip RD_base + SGI_base */
-+ if (typer & GICR_TYPER_VLPIS)
-+ ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
-+ }
-+ } while (!(typer & GICR_TYPER_LAST));
++ rcu_read_lock();
++ cfg = pci_mmconfig_lookup(domain, bus);
++ if (!cfg || !cfg->virt) {
++ rcu_read_unlock();
++ goto err;
+ }
+
-+ /* We couldn't even deal with ourselves... */
-+ WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
-+ smp_processor_id(), (unsigned long long)mpidr);
-+ return -ENODEV;
-+}
++ if (cfg->read)
++ ret = (*cfg->read)(cfg, bus, devfn, reg, len, val);
++ else
++ ret = __raw_pci_read(cfg, bus, devfn, reg, len, val);
+
-+static void gic_cpu_init(void)
-+{
-+ void __iomem *rbase;
++ rcu_read_unlock();
+
-+ /* Register ourselves with the rest of the world */
-+ if (gic_populate_rdist())
-+ return;
++ return ret;
++}
+
-+ gic_enable_redist();
++int raw_pci_write(unsigned int domain, unsigned int bus,
++ unsigned int devfn, int reg, int len, u32 val)
++{
++ struct pci_mmcfg_region *cfg;
++ int ret;
+
-+ rbase = gic_data_rdist_sgi_base();
++ if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
++ return -EINVAL;
+
-+ gic_cpu_config(rbase, gic_redist_wait_for_rwp);
++ rcu_read_lock();
++ cfg = pci_mmconfig_lookup(domain, bus);
++ if (!cfg || !cfg->virt) {
++ rcu_read_unlock();
++ return -EINVAL;
++ }
+
-+ /* Enable system registers */
-+ gic_enable_sre();
++ if (cfg->write)
++ ret = (*cfg->write)(cfg, bus, devfn, reg, len, val);
++ else
++ ret = __raw_pci_write(cfg, bus, devfn, reg, len, val);
+
-+ /* Set priority mask register */
-+ gic_write_pmr(DEFAULT_PMR_VALUE);
++ rcu_read_unlock();
+
-+ /* EOI deactivates interrupt too (mode 0) */
-+ gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
++ return ret;
++}
+
-+ /* ... and let's hit the road... */
-+ gic_write_grpen1(1);
++#ifdef CONFIG_ACPI
++static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
++ int size, u32 *value)
++{
++ return raw_pci_read(pci_domain_nr(bus), bus->number,
++ devfn, where, size, value);
+}
+
-+#ifdef CONFIG_SMP
-+static int gic_secondary_init(struct notifier_block *nfb,
-+ unsigned long action, void *hcpu)
++static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
++ int size, u32 value)
+{
-+ if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
-+ gic_cpu_init();
-+ return NOTIFY_OK;
++ return raw_pci_write(pci_domain_nr(bus), bus->number,
++ devfn, where, size, value);
+}
+
-+/*
-+ * Notifier for enabling the GIC CPU interface. Set an arbitrarily high
-+ * priority because the GIC needs to be up before the ARM generic timers.
-+ */
-+static struct notifier_block gic_cpu_notifier = {
-+ .notifier_call = gic_secondary_init,
-+ .priority = 100,
++struct pci_ops pci_root_ops = {
++ .read = pci_read,
++ .write = pci_write,
+};
+
-+static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
-+ u64 cluster_id)
++static acpi_status resource_to_addr(struct acpi_resource *resource,
++ struct acpi_resource_address64 *addr)
++{
++ acpi_status status;
++
++ memset(addr, 0, sizeof(*addr));
++ switch (resource->type) {
++ case ACPI_RESOURCE_TYPE_ADDRESS16:
++ case ACPI_RESOURCE_TYPE_ADDRESS32:
++ case ACPI_RESOURCE_TYPE_ADDRESS64:
++ status = acpi_resource_to_address64(resource, addr);
++ if (ACPI_SUCCESS(status) &&
++ (addr->resource_type == ACPI_MEMORY_RANGE ||
++ addr->resource_type == ACPI_IO_RANGE) &&
++ addr->address_length > 0) {
++ return AE_OK;
++ }
++ break;
++ }
++ return AE_ERROR;
++}
++
++static acpi_status count_resource(struct acpi_resource *acpi_res, void *data)
+{
-+ int cpu = *base_cpu;
-+ u64 mpidr = cpu_logical_map(cpu);
-+ u16 tlist = 0;
++ struct pci_root_info *info = data;
++ struct acpi_resource_address64 addr;
++ acpi_status status;
+
-+ while (cpu < nr_cpu_ids) {
-+ /*
-+ * If we ever get a cluster of more than 16 CPUs, just
-+ * scream and skip that CPU.
-+ */
-+ if (WARN_ON((mpidr & 0xff) >= 16))
-+ goto out;
++ status = resource_to_addr(acpi_res, &addr);
++ if (ACPI_SUCCESS(status))
++ info->res_num++;
++ return AE_OK;
++}
+
-+ tlist |= 1 << (mpidr & 0xf);
++static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
++{
++ struct pci_root_info *info = data;
++ struct resource *res;
++ struct acpi_resource_address64 addr;
++ acpi_status status;
++ unsigned long flags;
++ u64 start, end;
++
++ status = resource_to_addr(acpi_res, &addr);
++ if (!ACPI_SUCCESS(status))
++ return AE_OK;
++
++ if (addr.resource_type == ACPI_MEMORY_RANGE) {
++ flags = IORESOURCE_MEM;
++ if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
++ flags |= IORESOURCE_PREFETCH;
++ } else if (addr.resource_type == ACPI_IO_RANGE) {
++ flags = IORESOURCE_IO;
++ } else
++ return AE_OK;
++
++ start = addr.minimum + addr.translation_offset;
++ end = addr.maximum + addr.translation_offset;
++
++ res = &info->res[info->res_num];
++ res->name = info->name;
++ res->flags = flags;
++ res->start = start;
++ res->end = end;
++
++ if (flags & IORESOURCE_IO) {
++ unsigned long port;
++ int err;
++
++ err = pci_register_io_range(start, addr.address_length);
++ if (err)
++ return AE_OK;
+
-+ cpu = cpumask_next(cpu, mask);
-+ if (cpu == nr_cpu_ids)
-+ goto out;
++ port = pci_address_to_pio(start);
++ if (port == (unsigned long)-1) {
++ res->start = -1;
++ res->end = -1;
++ return AE_OK;
++ }
+
-+ mpidr = cpu_logical_map(cpu);
++ res->start = port;
++ res->end = res->start + addr.address_length - 1;
+
-+ if (cluster_id != (mpidr & ~0xffUL)) {
-+ cpu--;
-+ goto out;
-+ }
-+ }
-+out:
-+ *base_cpu = cpu;
-+ return tlist;
++ if (pci_remap_iospace(res, start) < 0)
++ return AE_OK;
++
++ info->res_offset[info->res_num] = 0;
++ } else
++ info->res_offset[info->res_num] = addr.translation_offset;
++
++ info->res_num++;
++
++ return AE_OK;
+}
+
-+static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
++static void coalesce_windows(struct pci_root_info *info, unsigned long type)
+{
-+ u64 val;
++ int i, j;
++ struct resource *res1, *res2;
++
++ for (i = 0; i < info->res_num; i++) {
++ res1 = &info->res[i];
++ if (!(res1->flags & type))
++ continue;
+
-+ val = (MPIDR_AFFINITY_LEVEL(cluster_id, 3) << 48 |
-+ MPIDR_AFFINITY_LEVEL(cluster_id, 2) << 32 |
-+ irq << 24 |
-+ MPIDR_AFFINITY_LEVEL(cluster_id, 1) << 16 |
-+ tlist);
++ for (j = i + 1; j < info->res_num; j++) {
++ res2 = &info->res[j];
++ if (!(res2->flags & type))
++ continue;
+
-+ pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
-+ gic_write_sgi1r(val);
++ /*
++ * I don't like throwing away windows because then
++ * our resources no longer match the ACPI _CRS, but
++ * the kernel resource tree doesn't allow overlaps.
++ */
++ if (resource_overlaps(res1, res2)) {
++ res2->start = min(res1->start, res2->start);
++ res2->end = max(res1->end, res2->end);
++ dev_info(&info->bridge->dev,
++ "host bridge window expanded to %pR; %pR ignored\n",
++ res2, res1);
++ res1->flags = 0;
++ }
++ }
++ }
+}
+
-+static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
++static void add_resources(struct pci_root_info *info,
++ struct list_head *resources)
+{
-+ int cpu;
++ int i;
++ struct resource *res, *root, *conflict;
+
-+ if (WARN_ON(irq >= 16))
-+ return;
++ coalesce_windows(info, IORESOURCE_MEM);
++ coalesce_windows(info, IORESOURCE_IO);
+
-+ /*
-+ * Ensure that stores to Normal memory are visible to the
-+ * other CPUs before issuing the IPI.
-+ */
-+ smp_wmb();
++ for (i = 0; i < info->res_num; i++) {
++ res = &info->res[i];
+
-+ for_each_cpu_mask(cpu, *mask) {
-+ u64 cluster_id = cpu_logical_map(cpu) & ~0xffUL;
-+ u16 tlist;
++ if (res->flags & IORESOURCE_MEM)
++ root = &iomem_resource;
++ else if (res->flags & IORESOURCE_IO)
++ root = &ioport_resource;
++ else
++ continue;
+
-+ tlist = gic_compute_target_list(&cpu, mask, cluster_id);
-+ gic_send_sgi(cluster_id, tlist, irq);
++ conflict = insert_resource_conflict(root, res);
++ if (conflict)
++ dev_info(&info->bridge->dev,
++ "ignoring host bridge window %pR (conflicts with %s %pR)\n",
++ res, conflict->name, conflict);
++ else
++ pci_add_resource_offset(resources, res,
++ info->res_offset[i]);
+ }
-+
-+ /* Force the above writes to ICC_SGI1R_EL1 to be executed */
-+ isb();
+}
+
-+static void gic_smp_init(void)
++static void free_pci_root_info_res(struct pci_root_info *info)
+{
-+ set_smp_cross_call(gic_raise_softirq);
-+ register_cpu_notifier(&gic_cpu_notifier);
++ kfree(info->res);
++ info->res = NULL;
++ kfree(info->res_offset);
++ info->res_offset = NULL;
++ info->res_num = 0;
+}
+
-+static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
-+ bool force)
++static void __release_pci_root_info(struct pci_root_info *info)
+{
-+ unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
-+ void __iomem *reg;
-+ int enabled;
-+ u64 val;
++ int i;
++ struct resource *res;
+
-+ if (gic_irq_in_rdist(d))
-+ return -EINVAL;
++ for (i = 0; i < info->res_num; i++) {
++ res = &info->res[i];
+
-+ /* If interrupt was enabled, disable it first */
-+ enabled = gic_peek_irq(d, GICD_ISENABLER);
-+ if (enabled)
-+ gic_mask_irq(d);
++ if (!res->parent)
++ continue;
+
-+ reg = gic_dist_base(d) + GICD_IROUTER + (gic_irq(d) * 8);
-+ val = gic_mpidr_to_affinity(cpu_logical_map(cpu));
++ if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
++ continue;
+
-+ writeq_relaxed(val, reg);
++ release_resource(res);
++ }
+
-+ /*
-+ * If the interrupt was enabled, enabled it again. Otherwise,
-+ * just wait for the distributor to have digested our changes.
-+ */
-+ if (enabled)
-+ gic_unmask_irq(d);
-+ else
-+ gic_dist_wait_for_rwp();
++ free_pci_root_info_res(info);
+
-+ return IRQ_SET_MASK_OK;
++ kfree(info);
+}
-+#else
-+#define gic_set_affinity NULL
-+#define gic_smp_init() do { } while(0)
-+#endif
+
-+static struct irq_chip gic_chip = {
-+ .name = "GICv3",
-+ .irq_mask = gic_mask_irq,
-+ .irq_unmask = gic_unmask_irq,
-+ .irq_eoi = gic_eoi_irq,
-+ .irq_set_type = gic_set_type,
-+ .irq_set_affinity = gic_set_affinity,
-+};
++static void release_pci_root_info(struct pci_host_bridge *bridge)
++{
++ struct pci_root_info *info = bridge->release_data;
+
-+static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
-+ irq_hw_number_t hw)
-+{
-+ /* SGIs are private to the core kernel */
-+ if (hw < 16)
-+ return -EPERM;
-+ /* PPIs */
-+ if (hw < 32) {
-+ irq_set_percpu_devid(irq);
-+ irq_set_chip_and_handler(irq, &gic_chip,
-+ handle_percpu_devid_irq);
-+ set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
-+ }
-+ /* SPIs */
-+ if (hw >= 32 && hw < gic_data.irq_nr) {
-+ irq_set_chip_and_handler(irq, &gic_chip,
-+ handle_fasteoi_irq);
-+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-+ }
-+ irq_set_chip_data(irq, d->host_data);
-+ return 0;
++ __release_pci_root_info(info);
+}
+
-+static int gic_irq_domain_xlate(struct irq_domain *d,
-+ struct device_node *controller,
-+ const u32 *intspec, unsigned int intsize,
-+ unsigned long *out_hwirq, unsigned int *out_type)
++static void probe_pci_root_info(struct pci_root_info *info,
++ struct acpi_device *device,
++ int busnum, int domain)
+{
-+ if (d->of_node != controller)
-+ return -EINVAL;
-+ if (intsize < 3)
-+ return -EINVAL;
++ size_t size;
+
-+ switch(intspec[0]) {
-+ case 0: /* SPI */
-+ *out_hwirq = intspec[1] + 32;
-+ break;
-+ case 1: /* PPI */
-+ *out_hwirq = intspec[1] + 16;
-+ break;
-+ default:
-+ return -EINVAL;
++ sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
++ info->bridge = device;
++
++ info->res_num = 0;
++ acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
++ info);
++ if (!info->res_num)
++ return;
++
++ size = sizeof(*info->res) * info->res_num;
++ info->res = kzalloc_node(size, GFP_KERNEL, info->sd.node);
++ if (!info->res) {
++ info->res_num = 0;
++ return;
+ }
+
-+ *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
-+ return 0;
-+}
++ size = sizeof(*info->res_offset) * info->res_num;
++ info->res_num = 0;
++ info->res_offset = kzalloc_node(size, GFP_KERNEL, info->sd.node);
++ if (!info->res_offset) {
++ kfree(info->res);
++ info->res = NULL;
++ return;
++ }
+
-+static const struct irq_domain_ops gic_irq_domain_ops = {
-+ .map = gic_irq_domain_map,
-+ .xlate = gic_irq_domain_xlate,
-+};
++ acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
++ info);
++}
+
-+static int __init gic_of_init(struct device_node *node, struct device_node *parent)
++/* Root bridge scanning */
++struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+{
-+ void __iomem *dist_base;
-+ void __iomem **redist_base;
-+ u64 redist_stride;
-+ u32 redist_regions;
-+ u32 reg;
-+ int gic_irqs;
-+ int err;
-+ int i;
-+
-+ dist_base = of_iomap(node, 0);
-+ if (!dist_base) {
-+ pr_err("%s: unable to map gic dist registers\n",
-+ node->full_name);
-+ return -ENXIO;
-+ }
++ struct acpi_device *device = root->device;
++ struct pci_mmcfg_region *mcfg;
++ struct pci_root_info *info;
++ int domain = root->segment;
++ int busnum = root->secondary.start;
++ LIST_HEAD(resources);
++ struct pci_bus *bus;
++ struct pci_sysdata *sd;
++ int node;
+
-+ reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
-+ if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
-+ pr_err("%s: no distributor detected, giving up\n",
-+ node->full_name);
-+ err = -ENODEV;
-+ goto out_unmap_dist;
++ /* we need mmconfig */
++ mcfg = pci_mmconfig_lookup(domain, busnum);
++ if (!mcfg) {
++ pr_err("pci_bus %04x:%02x has no MCFG table\n",
++ domain, busnum);
++ return NULL;
+ }
+
-+ if (of_property_read_u32(node, "#redistributor-regions", &redist_regions))
-+ redist_regions = 1;
++ /* temporary hack */
++ if (mcfg->fixup)
++ (*mcfg->fixup)(root, mcfg);
+
-+ redist_base = kzalloc(sizeof(*redist_base) * redist_regions, GFP_KERNEL);
-+ if (!redist_base) {
-+ err = -ENOMEM;
-+ goto out_unmap_dist;
++ if (domain && !pci_domains_supported) {
++ pr_warn("PCI %04x:%02x: multiple domains not supported.\n",
++ domain, busnum);
++ return NULL;
+ }
+
-+ for (i = 0; i < redist_regions; i++) {
-+ redist_base[i] = of_iomap(node, 1 + i);
-+ if (!redist_base[i]) {
-+ pr_err("%s: couldn't map region %d\n",
-+ node->full_name, i);
-+ err = -ENODEV;
-+ goto out_unmap_rdist;
-+ }
++ node = NUMA_NO_NODE;
++
++ info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
++ if (!info) {
++ pr_warn("PCI %04x:%02x: ignored (out of memory)\n",
++ domain, busnum);
++ return NULL;
+ }
++ info->segment = domain;
++ info->start_bus = busnum;
++ info->end_bus = root->secondary.end;
+
-+ if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
-+ redist_stride = 0;
++ sd = &info->sd;
++ sd->domain = domain;
++ sd->node = node;
++ sd->companion = device;
+
-+ gic_data.dist_base = dist_base;
-+ gic_data.redist_base = redist_base;
-+ gic_data.redist_regions = redist_regions;
-+ gic_data.redist_stride = redist_stride;
++ probe_pci_root_info(info, device, busnum, domain);
+
-+ /*
-+ * Find out how many interrupts are supported.
-+ * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
-+ */
-+ gic_irqs = readl_relaxed(gic_data.dist_base + GICD_TYPER) & 0x1f;
-+ gic_irqs = (gic_irqs + 1) * 32;
-+ if (gic_irqs > 1020)
-+ gic_irqs = 1020;
-+ gic_data.irq_nr = gic_irqs;
++ /* insert busn res at first */
++ pci_add_resource(&resources, &root->secondary);
+
-+ gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
-+ &gic_data);
-+ gic_data.rdist = alloc_percpu(typeof(*gic_data.rdist));
++ /* then _CRS resources */
++ add_resources(info, &resources);
+
-+ if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdist)) {
-+ err = -ENOMEM;
-+ goto out_free;
++ bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
++ if (bus) {
++ pci_scan_child_bus(bus);
++ pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
++ release_pci_root_info, info);
++ } else {
++ pci_free_resource_list(&resources);
++ __release_pci_root_info(info);
+ }
+
-+ set_handle_irq(gic_handle_irq);
-+
-+ gic_smp_init();
-+ gic_dist_init();
-+ gic_cpu_init();
++ /* After the PCI-E bus has been walked and all devices discovered,
++ * configure any settings of the fabric that might be necessary.
++ */
++ if (bus) {
++ struct pci_bus *child;
+
-+ return 0;
++ list_for_each_entry(child, &bus->children, node)
++ pcie_bus_configure_settings(child);
++ }
+
-+out_free:
-+ if (gic_data.domain)
-+ irq_domain_remove(gic_data.domain);
-+ free_percpu(gic_data.rdist);
-+out_unmap_rdist:
-+ for (i = 0; i < redist_regions; i++)
-+ if (redist_base[i])
-+ iounmap(redist_base[i]);
-+ kfree(redist_base);
-+out_unmap_dist:
-+ iounmap(dist_base);
-+ return err;
-+}
-+
-+IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
-diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
-index 7c131cf..1ddfdde 100644
---- a/drivers/irqchip/irq-gic.c
-+++ b/drivers/irqchip/irq-gic.c
-@@ -47,6 +47,7 @@
- #include <asm/exception.h>
- #include <asm/smp_plat.h>
-
-+#include "irq-gic-common.h"
- #include "irqchip.h"
-
- union gic_base {
-@@ -189,12 +190,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
- {
- void __iomem *base = gic_dist_base(d);
- unsigned int gicirq = gic_irq(d);
-- u32 enablemask = 1 << (gicirq % 32);
-- u32 enableoff = (gicirq / 32) * 4;
-- u32 confmask = 0x2 << ((gicirq % 16) * 2);
-- u32 confoff = (gicirq / 16) * 4;
-- bool enabled = false;
-- u32 val;
-
- /* Interrupt configuration for SGIs can't be changed */
- if (gicirq < 16)
-@@ -208,25 +203,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
- if (gic_arch_extn.irq_set_type)
- gic_arch_extn.irq_set_type(d, type);
-
-- val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
-- if (type == IRQ_TYPE_LEVEL_HIGH)
-- val &= ~confmask;
-- else if (type == IRQ_TYPE_EDGE_RISING)
-- val |= confmask;
--
-- /*
-- * As recommended by the spec, disable the interrupt before changing
-- * the configuration
-- */
-- if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
-- writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
-- enabled = true;
-- }
--
-- writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
--
-- if (enabled)
-- writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
-+ gic_configure_irq(gicirq, type, base, NULL);
-
- raw_spin_unlock(&irq_controller_lock);
-
-@@ -388,12 +365,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
- writel_relaxed(0, base + GIC_DIST_CTRL);
-
- /*
-- * Set all global interrupts to be level triggered, active low.
-- */
-- for (i = 32; i < gic_irqs; i += 16)
-- writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
--
-- /*
- * Set all global interrupts to this CPU only.
- */
- cpumask = gic_get_cpumask(gic);
-@@ -402,18 +373,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
- for (i = 32; i < gic_irqs; i += 4)
- writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
-
-- /*
-- * Set priority on all global interrupts.
-- */
-- for (i = 32; i < gic_irqs; i += 4)
-- writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
--
-- /*
-- * Disable all interrupts. Leave the PPI and SGIs alone
-- * as these enables are banked registers.
-- */
-- for (i = 32; i < gic_irqs; i += 32)
-- writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
-+ gic_dist_config(base, gic_irqs, NULL);
++ if (bus && node != NUMA_NO_NODE)
++ dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
++
++ return bus;
++}
++
++#endif /* CONFIG_ACPI */
+diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
+index b23fe37..555e226 100644
+--- a/drivers/acpi/Kconfig
++++ b/drivers/acpi/Kconfig
+@@ -5,8 +5,7 @@
+ menuconfig ACPI
+ bool "ACPI (Advanced Configuration and Power Interface) Support"
+ depends on !IA64_HP_SIM
+- depends on IA64 || X86
+- depends on PCI
++ depends on ((IA64 || X86) && PCI) || ARM64
+ select PNP
+ default y
+ help
+@@ -163,6 +162,7 @@ config ACPI_PROCESSOR
+ tristate "Processor"
+ select THERMAL
+ select CPU_IDLE
++ depends on X86 || IA64
+ default y
+ help
+ This driver installs ACPI as the idle handler for Linux and uses
+@@ -263,7 +263,7 @@ config ACPI_DEBUG
+
+ config ACPI_PCI_SLOT
+ bool "PCI slot detection driver"
+- depends on SYSFS
++ depends on SYSFS && PCI
+ default n
+ help
+ This driver creates entries in /sys/bus/pci/slots/ for all PCI
+diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
+index c3b2fcb..5a21476 100644
+--- a/drivers/acpi/Makefile
++++ b/drivers/acpi/Makefile
+@@ -23,7 +23,11 @@ acpi-y += nvs.o
+
+ # Power management related files
+ acpi-y += wakeup.o
++ifeq ($(ARCH), arm64)
++acpi-y += sleep-arm.o
++else # X86, IA64
+ acpi-y += sleep.o
++endif
+ acpi-y += device_pm.o
+ acpi-$(CONFIG_ACPI_SLEEP) += proc.o
+
+@@ -39,7 +43,7 @@ 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
+-acpi-y += pci_root.o pci_link.o pci_irq.o
++acpi-$(CONFIG_PCI) += pci_root.o pci_link.o pci_irq.o
+ acpi-y += acpi_lpss.o
+ acpi-y += acpi_platform.o
+ acpi-y += acpi_pnp.o
+@@ -47,6 +51,7 @@ acpi-y += int340x_thermal.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/bus.c b/drivers/acpi/bus.c
+index 8b67bd0..c412fdb 100644
+--- a/drivers/acpi/bus.c
++++ b/drivers/acpi/bus.c
+@@ -448,6 +448,9 @@ static int __init acpi_bus_init_irq(void)
+ case ACPI_IRQ_MODEL_IOSAPIC:
+ message = "IOSAPIC";
+ break;
++ case ACPI_IRQ_MODEL_GIC:
++ message = "GIC";
++ break;
+ case ACPI_IRQ_MODEL_PLATFORM:
+ message = "platform specific model";
+ break;
+diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
+index 447f6d6..c5ff8ba 100644
+--- a/drivers/acpi/internal.h
++++ b/drivers/acpi/internal.h
+@@ -26,8 +26,13 @@
+ acpi_status acpi_os_initialize1(void);
+ int init_acpi_device_notify(void);
+ int acpi_scan_init(void);
++#ifdef CONFIG_PCI
+ void acpi_pci_root_init(void);
+ void acpi_pci_link_init(void);
++#else
++static inline void acpi_pci_root_init(void) {}
++static inline void acpi_pci_link_init(void) {}
++#endif
+ void acpi_processor_init(void);
+ void acpi_platform_init(void);
+ void acpi_pnp_init(void);
+@@ -173,4 +178,10 @@ static inline void suspend_nvs_restore(void) {}
+ bool acpi_osi_is_win8(void);
+ #endif
- writel_relaxed(1, base + GIC_DIST_CTRL);
++/*--------------------------------------------------------------------------
++ 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 9964f70..5c480d5 100644
+--- a/drivers/acpi/osl.c
++++ b/drivers/acpi/osl.c
+@@ -336,11 +336,11 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
+ return NULL;
}
-@@ -423,6 +383,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
- void __iomem *dist_base = gic_data_dist_base(gic);
- void __iomem *base = gic_data_cpu_base(gic);
- unsigned int cpu_mask, cpu = smp_processor_id();
-+ unsigned int ctrl_mask;
- int i;
-
- /*
-@@ -440,27 +401,32 @@ static void gic_cpu_init(struct gic_chip_data *gic)
- if (i != cpu)
- gic_cpu_map[i] &= ~cpu_mask;
-- /*
-- * Deal with the banked PPI and SGI interrupts - disable all
-- * PPI interrupts, ensure all SGI interrupts are enabled.
-- */
-- writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
-- writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
--
-- /*
-- * Set priority on PPI and SGI interrupts
-- */
-- for (i = 0; i < 32; i += 4)
-- writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
-+ gic_cpu_config(dist_base, NULL);
+-#ifndef CONFIG_IA64
+-#define should_use_kmap(pfn) page_is_ram(pfn)
+-#else
++#if defined(CONFIG_IA64) || defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+ /* ioremap will take care of cache attributes */
+ #define should_use_kmap(pfn) 0
++#else
++#define should_use_kmap(pfn) page_is_ram(pfn)
+ #endif
- writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-- writel_relaxed(1, base + GIC_CPU_CTRL);
-+
-+ ctrl_mask = readl(base + GIC_CPU_CTRL);
-+
-+ /* Mask out the gic v2 bypass bits */
-+ ctrl_mask &= 0x1e0;
-+
-+ /* Enable group 0 */
-+ ctrl_mask |= 0x1;
-+ writel_relaxed(ctrl_mask, base + GIC_CPU_CTRL);
+ static void __iomem *acpi_map(acpi_physical_address pg_off, unsigned long pg_sz)
+diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
+index ef58f46..5c84e0d 100644
+--- a/drivers/acpi/processor_core.c
++++ b/drivers/acpi/processor_core.c
+@@ -64,6 +64,38 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
+ return 0;
}
- void gic_cpu_if_down(void)
- {
-+ unsigned int ctrl_mask;
- void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]);
-- writel_relaxed(0, cpu_base + GIC_CPU_CTRL);
++/*
++ * On ARM platform, MPIDR value is the hardware ID as apic ID
++ * on Intel platforms
++ */
++static int map_gicc_mpidr(struct acpi_subtable_header *entry,
++ int device_declaration, u32 acpi_id, int *mpidr)
++{
++ struct acpi_madt_generic_interrupt *gicc =
++ container_of(entry, struct acpi_madt_generic_interrupt, header);
+
-+ ctrl_mask = readl(cpu_base + GIC_CPU_CTRL);
-+ /*
-+ * Disable grp enable bit, leave the bypass bits alone as changing
-+ * them could leave the system unstable
-+ */
-+ ctrl_mask &= 0x1e0;
-+ writel_relaxed(ctrl_mask, cpu_base + GIC_CPU_CTRL);
- }
-
- #ifdef CONFIG_CPU_PM
-@@ -571,6 +537,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
- {
- int i;
- u32 *ptr;
-+ unsigned int ctrl_mask;
- void __iomem *dist_base;
- void __iomem *cpu_base;
-
-@@ -595,7 +562,15 @@ static void gic_cpu_restore(unsigned int gic_nr)
- writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
-
- writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-- writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
++ if (!(gicc->flags & ACPI_MADT_ENABLED))
++ return -ENODEV;
+
-+ ctrl_mask = readl(cpu_base + GIC_CPU_CTRL);
++ /* In the GIC interrupt model, logical processors are
++ * required to have a Processor Device object in the DSDT,
++ * so we should check device_declaration here
++ */
++ if (device_declaration && (gicc->uid == acpi_id)) {
++ /*
++ * Only bits [0:7] Aff0, bits [8:15] Aff1, bits [16:23] Aff2
++ * and bits [32:39] Aff3 are meaningful, so pack the Affx
++ * fields into a single 32 bit identifier to accommodate the
++ * acpi processor drivers.
++ */
++ *mpidr = ((gicc->arm_mpidr & 0xff00000000) >> 8)
++ | gicc->arm_mpidr;
++ return 0;
++ }
+
-+ /* Mask out the gic v2 bypass bits */
-+ ctrl_mask &= 0x1e0;
++ return -EINVAL;
++}
+
-+ /* Enable group 0 */
-+ ctrl_mask |= 0x1;
-+ writel_relaxed(ctrl_mask, cpu_base + GIC_CPU_CTRL);
- }
+ static int map_madt_entry(int type, u32 acpi_id)
+ {
+ unsigned long madt_end, entry;
+@@ -99,6 +131,9 @@ static int map_madt_entry(int type, u32 acpi_id)
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ if (!map_lsapic_id(header, type, acpi_id, &apic_id))
+ break;
++ } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
++ if (!map_gicc_mpidr(header, type, acpi_id, &apic_id))
++ break;
+ }
+ entry += header->length;
+ }
+@@ -131,6 +166,8 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
+ map_lsapic_id(header, type, acpi_id, &apic_id);
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
+ map_x2apic_id(header, type, acpi_id, &apic_id);
++ } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
++ map_gicc_mpidr(header, type, acpi_id, &apic_id);
+ }
- static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
-diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
-index edb7186..dc7406c 100644
---- a/drivers/net/ethernet/Kconfig
-+++ b/drivers/net/ethernet/Kconfig
-@@ -24,6 +24,7 @@ source "drivers/net/ethernet/allwinner/Kconfig"
- source "drivers/net/ethernet/alteon/Kconfig"
- source "drivers/net/ethernet/altera/Kconfig"
- source "drivers/net/ethernet/amd/Kconfig"
-+source "drivers/net/ethernet/apm/Kconfig"
- source "drivers/net/ethernet/apple/Kconfig"
- source "drivers/net/ethernet/arc/Kconfig"
- source "drivers/net/ethernet/atheros/Kconfig"
-diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
-index 58de333..224a018 100644
---- a/drivers/net/ethernet/Makefile
-+++ b/drivers/net/ethernet/Makefile
-@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/
- obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
- obj-$(CONFIG_ALTERA_TSE) += altera/
- obj-$(CONFIG_NET_VENDOR_AMD) += amd/
-+obj-$(CONFIG_NET_XGENE) += apm/
- obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
- obj-$(CONFIG_NET_VENDOR_ARC) += arc/
- obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
-diff --git a/drivers/net/ethernet/apm/Kconfig b/drivers/net/ethernet/apm/Kconfig
+ exit:
+diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
new file mode 100644
-index 0000000..ec63d70
+index 0000000..0d08373
--- /dev/null
-+++ b/drivers/net/ethernet/apm/Kconfig
-@@ -0,0 +1 @@
-+source "drivers/net/ethernet/apm/xgene/Kconfig"
-diff --git a/drivers/net/ethernet/apm/Makefile b/drivers/net/ethernet/apm/Makefile
-new file mode 100644
-index 0000000..65ce32a
---- /dev/null
-+++ b/drivers/net/ethernet/apm/Makefile
-@@ -0,0 +1,5 @@
-+#
-+# Makefile for APM X-GENE Ethernet driver.
-+#
-+
-+obj-$(CONFIG_NET_XGENE) += xgene/
-diff --git a/drivers/net/ethernet/apm/xgene/Kconfig b/drivers/net/ethernet/apm/xgene/Kconfig
-new file mode 100644
-index 0000000..616dff6
---- /dev/null
-+++ b/drivers/net/ethernet/apm/xgene/Kconfig
-@@ -0,0 +1,9 @@
-+config NET_XGENE
-+ tristate "APM X-Gene SoC Ethernet Driver"
-+ select PHYLIB
-+ help
-+ This is the Ethernet driver for the on-chip ethernet interface on the
-+ APM X-Gene SoC.
-+
-+ To compile this driver as a module, choose M here. This module will
-+ be called xgene_enet.
-diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile
-new file mode 100644
-index 0000000..c643e8a
---- /dev/null
-+++ b/drivers/net/ethernet/apm/xgene/Makefile
-@@ -0,0 +1,6 @@
-+#
-+# Makefile for APM X-Gene Ethernet Driver.
-+#
-+
-+xgene-enet-objs := xgene_enet_hw.o xgene_enet_main.o xgene_enet_ethtool.o
-+obj-$(CONFIG_NET_XGENE) += xgene-enet.o
-diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
-new file mode 100644
-index 0000000..63f2aa5
---- /dev/null
-+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
-@@ -0,0 +1,125 @@
-+/* Applied Micro X-Gene SoC Ethernet Driver
-+ *
-+ * Copyright (c) 2014, Applied Micro Circuits Corporation
-+ * Authors: Iyappan Subramanian <isubramanian@apm.com>
++++ b/drivers/acpi/property.c
+@@ -0,0 +1,551 @@
++/*
++ * ACPI device specific properties support.
+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
++ * Copyright (C) 2014, Intel Corporation
++ * All rights reserved.
+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
++ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
++ * Darren Hart <dvhart@linux.intel.com>
++ * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
+ */
+
-+#include <linux/ethtool.h>
-+#include "xgene_enet_main.h"
++#include <linux/acpi.h>
++#include <linux/device.h>
++#include <linux/export.h>
+
-+struct xgene_gstrings_stats {
-+ char name[ETH_GSTRING_LEN];
-+ int offset;
-+};
++#include "internal.h"
+
-+#define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) }
-+
-+static const struct xgene_gstrings_stats gstrings_stats[] = {
-+ XGENE_STAT(rx_packets),
-+ XGENE_STAT(tx_packets),
-+ XGENE_STAT(rx_bytes),
-+ XGENE_STAT(tx_bytes),
-+ XGENE_STAT(rx_errors),
-+ XGENE_STAT(tx_errors),
-+ XGENE_STAT(rx_length_errors),
-+ XGENE_STAT(rx_crc_errors),
-+ XGENE_STAT(rx_frame_errors),
-+ XGENE_STAT(rx_fifo_errors)
++/* 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
+};
+
-+#define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats)
-+
-+static void xgene_get_drvinfo(struct net_device *ndev,
-+ struct ethtool_drvinfo *info)
++static bool acpi_property_value_ok(const union acpi_object *value)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct platform_device *pdev = pdata->pdev;
++ int j;
+
-+ strcpy(info->driver, "xgene_enet");
-+ strcpy(info->version, XGENE_DRV_VERSION);
-+ snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A");
-+ sprintf(info->bus_info, "%s", pdev->name);
-+}
-+
-+static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
-+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct phy_device *phydev = pdata->phy_dev;
++ /*
++ * 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;
+
-+ if (phydev == NULL)
-+ return -ENODEV;
++ default:
++ return false;
++ }
+
-+ return phy_ethtool_gset(phydev, cmd);
++ return true;
++ }
++ return false;
+}
+
-+static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
++static bool acpi_properties_format_valid(const union acpi_object *properties)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct phy_device *phydev = pdata->phy_dev;
++ int i;
+
-+ if (phydev == NULL)
-+ return -ENODEV;
++ for (i = 0; i < properties->package.count; i++) {
++ const union acpi_object *property;
+
-+ return phy_ethtool_sset(phydev, cmd);
++ 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;
+}
+
-+static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
++static void acpi_init_of_compatible(struct acpi_device *adev)
+{
-+ int i;
-+ u8 *p = data;
-+
-+ if (stringset != ETH_SS_STATS)
-+ return;
++ const union acpi_object *of_compatible;
++ struct acpi_hardware_id *hwid;
++ bool acpi_of = false;
++ int ret;
+
-+ for (i = 0; i < XGENE_STATS_LEN; i++) {
-+ memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
-+ p += ETH_GSTRING_LEN;
++ /*
++ * 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;
++ }
+ }
-+}
+
-+static int xgene_get_sset_count(struct net_device *ndev, int sset)
-+{
-+ if (sset != ETH_SS_STATS)
-+ return -EINVAL;
++ if (!acpi_of)
++ return;
+
-+ return XGENE_STATS_LEN;
++ ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
++ &of_compatible);
++ if (ret) {
++ ret = acpi_dev_get_property(adev, "compatible",
++ ACPI_TYPE_STRING, &of_compatible);
++ if (ret) {
++ acpi_handle_warn(adev->handle,
++ "PRP0001 requires compatible property\n");
++ return;
++ }
++ }
++ adev->data.of_compatible = of_compatible;
+}
+
-+static void xgene_get_ethtool_stats(struct net_device *ndev,
-+ struct ethtool_stats *dummy,
-+ u64 *data)
++void acpi_init_properties(struct acpi_device *adev)
+{
-+ void *pdata = netdev_priv(ndev);
++ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
++ const union acpi_object *desc;
++ acpi_status status;
+ int i;
+
-+ for (i = 0; i < XGENE_STATS_LEN; i++)
-+ *data++ = *(u64 *)(pdata + gstrings_stats[i].offset);
-+}
++ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
++ ACPI_TYPE_PACKAGE);
++ if (ACPI_FAILURE(status))
++ return;
+
-+static const struct ethtool_ops xgene_ethtool_ops = {
-+ .get_drvinfo = xgene_get_drvinfo,
-+ .get_settings = xgene_get_settings,
-+ .set_settings = xgene_set_settings,
-+ .get_link = ethtool_op_get_link,
-+ .get_strings = xgene_get_strings,
-+ .get_sset_count = xgene_get_sset_count,
-+ .get_ethtool_stats = xgene_get_ethtool_stats
-+};
++ desc = buf.pointer;
++ if (desc->package.count % 2)
++ goto fail;
+
-+void xgene_enet_set_ethtool_ops(struct net_device *ndev)
-+{
-+ ndev->ethtool_ops = &xgene_ethtool_ops;
-+}
-diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
-new file mode 100644
-index 0000000..e52af60
---- /dev/null
-+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
-@@ -0,0 +1,747 @@
-+/* Applied Micro X-Gene SoC Ethernet Driver
-+ *
-+ * Copyright (c) 2014, Applied Micro Circuits Corporation
-+ * Authors: Iyappan Subramanian <isubramanian@apm.com>
-+ * Ravi Patel <rapatel@apm.com>
-+ * Keyur Chudgar <kchudgar@apm.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include "xgene_enet_main.h"
-+#include "xgene_enet_hw.h"
++ /* Look for the device properties UUID. */
++ for (i = 0; i < desc->package.count; i += 2) {
++ const union acpi_object *uuid, *properties;
+
-+static void xgene_enet_ring_init(struct xgene_enet_desc_ring *ring)
-+{
-+ u32 *ring_cfg = ring->state;
-+ u64 addr = ring->dma;
-+ enum xgene_enet_ring_cfgsize cfgsize = ring->cfgsize;
++ uuid = &desc->package.elements[i];
++ properties = &desc->package.elements[i + 1];
+
-+ ring_cfg[4] |= (1 << SELTHRSH_POS) &
-+ CREATE_MASK(SELTHRSH_POS, SELTHRSH_LEN);
-+ ring_cfg[3] |= ACCEPTLERR;
-+ ring_cfg[2] |= QCOHERENT;
++ /*
++ * 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;
+
-+ addr >>= 8;
-+ ring_cfg[2] |= (addr << RINGADDRL_POS) &
-+ CREATE_MASK_ULL(RINGADDRL_POS, RINGADDRL_LEN);
-+ addr >>= RINGADDRL_LEN;
-+ ring_cfg[3] |= addr & CREATE_MASK_ULL(RINGADDRH_POS, RINGADDRH_LEN);
-+ ring_cfg[3] |= ((u32) cfgsize << RINGSIZE_POS) &
-+ CREATE_MASK(RINGSIZE_POS, RINGSIZE_LEN);
-+}
++ if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
++ continue;
+
-+static void xgene_enet_ring_set_type(struct xgene_enet_desc_ring *ring)
-+{
-+ u32 *ring_cfg = ring->state;
-+ bool is_bufpool;
-+ u32 val;
++ /*
++ * We found the matching UUID. Now validate the format of the
++ * package immediately following it.
++ */
++ if (!acpi_properties_format_valid(properties))
++ break;
+
-+ is_bufpool = xgene_enet_is_bufpool(ring->id);
-+ val = (is_bufpool) ? RING_BUFPOOL : RING_REGULAR;
-+ ring_cfg[4] |= (val << RINGTYPE_POS) &
-+ CREATE_MASK(RINGTYPE_POS, RINGTYPE_LEN);
++ adev->data.pointer = buf.pointer;
++ adev->data.properties = properties;
+
-+ if (is_bufpool) {
-+ ring_cfg[3] |= (BUFPOOL_MODE << RINGMODE_POS) &
-+ CREATE_MASK(RINGMODE_POS, RINGMODE_LEN);
++ acpi_init_of_compatible(adev);
++ return;
+ }
-+}
-+
-+static void xgene_enet_ring_set_recombbuf(struct xgene_enet_desc_ring *ring)
-+{
-+ u32 *ring_cfg = ring->state;
-+
-+ ring_cfg[3] |= RECOMBBUF;
-+ ring_cfg[3] |= (0xf << RECOMTIMEOUTL_POS) &
-+ CREATE_MASK(RECOMTIMEOUTL_POS, RECOMTIMEOUTL_LEN);
-+ ring_cfg[4] |= 0x7 & CREATE_MASK(RECOMTIMEOUTH_POS, RECOMTIMEOUTH_LEN);
-+}
-+
-+static void xgene_enet_ring_wr32(struct xgene_enet_desc_ring *ring,
-+ u32 offset, u32 data)
-+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
+
-+ iowrite32(data, pdata->ring_csr_addr + offset);
++ fail:
++ dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
++ ACPI_FREE(buf.pointer);
+}
+
-+static void xgene_enet_ring_rd32(struct xgene_enet_desc_ring *ring,
-+ u32 offset, u32 *data)
++void acpi_free_properties(struct acpi_device *adev)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
-+
-+ *data = ioread32(pdata->ring_csr_addr + offset);
++ ACPI_FREE((void *)adev->data.pointer);
++ adev->data.of_compatible = NULL;
++ adev->data.pointer = NULL;
++ adev->data.properties = NULL;
+}
+
-+static void xgene_enet_write_ring_state(struct xgene_enet_desc_ring *ring)
++/**
++ * 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;
+
-+ xgene_enet_ring_wr32(ring, CSR_RING_CONFIG, ring->num);
-+ for (i = 0; i < NUM_RING_CONFIG; i++) {
-+ xgene_enet_ring_wr32(ring, CSR_RING_WR_BASE + (i * 4),
-+ ring->state[i]);
-+ }
-+}
-+
-+static void xgene_enet_clr_ring_state(struct xgene_enet_desc_ring *ring)
-+{
-+ memset(ring->state, 0, sizeof(u32) * NUM_RING_CONFIG);
-+ xgene_enet_write_ring_state(ring);
-+}
-+
-+static void xgene_enet_set_ring_state(struct xgene_enet_desc_ring *ring)
-+{
-+ xgene_enet_ring_set_type(ring);
-+
-+ if (xgene_enet_ring_owner(ring->id) == RING_OWNER_ETH0)
-+ xgene_enet_ring_set_recombbuf(ring);
-+
-+ xgene_enet_ring_init(ring);
-+ xgene_enet_write_ring_state(ring);
-+}
-+
-+static void xgene_enet_set_ring_id(struct xgene_enet_desc_ring *ring)
-+{
-+ u32 ring_id_val, ring_id_buf;
-+ bool is_bufpool;
-+
-+ is_bufpool = xgene_enet_is_bufpool(ring->id);
-+
-+ ring_id_val = ring->id & GENMASK(9, 0);
-+ ring_id_val |= OVERWRITE;
-+
-+ ring_id_buf = (ring->num << 9) & GENMASK(18, 9);
-+ ring_id_buf |= PREFETCH_BUF_EN;
-+ if (is_bufpool)
-+ ring_id_buf |= IS_BUFFER_POOL;
-+
-+ xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id_val);
-+ xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, ring_id_buf);
-+}
-+
-+static void xgene_enet_clr_desc_ring_id(struct xgene_enet_desc_ring *ring)
-+{
-+ u32 ring_id;
++ if (!adev || !name)
++ return -EINVAL;
+
-+ ring_id = ring->id | OVERWRITE;
-+ xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id);
-+ xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, 0);
-+}
++ if (!adev->data.pointer || !adev->data.properties)
++ return -ENODATA;
+
-+struct xgene_enet_desc_ring *xgene_enet_setup_ring(
-+ struct xgene_enet_desc_ring *ring)
-+{
-+ u32 size = ring->size;
-+ u32 i, data;
-+ u64 *desc;
-+ bool is_bufpool;
++ properties = adev->data.properties;
++ for (i = 0; i < properties->package.count; i++) {
++ const union acpi_object *propname, *propvalue;
++ const union acpi_object *property;
+
-+ xgene_enet_clr_ring_state(ring);
-+ xgene_enet_set_ring_state(ring);
-+ xgene_enet_set_ring_id(ring);
++ property = &properties->package.elements[i];
+
-+ ring->slots = xgene_enet_get_numslots(ring->id, size);
++ propname = &property->package.elements[0];
++ propvalue = &property->package.elements[1];
+
-+ is_bufpool = xgene_enet_is_bufpool(ring->id);
-+ if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU)
-+ return ring;
++ if (!strcmp(name, propname->string.pointer)) {
++ if (type != ACPI_TYPE_ANY && propvalue->type != type)
++ return -EPROTO;
++ else if (obj)
++ *obj = propvalue;
+
-+ for (i = 0; i < ring->slots; i++) {
-+ desc = (u64 *)&ring->raw_desc[i];
-+ desc[EMPTY_SLOT_INDEX] = EMPTY_SLOT;
++ return 0;
++ }
+ }
-+
-+ xgene_enet_ring_rd32(ring, CSR_RING_NE_INT_MODE, &data);
-+ data |= BIT(31 - xgene_enet_ring_bufnum(ring->id));
-+ xgene_enet_ring_wr32(ring, CSR_RING_NE_INT_MODE, data);
-+
-+ return ring;
++ return -ENODATA;
+}
++EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
-+void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring)
++/**
++ * 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)
+{
-+ u32 data;
-+ bool is_bufpool;
++ const union acpi_object *prop;
++ int ret, i;
+
-+ is_bufpool = xgene_enet_is_bufpool(ring->id);
-+ if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU)
-+ goto out;
-+
-+ xgene_enet_ring_rd32(ring, CSR_RING_NE_INT_MODE, &data);
-+ data &= ~BIT(31 - xgene_enet_ring_bufnum(ring->id));
-+ xgene_enet_ring_wr32(ring, CSR_RING_NE_INT_MODE, data);
-+
-+out:
-+ xgene_enet_clr_desc_ring_id(ring);
-+ xgene_enet_clr_ring_state(ring);
-+}
-+
-+void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
-+ struct xgene_enet_pdata *pdata,
-+ enum xgene_enet_err_code status)
-+{
-+ struct rtnl_link_stats64 *stats = &pdata->stats;
++ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
++ if (ret)
++ return ret;
+
-+ switch (status) {
-+ case INGRESS_CRC:
-+ stats->rx_crc_errors++;
-+ break;
-+ case INGRESS_CHECKSUM:
-+ case INGRESS_CHECKSUM_COMPUTE:
-+ stats->rx_errors++;
-+ break;
-+ case INGRESS_TRUNC_FRAME:
-+ stats->rx_frame_errors++;
-+ break;
-+ case INGRESS_PKT_LEN:
-+ stats->rx_length_errors++;
-+ break;
-+ case INGRESS_PKT_UNDER:
-+ stats->rx_frame_errors++;
-+ break;
-+ case INGRESS_FIFO_OVERRUN:
-+ stats->rx_fifo_errors++;
-+ break;
-+ default:
-+ break;
++ 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;
+ }
-+}
-+
-+static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata,
-+ u32 offset, u32 val)
-+{
-+ void __iomem *addr = pdata->eth_csr_addr + offset;
-+
-+ iowrite32(val, addr);
-+}
++ if (obj)
++ *obj = prop;
+
-+static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata,
-+ u32 offset, u32 val)
-+{
-+ void __iomem *addr = pdata->eth_ring_if_addr + offset;
-+
-+ iowrite32(val, addr);
++ return 0;
+}
++EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
+
-+static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata,
-+ u32 offset, u32 val)
++/**
++ * acpi_dev_get_property_reference - returns handle to the referenced object
++ * @adev: ACPI device to get property
++ * @name: Name of the property
++ * @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, store
++ * them in the @args->args[] array.
++ *
++ * 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, size_t index,
++ struct acpi_reference_args *args)
+{
-+ void __iomem *addr = pdata->eth_diag_csr_addr + offset;
++ const union acpi_object *element, *end;
++ const union acpi_object *obj;
++ struct acpi_device *device;
++ int ret, idx = 0;
+
-+ iowrite32(val, addr);
-+}
++ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
++ if (ret)
++ return ret;
+
-+static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata,
-+ u32 offset, u32 val)
-+{
-+ void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
++ /*
++ * The simplest case is when the value is a single reference. Just
++ * return that reference then.
++ */
++ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
++ if (index)
++ return -EINVAL;
+
-+ iowrite32(val, addr);
-+}
++ ret = acpi_bus_get_device(obj->reference.handle, &device);
++ if (ret)
++ return ret;
+
-+static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr,
-+ void __iomem *cmd, void __iomem *cmd_done,
-+ u32 wr_addr, u32 wr_data)
-+{
-+ u32 done;
-+ u8 wait = 10;
++ args->adev = device;
++ args->nargs = 0;
++ return 0;
++ }
+
-+ iowrite32(wr_addr, addr);
-+ iowrite32(wr_data, wr);
-+ iowrite32(XGENE_ENET_WR_CMD, cmd);
++ /*
++ * 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;
+
-+ /* wait for write command to complete */
-+ while (!(done = ioread32(cmd_done)) && wait--)
-+ udelay(1);
++ element = obj->package.elements;
++ end = element + obj->package.count;
+
-+ if (!done)
-+ return false;
++ while (element < end) {
++ u32 nargs, i;
+
-+ iowrite32(0, cmd);
++ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
++ return -EPROTO;
+
-+ return true;
-+}
++ ret = acpi_bus_get_device(element->reference.handle, &device);
++ if (ret)
++ return -ENODEV;
+
-+static void xgene_enet_wr_mcx_mac(struct xgene_enet_pdata *pdata,
-+ u32 wr_addr, u32 wr_data)
-+{
-+ void __iomem *addr, *wr, *cmd, *cmd_done;
-+ bool ret;
++ element++;
++ nargs = 0;
+
-+ addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
-+ wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET;
-+ cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
-+ cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
++ /* assume following integer elements are all args */
++ for (i = 0; element + i < end; i++) {
++ int type = element[i].type;
+
-+ ret = xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data);
-+ if (!ret)
-+ netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n",
-+ wr_addr);
-+}
++ if (type == ACPI_TYPE_INTEGER)
++ nargs++;
++ else if (type == ACPI_TYPE_LOCAL_REFERENCE)
++ break;
++ else
++ return -EPROTO;
++ }
+
-+static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata,
-+ u32 offset, u32 *val)
-+{
-+ void __iomem *addr = pdata->eth_csr_addr + offset;
++ if (idx++ == index) {
++ args->adev = device;
++ args->nargs = nargs;
++ for (i = 0; i < nargs; i++)
++ args->args[i] = element[i].integer.value;
+
-+ *val = ioread32(addr);
-+}
++ return 0;
++ }
+
-+static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata,
-+ u32 offset, u32 *val)
-+{
-+ void __iomem *addr = pdata->eth_diag_csr_addr + offset;
++ element += nargs;
++ }
+
-+ *val = ioread32(addr);
++ return -EPROTO;
+}
++EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
-+static void xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *pdata,
-+ u32 offset, u32 *val)
++int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
++ void **valptr)
+{
-+ void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
-+
-+ *val = ioread32(addr);
++ return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
++ (const union acpi_object **)valptr);
+}
+
-+static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd,
-+ void __iomem *cmd, void __iomem *cmd_done,
-+ u32 rd_addr, u32 *rd_data)
++int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
++ enum dev_prop_type proptype, void *val)
+{
-+ u32 done;
-+ u8 wait = 10;
-+
-+ iowrite32(rd_addr, addr);
-+ iowrite32(XGENE_ENET_RD_CMD, cmd);
++ const union acpi_object *obj;
++ int ret;
+
-+ /* wait for read command to complete */
-+ while (!(done = ioread32(cmd_done)) && wait--)
-+ udelay(1);
++ if (!val)
++ return -EINVAL;
+
-+ if (!done)
-+ return false;
++ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
++ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
++ if (ret)
++ return ret;
+
-+ *rd_data = ioread32(rd);
-+ iowrite32(0, cmd);
++ 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;
+
-+ return true;
++ *(char **)val = obj->string.pointer;
++ } else {
++ ret = -EINVAL;
++ }
++ return ret;
+}
+
-+static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata,
-+ u32 rd_addr, u32 *rd_data)
++static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
++ size_t nval)
+{
-+ void __iomem *addr, *rd, *cmd, *cmd_done;
-+ bool ret;
++ int i;
+
-+ addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
-+ rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET;
-+ cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
-+ cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
++ for (i = 0; i < nval; i++) {
++ if (items[i].type != ACPI_TYPE_INTEGER)
++ return -EPROTO;
++ if (items[i].integer.value > U8_MAX)
++ return -EOVERFLOW;
+
-+ ret = xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data);
-+ if (!ret)
-+ netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n",
-+ rd_addr);
++ val[i] = items[i].integer.value;
++ }
++ return 0;
+}
+
-+static int xgene_mii_phy_write(struct xgene_enet_pdata *pdata, int phy_id,
-+ u32 reg, u16 data)
++static int acpi_copy_property_array_u16(const union acpi_object *items,
++ u16 *val, size_t nval)
+{
-+ u32 addr = 0, wr_data = 0;
-+ u32 done;
-+ u8 wait = 10;
-+
-+ PHY_ADDR_SET(&addr, phy_id);
-+ REG_ADDR_SET(&addr, reg);
-+ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr);
++ int i;
+
-+ PHY_CONTROL_SET(&wr_data, data);
-+ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONTROL_ADDR, wr_data);
-+ do {
-+ usleep_range(5, 10);
-+ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done);
-+ } while ((done & BUSY_MASK) && wait--);
++ for (i = 0; i < nval; i++) {
++ if (items[i].type != ACPI_TYPE_INTEGER)
++ return -EPROTO;
++ if (items[i].integer.value > U16_MAX)
++ return -EOVERFLOW;
+
-+ if (done & BUSY_MASK) {
-+ netdev_err(pdata->ndev, "MII_MGMT write failed\n");
-+ return -1;
++ val[i] = items[i].integer.value;
+ }
-+
+ return 0;
+}
+
-+static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata,
-+ u8 phy_id, u32 reg)
++static int acpi_copy_property_array_u32(const union acpi_object *items,
++ u32 *val, size_t nval)
+{
-+ u32 addr = 0;
-+ u32 data, done;
-+ u8 wait = 10;
++ int i;
+
-+ PHY_ADDR_SET(&addr, phy_id);
-+ REG_ADDR_SET(&addr, reg);
-+ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr);
-+ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK);
-+ do {
-+ usleep_range(5, 10);
-+ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done);
-+ } while ((done & BUSY_MASK) && wait--);
++ for (i = 0; i < nval; i++) {
++ if (items[i].type != ACPI_TYPE_INTEGER)
++ return -EPROTO;
++ if (items[i].integer.value > U32_MAX)
++ return -EOVERFLOW;
+
-+ if (done & BUSY_MASK) {
-+ netdev_err(pdata->ndev, "MII_MGMT read failed\n");
-+ return -1;
++ val[i] = items[i].integer.value;
+ }
-+
-+ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_STATUS_ADDR, &data);
-+ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, 0);
-+
-+ return data;
++ return 0;
+}
+
-+void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata)
++static int acpi_copy_property_array_u64(const union acpi_object *items,
++ u64 *val, size_t nval)
+{
-+ u32 addr0, addr1;
-+ u8 *dev_addr = pdata->ndev->dev_addr;
++ int i;
+
-+ addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
-+ (dev_addr[1] << 8) | dev_addr[0];
-+ addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16);
-+ addr1 |= pdata->phy_addr & 0xFFFF;
++ for (i = 0; i < nval; i++) {
++ if (items[i].type != ACPI_TYPE_INTEGER)
++ return -EPROTO;
+
-+ xgene_enet_wr_mcx_mac(pdata, STATION_ADDR0_ADDR, addr0);
-+ xgene_enet_wr_mcx_mac(pdata, STATION_ADDR1_ADDR, addr1);
++ val[i] = items[i].integer.value;
++ }
++ return 0;
+}
+
-+static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
++static int acpi_copy_property_array_string(const union acpi_object *items,
++ char **val, size_t nval)
+{
-+ struct net_device *ndev = pdata->ndev;
-+ u32 data;
-+ u8 wait = 10;
++ int i;
+
-+ xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0);
-+ do {
-+ usleep_range(100, 110);
-+ xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data);
-+ } while ((data != 0xffffffff) && wait--);
++ for (i = 0; i < nval; i++) {
++ if (items[i].type != ACPI_TYPE_STRING)
++ return -EPROTO;
+
-+ if (data != 0xffffffff) {
-+ netdev_err(ndev, "Failed to release memory from shutdown\n");
-+ return -ENODEV;
++ val[i] = items[i].string.pointer;
+ }
-+
+ return 0;
+}
+
-+void xgene_gmac_reset(struct xgene_enet_pdata *pdata)
++int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
++ enum dev_prop_type proptype, void *val, size_t nval)
+{
-+ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1);
-+ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0);
-+}
++ const union acpi_object *obj;
++ const union acpi_object *items;
++ int ret;
+
-+void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed)
-+{
-+ u32 value, mc2;
-+ u32 intf_ctl, rgmii;
-+ u32 icm0, icm2;
++ if (val && nval == 1) {
++ ret = acpi_dev_prop_read_single(adev, propname, proptype, val);
++ if (!ret)
++ return ret;
++ }
+
-+ xgene_gmac_reset(pdata);
++ ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
++ if (ret)
++ return ret;
++
++ if (!val)
++ return obj->package.count;
++ else if (nval <= 0)
++ return -EINVAL;
+
-+ xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0);
-+ xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2);
-+ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_2_ADDR, &mc2);
-+ xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl);
-+ xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii);
++ if (nval > obj->package.count)
++ return -EOVERFLOW;
+
-+ switch (speed) {
-+ case SPEED_10:
-+ ENET_INTERFACE_MODE2_SET(&mc2, 1);
-+ CFG_MACMODE_SET(&icm0, 0);
-+ CFG_WAITASYNCRD_SET(&icm2, 500);
-+ rgmii &= ~CFG_SPEED_1250;
++ items = obj->package.elements;
++ switch (proptype) {
++ case DEV_PROP_U8:
++ ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
+ break;
-+ case SPEED_100:
-+ ENET_INTERFACE_MODE2_SET(&mc2, 1);
-+ intf_ctl |= ENET_LHD_MODE;
-+ CFG_MACMODE_SET(&icm0, 1);
-+ CFG_WAITASYNCRD_SET(&icm2, 80);
-+ rgmii &= ~CFG_SPEED_1250;
++ 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:
-+ ENET_INTERFACE_MODE2_SET(&mc2, 2);
-+ intf_ctl |= ENET_GHD_MODE;
-+ CFG_TXCLK_MUXSEL0_SET(&rgmii, 4);
-+ xgene_enet_rd_csr(pdata, DEBUG_REG_ADDR, &value);
-+ value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX;
-+ xgene_enet_wr_csr(pdata, DEBUG_REG_ADDR, value);
++ ret = -EINVAL;
+ break;
+ }
-+
-+ mc2 |= FULL_DUPLEX2;
-+ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2);
-+ xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl);
-+
-+ xgene_gmac_set_mac_addr(pdata);
-+
-+ /* Adjust MDC clock frequency */
-+ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &value);
-+ MGMT_CLOCK_SEL_SET(&value, 7);
-+ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, value);
-+
-+ /* Enable drop if bufpool not available */
-+ xgene_enet_rd_csr(pdata, RSIF_CONFIG_REG_ADDR, &value);
-+ value |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
-+ xgene_enet_wr_csr(pdata, RSIF_CONFIG_REG_ADDR, value);
-+
-+ /* Rtype should be copied from FP */
-+ xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0);
-+ xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii);
-+
-+ /* Rx-Tx traffic resume */
-+ xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0);
-+
-+ xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0);
-+ xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2);
-+
-+ xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value);
-+ value &= ~TX_DV_GATE_EN0;
-+ value &= ~RX_DV_GATE_EN0;
-+ value |= RESUME_RX0;
-+ xgene_enet_wr_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, value);
-+
-+ xgene_enet_wr_csr(pdata, CFG_BYPASS_ADDR, RESUME_TX);
++ return ret;
+}
-+
-+static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata)
+diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
+index 0476e90..9cb5cca 100644
+--- a/drivers/acpi/scan.c
++++ b/drivers/acpi/scan.c
+@@ -124,17 +124,56 @@ 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;
+-
+- 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;
++ /*
++ * If the device has PRP0001 we expose DT compatible modalias
++ * instead in form of of:NnameTCcompatible.
++ */
++ if (acpi_dev->data.of_compatible) {
++ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
++ const union acpi_object *of_compatible, *obj;
++ int i, nval;
++ char *c;
++
++ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
++ /* DT strings are all in lower case */
++ for (c = buf.pointer; *c != '\0'; c++)
++ *c = tolower(*c);
++
++ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
++ ACPI_FREE(buf.pointer);
++
++ of_compatible = acpi_dev->data.of_compatible;
++ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
++ nval = of_compatible->package.count;
++ obj = of_compatible->package.elements;
++ } else { /* Must be ACPI_TYPE_STRING. */
++ nval = 1;
++ obj = of_compatible;
++ }
++ for (i = 0; i < nval; i++, obj++) {
++ 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';
+@@ -902,6 +941,51 @@ int acpi_match_device_ids(struct acpi_device *device,
+ }
+ EXPORT_SYMBOL(acpi_match_device_ids);
+
++/* Performs match against special "PRP0001" shoehorn ACPI ID */
++static bool acpi_of_driver_match_device(struct device *dev,
++ const struct device_driver *drv)
+{
-+ u32 val = 0xffffffff;
++ const union acpi_object *of_compatible, *obj;
++ struct acpi_device *adev;
++ int i, nval;
+
-+ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, val);
-+ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, val);
-+ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, val);
-+ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, val);
-+}
++ adev = ACPI_COMPANION(dev);
++ if (!adev)
++ return false;
+
-+void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
-+ u32 dst_ring_num, u16 bufpool_id)
-+{
-+ u32 cb;
-+ u32 fpsel;
++ of_compatible = adev->data.of_compatible;
++ if (!drv->of_match_table || !of_compatible)
++ return false;
+
-+ fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20;
++ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
++ nval = of_compatible->package.count;
++ obj = of_compatible->package.elements;
++ } else { /* Must be ACPI_TYPE_STRING. */
++ nval = 1;
++ obj = of_compatible;
++ }
++ /* Now we can look for the driver DT compatible strings */
++ for (i = 0; i < nval; i++, obj++) {
++ const struct of_device_id *id;
+
-+ xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb);
-+ cb |= CFG_CLE_BYPASS_EN0;
-+ CFG_CLE_IP_PROTOCOL0_SET(&cb, 3);
-+ xgene_enet_wr_csr(pdata, CLE_BYPASS_REG0_0_ADDR, cb);
++ for (id = drv->of_match_table; id->compatible[0]; id++)
++ if (!strcasecmp(obj->string.pointer, id->compatible))
++ return true;
++ }
+
-+ xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb);
-+ CFG_CLE_DSTQID0_SET(&cb, dst_ring_num);
-+ CFG_CLE_FPSEL0_SET(&cb, fpsel);
-+ xgene_enet_wr_csr(pdata, CLE_BYPASS_REG1_0_ADDR, cb);
++ return false;
+}
+
-+void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata)
++bool acpi_driver_match_device(struct device *dev,
++ const struct device_driver *drv)
+{
-+ u32 data;
++ if (!drv->acpi_match_table)
++ return acpi_of_driver_match_device(dev, drv);
+
-+ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
-+ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN);
++ return !!acpi_match_device(drv->acpi_match_table, dev);
+}
++EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
-+void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata)
+ static void acpi_free_power_resources_lists(struct acpi_device *device)
+ {
+ int i;
+@@ -922,6 +1006,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);
+@@ -1304,6 +1389,26 @@ int acpi_device_add(struct acpi_device *device,
+ return result;
+ }
+
++struct acpi_device *acpi_get_next_child(struct device *dev,
++ struct acpi_device *child)
+{
-+ u32 data;
-+
-+ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
-+ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN);
-+}
++ struct acpi_device *adev = ACPI_COMPANION(dev);
++ struct list_head *head, *next;
+
-+void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata)
-+{
-+ u32 data;
++ if (!adev)
++ return NULL;
+
-+ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
-+ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN);
-+}
++ head = &adev->children;
++ if (list_empty(head))
++ return NULL;
+
-+void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata)
-+{
-+ u32 data;
++ if (!child)
++ return list_first_entry(head, struct acpi_device, node);
++
++ next = child->node.next;
++ return next == head ? NULL : list_entry(next, struct acpi_device, node);
++}
++
+ /* --------------------------------------------------------------------------
+ Driver Management
+ -------------------------------------------------------------------------- */
+@@ -1923,9 +2028,11 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
+ device->device_type = type;
+ device->handle = handle;
+ device->parent = acpi_bus_get_parent(handle);
++ device->fwnode.type = FWNODE_ACPI;
+ 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 <graeme.gregory@linaro.org>
++ *
++ * 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.
++ */
+
-+ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data);
-+ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN);
-+}
++#include <linux/acpi.h>
+
-+void xgene_enet_reset(struct xgene_enet_pdata *pdata)
++/*
++ * 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)
+{
-+ u32 val;
-+
-+ 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);
-+
-+ /* Enable auto-incr for scanning */
-+ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val);
-+ val |= SCAN_AUTO_INCR;
-+ MGMT_CLOCK_SEL_SET(&val, 1);
-+ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val);
++ return ACPI_STATE_S0;
+}
++EXPORT_SYMBOL_GPL(acpi_target_system_state);
+
-+void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
++int __init acpi_sleep_init(void)
+{
-+ clk_disable_unprepare(pdata->clk);
++ 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");
+
-+static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-+{
-+ struct xgene_enet_pdata *pdata = bus->priv;
-+ u32 val;
++ }
++ break;
+
-+ val = xgene_mii_phy_read(pdata, mii_id, regnum);
-+ netdev_dbg(pdata->ndev, "mdio_rd: bus=%d reg=%d val=%x\n",
-+ mii_id, regnum, val);
++ 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;
+
-+ return val;
-+}
++ 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 int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
-+ u16 val)
-+{
-+ struct xgene_enet_pdata *pdata = bus->priv;
-+ int ret;
++ 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;
+
-+ netdev_dbg(pdata->ndev, "mdio_wr: bus=%d reg=%d val=%x\n",
-+ mii_id, regnum, val);
-+ ret = xgene_mii_phy_write(pdata, mii_id, regnum, val);
+ 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)
+
+
+ int __init
+-acpi_table_parse_entries(char *id,
+- unsigned long table_size,
+- int entry_id,
+- acpi_tbl_entry_handler handler,
+- unsigned int max_entries)
++acpi_parse_entries(unsigned long table_size,
++ acpi_tbl_entry_handler handler,
++ struct acpi_table_header *table_header,
++ int entry_id, unsigned int max_entries)
+ {
+- struct acpi_table_header *table_header = NULL;
+ struct acpi_subtable_header *entry;
+- unsigned int count = 0;
++ int count = 0;
+ unsigned long table_end;
+- acpi_size tbl_size;
+
+ if (acpi_disabled)
+ return -ENODEV;
+@@ -210,13 +250,11 @@ acpi_table_parse_entries(char *id,
+ if (!handler)
+ return -EINVAL;
+
+- if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
+- acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size);
+- else
+- acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
++ if (!table_size)
++ return -EINVAL;
+
+ if (!table_header) {
+- pr_warn("%4.4s not present\n", id);
++ pr_warn("Table header not present\n");
+ return -ENODEV;
+ }
+
+@@ -230,32 +268,67 @@ acpi_table_parse_entries(char *id,
+ while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
+ table_end) {
+ if (entry->type == entry_id
+- && (!max_entries || count++ < max_entries))
++ && (!max_entries || count < max_entries)) {
+ if (handler(entry, table_end))
+- goto err;
++ return -EINVAL;
++
++ count++;
++ }
+
+ /*
+ * If entry->length is 0, break from this loop to avoid
+ * infinite loop.
+ */
+ if (entry->length == 0) {
+- pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
+- goto err;
++ pr_err("[0x%02x] Invalid zero length\n", entry_id);
++ return -EINVAL;
+ }
+
+ entry = (struct acpi_subtable_header *)
+ ((unsigned long)entry + entry->length);
+ }
+
-+ return ret;
+ if (max_entries && count > max_entries) {
+ pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
+- id, entry_id, count - max_entries, count);
++ table_header->signature, entry_id, count - max_entries,
++ count);
+ }
+
+- early_acpi_os_unmap_memory((char *)table_header, tbl_size);
+ return count;
+-err:
+}
+
-+static void xgene_enet_adjust_link(struct net_device *ndev)
++int __init
++acpi_table_parse_entries(char *id,
++ unsigned long table_size,
++ int entry_id,
++ acpi_tbl_entry_handler handler,
++ unsigned int max_entries)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct phy_device *phydev = pdata->phy_dev;
++ struct acpi_table_header *table_header = NULL;
++ acpi_size tbl_size;
++ int count;
+
-+ if (phydev->link) {
-+ if (pdata->phy_speed != phydev->speed) {
-+ xgene_gmac_init(pdata, phydev->speed);
-+ xgene_gmac_rx_enable(pdata);
-+ xgene_gmac_tx_enable(pdata);
-+ pdata->phy_speed = phydev->speed;
-+ phy_print_status(phydev);
-+ }
-+ } else {
-+ xgene_gmac_rx_disable(pdata);
-+ xgene_gmac_tx_disable(pdata);
-+ pdata->phy_speed = SPEED_UNKNOWN;
-+ phy_print_status(phydev);
-+ }
-+}
++ if (acpi_disabled)
++ return -ENODEV;
+
-+static int xgene_enet_phy_connect(struct net_device *ndev)
-+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct device_node *phy_np;
-+ struct phy_device *phy_dev;
-+ struct device *dev = &pdata->pdev->dev;
++ if (!handler)
++ return -EINVAL;
+
-+ 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 (strncmp(id, ACPI_SIG_MADT, 4) == 0)
++ acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size);
++ else
++ acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
+
-+ phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link,
-+ 0, pdata->phy_mode);
-+ if (!phy_dev) {
-+ netdev_err(ndev, "Could not connect to PHY\n");
-+ return -ENODEV;
++ if (!table_header) {
++ pr_warn("%4.4s not present\n", id);
++ return -ENODEV;
+ }
+
-+ pdata->phy_speed = SPEED_UNKNOWN;
-+ phy_dev->supported &= ~SUPPORTED_10baseT_Half &
-+ ~SUPPORTED_100baseT_Half &
-+ ~SUPPORTED_1000baseT_Half;
-+ phy_dev->advertising = phy_dev->supported;
-+ pdata->phy_dev = phy_dev;
++ count = acpi_parse_entries(table_size, handler, table_header,
++ entry_id, max_entries);
+
-+ return 0;
-+}
+ early_acpi_os_unmap_memory((char *)table_header, tbl_size);
+- return -EINVAL;
++ return count;
+ }
+
+ int __init
+diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
+index 371ac12..af325a7 100644
+--- a/drivers/acpi/utils.c
++++ b/drivers/acpi/utils.c
+@@ -723,3 +723,29 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
+ return false;
+ }
+ EXPORT_SYMBOL(acpi_check_dsm);
+
-+int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
++/**
++ * acpi_check_coherency - check for memory coherency of a device
++ * @handle: ACPI device handle
++ * @val: Pointer to returned value
++ *
++ * Search a device and its parents for a _CCA method and return
++ * its value.
++ */
++acpi_status acpi_check_coherency(acpi_handle handle, int *val)
+{
-+ struct net_device *ndev = pdata->ndev;
-+ struct device *dev = &pdata->pdev->dev;
-+ struct device_node *child_np;
-+ struct device_node *mdio_np = NULL;
-+ struct mii_bus *mdio_bus;
-+ int ret;
++ unsigned long long data;
++ acpi_status status;
+
-+ for_each_child_of_node(dev->of_node, child_np) {
-+ if (of_device_is_compatible(child_np, "apm,xgene-mdio")) {
-+ mdio_np = child_np;
++ do {
++ status = acpi_evaluate_integer(handle, "_CCA", NULL, &data);
++ if (!ACPI_FAILURE(status)) {
++ *val = data;
+ break;
+ }
-+ }
-+
-+ if (!mdio_np) {
-+ netdev_dbg(ndev, "No mdio node in the dts\n");
-+ return -1;
-+ }
++ status = acpi_get_parent(handle, &handle);
++ } while (!ACPI_FAILURE(status));
++
++ return status;
++}
++EXPORT_SYMBOL(acpi_check_coherency);
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index cd4cccb..edb00c6 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -48,7 +48,7 @@ config ATA_VERBOSE_ERROR
+
+ config ATA_ACPI
+ bool "ATA ACPI Support"
+- depends on ACPI && PCI
++ depends on ACPI
+ default y
+ help
+ This option adds support for ATA-related ACPI objects.
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 06f1d59..df2ea85 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -20,6 +20,9 @@
+ #include <linux/platform_device.h>
+ #include <linux/libata.h>
+ #include <linux/ahci_platform.h>
++#ifdef CONFIG_ATA_ACPI
++#include <linux/acpi.h>
++#endif
+ #include "ahci.h"
+
+ static const struct ata_port_info ahci_port_info = {
+@@ -71,6 +74,13 @@ static const struct of_device_id ahci_of_match[] = {
+ };
+ MODULE_DEVICE_TABLE(of, ahci_of_match);
+
++#ifdef CONFIG_ATA_ACPI
++static const struct acpi_device_id ahci_acpi_match[] = {
++ { "AMDI0600", 0 }, /* AMD Seattle AHCI */
++ { },
++};
++#endif
+
-+ mdio_bus = mdiobus_alloc();
-+ if (!mdio_bus)
-+ return -ENOMEM;
+ static struct platform_driver ahci_driver = {
+ .probe = ahci_probe,
+ .remove = ata_platform_remove_one,
+@@ -78,6 +88,9 @@ static struct platform_driver ahci_driver = {
+ .name = "ahci",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_of_match,
++#ifdef CONFIG_ATA_ACPI
++ .acpi_match_table = ACPI_PTR(ahci_acpi_match),
++#endif
+ .pm = &ahci_pm_ops,
+ },
+ };
+diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
+index 0f8538f..2d8103a 100644
+--- a/drivers/ata/ahci_xgene.c
++++ b/drivers/ata/ahci_xgene.c
+@@ -28,6 +28,7 @@
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+ #include <linux/phy/phy.h>
++#include <linux/acpi.h>
+ #include "ahci.h"
+
+ /* Max # of disk per a controller */
+@@ -137,7 +138,8 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ int rc = 0;
+
+- if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA))
++ if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA ||
++ ctx->last_cmd[ap->port_no] == ATA_CMD_SMART))
+ xgene_ahci_restart_engine(ap);
+
+ rc = ahci_qc_issue(qc);
+@@ -148,14 +150,6 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
+ return rc;
+ }
+
+-static bool xgene_ahci_is_memram_inited(struct xgene_ahci_context *ctx)
+-{
+- void __iomem *diagcsr = ctx->csr_diag;
+-
+- return (readl(diagcsr + CFG_MEM_RAM_SHUTDOWN) == 0 &&
+- readl(diagcsr + BLOCK_MEM_RDY) == 0xFFFFFFFF);
+-}
+-
+ /**
+ * xgene_ahci_read_id - Read ID data from the specified device
+ * @dev: device
+@@ -501,11 +495,6 @@ static int xgene_ahci_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
+- if (xgene_ahci_is_memram_inited(ctx)) {
+- dev_info(dev, "skip clock and PHY initialization\n");
+- goto skip_clk_phy;
+- }
+-
+ /* Due to errata, HW requires full toggle transition */
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+@@ -518,7 +507,7 @@ static int xgene_ahci_probe(struct platform_device *pdev)
+
+ /* Configure the host controller */
+ xgene_ahci_hw_init(hpriv);
+-skip_clk_phy:
+
-+ mdio_bus->name = "APM X-Gene MDIO bus";
-+ mdio_bus->read = xgene_enet_mdio_read;
-+ mdio_bus->write = xgene_enet_mdio_write;
-+ snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "xgene-mii",
-+ ndev->name);
+ hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
+
+ rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info);
+@@ -533,6 +522,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
+
-+ mdio_bus->priv = pdata;
-+ mdio_bus->parent = &ndev->dev;
+ static const struct of_device_id xgene_ahci_of_match[] = {
+ {.compatible = "apm,xgene-ahci"},
+ {},
+@@ -546,6 +545,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 6922cd6..53c3fe1 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..c458458
+--- /dev/null
++++ b/drivers/base/property.c
+@@ -0,0 +1,431 @@
++/*
++ * property.c - Unified device property interface.
++ *
++ * Copyright (C) 2014, Intel Corporation
++ * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
++ * Mika Westerberg <mika.westerberg@linux.intel.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
+
-+ ret = of_mdiobus_register(mdio_bus, mdio_np);
-+ if (ret) {
-+ netdev_err(ndev, "Failed to register MDIO bus\n");
-+ goto err;
-+ }
-+ pdata->mdio_bus = mdio_bus;
++#include <linux/property.h>
++#include <linux/export.h>
++#include <linux/acpi.h>
++#include <linux/of.h>
+
-+ ret = xgene_enet_phy_connect(ndev);
-+ if (ret)
-+ goto err;
++/**
++ * device_property_present - check if a property of a device is present
++ * @dev: Device whose property is being checked
++ * @propname: Name of the property
++ *
++ * Check if property @propname is present in the device firmware description.
++ */
++bool device_property_present(struct device *dev, const char *propname)
++{
++ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
++ return of_property_read_bool(dev->of_node, propname);
+
-+ return ret;
++ return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL);
++}
++EXPORT_SYMBOL_GPL(device_property_present);
+
-+err:
-+ mdiobus_free(mdio_bus);
++/**
++ * fwnode_property_present - check if a property of a firmware node is present
++ * @fwnode: Firmware node whose property to check
++ * @propname: Name of the property
++ */
++bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
++{
++ if (is_of_node(fwnode))
++ return of_property_read_bool(of_node(fwnode), propname);
++ else if (is_acpi_node(fwnode))
++ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
-+ return ret;
++ return false;
+}
++EXPORT_SYMBOL_GPL(fwnode_property_present);
+
-+int xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata)
-+{
-+ struct mii_bus *mdio_bus;
++#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
++ (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
++ : of_property_count_elems_of_size((node), (propname), sizeof(type))
+
-+ mdio_bus = pdata->mdio_bus;
-+ mdiobus_unregister(mdio_bus);
-+ mdiobus_free(mdio_bus);
-+ pdata->mdio_bus = NULL;
++#define DEV_PROP_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \
++ IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \
++ (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \
++ _val_, _nval_)) : \
++ acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \
++ _proptype_, _val_, _nval_)
+
-+ return 0;
-+}
-diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
-new file mode 100644
-index 0000000..2041313
---- /dev/null
-+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
-@@ -0,0 +1,375 @@
-+/* Applied Micro X-Gene SoC Ethernet Driver
++/**
++ * device_property_read_u8_array - return a u8 array property of a device
++ * @dev: Device to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
+ *
-+ * Copyright (c) 2014, Applied Micro Circuits Corporation
-+ * Authors: Iyappan Subramanian <isubramanian@apm.com>
-+ * Ravi Patel <rapatel@apm.com>
-+ * Keyur Chudgar <kchudgar@apm.com>
++ * Function reads an array of u8 properties with @propname from the device
++ * firmware description and stores them to @val if found.
+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of numbers,
++ * %-EOVERFLOW if the size of the property is not as expected.
++ */
++int device_property_read_u8_array(struct device *dev, const char *propname,
++ u8 *val, size_t nval)
++{
++ return DEV_PROP_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val, nval);
++}
++EXPORT_SYMBOL_GPL(device_property_read_u8_array);
++
++/**
++ * device_property_read_u16_array - return a u16 array property of a device
++ * @dev: Device to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
++ * Function reads an array of u16 properties with @propname from the device
++ * firmware description and stores them to @val if found.
+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of numbers,
++ * %-EOVERFLOW if the size of the property is not as expected.
+ */
-+
-+#ifndef __XGENE_ENET_HW_H__
-+#define __XGENE_ENET_HW_H__
-+
-+#include "xgene_enet_main.h"
-+
-+struct xgene_enet_pdata;
-+struct xgene_enet_stats;
-+
-+/* clears and then set bits */
-+static inline void xgene_set_bits(u32 *dst, u32 val, u32 start, u32 len)
-+{
-+ u32 end = start + len - 1;
-+ u32 mask = GENMASK(end, start);
-+
-+ *dst &= ~mask;
-+ *dst |= (val << start) & mask;
-+}
-+
-+static inline u32 xgene_get_bits(u32 val, u32 start, u32 end)
-+{
-+ return (val & GENMASK(end, start)) >> start;
-+}
-+
-+#define CSR_RING_ID 0x0008
-+#define OVERWRITE BIT(31)
-+#define IS_BUFFER_POOL BIT(20)
-+#define PREFETCH_BUF_EN BIT(21)
-+#define CSR_RING_ID_BUF 0x000c
-+#define CSR_RING_NE_INT_MODE 0x017c
-+#define CSR_RING_CONFIG 0x006c
-+#define CSR_RING_WR_BASE 0x0070
-+#define NUM_RING_CONFIG 5
-+#define BUFPOOL_MODE 3
-+#define RM3 3
-+#define INC_DEC_CMD_ADDR 0x002c
-+#define UDP_HDR_SIZE 2
-+#define BUF_LEN_CODE_2K 0x5000
-+
-+#define CREATE_MASK(pos, len) GENMASK((pos)+(len)-1, (pos))
-+#define CREATE_MASK_ULL(pos, len) GENMASK_ULL((pos)+(len)-1, (pos))
-+
-+/* Empty slot soft signature */
-+#define EMPTY_SLOT_INDEX 1
-+#define EMPTY_SLOT ~0ULL
-+
-+#define WORK_DESC_SIZE 32
-+#define BUFPOOL_DESC_SIZE 16
-+
-+#define RING_OWNER_MASK GENMASK(9, 6)
-+#define RING_BUFNUM_MASK GENMASK(5, 0)
-+
-+#define SELTHRSH_POS 3
-+#define SELTHRSH_LEN 3
-+#define RINGADDRL_POS 5
-+#define RINGADDRL_LEN 27
-+#define RINGADDRH_POS 0
-+#define RINGADDRH_LEN 6
-+#define RINGSIZE_POS 23
-+#define RINGSIZE_LEN 3
-+#define RINGTYPE_POS 19
-+#define RINGTYPE_LEN 2
-+#define RINGMODE_POS 20
-+#define RINGMODE_LEN 3
-+#define RECOMTIMEOUTL_POS 28
-+#define RECOMTIMEOUTL_LEN 3
-+#define RECOMTIMEOUTH_POS 0
-+#define RECOMTIMEOUTH_LEN 2
-+#define NUMMSGSINQ_POS 1
-+#define NUMMSGSINQ_LEN 16
-+#define ACCEPTLERR BIT(19)
-+#define QCOHERENT BIT(4)
-+#define RECOMBBUF BIT(27)
-+
-+#define BLOCK_ETH_CSR_OFFSET 0x2000
-+#define BLOCK_ETH_RING_IF_OFFSET 0x9000
-+#define BLOCK_ETH_CLKRST_CSR_OFFSET 0xC000
-+#define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000
-+
-+#define BLOCK_ETH_MAC_OFFSET 0x0000
-+#define BLOCK_ETH_STATS_OFFSET 0x0014
-+#define BLOCK_ETH_MAC_CSR_OFFSET 0x2800
-+
-+#define MAC_ADDR_REG_OFFSET 0x00
-+#define MAC_COMMAND_REG_OFFSET 0x04
-+#define MAC_WRITE_REG_OFFSET 0x08
-+#define MAC_READ_REG_OFFSET 0x0c
-+#define MAC_COMMAND_DONE_REG_OFFSET 0x10
-+
-+#define STAT_ADDR_REG_OFFSET 0x00
-+#define STAT_COMMAND_REG_OFFSET 0x04
-+#define STAT_WRITE_REG_OFFSET 0x08
-+#define STAT_READ_REG_OFFSET 0x0c
-+#define STAT_COMMAND_DONE_REG_OFFSET 0x10
-+
-+#define MII_MGMT_CONFIG_ADDR 0x20
-+#define MII_MGMT_COMMAND_ADDR 0x24
-+#define MII_MGMT_ADDRESS_ADDR 0x28
-+#define MII_MGMT_CONTROL_ADDR 0x2c
-+#define MII_MGMT_STATUS_ADDR 0x30
-+#define MII_MGMT_INDICATORS_ADDR 0x34
-+
-+#define BUSY_MASK BIT(0)
-+#define READ_CYCLE_MASK BIT(0)
-+#define PHY_CONTROL_SET(dst, val) xgene_set_bits(dst, val, 0, 16)
-+
-+#define ENET_SPARE_CFG_REG_ADDR 0x0750
-+#define RSIF_CONFIG_REG_ADDR 0x0010
-+#define RSIF_RAM_DBG_REG0_ADDR 0x0048
-+#define RGMII_REG_0_ADDR 0x07e0
-+#define CFG_LINK_AGGR_RESUME_0_ADDR 0x07c8
-+#define DEBUG_REG_ADDR 0x0700
-+#define CFG_BYPASS_ADDR 0x0294
-+#define CLE_BYPASS_REG0_0_ADDR 0x0490
-+#define CLE_BYPASS_REG1_0_ADDR 0x0494
-+#define CFG_RSIF_FPBUFF_TIMEOUT_EN BIT(31)
-+#define RESUME_TX BIT(0)
-+#define CFG_SPEED_1250 BIT(24)
-+#define TX_PORT0 BIT(0)
-+#define CFG_BYPASS_UNISEC_TX BIT(2)
-+#define CFG_BYPASS_UNISEC_RX BIT(1)
-+#define CFG_CLE_BYPASS_EN0 BIT(31)
-+#define CFG_TXCLK_MUXSEL0_SET(dst, val) xgene_set_bits(dst, val, 29, 3)
-+
-+#define CFG_CLE_IP_PROTOCOL0_SET(dst, val) xgene_set_bits(dst, val, 16, 2)
-+#define CFG_CLE_DSTQID0_SET(dst, val) xgene_set_bits(dst, val, 0, 12)
-+#define CFG_CLE_FPSEL0_SET(dst, val) xgene_set_bits(dst, val, 16, 4)
-+#define CFG_MACMODE_SET(dst, val) xgene_set_bits(dst, val, 18, 2)
-+#define CFG_WAITASYNCRD_SET(dst, val) xgene_set_bits(dst, val, 0, 16)
-+#define ICM_CONFIG0_REG_0_ADDR 0x0400
-+#define ICM_CONFIG2_REG_0_ADDR 0x0410
-+#define RX_DV_GATE_REG_0_ADDR 0x05fc
-+#define TX_DV_GATE_EN0 BIT(2)
-+#define RX_DV_GATE_EN0 BIT(1)
-+#define RESUME_RX0 BIT(0)
-+#define ENET_CFGSSQMIWQASSOC_ADDR 0xe0
-+#define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc
-+#define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0
-+#define ENET_CFGSSQMIQMLITEWQASSOC_ADDR 0xf4
-+#define ENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70
-+#define ENET_BLOCK_MEM_RDY_ADDR 0x74
-+#define MAC_CONFIG_1_ADDR 0x00
-+#define MAC_CONFIG_2_ADDR 0x04
-+#define MAX_FRAME_LEN_ADDR 0x10
-+#define INTERFACE_CONTROL_ADDR 0x38
-+#define STATION_ADDR0_ADDR 0x40
-+#define STATION_ADDR1_ADDR 0x44
-+#define PHY_ADDR_SET(dst, val) xgene_set_bits(dst, val, 8, 5)
-+#define REG_ADDR_SET(dst, val) xgene_set_bits(dst, val, 0, 5)
-+#define ENET_INTERFACE_MODE2_SET(dst, val) xgene_set_bits(dst, val, 8, 2)
-+#define MGMT_CLOCK_SEL_SET(dst, val) xgene_set_bits(dst, val, 0, 3)
-+#define SOFT_RESET1 BIT(31)
-+#define TX_EN BIT(0)
-+#define RX_EN BIT(2)
-+#define ENET_LHD_MODE BIT(25)
-+#define ENET_GHD_MODE BIT(26)
-+#define FULL_DUPLEX2 BIT(0)
-+#define SCAN_AUTO_INCR BIT(5)
-+#define TBYT_ADDR 0x38
-+#define TPKT_ADDR 0x39
-+#define TDRP_ADDR 0x45
-+#define TFCS_ADDR 0x47
-+#define TUND_ADDR 0x4a
-+
-+#define TSO_IPPROTO_TCP 1
-+#define FULL_DUPLEX 2
-+
-+#define USERINFO_POS 0
-+#define USERINFO_LEN 32
-+#define FPQNUM_POS 32
-+#define FPQNUM_LEN 12
-+#define LERR_POS 60
-+#define LERR_LEN 3
-+#define STASH_POS 52
-+#define STASH_LEN 2
-+#define BUFDATALEN_POS 48
-+#define BUFDATALEN_LEN 12
-+#define DATAADDR_POS 0
-+#define DATAADDR_LEN 42
-+#define COHERENT_POS 63
-+#define HENQNUM_POS 48
-+#define HENQNUM_LEN 12
-+#define TYPESEL_POS 44
-+#define TYPESEL_LEN 4
-+#define ETHHDR_POS 12
-+#define IC_POS 35 /* Insert CRC */
-+#define TCPHDR_POS 0
-+#define TCPHDR_LEN 6
-+#define IPHDR_POS 6
-+#define IPHDR_LEN 6
-+#define EC_POS 22 /* Enable checksum */
-+#define IS_POS 24 /* IP protocol select */
-+
-+#define DATAADDR_MASK CREATE_MASK_ULL(DATAADDR_POS, DATAADDR_LEN)
-+#define BUFDATALEN_MASK CREATE_MASK_ULL(BUFDATALEN_POS, BUFDATALEN_LEN)
-+#define USERINFO_MASK CREATE_MASK_ULL(USERINFO_POS, USERINFO_LEN)
-+#define FPQNUM_MASK CREATE_MASK_ULL(FPQNUM_POS, FPQNUM_LEN)
-+#define LERR_MASK CREATE_MASK_ULL(LERR_POS, LERR_LEN)
-+#define STASHING_MASK CREATE_MASK_ULL(STASH_POS, STASH_LEN)
-+#define COHERENT_MASK BIT_ULL(COHERENT_POS)
-+#define HENQNUM_MASK CREATE_MASK_ULL(HENQNUM_POS, HENQNUM_LEN)
-+#define TCPHDR_MASK CREATE_MASK(TCPHDR_POS, TCPHDR_LEN)
-+#define IPHDR_MASK CREATE_MASK(IPHDR_POS, IPHDR_LEN)
-+#define EC_MASK BIT(EC_POS)
-+#define IS_MASK BIT(IS_POS)
-+#define INSERT_CRC BIT_ULL(IC_POS)
-+#define TYPE_ETH_WORK_MESSAGE BIT_ULL(44)
-+
-+struct xgene_enet_raw_desc {
-+ u64 m0;
-+ u64 m1;
-+ u64 m2;
-+ u64 m3;
-+};
-+
-+struct xgene_enet_raw_desc16 {
-+ u64 m0;
-+ u64 m1;
-+};
-+
-+static inline void xgene_enet_cpu_to_le64(void *desc_ptr, int count)
++int device_property_read_u16_array(struct device *dev, const char *propname,
++ u16 *val, size_t nval)
+{
-+ u64 *desc = desc_ptr;
-+ int i;
-+
-+ for (i = 0; i < count; i++)
-+ desc[i] = cpu_to_le64(desc[i]);
++ return DEV_PROP_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val, nval);
+}
++EXPORT_SYMBOL_GPL(device_property_read_u16_array);
+
-+static inline void xgene_enet_le64_to_cpu(void *desc_ptr, int count)
++/**
++ * device_property_read_u32_array - return a u32 array property of a device
++ * @dev: Device to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
++ *
++ * Function reads an array of u32 properties with @propname from the device
++ * firmware description and stores them to @val if found.
++ *
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of numbers,
++ * %-EOVERFLOW if the size of the property is not as expected.
++ */
++int device_property_read_u32_array(struct device *dev, const char *propname,
++ u32 *val, size_t nval)
+{
-+ u64 *desc = desc_ptr;
-+ int i;
-+
-+ for (i = 0; i < count; i++)
-+ desc[i] = le64_to_cpu(desc[i]);
++ return DEV_PROP_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val, nval);
+}
++EXPORT_SYMBOL_GPL(device_property_read_u32_array);
+
-+static inline void xgene_enet_desc16_to_le64(void *desc_ptr)
++/**
++ * device_property_read_u64_array - return a u64 array property of a device
++ * @dev: Device to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
++ *
++ * Function reads an array of u64 properties with @propname from the device
++ * firmware description and stores them to @val if found.
++ *
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of numbers,
++ * %-EOVERFLOW if the size of the property is not as expected.
++ */
++int device_property_read_u64_array(struct device *dev, const char *propname,
++ u64 *val, size_t nval)
+{
-+ u64 *desc;
-+
-+ desc = desc_ptr;
-+ desc[1] = cpu_to_le64(desc[1]);
++ return DEV_PROP_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val, nval);
+}
++EXPORT_SYMBOL_GPL(device_property_read_u64_array);
+
-+static inline void xgene_enet_le64_to_desc16(void *desc_ptr)
++/**
++ * device_property_read_string_array - return a string array property of device
++ * @dev: Device to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
++ *
++ * Function reads an array of string properties with @propname from the device
++ * firmware description and stores them to @val if found.
++ *
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO or %-EILSEQ if the property is not an array of strings,
++ * %-EOVERFLOW if the size of the property is not as expected.
++ */
++int device_property_read_string_array(struct device *dev, const char *propname,
++ const char **val, size_t nval)
+{
-+ u64 *desc;
-+
-+ desc = desc_ptr;
-+ desc[1] = le64_to_cpu(desc[1]);
++ return IS_ENABLED(CONFIG_OF) && dev->of_node ?
++ of_property_read_string_array(dev->of_node, propname, val, nval) :
++ acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
++ DEV_PROP_STRING, val, nval);
+}
++EXPORT_SYMBOL_GPL(device_property_read_string_array);
+
-+enum xgene_enet_ring_cfgsize {
-+ RING_CFGSIZE_512B,
-+ RING_CFGSIZE_2KB,
-+ RING_CFGSIZE_16KB,
-+ RING_CFGSIZE_64KB,
-+ RING_CFGSIZE_512KB,
-+ RING_CFGSIZE_INVALID
-+};
-+
-+enum xgene_enet_ring_type {
-+ RING_DISABLED,
-+ RING_REGULAR,
-+ RING_BUFPOOL
-+};
-+
-+enum xgene_ring_owner {
-+ RING_OWNER_ETH0,
-+ RING_OWNER_CPU = 15,
-+ RING_OWNER_INVALID
-+};
-+
-+enum xgene_enet_ring_bufnum {
-+ RING_BUFNUM_REGULAR = 0x0,
-+ RING_BUFNUM_BUFPOOL = 0x20,
-+ RING_BUFNUM_INVALID
-+};
-+
-+enum xgene_enet_cmd {
-+ XGENE_ENET_WR_CMD = BIT(31),
-+ XGENE_ENET_RD_CMD = BIT(30)
-+};
-+
-+enum xgene_enet_err_code {
-+ HBF_READ_DATA = 3,
-+ HBF_LL_READ = 4,
-+ BAD_WORK_MSG = 6,
-+ BUFPOOL_TIMEOUT = 15,
-+ INGRESS_CRC = 16,
-+ INGRESS_CHECKSUM = 17,
-+ INGRESS_TRUNC_FRAME = 18,
-+ INGRESS_PKT_LEN = 19,
-+ INGRESS_PKT_UNDER = 20,
-+ INGRESS_FIFO_OVERRUN = 21,
-+ INGRESS_CHECKSUM_COMPUTE = 26,
-+ ERR_CODE_INVALID
-+};
++/**
++ * device_property_read_string - return a string property of a device
++ * @dev: Device to get the property of
++ * @propname: Name 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 a string.
++ *
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO or %-EILSEQ if the property type is not a string.
++ */
++int device_property_read_string(struct device *dev, const char *propname,
++ const char **val)
++{
++ return IS_ENABLED(CONFIG_OF) && dev->of_node ?
++ of_property_read_string(dev->of_node, propname, val) :
++ acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
++ DEV_PROP_STRING, val, 1);
++}
++EXPORT_SYMBOL_GPL(device_property_read_string);
++
++#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
++({ \
++ int _ret_; \
++ if (is_of_node(_fwnode_)) \
++ _ret_ = OF_DEV_PROP_READ_ARRAY(of_node(_fwnode_), _propname_, \
++ _type_, _val_, _nval_); \
++ else if (is_acpi_node(_fwnode_)) \
++ _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \
++ _proptype_, _val_, _nval_); \
++ else \
++ _ret_ = -ENXIO; \
++ _ret_; \
++})
+
-+static inline enum xgene_ring_owner xgene_enet_ring_owner(u16 id)
++/**
++ * fwnode_property_read_u8_array - return a u8 array property of firmware node
++ * @fwnode: Firmware node to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
++ *
++ * Read an array of u8 properties with @propname from @fwnode and stores them to
++ * @val if found.
++ *
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of numbers,
++ * %-EOVERFLOW if the size of the property is not as expected,
++ * %-ENXIO if no suitable firmware interface is present.
++ */
++int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
++ const char *propname, u8 *val, size_t nval)
+{
-+ return (id & RING_OWNER_MASK) >> 6;
++ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8,
++ val, nval);
+}
++EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
+
-+static inline u8 xgene_enet_ring_bufnum(u16 id)
++/**
++ * fwnode_property_read_u16_array - return a u16 array property of firmware node
++ * @fwnode: Firmware node to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
++ *
++ * Read an array of u16 properties with @propname from @fwnode and store them to
++ * @val if found.
++ *
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of numbers,
++ * %-EOVERFLOW if the size of the property is not as expected,
++ * %-ENXIO if no suitable firmware interface is present.
++ */
++int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
++ const char *propname, u16 *val, size_t nval)
+{
-+ return id & RING_BUFNUM_MASK;
++ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16,
++ val, nval);
+}
++EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
+
-+static inline bool xgene_enet_is_bufpool(u16 id)
++/**
++ * fwnode_property_read_u32_array - return a u32 array property of firmware node
++ * @fwnode: Firmware node to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
++ *
++ * Read an array of u32 properties with @propname from @fwnode store them to
++ * @val if found.
++ *
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of numbers,
++ * %-EOVERFLOW if the size of the property is not as expected,
++ * %-ENXIO if no suitable firmware interface is present.
++ */
++int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
++ const char *propname, u32 *val, size_t nval)
+{
-+ return ((id & RING_BUFNUM_MASK) >= 0x20) ? true : false;
++ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32,
++ val, nval);
+}
++EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
+
-+static inline u16 xgene_enet_get_numslots(u16 id, u32 size)
++/**
++ * fwnode_property_read_u64_array - return a u64 array property firmware node
++ * @fwnode: Firmware node to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
++ *
++ * Read an array of u64 properties with @propname from @fwnode and store them to
++ * @val if found.
++ *
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of numbers,
++ * %-EOVERFLOW if the size of the property is not as expected,
++ * %-ENXIO if no suitable firmware interface is present.
++ */
++int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
++ const char *propname, u64 *val, size_t nval)
+{
-+ bool is_bufpool = xgene_enet_is_bufpool(id);
-+
-+ return (is_bufpool) ? size / BUFPOOL_DESC_SIZE :
-+ size / WORK_DESC_SIZE;
++ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64,
++ val, nval);
+}
++EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
+
-+struct xgene_enet_desc_ring *xgene_enet_setup_ring(
-+ struct xgene_enet_desc_ring *ring);
-+void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring);
-+
-+void xgene_set_tx_desc(struct xgene_enet_desc_ring *ring,
-+ struct xgene_enet_raw_desc *raw_desc);
-+void xgene_get_desc(struct xgene_enet_desc_ring *ring,
-+ struct xgene_enet_raw_desc *raw_desc);
-+void xgene_get_bufpool_desc(struct xgene_enet_desc_ring *ring,
-+ struct xgene_enet_raw_desc16 *raw_desc);
-+void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
-+ struct xgene_enet_pdata *pdata,
-+ enum xgene_enet_err_code status);
-+
-+void xgene_enet_reset(struct xgene_enet_pdata *priv);
-+void xgene_gmac_reset(struct xgene_enet_pdata *priv);
-+void xgene_gmac_init(struct xgene_enet_pdata *priv, int speed);
-+void xgene_gmac_tx_enable(struct xgene_enet_pdata *priv);
-+void xgene_gmac_rx_enable(struct xgene_enet_pdata *priv);
-+void xgene_gmac_tx_disable(struct xgene_enet_pdata *priv);
-+void xgene_gmac_rx_disable(struct xgene_enet_pdata *priv);
-+void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata);
-+void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
-+ u32 dst_ring_num, u16 bufpool_id);
-+void xgene_gport_shutdown(struct xgene_enet_pdata *priv);
-+void xgene_gmac_get_tx_stats(struct xgene_enet_pdata *pdata);
-+
-+int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata);
-+int xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata);
-+
-+#endif /* __XGENE_ENET_HW_H__ */
-diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
-new file mode 100644
-index 0000000..756523a
---- /dev/null
-+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
-@@ -0,0 +1,962 @@
-+/* Applied Micro X-Gene SoC Ethernet Driver
++/**
++ * fwnode_property_read_string_array - return string array property of a node
++ * @fwnode: Firmware node to get the property of
++ * @propname: Name of the property
++ * @val: The values are stored here
++ * @nval: Size of the @val array
+ *
-+ * Copyright (c) 2014, Applied Micro Circuits Corporation
-+ * Authors: Iyappan Subramanian <isubramanian@apm.com>
-+ * Ravi Patel <rapatel@apm.com>
-+ * Keyur Chudgar <kchudgar@apm.com>
++ * Read an string list property @propname from the given firmware node and store
++ * them to @val if found.
+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO if the property is not an array of strings,
++ * %-EOVERFLOW if the size of the property is not as expected,
++ * %-ENXIO if no suitable firmware interface is present.
++ */
++int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
++ const char *propname, const char **val,
++ size_t nval)
++{
++ if (is_of_node(fwnode))
++ return of_property_read_string_array(of_node(fwnode), propname,
++ val, nval);
++ else if (is_acpi_node(fwnode))
++ return acpi_dev_prop_read(acpi_node(fwnode), propname,
++ DEV_PROP_STRING, val, nval);
++
++ return -ENXIO;
++}
++EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
++
++/**
++ * fwnode_property_read_string - return a string property of a firmware node
++ * @fwnode: Firmware node to get the property of
++ * @propname: Name of the property
++ * @val: The value is stored here
+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
++ * Read property @propname from the given firmware node and store the value into
++ * @val if found. The value is checked to be a string.
+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ * Return: %0 if the property was found (success),
++ * %-EINVAL if given arguments are not valid,
++ * %-ENODATA if the property does not have a value,
++ * %-EPROTO or %-EILSEQ if the property is not a string,
++ * %-ENXIO if no suitable firmware interface is present.
+ */
++int fwnode_property_read_string(struct fwnode_handle *fwnode,
++ const char *propname, const char **val)
++{
++ if (is_of_node(fwnode))
++ return of_property_read_string(of_node(fwnode),propname, val);
++ else if (is_acpi_node(fwnode))
++ return acpi_dev_prop_read(acpi_node(fwnode), propname,
++ DEV_PROP_STRING, val, 1);
+
-+#include "xgene_enet_main.h"
-+#include "xgene_enet_hw.h"
++ return -ENXIO;
++}
++EXPORT_SYMBOL_GPL(fwnode_property_read_string);
+
-+static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool)
++/**
++ * device_get_next_child_node - Return the next child node handle for a device
++ * @dev: Device to find the next child node for.
++ * @child: Handle to one of the device's child nodes or a null handle.
++ */
++struct fwnode_handle *device_get_next_child_node(struct device *dev,
++ struct fwnode_handle *child)
+{
-+ struct xgene_enet_raw_desc16 *raw_desc;
-+ int i;
++ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
++ struct device_node *node;
+
-+ for (i = 0; i < buf_pool->slots; i++) {
-+ raw_desc = &buf_pool->raw_desc16[i];
++ node = of_get_next_available_child(dev->of_node, of_node(child));
++ if (node)
++ return &node->fwnode;
++ } else if (IS_ENABLED(CONFIG_ACPI)) {
++ struct acpi_device *node;
+
-+ /* Hardware expects descriptor in little endian format */
-+ raw_desc->m0 = cpu_to_le64(i |
-+ (((u64)buf_pool->dst_ring_num << FPQNUM_POS) &
-+ FPQNUM_MASK) | STASHING_MASK);
++ node = acpi_get_next_child(dev, acpi_node(child));
++ if (node)
++ return acpi_fwnode_handle(node);
+ }
++ return NULL;
+}
++EXPORT_SYMBOL_GPL(device_get_next_child_node);
+
-+static struct device *ndev_to_dev(struct net_device *ndev)
++/**
++ * fwnode_handle_put - Drop reference to a device node
++ * @fwnode: Pointer to the device node to drop the reference to.
++ *
++ * This has to be used when terminating device_for_each_child_node() iteration
++ * with break or return to prevent stale device node references from being left
++ * behind.
++ */
++void fwnode_handle_put(struct fwnode_handle *fwnode)
+{
-+ return ndev->dev.parent;
++ if (is_of_node(fwnode))
++ of_node_put(of_node(fwnode));
+}
++EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
-+static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool,
-+ u32 nbuf)
++/**
++ * 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)
+{
-+ struct sk_buff *skb;
-+ struct xgene_enet_raw_desc16 *raw_desc;
-+ struct net_device *ndev;
-+ struct device *dev;
-+ dma_addr_t dma_addr;
-+ u32 tail = buf_pool->tail;
-+ u32 slots = buf_pool->slots - 1;
-+ u16 bufdatalen, len;
-+ int i;
-+
-+ ndev = buf_pool->ndev;
-+ dev = ndev_to_dev(buf_pool->ndev);
-+ bufdatalen = BUF_LEN_CODE_2K | (SKB_BUFFER_SIZE & GENMASK(11, 0));
-+ len = XGENE_ENET_MAX_MTU;
++ struct fwnode_handle *child;
++ unsigned int count = 0;
+
-+ for (i = 0; i < nbuf; i++) {
-+ raw_desc = &buf_pool->raw_desc16[tail];
++ device_for_each_child_node(dev, child)
++ count++;
+
-+ skb = netdev_alloc_skb_ip_align(ndev, len);
-+ if (unlikely(!skb))
-+ return -ENOMEM;
-+ buf_pool->rx_skb[tail] = skb;
++ 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 43005d4..c9411e6 100644
+--- a/drivers/clocksource/arm_arch_timer.c
++++ b/drivers/clocksource/arm_arch_timer.c
+@@ -21,6 +21,7 @@
+ #include <linux/io.h>
+ #include <linux/slab.h>
+ #include <linux/sched_clock.h>
++#include <linux/acpi.h>
+
+ #include <asm/arch_timer.h>
+ #include <asm/virt.h>
+@@ -61,7 +62,8 @@ enum ppi_nr {
+ MAX_TIMER_PPI
+ };
+
+-static int arch_timer_ppi[MAX_TIMER_PPI];
++int arch_timer_ppi[MAX_TIMER_PPI];
++EXPORT_SYMBOL(arch_timer_ppi);
+
+ static struct clock_event_device __percpu *arch_timer_evt;
+
+@@ -370,8 +372,12 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
+ if (arch_timer_rate)
+ return;
+
+- /* Try to determine the frequency from the device tree or CNTFRQ */
+- if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
++ /*
++ * Try to determine the frequency from the device tree or CNTFRQ,
++ * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
++ */
++ if (!acpi_disabled ||
++ of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
+ if (cntbase)
+ arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
+ else
+@@ -687,20 +693,8 @@ static void __init arch_timer_common_init(void)
+ arch_timer_arch_init();
+ }
+
+-static void __init arch_timer_init(struct device_node *np)
++static void __init arch_timer_init(void)
+ {
+- 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);
+-
+ /*
+ * If HYP mode is available, we know that the physical timer
+ * has been configured to be accessible from PL1. Use it, so
+@@ -719,13 +713,31 @@ static void __init arch_timer_init(struct device_node *np)
+ }
+ }
+
+- 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);
+
-+ dma_addr = dma_map_single(dev, skb->data, len, DMA_FROM_DEVICE);
-+ if (dma_mapping_error(dev, dma_addr)) {
-+ netdev_err(ndev, "DMA mapping error\n");
-+ dev_kfree_skb_any(skb);
-+ return -EINVAL;
-+ }
++static void __init arch_timer_of_init(struct device_node *np)
++{
++ int i;
+
-+ raw_desc->m1 = cpu_to_le64((dma_addr & DATAADDR_MASK) |
-+ (((u64)bufdatalen << BUFDATALEN_POS) &
-+ BUFDATALEN_MASK) | COHERENT_MASK);
-+ tail = (tail + 1) & slots;
++ if (arch_timers_present & ARCH_CP15_TIMER) {
++ pr_warn("arch_timer: multiple nodes in dt, skipping\n");
++ return;
+ }
+
-+ iowrite32(nbuf, buf_pool->cmd);
-+ buf_pool->tail = tail;
++ 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);
+
-+ return 0;
-+}
++ arch_timer_detect_rate(NULL, np);
+
-+static u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring)
-+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
++ arch_timer_c3stop = !of_property_read_bool(np, "always-on");
+
-+ return ((u16)pdata->rm << 10) | ring->num;
++ 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)
+ {
+@@ -792,3 +804,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);
+
-+static u8 xgene_enet_hdr_len(const void *data)
++#ifdef CONFIG_ACPI
++static int __init
++map_generic_timer_interrupt(u32 interrupt, u32 flags)
+{
-+ const struct ethhdr *eth = data;
++ int trigger, polarity;
+
-+ return (eth->h_proto == htons(ETH_P_8021Q)) ? VLAN_ETH_HLEN : ETH_HLEN;
-+}
++ if (!interrupt)
++ return 0;
+
-+static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
-+{
-+ u32 *cmd_base = ring->cmd_base;
-+ u32 ring_state, num_msgs;
++ trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
++ : ACPI_LEVEL_SENSITIVE;
+
-+ ring_state = ioread32(&cmd_base[1]);
-+ num_msgs = ring_state & CREATE_MASK(NUMMSGSINQ_POS, NUMMSGSINQ_LEN);
++ polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
++ : ACPI_ACTIVE_HIGH;
+
-+ return num_msgs >> NUMMSGSINQ_POS;
++ return acpi_register_gsi(NULL, interrupt, trigger, polarity);
+}
+
-+static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool)
++/* Initialize per-processor generic timer */
++static int __init arch_timer_acpi_init(struct acpi_table_header *table)
+{
-+ struct xgene_enet_raw_desc16 *raw_desc;
-+ u32 slots = buf_pool->slots - 1;
-+ u32 tail = buf_pool->tail;
-+ u32 userinfo;
-+ int i, len;
++ struct acpi_table_gtdt *gtdt;
+
-+ len = xgene_enet_ring_len(buf_pool);
-+ for (i = 0; i < len; i++) {
-+ tail = (tail - 1) & slots;
-+ raw_desc = &buf_pool->raw_desc16[tail];
-+
-+ /* Hardware stores descriptor in little endian format */
-+ userinfo = le64_to_cpu(raw_desc->m0) & USERINFO_MASK;
-+ dev_kfree_skb_any(buf_pool->rx_skb[userinfo]);
++ if (arch_timers_present & ARCH_CP15_TIMER) {
++ pr_warn("arch_timer: already initialized, skipping\n");
++ return -EINVAL;
+ }
+
-+ iowrite32(-len, buf_pool->cmd);
-+ buf_pool->tail = tail;
-+}
-+
-+static irqreturn_t xgene_enet_rx_irq(const int irq, void *data)
-+{
-+ struct xgene_enet_desc_ring *rx_ring = data;
++ gtdt = container_of(table, struct acpi_table_gtdt, header);
+
-+ if (napi_schedule_prep(&rx_ring->napi)) {
-+ disable_irq_nosync(irq);
-+ __napi_schedule(&rx_ring->napi);
-+ }
++ arch_timers_present |= ARCH_CP15_TIMER;
+
-+ return IRQ_HANDLED;
-+}
++ arch_timer_ppi[PHYS_SECURE_PPI] =
++ map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
++ gtdt->secure_el1_flags);
+
-+static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
-+ struct xgene_enet_raw_desc *raw_desc)
-+{
-+ struct sk_buff *skb;
-+ struct device *dev;
-+ u16 skb_index;
-+ u8 status;
-+ int ret = 0;
++ arch_timer_ppi[PHYS_NONSECURE_PPI] =
++ map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
++ gtdt->non_secure_el1_flags);
+
-+ skb_index = raw_desc->m0 & USERINFO_MASK;
-+ skb = cp_ring->cp_skb[skb_index];
++ arch_timer_ppi[VIRT_PPI] =
++ map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
++ gtdt->virtual_timer_flags);
+
-+ dev = ndev_to_dev(cp_ring->ndev);
-+ dma_unmap_single(dev, raw_desc->m1 & DATAADDR_MASK,
-+ (raw_desc->m1 & BUFDATALEN_MASK) >> BUFDATALEN_POS,
-+ DMA_TO_DEVICE);
++ arch_timer_ppi[HYP_PPI] =
++ map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
++ gtdt->non_secure_el2_flags);
+
-+ /* Checking for error */
-+ status = (raw_desc->m0 & LERR_MASK) >> LERR_POS;
-+ if (unlikely(status > 2)) {
-+ xgene_enet_parse_error(cp_ring, netdev_priv(cp_ring->ndev),
-+ status);
-+ ret = -1;
-+ }
++ /* Get the frequency from CNTFRQ */
++ arch_timer_detect_rate(NULL, NULL);
+
-+ if (likely(skb)) {
-+ dev_kfree_skb_any(skb);
-+ } else {
-+ netdev_err(cp_ring->ndev, "completion skb is NULL\n");
-+ ret = -1;
-+ }
++ /* Always-on capability */
++ arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
+
-+ return ret;
++ arch_timer_init();
++ return 0;
+}
+
-+static u64 xgene_enet_work_msg(struct sk_buff *skb)
++/* Initialize all the generic timers presented in GTDT */
++void __init acpi_generic_timer_init(void)
+{
-+ struct iphdr *iph;
-+ u8 l3hlen, l4hlen = 0;
-+ u8 csum_enable = 0;
-+ u8 proto = 0;
-+ u8 ethhdr;
-+ u64 hopinfo;
-+
-+ if (unlikely(skb->protocol != htons(ETH_P_IP)) &&
-+ unlikely(skb->protocol != htons(ETH_P_8021Q)))
-+ goto out;
-+
-+ if (unlikely(!(skb->dev->features & NETIF_F_IP_CSUM)))
-+ goto out;
-+
-+ iph = ip_hdr(skb);
-+ if (unlikely(ip_is_fragment(iph)))
-+ goto out;
-+
-+ if (likely(iph->protocol == IPPROTO_TCP)) {
-+ l4hlen = tcp_hdrlen(skb) >> 2;
-+ csum_enable = 1;
-+ proto = TSO_IPPROTO_TCP;
-+ } else if (iph->protocol == IPPROTO_UDP) {
-+ l4hlen = UDP_HDR_SIZE;
-+ csum_enable = 1;
-+ }
-+out:
-+ l3hlen = ip_hdrlen(skb) >> 2;
-+ ethhdr = xgene_enet_hdr_len(skb->data);
-+ hopinfo = (l4hlen & TCPHDR_MASK) |
-+ ((l3hlen << IPHDR_POS) & IPHDR_MASK) |
-+ (ethhdr << ETHHDR_POS) |
-+ (csum_enable << EC_POS) |
-+ (proto << IS_POS) |
-+ INSERT_CRC |
-+ TYPE_ETH_WORK_MESSAGE;
-+
-+ return hopinfo;
-+}
-+
-+static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring,
-+ struct sk_buff *skb)
-+{
-+ struct device *dev = ndev_to_dev(tx_ring->ndev);
-+ struct xgene_enet_raw_desc *raw_desc;
-+ dma_addr_t dma_addr;
-+ u16 tail = tx_ring->tail;
-+ u64 hopinfo;
-+
-+ raw_desc = &tx_ring->raw_desc[tail];
-+ memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc));
-+
-+ dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
-+ if (dma_mapping_error(dev, dma_addr)) {
-+ netdev_err(tx_ring->ndev, "DMA mapping error\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Hardware expects descriptor in little endian format */
-+ raw_desc->m0 = cpu_to_le64(tail);
-+ raw_desc->m1 = cpu_to_le64((dma_addr & DATAADDR_MASK) |
-+ (((u64)skb->len << BUFDATALEN_POS) & BUFDATALEN_MASK) |
-+ COHERENT_MASK);
-+ hopinfo = xgene_enet_work_msg(skb);
-+ raw_desc->m3 = cpu_to_le64(
-+ (((u64)tx_ring->dst_ring_num << HENQNUM_POS) &
-+ HENQNUM_MASK) | hopinfo);
-+ tx_ring->cp_ring->cp_skb[tail] = skb;
++ if (acpi_disabled)
++ return;
+
-+ return 0;
++ acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init);
+}
++#endif
+diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
+index 17afc51..c5f7b4e 100644
+--- a/drivers/firmware/dmi_scan.c
++++ b/drivers/firmware/dmi_scan.c
+@@ -93,6 +93,12 @@ static void dmi_table(u8 *buf, int len, int num,
+ const struct dmi_header *dm = (const struct dmi_header *)data;
+
+ /*
++ * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
++ */
++ if (dm->type == DMI_ENTRY_END_OF_TABLE)
++ break;
+
-+static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
-+ struct net_device *ndev)
++ /*
+ * We want to know the total length (formatted area and
+ * strings) before decoding to make sure we won't run off the
+ * table in dmi_decode or dmi_string
+@@ -107,7 +113,7 @@ static void dmi_table(u8 *buf, int len, int num,
+ }
+ }
+
+-static u32 dmi_base;
++static phys_addr_t dmi_base;
+ static u16 dmi_len;
+ static u16 dmi_num;
+
+@@ -467,7 +473,7 @@ static int __init dmi_present(const u8 *buf)
+
+ if (memcmp(buf, "_SM_", 4) == 0 &&
+ buf[5] < 32 && dmi_checksum(buf, buf[5])) {
+- smbios_ver = (buf[6] << 8) + buf[7];
++ smbios_ver = get_unaligned_be16(buf + 6);
+
+ /* Some BIOS report weird SMBIOS version, fix that up */
+ switch (smbios_ver) {
+@@ -489,10 +495,9 @@ static int __init dmi_present(const u8 *buf)
+ buf += 16;
+
+ if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) {
+- dmi_num = (buf[13] << 8) | buf[12];
+- dmi_len = (buf[7] << 8) | buf[6];
+- dmi_base = (buf[11] << 24) | (buf[10] << 16) |
+- (buf[9] << 8) | buf[8];
++ dmi_num = get_unaligned_le16(buf + 12);
++ dmi_len = get_unaligned_le16(buf + 6);
++ dmi_base = get_unaligned_le32(buf + 8);
+
+ if (dmi_walk_early(dmi_decode) == 0) {
+ if (smbios_ver) {
+@@ -514,12 +519,72 @@ static int __init dmi_present(const u8 *buf)
+ return 1;
+ }
+
++/*
++ * Check for the SMBIOS 3.0 64-bit entry point signature. Unlike the legacy
++ * 32-bit entry point, there is no embedded DMI header (_DMI_) in here.
++ */
++static int __init dmi_smbios3_present(const u8 *buf)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring;
-+ struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring;
-+ u32 tx_level, cq_level;
++ if (memcmp(buf, "_SM3_", 5) == 0 &&
++ buf[6] < 32 && dmi_checksum(buf, buf[6])) {
++ dmi_ver = get_unaligned_be16(buf + 7);
++ dmi_len = get_unaligned_le32(buf + 12);
++ dmi_base = get_unaligned_le64(buf + 16);
+
-+ tx_level = xgene_enet_ring_len(tx_ring);
-+ cq_level = xgene_enet_ring_len(cp_ring);
-+ if (unlikely(tx_level > pdata->tx_qcnt_hi ||
-+ cq_level > pdata->cp_qcnt_hi)) {
-+ netif_stop_queue(ndev);
-+ return NETDEV_TX_BUSY;
-+ }
++ /*
++ * The 64-bit SMBIOS 3.0 entry point no longer has a field
++ * containing the number of structures present in the table.
++ * Instead, it defines the table size as a maximum size, and
++ * relies on the end-of-table structure type (#127) to be used
++ * to signal the end of the table.
++ * So let's define dmi_num as an upper bound as well: each
++ * structure has a 4 byte header, so dmi_len / 4 is an upper
++ * bound for the number of structures in the table.
++ */
++ dmi_num = dmi_len / 4;
+
-+ if (xgene_enet_setup_tx_desc(tx_ring, skb)) {
-+ dev_kfree_skb_any(skb);
-+ return NETDEV_TX_OK;
++ if (dmi_walk_early(dmi_decode) == 0) {
++ pr_info("SMBIOS %d.%d present.\n",
++ dmi_ver >> 8, dmi_ver & 0xFF);
++ dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
++ pr_debug("DMI: %s\n", dmi_ids_string);
++ return 0;
++ }
+ }
-+
-+ iowrite32(1, tx_ring->cmd);
-+ skb_tx_timestamp(skb);
-+ tx_ring->tail = (tx_ring->tail + 1) & (tx_ring->slots - 1);
-+
-+ pdata->stats.tx_packets++;
-+ pdata->stats.tx_bytes += skb->len;
-+
-+ return NETDEV_TX_OK;
++ return 1;
+}
+
-+static void xgene_enet_skip_csum(struct sk_buff *skb)
-+{
-+ struct iphdr *iph = ip_hdr(skb);
+ void __init dmi_scan_machine(void)
+ {
+ char __iomem *p, *q;
+ char buf[32];
+
+ if (efi_enabled(EFI_CONFIG_TABLES)) {
++ /*
++ * According to the DMTF SMBIOS reference spec v3.0.0, it is
++ * allowed to define both the 64-bit entry point (smbios3) and
++ * the 32-bit entry point (smbios), in which case they should
++ * either both point to the same SMBIOS structure table, or the
++ * table pointed to by the 64-bit entry point should contain a
++ * superset of the table contents pointed to by the 32-bit entry
++ * point (section 5.2)
++ * This implies that the 64-bit entry point should have
++ * precedence if it is defined and supported by the OS. If we
++ * have the 64-bit entry point, but fail to decode it, fall
++ * back to the legacy one (if available)
++ */
++ if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) {
++ p = dmi_early_remap(efi.smbios3, 32);
++ if (p == NULL)
++ goto error;
++ memcpy_fromio(buf, p, 32);
++ dmi_early_unmap(p, 32);
++
++ if (!dmi_smbios3_present(buf)) {
++ dmi_available = 1;
++ goto out;
++ }
++ }
+ if (efi.smbios == EFI_INVALID_TABLE_ADDR)
+ goto error;
+
+@@ -552,7 +617,7 @@ void __init dmi_scan_machine(void)
+ memset(buf, 0, 16);
+ for (q = p; q < p + 0x10000; q += 16) {
+ memcpy_fromio(buf + 16, q, 16);
+- if (!dmi_present(buf)) {
++ if (!dmi_smbios3_present(buf) || !dmi_present(buf)) {
+ dmi_available = 1;
+ dmi_early_unmap(p, 0x10000);
+ goto out;
+diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
+index 8590099..9035c1b 100644
+--- a/drivers/firmware/efi/efi.c
++++ b/drivers/firmware/efi/efi.c
+@@ -30,6 +30,7 @@ struct efi __read_mostly efi = {
+ .acpi = EFI_INVALID_TABLE_ADDR,
+ .acpi20 = EFI_INVALID_TABLE_ADDR,
+ .smbios = EFI_INVALID_TABLE_ADDR,
++ .smbios3 = EFI_INVALID_TABLE_ADDR,
+ .sal_systab = EFI_INVALID_TABLE_ADDR,
+ .boot_info = EFI_INVALID_TABLE_ADDR,
+ .hcdp = EFI_INVALID_TABLE_ADDR,
+@@ -86,6 +87,8 @@ static ssize_t systab_show(struct kobject *kobj,
+ str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
+ if (efi.smbios != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
++ if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
++ str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
+ if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
+ if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
+@@ -260,6 +263,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
+ {MPS_TABLE_GUID, "MPS", &efi.mps},
+ {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
+ {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
++ {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
+ {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
+ {NULL_GUID, NULL, NULL},
+ };
+diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
+index 75ee059..eb48a1a 100644
+--- a/drivers/firmware/efi/libstub/arm-stub.c
++++ b/drivers/firmware/efi/libstub/arm-stub.c
+@@ -247,9 +247,18 @@ unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table,
+ goto fail_free_cmdline;
+ }
+ }
+- if (!fdt_addr)
+
-+ if (!ip_is_fragment(iph) ||
-+ (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) {
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ if (fdt_addr) {
++ pr_efi(sys_table, "Using DTB from command line\n");
++ } else {
+ /* Look for a device tree configuration table entry. */
+ fdt_addr = (uintptr_t)get_fdt(sys_table);
++ if (fdt_addr)
++ pr_efi(sys_table, "Using DTB from configuration table\n");
+ }
-+}
+
-+static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
-+ struct xgene_enet_raw_desc *raw_desc)
++ if (!fdt_addr)
++ pr_efi(sys_table, "Generating empty DTB\n");
+
+ status = handle_cmdline_files(sys_table, image, cmdline_ptr,
+ "initrd=", dram_base + SZ_512M,
+diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
+index 954b9f6..13dbd3d 100644
+--- a/drivers/gpio/devres.c
++++ b/drivers/gpio/devres.c
+@@ -109,6 +109,38 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
+ EXPORT_SYMBOL(__devm_gpiod_get_index);
+
+ /**
++ * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node
++ * @dev: GPIO consumer
++ * @child: firmware node (child of @dev)
++ *
++ * GPIO descriptors returned from this function are automatically disposed on
++ * driver detach.
++ */
++struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
++ struct fwnode_handle *child)
+{
-+ struct net_device *ndev;
-+ struct xgene_enet_pdata *pdata;
-+ struct device *dev;
-+ struct xgene_enet_desc_ring *buf_pool;
-+ u32 datalen, skb_index;
-+ struct sk_buff *skb;
-+ u8 status;
-+ int ret = 0;
++ struct gpio_desc **dr;
++ struct gpio_desc *desc;
+
-+ ndev = rx_ring->ndev;
-+ pdata = netdev_priv(ndev);
-+ dev = ndev_to_dev(rx_ring->ndev);
-+ buf_pool = rx_ring->buf_pool;
-+
-+ dma_unmap_single(dev, raw_desc->m1 & DATAADDR_MASK, XGENE_ENET_MAX_MTU,
-+ DMA_FROM_DEVICE);
-+ skb_index = raw_desc->m0 & USERINFO_MASK;
-+ skb = buf_pool->rx_skb[skb_index];
-+
-+ /* checking for error */
-+ status = (raw_desc->m0 & LERR_MASK) >> LERR_POS;
-+ if (unlikely(status > 2)) {
-+ dev_kfree_skb_any(skb);
-+ xgene_enet_parse_error(rx_ring, netdev_priv(rx_ring->ndev),
-+ status);
-+ pdata->stats.rx_dropped++;
-+ ret = -1;
-+ goto out;
++ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
++ GFP_KERNEL);
++ if (!dr)
++ return ERR_PTR(-ENOMEM);
++
++ desc = fwnode_get_named_gpiod(child, "gpios");
++ if (IS_ERR(desc)) {
++ devres_free(dr);
++ return desc;
+ }
+
-+ /* strip off CRC as HW isn't doing this */
-+ datalen = (raw_desc->m1 & BUFDATALEN_MASK) >> BUFDATALEN_POS;
-+ datalen -= 4;
-+ prefetch(skb->data - NET_IP_ALIGN);
-+ skb_put(skb, datalen);
++ *dr = desc;
++ devres_add(dev, dr);
+
-+ skb_checksum_none_assert(skb);
-+ skb->protocol = eth_type_trans(skb, ndev);
-+ if (likely((ndev->features & NETIF_F_IP_CSUM) &&
-+ skb->protocol == htons(ETH_P_IP))) {
-+ xgene_enet_skip_csum(skb);
-+ }
++ return desc;
++}
++EXPORT_SYMBOL(devm_get_gpiod_from_child);
+
-+ pdata->stats.rx_packets++;
-+ pdata->stats.rx_bytes += datalen;
-+ napi_gro_receive(&rx_ring->napi, skb);
-+out:
-+ if (--rx_ring->nbufpool == 0) {
-+ ret = xgene_enet_refill_bufpool(buf_pool, NUM_BUFPOOL);
-+ rx_ring->nbufpool = NUM_BUFPOOL;
++/**
+ * 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 <linux/gpio.h>
+
+-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);
+
-+ return ret;
-+}
++ 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;
+
-+static bool is_rx_desc(struct xgene_enet_raw_desc *raw_desc)
+ /*
+ * 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 05c6275..ba98bb5 100644
+--- a/drivers/gpio/gpiolib-acpi.c
++++ b/drivers/gpio/gpiolib-acpi.c
+@@ -287,9 +287,45 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
+ }
+ }
+
++int acpi_dev_add_driver_gpios(struct acpi_device *adev,
++ const struct acpi_gpio_mapping *gpios)
+{
-+ /* Hardware stores descriptor in little endian format */
-+ raw_desc->m0 = le64_to_cpu(raw_desc->m0);
-+ raw_desc->m1 = le64_to_cpu(raw_desc->m1);
-+ return ((raw_desc->m0 & FPQNUM_MASK) >> FPQNUM_POS) ? true : false;
++ if (adev && gpios) {
++ adev->driver_gpios = gpios;
++ return 0;
++ }
++ return -EINVAL;
+}
++EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
+
-+static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
-+ int budget)
++static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
++ const char *name, int index,
++ struct acpi_reference_args *args)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
-+ struct xgene_enet_raw_desc *raw_desc;
-+ u16 head = ring->head;
-+ u16 slots = ring->slots - 1;
-+ int ret, count = 0;
++ const struct acpi_gpio_mapping *gm;
+
-+ do {
-+ raw_desc = &ring->raw_desc[head];
-+ if (unlikely(((u64 *)raw_desc)[EMPTY_SLOT_INDEX] == EMPTY_SLOT))
-+ break;
++ if (!adev->driver_gpios)
++ return false;
+
-+ if (is_rx_desc(raw_desc))
-+ ret = xgene_enet_rx_frame(ring, raw_desc);
-+ else
-+ ret = xgene_enet_tx_completion(ring, raw_desc);
-+ ((u64 *)raw_desc)[EMPTY_SLOT_INDEX] = EMPTY_SLOT;
++ for (gm = adev->driver_gpios; gm->name; gm++)
++ if (!strcmp(name, gm->name) && gm->data && index < gm->size) {
++ const struct acpi_gpio_params *par = gm->data + index;
+
-+ head = (head + 1) & slots;
-+ count++;
++ args->adev = adev;
++ args->args[0] = par->crs_entry_index;
++ args->args[1] = par->line_index;
++ args->args[2] = par->active_low;
++ args->nargs = 3;
++ return true;
++ }
+
-+ if (ret)
-+ break;
-+ } while (--budget);
++ return false;
++}
+
-+ if (likely(count)) {
-+ iowrite32(-count, ring->cmd);
-+ ring->head = head;
+ struct acpi_gpio_lookup {
+ struct acpi_gpio_info info;
+ int index;
++ int pin_index;
+ struct gpio_desc *desc;
+ int n;
+ };
+@@ -303,13 +339,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 (netif_queue_stopped(ring->ndev)) {
-+ if (xgene_enet_ring_len(ring) < pdata->cp_qcnt_low)
-+ netif_wake_queue(ring->ndev);
-+ }
-+ }
++ 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;
+
-+ return budget;
-+}
++ /*
++ * 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;
+@@ -317,40 +364,79 @@ 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);
+-
+- 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;
++
++ dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
++
++ memset(&args, 0, sizeof(args));
++ ret = acpi_dev_get_property_reference(adev, propname,
++ index, &args);
++ if (ret) {
++ bool found = acpi_get_driver_gpio_data(adev, propname,
++ index, &args);
++ if (!found)
++ return ERR_PTR(ret);
++ }
+
-+static int xgene_enet_napi(struct napi_struct *napi, const int budget)
-+{
-+ struct xgene_enet_desc_ring *ring;
-+ int processed;
++ /*
++ * 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];
++ }
+
-+ ring = container_of(napi, struct xgene_enet_desc_ring, napi);
-+ processed = xgene_enet_process_ring(ring, budget);
++ 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);
++ }
+
-+ if (processed != budget) {
-+ napi_complete(napi);
-+ enable_irq(ring->irq);
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
+ &lookup);
+@@ -359,8 +445,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+
+ 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);
+ }
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index e8e98ca..58659db 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -1505,14 +1505,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]);
++ }
+
-+ return processed;
-+}
++ desc = acpi_get_gpiod_by_index(adev, propname, idx, &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;
++ }
+
-+static void xgene_enet_timeout(struct net_device *ndev)
++ if (info.active_low)
+ *flags |= GPIO_ACTIVE_LOW;
+
+ return desc;
+@@ -1713,6 +1735,61 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
+ EXPORT_SYMBOL_GPL(__gpiod_get_index);
+
+ /**
++ * fwnode_get_named_gpiod - obtain a GPIO from firmware node
++ * @fwnode: handle of the firmware node
++ * @propname: name of the firmware property representing the GPIO
++ *
++ * This function can be used for drivers that get their configuration
++ * from firmware.
++ *
++ * 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 *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
++ const char *propname)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
++ struct gpio_desc *desc = ERR_PTR(-ENODEV);
++ bool active_low = false;
++ int ret;
+
-+ xgene_gmac_reset(pdata);
-+}
++ if (!fwnode)
++ return ERR_PTR(-EINVAL);
+
-+static int xgene_enet_register_irq(struct net_device *ndev)
-+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct device *dev = ndev_to_dev(ndev);
-+ int ret;
++ if (is_of_node(fwnode)) {
++ enum of_gpio_flags flags;
+
-+ ret = devm_request_irq(dev, pdata->rx_ring->irq, xgene_enet_rx_irq,
-+ IRQF_SHARED, ndev->name, pdata->rx_ring);
-+ if (ret) {
-+ netdev_err(ndev, "rx%d interrupt request failed\n",
-+ pdata->rx_ring->irq);
++ desc = of_get_named_gpiod_flags(of_node(fwnode), propname, 0,
++ &flags);
++ if (!IS_ERR(desc))
++ active_low = flags & OF_GPIO_ACTIVE_LOW;
++ } else if (is_acpi_node(fwnode)) {
++ struct acpi_gpio_info info;
++
++ desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname, 0,
++ &info);
++ if (!IS_ERR(desc))
++ active_low = info.active_low;
+ }
+
-+ return ret;
-+}
++ if (IS_ERR(desc))
++ return desc;
+
-+static void xgene_enet_free_irq(struct net_device *ndev)
-+{
-+ struct xgene_enet_pdata *pdata;
-+ struct device *dev;
++ ret = gpiod_request(desc, NULL);
++ if (ret)
++ return ERR_PTR(ret);
+
-+ pdata = netdev_priv(ndev);
-+ dev = ndev_to_dev(ndev);
-+ devm_free_irq(dev, pdata->rx_ring->irq, pdata->rx_ring);
-+}
++ /* Only value flag can be set from both DT and ACPI is active_low */
++ if (active_low)
++ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
-+static int xgene_enet_open(struct net_device *ndev)
-+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ int ret;
++ return desc;
++}
++EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
+
-+ xgene_gmac_tx_enable(pdata);
-+ xgene_gmac_rx_enable(pdata);
++/**
+ * 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..c9c1c8c 100644
+--- a/drivers/input/keyboard/gpio_keys_polled.c
++++ b/drivers/input/keyboard/gpio_keys_polled.c
+@@ -23,10 +23,9 @@
+ #include <linux/ioport.h>
+ #include <linux/platform_device.h>
+ #include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
+ #include <linux/gpio_keys.h>
+-#include <linux/of.h>
+-#include <linux/of_platform.h>
+-#include <linux/of_gpio.h>
++#include <linux/property.h>
+
+ #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,15 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
+ pdata->disable(bdev->dev);
+ }
+
+-#ifdef CONFIG_OF
+ 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;
++ struct fwnode_handle *child;
+ 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,52 +118,44 @@ 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_property_present(dev, "autorepeat");
++ 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;
++ device_for_each_child_node(dev, child) {
++ struct gpio_desc *desc;
+
+- 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;
++ desc = devm_get_gpiod_from_child(dev, child);
++ if (IS_ERR(desc)) {
++ error = PTR_ERR(desc);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev,
+ "Failed to get gpio flags, error: %d\n",
+ error);
++ fwnode_handle_put(child);
+ return ERR_PTR(error);
+ }
+
+- button = &pdata->buttons[i++];
+-
+- button->gpio = gpio;
+- button->active_low = flags & OF_GPIO_ACTIVE_LOW;
++ button = &pdata->buttons[pdata->nbuttons++];
++ button->gpiod = desc;
+
+- if (of_property_read_u32(pp, "linux,code", &button->code)) {
+- dev_err(dev, "Button without keycode: 0x%x\n",
+- button->gpio);
++ if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
++ dev_err(dev, "Button without keycode: %d\n",
++ pdata->nbuttons - 1);
++ fwnode_handle_put(child);
+ return ERR_PTR(-EINVAL);
+ }
+
+- button->desc = of_get_property(pp, "label", NULL);
++ fwnode_property_read_string(child, "label", &button->desc);
+
+- if (of_property_read_u32(pp, "linux,input-type", &button->type))
++ if (fwnode_property_read_u32(child, "linux,input-type",
++ &button->type))
+ button->type = EV_KEY;
+
+- button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
++ button->wakeup = fwnode_property_present(child, "gpio-key,wakeup");
+
+- if (of_property_read_u32(pp, "debounce-interval",
+- &button->debounce_interval))
++ if (fwnode_property_read_u32(child, "debounce-interval",
++ &button->debounce_interval))
+ button->debounce_interval = 5;
+ }
+
+@@ -187,15 +171,6 @@ 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 int gpio_keys_polled_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -259,7 +234,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 +241,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;
++ }
+
-+ ret = xgene_enet_register_irq(ndev);
-+ if (ret)
-+ return ret;
-+ napi_enable(&pdata->rx_ring->napi);
++ 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 +298,7 @@ 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,
+ },
+ };
+ module_platform_driver(gpio_keys_polled_driver);
+diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
+index 60558f7..3b92862 100644
+--- a/drivers/iommu/arm-smmu.c
++++ b/drivers/iommu/arm-smmu.c
+@@ -444,7 +444,10 @@ static struct device_node *dev_get_dev_node(struct device *dev)
+
+ while (!pci_is_root_bus(bus))
+ bus = bus->parent;
+- return bus->bridge->parent->of_node;
++ if (bus->bridge->parent)
++ return bus->bridge->parent->of_node;
++ else
++ return NULL;
+ }
+
+ return dev->of_node;
+@@ -560,6 +563,9 @@ static struct arm_smmu_device *find_smmu_for_device(struct device *dev)
+ struct arm_smmu_master *master = NULL;
+ struct device_node *dev_node = dev_get_dev_node(dev);
+
++ if (!dev_node)
++ return NULL;
+
-+ if (pdata->phy_dev)
-+ phy_start(pdata->phy_dev);
+ spin_lock(&arm_smmu_devices_lock);
+ list_for_each_entry(smmu, &arm_smmu_devices, list) {
+ master = find_smmu_master(smmu, dev_node);
+diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
+index aa17ae8..d330dab 100644
+--- a/drivers/irqchip/irq-gic-v3.c
++++ b/drivers/irqchip/irq-gic-v3.c
+@@ -506,9 +506,19 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+ isb();
+ }
+
++#ifdef CONFIG_ARM_PARKING_PROTOCOL
++static void gic_wakeup_parked_cpu(int cpu)
++{
++ gic_raise_softirq(cpumask_of(cpu), 0);
++}
++#endif
+
-+ netif_start_queue(ndev);
+ static void gic_smp_init(void)
+ {
+ set_smp_cross_call(gic_raise_softirq);
++#ifdef CONFIG_ARM_PARKING_PROTOCOL
++ set_smp_boot_wakeup_call(gic_wakeup_parked_cpu);
++#endif
+ register_cpu_notifier(&gic_cpu_notifier);
+ }
+
+diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
+index 38493ff..26e6773 100644
+--- a/drivers/irqchip/irq-gic.c
++++ b/drivers/irqchip/irq-gic.c
+@@ -33,12 +33,14 @@
+ #include <linux/of.h>
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
++#include <linux/acpi.h>
+ #include <linux/irqdomain.h>
+ #include <linux/interrupt.h>
+ #include <linux/percpu.h>
+ #include <linux/slab.h>
+ #include <linux/irqchip/chained_irq.h>
+ #include <linux/irqchip/arm-gic.h>
++#include <linux/irqchip/arm-gic-acpi.h>
+
+ #include <asm/cputype.h>
+ #include <asm/irq.h>
+@@ -641,6 +643,13 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+ }
+
-+ return ret;
++#ifdef CONFIG_ARM_PARKING_PROTOCOL
++static void gic_wakeup_parked_cpu(int cpu)
++{
++ gic_raise_softirq(cpumask_of(cpu), GIC_DIST_SOFTINT_NSATT);
+}
++#endif
+ #endif
+
+ #ifdef CONFIG_BL_SWITCHER
+@@ -996,6 +1005,9 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
+ #ifdef CONFIG_SMP
+ set_smp_cross_call(gic_raise_softirq);
+ register_cpu_notifier(&gic_cpu_notifier);
++#ifdef CONFIG_ARM_PARKING_PROTOCOL
++ set_smp_boot_wakeup_call(gic_wakeup_parked_cpu);
++#endif
+ #endif
+ set_handle_irq(gic_handle_irq);
+ }
+@@ -1048,3 +1060,107 @@ IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
+ IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
+
+ #endif
+
-+static int xgene_enet_close(struct net_device *ndev)
-+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
++#ifdef CONFIG_ACPI
++static phys_addr_t dist_phy_base, cpu_phy_base;
++static int cpu_base_assigned;
+
-+ netif_stop_queue(ndev);
++static int __init
++gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
++ const unsigned long end)
++{
++ struct acpi_madt_generic_interrupt *processor;
++ phys_addr_t gic_cpu_base;
+
-+ if (pdata->phy_dev)
-+ phy_stop(pdata->phy_dev);
++ processor = (struct acpi_madt_generic_interrupt *)header;
+
-+ napi_disable(&pdata->rx_ring->napi);
-+ xgene_enet_free_irq(ndev);
-+ xgene_enet_process_ring(pdata->rx_ring, -1);
++ if (BAD_MADT_ENTRY(processor, end))
++ return -EINVAL;
+
-+ xgene_gmac_tx_disable(pdata);
-+ xgene_gmac_rx_disable(pdata);
++ /*
++ * There is no support for non-banked GICv1/2 register in ACPI spec.
++ * All CPU interface addresses have to be the same.
++ */
++ gic_cpu_base = processor->base_address;
++ if (cpu_base_assigned && gic_cpu_base != cpu_phy_base)
++ return -EFAULT;
+
++ cpu_phy_base = gic_cpu_base;
++ cpu_base_assigned = 1;
+ return 0;
+}
+
-+static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring)
++static int __init
++gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
++ const unsigned long end)
+{
-+ struct xgene_enet_pdata *pdata;
-+ struct device *dev;
++ struct acpi_madt_generic_distributor *dist;
++
++ dist = (struct acpi_madt_generic_distributor *)header;
+
-+ pdata = netdev_priv(ring->ndev);
-+ dev = ndev_to_dev(ring->ndev);
++ if (BAD_MADT_ENTRY(dist, end))
++ return -EINVAL;
+
-+ xgene_enet_clear_ring(ring);
-+ dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
++ dist_phy_base = dist->base_address;
++ return 0;
+}
+
-+static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata)
++int __init
++gic_v2_acpi_init(struct acpi_table_header *table)
+{
-+ struct xgene_enet_desc_ring *buf_pool;
++ void __iomem *cpu_base, *dist_base;
++ int count;
+
-+ if (pdata->tx_ring) {
-+ xgene_enet_delete_ring(pdata->tx_ring);
-+ pdata->tx_ring = NULL;
++ /* Collect CPU base addresses */
++ count = acpi_parse_entries(sizeof(struct acpi_table_madt),
++ gic_acpi_parse_madt_cpu, table,
++ ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
++ if (count < 0) {
++ pr_err("Error during GICC entries parsing\n");
++ return -EFAULT;
++ } else if (!count) {
++ pr_err("No valid GICC entries exist\n");
++ return -EINVAL;
+ }
+
-+ if (pdata->rx_ring) {
-+ buf_pool = pdata->rx_ring->buf_pool;
-+ xgene_enet_delete_bufpool(buf_pool);
-+ xgene_enet_delete_ring(buf_pool);
-+ xgene_enet_delete_ring(pdata->rx_ring);
-+ pdata->rx_ring = NULL;
++ /*
++ * Find distributor base address. We expect one distributor entry since
++ * ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade.
++ */
++ count = acpi_parse_entries(sizeof(struct acpi_table_madt),
++ gic_acpi_parse_madt_distributor, table,
++ ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
++ if (count <= 0) {
++ pr_err("Error during GICD entries parsing\n");
++ return -EFAULT;
++ } else if (!count) {
++ pr_err("No valid GICD entries exist\n");
++ return -EINVAL;
++ } else if (count > 1) {
++ pr_err("More than one GICD entry detected\n");
++ return -EINVAL;
+ }
-+}
+
-+static int xgene_enet_get_ring_size(struct device *dev,
-+ enum xgene_enet_ring_cfgsize cfgsize)
-+{
-+ int size = -EINVAL;
++ cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE);
++ if (!cpu_base) {
++ pr_err("Unable to map GICC registers\n");
++ return -ENOMEM;
++ }
+
-+ switch (cfgsize) {
-+ case RING_CFGSIZE_512B:
-+ size = 0x200;
-+ break;
-+ case RING_CFGSIZE_2KB:
-+ size = 0x800;
-+ break;
-+ case RING_CFGSIZE_16KB:
-+ size = 0x4000;
-+ break;
-+ case RING_CFGSIZE_64KB:
-+ size = 0x10000;
-+ break;
-+ case RING_CFGSIZE_512KB:
-+ size = 0x80000;
-+ break;
-+ default:
-+ dev_err(dev, "Unsupported cfg ring size %d\n", cfgsize);
-+ break;
++ dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE);
++ if (!dist_base) {
++ pr_err("Unable to map GICD registers\n");
++ iounmap(cpu_base);
++ return -ENOMEM;
+ }
+
-+ return size;
++ /*
++ * 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 <linux/init.h>
+ #include <linux/of_irq.h>
+ #include <linux/irqchip.h>
++#include <linux/irqchip/arm-gic-acpi.h>
+
+ /*
+ * 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);
+
-+static void xgene_enet_free_desc_ring(struct xgene_enet_desc_ring *ring)
-+{
-+ struct device *dev;
-+
-+ if (!ring)
-+ return;
-+
-+ dev = ndev_to_dev(ring->ndev);
++ acpi_gic_init();
+ }
+diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
+index b4518c8..b3c5d9d 100644
+--- a/drivers/leds/leds-gpio.c
++++ b/drivers/leds/leds-gpio.c
+@@ -12,25 +12,23 @@
+ */
+ #include <linux/err.h>
+ #include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
+ #include <linux/kernel.h>
+ #include <linux/leds.h>
+ #include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_gpio.h>
+-#include <linux/of_platform.h>
+ #include <linux/platform_device.h>
++#include <linux/property.h>
+ #include <linux/slab.h>
+ #include <linux/workqueue.h>
+
+ 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,
++ int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
+ unsigned long *delay_on, unsigned long *delay_off);
+ };
+
+@@ -40,12 +38,11 @@ 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);
++ led_dat->platform_gpio_blink_set(led_dat->gpiod,
++ led_dat->new_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 +57,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 +66,11 @@ 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,
++ led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
+ NULL, NULL);
+ led_dat->blinking = 0;
+ } else
+- gpio_set_value(led_dat->gpio, level);
++ gpiod_set_value(led_dat->gpiod, level);
+ }
+ }
+
+@@ -87,34 +81,49 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
+ container_of(led_cdev, struct gpio_led_data, cdev);
+
+ led_dat->blinking = 1;
+- return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
++ return led_dat->platform_gpio_blink_set(led_dat->gpiod, GPIO_LED_BLINK,
+ delay_on, delay_off);
+ }
+
+ static int create_gpio_led(const struct gpio_led *template,
+ struct gpio_led_data *led_dat, struct device *parent,
+- int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
++ int (*blink_set)(struct gpio_desc *, int, unsigned long *,
++ unsigned long *))
+ {
+ int ret, state;
+
+- led_dat->gpio = -1;
++ led_dat->gpiod = template->gpiod;
++ if (!led_dat->gpiod) {
++ /*
++ * This is the legacy code path for platform code that
++ * still uses GPIO numbers. Ultimately we would like to get
++ * rid of this block completely.
++ */
++ unsigned long flags = 0;
+
-+ if (ring->desc_addr) {
-+ xgene_enet_clear_ring(ring);
-+ dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
++ /* 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;
+- }
++ if (template->active_low)
++ flags |= GPIOF_ACTIVE_LOW;
+
+- ret = devm_gpio_request(parent, template->gpio, template->name);
+- if (ret < 0)
+- return ret;
++ 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);
+ }
-+ devm_kfree(dev, ring);
-+}
-+
-+static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata)
-+{
-+ struct device *dev = &pdata->pdev->dev;
-+ struct xgene_enet_desc_ring *ring;
-+
-+ ring = pdata->tx_ring;
-+ if (ring && ring->cp_ring && ring->cp_ring->cp_skb)
-+ devm_kfree(dev, ring->cp_ring->cp_skb);
-+ xgene_enet_free_desc_ring(ring);
+
+ 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->can_sleep = gpiod_cansleep(led_dat->gpiod);
+ led_dat->blinking = 0;
+ if (blink_set) {
+ led_dat->platform_gpio_blink_set = blink_set;
+@@ -122,30 +131,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,40 +164,37 @@ 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 struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
+ {
+- struct device_node *np = pdev->dev.of_node, *child;
++ struct device *dev = &pdev->dev;
++ struct fwnode_handle *child;
+ struct gpio_leds_priv *priv;
+ int count, ret;
+
+- /* 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(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);
++ priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
+ if (!priv)
+ return ERR_PTR(-ENOMEM);
+
+- for_each_available_child_of_node(np, child) {
++ device_for_each_child_node(dev, 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) {
++ const char *state = NULL;
++
++ led.gpiod = devm_get_gpiod_from_child(dev, child);
++ if (IS_ERR(led.gpiod)) {
++ fwnode_handle_put(child);
++ goto err;
++ }
+
-+ ring = pdata->rx_ring;
-+ if (ring && ring->buf_pool && ring->buf_pool->rx_skb)
-+ devm_kfree(dev, ring->buf_pool->rx_skb);
-+ xgene_enet_free_desc_ring(ring->buf_pool);
-+ xgene_enet_free_desc_ring(ring);
-+}
++ fwnode_property_read_string(child, "label", &led.name);
++ fwnode_property_read_string(child, "linux,default-trigger",
++ &led.default_trigger);
++
++ if (!fwnode_property_read_string(child, "linux,default_state",
++ &state)) {
+ if (!strcmp(state, "keep"))
+ led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
+ else if (!strcmp(state, "on"))
+@@ -203,13 +203,13 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+ led.default_state = LEDS_GPIO_DEFSTATE_OFF;
+ }
+
+- if (of_get_property(child, "retain-state-suspended", NULL))
++ if (fwnode_property_present(child, "retain-state-suspended"))
+ led.retain_state_suspended = 1;
+
+ ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
+- &pdev->dev, NULL);
++ dev, NULL);
+ if (ret < 0) {
+- of_node_put(child);
++ fwnode_handle_put(child);
+ goto err;
+ }
+ }
+@@ -228,12 +228,6 @@ 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 int gpio_led_probe(struct platform_device *pdev)
+ {
+@@ -261,7 +255,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);
+ }
+@@ -288,7 +282,7 @@ 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,
+ },
+ };
+
+diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
+index 634f729..0a1af93 100644
+--- a/drivers/misc/eeprom/at25.c
++++ b/drivers/misc/eeprom/at25.c
+@@ -18,7 +18,7 @@
+
+ #include <linux/spi/spi.h>
+ #include <linux/spi/eeprom.h>
+-#include <linux/of.h>
++#include <linux/property.h>
+
+ /*
+ * 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)
+ {
+ 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_property_present(dev, "read-only"))
+ 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;
+
+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 9da3a03..a34cad2 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+@@ -130,7 +130,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
+@@ -153,7 +153,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
+@@ -695,6 +695,18 @@ static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
+ else
+ mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
+
++ if (XGBE_SEATTLE_A0) {
++ /* The PCS implementation has reversed the devices in
++ * package registers so we need to change 05 to 06 and
++ * 06 to 05 if being read (these registers are readonly
++ * so no need to do this in the write function)
++ */
++ if ((mmd_address & 0xffff) == 0x05)
++ mmd_address = (mmd_address & ~0xffff) | 0x06;
++ else if ((mmd_address & 0xffff) == 0x06)
++ mmd_address = (mmd_address & ~0xffff) | 0x05;
++ }
+
-+static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
-+ struct net_device *ndev, u32 ring_num,
-+ enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id)
+ /* The PCS registers are accessed using mmio. The underlying APB3
+ * management interface uses indirect addressing to access the MMD
+ * register sets. This requires accessing of the PCS register in two
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+index 2349ea9..a04b18b 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+@@ -425,6 +425,9 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
+ hw_feat->rx_ch_cnt++;
+ hw_feat->tx_ch_cnt++;
+
++ /* A0 does not support NUMTC, hardcode it for now */
++ hw_feat->tc_cnt = XGBE_TC_CNT;
++
+ 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 f5a8fa0..338c0ed 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+@@ -124,6 +124,7 @@
+ #include <linux/of.h>
+ #include <linux/of_net.h>
+ #include <linux/clk.h>
++#include <linux/acpi.h>
+
+ #include "xgbe.h"
+ #include "xgbe-common.h"
+@@ -215,6 +216,205 @@ 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 xgene_enet_desc_ring *ring;
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct device *dev = ndev_to_dev(ndev);
-+ u32 size;
-+
-+ ring = devm_kzalloc(dev, sizeof(struct xgene_enet_desc_ring),
-+ GFP_KERNEL);
-+ if (!ring)
-+ return NULL;
-+
-+ ring->ndev = ndev;
-+ ring->num = ring_num;
-+ ring->cfgsize = cfgsize;
-+ ring->id = ring_id;
++ struct platform_device *pdev = pdata->pdev;
++ struct device *dev = pdata->dev;
++ struct resource *res;
+
-+ size = xgene_enet_get_ring_size(dev, cfgsize);
-+ ring->desc_addr = dma_zalloc_coherent(dev, size, &ring->dma,
-+ GFP_KERNEL);
-+ if (!ring->desc_addr) {
-+ devm_kfree(dev, ring);
-+ return NULL;
++ /* 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);
+ }
-+ ring->size = size;
++ DBGPR(" xgmac_regs = %p\n", pdata->xgmac_regs);
+
-+ ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6);
-+ ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR;
-+ pdata->rm = RM3;
-+ ring = xgene_enet_setup_ring(ring);
-+ netdev_dbg(ndev, "ring info: num=%d size=%d id=%d slots=%d\n",
-+ ring->num, ring->size, ring->id, ring->slots);
-+
-+ return ring;
-+}
++ 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);
+
-+static u16 xgene_enet_get_ring_id(enum xgene_ring_owner owner, u8 bufnum)
-+{
-+ return (owner << 6) | (bufnum & GENMASK(5, 0));
++ return 0;
+}
+
-+static int xgene_enet_create_desc_rings(struct net_device *ndev)
++#ifdef CONFIG_ACPI
++static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct device *dev = ndev_to_dev(ndev);
-+ struct xgene_enet_desc_ring *rx_ring, *tx_ring, *cp_ring;
-+ struct xgene_enet_desc_ring *buf_pool = NULL;
-+ u8 cpu_bufnum = 0, eth_bufnum = 0;
-+ u8 bp_bufnum = 0x20;
-+ u16 ring_id, ring_num = 0;
++ 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;
+
-+ /* allocate rx descriptor ring */
-+ ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
-+ rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
-+ RING_CFGSIZE_16KB, ring_id);
-+ if (!rx_ring) {
-+ ret = -ENOMEM;
-+ goto err;
++ /* 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;
+
-+ /* allocate buffer pool for receiving packets */
-+ ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, bp_bufnum++);
-+ buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++,
-+ RING_CFGSIZE_2KB, ring_id);
-+ if (!buf_pool) {
-+ ret = -ENOMEM;
-+ goto err;
++ /* 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;
+
-+ rx_ring->nbufpool = NUM_BUFPOOL;
-+ rx_ring->buf_pool = buf_pool;
-+ rx_ring->irq = pdata->rx_irq;
-+ buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots,
-+ sizeof(struct sk_buff *), GFP_KERNEL);
-+ if (!buf_pool->rx_skb) {
-+ ret = -ENOMEM;
-+ goto err;
++ /* 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];
+
-+ buf_pool->dst_ring_num = xgene_enet_dst_ring_num(buf_pool);
-+ rx_ring->buf_pool = buf_pool;
-+ pdata->rx_ring = rx_ring;
++ 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);
++ return -EINVAL;
++ }
+
-+ /* allocate tx descriptor ring */
-+ ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, eth_bufnum++);
-+ tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
-+ RING_CFGSIZE_16KB, ring_id);
-+ if (!tx_ring) {
-+ ret = -ENOMEM;
-+ goto err;
++ /* 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->tx_ring = tx_ring;
++ pdata->phy_mode = PHY_INTERFACE_MODE_XGMII;
+
-+ cp_ring = pdata->rx_ring;
-+ cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots,
-+ sizeof(struct sk_buff *), GFP_KERNEL);
-+ if (!cp_ring->cp_skb) {
-+ ret = -ENOMEM;
-+ goto err;
++#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;
+ }
-+ pdata->tx_ring->cp_ring = cp_ring;
-+ pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
+
-+ pdata->tx_qcnt_hi = pdata->tx_ring->slots / 2;
-+ pdata->cp_qcnt_hi = pdata->rx_ring->slots / 2;
-+ pdata->cp_qcnt_low = pdata->cp_qcnt_hi / 2;
++ 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;
-+
-+err:
-+ xgene_enet_free_desc_rings(pdata);
-+ return ret;
+}
-+
-+static struct rtnl_link_stats64 *xgene_enet_get_stats64(
-+ struct net_device *ndev,
-+ struct rtnl_link_stats64 *storage)
++#else /* CONFIG_ACPI */
++static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-+ struct rtnl_link_stats64 *stats = &pdata->stats;
-+
-+ spin_lock(&pdata->stats_lock);
-+ stats->rx_errors += stats->rx_length_errors +
-+ stats->rx_crc_errors +
-+ stats->rx_frame_errors +
-+ stats->rx_fifo_errors;
-+ memcpy(storage, &pdata->stats, sizeof(struct rtnl_link_stats64));
-+ spin_unlock(&pdata->stats_lock);
-+
-+ return storage;
++ return -EINVAL;
+}
++#endif /* CONFIG_ACPI */
+
-+static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr)
++#ifdef CONFIG_OF
++static int xgbe_of_support(struct xgbe_prv_data *pdata)
+{
-+ struct xgene_enet_pdata *pdata = netdev_priv(ndev);
++ struct device *dev = pdata->dev;
++ const u8 *mac_addr;
+ int ret;
+
-+ ret = eth_mac_addr(ndev, addr);
++ /* Map the memory resources */
++ ret = xgbe_map_resources(pdata);
+ if (ret)
+ return ret;
-+ xgene_gmac_set_mac_addr(pdata);
-+
-+ return ret;
-+}
-+
-+static const struct net_device_ops xgene_ndev_ops = {
-+ .ndo_open = xgene_enet_open,
-+ .ndo_stop = xgene_enet_close,
-+ .ndo_start_xmit = xgene_enet_start_xmit,
-+ .ndo_tx_timeout = xgene_enet_timeout,
-+ .ndo_get_stats64 = xgene_enet_get_stats64,
-+ .ndo_change_mtu = eth_change_mtu,
-+ .ndo_set_mac_address = xgene_enet_set_mac_address,
-+};
-+
-+static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
-+{
-+ struct platform_device *pdev;
-+ struct net_device *ndev;
-+ struct device *dev;
-+ struct resource *res;
-+ void *base_addr;
-+ const char *mac;
-+ int ret;
+
-+ pdev = pdata->pdev;
-+ dev = &pdev->dev;
-+ ndev = pdata->ndev;
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr");
-+ if (!res) {
-+ dev_err(dev, "Resource enet_csr not defined\n");
-+ return -ENODEV;
-+ }
-+ pdata->base_addr = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pdata->base_addr)) {
-+ dev_err(dev, "Unable to retrieve ENET Port CSR region\n");
-+ return PTR_ERR(pdata->base_addr);
++ /* 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);
+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr");
-+ if (!res) {
-+ dev_err(dev, "Resource ring_csr not defined\n");
-+ return -ENODEV;
-+ }
-+ pdata->ring_csr_addr = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pdata->ring_csr_addr)) {
-+ dev_err(dev, "Unable to retrieve ENET Ring CSR region\n");
-+ return PTR_ERR(pdata->ring_csr_addr);
++ /* 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);
+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd");
-+ if (!res) {
-+ dev_err(dev, "Resource ring_cmd not defined\n");
-+ return -ENODEV;
-+ }
-+ 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);
-+ }
-+
-+ ret = platform_get_irq(pdev, 0);
-+ if (ret <= 0) {
-+ dev_err(dev, "Unable to get ENET Rx IRQ\n");
-+ ret = ret ? : -ENXIO;
-+ return ret;
++ /* 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;
+ }
-+ pdata->rx_irq = ret;
++ memcpy(pdata->mac_addr, mac_addr, ETH_ALEN);
+
-+ mac = of_get_mac_address(dev->of_node);
-+ if (mac)
-+ memcpy(ndev->dev_addr, mac, ndev->addr_len);
-+ else
-+ 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) {
-+ dev_err(dev, "Incorrect phy-connection-type in DTS\n");
++ /* 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;
+ }
+
-+ 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;
++ /* 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;
+ }
+
-+ base_addr = pdata->base_addr;
-+ pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET;
-+ pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET;
-+ pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET;
-+ pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET;
-+ pdata->mcx_stats_addr = base_addr + BLOCK_ETH_STATS_OFFSET;
-+ 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)
++#else /* CONFIG_OF */
++static int xgbe_of_support(struct xgbe_prv_data *pdata)
+{
-+ struct net_device *ndev = pdata->ndev;
-+ struct xgene_enet_desc_ring *buf_pool;
-+ u16 dst_ring_num;
-+ int ret;
-+
-+ xgene_gmac_tx_disable(pdata);
-+ xgene_gmac_rx_disable(pdata);
-+
-+ ret = xgene_enet_create_desc_rings(ndev);
-+ if (ret) {
-+ netdev_err(ndev, "Error in ring configuration\n");
-+ return ret;
-+ }
++ return -EINVAL;
++}
++#endif /*CONFIG_OF */
+
-+ /* setup buffer pool */
-+ buf_pool = pdata->rx_ring->buf_pool;
-+ xgene_enet_init_bufpool(buf_pool);
-+ ret = xgene_enet_refill_bufpool(buf_pool, pdata->rx_buff_cnt);
+ static int xgbe_probe(struct platform_device *pdev)
+ {
+ struct xgbe_prv_data *pdata;
+@@ -222,8 +422,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");
+@@ -239,6 +437,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);
+
+@@ -264,40 +463,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)
-+ return ret;
-+
-+ dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring);
-+ xgene_enet_cle_bypass(pdata, dst_ring_num, buf_pool->id);
+ goto err_io;
+- }
+- DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs);
+
+ /* Set the DMA mask */
+ if (!dev->dma_mask)
+@@ -308,23 +480,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;
+ }
+
-+ return ret;
-+}
+ 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);
+@@ -337,23 +502,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);
+
+@@ -531,10 +679,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 },
++ {},
++};
+
-+static int xgene_enet_probe(struct platform_device *pdev)
-+{
-+ struct net_device *ndev;
-+ struct xgene_enet_pdata *pdata;
-+ struct device *dev = &pdev->dev;
-+ struct napi_struct *napi;
-+ int ret;
++MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match);
++#endif
+
-+ ndev = alloc_etherdev(sizeof(struct xgene_enet_pdata));
-+ if (!ndev)
++#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);
+@@ -542,7 +702,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 363b210..5d2c89b 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+@@ -119,6 +119,7 @@
+ #include <linux/mdio.h>
+ #include <linux/phy.h>
+ #include <linux/of.h>
++#include <linux/acpi.h>
+
+ #include "xgbe.h"
+ #include "xgbe-common.h"
+@@ -205,25 +206,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) */
+@@ -252,12 +244,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;
+ }
+
+@@ -283,8 +272,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");
+@@ -300,9 +287,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 a1bf9d1c..fa67203 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
+@@ -239,7 +239,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;
+@@ -260,7 +260,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);
+
+ /* 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 789957d..59498eb 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
++++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
+@@ -172,6 +172,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
+ */
+@@ -186,8 +192,11 @@
+ #define XGBE_FIFO_SIZE_B(x) (x)
+ #define XGBE_FIFO_SIZE_KB(x) (x * 1024)
+
++#define XGBE_TC_CNT 2
+ #define XGBE_TC_MIN_QUANTUM 10
+
++#define XGBE_SEATTLE_A0 ((read_cpuid_id() & 0x00f0000f) == 0)
++
+ /* 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
+@@ -569,6 +578,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 */
+@@ -649,6 +659,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;
+@@ -658,7 +669,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 7ba83ff..29aad5e 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+@@ -663,15 +663,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;
+
-+ pdata = netdev_priv(ndev);
++ 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;
+ }
+@@ -681,11 +686,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;
+
-+ pdata->pdev = pdev;
-+ pdata->ndev = ndev;
-+ SET_NETDEV_DEV(ndev, dev);
-+ platform_set_drvdata(pdev, pdata);
-+ ndev->netdev_ops = &xgene_ndev_ops;
-+ xgene_enet_set_ethtool_ops(ndev);
-+ ndev->features |= NETIF_F_IP_CSUM |
-+ NETIF_F_GSO |
-+ NETIF_F_GRO;
++ /* Mask out all PHYs from auto probing. */
++ mdio->phy_mask = ~0;
+
-+ ret = xgene_enet_get_resources(pdata);
-+ if (ret)
-+ goto err;
++ /* Clear all the IRQ properties */
++ if (mdio->irq)
++ for (i = 0; i < PHY_MAX_ADDR; i++)
++ mdio->irq[i] = PHY_POLL;
+
-+ xgene_enet_reset(pdata);
-+ xgene_gmac_init(pdata, SPEED_1000);
++ /* Register the MDIO bus */
++ ret = mdiobus_register(mdio);
++ if (ret)
++ return ret;
+
-+ spin_lock_init(&pdata->stats_lock);
-+ ret = register_netdev(ndev);
-+ if (ret) {
-+ netdev_err(ndev, "Failed to register netdev\n");
-+ goto err;
-+ }
++ ret = device_property_read_u32(dev, "phy-channel", &phy_id);
++ if (ret)
++ return -EINVAL;
+
-+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
-+ if (ret) {
-+ netdev_err(ndev, "No usable DMA configuration\n");
-+ goto err;
-+ }
++ phy = get_phy_device(mdio, phy_id, true);
++ if (!phy || IS_ERR(phy))
++ return -EIO;
+
-+ ret = xgene_enet_init_hw(pdata);
++ ret = phy_device_register(phy);
+ if (ret)
-+ goto err;
-+
-+ napi = &pdata->rx_ring->napi;
-+ netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT);
-+ ret = xgene_enet_mdio_config(pdata);
++ phy_device_free(phy);
++ else
++ pdata->phy_dev = phy;
+
+ return ret;
-+err:
-+ free_netdev(ndev);
-+ return ret;
+}
++#else
++#define xgene_acpi_mdiobus_register(a, b) -1
++#endif
+
-+static int xgene_enet_remove(struct platform_device *pdev)
+ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
+ {
+ struct net_device *ndev = pdata->ndev;
+@@ -702,7 +748,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;
+ }
+@@ -720,7 +766,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 1236696..f66598a 100644
+--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+@@ -746,6 +746,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)
+{
-+ struct xgene_enet_pdata *pdata;
-+ struct net_device *ndev;
++ int ret;
+
-+ pdata = platform_get_drvdata(pdev);
-+ ndev = pdata->ndev;
++ ret = device_property_read_u8_array(dev, "mac-address", addr, 6);
++ if (ret)
++ return 0;
+
-+ xgene_gmac_rx_disable(pdata);
-+ xgene_gmac_tx_disable(pdata);
++ return 6;
++}
+
-+ netif_napi_del(&pdata->rx_ring->napi);
-+ xgene_enet_mdio_remove(pdata);
-+ xgene_enet_delete_desc_rings(pdata);
-+ unregister_netdev(ndev);
-+ xgene_gport_shutdown(pdata);
-+ free_netdev(ndev);
++static int acpi_get_phy_mode(struct device *dev)
++{
++ int i, ret, phy_mode;
++ char *modestr;
+
-+ return 0;
++ 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 struct of_device_id xgene_enet_match[] = {
-+ {.compatible = "apm,xgene-enet",},
-+ {},
+ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
+ {
+ struct platform_device *pdev;
+@@ -761,6 +797,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;
+@@ -772,6 +810,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;
+@@ -783,6 +823,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;
+@@ -804,11 +846,13 @@ 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, "Unable to get phy-connection-type\n");
+ return pdata->phy_mode;
+@@ -821,11 +865,12 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
+ }
+
+ 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;
+@@ -875,7 +920,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata)
+ pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id);
+ pdata->mac_ops->init(pdata);
+
+- return ret;
++ return 0;
+ }
+
+ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata)
+@@ -936,7 +981,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;
+@@ -984,6 +1029,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
+
-+MODULE_DEVICE_TABLE(of, xgene_enet_match);
-+
-+static struct platform_driver xgene_enet_driver = {
-+ .driver = {
-+ .name = "xgene-enet",
-+ .owner = THIS_MODULE,
-+ .of_match_table = xgene_enet_match,
-+ },
-+ .probe = xgene_enet_probe,
-+ .remove = xgene_enet_remove,
+ static struct of_device_id xgene_enet_match[] = {
+ {.compatible = "apm,xgene-enet",},
+ {},
+@@ -995,6 +1048,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 f9958fa..0e06cad 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 <linux/prefetch.h>
+ #include <linux/if_vlan.h>
+ #include <linux/phy.h>
++#include <linux/acpi.h>
+ #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 6cc3cf6..91c36a2 100644
+--- a/drivers/net/ethernet/smsc/smc91x.c
++++ b/drivers/net/ethernet/smsc/smc91x.c
+@@ -82,6 +82,7 @@ static const char version[] =
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_gpio.h>
++#include <linux/acpi.h>
+
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+@@ -2467,6 +2468,14 @@ static struct dev_pm_ops smc_drv_pm_ops = {
+ .resume = smc_drv_resume,
+ };
+
++#ifdef CONFIG_ACPI
++static const struct acpi_device_id smc91x_acpi_match[] = {
++ { "LNRO0003", },
++ { }
+};
++MODULE_DEVICE_TABLE(acpi, smc91x_acpi_match);
++#endif
+
-+module_platform_driver(xgene_enet_driver);
+ static struct platform_driver smc_driver = {
+ .probe = smc_drv_probe,
+ .remove = smc_drv_remove,
+@@ -2475,6 +2484,7 @@ static struct platform_driver smc_driver = {
+ .owner = THIS_MODULE,
+ .pm = &smc_drv_pm_ops,
+ .of_match_table = of_match_ptr(smc91x_match),
++ .acpi_match_table = ACPI_PTR(smc91x_acpi_match),
+ },
+ };
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 75472cf7..bacafe2 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 c456559..d852c6e 100644
+--- a/drivers/net/phy/amd-xgbe-phy.c
++++ b/drivers/net/phy/amd-xgbe-phy.c
+@@ -74,15 +74,19 @@
+ #include <linux/of_platform.h>
+ #include <linux/of_device.h>
+ #include <linux/uaccess.h>
++#include <linux/acpi.h>
+
-+MODULE_DESCRIPTION("APM X-Gene SoC Ethernet driver");
-+MODULE_VERSION(XGENE_DRV_VERSION);
-+MODULE_AUTHOR("Keyur Chudgar <kchudgar@apm.com>");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
-new file mode 100644
-index 0000000..f4f7e4a
---- /dev/null
-+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
-@@ -0,0 +1,107 @@
-+/* Applied Micro X-Gene SoC Ethernet Driver
-+ *
-+ * Copyright (c) 2014, Applied Micro Circuits Corporation
-+ * Authors: Iyappan Subramanian <isubramanian@apm.com>
-+ * Ravi Patel <rapatel@apm.com>
-+ * Keyur Chudgar <kchudgar@apm.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
+
+ MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
+ MODULE_LICENSE("Dual BSD/GPL");
+-MODULE_VERSION("1.0.0-a");
++MODULE_VERSION("0.0.0-a");
+ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
+
+-#define XGBE_PHY_ID 0x000162d0
++#define XGBE_PHY_ID 0x7996ced0
+ #define XGBE_PHY_MASK 0xfffffff0
+
++#define XGBE_PHY_SERDES_RETRY 32
++#define XGBE_PHY_CHANNEL_PROPERTY "amd,serdes-channel"
+ #define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set"
+
+ #define XGBE_AN_INT_CMPLT 0x01
+@@ -99,11 +103,9 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
+ #ifndef MDIO_PMA_10GBR_PMD_CTRL
+ #define MDIO_PMA_10GBR_PMD_CTRL 0x0096
+ #endif
+-
+ #ifndef MDIO_PMA_10GBR_FEC_CTRL
+ #define MDIO_PMA_10GBR_FEC_CTRL 0x00ab
+ #endif
+-
+ #ifndef MDIO_AN_XNP
+ #define MDIO_AN_XNP 0x0016
+ #endif
+@@ -111,93 +113,14 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
+ #ifndef MDIO_AN_INTMASK
+ #define MDIO_AN_INTMASK 0x8001
+ #endif
+-
+ #ifndef MDIO_AN_INT
+ #define MDIO_AN_INT 0x8002
+ #endif
+
+-#ifndef MDIO_AN_KR_CTRL
+-#define MDIO_AN_KR_CTRL 0x8003
+-#endif
+-
+ #ifndef MDIO_CTRL1_SPEED1G
+ #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
+ #endif
+
+-#ifndef MDIO_KR_CTRL_PDETECT
+-#define MDIO_KR_CTRL_PDETECT 0x01
+-#endif
+-
+-/* SerDes integration register offsets */
+-#define SIR0_KR_RT_1 0x002c
+-#define SIR0_STATUS 0x0040
+-#define SIR1_SPEED 0x0000
+-
+-/* SerDes integration register entry bit positions and sizes */
+-#define SIR0_KR_RT_1_RESET_INDEX 11
+-#define SIR0_KR_RT_1_RESET_WIDTH 1
+-#define SIR0_STATUS_RX_READY_INDEX 0
+-#define SIR0_STATUS_RX_READY_WIDTH 1
+-#define SIR0_STATUS_TX_READY_INDEX 8
+-#define SIR0_STATUS_TX_READY_WIDTH 1
+-#define SIR1_SPEED_DATARATE_INDEX 4
+-#define SIR1_SPEED_DATARATE_WIDTH 2
+-#define SIR1_SPEED_PI_SPD_SEL_INDEX 12
+-#define SIR1_SPEED_PI_SPD_SEL_WIDTH 4
+-#define SIR1_SPEED_PLLSEL_INDEX 3
+-#define SIR1_SPEED_PLLSEL_WIDTH 1
+-#define SIR1_SPEED_RATECHANGE_INDEX 6
+-#define SIR1_SPEED_RATECHANGE_WIDTH 1
+-#define SIR1_SPEED_TXAMP_INDEX 8
+-#define SIR1_SPEED_TXAMP_WIDTH 4
+-#define SIR1_SPEED_WORDMODE_INDEX 0
+-#define SIR1_SPEED_WORDMODE_WIDTH 3
+-
+-#define SPEED_10000_CDR 0x7
+-#define SPEED_10000_PLL 0x1
+-#define SPEED_10000_RATE 0x0
+-#define SPEED_10000_TXAMP 0xa
+-#define SPEED_10000_WORD 0x7
+-
+-#define SPEED_2500_CDR 0x2
+-#define SPEED_2500_PLL 0x0
+-#define SPEED_2500_RATE 0x1
+-#define SPEED_2500_TXAMP 0xf
+-#define SPEED_2500_WORD 0x1
+-
+-#define SPEED_1000_CDR 0x2
+-#define SPEED_1000_PLL 0x0
+-#define SPEED_1000_RATE 0x3
+-#define SPEED_1000_TXAMP 0xf
+-#define SPEED_1000_WORD 0x1
+-
+-/* SerDes RxTx register offsets */
+-#define RXTX_REG20 0x0050
+-#define RXTX_REG114 0x01c8
+-
+-/* SerDes RxTx register entry bit positions and sizes */
+-#define RXTX_REG20_BLWC_ENA_INDEX 2
+-#define RXTX_REG20_BLWC_ENA_WIDTH 1
+-#define RXTX_REG114_PQ_REG_INDEX 9
+-#define RXTX_REG114_PQ_REG_WIDTH 7
+-
+-#define RXTX_10000_BLWC 0
+-#define RXTX_10000_PQ 0x1e
+-
+-#define RXTX_2500_BLWC 1
+-#define RXTX_2500_PQ 0xa
+-
+-#define RXTX_1000_BLWC 1
+-#define RXTX_1000_PQ 0xa
+-
+-/* Bit setting and getting macros
+- * The get macro will extract the current bit field value from within
+- * the variable
+- *
+- * The set macro will clear the current bit field value within the
+- * variable and then set the bit field of the variable to the
+- * specified value
+- */
+ #define GET_BITS(_var, _index, _width) \
+ (((_var) >> (_index)) & ((0x1 << (_width)) - 1))
+
+@@ -207,70 +130,12 @@ do { \
+ (_var) |= (((_val) & ((0x1 << (_width)) - 1)) << (_index)); \
+ } while (0)
+
+-#define XSIR_GET_BITS(_var, _prefix, _field) \
+- GET_BITS((_var), \
+- _prefix##_##_field##_INDEX, \
+- _prefix##_##_field##_WIDTH)
+-
+-#define XSIR_SET_BITS(_var, _prefix, _field, _val) \
+- SET_BITS((_var), \
+- _prefix##_##_field##_INDEX, \
+- _prefix##_##_field##_WIDTH, (_val))
+-
+-/* 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
+- *
+- * The iowrite macros will set bit fields or full values using the
+- * register definitions formed using the input names
+- */
+-#define XSIR0_IOREAD(_priv, _reg) \
+- ioread16((_priv)->sir0_regs + _reg)
+-
+-#define XSIR0_IOREAD_BITS(_priv, _reg, _field) \
+- GET_BITS(XSIR0_IOREAD((_priv), _reg), \
+- _reg##_##_field##_INDEX, \
+- _reg##_##_field##_WIDTH)
+-
+-#define XSIR0_IOWRITE(_priv, _reg, _val) \
+- iowrite16((_val), (_priv)->sir0_regs + _reg)
+-
+-#define XSIR0_IOWRITE_BITS(_priv, _reg, _field, _val) \
+-do { \
+- u16 reg_val = XSIR0_IOREAD((_priv), _reg); \
+- SET_BITS(reg_val, \
+- _reg##_##_field##_INDEX, \
+- _reg##_##_field##_WIDTH, (_val)); \
+- XSIR0_IOWRITE((_priv), _reg, reg_val); \
+-} while (0)
+-
+-#define XSIR1_IOREAD(_priv, _reg) \
+- ioread16((_priv)->sir1_regs + _reg)
+-
+-#define XSIR1_IOREAD_BITS(_priv, _reg, _field) \
+- GET_BITS(XSIR1_IOREAD((_priv), _reg), \
+- _reg##_##_field##_INDEX, \
+- _reg##_##_field##_WIDTH)
++#define XCMU_IOREAD(_priv, _reg) \
++ ioread16((_priv)->cmu_regs + _reg)
+
+-#define XSIR1_IOWRITE(_priv, _reg, _val) \
+- iowrite16((_val), (_priv)->sir1_regs + _reg)
++#define XCMU_IOWRITE(_priv, _reg, _val) \
++ iowrite16((_val), (_priv)->cmu_regs + _reg)
+
+-#define XSIR1_IOWRITE_BITS(_priv, _reg, _field, _val) \
+-do { \
+- u16 reg_val = XSIR1_IOREAD((_priv), _reg); \
+- SET_BITS(reg_val, \
+- _reg##_##_field##_INDEX, \
+- _reg##_##_field##_WIDTH, (_val)); \
+- XSIR1_IOWRITE((_priv), _reg, reg_val); \
+-} while (0)
+-
+-/* 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
+- *
+- * The iowrite macros will set bit fields or full values using the
+- * register definitions formed using the input names
+- */
+ #define XRXTX_IOREAD(_priv, _reg) \
+ ioread16((_priv)->rxtx_regs + _reg)
+
+@@ -291,6 +156,78 @@ do { \
+ XRXTX_IOWRITE((_priv), _reg, reg_val); \
+ } while (0)
+
++/* SerDes CMU register offsets */
++#define CMU_REG15 0x003c
++#define CMU_REG16 0x0040
++
++/* SerDes CMU register entry bit positions and sizes */
++#define CMU_REG16_TX_RATE_CHANGE_BASE 15
++#define CMU_REG16_RX_RATE_CHANGE_BASE 14
++#define CMU_REG16_RATE_CHANGE_DECR 2
++
++
++/* SerDes RxTx register offsets */
++#define RXTX_REG2 0x0008
++#define RXTX_REG3 0x000c
++#define RXTX_REG5 0x0014
++#define RXTX_REG6 0x0018
++#define RXTX_REG20 0x0050
++#define RXTX_REG53 0x00d4
++#define RXTX_REG114 0x01c8
++#define RXTX_REG115 0x01cc
++#define RXTX_REG142 0x0238
++
++/* SerDes RxTx register entry bit positions and sizes */
++#define RXTX_REG2_RESETB_INDEX 15
++#define RXTX_REG2_RESETB_WIDTH 1
++#define RXTX_REG3_TX_DATA_RATE_INDEX 14
++#define RXTX_REG3_TX_DATA_RATE_WIDTH 2
++#define RXTX_REG3_TX_WORD_MODE_INDEX 11
++#define RXTX_REG3_TX_WORD_MODE_WIDTH 3
++#define RXTX_REG5_TXAMP_CNTL_INDEX 7
++#define RXTX_REG5_TXAMP_CNTL_WIDTH 4
++#define RXTX_REG6_RX_DATA_RATE_INDEX 9
++#define RXTX_REG6_RX_DATA_RATE_WIDTH 2
++#define RXTX_REG6_RX_WORD_MODE_INDEX 11
++#define RXTX_REG6_RX_WORD_MODE_WIDTH 3
++#define RXTX_REG20_BLWC_ENA_INDEX 2
++#define RXTX_REG20_BLWC_ENA_WIDTH 1
++#define RXTX_REG53_RX_PLLSELECT_INDEX 15
++#define RXTX_REG53_RX_PLLSELECT_WIDTH 1
++#define RXTX_REG53_TX_PLLSELECT_INDEX 14
++#define RXTX_REG53_TX_PLLSELECT_WIDTH 1
++#define RXTX_REG53_PI_SPD_SEL_CDR_INDEX 10
++#define RXTX_REG53_PI_SPD_SEL_CDR_WIDTH 4
++#define RXTX_REG114_PQ_REG_INDEX 9
++#define RXTX_REG114_PQ_REG_WIDTH 7
++#define RXTX_REG115_FORCE_LAT_CAL_START_INDEX 2
++#define RXTX_REG115_FORCE_LAT_CAL_START_WIDTH 1
++#define RXTX_REG115_FORCE_SUM_CAL_START_INDEX 1
++#define RXTX_REG115_FORCE_SUM_CAL_START_WIDTH 1
++#define RXTX_REG142_SUM_CALIB_DONE_INDEX 15
++#define RXTX_REG142_SUM_CALIB_DONE_WIDTH 1
++#define RXTX_REG142_SUM_CALIB_ERR_INDEX 14
++#define RXTX_REG142_SUM_CALIB_ERR_WIDTH 1
++#define RXTX_REG142_LAT_CALIB_DONE_INDEX 11
++#define RXTX_REG142_LAT_CALIB_DONE_WIDTH 1
++
++#define RXTX_FULL_RATE 0x0
++#define RXTX_HALF_RATE 0x1
++#define RXTX_FIFTH_RATE 0x3
++#define RXTX_66BIT_WORD 0x7
++#define RXTX_10BIT_WORD 0x1
++#define RXTX_10G_TX_AMP 0xa
++#define RXTX_1G_TX_AMP 0xf
++#define RXTX_10G_CDR 0x7
++#define RXTX_1G_CDR 0x2
++#define RXTX_10G_PLL 0x1
++#define RXTX_1G_PLL 0x0
++#define RXTX_10G_PQ 0x1e
++#define RXTX_1G_PQ 0xa
++
++
++DEFINE_SPINLOCK(cmu_lock);
++
+ enum amd_xgbe_phy_an {
+ AMD_XGBE_AN_READY = 0,
+ AMD_XGBE_AN_START,
+@@ -316,29 +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;
+- struct resource *sir0_res;
+- struct resource *sir1_res;
++ struct resource *cmu_res;
+
+ /* SerDes related mmio registers */
+ void __iomem *rxtx_regs; /* SerDes Rx/Tx CSRs */
+- void __iomem *sir0_regs; /* SerDes integration registers (1/2) */
+- void __iomem *sir1_regs; /* SerDes integration registers (2/2) */
++ void __iomem *cmu_regs; /* SerDes CMU CSRs */
++
++ unsigned int serdes_channel;
++ unsigned int speed_set;
+
+ /* Maintain link status for re-starting auto-negotiation */
+ unsigned int link;
+- unsigned int speed_set;
++ enum amd_xgbe_phy_mode mode;
+
+ /* Auto-negotiation state machine support */
+ struct mutex an_mutex;
+@@ -348,7 +287,6 @@ struct amd_xgbe_phy_priv {
+ enum amd_xgbe_phy_rx kx_state;
+ struct work_struct an_work;
+ struct workqueue_struct *an_workqueue;
+- unsigned int parallel_detect;
+ };
+
+ static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev)
+@@ -401,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;
++ u16 val, mask;
+
-+#ifndef __XGENE_ENET_MAIN_H__
-+#define __XGENE_ENET_MAIN_H__
++ /* Assert Rx and Tx ratechange in CMU_reg16 */
++ val = XCMU_IOREAD(priv, CMU_REG16);
+
+- /* Assert Rx and Tx ratechange */
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, RATECHANGE, 1);
++ mask = (1 << (CMU_REG16_TX_RATE_CHANGE_BASE -
++ (priv->serdes_channel * CMU_REG16_RATE_CHANGE_DECR))) |
++ (1 << (CMU_REG16_RX_RATE_CHANGE_BASE -
++ (priv->serdes_channel * CMU_REG16_RATE_CHANGE_DECR)));
++ val |= mask;
+
-+#include <linux/clk.h>
-+#include <linux/of_platform.h>
-+#include <linux/of_net.h>
-+#include <linux/of_mdio.h>
-+#include <linux/module.h>
-+#include <net/ip.h>
-+#include <linux/prefetch.h>
-+#include <linux/if_vlan.h>
-+#include <linux/phy.h>
-+#include "xgene_enet_hw.h"
-+
-+#define XGENE_DRV_VERSION "v1.0"
-+#define XGENE_ENET_MAX_MTU 1536
-+#define SKB_BUFFER_SIZE (XGENE_ENET_MAX_MTU - NET_IP_ALIGN)
-+#define NUM_PKT_BUF 64
-+#define NUM_BUFPOOL 32
-+
-+/* software context of a descriptor ring */
-+struct xgene_enet_desc_ring {
-+ struct net_device *ndev;
-+ u16 id;
-+ u16 num;
-+ u16 head;
-+ u16 tail;
-+ u16 slots;
-+ u16 irq;
-+ u32 size;
-+ u32 state[NUM_RING_CONFIG];
-+ void __iomem *cmd_base;
-+ void __iomem *cmd;
-+ dma_addr_t dma;
-+ u16 dst_ring_num;
-+ u8 nbufpool;
-+ struct sk_buff *(*rx_skb);
-+ struct sk_buff *(*cp_skb);
-+ enum xgene_enet_ring_cfgsize cfgsize;
-+ struct xgene_enet_desc_ring *cp_ring;
-+ struct xgene_enet_desc_ring *buf_pool;
-+ struct napi_struct napi;
-+ union {
-+ void *desc_addr;
-+ struct xgene_enet_raw_desc *raw_desc;
-+ struct xgene_enet_raw_desc16 *raw_desc16;
-+ };
-+};
++ XCMU_IOWRITE(priv, CMU_REG16, val);
+ }
+
+ static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev)
+ {
+ struct amd_xgbe_phy_priv *priv = phydev->priv;
++ u16 val, mask;
+ unsigned int wait;
+- u16 status;
+
+- /* Release Rx and Tx ratechange */
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, RATECHANGE, 0);
++ /* Release Rx and Tx ratechange for proper channel in CMU_reg16 */
++ val = XCMU_IOREAD(priv, CMU_REG16);
++
++ mask = (1 << (CMU_REG16_TX_RATE_CHANGE_BASE -
++ (priv->serdes_channel * CMU_REG16_RATE_CHANGE_DECR))) |
++ (1 << (CMU_REG16_RX_RATE_CHANGE_BASE -
++ (priv->serdes_channel * CMU_REG16_RATE_CHANGE_DECR)));
++ val &= ~mask;
+
+- /* Wait for Rx and Tx ready */
++ XCMU_IOWRITE(priv, CMU_REG16, val);
++
++ /* Wait for Rx and Tx ready in CMU_reg15 */
++ mask = (1 << priv->serdes_channel) |
++ (1 << (priv->serdes_channel + 8));
+ wait = XGBE_PHY_RATECHANGE_COUNT;
+ while (wait--) {
+- usleep_range(50, 75);
++ udelay(50);
+
+- status = XSIR0_IOREAD(priv, SIR0_STATUS);
+- if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
+- XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
++ val = XCMU_IOREAD(priv, CMU_REG15);
++ if ((val & mask) == mask)
+ return;
+ }
+
+ netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n",
+- status);
++ val);
+ }
+
+ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
+@@ -435,8 +391,8 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
+ struct amd_xgbe_phy_priv *priv = phydev->priv;
+ int ret;
+
+- /* Enable KR training */
+- ret = amd_xgbe_an_enable_kr_training(phydev);
++ /* Disable KR training */
++ ret = amd_xgbe_an_disable_kr_training(phydev);
+ if (ret < 0)
+ return ret;
+
+@@ -462,19 +418,32 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
+ return ret;
+
+ /* Set SerDes to 10G speed */
++ spin_lock(&cmu_lock);
+
-+/* ethernet private data */
-+struct xgene_enet_pdata {
-+ struct net_device *ndev;
-+ struct mii_bus *mdio_bus;
-+ struct phy_device *phy_dev;
-+ int phy_speed;
-+ struct clk *clk;
-+ struct platform_device *pdev;
-+ struct xgene_enet_desc_ring *tx_ring;
-+ struct xgene_enet_desc_ring *rx_ring;
-+ char *dev_name;
-+ u32 rx_buff_cnt;
-+ u32 tx_qcnt_hi;
-+ u32 cp_qcnt_hi;
-+ u32 cp_qcnt_low;
-+ u32 rx_irq;
-+ void __iomem *eth_csr_addr;
-+ void __iomem *eth_ring_if_addr;
-+ void __iomem *eth_diag_csr_addr;
-+ void __iomem *mcx_mac_addr;
-+ void __iomem *mcx_stats_addr;
-+ void __iomem *mcx_mac_csr_addr;
-+ void __iomem *base_addr;
-+ void __iomem *ring_csr_addr;
-+ void __iomem *ring_cmd_addr;
-+ u32 phy_addr;
-+ int phy_mode;
-+ u32 speed;
-+ u16 rm;
-+ struct rtnl_link_stats64 stats;
-+ /* statistics lock */
-+ spinlock_t stats_lock;
-+};
+ amd_xgbe_phy_serdes_start_ratechange(phydev);
+
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_10000_TXAMP);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_10000_CDR);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_DATA_RATE, RXTX_FULL_RATE);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_WORD_MODE, RXTX_66BIT_WORD);
+
+- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_10000_BLWC);
+- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10000_PQ);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG5, TXAMP_CNTL, RXTX_10G_TX_AMP);
+
-+void xgene_enet_set_ethtool_ops(struct net_device *netdev);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_FULL_RATE);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_66BIT_WORD);
+
-+#endif /* __XGENE_ENET_MAIN_H__ */
-diff --git a/drivers/of/address.c b/drivers/of/address.c
-index 5edfcb0..cbbaed2 100644
---- a/drivers/of/address.c
-+++ b/drivers/of/address.c
-@@ -5,6 +5,7 @@
- #include <linux/module.h>
- #include <linux/of_address.h>
- #include <linux/pci_regs.h>
-+#include <linux/slab.h>
- #include <linux/string.h>
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, 0);
++
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, RX_PLLSELECT, RXTX_10G_PLL);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, TX_PLLSELECT, RXTX_10G_PLL);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, PI_SPD_SEL_CDR, RXTX_10G_CDR);
++
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10G_PQ);
+
+ amd_xgbe_phy_serdes_complete_ratechange(phydev);
- /* Max address size we deal with */
-@@ -601,12 +602,72 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
++ spin_unlock(&cmu_lock);
++
++ priv->mode = AMD_XGBE_MODE_KR;
++
+ return 0;
}
- EXPORT_SYMBOL(of_get_address);
-+struct io_range {
-+ struct list_head list;
-+ phys_addr_t start;
-+ resource_size_t size;
-+};
+@@ -510,19 +479,32 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
+ return ret;
+
+ /* Set SerDes to 2.5G speed */
++ spin_lock(&cmu_lock);
+
-+static LIST_HEAD(io_range_list);
+ amd_xgbe_phy_serdes_start_ratechange(phydev);
+
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_2500_TXAMP);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_2500_CDR);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_DATA_RATE, RXTX_HALF_RATE);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_WORD_MODE, RXTX_10BIT_WORD);
+
-+/*
-+ * Record the PCI IO range (expressed as CPU physical address + size).
-+ * Return a negative value if an error has occured, zero otherwise
-+ */
-+int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size)
-+{
-+#ifdef PCI_IOBASE
-+ struct io_range *res;
-+ resource_size_t allocated_size = 0;
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG5, TXAMP_CNTL, RXTX_1G_TX_AMP);
+
-+ /* check if the range hasn't been previously recorded */
-+ list_for_each_entry(res, &io_range_list, list) {
-+ if (addr >= res->start && addr + size <= res->start + size)
-+ return 0;
-+ allocated_size += res->size;
-+ }
++ 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_REG20, BLWC_ENA, 1);
+
-+ /* range not registed yet, check for available space */
-+ if (allocated_size + size - 1 > IO_SPACE_LIMIT)
-+ return -E2BIG;
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, RX_PLLSELECT, RXTX_1G_PLL);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, TX_PLLSELECT, RXTX_1G_PLL);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, PI_SPD_SEL_CDR, RXTX_1G_CDR);
+
-+ /* add the range to the list */
-+ res = kzalloc(sizeof(*res), GFP_KERNEL);
-+ if (!res)
-+ return -ENOMEM;
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1G_PQ);
+
+ amd_xgbe_phy_serdes_complete_ratechange(phydev);
+
++ spin_unlock(&cmu_lock);
+
-+ res->start = addr;
-+ res->size = size;
++ priv->mode = AMD_XGBE_MODE_KX;
+
-+ list_add_tail(&res->list, &io_range_list);
+ return 0;
+ }
+
+@@ -558,47 +540,33 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
+ return ret;
+
+ /* Set SerDes to 1G speed */
++ spin_lock(&cmu_lock);
+
+ amd_xgbe_phy_serdes_start_ratechange(phydev);
+
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_1000_TXAMP);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL);
+- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_1000_CDR);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_DATA_RATE, RXTX_FIFTH_RATE);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_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_REG5, TXAMP_CNTL, RXTX_1G_TX_AMP);
+
+- amd_xgbe_phy_serdes_complete_ratechange(phydev);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_FIFTH_RATE);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_10BIT_WORD);
+
+- return 0;
+-}
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, 1);
+
+-static int amd_xgbe_phy_cur_mode(struct phy_device *phydev,
+- enum amd_xgbe_phy_mode *mode)
+-{
+- int ret;
+-
+- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
+- if (ret < 0)
+- return ret;
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, RX_PLLSELECT, RXTX_1G_PLL);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, TX_PLLSELECT, RXTX_1G_PLL);
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, PI_SPD_SEL_CDR, RXTX_1G_CDR);
+
+- if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
+- *mode = AMD_XGBE_MODE_KR;
+- else
+- *mode = AMD_XGBE_MODE_KX;
++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1G_PQ);
+
+- return 0;
+-}
++ amd_xgbe_phy_serdes_complete_ratechange(phydev);
+
+-static bool amd_xgbe_phy_in_kr_mode(struct phy_device *phydev)
+-{
+- enum amd_xgbe_phy_mode mode;
++ spin_unlock(&cmu_lock);
+
+- if (amd_xgbe_phy_cur_mode(phydev, &mode))
+- return false;
++ priv->mode = AMD_XGBE_MODE_KX;
+
+- return (mode == AMD_XGBE_MODE_KR);
+ return 0;
-+#else
-+ return -EINVAL;
-+#endif
-+}
-+
- unsigned long __weak pci_address_to_pio(phys_addr_t address)
+ }
+
+ static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
+@@ -607,7 +575,7 @@ static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
+ int ret;
+
+ /* If we are in KR switch to KX, and vice-versa */
+- if (amd_xgbe_phy_in_kr_mode(phydev)) {
++ if (priv->mode == AMD_XGBE_MODE_KR) {
+ if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000)
+ ret = amd_xgbe_phy_gmii_mode(phydev);
+ else
+@@ -619,20 +587,15 @@ static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
+ return ret;
+ }
+
+-static int amd_xgbe_phy_set_mode(struct phy_device *phydev,
+- enum amd_xgbe_phy_mode mode)
++static enum amd_xgbe_phy_an amd_xgbe_an_switch_mode(struct phy_device *phydev)
{
-+#ifdef PCI_IOBASE
-+ struct io_range *res;
-+ resource_size_t offset = 0;
-+
-+ list_for_each_entry(res, &io_range_list, list) {
-+ if (address >= res->start &&
-+ address < res->start + res->size) {
-+ return res->start - address + offset;
-+ }
-+ offset += res->size;
-+ }
-+
-+ return (unsigned long)-1;
-+#else
- if (address > IO_SPACE_LIMIT)
- return (unsigned long)-1;
+- enum amd_xgbe_phy_mode cur_mode;
+ int ret;
- return (unsigned long) address;
-+#endif
+- ret = amd_xgbe_phy_cur_mode(phydev, &cur_mode);
+- if (ret)
+- return ret;
+-
+- if (mode != cur_mode)
+- ret = amd_xgbe_phy_switch_mode(phydev);
++ ret = amd_xgbe_phy_switch_mode(phydev);
++ if (ret < 0)
++ return AMD_XGBE_AN_ERROR;
+
+- return ret;
++ return AMD_XGBE_AN_START;
}
- static int __of_address_to_resource(struct device_node *dev,
-@@ -811,3 +872,50 @@ bool of_dma_is_coherent(struct device_node *np)
- return false;
+ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
+@@ -643,8 +606,8 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
+
+ *state = AMD_XGBE_RX_COMPLETE;
+
+- /* If we're not in KR mode then we're done */
+- if (!amd_xgbe_phy_in_kr_mode(phydev))
++ /* If we're in KX mode then we're done */
++ if (priv->mode == AMD_XGBE_MODE_KX)
+ return AMD_XGBE_AN_EVENT;
+
+ /* Enable/Disable FEC */
+@@ -672,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;
+
+- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1);
+-
+ ret |= 0x01;
+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
+
+- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0);
+-
+ return AMD_XGBE_AN_EVENT;
+ }
+
+@@ -702,6 +661,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev,
+ static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
+ enum amd_xgbe_phy_rx *state)
+ {
++ struct amd_xgbe_phy_priv *priv = phydev->priv;
+ unsigned int link_support;
+ int ret, ad_reg, lp_reg;
+
+@@ -711,9 +671,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
+ return AMD_XGBE_AN_ERROR;
+
+ /* Check for a supported mode, otherwise restart in a different one */
+- link_support = amd_xgbe_phy_in_kr_mode(phydev) ? 0x80 : 0x20;
++ link_support = (priv->mode == AMD_XGBE_MODE_KR) ? 0x80 : 0x20;
+ if (!(ret & link_support))
+- return AMD_XGBE_AN_INCOMPAT_LINK;
++ return amd_xgbe_an_switch_mode(phydev);
+
+ /* Check Extended Next Page support */
+ ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+@@ -754,7 +714,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev)
+ int ret;
+
+ /* Be sure we aren't looping trying to negotiate */
+- if (amd_xgbe_phy_in_kr_mode(phydev)) {
++ if (priv->mode == AMD_XGBE_MODE_KR) {
+ if (priv->kr_state != AMD_XGBE_RX_READY)
+ return AMD_XGBE_AN_NO_LINK;
+ priv->kr_state = AMD_XGBE_RX_BPA;
+@@ -817,13 +777,6 @@ static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev)
+ /* Enable and start auto-negotiation */
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
+- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL);
+- if (ret < 0)
+- return AMD_XGBE_AN_ERROR;
+-
+- ret |= MDIO_KR_CTRL_PDETECT;
+- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL, ret);
+-
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
+ if (ret < 0)
+ return AMD_XGBE_AN_ERROR;
+@@ -864,8 +817,8 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
+ enum amd_xgbe_phy_rx *state;
+ int ret;
+
+- state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state
+- : &priv->kx_state;
++ state = (priv->mode == AMD_XGBE_MODE_KR) ? &priv->kr_state
++ : &priv->kx_state;
+
+ switch (*state) {
+ case AMD_XGBE_RX_BPA:
+@@ -885,13 +838,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
+
+ static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev)
+ {
+- int ret;
+-
+- ret = amd_xgbe_phy_switch_mode(phydev);
+- if (ret)
+- return AMD_XGBE_AN_ERROR;
+-
+- return AMD_XGBE_AN_START;
++ return amd_xgbe_an_switch_mode(phydev);
}
- EXPORT_SYMBOL_GPL(of_dma_is_coherent);
+
+ static void amd_xgbe_an_state_machine(struct work_struct *work)
+@@ -904,10 +851,6 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
+ int sleep;
+ unsigned int an_supported = 0;
+
+- /* Start in KX mode */
+- if (amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX))
+- priv->an_state = AMD_XGBE_AN_ERROR;
+-
+ while (1) {
+ mutex_lock(&priv->an_mutex);
+
+@@ -915,9 +858,8 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
+
+ switch (priv->an_state) {
+ case AMD_XGBE_AN_START:
+- an_supported = 0;
+- priv->parallel_detect = 0;
+ priv->an_state = amd_xgbe_an_start(phydev);
++ an_supported = 0;
+ break;
+
+ case AMD_XGBE_AN_EVENT:
+@@ -934,7 +876,6 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
+ break;
+
+ case AMD_XGBE_AN_COMPLETE:
+- priv->parallel_detect = an_supported ? 0 : 1;
+ netdev_info(phydev->attached_dev, "%s successful\n",
+ an_supported ? "Auto negotiation"
+ : "Parallel detection");
+@@ -1069,6 +1010,7 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
+ {
+ struct amd_xgbe_phy_priv *priv = phydev->priv;
+ u32 mmd_mask = phydev->c45_ids.devices_in_package;
++ int ret;
+
+ if (phydev->autoneg != AUTONEG_ENABLE)
+ return amd_xgbe_phy_setup_forced(phydev);
+@@ -1077,6 +1019,11 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
+ if (!(mmd_mask & MDIO_DEVS_AN))
+ return -EINVAL;
+
++ /* Get the current speed mode */
++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
++ if (ret < 0)
++ return ret;
+
-+/*
-+ * of_pci_range_to_resource - Create a resource from an of_pci_range
-+ * @range: the PCI range that describes the resource
-+ * @np: device node where the range belongs to
-+ * @res: pointer to a valid resource that will be updated to
-+ * reflect the values contained in the range.
-+ *
-+ * Returns EINVAL if the range cannot be converted to resource.
-+ *
-+ * Note that if the range is an IO range, the resource will be converted
-+ * using pci_address_to_pio() which can fail if it is called too early or
-+ * if the range cannot be matched to any host bridge IO space (our case here).
-+ * To guard against that we try to register the IO range first.
-+ * If that fails we know that pci_address_to_pio() will do too.
-+ */
-+int of_pci_range_to_resource(struct of_pci_range *range,
-+ struct device_node *np, struct resource *res)
+ /* Start/Restart the auto-negotiation state machine */
+ mutex_lock(&priv->an_mutex);
+ priv->an_result = AMD_XGBE_AN_READY;
+@@ -1166,14 +1113,18 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev)
+ {
+ struct amd_xgbe_phy_priv *priv = phydev->priv;
+ u32 mmd_mask = phydev->c45_ids.devices_in_package;
+- int ret, ad_ret, lp_ret;
++ int ret, mode, ad_ret, lp_ret;
+
+ ret = amd_xgbe_phy_update_link(phydev);
+ if (ret)
+ return ret;
+
+- if ((phydev->autoneg == AUTONEG_ENABLE) &&
+- !priv->parallel_detect) {
++ mode = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
++ if (mode < 0)
++ return mode;
++ mode &= MDIO_PCS_CTRL2_TYPE;
++
++ if (phydev->autoneg == AUTONEG_ENABLE) {
+ if (!(mmd_mask & MDIO_DEVS_AN))
+ return -EINVAL;
+
+@@ -1204,39 +1155,40 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev)
+ ad_ret &= lp_ret;
+ if (ad_ret & 0x80) {
+ phydev->speed = SPEED_10000;
+- ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR);
+- if (ret)
+- return ret;
++ if (mode != MDIO_PCS_CTRL2_10GBR) {
++ ret = amd_xgbe_phy_xgmii_mode(phydev);
++ if (ret < 0)
++ return ret;
++ }
+ } else {
+- switch (priv->speed_set) {
+- case AMD_XGBE_PHY_SPEEDSET_1000_10000:
+- phydev->speed = SPEED_1000;
+- break;
++ int (*mode_fcn)(struct phy_device *);
+
+- case AMD_XGBE_PHY_SPEEDSET_2500_10000:
++ if (priv->speed_set ==
++ AMD_XGBE_PHY_SPEEDSET_1000_10000) {
++ phydev->speed = SPEED_1000;
++ mode_fcn = amd_xgbe_phy_gmii_mode;
++ } else {
+ phydev->speed = SPEED_2500;
+- break;
++ mode_fcn = amd_xgbe_phy_gmii_2500_mode;
+ }
+
+- ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX);
+- if (ret)
+- return ret;
++ if (mode == MDIO_PCS_CTRL2_10GBR) {
++ ret = mode_fcn(phydev);
++ if (ret < 0)
++ return ret;
++ }
+ }
+
+ phydev->duplex = DUPLEX_FULL;
+ } else {
+- if (amd_xgbe_phy_in_kr_mode(phydev)) {
++ if (mode == MDIO_PCS_CTRL2_10GBR) {
+ phydev->speed = SPEED_10000;
+ } else {
+- switch (priv->speed_set) {
+- case AMD_XGBE_PHY_SPEEDSET_1000_10000:
++ if (priv->speed_set ==
++ AMD_XGBE_PHY_SPEEDSET_1000_10000)
+ phydev->speed = SPEED_1000;
+- break;
+-
+- case AMD_XGBE_PHY_SPEEDSET_2500_10000:
++ else
+ phydev->speed = SPEED_2500;
+- break;
+- }
+ }
+ phydev->duplex = DUPLEX_FULL;
+ phydev->pause = 0;
+@@ -1288,29 +1240,188 @@ unlock:
+ return ret;
+ }
+
++static int amd_xgbe_phy_map_resources(struct amd_xgbe_phy_priv *priv,
++ struct platform_device *phy_pdev,
++ unsigned int phy_resnum)
+{
-+ int err;
-+ res->flags = range->flags;
-+ res->parent = res->child = res->sibling = NULL;
-+ res->name = np->full_name;
++ struct device *dev = priv->dev;
++ int ret;
+
-+ if (res->flags & IORESOURCE_IO) {
-+ unsigned long port = -1;
-+ err = pci_register_io_range(range->cpu_addr, range->size);
-+ if (err)
-+ goto invalid_range;
-+ port = pci_address_to_pio(range->cpu_addr);
-+ if (port == (unsigned long)-1) {
-+ err = -EINVAL;
-+ goto invalid_range;
-+ }
-+ res->start = port;
-+ } else {
-+ res->start = range->cpu_addr;
++ /* 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);
+ }
-+ res->end = res->start + range->size - 1;
++
++ /* 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(phy_pdev, IORESOURCE_MEM,
++ phy_resnum++);
++ if (!priv->cmu_res) {
++ dev_err(dev, "cmu invalid resource\n");
++ ret = -EINVAL;
++ goto err_rxtx;
++ }
++ priv->cmu_regs = devm_ioremap_nocache(dev, priv->cmu_res->start,
++ resource_size(priv->cmu_res));
++ if (!priv->cmu_regs) {
++ dev_err(dev, "cmu ioremap failed\n");
++ ret = -ENOMEM;
++ goto err_rxtx;
++ }
++
+ return 0;
+
-+invalid_range:
-+ res->start = (resource_size_t)OF_BAD_ADDR;
-+ res->end = (resource_size_t)OF_BAD_ADDR;
-+ return err;
++err_rxtx:
++ devm_iounmap(dev, priv->rxtx_regs);
++ devm_release_mem_region(dev, priv->rxtx_res->start,
++ resource_size(priv->rxtx_res));
++
++ return ret;
+}
+
-diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
-index 8481996..e81402a 100644
---- a/drivers/of/of_pci.c
-+++ b/drivers/of/of_pci.c
-@@ -1,6 +1,7 @@
- #include <linux/kernel.h>
- #include <linux/export.h>
- #include <linux/of.h>
-+#include <linux/of_address.h>
- #include <linux/of_pci.h>
-
- static inline int __of_pci_pci_compare(struct device_node *node,
-@@ -89,6 +90,141 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
- }
- EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
-
-+/**
-+ * pci_host_bridge_of_get_ranges - Parse PCI host bridge resources from DT
-+ * @dev: device node of the host bridge having the range property
-+ * @resources: list where the range of resources will be added after DT parsing
-+ * @io_base: pointer to a variable that will contain the physical address for
-+ * the start of the I/O range.
-+ *
-+ * It is the callers job to free the @resources list if an error is returned.
-+ *
-+ * This function will parse the "ranges" property of a PCI host bridge device
-+ * node and setup the resource mapping based on its content. It is expected
-+ * that the property conforms with the Power ePAPR document.
-+ *
-+ * Each architecture is then offered the chance of applying their own
-+ * filtering of pci_host_bridge_windows based on their own restrictions by
-+ * calling pcibios_fixup_bridge_ranges(). The filtered list of windows
-+ * can then be used when creating a pci_host_bridge structure.
-+ */
-+static int pci_host_bridge_of_get_ranges(struct device_node *dev,
-+ struct list_head *resources, resource_size_t *io_base)
++static void amd_xgbe_phy_unmap_resources(struct amd_xgbe_phy_priv *priv)
+{
-+ struct resource *res;
-+ struct of_pci_range range;
-+ struct of_pci_range_parser parser;
-+ int err;
++ struct device *dev = priv->dev;
+
-+ pr_info("PCI host bridge %s ranges:\n", dev->full_name);
++ devm_iounmap(dev, priv->cmu_regs);
+
-+ /* Check for ranges property */
-+ err = of_pci_range_parser_init(&parser, dev);
-+ if (err)
-+ return err;
++ devm_iounmap(dev, priv->rxtx_regs);
++ devm_release_mem_region(dev, priv->rxtx_res->start,
++ resource_size(priv->rxtx_res));
++}
+
-+ pr_debug("Parsing ranges property...\n");
-+ for_each_of_pci_range(&parser, &range) {
-+ /* Read next ranges element */
-+ pr_debug("pci_space: 0x%08x pci_addr:0x%016llx cpu_addr:0x%016llx size:0x%016llx\n",
-+ range.pci_space, range.pci_addr, range.cpu_addr, range.size);
++#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;
+
-+ /*
-+ * If we failed translation or got a zero-sized region
-+ * then skip this range
-+ */
-+ if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
-+ continue;
++ /* Map the memory resources */
++ ret = amd_xgbe_phy_map_resources(priv, phy_pdev, 2);
++ if (ret)
++ return ret;
+
-+ res = kzalloc(sizeof(struct resource), GFP_KERNEL);
-+ if (!res)
-+ return -ENOMEM;
++ /* 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;
+
-+ err = of_pci_range_to_resource(&range, dev, res);
-+ if (err)
-+ return err;
++ /* 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;
+
-+ if (resource_type(res) == IORESOURCE_IO)
-+ *io_base = range.cpu_addr;
++ return 0;
+
-+ pci_add_resource_offset(resources, res,
-+ res->start - range.pci_addr);
-+ }
++err_resources:
++ amd_xgbe_phy_unmap_resources(priv);
+
-+ /* Apply architecture specific fixups for the ranges */
-+ return pcibios_fixup_bridge_ranges(resources);
++ return ret;
+}
++#else /* CONFIG_ACPI */
++static int amd_xgbe_phy_acpi_support(struct amd_xgbe_phy_priv *priv)
++{
++ return -EINVAL;
++}
++#endif /* CONFIG_ACPI */
+
-+static atomic_t domain_nr = ATOMIC_INIT(-1);
-+
-+/**
-+ * of_create_pci_host_bridge - Create a PCI host bridge structure using
-+ * information passed in the DT.
-+ * @parent: device owning this host bridge
-+ * @ops: pci_ops associated with the host controller
-+ * @host_data: opaque data structure used by the host controller.
-+ *
-+ * returns a pointer to the newly created pci_host_bridge structure, or
-+ * NULL if the call failed.
-+ *
-+ * This function will try to obtain the host bridge domain number by
-+ * using of_alias_get_id() call with "pci-domain" as a stem. If that
-+ * fails, a local allocator will be used that will put each host bridge
-+ * in a new domain.
-+ */
-+struct pci_host_bridge *
-+of_create_pci_host_bridge(struct device *parent, struct pci_ops *ops, void *host_data)
++#ifdef CONFIG_OF
++static int amd_xgbe_phy_of_support(struct amd_xgbe_phy_priv *priv)
+{
-+ int err, domain, busno;
-+ struct resource *bus_range;
-+ struct pci_bus *root_bus;
-+ struct pci_host_bridge *bridge;
-+ resource_size_t io_base = 0;
-+ LIST_HEAD(res);
++ 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_range = kzalloc(sizeof(*bus_range), GFP_KERNEL);
-+ if (!bus_range)
-+ return ERR_PTR(-ENOMEM);
++ 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;
++ }
+
-+ domain = of_alias_get_id(parent->of_node, "pci-domain");
-+ if (domain == -ENODEV)
-+ domain = atomic_inc_return(&domain_nr);
++ 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;
++ }
+
-+ err = of_pci_parse_bus_range(parent->of_node, bus_range);
-+ if (err) {
-+ dev_info(parent, "No bus range for %s, using default [0-255]\n",
-+ parent->of_node->full_name);
-+ bus_range->start = 0;
-+ bus_range->end = 255;
-+ bus_range->flags = IORESOURCE_BUS;
++ /* 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;
+ }
-+ busno = bus_range->start;
-+ pci_add_resource(&res, bus_range);
++ priv->serdes_channel = be32_to_cpu(*property);
+
-+ /* now parse the rest of host bridge bus ranges */
-+ err = pci_host_bridge_of_get_ranges(parent->of_node, &res, &io_base);
-+ if (err)
-+ goto err_create;
++ /* 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);
+
-+ /* then create the root bus */
-+ root_bus = pci_create_root_bus_in_domain(parent, domain, busno,
-+ ops, host_data, &res);
-+ if (IS_ERR(root_bus)) {
-+ err = PTR_ERR(root_bus);
-+ goto err_create;
-+ }
++ of_node_put(phy_node);
++
++ return 0;
+
-+ bridge = to_pci_host_bridge(root_bus->bridge);
-+ bridge->io_base = io_base;
++err_resources:
++ amd_xgbe_phy_unmap_resources(priv);
+
-+ return bridge;
++err_put:
++ of_node_put(phy_node);
+
-+err_create:
-+ pci_free_resource_list(&res);
-+ return ERR_PTR(err);
++ return ret;
++}
++#else /* CONFIG_OF */
++static int amd_xgbe_phy_of_support(struct amd_xgbe_phy_priv *priv)
++{
++ return -EINVAL;
+}
-+EXPORT_SYMBOL_GPL(of_create_pci_host_bridge);
++#endif /* CONFIG_OF */
+
- #ifdef CONFIG_PCI_MSI
+ 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;
- static LIST_HEAD(of_pci_msi_chip_list);
-diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
-index 0e5f3c9..54ceafd 100644
---- a/drivers/pci/host-bridge.c
-+++ b/drivers/pci/host-bridge.c
-@@ -16,12 +16,13 @@ static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
- return bus;
- }
+- if (!phydev->dev.of_node)
++ if (!phydev->bus || !phydev->bus->parent)
+ return -EINVAL;
--static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
-+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
- {
- struct pci_bus *root_bus = find_pci_root_bus(bus);
+- 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) {
+@@ -1318,86 +1429,54 @@ 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;
+- }
- return to_pci_host_bridge(root_bus->bridge);
+- /* 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_resources;
+ }
+
+ priv->link = 1;
+
++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
++ if (ret < 0)
++ goto err_resources;
++ if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
++ priv->mode = AMD_XGBE_MODE_KR;
++ else
++ priv->mode = AMD_XGBE_MODE_KX;
++
+ mutex_init(&priv->an_mutex);
+ INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine);
+ priv->an_workqueue = create_singlethread_workqueue(wq_name);
+ if (!priv->an_workqueue) {
+ ret = -ENOMEM;
+- goto err_sir1;
++ goto err_resources;
+ }
+
+ phydev->priv = priv;
+
+ kfree(wq_name);
+- of_dev_put(pdev);
+
+ return 0;
+
+-err_sir1:
+- devm_iounmap(dev, priv->sir1_regs);
+- devm_release_mem_region(dev, priv->sir1_res->start,
+- resource_size(priv->sir1_res));
+-
+-err_sir0:
+- devm_iounmap(dev, priv->sir0_regs);
+- devm_release_mem_region(dev, priv->sir0_res->start,
+- resource_size(priv->sir0_res));
+-
+-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);
+@@ -1405,9 +1484,6 @@ err_priv:
+ err_name:
+ kfree(wq_name);
+
+-err_pdev:
+- of_dev_put(pdev);
+-
+ return ret;
}
-+EXPORT_SYMBOL_GPL(find_pci_host_bridge);
- void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
- void (*release_fn)(struct pci_host_bridge *),
-@@ -82,3 +83,18 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
- res->end = region->end + offset;
+@@ -1424,18 +1500,7 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev)
+ flush_workqueue(priv->an_workqueue);
+ destroy_workqueue(priv->an_workqueue);
+
+- /* Release resources */
+- devm_iounmap(dev, priv->sir1_regs);
+- devm_release_mem_region(dev, priv->sir1_res->start,
+- resource_size(priv->sir1_res));
+-
+- devm_iounmap(dev, priv->sir0_regs);
+- devm_release_mem_region(dev, priv->sir0_res->start,
+- resource_size(priv->sir0_res));
+-
+- 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_kfree(dev, priv);
}
- EXPORT_SYMBOL(pcibios_bus_to_resource);
-+
-+/**
-+ * Simple version of the platform specific code for filtering the list
-+ * of resources obtained from the ranges declaration in DT.
-+ *
-+ * Platforms can override this function in order to impose stronger
-+ * constraints onto the list of resources that a host bridge can use.
-+ * The filtered list will then be used to create a root bus and associate
-+ * it with the host bridge.
-+ *
-+ */
-+int __weak pcibios_fixup_bridge_ranges(struct list_head *resources)
-+{
-+ return 0;
-+}
-diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
-index 21df477..3b988a2 100644
---- a/drivers/pci/host/Kconfig
-+++ b/drivers/pci/host/Kconfig
-@@ -46,4 +46,14 @@ config PCI_HOST_GENERIC
- Say Y here if you want to support a simple generic PCI host
- controller, such as the one emulated by kvmtool.
-
-+config PCI_XGENE
-+ bool "X-Gene PCIe controller"
-+ depends on ARCH_XGENE
-+ depends on OF
-+ select PCIEPORTBUS
-+ help
-+ Say Y here if you want internal PCI support on APM X-Gene SoC.
-+ There are 5 internal PCIe ports available. Each port is GEN3 capable
-+ and have varied lanes from x1 to x8.
-+
- endmenu
-diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
-index 611ba4b..0801606 100644
---- a/drivers/pci/host/Makefile
-+++ b/drivers/pci/host/Makefile
-@@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
- obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
- obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
- obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
-+obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
-diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
-new file mode 100644
-index 0000000..7bf4ac7
---- /dev/null
-+++ b/drivers/pci/host/pci-xgene.c
-@@ -0,0 +1,725 @@
-+/**
-+ * APM X-Gene PCIe Driver
-+ *
-+ * Copyright (c) 2013 Applied Micro Circuits Corporation.
-+ *
-+ * Author: Tanmay Inamdar <tinamdar@apm.com>.
+diff --git a/drivers/of/base.c b/drivers/of/base.c
+index 3823edf..4c2ccde 100644
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -1250,6 +1250,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.
+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
++ * @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
+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
++ * 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.
+ */
-+#include <linux/clk-private.h>
-+#include <linux/delay.h>
-+#include <linux/io.h>
-+#include <linux/jiffies.h>
-+#include <linux/memblock.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_pci.h>
-+#include <linux/pci.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+
-+#define PCIECORE_LTSSM 0x4c
-+#define PCIECORE_CTLANDSTATUS 0x50
-+#define INTXSTATUSMASK 0x6c
-+#define PIM1_1L 0x80
-+#define IBAR2 0x98
-+#define IR2MSK 0x9c
-+#define PIM2_1L 0xa0
-+#define IBAR3L 0xb4
-+#define IR3MSKL 0xbc
-+#define PIM3_1L 0xc4
-+#define OMR1BARL 0x100
-+#define OMR2BARL 0x118
-+#define OMR3BARL 0x130
-+#define CFGBARL 0x154
-+#define CFGBARH 0x158
-+#define CFGCTL 0x15c
-+#define RTDID 0x160
-+#define BRIDGE_CFG_0 0x2000
-+#define BRIDGE_CFG_1 0x2004
-+#define BRIDGE_CFG_4 0x2010
-+#define BRIDGE_CFG_32 0x2030
-+#define BRIDGE_CFG_14 0x2038
-+#define BRIDGE_CTRL_1 0x2204
-+#define BRIDGE_CTRL_2 0x2208
-+#define BRIDGE_CTRL_5 0x2214
-+#define BRIDGE_STATUS_0 0x2600
-+#define MEM_RAM_SHUTDOWN 0xd070
-+#define BLOCK_MEM_RDY 0xd074
-+
-+#define DEVICE_PORT_TYPE_MASK 0x03c00000
-+#define PM_FORCE_RP_MODE_MASK 0x00000400
-+#define SWITCH_PORT_MODE_MASK 0x00000800
-+#define CLASS_CODE_MASK 0xffffff00
-+#define LINK_UP_MASK 0x00000100
-+#define AER_OPTIONAL_ERROR_EN 0xffc00000
-+#define XGENE_PCIE_DEV_CTRL 0x2f0f
-+#define AXI_EP_CFG_ACCESS 0x10000
-+#define ENABLE_ASPM 0x08000000
-+#define XGENE_PORT_TYPE_RC 0x05000000
-+#define BLOCK_MEM_RDY_VAL 0xFFFFFFFF
-+#define EN_COHERENCY 0xF0000000
-+#define EN_REG 0x00000001
-+#define OB_LO_IO 0x00000002
-+#define XGENE_PCIE_VENDORID 0xE008
-+#define XGENE_PCIE_DEVICEID 0xE004
-+#define XGENE_PCIE_ECC_TIMEOUT 10 /* ms */
-+#define XGENE_LTSSM_DETECT_WAIT 20 /* ms */
-+#define XGENE_LTSSM_L0_WAIT 4 /* ms */
-+#define SZ_1T (SZ_1G*1024ULL)
-+#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe)
-+
-+struct xgene_pcie_port {
-+ struct device_node *node;
-+ struct device *dev;
-+ struct clk *clk;
-+ void __iomem *csr_base;
-+ void __iomem *cfg_base;
-+ u8 link_up;
-+};
-+
-+static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
-+{
-+ return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags;
-+}
-+
-+/* PCIE Configuration Out/In */
-+static inline void xgene_pcie_cfg_out32(void __iomem *addr, int offset, u32 val)
-+{
-+ writel(val, addr + offset);
-+}
-+
-+static inline void xgene_pcie_cfg_out16(void __iomem *addr, int offset, u16 val)
-+{
-+ u32 val32 = readl(addr + (offset & ~0x3));
-+
-+ switch (offset & 0x3) {
-+ case 2:
-+ val32 &= ~0xFFFF0000;
-+ val32 |= (u32)val << 16;
-+ break;
-+ case 0:
-+ default:
-+ val32 &= ~0xFFFF;
-+ val32 |= val;
-+ break;
-+ }
-+ writel(val32, addr + (offset & ~0x3));
-+}
-+
-+static inline void xgene_pcie_cfg_out8(void __iomem *addr, int offset, u8 val)
-+{
-+ u32 val32 = readl(addr + (offset & ~0x3));
-+
-+ switch (offset & 0x3) {
-+ case 0:
-+ val32 &= ~0xFF;
-+ val32 |= val;
-+ break;
-+ case 1:
-+ val32 &= ~0xFF00;
-+ val32 |= (u32)val << 8;
-+ break;
-+ case 2:
-+ val32 &= ~0xFF0000;
-+ val32 |= (u32)val << 16;
-+ break;
-+ case 3:
-+ default:
-+ val32 &= ~0xFF000000;
-+ val32 |= (u32)val << 24;
-+ break;
-+ }
-+ writel(val32, addr + (offset & ~0x3));
-+}
-+
-+static inline void xgene_pcie_cfg_in32(void __iomem *addr, int offset, u32 *val)
++int of_property_read_u64_array(const struct device_node *np,
++ const char *propname, u64 *out_values,
++ size_t sz)
+{
-+ *val = readl(addr + offset);
-+}
++ const __be32 *val = of_find_property_value_of_size(np, propname,
++ (sz * sizeof(*out_values)));
+
-+static inline void
-+xgene_pcie_cfg_in16(void __iomem *addr, int offset, u32 *val)
-+{
-+ *val = readl(addr + (offset & ~0x3));
++ if (IS_ERR(val))
++ return PTR_ERR(val);
+
-+ switch (offset & 0x3) {
-+ case 2:
-+ *val >>= 16;
-+ break;
++ while (sz--) {
++ *out_values++ = of_read_number(val, 2);
++ val += 2;
+ }
-+
-+ *val &= 0xFFFF;
++ return 0;
+}
+
-+static inline void
-+xgene_pcie_cfg_in8(void __iomem *addr, int offset, u32 *val)
-+{
-+ *val = readl(addr + (offset & ~0x3));
-+
-+ switch (offset & 0x3) {
-+ case 3:
-+ *val = *val >> 24;
-+ break;
-+ case 2:
-+ *val = *val >> 16;
-+ break;
-+ case 1:
-+ *val = *val >> 8;
-+ break;
-+ }
-+ *val &= 0xFF;
-+}
++/**
+ * 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.
+diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
+index 2988fe1..9029d59c 100644
+--- a/drivers/pci/host/pci-xgene.c
++++ b/drivers/pci/host/pci-xgene.c
+@@ -29,6 +29,7 @@
+ #include <linux/pci.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
++#include <linux/acpi.h>
+
+ #define PCIECORE_CTLANDSTATUS 0x50
+ #define PIM1_1L 0x80
+@@ -235,6 +236,13 @@ static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
+ break;
+ case 2:
+ xgene_pcie_cfg_in16(addr, offset, val);
++ /* FIXME.
++ * Something wrong with Configuration Request Retry Status
++ * on this hw. Pretend it isn't supported until the problem
++ * gets sorted out properly.
++ */
++ if (pci_is_root_bus(bus) && offset == (0x40 + PCI_EXP_RTCAP))
++ *val &= ~PCI_EXP_RTCAP_CRSVIS;
+ break;
+ default:
+ xgene_pcie_cfg_in32(addr, offset, val);
+@@ -600,6 +608,165 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port,
+ return 0;
+ }
+
++#ifdef CONFIG_ACPI
++struct xgene_mcfg_info {
++ void __iomem *csr_base;
++};
+
-+/* When the address bit [17:16] is 2'b01, the Configuration access will be
++/*
++ * When the address bit [17:16] is 2'b01, the Configuration access will be
+ * treated as Type 1 and it will be forwarded to external PCIe device.
+ */
-+static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
++static void __iomem *__get_cfg_base(struct pci_mmcfg_region *cfg,
++ unsigned int bus)
+{
-+ struct xgene_pcie_port *port = bus->sysdata;
-+
-+ if (bus->number >= (bus->primary + 1))
-+ return port->cfg_base + AXI_EP_CFG_ACCESS;
++ if (bus > cfg->start_bus)
++ return cfg->virt + AXI_EP_CFG_ACCESS;
+
-+ return port->cfg_base;
++ return cfg->virt;
+}
+
-+/* For Configuration request, RTDID register is used as Bus Number,
++/*
++ * For Configuration request, RTDID register is used as Bus Number,
+ * Device Number and Function number of the header fields.
+ */
-+static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn)
++static void __set_rtdid_reg(struct pci_mmcfg_region *cfg,
++ unsigned int bus, unsigned int devfn)
+{
-+ struct xgene_pcie_port *port = bus->sysdata;
++ struct xgene_mcfg_info *info = cfg->data;
+ unsigned int b, d, f;
+ u32 rtdid_val = 0;
+
-+ b = bus->number;
++ b = bus;
+ d = PCI_SLOT(devfn);
+ f = PCI_FUNC(devfn);
+
-+ if (!pci_is_root_bus(bus))
++ if (bus != cfg->start_bus)
+ rtdid_val = (b << 8) | (d << 3) | f;
+
-+ writel(rtdid_val, port->csr_base + RTDID);
++ writel(rtdid_val, info->csr_base + RTDID);
+ /* read the register back to ensure flush */
-+ readl(port->csr_base + RTDID);
++ readl(info->csr_base + RTDID);
+}
+
-+static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
-+ int offset, int len, u32 *val)
++static int xgene_raw_pci_read(struct pci_mmcfg_region *cfg, unsigned int bus,
++ unsigned int devfn, int offset, int len, u32 *val)
+{
-+ struct xgene_pcie_port *port = bus->sysdata;
+ void __iomem *addr;
+
-+ if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
-+ return PCIBIOS_DEVICE_NOT_FOUND;
++ if (bus == cfg->start_bus) {
++ if (devfn != 0) {
++ *val = 0xffffffff;
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ }
+
-+ xgene_pcie_set_rtdid_reg(bus, devfn);
-+ addr = xgene_pcie_get_cfg_base(bus);
++ /* see xgene_pcie_hide_rc_bars() above */
++ if (offset == PCI_BASE_ADDRESS_0 ||
++ offset == PCI_BASE_ADDRESS_1) {
++ *val = 0;
++ return PCIBIOS_SUCCESSFUL;
++ }
++ }
++
++ __set_rtdid_reg(cfg, bus, devfn);
++ addr = __get_cfg_base(cfg, bus);
+ switch (len) {
+ case 1:
+ xgene_pcie_cfg_in8(addr, offset, val);
+ break;
+ case 2:
+ xgene_pcie_cfg_in16(addr, offset, val);
++ /* FIXME.
++ * Something wrong with Configuration Request Retry Status
++ * on this hw. Pretend it isn't supported until the problem
++ * gets sorted out properly.
++ */
++ if (bus == cfg->start_bus && offset == (0x40 + PCI_EXP_RTCAP))
++ *val &= ~PCI_EXP_RTCAP_CRSVIS;
+ break;
+ default:
+ xgene_pcie_cfg_in32(addr, offset, val);
@@ -7774,17 +11562,16 @@ index 0000000..7bf4ac7
+ return PCIBIOS_SUCCESSFUL;
+}
+
-+static int xgene_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
-+ int offset, int len, u32 val)
++static int xgene_raw_pci_write(struct pci_mmcfg_region *cfg, unsigned int bus,
++ unsigned int devfn, int offset, int len, u32 val)
+{
-+ struct xgene_pcie_port *port = bus->sysdata;
+ void __iomem *addr;
+
-+ if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
++ if (bus == cfg->start_bus && devfn != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
-+ xgene_pcie_set_rtdid_reg(bus, devfn);
-+ addr = xgene_pcie_get_cfg_base(bus);
++ __set_rtdid_reg(cfg, bus, devfn);
++ addr = __get_cfg_base(cfg, bus);
+ switch (len) {
+ case 1:
+ xgene_pcie_cfg_out8(addr, offset, (u8)val);
@@ -7799,2381 +11586,1780 @@ index 0000000..7bf4ac7
+ return PCIBIOS_SUCCESSFUL;
+}
+
-+static struct pci_ops xgene_pcie_ops = {
-+ .read = xgene_pcie_read_config,
-+ .write = xgene_pcie_write_config
-+};
-+
-+static void xgene_pcie_program_core(void __iomem *csr_base)
++static acpi_status find_csr_base(struct acpi_resource *acpi_res, void *data)
+{
-+ u32 val;
++ struct pci_mmcfg_region *cfg = data;
++ struct xgene_mcfg_info *info = cfg->data;
++ struct acpi_resource_fixed_memory32 *fixed32;
+
-+ val = readl(csr_base + BRIDGE_CFG_0);
-+ val |= AER_OPTIONAL_ERROR_EN;
-+ writel(val, csr_base + BRIDGE_CFG_0);
-+ writel(0x0, csr_base + INTXSTATUSMASK);
-+ val = readl(csr_base + BRIDGE_CTRL_1);
-+ val = (val & ~0xffff) | XGENE_PCIE_DEV_CTRL;
-+ writel(val, csr_base + BRIDGE_CTRL_1);
++ if (acpi_res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
++ fixed32 = &acpi_res->data.fixed_memory32;
++ info->csr_base = ioremap(fixed32->address,
++ fixed32->address_length);
++ return AE_CTRL_TERMINATE;
++ }
++ return AE_OK;
+}
+
-+static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr,
-+ u32 flags, u64 size)
++static int xgene_mcfg_fixup(struct acpi_pci_root *root,
++ struct pci_mmcfg_region *cfg)
+{
-+ u64 mask = (~(size - 1) & PCI_BASE_ADDRESS_MEM_MASK) | flags;
-+ u32 val32 = 0;
-+ u32 val;
++ struct acpi_device *device = root->device;
++ struct xgene_mcfg_info *info;
+
-+ val32 = readl(csr_base + addr);
-+ val = (val32 & 0x0000ffff) | (lower_32_bits(mask) << 16);
-+ writel(val, csr_base + addr);
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
++ if (info == NULL)
++ return -ENOMEM;
+
-+ val32 = readl(csr_base + addr + 0x04);
-+ val = (val32 & 0xffff0000) | (lower_32_bits(mask) >> 16);
-+ writel(val, csr_base + addr + 0x04);
++ cfg->data = info;
+
-+ val32 = readl(csr_base + addr + 0x04);
-+ val = (val32 & 0x0000ffff) | (upper_32_bits(mask) << 16);
-+ writel(val, csr_base + addr + 0x04);
++ acpi_walk_resources(device->handle, METHOD_NAME__CRS,
++ find_csr_base, cfg);
+
-+ val32 = readl(csr_base + addr + 0x08);
-+ val = (val32 & 0xffff0000) | (upper_32_bits(mask) >> 16);
-+ writel(val, csr_base + addr + 0x08);
++ if (!info->csr_base) {
++ kfree(info);
++ cfg->data = NULL;
++ return -ENODEV;
++ }
+
-+ return mask;
-+}
++ cfg->read = xgene_raw_pci_read;
++ cfg->write = xgene_raw_pci_write;
+
-+static void xgene_pcie_poll_linkup(struct xgene_pcie_port *port,
-+ u32 *lanes, u32 *speed)
-+{
-+ void __iomem *csr_base = port->csr_base;
-+ ulong timeout;
-+ u32 val32;
++ /* actual last bus reachable through this mmconfig */
++ cfg->end_bus = root->secondary.end;
+
-+ /*
-+ * A component enters the LTSSM Detect state within
-+ * 20ms of the end of fundamental core reset.
-+ */
-+ msleep(XGENE_LTSSM_DETECT_WAIT);
-+ port->link_up = 0;
-+ timeout = jiffies + msecs_to_jiffies(XGENE_LTSSM_L0_WAIT);
-+ while (time_before(jiffies, timeout)) {
-+ val32 = readl(csr_base + PCIECORE_CTLANDSTATUS);
-+ if (val32 & LINK_UP_MASK) {
-+ port->link_up = 1;
-+ *speed = PIPE_PHY_RATE_RD(val32);
-+ val32 = readl(csr_base + BRIDGE_STATUS_0);
-+ *lanes = val32 >> 26;
-+ break;
-+ }
-+ msleep(1);
-+ }
-+}
++ /* firmware should have done this */
++ xgene_raw_pci_write(cfg, cfg->start_bus, 0, PCI_PRIMARY_BUS, 4,
++ cfg->start_bus | ((cfg->start_bus + 1) << 8) |
++ (cfg->end_bus << 16));
+
-+static void xgene_pcie_setup_root_complex(struct xgene_pcie_port *port)
-+{
-+ void __iomem *csr_base = port->csr_base;
-+ u32 val;
++ return 0;
++}
++DECLARE_ACPI_MCFG_FIXUP("APM ", "XGENE ", xgene_mcfg_fixup);
++#endif /* CONFIG_ACPI */
+
-+ val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID;
-+ writel(val, csr_base + BRIDGE_CFG_0);
+ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
+ {
+ struct device_node *dn = pdev->dev.of_node;
+diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
+index 782e822..d952462 100644
+--- a/drivers/pnp/resource.c
++++ b/drivers/pnp/resource.c
+@@ -313,6 +313,7 @@ static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci,
+ progif = class & 0xff;
+ class >>= 8;
+
++#ifdef HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ
+ if (class == PCI_CLASS_STORAGE_IDE) {
+ /*
+ * Unless both channels are native-PCI mode only,
+@@ -326,6 +327,7 @@ static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci,
+ return 1;
+ }
+ }
++#endif /* HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ */
+
+ return 0;
+ }
+diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
+index b24aa01..50fe279 100644
+--- a/drivers/tty/Kconfig
++++ b/drivers/tty/Kconfig
+@@ -419,4 +419,10 @@ config DA_CONSOLE
+ help
+ This enables a console on a Dash channel.
+
++config SBSAUART_TTY
++ tristate "SBSA UART TTY Driver"
++ help
++ Console and system TTY driver for the SBSA UART which is defined
++ in the Server Base System Architecure document for ARM64 servers.
++
+ endif # TTY
+diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
+index 58ad1c0..c3211c0 100644
+--- a/drivers/tty/Makefile
++++ b/drivers/tty/Makefile
+@@ -29,5 +29,6 @@ obj-$(CONFIG_SYNCLINK) += synclink.o
+ obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
+ obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
+ obj-$(CONFIG_DA_TTY) += metag_da.o
++obj-$(CONFIG_SBSAUART_TTY) += sbsauart.o
+
+ obj-y += ipwireless/
+diff --git a/drivers/tty/sbsauart.c b/drivers/tty/sbsauart.c
+new file mode 100644
+index 0000000..0f44624
+--- /dev/null
++++ b/drivers/tty/sbsauart.c
+@@ -0,0 +1,358 @@
++/*
++ * SBSA (Server Base System Architecture) Compatible UART driver
++ *
++ * Copyright (C) 2014 Linaro Ltd
++ *
++ * Author: Graeme Gregory <graeme.gregory@linaro.org>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ */
+
-+ val = readl(csr_base + BRIDGE_CFG_1);
-+ val &= ~CLASS_CODE_MASK;
-+ val |= PCI_CLASS_BRIDGE_PCI << 16;
-+ writel(val, csr_base + BRIDGE_CFG_1);
++#include <linux/acpi.h>
++#include <linux/amba/serial.h>
++#include <linux/console.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/serial_core.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
+
-+ val = readl(csr_base + BRIDGE_CFG_14);
-+ val |= SWITCH_PORT_MODE_MASK;
-+ val &= ~PM_FORCE_RP_MODE_MASK;
-+ writel(val, csr_base + BRIDGE_CFG_14);
++struct sbsa_tty {
++ struct tty_port port;
++ spinlock_t lock;
++ void __iomem *base;
++ u32 irq;
++ int opencount;
++ struct console console;
++};
+
-+ val = readl(csr_base + BRIDGE_CTRL_5);
-+ val &= ~DEVICE_PORT_TYPE_MASK;
-+ val |= XGENE_PORT_TYPE_RC;
-+ writel(val, csr_base + BRIDGE_CTRL_5);
++static struct tty_driver *sbsa_tty_driver;
++static struct sbsa_tty *sbsa_tty;
+
-+ val = readl(csr_base + BRIDGE_CTRL_2);
-+ val |= ENABLE_ASPM;
-+ writel(val, csr_base + BRIDGE_CTRL_2);
++#define SBSAUART_CHAR_MASK 0xFF
+
-+ val = readl(csr_base + BRIDGE_CFG_32);
-+ writel(val | (1 << 19), csr_base + BRIDGE_CFG_32);
++static void sbsa_raw_putc(struct uart_port *port, int c)
++{
++ while (readw(port->membase + UART01x_FR) & UART01x_FR_TXFF)
++ ;
++ writew(c & 0xFF, port->membase + UART01x_DR);
+}
+
-+/* Return 0 on success */
-+static int xgene_pcie_init_ecc(struct xgene_pcie_port *port)
++static void sbsa_uart_early_write(struct console *con, const char *buf,
++ unsigned count)
+{
-+ void __iomem *csr_base = port->csr_base;
-+ ulong timeout;
-+ u32 val;
-+
-+ val = readl(csr_base + MEM_RAM_SHUTDOWN);
-+ if (!val)
-+ return 0;
-+ writel(0x0, csr_base + MEM_RAM_SHUTDOWN);
-+ timeout = jiffies + msecs_to_jiffies(XGENE_PCIE_ECC_TIMEOUT);
-+ while (time_before(jiffies, timeout)) {
-+ val = readl(csr_base + BLOCK_MEM_RDY);
-+ if (val == BLOCK_MEM_RDY_VAL)
-+ return 0;
-+ msleep(1);
-+ }
++ struct earlycon_device *dev = con->data;
+
-+ return 1;
++ uart_console_write(&dev->port, buf, count, sbsa_raw_putc);
+}
+
-+static int xgene_pcie_init_port(struct xgene_pcie_port *port)
++static int __init sbsa_uart_early_console_setup(struct earlycon_device *device,
++ const char *opt)
+{
-+ int rc;
-+
-+ port->clk = clk_get(port->dev, NULL);
-+ if (IS_ERR(port->clk)) {
-+ dev_err(port->dev, "clock not available\n");
++ if (!device->port.membase)
+ return -ENODEV;
-+ }
-+
-+ rc = clk_prepare_enable(port->clk);
-+ if (rc) {
-+ dev_err(port->dev, "clock enable failed\n");
-+ return rc;
-+ }
-+
-+ rc = xgene_pcie_init_ecc(port);
-+ if (rc) {
-+ dev_err(port->dev, "memory init failed\n");
-+ return rc;
-+ }
+
++ device->con->write = sbsa_uart_early_write;
+ return 0;
+}
++EARLYCON_DECLARE(sbsauart, sbsa_uart_early_console_setup);
+
-+static void xgene_pcie_fixup_bridge(struct pci_dev *dev)
++static void sbsa_tty_do_write(const char *buf, unsigned count)
+{
-+ int i;
++ unsigned long irq_flags;
++ struct sbsa_tty *qtty = sbsa_tty;
++ void __iomem *base = qtty->base;
++ unsigned n;
+
-+ /* Hide the PCI host BARs from the kernel as their content doesn't
-+ * fit well in the resource management
-+ */
-+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-+ dev->resource[i].start = dev->resource[i].end = 0;
-+ dev->resource[i].flags = 0;
++ spin_lock_irqsave(&qtty->lock, irq_flags);
++ for (n = 0; n < count; n++) {
++ while (readw(base + UART01x_FR) & UART01x_FR_TXFF)
++ ;
++ writew(buf[n], base + UART01x_DR);
+ }
-+ dev_info(&dev->dev, "Hiding X-Gene pci host bridge resources %s\n",
-+ pci_name(dev));
++ spin_unlock_irqrestore(&qtty->lock, irq_flags);
+}
-+DECLARE_PCI_FIXUP_HEADER(XGENE_PCIE_VENDORID, XGENE_PCIE_DEVICEID,
-+ xgene_pcie_fixup_bridge);
+
-+static int xgene_pcie_map_reg(struct xgene_pcie_port *port,
-+ struct platform_device *pdev, u64 *cfg_addr)
++static void sbsauart_fifo_to_tty(struct sbsa_tty *qtty)
+{
-+ struct resource *res;
++ void __iomem *base = qtty->base;
++ unsigned int flag, max_count = 32;
++ u16 status, ch;
+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr");
-+ port->csr_base = devm_ioremap_resource(port->dev, res);
-+ if (IS_ERR(port->csr_base))
-+ return PTR_ERR(port->csr_base);
++ while (max_count--) {
++ status = readw(base + UART01x_FR);
++ if (status & UART01x_FR_RXFE)
++ break;
+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
-+ port->cfg_base = devm_ioremap_resource(port->dev, res);
-+ if (IS_ERR(port->cfg_base))
-+ return PTR_ERR(port->cfg_base);
-+ *cfg_addr = res->start;
++ /* Take chars from the FIFO and update status */
++ ch = readw(base + UART01x_DR);
++ flag = TTY_NORMAL;
+
-+ return 0;
-+}
++ if (ch & UART011_DR_BE)
++ flag = TTY_BREAK;
++ else if (ch & UART011_DR_PE)
++ flag = TTY_PARITY;
++ else if (ch & UART011_DR_FE)
++ flag = TTY_FRAME;
++ else if (ch & UART011_DR_OE)
++ flag = TTY_OVERRUN;
+
-+static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port,
-+ struct resource *res, u32 offset, u64 addr)
-+{
-+ void __iomem *base = port->csr_base + offset;
-+ resource_size_t size = resource_size(res);
-+ u64 restype = resource_type(res);
-+ u64 cpu_addr, pci_addr;
-+ u64 mask = 0;
-+ u32 min_size;
-+ u32 flag = EN_REG;
++ ch &= SBSAUART_CHAR_MASK;
+
-+ if (restype == IORESOURCE_MEM) {
-+ cpu_addr = res->start;
-+ pci_addr = addr;
-+ min_size = SZ_128M;
-+ } else {
-+ cpu_addr = addr;
-+ pci_addr = res->start;
-+ min_size = 128;
-+ flag |= OB_LO_IO;
++ tty_insert_flip_char(&qtty->port, ch, flag);
+ }
-+ if (size >= min_size)
-+ mask = ~(size - 1) | flag;
-+ else
-+ dev_warn(port->dev, "res size 0x%llx less than minimum 0x%x\n",
-+ (u64)size, min_size);
-+ writel(lower_32_bits(cpu_addr), base);
-+ writel(upper_32_bits(cpu_addr), base + 0x04);
-+ writel(lower_32_bits(mask), base + 0x08);
-+ writel(upper_32_bits(mask), base + 0x0c);
-+ writel(lower_32_bits(pci_addr), base + 0x10);
-+ writel(upper_32_bits(pci_addr), base + 0x14);
++
++ tty_schedule_flip(&qtty->port);
++
++ /* Clear the RX IRQ */
++ writew(UART011_RXIC | UART011_RXIC, base + UART011_ICR);
+}
+
-+static void xgene_pcie_setup_cfg_reg(void __iomem *csr_base, u64 addr)
++static irqreturn_t sbsa_tty_interrupt(int irq, void *dev_id)
+{
-+ writel(lower_32_bits(addr), csr_base + CFGBARL);
-+ writel(upper_32_bits(addr), csr_base + CFGBARH);
-+ writel(EN_REG, csr_base + CFGCTL);
++ struct sbsa_tty *qtty = sbsa_tty;
++ unsigned long irq_flags;
++
++ spin_lock_irqsave(&qtty->lock, irq_flags);
++ sbsauart_fifo_to_tty(qtty);
++ spin_unlock_irqrestore(&qtty->lock, irq_flags);
++
++ return IRQ_HANDLED;
+}
+
-+static int xgene_pcie_map_ranges(struct xgene_pcie_port *port,
-+ struct pci_host_bridge *bridge,
-+ u64 cfg_addr)
++static int sbsa_tty_open(struct tty_struct *tty, struct file *filp)
+{
-+ struct device *dev = port->dev;
-+ struct pci_host_bridge_window *window;
-+ int ret;
++ struct sbsa_tty *qtty = sbsa_tty;
+
-+ list_for_each_entry(window, &bridge->windows, list) {
-+ struct resource *res = window->res;
-+ u64 restype = resource_type(res);
-+ dev_dbg(port->dev, "0x%08lx 0x%016llx...0x%016llx\n",
-+ res->flags, res->start, res->end);
-+
-+ switch (restype) {
-+ case IORESOURCE_IO:
-+ xgene_pcie_setup_ob_reg(port, res, OMR2BARL,
-+ bridge->io_base);
-+ ret = pci_remap_iospace(res, bridge->io_base);
-+ if (ret < 0)
-+ return ret;
-+ break;
-+ case IORESOURCE_MEM:
-+ xgene_pcie_setup_ob_reg(port, res, OMR3BARL,
-+ res->start - window->offset);
-+ break;
-+ case IORESOURCE_BUS:
-+ break;
-+ default:
-+ dev_err(dev, "invalid io resource!");
-+ return -EINVAL;
-+ }
-+ }
-+ xgene_pcie_setup_cfg_reg(port->csr_base, cfg_addr);
-+ return 0;
++ return tty_port_open(&qtty->port, tty, filp);
+}
+
-+static void xgene_pcie_setup_pims(void *addr, u64 pim, u64 size)
++static void sbsa_tty_close(struct tty_struct *tty, struct file *filp)
+{
-+ writel(lower_32_bits(pim), addr);
-+ writel(upper_32_bits(pim) | EN_COHERENCY, addr + 0x04);
-+ writel(lower_32_bits(size), addr + 0x10);
-+ writel(upper_32_bits(size), addr + 0x14);
++ tty_port_close(tty->port, tty, filp);
+}
+
-+/*
-+ * X-Gene PCIe support maximum 3 inbound memory regions
-+ * This function helps to select a region based on size of region
-+ */
-+static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size)
++static void sbsa_tty_hangup(struct tty_struct *tty)
+{
-+ if ((size > 4) && (size < SZ_16M) && !(*ib_reg_mask & (1 << 1))) {
-+ *ib_reg_mask |= (1 << 1);
-+ return 1;
-+ }
-+
-+ if ((size > SZ_1K) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 0))) {
-+ *ib_reg_mask |= (1 << 0);
-+ return 0;
-+ }
-+
-+ if ((size > SZ_1M) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 2))) {
-+ *ib_reg_mask |= (1 << 2);
-+ return 2;
-+ }
-+ return -EINVAL;
++ tty_port_hangup(tty->port);
+}
+
-+static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
-+ struct of_pci_range *range, u8 *ib_reg_mask)
-+{
-+ void __iomem *csr_base = port->csr_base;
-+ void __iomem *cfg_base = port->cfg_base;
-+ void *bar_addr;
-+ void *pim_addr;
-+ u64 restype = range->flags & IORESOURCE_TYPE_BITS;
-+ u64 cpu_addr = range->cpu_addr;
-+ u64 pci_addr = range->pci_addr;
-+ u64 size = range->size;
-+ u64 mask = ~(size - 1) | EN_REG;
-+ u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64;
-+ u32 bar_low;
-+ int region;
-+
-+ region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size);
-+ if (region < 0) {
-+ dev_warn(port->dev, "invalid pcie dma-range config\n");
-+ return;
-+ }
-+
-+ if (restype == PCI_BASE_ADDRESS_MEM_PREFETCH)
-+ flags |= PCI_BASE_ADDRESS_MEM_PREFETCH;
-+
-+ bar_low = pcie_bar_low_val((u32)cpu_addr, flags);
-+ switch (region) {
-+ case 0:
-+ xgene_pcie_set_ib_mask(csr_base, BRIDGE_CFG_4, flags, size);
-+ bar_addr = cfg_base + PCI_BASE_ADDRESS_0;
-+ writel(bar_low, bar_addr);
-+ writel(upper_32_bits(cpu_addr), bar_addr + 0x4);
-+ pim_addr = csr_base + PIM1_1L;
-+ break;
-+ case 1:
-+ bar_addr = csr_base + IBAR2;
-+ writel(bar_low, bar_addr);
-+ writel(lower_32_bits(mask), csr_base + IR2MSK);
-+ pim_addr = csr_base + PIM2_1L;
-+ break;
-+ case 2:
-+ bar_addr = csr_base + IBAR3L;
-+ writel(bar_low, bar_addr);
-+ writel(upper_32_bits(cpu_addr), bar_addr + 0x4);
-+ writel(lower_32_bits(mask), csr_base + IR3MSKL);
-+ writel(upper_32_bits(mask), csr_base + IR3MSKL + 0x4);
-+ pim_addr = csr_base + PIM3_1L;
-+ break;
-+ }
-+
-+ xgene_pcie_setup_pims(pim_addr, pci_addr, size);
++static int sbsa_tty_write(struct tty_struct *tty, const unsigned char *buf,
++ int count)
++{
++ sbsa_tty_do_write(buf, count);
++ return count;
+}
+
-+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-+ struct device_node *node)
++static int sbsa_tty_write_room(struct tty_struct *tty)
+{
-+ const int na = 3, ns = 2;
-+ int rlen;
-+
-+ parser->node = node;
-+ parser->pna = of_n_addr_cells(node);
-+ parser->np = parser->pna + na + ns;
-+
-+ parser->range = of_get_property(node, "dma-ranges", &rlen);
-+ if (!parser->range)
-+ return -ENOENT;
-+
-+ parser->end = parser->range + rlen / sizeof(__be32);
-+ return 0;
++ return 32;
+}
+
-+static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port)
++static void sbsa_tty_console_write(struct console *co, const char *b,
++ unsigned count)
+{
-+ struct device_node *np = port->node;
-+ struct of_pci_range range;
-+ struct of_pci_range_parser parser;
-+ struct device *dev = port->dev;
-+ u8 ib_reg_mask = 0;
++ sbsa_tty_do_write(b, count);
+
-+ if (pci_dma_range_parser_init(&parser, np)) {
-+ dev_err(dev, "missing dma-ranges property\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Get the dma-ranges from DT */
-+ for_each_of_pci_range(&parser, &range) {
-+ u64 end = range.cpu_addr + range.size - 1;
-+ dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
-+ range.flags, range.cpu_addr, end, range.pci_addr);
-+ xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask);
-+ }
-+ return 0;
++ if (b[count - 1] == '\n')
++ sbsa_tty_do_write("\r", 1);
+}
+
-+static int xgene_pcie_probe_bridge(struct platform_device *pdev)
++static struct tty_driver *sbsa_tty_console_device(struct console *c,
++ int *index)
+{
-+ struct device_node *np = of_node_get(pdev->dev.of_node);
-+ struct xgene_pcie_port *port;
-+ struct pci_host_bridge *bridge;
-+ resource_size_t lastbus;
-+ u32 lanes = 0, speed = 0;
-+ u64 cfg_addr = 0;
-+ int ret;
-+
-+ port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
-+ if (!port)
-+ return -ENOMEM;
-+ port->node = np;
-+ port->dev = &pdev->dev;
++ *index = c->index;
++ return sbsa_tty_driver;
++}
+
-+ ret = xgene_pcie_map_reg(port, pdev, &cfg_addr);
-+ if (ret)
-+ return ret;
++static int sbsa_tty_console_setup(struct console *co, char *options)
++{
++ if ((unsigned)co->index > 0)
++ return -ENODEV;
++ if (sbsa_tty->base == NULL)
++ return -ENODEV;
++ return 0;
++}
+
-+ ret = xgene_pcie_init_port(port);
-+ if (ret)
-+ return ret;
-+ xgene_pcie_program_core(port->csr_base);
-+ xgene_pcie_setup_root_complex(port);
++static struct tty_port_operations sbsa_port_ops = {
++};
+
-+ bridge = of_create_pci_host_bridge(&pdev->dev, &xgene_pcie_ops, port);
-+ if (IS_ERR_OR_NULL(bridge))
-+ return PTR_ERR(bridge);
++static const struct tty_operations sbsa_tty_ops = {
++ .open = sbsa_tty_open,
++ .close = sbsa_tty_close,
++ .hangup = sbsa_tty_hangup,
++ .write = sbsa_tty_write,
++ .write_room = sbsa_tty_write_room,
++};
+
-+ ret = xgene_pcie_map_ranges(port, bridge, cfg_addr);
-+ if (ret)
-+ return ret;
++static int sbsa_tty_create_driver(void)
++{
++ int ret;
++ struct tty_driver *tty;
+
-+ ret = xgene_pcie_parse_map_dma_ranges(port);
++ sbsa_tty = kzalloc(sizeof(*sbsa_tty), GFP_KERNEL);
++ if (sbsa_tty == NULL) {
++ ret = -ENOMEM;
++ goto err_alloc_sbsa_tty_failed;
++ }
++ tty = alloc_tty_driver(1);
++ if (tty == NULL) {
++ ret = -ENOMEM;
++ goto err_alloc_tty_driver_failed;
++ }
++ tty->driver_name = "sbsauart";
++ tty->name = "ttySBSA";
++ tty->type = TTY_DRIVER_TYPE_SERIAL;
++ tty->subtype = SERIAL_TYPE_NORMAL;
++ tty->init_termios = tty_std_termios;
++ tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
++ TTY_DRIVER_DYNAMIC_DEV;
++ tty_set_operations(tty, &sbsa_tty_ops);
++ ret = tty_register_driver(tty);
+ if (ret)
-+ return ret;
++ goto err_tty_register_driver_failed;
+
-+ xgene_pcie_poll_linkup(port, &lanes, &speed);
-+ if (!port->link_up)
-+ dev_info(port->dev, "(rc) link down\n");
-+ else
-+ dev_info(port->dev, "(rc) x%d gen-%d link up\n",
-+ lanes, speed + 1);
-+ platform_set_drvdata(pdev, port);
-+ lastbus = pci_rescan_bus(bridge->bus);
-+ pci_bus_update_busn_res_end(bridge->bus, lastbus);
++ sbsa_tty_driver = tty;
+ return 0;
-+}
+
-+static const struct of_device_id xgene_pcie_match_table[] = {
-+ {.compatible = "apm,xgene-pcie",},
-+ {},
-+};
-+
-+static struct platform_driver xgene_pcie_driver = {
-+ .driver = {
-+ .name = "xgene-pcie",
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(xgene_pcie_match_table),
-+ },
-+ .probe = xgene_pcie_probe_bridge,
-+};
-+module_platform_driver(xgene_pcie_driver);
++err_tty_register_driver_failed:
++ put_tty_driver(tty);
++err_alloc_tty_driver_failed:
++ kfree(sbsa_tty);
++ sbsa_tty = NULL;
++err_alloc_sbsa_tty_failed:
++ return ret;
++}
+
-+MODULE_AUTHOR("Tanmay Inamdar <tinamdar@apm.com>");
-+MODULE_DESCRIPTION("APM X-Gene PCIe driver");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
-index 1c8592b..b81dc68 100644
---- a/drivers/pci/pci.c
-+++ b/drivers/pci/pci.c
-@@ -17,6 +17,7 @@
- #include <linux/spinlock.h>
- #include <linux/string.h>
- #include <linux/log2.h>
-+#include <linux/of_pci.h>
- #include <linux/pci-aspm.h>
- #include <linux/pm_wakeup.h>
- #include <linux/interrupt.h>
-@@ -1453,6 +1454,9 @@ EXPORT_SYMBOL(pcim_pin_device);
- */
- int __weak pcibios_add_device(struct pci_dev *dev)
- {
-+#ifdef CONFIG_OF
-+ dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
-+#endif
- return 0;
- }
-
-@@ -2704,6 +2708,39 @@ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
- }
- EXPORT_SYMBOL(pci_request_regions_exclusive);
-
-+/**
-+ * pci_remap_iospace - Remap the memory mapped I/O space
-+ * @res: Resource describing the I/O space
-+ * @phys_addr: physical address where the range will be mapped.
-+ *
-+ * Remap the memory mapped I/O space described by the @res
-+ * into the CPU physical address space. Only architectures
-+ * that have memory mapped IO defined (and hence PCI_IOBASE)
-+ * should call this function.
-+ */
-+int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
++static void sbsa_tty_delete_driver(void)
+{
-+ int err = -ENODEV;
++ tty_unregister_driver(sbsa_tty_driver);
++ put_tty_driver(sbsa_tty_driver);
++ sbsa_tty_driver = NULL;
++ kfree(sbsa_tty);
++ sbsa_tty = NULL;
++}
+
-+#ifdef PCI_IOBASE
-+ if (!(res->flags & IORESOURCE_IO))
-+ return -EINVAL;
++static int sbsa_tty_probe(struct platform_device *pdev)
++{
++ struct sbsa_tty *qtty;
++ int ret = -EINVAL;
++ int i;
++ struct resource *r;
++ struct device *ttydev;
++ void __iomem *base;
++ u32 irq;
+
-+ if (res->end > IO_SPACE_LIMIT)
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (r == NULL)
+ return -EINVAL;
+
-+ err = ioremap_page_range(res->start + (unsigned long)PCI_IOBASE,
-+ res->end + 1 + (unsigned long)PCI_IOBASE,
-+ phys_addr, __pgprot(PROT_DEVICE_nGnRE));
-+#else
-+ /* this architecture does not have memory mapped I/O space,
-+ so this function should never be called */
-+ WARN_ON(1);
-+#endif
++ base = ioremap(r->start, r->end - r->start);
++ if (base == NULL)
++ pr_err("sbsa_tty: unable to remap base\n");
+
-+ return err;
-+}
++ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (r == NULL)
++ goto err_unmap;
+
- static void __pci_set_master(struct pci_dev *dev, bool enable)
- {
- u16 old_cmd, cmd;
-diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
-index e3cf8a2..abf5e82 100644
---- a/drivers/pci/probe.c
-+++ b/drivers/pci/probe.c
-@@ -515,7 +515,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 +524,6 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
- return NULL;
-
- INIT_LIST_HEAD(&bridge->windows);
-- bridge->bus = b;
- return bridge;
- }
-
-@@ -1749,8 +1748,9 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
- {
- }
-
--struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
-- struct pci_ops *ops, void *sysdata, struct list_head *resources)
-+struct pci_bus *pci_create_root_bus_in_domain(struct device *parent,
-+ int domain, int bus, struct pci_ops *ops, void *sysdata,
-+ struct list_head *resources)
- {
- int error;
- struct pci_host_bridge *bridge;
-@@ -1761,37 +1761,41 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
- char bus_addr[64];
- char *fmt;
-
-+ bridge = pci_alloc_host_bridge();
-+ if (!bridge)
-+ return ERR_PTR(-ENOMEM);
++ irq = r->start;
+
-+ bridge->dev.parent = parent;
-+ bridge->dev.release = pci_release_host_bridge_dev;
-+ bridge->domain_nr = domain;
++ if (pdev->id > 0)
++ goto err_unmap;
+
- b = pci_alloc_bus();
-- if (!b)
-- return NULL;
-+ if (!b) {
-+ error = -ENOMEM;
-+ goto err_out;
-+ }
-
- b->sysdata = sysdata;
- b->ops = ops;
- b->number = b->busn_res.start = bus;
-- b2 = pci_find_bus(pci_domain_nr(b), bus);
-+ b2 = pci_find_bus(bridge->domain_nr, 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;
-+ error = -EEXIST;
-+ 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;
-- dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
-+ bridge->bus = b;
-+ dev_set_name(&bridge->dev, "pci%04x:%02x", bridge->domain_nr, 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);
-@@ -1802,7 +1806,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
-
- b->dev.class = &pcibus_class;
- b->dev.parent = b->bridge;
-- dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
-+ dev_set_name(&b->dev, "%04x:%02x", bridge->domain_nr, bus);
- error = device_register(&b->dev);
- if (error)
- goto class_dev_reg_err;
-@@ -1848,9 +1852,31 @@ 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_bus_out:
-+ kfree(b);
- err_out:
-+ kfree(bridge);
-+ return ERR_PTR(error);
-+}
-+
-+struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
-+ struct pci_ops *ops, void *sysdata, struct list_head *resources)
-+{
-+ int domain_nr;
-+ struct pci_bus *b = pci_alloc_bus();
-+ if (!b)
-+ return NULL;
++ ret = sbsa_tty_create_driver();
++ if (ret)
++ goto err_unmap;
+
-+ b->sysdata = sysdata;
-+ domain_nr = pci_domain_nr(b);
- kfree(b);
-- return NULL;
++ qtty = sbsa_tty;
++ spin_lock_init(&qtty->lock);
++ tty_port_init(&qtty->port);
++ qtty->port.ops = &sbsa_port_ops;
++ qtty->base = base;
++ qtty->irq = irq;
+
-+ b = pci_create_root_bus_in_domain(parent, domain_nr, bus,
-+ ops, sysdata, resources);
-+ if (IS_ERR(b))
-+ return NULL;
++ /* Clear and Mask all IRQs */
++ writew(0, base + UART011_IMSC);
++ writew(0xFFFF, base + UART011_ICR);
+
-+ return b;
- }
-
- int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
-diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
-index 0754f5c..4478a59 100644
---- a/drivers/rtc/Kconfig
-+++ b/drivers/rtc/Kconfig
-@@ -789,7 +789,7 @@ config RTC_DRV_DA9063
-
- config RTC_DRV_EFI
- tristate "EFI RTC"
-- depends on IA64
-+ depends on EFI
- help
- If you say yes here you will get support for the EFI
- Real Time Clock.
-diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
-index 70347d0..f1dfc36 100644
---- a/drivers/rtc/Makefile
-+++ b/drivers/rtc/Makefile
-@@ -10,6 +10,10 @@ obj-$(CONFIG_RTC_SYSTOHC) += systohc.o
- obj-$(CONFIG_RTC_CLASS) += rtc-core.o
- rtc-core-y := class.o interface.o
-
-+ifdef CONFIG_RTC_DRV_EFI
-+rtc-core-y += rtc-efi-platform.o
-+endif
++ ret = request_irq(irq, sbsa_tty_interrupt, IRQF_SHARED,
++ "sbsa_tty", pdev);
++ if (ret)
++ goto err_request_irq_failed;
+
- rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
- rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
- rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
-diff --git a/drivers/rtc/rtc-efi-platform.c b/drivers/rtc/rtc-efi-platform.c
-new file mode 100644
-index 0000000..b40fbe3
---- /dev/null
-+++ b/drivers/rtc/rtc-efi-platform.c
-@@ -0,0 +1,31 @@
-+/*
-+ * Moved from arch/ia64/kernel/time.c
-+ *
-+ * Copyright (C) 1998-2003 Hewlett-Packard Co
-+ * Stephane Eranian <eranian@hpl.hp.com>
-+ * David Mosberger <davidm@hpl.hp.com>
-+ * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
-+ * Copyright (C) 1999-2000 VA Linux Systems
-+ * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com>
-+ */
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/efi.h>
-+#include <linux/platform_device.h>
++ /* Unmask the RX IRQ */
++ writew(UART011_RXIM | UART011_RTIM, base + UART011_IMSC);
+
-+static struct platform_device rtc_efi_dev = {
-+ .name = "rtc-efi",
-+ .id = -1,
-+};
++ ttydev = tty_port_register_device(&qtty->port, sbsa_tty_driver,
++ 0, &pdev->dev);
++ if (IS_ERR(ttydev)) {
++ ret = PTR_ERR(ttydev);
++ goto err_tty_register_device_failed;
++ }
+
-+static int __init rtc_init(void)
-+{
-+ if (efi_enabled(EFI_RUNTIME_SERVICES))
-+ if (platform_device_register(&rtc_efi_dev) < 0)
-+ pr_err("unable to register rtc device...\n");
++ strcpy(qtty->console.name, "ttySBSA");
++ qtty->console.write = sbsa_tty_console_write;
++ 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);
+
-+ /* not necessarily an error */
+ return 0;
++
++ tty_unregister_device(sbsa_tty_driver, i);
++err_tty_register_device_failed:
++ free_irq(irq, pdev);
++err_request_irq_failed:
++ sbsa_tty_delete_driver();
++err_unmap:
++ iounmap(base);
++ return ret;
+}
-+module_init(rtc_init);
-diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
-index 975e1cc..2e2161b 100644
---- a/include/asm-generic/io.h
-+++ b/include/asm-generic/io.h
-@@ -331,7 +331,7 @@ static inline void iounmap(void __iomem *addr)
- #ifndef CONFIG_GENERIC_IOMAP
- 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));
- }
-
- static inline void ioport_unmap(void __iomem *p)
-diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
-index f27000f..35b0c12 100644
---- a/include/kvm/arm_vgic.h
-+++ b/include/kvm/arm_vgic.h
-@@ -24,7 +24,6 @@
- #include <linux/irqreturn.h>
- #include <linux/spinlock.h>
- #include <linux/types.h>
--#include <linux/irqchip/arm-gic.h>
-
- #define VGIC_NR_IRQS 256
- #define VGIC_NR_SGIS 16
-@@ -32,7 +31,9 @@
- #define VGIC_NR_PRIVATE_IRQS (VGIC_NR_SGIS + VGIC_NR_PPIS)
- #define VGIC_NR_SHARED_IRQS (VGIC_NR_IRQS - VGIC_NR_PRIVATE_IRQS)
- #define VGIC_MAX_CPUS KVM_MAX_VCPUS
--#define VGIC_MAX_LRS (1 << 6)
-+
-+#define VGIC_V2_MAX_LRS (1 << 6)
-+#define VGIC_V3_MAX_LRS 16
-
- /* Sanity checks... */
- #if (VGIC_MAX_CPUS > 8)
-@@ -68,9 +69,62 @@ struct vgic_bytemap {
- u32 shared[VGIC_NR_SHARED_IRQS / 4];
- };
-
-+struct kvm_vcpu;
+
-+enum vgic_type {
-+ VGIC_V2, /* Good ol' GICv2 */
-+ VGIC_V3, /* New fancy GICv3 */
-+};
++static int sbsa_tty_remove(struct platform_device *pdev)
++{
++ struct sbsa_tty *qtty;
+
-+#define LR_STATE_PENDING (1 << 0)
-+#define LR_STATE_ACTIVE (1 << 1)
-+#define LR_STATE_MASK (3 << 0)
-+#define LR_EOI_INT (1 << 2)
++ qtty = sbsa_tty;
++ unregister_console(&qtty->console);
++ tty_unregister_device(sbsa_tty_driver, pdev->id);
++ iounmap(qtty->base);
++ qtty->base = 0;
++ free_irq(qtty->irq, pdev);
++ sbsa_tty_delete_driver();
++ return 0;
++}
+
-+struct vgic_lr {
-+ u16 irq;
-+ u8 source;
-+ u8 state;
++static const struct acpi_device_id sbsa_acpi_match[] = {
++ { "ARMH0011", 0 },
++ { }
+};
+
-+struct vgic_vmcr {
-+ u32 ctlr;
-+ u32 abpr;
-+ u32 bpr;
-+ u32 pmr;
++static struct platform_driver sbsa_tty_platform_driver = {
++ .probe = sbsa_tty_probe,
++ .remove = sbsa_tty_remove,
++ .driver = {
++ .name = "sbsa_tty",
++ .acpi_match_table = ACPI_PTR(sbsa_acpi_match),
++ }
+};
+
-+struct vgic_ops {
-+ struct vgic_lr (*get_lr)(const struct kvm_vcpu *, int);
-+ void (*set_lr)(struct kvm_vcpu *, int, struct vgic_lr);
-+ void (*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
-+ u64 (*get_elrsr)(const struct kvm_vcpu *vcpu);
-+ u64 (*get_eisr)(const struct kvm_vcpu *vcpu);
-+ u32 (*get_interrupt_status)(const struct kvm_vcpu *vcpu);
-+ void (*enable_underflow)(struct kvm_vcpu *vcpu);
-+ void (*disable_underflow)(struct kvm_vcpu *vcpu);
-+ void (*get_vmcr)(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-+ void (*set_vmcr)(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-+ void (*enable)(struct kvm_vcpu *vcpu);
-+};
++module_platform_driver(sbsa_tty_platform_driver);
+
-+struct vgic_params {
-+ /* vgic type */
-+ enum vgic_type type;
-+ /* Physical address of vgic virtual cpu interface */
-+ phys_addr_t vcpu_base;
-+ /* Number of list registers */
-+ u32 nr_lr;
-+ /* Interrupt number */
-+ unsigned int maint_irq;
-+ /* Virtual control interface base address */
-+ void __iomem *vctrl_base;
-+};
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
+index beea6ca..7038a2d 100644
+--- a/drivers/tty/serial/8250/8250_dw.c
++++ b/drivers/tty/serial/8250/8250_dw.c
+@@ -310,10 +310,18 @@ static int dw8250_probe_of(struct uart_port *p,
+ static int dw8250_probe_acpi(struct uart_8250_port *up,
+ struct dw8250_data *data)
+ {
++ const struct acpi_device_id *id;
+ struct uart_port *p = &up->port;
+
+ dw8250_setup_port(up);
+
++ id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
++ if (!id)
++ return -ENODEV;
+
- struct vgic_dist {
- #ifdef CONFIG_KVM_ARM_VGIC
- spinlock_t lock;
-+ bool in_kernel;
- bool ready;
++ if (!p->uartclk)
++ p->uartclk = (unsigned int)id->driver_data;
++
+ p->iotype = UPIO_MEM32;
+ p->serial_in = dw8250_serial_in32;
+ p->serial_out = dw8250_serial_out32;
+@@ -536,6 +544,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
+ { "INT3435", 0 },
+ { "80860F0A", 0 },
+ { "8086228A", 0 },
++ { "APMC0D08", 50000000},
+ { },
+ };
+ MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
+diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
+index ef9a165..9f1939c 100644
+--- a/drivers/virtio/virtio_mmio.c
++++ b/drivers/virtio/virtio_mmio.c
+@@ -100,8 +100,7 @@
+ #include <linux/virtio_config.h>
+ #include <linux/virtio_mmio.h>
+ #include <linux/virtio_ring.h>
+-
+-
++#include <linux/acpi.h>
- /* Virtual control interface mapping */
-@@ -110,6 +164,29 @@ struct vgic_dist {
- #endif
+ /* The alignment to use between consumer and producer parts of vring.
+ * Currently hardcoded to the page size. */
+@@ -634,6 +633,14 @@ static struct of_device_id virtio_mmio_match[] = {
};
+ MODULE_DEVICE_TABLE(of, virtio_mmio_match);
-+struct vgic_v2_cpu_if {
-+ u32 vgic_hcr;
-+ u32 vgic_vmcr;
-+ u32 vgic_misr; /* Saved only */
-+ u32 vgic_eisr[2]; /* Saved only */
-+ u32 vgic_elrsr[2]; /* Saved only */
-+ u32 vgic_apr;
-+ u32 vgic_lr[VGIC_V2_MAX_LRS];
++#ifdef CONFIG_ACPI
++static const struct acpi_device_id virtio_mmio_acpi_match[] = {
++ { "LNRO0005", },
++ { }
+};
-+
-+struct vgic_v3_cpu_if {
-+#ifdef CONFIG_ARM_GIC_V3
-+ u32 vgic_hcr;
-+ u32 vgic_vmcr;
-+ u32 vgic_misr; /* Saved only */
-+ u32 vgic_eisr; /* Saved only */
-+ u32 vgic_elrsr; /* Saved only */
-+ u32 vgic_ap0r[4];
-+ u32 vgic_ap1r[4];
-+ u64 vgic_lr[VGIC_V3_MAX_LRS];
++MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match);
+#endif
-+};
+
- struct vgic_cpu {
- #ifdef CONFIG_KVM_ARM_VGIC
- /* per IRQ to LR mapping */
-@@ -120,24 +197,24 @@ struct vgic_cpu {
- DECLARE_BITMAP( pending_shared, VGIC_NR_SHARED_IRQS);
-
- /* Bitmap of used/free list registers */
-- DECLARE_BITMAP( lr_used, VGIC_MAX_LRS);
-+ DECLARE_BITMAP( lr_used, VGIC_V2_MAX_LRS);
-
- /* Number of list registers on this CPU */
- int nr_lr;
-
- /* CPU vif control registers for world switch */
-- u32 vgic_hcr;
-- u32 vgic_vmcr;
-- u32 vgic_misr; /* Saved only */
-- u32 vgic_eisr[2]; /* Saved only */
-- u32 vgic_elrsr[2]; /* Saved only */
-- u32 vgic_apr;
-- u32 vgic_lr[VGIC_MAX_LRS];
-+ union {
-+ struct vgic_v2_cpu_if vgic_v2;
-+ struct vgic_v3_cpu_if vgic_v3;
-+ };
- #endif
+ static struct platform_driver virtio_mmio_driver = {
+ .probe = virtio_mmio_probe,
+ .remove = virtio_mmio_remove,
+@@ -641,6 +648,7 @@ static struct platform_driver virtio_mmio_driver = {
+ .name = "virtio-mmio",
+ .owner = THIS_MODULE,
+ .of_match_table = virtio_mmio_match,
++ .acpi_match_table = ACPI_PTR(virtio_mmio_acpi_match),
+ },
};
- #define LR_EMPTY 0xff
+diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c
+index 1f850c9..f745db2 100644
+--- a/drivers/xen/efi.c
++++ b/drivers/xen/efi.c
+@@ -294,6 +294,7 @@ static const struct efi efi_xen __initconst = {
+ .acpi = EFI_INVALID_TABLE_ADDR,
+ .acpi20 = EFI_INVALID_TABLE_ADDR,
+ .smbios = EFI_INVALID_TABLE_ADDR,
++ .smbios3 = EFI_INVALID_TABLE_ADDR,
+ .sal_systab = EFI_INVALID_TABLE_ADDR,
+ .boot_info = EFI_INVALID_TABLE_ADDR,
+ .hcdp = EFI_INVALID_TABLE_ADDR,
+diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
+index f34a083..04d02fc 100644
+--- a/include/acpi/acpi_bus.h
++++ b/include/acpi/acpi_bus.h
+@@ -27,6 +27,7 @@
+ #define __ACPI_BUS_H__
+
+ #include <linux/device.h>
++#include <linux/property.h>
+
+ /* TBD: Make dynamic */
+ #define ACPI_MAX_HANDLES 10
+@@ -68,6 +69,8 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs);
+ union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid,
+ int rev, int func, union acpi_object *argv4);
+
++acpi_status acpi_check_coherency(acpi_handle handle, int *val);
++
+ 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,10 +340,20 @@ struct acpi_device_physical_node {
+ bool put_online:1;
+ };
-+#define INT_STATUS_EOI (1 << 0)
-+#define INT_STATUS_UNDERFLOW (1 << 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;
++};
+
- struct kvm;
- struct kvm_vcpu;
- struct kvm_run;
-@@ -157,9 +234,25 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
- bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
- struct kvm_exit_mmio *mmio);
-
--#define irqchip_in_kernel(k) (!!((k)->arch.vgic.vctrl_base))
-+#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
- #define vgic_initialized(k) ((k)->arch.vgic.ready)
++struct acpi_gpio_mapping;
++
+ /* Device */
+ struct acpi_device {
+ int device_type;
+ acpi_handle handle; /* no handle for fixed hardware */
++ struct fwnode_handle fwnode;
+ struct acpi_device *parent;
+ struct list_head children;
+ struct list_head node;
+@@ -353,9 +366,11 @@ 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;
++ const struct acpi_gpio_mapping *driver_gpios;
+ void *driver_data;
+ struct device dev;
+ unsigned int physical_node_count;
+@@ -364,6 +379,21 @@ struct acpi_device {
+ void (*remove)(struct acpi_device *);
+ };
-+int vgic_v2_probe(struct device_node *vgic_node,
-+ const struct vgic_ops **ops,
-+ const struct vgic_params **params);
-+#ifdef CONFIG_ARM_GIC_V3
-+int vgic_v3_probe(struct device_node *vgic_node,
-+ const struct vgic_ops **ops,
-+ const struct vgic_params **params);
-+#else
-+static inline int vgic_v3_probe(struct device_node *vgic_node,
-+ const struct vgic_ops **ops,
-+ const struct vgic_params **params)
++static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
-+ return -ENODEV;
++ return fwnode && fwnode->type == FWNODE_ACPI;
+}
-+#endif
+
- #else
- static inline int kvm_vgic_hyp_init(void)
++static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
++{
++ return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
++}
++
++static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
++{
++ return &adev->fwnode;
++}
++
+ static inline void *acpi_driver_data(struct acpi_device *d)
{
-diff --git a/include/linux/efi.h b/include/linux/efi.h
-index 41bbf8b..b3fac7c 100644
---- a/include/linux/efi.h
-+++ b/include/linux/efi.h
-@@ -20,6 +20,7 @@
- #include <linux/ioport.h>
- #include <linux/pfn.h>
- #include <linux/pstore.h>
-+#include <linux/reboot.h>
+ return d->driver_data;
+diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h
+index 444671e..9d573db 100644
+--- a/include/acpi/acpi_io.h
++++ b/include/acpi/acpi_io.h
+@@ -1,11 +1,17 @@
+ #ifndef _ACPI_IO_H_
+ #define _ACPI_IO_H_
- #include <asm/page.h>
-
-@@ -875,6 +876,9 @@ extern void efi_reserve_boot_services(void);
- extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
- extern struct efi_memory_map memmap;
++#include <linux/mm.h>
+ #include <linux/io.h>
-+extern int efi_reboot_quirk_mode;
-+extern bool efi_poweroff_required(void);
-+
- /* Iterate through an efi_memory_map */
- #define for_each_efi_memory_desc(m, md) \
- for ((md) = (m)->map; \
-@@ -926,11 +930,14 @@ static inline bool efi_enabled(int feature)
+ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
+ acpi_size size)
{
- return test_bit(feature, &efi.flags) != 0;
++#ifdef CONFIG_ARM64
++ if (!page_is_ram(phys >> PAGE_SHIFT))
++ return ioremap(phys, size);
++#endif
++
+ return ioremap_cache(phys, size);
}
-+extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused);
+
+diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
+index aa70cbd..1261fef 100644
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -275,6 +275,13 @@
+ VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \
+ } \
+ \
++ /* ACPI quirks */ \
++ .acpi_fixup : AT(ADDR(.acpi_fixup) - LOAD_OFFSET) { \
++ VMLINUX_SYMBOL(__start_acpi_mcfg_fixups) = .; \
++ *(.acpi_fixup_mcfg) \
++ VMLINUX_SYMBOL(__end_acpi_mcfg_fixups) = .; \
++ } \
++ \
+ /* Built-in firmware blobs */ \
+ .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start_builtin_fw) = .; \
+diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
+index 206dcc3..660dbfc 100644
+--- a/include/kvm/arm_vgic.h
++++ b/include/kvm/arm_vgic.h
+@@ -289,17 +289,19 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
+ #define vgic_initialized(k) ((k)->arch.vgic.ready)
+
+-int vgic_v2_probe(struct device_node *vgic_node,
+- const struct vgic_ops **ops,
+- const struct vgic_params **params);
++int vgic_v2_dt_probe(struct device_node *vgic_node,
++ const struct vgic_ops **ops,
++ const struct vgic_params **params);
++int vgic_v2_acpi_probe(const struct vgic_ops **ops,
++ const struct vgic_params **params);
+ #ifdef CONFIG_ARM_GIC_V3
+-int vgic_v3_probe(struct device_node *vgic_node,
+- const struct vgic_ops **ops,
+- const struct vgic_params **params);
++int vgic_v3_dt_probe(struct device_node *vgic_node,
++ const struct vgic_ops **ops,
++ const struct vgic_params **params);
#else
- static inline bool efi_enabled(int feature)
+-static inline int vgic_v3_probe(struct device_node *vgic_node,
+- const struct vgic_ops **ops,
+- const struct vgic_params **params)
++static inline int vgic_v3_dt_probe(struct device_node *vgic_node,
++ const struct vgic_ops **ops,
++ const struct vgic_params **params)
{
- return false;
+ return -ENODEV;
}
-+static inline void
-+efi_reboot(enum reboot_mode reboot_mode, const char *__unused) {}
- #endif
+diff --git a/include/linux/acpi.h b/include/linux/acpi.h
+index 407a12f..de81de3 100644
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -28,6 +28,7 @@
+ #include <linux/errno.h>
+ #include <linux/ioport.h> /* for struct resource */
+ #include <linux/device.h>
++#include <linux/property.h>
+
+ #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,
++ ACPI_IRQ_MODEL_GIC,
+ ACPI_IRQ_MODEL_COUNT
+ };
- /*
-diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
-new file mode 100644
-index 0000000..30cb755
---- /dev/null
-+++ b/include/linux/irqchip/arm-gic-v3.h
-@@ -0,0 +1,198 @@
-+/*
-+ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
-+ * Author: Marc Zyngier <marc.zyngier@arm.com>
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef __LINUX_IRQCHIP_ARM_GIC_V3_H
-+#define __LINUX_IRQCHIP_ARM_GIC_V3_H
-+
-+/*
-+ * Distributor registers. We assume we're running non-secure, with ARE
-+ * being set. Secure-only and non-ARE registers are not described.
-+ */
-+#define GICD_CTLR 0x0000
-+#define GICD_TYPER 0x0004
-+#define GICD_IIDR 0x0008
-+#define GICD_STATUSR 0x0010
-+#define GICD_SETSPI_NSR 0x0040
-+#define GICD_CLRSPI_NSR 0x0048
-+#define GICD_SETSPI_SR 0x0050
-+#define GICD_CLRSPI_SR 0x0058
-+#define GICD_SEIR 0x0068
-+#define GICD_ISENABLER 0x0100
-+#define GICD_ICENABLER 0x0180
-+#define GICD_ISPENDR 0x0200
-+#define GICD_ICPENDR 0x0280
-+#define GICD_ISACTIVER 0x0300
-+#define GICD_ICACTIVER 0x0380
-+#define GICD_IPRIORITYR 0x0400
-+#define GICD_ICFGR 0x0C00
-+#define GICD_IROUTER 0x6000
-+#define GICD_PIDR2 0xFFE8
-+
-+#define GICD_CTLR_RWP (1U << 31)
-+#define GICD_CTLR_ARE_NS (1U << 4)
-+#define GICD_CTLR_ENABLE_G1A (1U << 1)
-+#define GICD_CTLR_ENABLE_G1 (1U << 0)
-+
-+#define GICD_IROUTER_SPI_MODE_ONE (0U << 31)
-+#define GICD_IROUTER_SPI_MODE_ANY (1U << 31)
-+
-+#define GIC_PIDR2_ARCH_MASK 0xf0
-+#define GIC_PIDR2_ARCH_GICv3 0x30
-+#define GIC_PIDR2_ARCH_GICv4 0x40
-+
-+/*
-+ * Re-Distributor registers, offsets from RD_base
-+ */
-+#define GICR_CTLR GICD_CTLR
-+#define GICR_IIDR 0x0004
-+#define GICR_TYPER 0x0008
-+#define GICR_STATUSR GICD_STATUSR
-+#define GICR_WAKER 0x0014
-+#define GICR_SETLPIR 0x0040
-+#define GICR_CLRLPIR 0x0048
-+#define GICR_SEIR GICD_SEIR
-+#define GICR_PROPBASER 0x0070
-+#define GICR_PENDBASER 0x0078
-+#define GICR_INVLPIR 0x00A0
-+#define GICR_INVALLR 0x00B0
-+#define GICR_SYNCR 0x00C0
-+#define GICR_MOVLPIR 0x0100
-+#define GICR_MOVALLR 0x0110
-+#define GICR_PIDR2 GICD_PIDR2
-+
-+#define GICR_WAKER_ProcessorSleep (1U << 1)
-+#define GICR_WAKER_ChildrenAsleep (1U << 2)
-+
-+/*
-+ * Re-Distributor registers, offsets from SGI_base
-+ */
-+#define GICR_ISENABLER0 GICD_ISENABLER
-+#define GICR_ICENABLER0 GICD_ICENABLER
-+#define GICR_ISPENDR0 GICD_ISPENDR
-+#define GICR_ICPENDR0 GICD_ICPENDR
-+#define GICR_ISACTIVER0 GICD_ISACTIVER
-+#define GICR_ICACTIVER0 GICD_ICACTIVER
-+#define GICR_IPRIORITYR0 GICD_IPRIORITYR
-+#define GICR_ICFGR0 GICD_ICFGR
-+
-+#define GICR_TYPER_VLPIS (1U << 1)
-+#define GICR_TYPER_LAST (1U << 4)
-+
-+/*
-+ * CPU interface registers
-+ */
-+#define ICC_CTLR_EL1_EOImode_drop_dir (0U << 1)
-+#define ICC_CTLR_EL1_EOImode_drop (1U << 1)
-+#define ICC_SRE_EL1_SRE (1U << 0)
-+
-+/*
-+ * Hypervisor interface registers (SRE only)
-+ */
-+#define ICH_LR_VIRTUAL_ID_MASK ((1UL << 32) - 1)
-+
-+#define ICH_LR_EOI (1UL << 41)
-+#define ICH_LR_GROUP (1UL << 60)
-+#define ICH_LR_STATE (3UL << 62)
-+#define ICH_LR_PENDING_BIT (1UL << 62)
-+#define ICH_LR_ACTIVE_BIT (1UL << 63)
-+
-+#define ICH_MISR_EOI (1 << 0)
-+#define ICH_MISR_U (1 << 1)
-+
-+#define ICH_HCR_EN (1 << 0)
-+#define ICH_HCR_UIE (1 << 1)
-+
-+#define ICH_VMCR_CTLR_SHIFT 0
-+#define ICH_VMCR_CTLR_MASK (0x21f << ICH_VMCR_CTLR_SHIFT)
-+#define ICH_VMCR_BPR1_SHIFT 18
-+#define ICH_VMCR_BPR1_MASK (7 << ICH_VMCR_BPR1_SHIFT)
-+#define ICH_VMCR_BPR0_SHIFT 21
-+#define ICH_VMCR_BPR0_MASK (7 << ICH_VMCR_BPR0_SHIFT)
-+#define ICH_VMCR_PMR_SHIFT 24
-+#define ICH_VMCR_PMR_MASK (0xffUL << ICH_VMCR_PMR_SHIFT)
-+
-+#define ICC_EOIR1_EL1 S3_0_C12_C12_1
-+#define ICC_IAR1_EL1 S3_0_C12_C12_0
-+#define ICC_SGI1R_EL1 S3_0_C12_C11_5
-+#define ICC_PMR_EL1 S3_0_C4_C6_0
-+#define ICC_CTLR_EL1 S3_0_C12_C12_4
-+#define ICC_SRE_EL1 S3_0_C12_C12_5
-+#define ICC_GRPEN1_EL1 S3_0_C12_C12_7
-+
-+#define ICC_IAR1_EL1_SPURIOUS 0x3ff
-+
-+#define ICC_SRE_EL2 S3_4_C12_C9_5
-+
-+#define ICC_SRE_EL2_SRE (1 << 0)
-+#define ICC_SRE_EL2_ENABLE (1 << 3)
-+
-+/*
-+ * System register definitions
-+ */
-+#define ICH_VSEIR_EL2 S3_4_C12_C9_4
-+#define ICH_HCR_EL2 S3_4_C12_C11_0
-+#define ICH_VTR_EL2 S3_4_C12_C11_1
-+#define ICH_MISR_EL2 S3_4_C12_C11_2
-+#define ICH_EISR_EL2 S3_4_C12_C11_3
-+#define ICH_ELSR_EL2 S3_4_C12_C11_5
-+#define ICH_VMCR_EL2 S3_4_C12_C11_7
-+
-+#define __LR0_EL2(x) S3_4_C12_C12_ ## x
-+#define __LR8_EL2(x) S3_4_C12_C13_ ## x
-+
-+#define ICH_LR0_EL2 __LR0_EL2(0)
-+#define ICH_LR1_EL2 __LR0_EL2(1)
-+#define ICH_LR2_EL2 __LR0_EL2(2)
-+#define ICH_LR3_EL2 __LR0_EL2(3)
-+#define ICH_LR4_EL2 __LR0_EL2(4)
-+#define ICH_LR5_EL2 __LR0_EL2(5)
-+#define ICH_LR6_EL2 __LR0_EL2(6)
-+#define ICH_LR7_EL2 __LR0_EL2(7)
-+#define ICH_LR8_EL2 __LR8_EL2(0)
-+#define ICH_LR9_EL2 __LR8_EL2(1)
-+#define ICH_LR10_EL2 __LR8_EL2(2)
-+#define ICH_LR11_EL2 __LR8_EL2(3)
-+#define ICH_LR12_EL2 __LR8_EL2(4)
-+#define ICH_LR13_EL2 __LR8_EL2(5)
-+#define ICH_LR14_EL2 __LR8_EL2(6)
-+#define ICH_LR15_EL2 __LR8_EL2(7)
-+
-+#define __AP0Rx_EL2(x) S3_4_C12_C8_ ## x
-+#define ICH_AP0R0_EL2 __AP0Rx_EL2(0)
-+#define ICH_AP0R1_EL2 __AP0Rx_EL2(1)
-+#define ICH_AP0R2_EL2 __AP0Rx_EL2(2)
-+#define ICH_AP0R3_EL2 __AP0Rx_EL2(3)
-+
-+#define __AP1Rx_EL2(x) S3_4_C12_C9_ ## x
-+#define ICH_AP1R0_EL2 __AP1Rx_EL2(0)
-+#define ICH_AP1R1_EL2 __AP1Rx_EL2(1)
-+#define ICH_AP1R2_EL2 __AP1Rx_EL2(2)
-+#define ICH_AP1R3_EL2 __AP1Rx_EL2(3)
-+
-+#ifndef __ASSEMBLY__
-+
-+#include <linux/stringify.h>
-+
-+static inline void gic_write_eoir(u64 irq)
-+{
-+ asm volatile("msr " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" (irq));
-+ isb();
-+}
-+
-+#endif
-+
-+#endif
-diff --git a/include/linux/of_address.h b/include/linux/of_address.h
-index c13b878..33c0420 100644
---- a/include/linux/of_address.h
-+++ b/include/linux/of_address.h
-@@ -23,17 +23,8 @@ struct of_pci_range {
- #define for_each_of_pci_range(parser, range) \
- for (; of_pci_range_parser_one(parser, range);)
-
--static inline void of_pci_range_to_resource(struct of_pci_range *range,
-- struct device_node *np,
-- struct resource *res)
+@@ -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);
++int __init acpi_parse_entries(unsigned long table_size,
++ acpi_tbl_entry_handler handler,
++ struct acpi_table_header *table_header,
++ int entry_id, unsigned int max_entries);
+ 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)
-{
-- res->flags = range->flags;
-- res->start = range->cpu_addr;
-- res->end = range->cpu_addr + range->size - 1;
-- res->parent = res->child = res->sibling = NULL;
-- res->name = np->full_name;
+- return !!acpi_match_device(drv->acpi_match_table, dev);
-}
-
-+extern int of_pci_range_to_resource(struct of_pci_range *range,
-+ struct device_node *np, struct resource *res);
- /* Translate a DMA address from device space to CPU space */
- extern u64 of_translate_dma_address(struct device_node *dev,
- const __be32 *in_addr);
-@@ -55,6 +46,7 @@ extern void __iomem *of_iomap(struct device_node *device, int index);
- extern const __be32 *of_get_address(struct device_node *dev, int index,
- u64 *size, unsigned int *flags);
-
-+extern int pci_register_io_range(phys_addr_t addr, resource_size_t size);
- extern unsigned long pci_address_to_pio(phys_addr_t addr);
-
- extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
-diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
-index dde3a4a..71e36d0 100644
---- a/include/linux/of_pci.h
-+++ b/include/linux/of_pci.h
-@@ -15,6 +15,9 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
- int of_pci_get_devfn(struct device_node *np);
- int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
- int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
-+struct pci_host_bridge *of_create_pci_host_bridge(struct device *parent,
-+ struct pci_ops *ops, void *host_data);
++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);
+
+@@ -443,6 +445,23 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *);
+ #define ACPI_COMPANION_SET(dev, adev) do { } while (0)
+ #define ACPI_HANDLE(dev) (NULL)
+
++struct fwnode_handle;
+
- #else
- static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
- {
-@@ -43,6 +46,13 @@ of_pci_parse_bus_range(struct device_node *node, struct resource *res)
- {
- return -EINVAL;
- }
++static inline bool is_acpi_node(struct fwnode_handle *fwnode)
++{
++ return false;
++}
+
-+static inline struct pci_host_bridge *
-+of_create_pci_host_bridge(struct device *parent, struct pci_ops *ops,
-+ void *host_data)
++static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
- #endif
-
- #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
-diff --git a/include/linux/pci.h b/include/linux/pci.h
-index 466bcd1..65fb1fc 100644
---- a/include/linux/pci.h
-+++ b/include/linux/pci.h
-@@ -401,6 +401,8 @@ struct pci_host_bridge_window {
- struct pci_host_bridge {
- struct device dev;
- struct pci_bus *bus; /* root bus */
-+ int domain_nr;
-+ resource_size_t io_base; /* physical address for the start of I/O area */
- struct list_head windows; /* pci_host_bridge_windows */
- void (*release_fn)(struct pci_host_bridge *);
- void *release_data;
-@@ -769,6 +771,9 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
- struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
- struct pci_ops *ops, void *sysdata,
- struct list_head *resources);
-+struct pci_bus *pci_create_root_bus_in_domain(struct device *parent,
-+ int domain, int bus, struct pci_ops *ops,
-+ void *sysdata, struct list_head *resources);
- int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
- int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
- void pci_bus_release_busn_res(struct pci_bus *b);
-@@ -1095,6 +1100,9 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
- resource_size_t),
- void *alignf_data);
-
-+
-+int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
-+
- static inline dma_addr_t pci_bus_address(struct pci_dev *pdev, int bar)
- {
- struct pci_bus_region region;
-@@ -1805,8 +1813,15 @@ static inline void pci_set_of_node(struct pci_dev *dev) { }
- static inline void pci_release_of_node(struct pci_dev *dev) { }
- static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
- static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
+
- #endif /* CONFIG_OF */
-
-+/* Used by architecture code to apply any quirks to the list of
-+ * pci_host_bridge resource ranges before they are being used
-+ * by of_create_pci_host_bridge()
-+ */
-+extern int pcibios_fixup_bridge_ranges(struct list_head *resources);
++static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
++{
++ return NULL;
++}
+
- #ifdef CONFIG_EEH
- static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
+ static inline const char *acpi_dev_name(struct acpi_device *adev)
{
-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
-+++ b/tools/perf/arch/arm64/include/perf_regs.h
-@@ -6,6 +6,8 @@
- #include <asm/perf_regs.h>
-
- #define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1)
-+#define PERF_REGS_MAX PERF_REG_ARM64_MAX
-+
- #define PERF_REG_IP PERF_REG_ARM64_PC
- #define PERF_REG_SP PERF_REG_ARM64_SP
+ return NULL;
+@@ -659,4 +678,114 @@ do { \
+ #endif
+ #endif
-diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
-new file mode 100644
-index 0000000..ff597d8
---- /dev/null
-+++ b/virt/kvm/arm/vgic-v2.c
-@@ -0,0 +1,259 @@
-+/*
-+ * Copyright (C) 2012,2013 ARM Limited, All Rights Reserved.
-+ * Author: Marc Zyngier <marc.zyngier@arm.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/cpu.h>
-+#include <linux/kvm.h>
-+#include <linux/kvm_host.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+
-+#include <linux/irqchip/arm-gic.h>
-+
-+#include <asm/kvm_emulate.h>
-+#include <asm/kvm_arm.h>
-+#include <asm/kvm_mmu.h>
-+
-+static struct vgic_lr vgic_v2_get_lr(const struct kvm_vcpu *vcpu, int lr)
-+{
-+ struct vgic_lr lr_desc;
-+ u32 val = vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr];
-+
-+ lr_desc.irq = val & GICH_LR_VIRTUALID;
-+ if (lr_desc.irq <= 15)
-+ lr_desc.source = (val >> GICH_LR_PHYSID_CPUID_SHIFT) & 0x7;
-+ else
-+ lr_desc.source = 0;
-+ lr_desc.state = 0;
++struct acpi_gpio_params {
++ unsigned int crs_entry_index;
++ unsigned int line_index;
++ bool active_low;
++};
+
-+ if (val & GICH_LR_PENDING_BIT)
-+ lr_desc.state |= LR_STATE_PENDING;
-+ if (val & GICH_LR_ACTIVE_BIT)
-+ lr_desc.state |= LR_STATE_ACTIVE;
-+ if (val & GICH_LR_EOI)
-+ lr_desc.state |= LR_EOI_INT;
++struct acpi_gpio_mapping {
++ const char *name;
++ const struct acpi_gpio_params *data;
++ unsigned int size;
++};
+
-+ return lr_desc;
-+}
++#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
++int acpi_dev_add_driver_gpios(struct acpi_device *adev,
++ const struct acpi_gpio_mapping *gpios);
+
-+static void vgic_v2_set_lr(struct kvm_vcpu *vcpu, int lr,
-+ struct vgic_lr lr_desc)
++static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
+{
-+ u32 lr_val = (lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT) | lr_desc.irq;
-+
-+ if (lr_desc.state & LR_STATE_PENDING)
-+ lr_val |= GICH_LR_PENDING_BIT;
-+ if (lr_desc.state & LR_STATE_ACTIVE)
-+ lr_val |= GICH_LR_ACTIVE_BIT;
-+ if (lr_desc.state & LR_EOI_INT)
-+ lr_val |= GICH_LR_EOI;
-+
-+ vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = lr_val;
++ if (adev)
++ adev->driver_gpios = NULL;
+}
-+
-+static void vgic_v2_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
-+ struct vgic_lr lr_desc)
++#else
++static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
++ const struct acpi_gpio_mapping *gpios)
+{
-+ if (!(lr_desc.state & LR_STATE_MASK))
-+ set_bit(lr, (unsigned long *)vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr);
++ return -ENXIO;
+}
++static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
++#endif
+
-+static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
-+{
-+ u64 val;
-+
-+ val = vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr[1];
-+ val <<= 32;
-+ val |= vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr[0];
++/* Device properties */
+
-+ return val;
-+}
++#define MAX_ACPI_REFERENCE_ARGS 8
++struct acpi_reference_args {
++ struct acpi_device *adev;
++ size_t nargs;
++ u64 args[MAX_ACPI_REFERENCE_ARGS];
++};
+
-+static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
++#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, 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_single(struct acpi_device *adev, const char *propname,
++ enum dev_prop_type proptype, void *val);
++int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
++ enum dev_prop_type proptype, void *val, size_t nval);
++
++struct acpi_device *acpi_get_next_child(struct device *dev,
++ struct acpi_device *child);
++#else
++static inline int acpi_dev_get_property(struct acpi_device *adev,
++ const char *name, acpi_object_type type,
++ const union acpi_object **obj)
+{
-+ u64 val;
-+
-+ val = vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr[1];
-+ val <<= 32;
-+ val |= vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr[0];
-+
-+ return val;
++ return -ENXIO;
+}
-+
-+static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)
++static inline int acpi_dev_get_property_array(struct acpi_device *adev,
++ const char *name,
++ acpi_object_type type,
++ const union acpi_object **obj)
+{
-+ u32 misr = vcpu->arch.vgic_cpu.vgic_v2.vgic_misr;
-+ u32 ret = 0;
-+
-+ if (misr & GICH_MISR_EOI)
-+ ret |= INT_STATUS_EOI;
-+ if (misr & GICH_MISR_U)
-+ ret |= INT_STATUS_UNDERFLOW;
-+
-+ return ret;
++ return -ENXIO;
+}
-+
-+static void vgic_v2_enable_underflow(struct kvm_vcpu *vcpu)
++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)
+{
-+ vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr |= GICH_HCR_UIE;
++ return -ENXIO;
+}
+
-+static void vgic_v2_disable_underflow(struct kvm_vcpu *vcpu)
++static inline int acpi_dev_prop_get(struct acpi_device *adev,
++ const char *propname,
++ void **valptr)
+{
-+ vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr &= ~GICH_HCR_UIE;
++ return -ENXIO;
+}
+
-+static void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
++static inline int acpi_dev_prop_read_single(struct acpi_device *adev,
++ const char *propname,
++ enum dev_prop_type proptype,
++ void *val)
+{
-+ u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
-+
-+ vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >> GICH_VMCR_CTRL_SHIFT;
-+ vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >> GICH_VMCR_ALIAS_BINPOINT_SHIFT;
-+ vmcrp->bpr = (vmcr & GICH_VMCR_BINPOINT_MASK) >> GICH_VMCR_BINPOINT_SHIFT;
-+ vmcrp->pmr = (vmcr & GICH_VMCR_PRIMASK_MASK) >> GICH_VMCR_PRIMASK_SHIFT;
++ return -ENXIO;
+}
+
-+static void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
++static inline int acpi_dev_prop_read(struct acpi_device *adev,
++ const char *propname,
++ enum dev_prop_type proptype,
++ void *val, size_t nval)
+{
-+ u32 vmcr;
-+
-+ vmcr = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
-+ vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) & GICH_VMCR_ALIAS_BINPOINT_MASK;
-+ vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) & GICH_VMCR_BINPOINT_MASK;
-+ vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) & GICH_VMCR_PRIMASK_MASK;
-+
-+ vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
++ return -ENXIO;
+}
+
-+static void vgic_v2_enable(struct kvm_vcpu *vcpu)
++static inline struct acpi_device *acpi_get_next_child(struct device *dev,
++ struct acpi_device *child)
+{
-+ /*
-+ * By forcing VMCR to zero, the GIC will restore the binary
-+ * points to their reset values. Anything else resets to zero
-+ * anyway.
-+ */
-+ vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
-+
-+ /* Get the show on the road... */
-+ vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
-+}
-+
-+static const struct vgic_ops vgic_v2_ops = {
-+ .get_lr = vgic_v2_get_lr,
-+ .set_lr = vgic_v2_set_lr,
-+ .sync_lr_elrsr = vgic_v2_sync_lr_elrsr,
-+ .get_elrsr = vgic_v2_get_elrsr,
-+ .get_eisr = vgic_v2_get_eisr,
-+ .get_interrupt_status = vgic_v2_get_interrupt_status,
-+ .enable_underflow = vgic_v2_enable_underflow,
-+ .disable_underflow = vgic_v2_disable_underflow,
-+ .get_vmcr = vgic_v2_get_vmcr,
-+ .set_vmcr = vgic_v2_set_vmcr,
-+ .enable = vgic_v2_enable,
-+};
-+
-+static struct vgic_params vgic_v2_params;
-+
-+/**
-+ * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
-+ * @node: pointer to the DT node
-+ * @ops: address of a pointer to the GICv2 operations
-+ * @params: address of a pointer to HW-specific parameters
-+ *
-+ * Returns 0 if a GICv2 has been found, with the low level operations
-+ * in *ops and the HW parameters in *params. Returns an error code
-+ * otherwise.
-+ */
-+int vgic_v2_probe(struct device_node *vgic_node,
-+ const struct vgic_ops **ops,
-+ const struct vgic_params **params)
-+{
-+ int ret;
-+ struct resource vctrl_res;
-+ struct resource vcpu_res;
-+ struct vgic_params *vgic = &vgic_v2_params;
-+
-+ vgic->maint_irq = irq_of_parse_and_map(vgic_node, 0);
-+ if (!vgic->maint_irq) {
-+ kvm_err("error getting vgic maintenance irq from DT\n");
-+ ret = -ENXIO;
-+ goto out;
-+ }
-+
-+ ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
-+ if (ret) {
-+ kvm_err("Cannot obtain GICH resource\n");
-+ goto out;
-+ }
-+
-+ vgic->vctrl_base = of_iomap(vgic_node, 2);
-+ if (!vgic->vctrl_base) {
-+ kvm_err("Cannot ioremap GICH\n");
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ vgic->nr_lr = readl_relaxed(vgic->vctrl_base + GICH_VTR);
-+ vgic->nr_lr = (vgic->nr_lr & 0x3f) + 1;
-+
-+ ret = create_hyp_io_mappings(vgic->vctrl_base,
-+ vgic->vctrl_base + resource_size(&vctrl_res),
-+ vctrl_res.start);
-+ if (ret) {
-+ kvm_err("Cannot map VCTRL into hyp\n");
-+ goto out_unmap;
-+ }
-+
-+ if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
-+ kvm_err("Cannot obtain GICV resource\n");
-+ ret = -ENXIO;
-+ goto out_unmap;
-+ }
-+
-+ if (!PAGE_ALIGNED(vcpu_res.start)) {
-+ kvm_err("GICV physical address 0x%llx not page aligned\n",
-+ (unsigned long long)vcpu_res.start);
-+ ret = -ENXIO;
-+ goto out_unmap;
-+ }
-+
-+ if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
-+ kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
-+ (unsigned long long)resource_size(&vcpu_res),
-+ PAGE_SIZE);
-+ ret = -ENXIO;
-+ goto out_unmap;
-+ }
-+
-+ vgic->vcpu_base = vcpu_res.start;
++ return NULL;
++}
+
-+ kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
-+ vgic->vctrl_base, vgic->maint_irq);
++#endif
+
-+ vgic->type = VGIC_V2;
-+ *ops = &vgic_v2_ops;
-+ *params = vgic;
-+ goto out;
+ #endif /*_LINUX_ACPI_H*/
+diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
+index abcafaa..4f5caa1 100644
+--- a/include/linux/clocksource.h
++++ b/include/linux/clocksource.h
+@@ -346,4 +346,10 @@ extern void clocksource_of_init(void);
+ static inline void clocksource_of_init(void) {}
+ #endif
+
++#ifdef CONFIG_ACPI
++void acpi_generic_timer_init(void);
++#else
++static inline void acpi_generic_timer_init(void) {}
++#endif
+
-+out_unmap:
-+ iounmap(vgic->vctrl_base);
-+out:
-+ of_node_put(vgic_node);
-+ return ret;
-+}
-diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
+ #endif /* _LINUX_CLOCKSOURCE_H */
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 0949f9c..0238d61 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -547,6 +547,9 @@ void efi_native_runtime_setup(void);
+ #define SMBIOS_TABLE_GUID \
+ EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+
++#define SMBIOS3_TABLE_GUID \
++ EFI_GUID( 0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 )
++
+ #define SAL_SYSTEM_TABLE_GUID \
+ EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+
+@@ -810,7 +813,8 @@ extern struct efi {
+ unsigned long mps; /* MPS table */
+ unsigned long acpi; /* ACPI table (IA64 ext 0.71) */
+ unsigned long acpi20; /* ACPI table (ACPI 2.0) */
+- unsigned long smbios; /* SM BIOS table */
++ unsigned long smbios; /* SMBIOS table (32 bit entry point) */
++ unsigned long smbios3; /* SMBIOS table (64 bit entry point) */
+ unsigned long sal_systab; /* SAL system table */
+ unsigned long boot_info; /* boot info table */
+ unsigned long hcdp; /* HCDP table */
+diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
+index 12f146f..00b1b70 100644
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -94,6 +94,13 @@ 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 fwnode_handle;
++
++struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
++ const char *propname);
++struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
++ struct fwnode_handle *child);
+ #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..f01d446
+index 0000000..ad5b577
--- /dev/null
-+++ b/virt/kvm/arm/vgic-v3.c
-@@ -0,0 +1,231 @@
++++ b/include/linux/irqchip/arm-gic-acpi.h
+@@ -0,0 +1,31 @@
+/*
-+ * Copyright (C) 2013 ARM Limited, All Rights Reserved.
-+ * Author: Marc Zyngier <marc.zyngier@arm.com>
++ * Copyright (C) 2014, Linaro Ltd.
++ * Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
-+#include <linux/cpu.h>
-+#include <linux/kvm.h>
-+#include <linux/kvm_host.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+
-+#include <linux/irqchip/arm-gic-v3.h>
++#ifndef ARM_GIC_ACPI_H_
++#define ARM_GIC_ACPI_H_
+
-+#include <asm/kvm_emulate.h>
-+#include <asm/kvm_arm.h>
-+#include <asm/kvm_mmu.h>
-+
-+/* These are for GICv2 emulation only */
-+#define GICH_LR_VIRTUALID (0x3ffUL << 0)
-+#define GICH_LR_PHYSID_CPUID_SHIFT (10)
-+#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
++#ifdef CONFIG_ACPI
+
+/*
-+ * LRs are stored in reverse order in memory. make sure we index them
-+ * correctly.
++ * Hard code here, we can not get memory size from MADT (but FDT does),
++ * Actually no need to do that, because this size can be inferred
++ * from GIC spec.
+ */
-+#define LR_INDEX(lr) (VGIC_V3_MAX_LRS - 1 - lr)
-+
-+static u32 ich_vtr_el2;
++#define ACPI_GICV2_DIST_MEM_SIZE (SZ_4K)
++#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K)
+
-+static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
-+{
-+ struct vgic_lr lr_desc;
-+ u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)];
-+
-+ lr_desc.irq = val & GICH_LR_VIRTUALID;
-+ if (lr_desc.irq <= 15)
-+ lr_desc.source = (val >> GICH_LR_PHYSID_CPUID_SHIFT) & 0x7;
-+ else
-+ lr_desc.source = 0;
-+ lr_desc.state = 0;
-+
-+ if (val & ICH_LR_PENDING_BIT)
-+ lr_desc.state |= LR_STATE_PENDING;
-+ if (val & ICH_LR_ACTIVE_BIT)
-+ lr_desc.state |= LR_STATE_ACTIVE;
-+ if (val & ICH_LR_EOI)
-+ lr_desc.state |= LR_EOI_INT;
-+
-+ return lr_desc;
-+}
-+
-+static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
-+ struct vgic_lr lr_desc)
-+{
-+ u64 lr_val = (((u32)lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT) |
-+ lr_desc.irq);
-+
-+ if (lr_desc.state & LR_STATE_PENDING)
-+ lr_val |= ICH_LR_PENDING_BIT;
-+ if (lr_desc.state & LR_STATE_ACTIVE)
-+ lr_val |= ICH_LR_ACTIVE_BIT;
-+ if (lr_desc.state & LR_EOI_INT)
-+ lr_val |= ICH_LR_EOI;
++struct acpi_table_header;
+
-+ vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val;
-+}
++void acpi_gic_init(void);
++int gic_v2_acpi_init(struct acpi_table_header *table);
++#else
++static inline void acpi_gic_init(void) { }
++#endif
+
-+static void vgic_v3_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
-+ struct vgic_lr lr_desc)
++#endif /* ARM_GIC_ACPI_H_ */
+diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
+index 13eed92..dc9cb5f 100644
+--- a/include/linux/irqchip/arm-gic.h
++++ b/include/linux/irqchip/arm-gic.h
+@@ -55,6 +55,8 @@
+ (GICD_INT_DEF_PRI << 8) |\
+ GICD_INT_DEF_PRI)
+
++#define GIC_DIST_SOFTINT_NSATT 0x8000
++
+ #define GICH_HCR 0x0
+ #define GICH_VTR 0x4
+ #define GICH_VMCR 0x8
+diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
+index a6059bd..e4d8f70 100644
+--- a/include/linux/kvm_host.h
++++ b/include/linux/kvm_host.h
+@@ -43,6 +43,7 @@
+ * include/linux/kvm_h.
+ */
+ #define KVM_MEMSLOT_INVALID (1UL << 16)
++#define KVM_MEMSLOT_INCOHERENT (1UL << 17)
+
+ /* Two fragments for cross MMIO pages. */
+ #define KVM_MAX_MMIO_FRAGMENTS 2
+diff --git a/include/linux/leds.h b/include/linux/leds.h
+index a57611d..361101f 100644
+--- a/include/linux/leds.h
++++ b/include/linux/leds.h
+@@ -261,6 +261,7 @@ struct gpio_led {
+ unsigned retain_state_suspended : 1;
+ unsigned default_state : 2;
+ /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
++ struct gpio_desc *gpiod;
+ };
+ #define LEDS_GPIO_DEFSTATE_OFF 0
+ #define LEDS_GPIO_DEFSTATE_ON 1
+@@ -273,7 +274,7 @@ struct gpio_led_platform_data {
+ #define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */
+ #define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
+ #define GPIO_LED_BLINK 2 /* Please, blink */
+- int (*gpio_blink_set)(unsigned gpio, int state,
++ int (*gpio_blink_set)(struct gpio_desc *desc, int state,
+ unsigned long *delay_on,
+ unsigned long *delay_off);
+ };
+diff --git a/include/linux/of.h b/include/linux/of.h
+index 29f0adc..cf79be1 100644
+--- a/include/linux/of.h
++++ b/include/linux/of.h
+@@ -23,6 +23,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/topology.h>
+ #include <linux/notifier.h>
++#include <linux/property.h>
+
+ #include <asm/byteorder.h>
+ #include <asm/errno.h>
+@@ -49,6 +50,7 @@ struct device_node {
+ const char *type;
+ phandle phandle;
+ const char *full_name;
++ struct fwnode_handle fwnode;
+
+ struct property *properties;
+ struct property *deadprops; /* removed properties */
+@@ -79,6 +81,7 @@ extern struct kobj_type of_node_ktype;
+ static inline void of_node_init(struct device_node *node)
+ {
+ kobject_init(&node->kobj, &of_node_ktype);
++ node->fwnode.type = FWNODE_OF;
+ }
+
+ /* true when node is initialized */
+@@ -114,6 +117,16 @@ extern struct device_node *of_aliases;
+ extern struct device_node *of_stdout;
+ extern raw_spinlock_t devtree_lock;
+
++static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
-+ if (!(lr_desc.state & LR_STATE_MASK))
-+ vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
++ return fwnode && fwnode->type == FWNODE_OF;
+}
+
-+static u64 vgic_v3_get_elrsr(const struct kvm_vcpu *vcpu)
++static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
-+ return vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr;
++ return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
+}
+
-+static u64 vgic_v3_get_eisr(const struct kvm_vcpu *vcpu)
+ static inline bool of_have_populated_dt(void)
+ {
+ return of_allnodes != NULL;
+@@ -263,6 +276,10 @@ extern int of_property_read_u32_array(const struct device_node *np,
+ size_t sz);
+ extern int of_property_read_u64(const struct device_node *np,
+ const char *propname, u64 *out_value);
++extern int of_property_read_u64_array(const struct device_node *np,
++ const char *propname,
++ u64 *out_values,
++ size_t sz);
+
+ extern int of_property_read_string(struct device_node *np,
+ const char *propname,
+@@ -355,6 +372,16 @@ bool of_console_check(struct device_node *dn, char *name, int index);
+
+ #else /* CONFIG_OF */
+
++static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
-+ return vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr;
++ return false;
+}
+
-+static u32 vgic_v3_get_interrupt_status(const struct kvm_vcpu *vcpu)
++static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
-+ u32 misr = vcpu->arch.vgic_cpu.vgic_v3.vgic_misr;
-+ u32 ret = 0;
-+
-+ if (misr & ICH_MISR_EOI)
-+ ret |= INT_STATUS_EOI;
-+ if (misr & ICH_MISR_U)
-+ ret |= INT_STATUS_UNDERFLOW;
-+
-+ return ret;
++ return NULL;
+}
+
-+static void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+ static inline const char* of_node_full_name(const struct device_node *np)
+ {
+ return "<no-node>";
+@@ -477,6 +504,13 @@ static inline int of_property_read_u32_array(const struct device_node *np,
+ return -ENOSYS;
+ }
+
++static inline int of_property_read_u64_array(const struct device_node *np,
++ const char *propname,
++ u64 *out_values, size_t sz)
+{
-+ u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
-+
-+ vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
-+ vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
-+ vmcrp->bpr = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
-+ vmcrp->pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
++ return -ENOSYS;
+}
+
-+static void vgic_v3_enable_underflow(struct kvm_vcpu *vcpu)
-+{
-+ vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr |= ICH_HCR_UIE;
-+}
+ static inline int of_property_read_string(struct device_node *np,
+ const char *propname,
+ const char **out_string)
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 4c8ac5f..ea663d8 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -563,15 +563,6 @@ struct pci_ops {
+ int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
+ };
+
+-/*
+- * ACPI needs to be able to access PCI config space before we've done a
+- * PCI bus scan and created pci_bus structures.
+- */
+-int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
+- int reg, int len, u32 *val);
+-int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
+- int reg, int len, u32 val);
+-
+ struct pci_bus_region {
+ dma_addr_t start;
+ dma_addr_t end;
+@@ -1326,6 +1317,16 @@ typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
+ unsigned int command_bits, u32 flags);
+ void pci_register_set_vga_state(arch_set_vga_state_t func);
+
++/*
++ * ACPI needs to be able to access PCI config space before we've done a
++ * PCI bus scan and created pci_bus structures.
++ */
++int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
++ int reg, int len, u32 *val);
++int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
++ int reg, int len, u32 val);
++void pcibios_penalize_isa_irq(int irq, int active);
+
-+static void vgic_v3_disable_underflow(struct kvm_vcpu *vcpu)
-+{
-+ vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr &= ~ICH_HCR_UIE;
-+}
+ #else /* CONFIG_PCI is not enabled */
+
+ /*
+@@ -1427,6 +1428,23 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
+ unsigned int devfn)
+ { return NULL; }
+
++static inline struct pci_bus *pci_find_bus(int domain, int busnr)
++{ return NULL; }
++
++static inline int pci_bus_write_config_byte(struct pci_bus *bus,
++ unsigned int devfn, int where, u8 val)
++{ return -ENOSYS; }
++
++static inline int raw_pci_read(unsigned int domain, unsigned int bus,
++ unsigned int devfn, int reg, int len, u32 *val)
++{ return -ENOSYS; }
++
++static inline int raw_pci_write(unsigned int domain, unsigned int bus,
++ unsigned int devfn, int reg, int len, u32 val)
++{ return -ENOSYS; }
++
++static inline void pcibios_penalize_isa_irq(int irq, int active) { }
++
+ static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
+ static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
+ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
+@@ -1636,7 +1654,6 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev,
+ enum pcie_reset_state state);
+ int pcibios_add_device(struct pci_dev *dev);
+ void pcibios_release_device(struct pci_dev *dev);
+-void pcibios_penalize_isa_irq(int irq, int active);
+
+ #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..a6a3d98
+--- /dev/null
++++ b/include/linux/property.h
+@@ -0,0 +1,143 @@
++/*
++ * property.h - Unified device property interface.
++ *
++ * Copyright (C) 2014, Intel Corporation
++ * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
++ * Mika Westerberg <mika.westerberg@linux.intel.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
+
-+static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
-+{
-+ u32 vmcr;
++#ifndef _LINUX_PROPERTY_H_
++#define _LINUX_PROPERTY_H_
+
-+ vmcr = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
-+ vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
-+ vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
-+ vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
++#include <linux/types.h>
+
-+ vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
-+}
++struct device;
+
-+static void vgic_v3_enable(struct kvm_vcpu *vcpu)
-+{
-+ /*
-+ * By forcing VMCR to zero, the GIC will restore the binary
-+ * points to their reset values. Anything else resets to zero
-+ * anyway.
-+ */
-+ vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = 0;
-+
-+ /* Get the show on the road... */
-+ vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr = ICH_HCR_EN;
-+}
-+
-+static const struct vgic_ops vgic_v3_ops = {
-+ .get_lr = vgic_v3_get_lr,
-+ .set_lr = vgic_v3_set_lr,
-+ .sync_lr_elrsr = vgic_v3_sync_lr_elrsr,
-+ .get_elrsr = vgic_v3_get_elrsr,
-+ .get_eisr = vgic_v3_get_eisr,
-+ .get_interrupt_status = vgic_v3_get_interrupt_status,
-+ .enable_underflow = vgic_v3_enable_underflow,
-+ .disable_underflow = vgic_v3_disable_underflow,
-+ .get_vmcr = vgic_v3_get_vmcr,
-+ .set_vmcr = vgic_v3_set_vmcr,
-+ .enable = vgic_v3_enable,
++enum dev_prop_type {
++ DEV_PROP_U8,
++ DEV_PROP_U16,
++ DEV_PROP_U32,
++ DEV_PROP_U64,
++ DEV_PROP_STRING,
++ DEV_PROP_MAX,
+};
+
-+static struct vgic_params vgic_v3_params;
-+
-+/**
-+ * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
-+ * @node: pointer to the DT node
-+ * @ops: address of a pointer to the GICv3 operations
-+ * @params: address of a pointer to HW-specific parameters
-+ *
-+ * Returns 0 if a GICv3 has been found, with the low level operations
-+ * in *ops and the HW parameters in *params. Returns an error code
-+ * otherwise.
-+ */
-+int vgic_v3_probe(struct device_node *vgic_node,
-+ const struct vgic_ops **ops,
-+ const struct vgic_params **params)
-+{
-+ int ret = 0;
-+ u32 gicv_idx;
-+ struct resource vcpu_res;
-+ struct vgic_params *vgic = &vgic_v3_params;
++bool device_property_present(struct device *dev, const char *propname);
++int device_property_read_u8_array(struct device *dev, const char *propname,
++ u8 *val, size_t nval);
++int device_property_read_u16_array(struct device *dev, const char *propname,
++ u16 *val, size_t nval);
++int device_property_read_u32_array(struct device *dev, const char *propname,
++ u32 *val, size_t nval);
++int device_property_read_u64_array(struct device *dev, const char *propname,
++ u64 *val, size_t nval);
++int device_property_read_string_array(struct device *dev, const char *propname,
++ const char **val, size_t nval);
++int device_property_read_string(struct device *dev, const char *propname,
++ const char **val);
++
++enum fwnode_type {
++ FWNODE_INVALID = 0,
++ FWNODE_OF,
++ FWNODE_ACPI,
++};
+
-+ vgic->maint_irq = irq_of_parse_and_map(vgic_node, 0);
-+ if (!vgic->maint_irq) {
-+ kvm_err("error getting vgic maintenance irq from DT\n");
-+ ret = -ENXIO;
-+ goto out;
-+ }
++struct fwnode_handle {
++ enum fwnode_type type;
++};
+
-+ ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
++bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
++int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
++ const char *propname, u8 *val,
++ size_t nval);
++int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
++ const char *propname, u16 *val,
++ size_t nval);
++int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
++ const char *propname, u32 *val,
++ size_t nval);
++int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
++ const char *propname, u64 *val,
++ size_t nval);
++int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
++ const char *propname, const char **val,
++ size_t nval);
++int fwnode_property_read_string(struct fwnode_handle *fwnode,
++ const char *propname, const char **val);
+
-+ /*
-+ * The ListRegs field is 5 bits, but there is a architectural
-+ * maximum of 16 list registers. Just ignore bit 4...
-+ */
-+ vgic->nr_lr = (ich_vtr_el2 & 0xf) + 1;
++struct fwnode_handle *device_get_next_child_node(struct device *dev,
++ struct fwnode_handle *child);
+
-+ if (of_property_read_u32(vgic_node, "#redistributor-regions", &gicv_idx))
-+ gicv_idx = 1;
++#define device_for_each_child_node(dev, child) \
++ for (child = device_get_next_child_node(dev, NULL); child; \
++ child = device_get_next_child_node(dev, child))
+
-+ gicv_idx += 3; /* Also skip GICD, GICC, GICH */
-+ if (of_address_to_resource(vgic_node, gicv_idx, &vcpu_res)) {
-+ kvm_err("Cannot obtain GICV region\n");
-+ ret = -ENXIO;
-+ goto out;
-+ }
-+ vgic->vcpu_base = vcpu_res.start;
-+ vgic->vctrl_base = NULL;
-+ vgic->type = VGIC_V3;
++void fwnode_handle_put(struct fwnode_handle *fwnode);
+
-+ kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
-+ vcpu_res.start, vgic->maint_irq);
++unsigned int device_get_child_node_count(struct device *dev);
+
-+ *ops = &vgic_v3_ops;
-+ *params = vgic;
-+
-+out:
-+ of_node_put(vgic_node);
-+ return ret;
-+}
-diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
-index 476d3bf..795ab48 100644
---- a/virt/kvm/arm/vgic.c
-+++ b/virt/kvm/arm/vgic.c
-@@ -76,14 +76,6 @@
- #define IMPLEMENTER_ARM 0x43b
- #define GICC_ARCH_VERSION_V2 0x2
-
--/* Physical address of vgic virtual cpu interface */
--static phys_addr_t vgic_vcpu_base;
--
--/* Virtual control interface base address */
--static void __iomem *vgic_vctrl_base;
--
--static struct device_node *vgic_node;
--
- #define ACCESS_READ_VALUE (1 << 0)
- #define ACCESS_READ_RAZ (0 << 0)
- #define ACCESS_READ_MASK(x) ((x) & (1 << 0))
-@@ -94,12 +86,17 @@ static struct device_node *vgic_node;
- #define ACCESS_WRITE_MASK(x) ((x) & (3 << 1))
-
- static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
-+static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu);
- static void vgic_update_state(struct kvm *kvm);
- static void vgic_kick_vcpus(struct kvm *kvm);
- static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg);
--static u32 vgic_nr_lr;
-+static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr);
-+static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc);
-+static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-+static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-
--static unsigned int vgic_maint_irq;
-+static const struct vgic_ops *vgic_ops;
-+static const struct vgic_params *vgic;
-
- static u32 *vgic_bitmap_get_reg(struct vgic_bitmap *x,
- int cpuid, u32 offset)
-@@ -593,18 +590,6 @@ static bool handle_mmio_sgi_reg(struct kvm_vcpu *vcpu,
- return false;
- }
-
--#define LR_CPUID(lr) \
-- (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
--#define LR_IRQID(lr) \
-- ((lr) & GICH_LR_VIRTUALID)
--
--static void vgic_retire_lr(int lr_nr, int irq, struct vgic_cpu *vgic_cpu)
--{
-- clear_bit(lr_nr, vgic_cpu->lr_used);
-- vgic_cpu->vgic_lr[lr_nr] &= ~GICH_LR_STATE;
-- vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
--}
--
- /**
- * vgic_unqueue_irqs - move pending IRQs from LRs to the distributor
- * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs
-@@ -622,13 +607,10 @@ static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
- struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
- struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
- int vcpu_id = vcpu->vcpu_id;
-- int i, irq, source_cpu;
-- u32 *lr;
-+ int i;
-
- for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
-- lr = &vgic_cpu->vgic_lr[i];
-- irq = LR_IRQID(*lr);
-- source_cpu = LR_CPUID(*lr);
-+ struct vgic_lr lr = vgic_get_lr(vcpu, i);
-
- /*
- * There are three options for the state bits:
-@@ -640,7 +622,7 @@ static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
- * If the LR holds only an active interrupt (not pending) then
- * just leave it alone.
- */
-- if ((*lr & GICH_LR_STATE) == GICH_LR_ACTIVE_BIT)
-+ if ((lr.state & LR_STATE_MASK) == LR_STATE_ACTIVE)
- continue;
-
- /*
-@@ -649,18 +631,19 @@ static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
- * is fine, then we are only setting a few bits that were
- * already set.
- */
-- vgic_dist_irq_set(vcpu, irq);
-- if (irq < VGIC_NR_SGIS)
-- dist->irq_sgi_sources[vcpu_id][irq] |= 1 << source_cpu;
-- *lr &= ~GICH_LR_PENDING_BIT;
-+ vgic_dist_irq_set(vcpu, lr.irq);
-+ if (lr.irq < VGIC_NR_SGIS)
-+ dist->irq_sgi_sources[vcpu_id][lr.irq] |= 1 << lr.source;
-+ lr.state &= ~LR_STATE_PENDING;
-+ vgic_set_lr(vcpu, i, lr);
-
- /*
- * If there's no state left on the LR (it could still be
- * active), then the LR does not hold any useful info and can
- * be marked as free for other use.
- */
-- if (!(*lr & GICH_LR_STATE))
-- vgic_retire_lr(i, irq, vgic_cpu);
-+ if (!(lr.state & LR_STATE_MASK))
-+ vgic_retire_lr(i, lr.irq, vcpu);
-
- /* Finally update the VGIC state. */
- vgic_update_state(vcpu->kvm);
-@@ -989,8 +972,73 @@ static void vgic_update_state(struct kvm *kvm)
- }
- }
-
--#define MK_LR_PEND(src, irq) \
-- (GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) | (irq))
-+static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
++static inline bool device_property_read_bool(struct device *dev,
++ const char *propname)
+{
-+ return vgic_ops->get_lr(vcpu, lr);
++ return device_property_present(dev, propname);
+}
+
-+static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr,
-+ struct vgic_lr vlr)
++static inline int device_property_read_u8(struct device *dev,
++ const char *propname, u8 *val)
+{
-+ vgic_ops->set_lr(vcpu, lr, vlr);
++ return device_property_read_u8_array(dev, propname, val, 1);
+}
+
-+static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
-+ struct vgic_lr vlr)
++static inline int device_property_read_u16(struct device *dev,
++ const char *propname, u16 *val)
+{
-+ vgic_ops->sync_lr_elrsr(vcpu, lr, vlr);
++ return device_property_read_u16_array(dev, propname, val, 1);
+}
+
-+static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
++static inline int device_property_read_u32(struct device *dev,
++ const char *propname, u32 *val)
+{
-+ return vgic_ops->get_elrsr(vcpu);
++ return device_property_read_u32_array(dev, propname, val, 1);
+}
+
-+static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
++static inline int device_property_read_u64(struct device *dev,
++ const char *propname, u64 *val)
+{
-+ return vgic_ops->get_eisr(vcpu);
++ return device_property_read_u64_array(dev, propname, val, 1);
+}
+
-+static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)
++static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode,
++ const char *propname)
+{
-+ return vgic_ops->get_interrupt_status(vcpu);
++ return fwnode_property_present(fwnode, propname);
+}
+
-+static inline void vgic_enable_underflow(struct kvm_vcpu *vcpu)
++static inline int fwnode_property_read_u8(struct fwnode_handle *fwnode,
++ const char *propname, u8 *val)
+{
-+ vgic_ops->enable_underflow(vcpu);
++ return fwnode_property_read_u8_array(fwnode, propname, val, 1);
+}
+
-+static inline void vgic_disable_underflow(struct kvm_vcpu *vcpu)
++static inline int fwnode_property_read_u16(struct fwnode_handle *fwnode,
++ const char *propname, u16 *val)
+{
-+ vgic_ops->disable_underflow(vcpu);
++ return fwnode_property_read_u16_array(fwnode, propname, val, 1);
+}
+
-+static inline void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
++static inline int fwnode_property_read_u32(struct fwnode_handle *fwnode,
++ const char *propname, u32 *val)
+{
-+ vgic_ops->get_vmcr(vcpu, vmcr);
++ return fwnode_property_read_u32_array(fwnode, propname, val, 1);
+}
+
-+static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
++static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode,
++ const char *propname, u64 *val)
+{
-+ vgic_ops->set_vmcr(vcpu, vmcr);
++ return fwnode_property_read_u64_array(fwnode, propname, val, 1);
+}
+
-+static inline void vgic_enable(struct kvm_vcpu *vcpu)
-+{
-+ vgic_ops->enable(vcpu);
-+}
++#endif /* _LINUX_PROPERTY_H_ */
+diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
+index 0f62326..2a47179 100644
+--- a/net/rfkill/rfkill-gpio.c
++++ b/net/rfkill/rfkill-gpio.c
+@@ -63,6 +63,15 @@ static const struct rfkill_ops rfkill_gpio_ops = {
+ .set_block = rfkill_gpio_set_power,
+ };
+
++static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
++static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
+
-+static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
-+{
-+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-+ struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
++static const struct acpi_gpio_mapping acpi_rfkill_default_gpios[] = {
++ { "reset-gpios", &reset_gpios, 1 },
++ { "shutdown-gpios", &shutdown_gpios, 1 },
++ { },
++};
+
-+ vlr.state = 0;
-+ vgic_set_lr(vcpu, lr_nr, vlr);
-+ clear_bit(lr_nr, vgic_cpu->lr_used);
-+ vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
-+}
-
- /*
- * An interrupt may have been disabled after being made pending on the
-@@ -1006,13 +1054,13 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
- struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
- int lr;
-
-- for_each_set_bit(lr, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
-- int irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
-+ for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) {
-+ struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
-
-- if (!vgic_irq_is_enabled(vcpu, irq)) {
-- vgic_retire_lr(lr, irq, vgic_cpu);
-- if (vgic_irq_is_active(vcpu, irq))
-- vgic_irq_clear_active(vcpu, irq);
-+ if (!vgic_irq_is_enabled(vcpu, vlr.irq)) {
-+ vgic_retire_lr(lr, vlr.irq, vcpu);
-+ if (vgic_irq_is_active(vcpu, vlr.irq))
-+ vgic_irq_clear_active(vcpu, vlr.irq);
- }
- }
- }
-@@ -1024,6 +1072,7 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
- static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
+ static int rfkill_gpio_acpi_probe(struct device *dev,
+ struct rfkill_gpio_data *rfkill)
{
- struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-+ struct vgic_lr vlr;
- int lr;
-
- /* Sanitize the input... */
-@@ -1036,28 +1085,34 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
- lr = vgic_cpu->vgic_irq_lr_map[irq];
-
- /* Do we have an active interrupt for the same CPUID? */
-- if (lr != LR_EMPTY &&
-- (LR_CPUID(vgic_cpu->vgic_lr[lr]) == sgi_source_id)) {
-- kvm_debug("LR%d piggyback for IRQ%d %x\n",
-- lr, irq, vgic_cpu->vgic_lr[lr]);
-- BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
-- vgic_cpu->vgic_lr[lr] |= GICH_LR_PENDING_BIT;
-- return true;
-+ if (lr != LR_EMPTY) {
-+ vlr = vgic_get_lr(vcpu, lr);
-+ if (vlr.source == sgi_source_id) {
-+ kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq);
-+ BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
-+ vlr.state |= LR_STATE_PENDING;
-+ vgic_set_lr(vcpu, lr, vlr);
-+ return true;
-+ }
- }
+@@ -75,7 +84,8 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
+ rfkill->name = dev_name(dev);
+ rfkill->type = (unsigned)id->driver_data;
- /* Try to use another LR for this interrupt */
- lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used,
-- vgic_cpu->nr_lr);
-- if (lr >= vgic_cpu->nr_lr)
-+ vgic->nr_lr);
-+ if (lr >= vgic->nr_lr)
- return false;
-
- kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
-- vgic_cpu->vgic_lr[lr] = MK_LR_PEND(sgi_source_id, irq);
- vgic_cpu->vgic_irq_lr_map[irq] = lr;
- set_bit(lr, vgic_cpu->lr_used);
-
-+ vlr.irq = irq;
-+ vlr.source = sgi_source_id;
-+ vlr.state = LR_STATE_PENDING;
- if (!vgic_irq_is_edge(vcpu, irq))
-- vgic_cpu->vgic_lr[lr] |= GICH_LR_EOI;
-+ vlr.state |= LR_EOI_INT;
-+
-+ vgic_set_lr(vcpu, lr, vlr);
-
- return true;
+- return 0;
++ return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
++ acpi_rfkill_default_gpios);
}
-@@ -1155,9 +1210,9 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
- epilog:
- if (overflow) {
-- vgic_cpu->vgic_hcr |= GICH_HCR_UIE;
-+ vgic_enable_underflow(vcpu);
- } else {
-- vgic_cpu->vgic_hcr &= ~GICH_HCR_UIE;
-+ vgic_disable_underflow(vcpu);
- /*
- * We're about to run this VCPU, and we've consumed
- * everything the distributor had in store for
-@@ -1170,44 +1225,46 @@ epilog:
-
- static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
- {
-- struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-+ u32 status = vgic_get_interrupt_status(vcpu);
- bool level_pending = false;
+ static int rfkill_gpio_probe(struct platform_device *pdev)
+@@ -102,7 +112,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
-- kvm_debug("MISR = %08x\n", vgic_cpu->vgic_misr);
-+ kvm_debug("STATUS = %08x\n", status);
-
-- if (vgic_cpu->vgic_misr & GICH_MISR_EOI) {
-+ if (status & INT_STATUS_EOI) {
- /*
- * Some level interrupts have been EOIed. Clear their
- * active bit.
- */
-- int lr, irq;
-+ u64 eisr = vgic_get_eisr(vcpu);
-+ unsigned long *eisr_ptr = (unsigned long *)&eisr;
-+ int lr;
-
-- for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_eisr,
-- vgic_cpu->nr_lr) {
-- irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
-+ for_each_set_bit(lr, eisr_ptr, vgic->nr_lr) {
-+ struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
-
-- vgic_irq_clear_active(vcpu, irq);
-- vgic_cpu->vgic_lr[lr] &= ~GICH_LR_EOI;
-+ vgic_irq_clear_active(vcpu, vlr.irq);
-+ WARN_ON(vlr.state & LR_STATE_MASK);
-+ vlr.state = 0;
-+ vgic_set_lr(vcpu, lr, vlr);
-
- /* Any additional pending interrupt? */
-- if (vgic_dist_irq_is_pending(vcpu, irq)) {
-- vgic_cpu_irq_set(vcpu, irq);
-+ if (vgic_dist_irq_is_pending(vcpu, vlr.irq)) {
-+ vgic_cpu_irq_set(vcpu, vlr.irq);
- level_pending = true;
- } else {
-- vgic_cpu_irq_clear(vcpu, irq);
-+ vgic_cpu_irq_clear(vcpu, vlr.irq);
- }
+ rfkill->clk = devm_clk_get(&pdev->dev, NULL);
- /*
- * Despite being EOIed, the LR may not have
- * been marked as empty.
- */
-- set_bit(lr, (unsigned long *)vgic_cpu->vgic_elrsr);
-- vgic_cpu->vgic_lr[lr] &= ~GICH_LR_ACTIVE_BIT;
-+ vgic_sync_lr_elrsr(vcpu, lr, vlr);
- }
- }
-
-- if (vgic_cpu->vgic_misr & GICH_MISR_U)
-- vgic_cpu->vgic_hcr &= ~GICH_HCR_UIE;
-+ if (status & INT_STATUS_UNDERFLOW)
-+ vgic_disable_underflow(vcpu);
-
- return level_pending;
- }
-@@ -1220,29 +1277,31 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
- {
- struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
- struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-+ u64 elrsr;
-+ unsigned long *elrsr_ptr;
- int lr, pending;
- bool level_pending;
-
- level_pending = vgic_process_maintenance(vcpu);
-+ elrsr = vgic_get_elrsr(vcpu);
-+ elrsr_ptr = (unsigned long *)&elrsr;
-
- /* Clear mappings for empty LRs */
-- for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_elrsr,
-- vgic_cpu->nr_lr) {
-- int irq;
-+ for_each_set_bit(lr, elrsr_ptr, vgic->nr_lr) {
-+ struct vgic_lr vlr;
-
- if (!test_and_clear_bit(lr, vgic_cpu->lr_used))
- continue;
-
-- irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
-+ vlr = vgic_get_lr(vcpu, lr);
-
-- BUG_ON(irq >= VGIC_NR_IRQS);
-- vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
-+ BUG_ON(vlr.irq >= VGIC_NR_IRQS);
-+ vgic_cpu->vgic_irq_lr_map[vlr.irq] = LR_EMPTY;
+- gpio = devm_gpiod_get_index(&pdev->dev, "reset", 0);
++ gpio = devm_gpiod_get(&pdev->dev, "reset");
+ if (!IS_ERR(gpio)) {
+ ret = gpiod_direction_output(gpio, 0);
+ if (ret)
+@@ -110,7 +120,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
+ rfkill->reset_gpio = gpio;
}
- /* Check if we still have something up our sleeve... */
-- pending = find_first_zero_bit((unsigned long *)vgic_cpu->vgic_elrsr,
-- vgic_cpu->nr_lr);
-- if (level_pending || pending < vgic_cpu->nr_lr)
-+ pending = find_first_zero_bit(elrsr_ptr, vgic->nr_lr);
-+ if (level_pending || pending < vgic->nr_lr)
- set_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu);
- }
-
-@@ -1432,21 +1491,20 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
- }
-
- /*
-- * By forcing VMCR to zero, the GIC will restore the binary
-- * points to their reset values. Anything else resets to zero
-- * anyway.
-+ * Store the number of LRs per vcpu, so we don't have to go
-+ * all the way to the distributor structure to find out. Only
-+ * assembly code should use this one.
- */
-- vgic_cpu->vgic_vmcr = 0;
-+ vgic_cpu->nr_lr = vgic->nr_lr;
-
-- vgic_cpu->nr_lr = vgic_nr_lr;
-- vgic_cpu->vgic_hcr = GICH_HCR_EN; /* Get the show on the road... */
-+ vgic_enable(vcpu);
+- gpio = devm_gpiod_get_index(&pdev->dev, "shutdown", 1);
++ gpio = devm_gpiod_get(&pdev->dev, "shutdown");
+ if (!IS_ERR(gpio)) {
+ ret = gpiod_direction_output(gpio, 0);
+ if (ret)
+@@ -150,6 +160,8 @@ static int rfkill_gpio_remove(struct platform_device *pdev)
+ rfkill_unregister(rfkill->rfkill_dev);
+ rfkill_destroy(rfkill->rfkill_dev);
++ acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
++
return 0;
}
- static void vgic_init_maintenance_interrupt(void *info)
- {
-- enable_percpu_irq(vgic_maint_irq, 0);
-+ enable_percpu_irq(vgic->maint_irq, 0);
- }
+diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
+index 22fa819..642dad4 100644
+--- a/virt/kvm/arm/arch_timer.c
++++ b/virt/kvm/arm/arch_timer.c
+@@ -21,9 +21,11 @@
+ #include <linux/kvm.h>
+ #include <linux/kvm_host.h>
+ #include <linux/interrupt.h>
++#include <linux/acpi.h>
- static int vgic_cpu_notify(struct notifier_block *self,
-@@ -1459,7 +1517,7 @@ static int vgic_cpu_notify(struct notifier_block *self,
- break;
- case CPU_DYING:
- case CPU_DYING_FROZEN:
-- disable_percpu_irq(vgic_maint_irq);
-+ disable_percpu_irq(vgic->maint_irq);
- break;
- }
+ #include <clocksource/arm_arch_timer.h>
+ #include <asm/arch_timer.h>
++#include <asm/acpi.h>
-@@ -1470,30 +1528,37 @@ static struct notifier_block vgic_cpu_nb = {
- .notifier_call = vgic_cpu_notify,
+ #include <kvm/arm_vgic.h>
+ #include <kvm/arm_arch_timer.h>
+@@ -244,60 +246,91 @@ static const struct of_device_id arch_timer_of_match[] = {
+ {},
};
-+static const struct of_device_id vgic_ids[] = {
-+ { .compatible = "arm,cortex-a15-gic", .data = vgic_v2_probe, },
-+ { .compatible = "arm,gic-v3", .data = vgic_v3_probe, },
-+ {},
-+};
-+
- int kvm_vgic_hyp_init(void)
+-int kvm_timer_hyp_init(void)
++static int kvm_timer_ppi_parse_dt(unsigned int *ppi)
{
-+ const struct of_device_id *matched_id;
-+ int (*vgic_probe)(struct device_node *,const struct vgic_ops **,
-+ const struct vgic_params **);
-+ struct device_node *vgic_node;
- int ret;
-- struct resource vctrl_res;
-- struct resource vcpu_res;
-
-- vgic_node = of_find_compatible_node(NULL, NULL, "arm,cortex-a15-gic");
-+ vgic_node = of_find_matching_node_and_match(NULL,
-+ vgic_ids, &matched_id);
- if (!vgic_node) {
-- kvm_err("error: no compatible vgic node in DT\n");
-+ kvm_err("error: no compatible GIC node found\n");
+ struct device_node *np;
+- unsigned int ppi;
+- int err;
+-
+- timecounter = arch_timer_get_timecounter();
+- if (!timecounter)
+- return -ENODEV;
+
+ np = of_find_matching_node(NULL, arch_timer_of_match);
+ if (!np) {
+- kvm_err("kvm_arch_timer: can't find DT node\n");
return -ENODEV;
}
-- vgic_maint_irq = irq_of_parse_and_map(vgic_node, 0);
-- if (!vgic_maint_irq) {
-- kvm_err("error getting vgic maintenance irq from DT\n");
-- ret = -ENXIO;
+- ppi = irq_of_parse_and_map(np, 2);
+- if (!ppi) {
+- kvm_err("kvm_arch_timer: no virtual timer interrupt\n");
+- err = -EINVAL;
- goto out;
-- }
-+ vgic_probe = matched_id->data;
-+ ret = vgic_probe(vgic_node, &vgic_ops, &vgic);
-+ if (ret)
-+ return ret;
++ *ppi = irq_of_parse_and_map(np, 2);
++ if (*ppi == 0) {
++ of_node_put(np);
++ return -EINVAL;
+ }
-- ret = request_percpu_irq(vgic_maint_irq, vgic_maintenance_handler,
-+ ret = request_percpu_irq(vgic->maint_irq, vgic_maintenance_handler,
- "vgic", kvm_get_running_vcpus());
- if (ret) {
-- kvm_err("Cannot register interrupt %d\n", vgic_maint_irq);
+- err = request_percpu_irq(ppi, kvm_arch_timer_handler,
+- "kvm guest timer", kvm_get_running_vcpus());
+- if (err) {
+- kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
+- ppi, err);
- goto out;
-+ kvm_err("Cannot register interrupt %d\n", vgic->maint_irq);
-+ return ret;
- }
+- }
++ return 0;
++}
- ret = __register_cpu_notifier(&vgic_cpu_nb);
-@@ -1502,65 +1567,15 @@ int kvm_vgic_hyp_init(void)
- goto out_free_irq;
- }
+- host_vtimer_irq = ppi;
++extern int arch_timer_ppi[];
-- ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
-- if (ret) {
-- kvm_err("Cannot obtain VCTRL resource\n");
-- goto out_free_irq;
-- }
--
-- vgic_vctrl_base = of_iomap(vgic_node, 2);
-- if (!vgic_vctrl_base) {
-- kvm_err("Cannot ioremap VCTRL\n");
-- ret = -ENOMEM;
-- goto out_free_irq;
-- }
--
-- vgic_nr_lr = readl_relaxed(vgic_vctrl_base + GICH_VTR);
-- vgic_nr_lr = (vgic_nr_lr & 0x3f) + 1;
--
-- ret = create_hyp_io_mappings(vgic_vctrl_base,
-- vgic_vctrl_base + resource_size(&vctrl_res),
-- vctrl_res.start);
-- if (ret) {
-- kvm_err("Cannot map VCTRL into hyp\n");
-- goto out_unmap;
-- }
--
-- if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
-- kvm_err("Cannot obtain VCPU resource\n");
-- ret = -ENXIO;
-- goto out_unmap;
-- }
--
-- if (!PAGE_ALIGNED(vcpu_res.start)) {
-- kvm_err("GICV physical address 0x%llx not page aligned\n",
-- (unsigned long long)vcpu_res.start);
-- ret = -ENXIO;
-- goto out_unmap;
+- err = __register_cpu_notifier(&kvm_timer_cpu_nb);
+- if (err) {
+- kvm_err("Cannot register timer CPU notifier\n");
+- goto out_free;
- }
--
-- if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
-- kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
-- (unsigned long long)resource_size(&vcpu_res),
-- PAGE_SIZE);
-- ret = -ENXIO;
-- goto out_unmap;
++static int kvm_timer_ppi_parse_acpi(unsigned int *ppi)
+
+- wqueue = create_singlethread_workqueue("kvm_arch_timer");
+- if (!wqueue) {
+- err = -ENOMEM;
+- goto out_free;
- }
--
-- vgic_vcpu_base = vcpu_res.start;
--
-- kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
-- vctrl_res.start, vgic_maint_irq);
- on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
++{
++ /* retrieve VIRT_PPI info */
++ *ppi = arch_timer_ppi[2];
-- goto out;
-+ /* Callback into for arch code for setup */
-+ vgic_arch_setup(vgic);
+- kvm_info("%s IRQ%d\n", np->name, ppi);
+- on_each_cpu(kvm_timer_init_interrupt, NULL, 1);
++ if (*ppi == 0)
++ return -EINVAL;
++ else
++ return 0;
++}
+
-+ return 0;
++int kvm_timer_hyp_init(void)
++{
++ unsigned int ppi;
++ int err;
++
++ timecounter = arch_timer_get_timecounter();
++ if (!timecounter)
++ return -ENODEV;
++
++ /* PPI DT parsing */
++ err = kvm_timer_ppi_parse_dt(&ppi);
--out_unmap:
-- iounmap(vgic_vctrl_base);
- out_free_irq:
-- free_percpu_irq(vgic_maint_irq, kvm_get_running_vcpus());
--out:
-- of_node_put(vgic_node);
-+ free_percpu_irq(vgic->maint_irq, kvm_get_running_vcpus());
- return ret;
+- goto out;
++ /* if DT parsing fails, try ACPI next */
++ if (err && !acpi_disabled)
++ err = kvm_timer_ppi_parse_acpi(&ppi);
++
++ if (err) {
++ kvm_err("kvm_timer_hyp_init: can't find virtual timer info or "
++ "config virtual timer interrupt\n");
++ return err;
++ }
++
++ /* configure IRQ handler */
++ err = request_percpu_irq(ppi, kvm_arch_timer_handler,
++ "kvm guest timer", kvm_get_running_vcpus());
++ if (err) {
++ kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
++ ppi, err);
++ goto out;
++ }
++
++ host_vtimer_irq = ppi;
++
++ err = __register_cpu_notifier(&kvm_timer_cpu_nb);
++ if (err) {
++ kvm_err("Cannot register timer CPU notifier\n");
++ goto out_free;
++ }
++
++ wqueue = create_singlethread_workqueue("kvm_arch_timer");
++ if (!wqueue) {
++ err = -ENOMEM;
++ goto out_free;
++ }
++
++ kvm_info("timer IRQ%d\n", ppi);
++ on_each_cpu(kvm_timer_init_interrupt, NULL, 1);
++
++ goto out;
+ out_free:
+- free_percpu_irq(ppi, kvm_get_running_vcpus());
++ free_percpu_irq(ppi, kvm_get_running_vcpus());
+ out:
+- of_node_put(np);
+- return err;
++ return err;
}
-@@ -1593,7 +1608,7 @@ int kvm_vgic_init(struct kvm *kvm)
- }
+ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
+diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
+index 2935405..510049c 100644
+--- a/virt/kvm/arm/vgic-v2.c
++++ b/virt/kvm/arm/vgic-v2.c
+@@ -19,6 +19,7 @@
+ #include <linux/kvm.h>
+ #include <linux/kvm_host.h>
+ #include <linux/interrupt.h>
++#include <linux/acpi.h>
+ #include <linux/io.h>
+ #include <linux/of.h>
+ #include <linux/of_address.h>
+@@ -26,6 +27,7 @@
- ret = kvm_phys_addr_ioremap(kvm, kvm->arch.vgic.vgic_cpu_base,
-- vgic_vcpu_base, KVM_VGIC_V2_CPU_SIZE);
-+ vgic->vcpu_base, KVM_VGIC_V2_CPU_SIZE);
- if (ret) {
- kvm_err("Unable to remap VGIC CPU to VCPU\n");
- goto out;
-@@ -1639,7 +1654,8 @@ int kvm_vgic_create(struct kvm *kvm)
- }
+ #include <linux/irqchip/arm-gic.h>
- spin_lock_init(&kvm->arch.vgic.lock);
-- kvm->arch.vgic.vctrl_base = vgic_vctrl_base;
-+ kvm->arch.vgic.in_kernel = true;
-+ kvm->arch.vgic.vctrl_base = vgic->vctrl_base;
- kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
- kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
++#include <asm/acpi.h>
+ #include <asm/kvm_emulate.h>
+ #include <asm/kvm_arm.h>
+ #include <asm/kvm_mmu.h>
+@@ -159,7 +161,7 @@ static const struct vgic_ops vgic_v2_ops = {
+ static struct vgic_params vgic_v2_params;
-@@ -1738,39 +1754,40 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
- static bool handle_cpu_mmio_misc(struct kvm_vcpu *vcpu,
- struct kvm_exit_mmio *mmio, phys_addr_t offset)
+ /**
+- * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
++ * vgic_v2_dt_probe - probe for a GICv2 compatible interrupt controller in DT
+ * @node: pointer to the DT node
+ * @ops: address of a pointer to the GICv2 operations
+ * @params: address of a pointer to HW-specific parameters
+@@ -168,7 +170,7 @@ static struct vgic_params vgic_v2_params;
+ * in *ops and the HW parameters in *params. Returns an error code
+ * otherwise.
+ */
+-int vgic_v2_probe(struct device_node *vgic_node,
++int vgic_v2_dt_probe(struct device_node *vgic_node,
+ const struct vgic_ops **ops,
+ const struct vgic_params **params)
{
-- struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-- u32 reg, mask = 0, shift = 0;
- bool updated = false;
-+ struct vgic_vmcr vmcr;
-+ u32 *vmcr_field;
-+ u32 reg;
-+
-+ vgic_get_vmcr(vcpu, &vmcr);
-
- switch (offset & ~0x3) {
- case GIC_CPU_CTRL:
-- mask = GICH_VMCR_CTRL_MASK;
-- shift = GICH_VMCR_CTRL_SHIFT;
-+ vmcr_field = &vmcr.ctlr;
- break;
- case GIC_CPU_PRIMASK:
-- mask = GICH_VMCR_PRIMASK_MASK;
-- shift = GICH_VMCR_PRIMASK_SHIFT;
-+ vmcr_field = &vmcr.pmr;
- break;
- case GIC_CPU_BINPOINT:
-- mask = GICH_VMCR_BINPOINT_MASK;
-- shift = GICH_VMCR_BINPOINT_SHIFT;
-+ vmcr_field = &vmcr.bpr;
- break;
- case GIC_CPU_ALIAS_BINPOINT:
-- mask = GICH_VMCR_ALIAS_BINPOINT_MASK;
-- shift = GICH_VMCR_ALIAS_BINPOINT_SHIFT;
-+ vmcr_field = &vmcr.abpr;
- break;
-+ default:
-+ BUG();
+@@ -222,11 +224,22 @@ int vgic_v2_probe(struct device_node *vgic_node,
}
- if (!mmio->is_write) {
-- reg = (vgic_cpu->vgic_vmcr & mask) >> shift;
-+ reg = *vmcr_field;
- mmio_data_write(mmio, ~0, reg);
- } else {
- reg = mmio_data_read(mmio, ~0);
-- reg = (reg << shift) & mask;
-- if (reg != (vgic_cpu->vgic_vmcr & mask))
-+ if (reg != *vmcr_field) {
-+ *vmcr_field = reg;
-+ vgic_set_vmcr(vcpu, &vmcr);
- updated = true;
-- vgic_cpu->vgic_vmcr &= ~mask;
-- vgic_cpu->vgic_vmcr |= reg;
-+ }
+ if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
++#if 0
+ kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+ (unsigned long long)resource_size(&vcpu_res),
+ PAGE_SIZE);
+ ret = -ENXIO;
+ goto out_unmap;
++#else
++ /*
++ * The check fails for arm64 with 64K pagesize and certain firmware.
++ * Ignore for now until firmware takes care of the problem.
++ */
++ kvm_info("GICV size 0x%llx not a multiple of page size 0x%lx\n",
++ (unsigned long long)resource_size(&vcpu_res),
++ PAGE_SIZE);
++ kvm_info("Update DT to assign GICV a multiple of kernel page size \n");
++#endif
}
- return updated;
+
+ vgic->vcpu_base = vcpu_res.start;
+@@ -245,3 +258,72 @@ out:
+ of_node_put(vgic_node);
+ return ret;
}
++
++struct acpi_madt_generic_interrupt *vgic_acpi;
++static void gic_get_acpi_header(struct acpi_subtable_header *header)
++{
++ vgic_acpi = (struct acpi_madt_generic_interrupt *)header;
++}
++
++int vgic_v2_acpi_probe(const struct vgic_ops **ops,
++ const struct vgic_params **params)
++{
++ struct vgic_params *vgic = &vgic_v2_params;
++ int irq_mode, ret;
++
++ /* MADT table */
++ ret = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
++ (acpi_tbl_entry_handler)gic_get_acpi_header, 0);
++ if (!ret) {
++ pr_err("Failed to get MADT VGIC CPU entry\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ /* IRQ trigger mode */
++ irq_mode = (vgic_acpi->flags & ACPI_MADT_VGIC_IRQ_MODE) ?
++ ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
++ /* According to GIC-400 manual, all PPIs are active-LOW, level
++ * sensative. We register IRQ as active-low.
++ */
++ vgic->maint_irq = acpi_register_gsi(NULL, vgic_acpi->vgic_interrupt,
++ irq_mode, ACPI_ACTIVE_LOW);
++ if (!vgic->maint_irq) {
++ pr_err("Cannot register VGIC ACPI maintenance irq\n");
++ ret = -ENXIO;
++ goto out;
++ }
++
++ /* GICH resource */
++ vgic->vctrl_base = ioremap(vgic_acpi->gich_base_address, SZ_8K);
++ if (!vgic->vctrl_base) {
++ pr_err("cannot ioremap GICH memory\n");
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ vgic->nr_lr = readl_relaxed(vgic->vctrl_base + GICH_VTR);
++ vgic->nr_lr = (vgic->nr_lr & 0x3f) + 1;
++
++ ret = create_hyp_io_mappings(vgic->vctrl_base,
++ vgic->vctrl_base + SZ_8K,
++ vgic_acpi->gich_base_address);
++ if (ret) {
++ kvm_err("Cannot map GICH into hyp\n");
++ goto out;
++ }
++
++ vgic->vcpu_base = vgic_acpi->gicv_base_address;
++
++ kvm_info("GICH base=0x%llx, GICV base=0x%llx, IRQ=%d\n",
++ (unsigned long long)vgic_acpi->gich_base_address,
++ (unsigned long long)vgic_acpi->gicv_base_address,
++ vgic->maint_irq);
++
++ vgic->type = VGIC_V2;
++ *ops = &vgic_v2_ops;
++ *params = vgic;
++
++out:
++ return ret;
++}
+diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
+index 1c2c8ee..8b56920 100644
+--- a/virt/kvm/arm/vgic-v3.c
++++ b/virt/kvm/arm/vgic-v3.c
+@@ -173,7 +173,7 @@ static const struct vgic_ops vgic_v3_ops = {
+ static struct vgic_params vgic_v3_params;
+
+ /**
+- * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
++ * vgic_v3_dt_probe - probe for a GICv3 compatible interrupt controller in DT
+ * @node: pointer to the DT node
+ * @ops: address of a pointer to the GICv3 operations
+ * @params: address of a pointer to HW-specific parameters
+@@ -182,9 +182,9 @@ static struct vgic_params vgic_v3_params;
+ * in *ops and the HW parameters in *params. Returns an error code
+ * otherwise.
+ */
+-int vgic_v3_probe(struct device_node *vgic_node,
+- const struct vgic_ops **ops,
+- const struct vgic_params **params)
++int vgic_v3_dt_probe(struct device_node *vgic_node,
++ const struct vgic_ops **ops,
++ const struct vgic_params **params)
+ {
+ int ret = 0;
+ u32 gicv_idx;
+diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
+index aacdb59..d972d63 100644
+--- a/virt/kvm/arm/vgic.c
++++ b/virt/kvm/arm/vgic.c
+@@ -25,9 +25,11 @@
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+ #include <linux/uaccess.h>
++#include <linux/acpi.h>
+
+ #include <linux/irqchip/arm-gic.h>
+
++#include <asm/acpi.h>
+ #include <asm/kvm_emulate.h>
+ #include <asm/kvm_arm.h>
+ #include <asm/kvm_mmu.h>
+@@ -2427,8 +2429,8 @@ static struct notifier_block vgic_cpu_nb = {
+ };
+
+ static const struct of_device_id vgic_ids[] = {
+- { .compatible = "arm,cortex-a15-gic", .data = vgic_v2_probe, },
+- { .compatible = "arm,gic-v3", .data = vgic_v3_probe, },
++ { .compatible = "arm,cortex-a15-gic", .data = vgic_v2_dt_probe, },
++ { .compatible = "arm,gic-v3", .data = vgic_v3_dt_probe, },
+ {},
+ };
+
+@@ -2438,20 +2440,26 @@ int kvm_vgic_hyp_init(void)
+ const int (*vgic_probe)(struct device_node *,const struct vgic_ops **,
+ const struct vgic_params **);
+ struct device_node *vgic_node;
+- int ret;
++ int ret = -ENODEV;
+
+- vgic_node = of_find_matching_node_and_match(NULL,
+- vgic_ids, &matched_id);
+- if (!vgic_node) {
+- kvm_err("error: no compatible GIC node found\n");
+- return -ENODEV;
++ /* probe VGIC */
++ if ((vgic_node = of_find_matching_node_and_match(NULL,
++ vgic_ids, &matched_id))) {
++ /* probe VGIC in DT */
++ vgic_probe = matched_id->data;
++ ret = vgic_probe(vgic_node, &vgic_ops, &vgic);
++ }
++ else if (!acpi_disabled) {
++ /* probe VGIC in ACPI */
++ ret = vgic_v2_acpi_probe(&vgic_ops, &vgic);
+ }
+
+- vgic_probe = matched_id->data;
+- ret = vgic_probe(vgic_node, &vgic_ops, &vgic);
+- if (ret)
++ if (ret) {
++ kvm_err("error: no compatible GIC info found\n");
+ return ret;
++ }
+
++ /* configuration */
+ ret = request_percpu_irq(vgic->maint_irq, vgic_maintenance_handler,
+ "vgic", kvm_get_running_vcpus());
+ if (ret) {
diff --git a/freed-ora/current/f20/kernel.spec b/freed-ora/current/f20/kernel.spec
index cf385ba0e..ee6ef6ecc 100644
--- a/freed-ora/current/f20/kernel.spec
+++ b/freed-ora/current/f20/kernel.spec
@@ -112,7 +112,7 @@ Summary: The Linux kernel
%if 0%{?released_kernel}
# Do we have a -stable update to apply?
-%define stable_update 6
+%define stable_update 7
# Is it a -stable RC?
%define stable_rc 0
# Set rpm version accordingly
@@ -819,6 +819,9 @@ Patch30002: ipv4-try-to-cache-dst_entries-which-would-cause-a-re.patch
#rhbz 1188074
Patch30003: 0001-ntp-Fixup-adjtimex-freq-validation-on-32bit-systems.patch
+#rhbz 1186097
+Patch30004: acpi-video-add-disable_native_backlight_quirk_for_samsung_510r.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -1601,6 +1604,9 @@ ApplyPatch ipv4-try-to-cache-dst_entries-which-would-cause-a-re.patch
#rhbz 1188074
ApplyPatch 0001-ntp-Fixup-adjtimex-freq-validation-on-32bit-systems.patch
+#rhbz 1186097
+ApplyPatch acpi-video-add-disable_native_backlight_quirk_for_samsung_510r.patch
+
%if 0%{?aarch64patches}
ApplyPatch kernel-arm64.patch
%ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does.
@@ -2430,6 +2436,13 @@ fi
# ||----w |
# || ||
%changelog
+* Thu Feb 12 2015 Alexandre Oliva <lxoliva@fsfla.org> -libre
+- GNU Linux-libre 3.18.7-gnu.
+
+* Wed Feb 11 2015 Justin M. Forbes <jforbes@fedoraproject.org> - 3.18.7-100
+- Linux v3.18.7
+- Add disable_native_backlight quirk for Samsung 510R (rhbz 1186097)
+
* Sat Feb 7 2015 Alexandre Oliva <lxoliva@fsfla.org> -libre
- GNU Linux-libre 3.18.6-gnu.
diff --git a/freed-ora/current/f20/sources b/freed-ora/current/f20/sources
index 4b138c33c..a10805b44 100644
--- a/freed-ora/current/f20/sources
+++ b/freed-ora/current/f20/sources
@@ -1,3 +1,3 @@
b3c2a6827813398dde7e8a2d4e02a2c3 linux-libre-3.18-gnu.tar.xz
813ccb96f0b379d656e57442c2587ca3 perf-man-3.18.tar.gz
-30aa769974e64fd17a01724d1577a913 patch-3.18.6.xz
+9db3178b87ddf7c05e6191bf57645610 patch-3.18.7.xz
OpenPOWER on IntegriCloud