diff options
Diffstat (limited to 'freed-ora/current')
-rw-r--r-- | freed-ora/current/f20/acpi-video-add-disable_native_backlight_quirk_for_samsung_510r.patch | 39 | ||||
-rw-r--r-- | freed-ora/current/f20/kernel-arm64.patch | 20298 | ||||
-rw-r--r-- | freed-ora/current/f20/kernel.spec | 15 | ||||
-rw-r--r-- | freed-ora/current/f20/sources | 2 |
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 = <ðclk 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 |