* [PATCH v2 0/4] ARM: Add support for CONFIG_DEBUG_VIRTUAL
From: Florian Fainelli @ 2016-12-08 18:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481068257-6367-1-git-send-email-labbott@redhat.com>
This patch series builds on top of Laura's [PATCHv5 00/10] CONFIG_DEBUG_VIRTUAL
for arm64 to add support for CONFIG_DEBUG_VIRTUAL for ARM.
This was tested on a Brahma B15 platform (ARMv7 + HIGHMEM + LPAE).
Note that the treewide changes would involve a huge CC list, which
is why it has been purposely trimmed to just focusing on the DEBUG_VIRTUAL
aspect.
Changes in v2:
- Modified MTD LART driver not to create symbol conflicts with
KERNEL_START
- Fixed patch that defines and uses KERNEL_START/END
- Fixed __pa_symbol()'s definition
- Inline __pa_symbol() check wihtin the VIRTUAL_BUG_ON statement
- Simplified check for virtual addresses
- Added a tree-wide patch changing SMP/PM implementations to use
__pa_symbol(), build tested against multi_v{5,7}_defconfig
Thanks!
Florian Fainelli (4):
mtd: lart: Rename partition defines to be prefixed with PART_
ARM: Define KERNEL_START and KERNEL_END
ARM: Add support for CONFIG_DEBUG_VIRTUAL
ARM: treewide: Replace uses of virt_to_phys with __pa_symbol
arch/arm/Kconfig | 1 +
arch/arm/boot/compressed/piggy.xzkern | Bin 0 -> 2998584 bytes
arch/arm/common/mcpm_entry.c | 12 +++----
arch/arm/include/asm/memory.h | 23 ++++++++++++--
arch/arm/mach-alpine/platsmp.c | 2 +-
arch/arm/mach-axxia/platsmp.c | 2 +-
arch/arm/mach-bcm/bcm63xx_smp.c | 2 +-
arch/arm/mach-bcm/platsmp-brcmstb.c | 2 +-
arch/arm/mach-bcm/platsmp.c | 4 +--
arch/arm/mach-berlin/platsmp.c | 2 +-
arch/arm/mach-exynos/firmware.c | 4 +--
arch/arm/mach-exynos/mcpm-exynos.c | 2 +-
arch/arm/mach-exynos/platsmp.c | 4 +--
arch/arm/mach-exynos/pm.c | 6 ++--
arch/arm/mach-exynos/suspend.c | 6 ++--
arch/arm/mach-hisi/platmcpm.c | 2 +-
arch/arm/mach-hisi/platsmp.c | 6 ++--
arch/arm/mach-imx/platsmp.c | 2 +-
arch/arm/mach-imx/pm-imx6.c | 2 +-
arch/arm/mach-imx/src.c | 2 +-
arch/arm/mach-mediatek/platsmp.c | 2 +-
arch/arm/mach-mvebu/pm.c | 2 +-
arch/arm/mach-mvebu/pmsu.c | 2 +-
arch/arm/mach-mvebu/system-controller.c | 2 +-
arch/arm/mach-omap2/control.c | 8 ++---
arch/arm/mach-omap2/omap-mpuss-lowpower.c | 8 ++---
arch/arm/mach-omap2/omap-smp.c | 4 +--
arch/arm/mach-prima2/platsmp.c | 2 +-
arch/arm/mach-prima2/pm.c | 2 +-
arch/arm/mach-pxa/palmz72.c | 2 +-
arch/arm/mach-pxa/pxa25x.c | 2 +-
arch/arm/mach-pxa/pxa27x.c | 2 +-
arch/arm/mach-pxa/pxa3xx.c | 2 +-
arch/arm/mach-realview/platsmp-dt.c | 2 +-
arch/arm/mach-rockchip/platsmp.c | 4 +--
arch/arm/mach-rockchip/pm.c | 2 +-
arch/arm/mach-s3c24xx/mach-jive.c | 2 +-
arch/arm/mach-s3c24xx/pm-s3c2410.c | 2 +-
arch/arm/mach-s3c24xx/pm-s3c2416.c | 2 +-
arch/arm/mach-s3c64xx/pm.c | 2 +-
arch/arm/mach-s5pv210/pm.c | 2 +-
arch/arm/mach-sa1100/pm.c | 2 +-
arch/arm/mach-shmobile/platsmp-apmu.c | 6 ++--
arch/arm/mach-shmobile/platsmp-scu.c | 4 +--
arch/arm/mach-socfpga/platsmp.c | 4 +--
arch/arm/mach-spear/platsmp.c | 2 +-
arch/arm/mach-sti/platsmp.c | 2 +-
arch/arm/mach-sunxi/platsmp.c | 4 +--
arch/arm/mach-tango/platsmp.c | 2 +-
arch/arm/mach-tango/pm.c | 2 +-
arch/arm/mach-tegra/reset.c | 4 +--
arch/arm/mach-ux500/platsmp.c | 2 +-
arch/arm/mach-vexpress/dcscb.c | 2 +-
arch/arm/mach-vexpress/platsmp.c | 2 +-
arch/arm/mach-vexpress/tc2_pm.c | 4 +--
arch/arm/mach-zx/platsmp.c | 4 +--
arch/arm/mach-zynq/platsmp.c | 2 +-
arch/arm/mm/Makefile | 1 +
arch/arm/mm/init.c | 7 ++--
arch/arm/mm/mmu.c | 6 +---
arch/arm/mm/physaddr.c | 51 ++++++++++++++++++++++++++++++
drivers/mtd/devices/lart.c | 24 +++++++-------
62 files changed, 173 insertions(+), 108 deletions(-)
create mode 100644 arch/arm/boot/compressed/piggy.xzkern
create mode 100644 arch/arm/mm/physaddr.c
--
2.9.3
^ permalink raw reply
* [PATCH 1/1] arm64: mm: add config options for page table configuration
From: Catalin Marinas @ 2016-12-08 18:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <762b8bec-60da-0bb8-28f4-b407ad70687b@broadcom.com>
On Thu, Dec 08, 2016 at 08:30:36AM -0800, Scott Branden wrote:
> On 16-12-08 02:00 AM, Catalin Marinas wrote:
> >On Wed, Dec 07, 2016 at 11:40:00AM -0800, Scott Branden wrote:
> >>Make MAX_PHYSMEM_BITS and SECTIONS_SIZE_BITS configurable by adding
> >>config options.
> >>Default to current settings currently defined in sparesmem.h.
> >>For systems wishing to save memory the config options can be overridden.
> >>Example, changing MAX_PHYSMEM_BITS from 48 to 36 at the same time as
> >>changing SECTION_SIZE_BITS from 30 to 26 frees 13MB of memory.
[...]
> > I would rather reduce SECTION_SIZE_BITS permanently where
> >feasible, like in this patch:
> >
> >http://lkml.kernel.org/r/1465821119-3384-1-git-send-email-jszhang at marvell.com
>
> This patch does not meet my requirements as I need SECTION_SIZE_BITS to be
> set to 28 to reduce memory
So with this patch, we reduce it to 27, it should be fine-grained enough
for 128MB sections. Alternatively, there were other suggestions here:
http://lkml.iu.edu/hypermail/linux/kernel/1604.1/03036.html
> and to allow memory hotplug to allocate a 256 MB section.
Can memory hotplug not work with 2*128MB sections in this case?
> My patch future proofs the tuning of the parameters by allowing
> any section size to be made.
While MAX_PHYSMEM_BITS makes sense to users in general,
SECTION_SIZE_BITS is not always clear to the average user what it means
and its min/max boundaries. That's another reason (apart from single/few
Image case) why I prefer to not expose it as configuration option.
> I could combine the patch you list such that
> SECTION_SIZE_BITS defaults to 30 when CONFIG_ARM64_64_PAGES is selected and
> 27 otherwise. Should it default to something else for 16K and 4K pages?
I haven't done any calculations for 16K yet but we could probably come
up with some formula based on PAGE_SHIFT to cover all cases.
> In terms of MAX_PHYSMEM_BITS, if our SoCs only use 40 (or less) bits I would
> also like the configuration functionality. This allows us to make the
> SECTION_SIZE_BITS smaller.
So how small do you want SECTION_SIZE_BITS to be? As I said above, 128MB
sections should be sufficient in most cases and without the need to
reduce MAX_PHYSMEM_BITS.
--
Catalin
^ permalink raw reply
* [PATCH] ARM: Ignore compressed kernel build products
From: Florian Fainelli @ 2016-12-08 18:54 UTC (permalink / raw)
To: linux-arm-kernel
When we select a kernel compression scheme, we will end-up with e.g:
piggy.xzkern under arch/arm/boot/compressed/, let's ignore these files.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
arch/arm/boot/compressed/.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index 86b2f5d28240..06686768610f 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -4,6 +4,7 @@ font.c
lib1funcs.S
hyp-stub.S
piggy_data
+piggy.*
vmlinux
vmlinux.lds
--
2.9.3
^ permalink raw reply related
* [PATCH] ARM: Ignore compressed kernel build products
From: Florian Fainelli @ 2016-12-08 18:54 UTC (permalink / raw)
To: linux-arm-kernel
When we select a kernel compression scheme, we will end-up with e.g:
piggy.xzkern under arch/arm/boot/compressed/, let's ignore these files.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
arch/arm/boot/compressed/.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index 86b2f5d28240..06686768610f 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -4,6 +4,7 @@ font.c
lib1funcs.S
hyp-stub.S
piggy_data
+piggy.*
vmlinux
vmlinux.lds
--
2.9.3
^ permalink raw reply related
* [GIT PULL 1/3] ARM: exynos: Soc/mach for v4.10
From: Krzysztof Kozlowski @ 2016-12-08 18:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOesGMicc8xEvxn1k6Te20rTEv36it0PZmnXyhhn+U+oh7jdeQ@mail.gmail.com>
On Thu, Dec 08, 2016 at 10:25:35AM -0800, Olof Johansson wrote:
> On Thu, Dec 8, 2016 at 7:28 AM, Pankaj Dubey <dubepankaj1980@gmail.com> wrote:
> > On 3 December 2016 at 22:33, Krzysztof Kozlowski <krzk@kernel.org> wrote:
> >> On Fri, Dec 02, 2016 at 10:52:57PM +0100, Arnd Bergmann wrote:
> >>>
> >>> Sorry, I initially deferred it and then didn't get back to it.
> >>>
> >>> The dependency on the .dts changes made me a bit nervous about
> >>> taking it, mostly because the changelog fails to explain the
> >>> exact dependencies.
> >>>
> >>> This breaks compatibility with existing .dtb files, right?
> >>
> >> No, strictly speaking not. There was no dt-bindings change here, no DT
> >> properties for SCU before. We are converting our drivers to DTB so this
> >> is the same as before when switching for pinctrl, clocks or all other
> >> drivers to DT.
> >>
> >> We are not braking DTB ABI because there was no ABI around it before.
> >> Otherwise, one would say that lack of SCU DT node was an ABI. That is
> >> wrong, because DT should describe the hardware and SCU is in hardware.
> >>
> >>> What I'd like to see here is an explanation about:
> >>>
> >>> - what the upside of breaking compatibility is
> >>
> >> DTBs which do not have SCU are not proper because they skip that part of
> >> hardware. However we are breaking them in the way the SMP won't work
> >> there. It is not an ABI break, as I mentioned above.
> >>
> >>> - what exactly stops working with an old dtb
> >>> - why we don't keep a fallback for handling old dtb files
> >>
> >> What is the point for it? This is not an ABI break. Even if it was,
> >> Samsung guys don't care for ABI breaks at all (and in fact we wanted to
> >> mark the platform experimental...).
> >>
> >>> It would also be helpful to have a separate pull request for
> >>> the commits require the new dtb, and the stuff that is unrelated.
> >>
> >> I can do that but the pull will be small.
> >>
> >
> > Arnd,
> >
> > Any update on this? Intention of this change is to improve
> > Exynos SoC's DT support in mainline kernel. This will help in removing static
> > mapping from exynos machine files and simplify mach-exynos code-base.
>
> Adding the SCU nodes now makes sense. So does using them if they're available.
>
> Given the prevalence of exynos systems with DTS already out there, it
> would make sense to give an overlap of making the kernel work without
> the SCU in DT for a period of time.
>
> This isn't like the old days of when we were mass-converting things
> and breakage was expected. We're well into a steady state here, so
> being nicer to downstream users is likely the right thing to do here.
I think that either we treat this as an ABI break, or just "being
nice to downstream".
In the first case, not breaking things would be a valid reason. But I
believe this is not an ABI break. ABI is about an interface, not about
being nice. The SCU should be defined by downstream users because this
is the description of the hardware. In the same time, kernel did not
document as an interface something like "there should be no SCU node
defined" so creating a requirement of SCU is not an breakage of existing
interface.
The second case then, being nice to downstream. Do we want to be nice or
do we want to push them to mainline? Okay, it is never black or white...
yet we should rather encourage downstream to mainline and creating
compatibility periods is rather opposite of that.
Best regards,
Krzysztof
^ permalink raw reply
* [RFC v3 00/10] KVM PCIe/MSI passthrough on ARM/ARM64 and IOVA reserved regions
From: Robin Murphy @ 2016-12-08 18:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208100132.4e9cc3c5@t450s.home>
On 08/12/16 17:01, Alex Williamson wrote:
> On Thu, 8 Dec 2016 13:14:04 +0000
> Robin Murphy <robin.murphy@arm.com> wrote:
>> On 08/12/16 09:36, Auger Eric wrote:
>>> 3) RMRR reporting in the iommu group sysfs? Joerg: yes; Don: no
>>> My current series does not expose them in iommu group sysfs.
>>> I understand we can expose the RMRR regions in the iomm group sysfs
>>> without necessarily supporting RMRR requiring device assignment.
>>> We can also add this support later.
>>
>> As you say, reporting them doesn't necessitate allowing device
>> assignment, and it's information which can already be easily grovelled
>> out of dmesg (for intel-iommu at least) - there doesn't seem to be any
>> need to hide them, but the x86 folks can have the final word on that.
>
> Eric and I talked about this and I don't see the value in identifying
> an RMRR as anything other than a reserved range for a device. It's not
> userspace's job to maintain an identify mapped range for the device,
> and it can't be trusted to do so anyway. It does throw a kink in the
> machinery though as an RMRR is a reserved memory range unique to a
> device. It doesn't really fit into a monolithic /sys/class/iommu view
> of global reserved regions as an RMRR is only relevant to the device
> paths affected.
I think we're in violent agreement then - to clarify, I was thinking in
terms of patch 7 of this series, where everything relevant to a
particular group would be exposed as just an opaque "don't use this
address range" regardless of the internal type.
I'm less convinced the kernel has any need to provide its own 'global'
view of reservations which strictly are always at least per-IOMMU, if
not per-root-complex, even when all the instances do share the same
address by design. The group-based interface fits the reality neatly,
and userspace can easily iterate all the groups if it wants to consider
everything. Plus if it doesn't want to, then it needn't bother reserving
anything which doesn't apply to the group(s) it's going to bind to VFIO.
Robin.
> Another kink is that sometimes we know what the RMRR is for, know that
> it's irrelevant for our use case, and ignore it. This is true for USB
> and Intel graphics use cases of RMRRs.
>
> Also, aside from the above mentioned cases, devices with RMRRs are
> currently excluded from participating in the IOMMU API by the
> intel-iommu driver and I expect this to continue in the general case
> regardless of whether the ranges are more easily exposed to userspace.
> ARM may have to deal with mangling a guest memory map due to lack of
> any standard layout, de facto or otherwise, but for x86 I don't think
> it's worth the migration and hotplug implications. Thanks,
>
> Alex
>
^ permalink raw reply
* [PATCH pci/host-iproc] pci-iproc: skip check for legacy IRQ on PAXC buses
From: Bjorn Helgaas @ 2016-12-08 18:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480624492-32420-1-git-send-email-gospo@broadcom.com>
On Thu, Dec 01, 2016 at 03:34:52PM -0500, Andy Gospodarek wrote:
> PAXC and PAXCv2 buses do not support legacy IRQs so there is no reason
> to even try and map them. Without a change like this, one cannot create
> VFs on Nitro ports since legacy interrupts are checked as part of the
> PCI device creation process. Testing on PAXC hardware showed that VFs
> are properly created with only the change to not set pcie->map_irq, but
> just to be safe the change in iproc_pcie_setup will ensure that
> pdev_fixup_irq will not panic.
>
> Signed-off-by: Andy Gospodarek <gospo@broadcom.com>
> Signed-off-by: Ray Jui <rjui@broadcom.com>
Applied to pci/host-iproc for v4.10 with Ray's acked-by, thanks!
> ---
> drivers/pci/host/pcie-iproc-platform.c | 9 ++++++++-
> drivers/pci/host/pcie-iproc.c | 5 ++++-
> 2 files changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c
> index fd3ed9b..22d814a 100644
> --- a/drivers/pci/host/pcie-iproc-platform.c
> +++ b/drivers/pci/host/pcie-iproc-platform.c
> @@ -108,7 +108,14 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
> return ret;
> }
>
> - pcie->map_irq = of_irq_parse_and_map_pci;
> + /* PAXC doesn't support legacy IRQs, skip mapping */
> + switch (pcie->type) {
> + case IPROC_PCIE_PAXC:
> + case IPROC_PCIE_PAXC_V2:
> + break;
> + default:
> + pcie->map_irq = of_irq_parse_and_map_pci;
> + }
>
> ret = iproc_pcie_setup(pcie, &res);
> if (ret)
> diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c
> index cd51334..3ebc025 100644
> --- a/drivers/pci/host/pcie-iproc.c
> +++ b/drivers/pci/host/pcie-iproc.c
> @@ -1274,7 +1274,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
>
> pci_scan_child_bus(bus);
> pci_assign_unassigned_bus_resources(bus);
> - pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
> +
> + if (pcie->map_irq)
> + pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
> +
> pci_bus_add_devices(bus);
>
> return 0;
> --
> 2.1.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [GIT PULL 1/3] ARM: exynos: Soc/mach for v4.10
From: Olof Johansson @ 2016-12-08 18:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGcde9HwfPbw6NMEmcTfn+Df+-AkyyrP3u=7NUyT1XDVbCjtqg@mail.gmail.com>
On Thu, Dec 8, 2016 at 7:28 AM, Pankaj Dubey <dubepankaj1980@gmail.com> wrote:
> On 3 December 2016 at 22:33, Krzysztof Kozlowski <krzk@kernel.org> wrote:
>> On Fri, Dec 02, 2016 at 10:52:57PM +0100, Arnd Bergmann wrote:
>>> On Thursday, December 1, 2016 8:34:04 PM CET Krzysztof Kozlowski wrote:
>>> > On Thu, Nov 24, 2016 at 08:08:27AM +0200, Krzysztof Kozlowski wrote:
>>> > > Hi,
>>> > >
>>> > > This contains previous dts branch because SCU node in dts is needed
>>> > > prior to removing it from mach code.
>>> > >
>>> > > Below you will find full pull request and one stripped from dependency.
>>> > >
>>> >
>>> > Hi Arnd, Kevin and Olof,
>>> >
>>> > What about this pull from the set?
>>> >
>>>
>>> Sorry, I initially deferred it and then didn't get back to it.
>>>
>>> The dependency on the .dts changes made me a bit nervous about
>>> taking it, mostly because the changelog fails to explain the
>>> exact dependencies.
>>>
>>> This breaks compatibility with existing .dtb files, right?
>>
>> No, strictly speaking not. There was no dt-bindings change here, no DT
>> properties for SCU before. We are converting our drivers to DTB so this
>> is the same as before when switching for pinctrl, clocks or all other
>> drivers to DT.
>>
>> We are not braking DTB ABI because there was no ABI around it before.
>> Otherwise, one would say that lack of SCU DT node was an ABI. That is
>> wrong, because DT should describe the hardware and SCU is in hardware.
>>
>>> What I'd like to see here is an explanation about:
>>>
>>> - what the upside of breaking compatibility is
>>
>> DTBs which do not have SCU are not proper because they skip that part of
>> hardware. However we are breaking them in the way the SMP won't work
>> there. It is not an ABI break, as I mentioned above.
>>
>>> - what exactly stops working with an old dtb
>>> - why we don't keep a fallback for handling old dtb files
>>
>> What is the point for it? This is not an ABI break. Even if it was,
>> Samsung guys don't care for ABI breaks at all (and in fact we wanted to
>> mark the platform experimental...).
>>
>>> It would also be helpful to have a separate pull request for
>>> the commits require the new dtb, and the stuff that is unrelated.
>>
>> I can do that but the pull will be small.
>>
>
> Arnd,
>
> Any update on this? Intention of this change is to improve
> Exynos SoC's DT support in mainline kernel. This will help in removing static
> mapping from exynos machine files and simplify mach-exynos code-base.
Adding the SCU nodes now makes sense. So does using them if they're available.
Given the prevalence of exynos systems with DTS already out there, it
would make sense to give an overlap of making the kernel work without
the SCU in DT for a period of time.
This isn't like the old days of when we were mass-converting things
and breakage was expected. We're well into a steady state here, so
being nicer to downstream users is likely the right thing to do here.
-Olof
^ permalink raw reply
* [GIT PULL] ARM: mvebu: fixes for v4.9 (#2)
From: Olof Johansson @ 2016-12-08 18:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87r35ifl13.fsf@free-electrons.com>
On Thu, Dec 8, 2016 at 8:22 AM, Gregory CLEMENT
<gregory.clement@free-electrons.com> wrote:
> Hi,
>
> Here is the second pull request for fixes for mvebu for v4.9.
>
> Gregory
>
> The following changes since commit 8d897006fe9206d64cbe353310be26d7c911e69d:
>
> arm64: dts: marvell: add unique identifiers for Armada A8k SPI controllers (2016-11-09 09:44:08 +0100)
>
> are available in the git repository at:
>
> git://git.infradead.org/linux-mvebu.git tags/mvebu-fixes-4.9-2
>
> for you to fetch changes up to b150e59f1d217473b3eab354a9e5e9fe907868ff:
>
> ARM: dts: orion5x: fix number of sata port for linkstation ls-gl (2016-12-05 16:43:05 +0100)
>
> ----------------------------------------------------------------
> mvebu fixes for 4.9 (part 2)
>
> Fix number of sata port for linkstation ls-gl: without this the hard
> drive is not detected as it was before the dt conversion
Merged, thanks.
-Olof
^ permalink raw reply
* [PATCH 3/3] rtc: armada38x: Prepare for being use on 64 bits
From: Russell King - ARM Linux @ 2016-12-08 18:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208171010.29446-4-gregory.clement@free-electrons.com>
On Thu, Dec 08, 2016 at 06:10:10PM +0100, Gregory CLEMENT wrote:
> The drivers are supposed to be portable, however there are few assumption
> done here about the unsigned long size. Make sure we use the accurate
> width for the variable.
>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
> drivers/rtc/rtc-armada38x.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
> index b8a74ffaae80..c4138130febf 100644
> --- a/drivers/rtc/rtc-armada38x.c
> +++ b/drivers/rtc/rtc-armada38x.c
> @@ -84,14 +84,14 @@ static void rtc_update_mbus_timing_params(struct armada38x_rtc *rtc)
> }
>
> struct str_value_to_freq {
> - unsigned long value;
> + u32 value;
> u8 freq;
> } __packed;
>
> -static unsigned long read_rtc_register_wa(struct armada38x_rtc *rtc, u8 rtc_reg)
> +static u32 read_rtc_register_wa(struct armada38x_rtc *rtc, u8 rtc_reg)
> {
> - unsigned long value_array[SAMPLE_NR], i, j, value;
> - unsigned long max = 0, index_max = SAMPLE_NR - 1;
> + int i, j, index_max = SAMPLE_NR - 1;
> + u32 value_array[SAMPLE_NR], value, max = 0;
Ah, I see my comments on patch 1 got addressed in patch 3... :)
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* [PATCH 2/3] rtc: armada38x: Convert to time64_t
From: Russell King - ARM Linux @ 2016-12-08 18:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208171010.29446-3-gregory.clement@free-electrons.com>
On Thu, Dec 08, 2016 at 06:10:09PM +0100, Gregory CLEMENT wrote:
> It is one more step to remove the deprecated functions rtc_time_to_tm
> and rtc_tm_to_time.
I fail to see any advantage to this patch, or in fact the y2038 patch
merged into rtc.
Let's first look at the original rtc_time_to_tm():
+void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+{
+ days = time / 86400;
+ year = 1970 + days / 365;
time is an unsigned long, so is 32-bit or 64-bit. Let's assume 32-bit.
The maximum value it can have is 2^32-1 - which gives a maximum days
value of 49710 (it always fits in an int or unsigned int as a positive
value on any arch supported by Linux.)
That gives a maximum value of 'year' as 2106. So, actually
rtc_time_to_tm() doesn't have a y2038 problem, it has a y2106 problem.
So, the commentary in the original commit is actually wrong!
Okay, that aside, let's look at what your patch actually achieves.
Old code to set the time:
unsigned long time;
ret = rtc_tm_to_time(tm, &time);
if (ret)
goto out;
/* write time to a 32-bit register */
New code:
time64_t time;
time = rtc_tm_to_time64(tm);
/* write time to a 32-bit register */
I fail to see how this is any kind of improvement, or aids to solve the
y2106 problem (not y2038) here.
A better approach would have been to also provide a rtc_tm_to_time32()
following the function signature of rtc_tm_to_time(), but replacing the
unsigned long pointer with a u32 pointer, and (importantly) making it
fail if the time was unrepresentable as a u32 value.
Why u32 and not time_t? time_t is a signed value, which suffers from
the y2038 problem. u32 suffers from a y2106 problem, and is what we
have with the original rtc_tm_to_time() on 32-bit platforms. So it's
safe _not_ to needlessly chop off a bit there which wasn't done in the
original code.
This would mean that drivers (such as armada38x) which are only capable
of storing a 32-bit time fail gracefully to set times beyond y2106.
The problem as I see it right now is that the y2038 patch which
deprecates rtc_time_to_tm() etc wasn't thought out thoroughly enough,
and is making the situation much worse by pushing the problem in many
drivers in a way that results in it being less visible.
I think this needs to be reconsidered, and it needs a much better
implementation - one which at least tells the user that their hardware
has broken when trying to set the time to something the hardware can't
support.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* [PATCH v2 4/5] arm64: dts: exynos5433: Add bus dt node using VDD_INT for Exynos5433
From: Krzysztof Kozlowski @ 2016-12-08 17:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481173091-9728-5-git-send-email-cw00.choi@samsung.com>
On Thu, Dec 08, 2016 at 01:58:10PM +0900, Chanwoo Choi wrote:
> This patch adds the bus nodes using VDD_INT for Exynos5433 SoC.
> Exynos5433 has the following AMBA AXI buses to translate data
> between DRAM and sub-blocks.
>
> Following list specify the detailed correlation between sub-block and clock:
> - CLK_ACLK_G2D_{400|266} : Bus clock for G2D (2D graphic engine)
> - CLK_ACLK_MSCL_400 : Bus clock for MSCL (Memory to memory Scaler)
> - CLK_ACLK_GSCL_333 : Bus clock for GSCL (General Scaler)
> - CLK_SCLK_JPEG_MSCL : Bus clock for JPEG
> - CLK_ACLK_MFC_400 : Bus clock for MFC (Multi Format Codec)
> - CLK_ACLK_HEVC_400 : Bus clock for HEVC (High Efficient Video Codec)
> - CLK_ACLK_BUS0_400 : NoC(Network On Chip)'s bus clock for PERIC/PERIS/FSYS/MSCL
> - CLK_ACLK_BUS1_400 : NoC's bus clock for MFC/HEVC/G3D
> - CLK_ACLK_BUS2_400 : NoC's bus clock for GSCL/DISP/G2D/CAM0/CAM1/ISP
>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
> arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi | 197 +++++++++++++++++++++++++
> arch/arm64/boot/dts/exynos/exynos5433.dtsi | 1 +
> 2 files changed, 198 insertions(+)
> create mode 100644 arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi
For the reference:
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
I'll queue it for v4.11, after this merge window.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH 1/3] rtc: armada38x: improve RTC errata implementation
From: Russell King - ARM Linux @ 2016-12-08 17:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208171010.29446-2-gregory.clement@free-electrons.com>
On Thu, Dec 08, 2016 at 06:10:08PM +0100, Gregory CLEMENT wrote:
> From: Shaker Daibes <shaker@marvell.com>
>
> According to FE-3124064:
> The device supports CPU write and read access to the RTC time register.
> However, due to this errata, read from RTC TIME register may fail.
>
> Workaround:
> General configuration:
> 1. Configure the RTC Mbus Bridge Timing Control register (offset 0x184A0)
> to value 0xFD4D4FFF
> Write RTC WRCLK Period to its maximum value (0x3FF)
> Write RTC WRCLK setup to 0x53 (default value )
> Write RTC WRCLK High Time to 0x53 (default value )
> Write RTC Read Output Delay to its maximum value (0x1F)
> Mbus - Read All Byte Enable to 0x1 (default value )
> 2. Configure the RTC Test Configuration Register (offset 0xA381C) bit3
> to '1' (Reserved, Marvell internal)
>
> For any RTC register read operation:
> 1. Read the requested register 100 times.
> 2. Find the result that appears most frequently and use this result
> as the correct value.
>
> For any RTC register write operation:
> 1. Issue two dummy writes of 0x0 to the RTC Status register (offset
> 0xA3800).
> 2. Write the time to the RTC Time register (offset 0xA380C).
>
> [gregory.clement at free-electrons.com: cosmetic changes and fix issues for
> interrupt in original patch]
A particularly interesting question here is whether the above description
came first or whether the code below came first, and which was derived
from which.
Given that both readl() writel() involves a barrier operation, which is
not mentioned in the above workaround text, is it appropriate to use the
barriered operations?
>
> Reviewed-by: Lior Amsalem <alior@marvell.com>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
> drivers/rtc/rtc-armada38x.c | 109 ++++++++++++++++++++++++++++++++++----------
> 1 file changed, 85 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
> index 9a3f2a6f512e..a0859286a4c4 100644
> --- a/drivers/rtc/rtc-armada38x.c
> +++ b/drivers/rtc/rtc-armada38x.c
> @@ -29,12 +29,21 @@
> #define RTC_TIME 0xC
> #define RTC_ALARM1 0x10
>
> +#define SOC_RTC_BRIDGE_TIMING_CTL 0x0
> +#define SOC_RTC_PERIOD_OFFS 0
> +#define SOC_RTC_PERIOD_MASK (0x3FF << SOC_RTC_PERIOD_OFFS)
> +#define SOC_RTC_READ_DELAY_OFFS 26
> +#define SOC_RTC_READ_DELAY_MASK (0x1F << SOC_RTC_READ_DELAY_OFFS)
> +
> #define SOC_RTC_INTERRUPT 0x8
> #define SOC_RTC_ALARM1 BIT(0)
> #define SOC_RTC_ALARM2 BIT(1)
> #define SOC_RTC_ALARM1_MASK BIT(2)
> #define SOC_RTC_ALARM2_MASK BIT(3)
>
> +
> +#define SAMPLE_NR 100
> +
> struct armada38x_rtc {
> struct rtc_device *rtc_dev;
> void __iomem *regs;
> @@ -47,32 +56,85 @@ struct armada38x_rtc {
> * According to the datasheet, the OS should wait 5us after every
> * register write to the RTC hard macro so that the required update
> * can occur without holding off the system bus
> + * According to errata FE-3124064, Write to any RTC register
> + * may fail. As a workaround, before writing to RTC
> + * register, issue a dummy write of 0x0 twice to RTC Status
> + * register.
> */
> +
> static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
> {
> + writel(0, rtc->regs + RTC_STATUS);
> + writel(0, rtc->regs + RTC_STATUS);
> writel(val, rtc->regs + offset);
> udelay(5);
> }
>
> +/* Update RTC-MBUS bridge timing parameters */
> +static void rtc_update_mbus_timing_params(struct armada38x_rtc *rtc)
> +{
> + uint32_t reg;
> +
> + reg = readl(rtc->regs_soc + SOC_RTC_BRIDGE_TIMING_CTL);
> + reg &= ~SOC_RTC_PERIOD_MASK;
> + reg |= 0x3FF << SOC_RTC_PERIOD_OFFS; /* Maximum value */
> + reg &= ~SOC_RTC_READ_DELAY_MASK;
> + reg |= 0x1F << SOC_RTC_READ_DELAY_OFFS; /* Maximum value */
> + writel(reg, rtc->regs_soc + SOC_RTC_BRIDGE_TIMING_CTL);
> +}
> +
> +struct str_value_to_freq {
> + unsigned long value;
> + u8 freq;
> +} __packed;
Why packed? This makes accesses to this structure very inefficient -
the compiler for some CPUs will load "value" by bytes.
As you're targetting 32-bit and 64-bit, why the use of "unsigned long"
here - readl() returns a u32, guaranteed to be 32-bit. "unsigned long"
will be 64-bit on ARM64, so wastes 32-bits per sample, completely
negating any advantage of that __packed attribute.
> +
> +static unsigned long read_rtc_register_wa(struct armada38x_rtc *rtc, u8 rtc_reg)
> +{
> + unsigned long value_array[SAMPLE_NR], i, j, value;
> + unsigned long max = 0, index_max = SAMPLE_NR - 1;
> + struct str_value_to_freq value_to_freq[SAMPLE_NR];
Consider using int or unsigned int for loop variables and indexes, but
something other than unsigned long to store the results from reading
hardware registers (same reason as above.)
> +
> + for (i = 0; i < SAMPLE_NR; i++) {
> + value_to_freq[i].freq = 0;
> + value_array[i] = readl(rtc->regs + rtc_reg);
> + }
> + for (i = 0; i < SAMPLE_NR; i++) {
> + value = value_array[i];
> + /*
> + * if value appears in value_to_freq array so add the
> + * counter of value, if didn't appear yet in counters
> + * array then allocate new member of value_to_freq
> + * array with counter = 1
> + */
> + for (j = 0; j < SAMPLE_NR; j++) {
> + if (value_to_freq[j].freq == 0 ||
> + value_to_freq[j].value == value)
> + break;
> + if (j == (SAMPLE_NR - 1))
> + break;
> + }
> + if (value_to_freq[j].freq == 0)
> + value_to_freq[j].value = value;
> + value_to_freq[j].freq++;
> + /* find the most common result */
> + if (max < value_to_freq[j].freq) {
> + index_max = j;
> + max = value_to_freq[j].freq;
> + }
> + }
> + return value_to_freq[index_max].value;
> +}
> +
> static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
> {
> struct armada38x_rtc *rtc = dev_get_drvdata(dev);
> - unsigned long time, time_check, flags;
> + unsigned long time, flags;
>
> spin_lock_irqsave(&rtc->lock, flags);
> - time = readl(rtc->regs + RTC_TIME);
> - /*
> - * WA for failing time set attempts. As stated in HW ERRATA if
> - * more than one second between two time reads is detected
> - * then read once again.
> - */
> - time_check = readl(rtc->regs + RTC_TIME);
> - if ((time_check - time) > 1)
> - time_check = readl(rtc->regs + RTC_TIME);
> -
> + time = read_rtc_register_wa(rtc, RTC_TIME);
> spin_unlock_irqrestore(&rtc->lock, flags);
>
> - rtc_time_to_tm(time_check, tm);
> + rtc_time_to_tm(time, tm);
>
> return 0;
> }
> @@ -87,16 +149,9 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
>
> if (ret)
> goto out;
> - /*
> - * According to errata FE-3124064, Write to RTC TIME register
> - * may fail. As a workaround, after writing to RTC TIME
> - * register, issue a dummy write of 0x0 twice to RTC Status
> - * register.
> - */
> +
> spin_lock_irqsave(&rtc->lock, flags);
> rtc_delayed_write(time, rtc, RTC_TIME);
> - rtc_delayed_write(0, rtc, RTC_STATUS);
> - rtc_delayed_write(0, rtc, RTC_STATUS);
> spin_unlock_irqrestore(&rtc->lock, flags);
>
> out:
> @@ -111,8 +166,8 @@ static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
>
> spin_lock_irqsave(&rtc->lock, flags);
>
> - time = readl(rtc->regs + RTC_ALARM1);
> - val = readl(rtc->regs + RTC_IRQ1_CONF) & RTC_IRQ1_AL_EN;
> + time = read_rtc_register_wa(rtc, RTC_ALARM1);
> + val = read_rtc_register_wa(rtc, RTC_IRQ1_CONF) & RTC_IRQ1_AL_EN;
>
> spin_unlock_irqrestore(&rtc->lock, flags);
>
> @@ -182,7 +237,7 @@ static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
> val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
>
> writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT);
> - val = readl(rtc->regs + RTC_IRQ1_CONF);
> + val = read_rtc_register_wa(rtc, RTC_IRQ1_CONF);
> /* disable all the interrupts for alarm 1 */
> rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
> /* Ack the event */
> @@ -196,7 +251,6 @@ static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
> else
> event |= RTC_PF;
> }
> -
> rtc_update_irq(rtc->rtc_dev, 1, event);
>
> return IRQ_HANDLED;
> @@ -253,6 +307,9 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
> if (rtc->irq != -1)
> device_init_wakeup(&pdev->dev, 1);
>
> + /* Update RTC-MBUS bridge timing parameters */
> + rtc_update_mbus_timing_params(rtc);
> +
> rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
> &armada38x_rtc_ops, THIS_MODULE);
> if (IS_ERR(rtc->rtc_dev)) {
> @@ -260,6 +317,7 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
> dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
> return ret;
> }
> +
> return 0;
> }
>
> @@ -280,6 +338,9 @@ static int armada38x_rtc_resume(struct device *dev)
> if (device_may_wakeup(dev)) {
> struct armada38x_rtc *rtc = dev_get_drvdata(dev);
>
> + /* Update RTC-MBUS bridge timing parameters */
> + rtc_update_mbus_timing_params(rtc);
> +
> return disable_irq_wake(rtc->irq);
> }
>
> --
> 2.10.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* [RESEND-PATCH] ARM: EXYNOS: remove smp hook from machine descriptor
From: Krzysztof Kozlowski @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481166135-1588-1-git-send-email-pankaj.dubey@samsung.com>
On Thu, Dec 08, 2016 at 08:32:15AM +0530, Pankaj Dubey wrote:
> Use CPU_METHOD_OF_DECLARE() for smp_ops instead of using it
> via machine descriptor.
>
> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> ---
>
> Resending as I missed to include samsung mailing list.
>
> arch/arm/boot/dts/exynos3250.dtsi | 1 +
> arch/arm/boot/dts/exynos4210.dtsi | 1 +
> arch/arm/boot/dts/exynos4212.dtsi | 1 +
> arch/arm/boot/dts/exynos4412.dtsi | 1 +
> arch/arm/boot/dts/exynos5250.dtsi | 1 +
> arch/arm/boot/dts/exynos5260.dtsi | 1 +
> arch/arm/boot/dts/exynos5410.dtsi | 1 +
> arch/arm/boot/dts/exynos5420-cpus.dtsi | 1 +
> arch/arm/boot/dts/exynos5422-cpus.dtsi | 1 +
> arch/arm/boot/dts/exynos5440.dtsi | 1 +
> arch/arm/mach-exynos/common.h | 2 --
> arch/arm/mach-exynos/exynos.c | 1 -
> arch/arm/mach-exynos/platsmp.c | 2 ++
> 13 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
> index ba17ee1..f28f669 100644
> --- a/arch/arm/boot/dts/exynos3250.dtsi
> +++ b/arch/arm/boot/dts/exynos3250.dtsi
> @@ -53,6 +53,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu0: cpu at 0 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
> index 7f3a18c..6dfd98d 100644
> --- a/arch/arm/boot/dts/exynos4210.dtsi
> +++ b/arch/arm/boot/dts/exynos4210.dtsi
> @@ -35,6 +35,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu0: cpu at 900 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi
> index 5389011..3e8982e 100644
> --- a/arch/arm/boot/dts/exynos4212.dtsi
> +++ b/arch/arm/boot/dts/exynos4212.dtsi
> @@ -25,6 +25,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu0: cpu at A00 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi
> index 40beede..faf2fb8 100644
> --- a/arch/arm/boot/dts/exynos4412.dtsi
> +++ b/arch/arm/boot/dts/exynos4412.dtsi
> @@ -25,6 +25,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu0: cpu at A00 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
> index b6d7444..580897c 100644
> --- a/arch/arm/boot/dts/exynos5250.dtsi
> +++ b/arch/arm/boot/dts/exynos5250.dtsi
> @@ -52,6 +52,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu0: cpu at 0 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5260.dtsi b/arch/arm/boot/dts/exynos5260.dtsi
> index 5818718..1af6e76 100644
> --- a/arch/arm/boot/dts/exynos5260.dtsi
> +++ b/arch/arm/boot/dts/exynos5260.dtsi
> @@ -32,6 +32,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu at 0 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5410.dtsi b/arch/arm/boot/dts/exynos5410.dtsi
> index 2b6adaf..b092cdc 100644
> --- a/arch/arm/boot/dts/exynos5410.dtsi
> +++ b/arch/arm/boot/dts/exynos5410.dtsi
> @@ -33,6 +33,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu0: cpu at 0 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5420-cpus.dtsi b/arch/arm/boot/dts/exynos5420-cpus.dtsi
> index 5c052d7..a587704 100644
> --- a/arch/arm/boot/dts/exynos5420-cpus.dtsi
> +++ b/arch/arm/boot/dts/exynos5420-cpus.dtsi
> @@ -24,6 +24,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu0: cpu at 0 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5422-cpus.dtsi b/arch/arm/boot/dts/exynos5422-cpus.dtsi
> index bf3c6f1..7fcdfd0 100644
> --- a/arch/arm/boot/dts/exynos5422-cpus.dtsi
> +++ b/arch/arm/boot/dts/exynos5422-cpus.dtsi
> @@ -23,6 +23,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu0: cpu at 100 {
> device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
> index 2a2e570..0a958e8 100644
> --- a/arch/arm/boot/dts/exynos5440.dtsi
> +++ b/arch/arm/boot/dts/exynos5440.dtsi
> @@ -50,6 +50,7 @@
> cpus {
> #address-cells = <1>;
> #size-cells = <0>;
> + enable-method = "samsung,exynos-smp";
>
> cpu at 0 {
> device_type = "cpu";
> diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
> index fb12d11..051e1ab 100644
> --- a/arch/arm/mach-exynos/common.h
> +++ b/arch/arm/mach-exynos/common.h
> @@ -143,8 +143,6 @@ static inline void exynos_pm_init(void) {}
> extern void exynos_cpu_resume(void);
> extern void exynos_cpu_resume_ns(void);
>
> -extern const struct smp_operations exynos_smp_ops;
> -
> extern void exynos_cpu_power_down(int cpu);
> extern void exynos_cpu_power_up(int cpu);
> extern int exynos_cpu_power_state(int cpu);
> diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
> index fa08ef9..f0a766e 100644
> --- a/arch/arm/mach-exynos/exynos.c
> +++ b/arch/arm/mach-exynos/exynos.c
> @@ -211,7 +211,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
> /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
> .l2c_aux_val = 0x3c400001,
> .l2c_aux_mask = 0xc20fffff,
> - .smp = smp_ops(exynos_smp_ops),
> .map_io = exynos_init_io,
> .init_early = exynos_firmware_init,
> .init_irq = exynos_init_irq,
> diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
> index 94405c7..43eec10 100644
> --- a/arch/arm/mach-exynos/platsmp.c
> +++ b/arch/arm/mach-exynos/platsmp.c
> @@ -474,3 +474,5 @@ const struct smp_operations exynos_smp_ops __initconst = {
> .cpu_die = exynos_cpu_die,
> #endif
> };
> +
> +CPU_METHOD_OF_DECLARE(exynos_smp, "samsung,exynos-smp", &exynos_smp_ops);
Three issues:
1. This has to be documented. Checkpatch did not complain about it?
2. I think this breaks the ABI with existing DTBs because now the
enable-method of cpus becomes mandatory. But the
Documentation/devicetree/bindings/arm/cpus.txt is saying that:
"On ARM 32-bit systems this property is optional and can be one of"
3. Please split DTS changes to separate patches. This is, by the way,
connected with #2 above: if there was no ABI break, then the DTS
could go to separate branch easily.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v18 15/15] acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
This driver adds support for parsing SBSA Generic Watchdog timer
in GTDT, parse all info in SBSA Generic Watchdog Structure in GTDT,
and creating a platform device with that information.
This allows the operating system to obtain device data from the
resource of platform device. The platform device named "sbsa-gwdt"
can be used by the ARM SBSA Generic Watchdog driver.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
drivers/acpi/arm64/gtdt.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/watchdog/Kconfig | 1 +
2 files changed, 94 insertions(+)
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
index 91ea6cb..22d3659 100644
--- a/drivers/acpi/arm64/gtdt.c
+++ b/drivers/acpi/arm64/gtdt.c
@@ -14,6 +14,7 @@
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/platform_device.h>
#include <clocksource/arm_arch_timer.h>
@@ -59,6 +60,13 @@ static inline bool is_timer_block(void *platform_timer)
return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK;
}
+static inline bool is_watchdog(void *platform_timer)
+{
+ struct acpi_gtdt_header *gh = platform_timer;
+
+ return gh->type == ACPI_GTDT_TYPE_WATCHDOG;
+}
+
static int __init map_gt_gsi(u32 interrupt, u32 flags)
{
int trigger, polarity;
@@ -279,3 +287,88 @@ int __init acpi_arch_timer_mem_init(struct arch_timer_mem *data,
return 0;
}
+
+/*
+ * Initialize a SBSA generic Watchdog platform device info from GTDT
+ */
+static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd,
+ int index)
+{
+ struct platform_device *pdev;
+ int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags);
+ int no_irq = 1;
+
+ /*
+ * According to SBSA specification the size of refresh and control
+ * frames of SBSA Generic Watchdog is SZ_4K(Offset 0x000 ? 0xFFF).
+ */
+ struct resource res[] = {
+ DEFINE_RES_MEM(wd->control_frame_address, SZ_4K),
+ DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K),
+ DEFINE_RES_IRQ(irq),
+ };
+
+ pr_debug("found a Watchdog (0x%llx/0x%llx gsi:%u flags:0x%x).\n",
+ wd->refresh_frame_address, wd->control_frame_address,
+ wd->timer_interrupt, wd->timer_flags);
+
+ if (!(wd->refresh_frame_address && wd->control_frame_address)) {
+ pr_err(FW_BUG "failed to get the Watchdog base address.\n");
+ return -EINVAL;
+ }
+
+ if (!wd->timer_interrupt)
+ pr_warn(FW_BUG "failed to get the Watchdog interrupt.\n");
+ else if (irq <= 0)
+ pr_warn("failed to map the Watchdog interrupt.\n");
+ else
+ no_irq = 0;
+
+ /*
+ * Add a platform device named "sbsa-gwdt" to match the platform driver.
+ * "sbsa-gwdt": SBSA(Server Base System Architecture) Generic Watchdog
+ * The platform driver (like drivers/watchdog/sbsa_gwdt.c)can get device
+ * info below by matching this name.
+ */
+ pdev = platform_device_register_simple("sbsa-gwdt", index, res,
+ ARRAY_SIZE(res) - no_irq);
+ if (IS_ERR(pdev)) {
+ acpi_unregister_gsi(wd->timer_interrupt);
+ return PTR_ERR(pdev);
+ }
+
+ return 0;
+}
+
+static int __init gtdt_sbsa_gwdt_init(void)
+{
+ int ret, i = 0;
+ void *platform_timer;
+ struct acpi_table_header *table;
+
+ if (acpi_disabled)
+ return 0;
+
+ if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, &table)))
+ return -EINVAL;
+
+ ret = acpi_gtdt_init(table, NULL);
+ if (ret)
+ return ret;
+
+ for_each_platform_timer(platform_timer) {
+ if (is_watchdog(platform_timer)) {
+ ret = gtdt_import_sbsa_gwdt(platform_timer, i);
+ if (ret)
+ break;
+ i++;
+ }
+ }
+
+ if (i)
+ pr_info("found %d SBSA generic Watchdog(s).\n", i);
+
+ return ret;
+}
+
+device_initcall(gtdt_sbsa_gwdt_init);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3eb58cb..a95c62d 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -219,6 +219,7 @@ config ARM_SBSA_WATCHDOG
tristate "ARM SBSA Generic Watchdog"
depends on ARM64
depends on ARM_ARCH_TIMER
+ depends on ACPI_GTDT || !ACPI
select WATCHDOG_CORE
help
ARM SBSA Generic Watchdog has two stage timeouts:
--
2.9.3
^ permalink raw reply related
* [PATCH v18 14/15] clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped timer
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch add memory-mapped timer register support by using the
information provided by the new GTDT driver of ACPI.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 7f059f9..1fe1c08 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1054,10 +1054,36 @@ CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_of_init);
#ifdef CONFIG_ACPI_GTDT
-/* Initialize per-processor generic timer */
+static int __init arch_timer_mem_acpi_init(int platform_timer_count)
+{
+ struct arch_timer_mem *timer_mem;
+ int timer_count, i, ret;
+
+ timer_mem = kcalloc(platform_timer_count, sizeof(*timer_mem),
+ GFP_KERNEL);
+ if (!timer_mem)
+ return -ENOMEM;
+
+ ret = acpi_arch_timer_mem_init(timer_mem, &timer_count);
+ if (ret || !timer_count)
+ goto error;
+
+ for (i = 0; i < timer_count; i++) {
+ ret = arch_timer_mem_init(timer_mem);
+ if (!ret)
+ break;
+ timer_mem++;
+ }
+
+error:
+ kfree(timer_mem);
+ return ret;
+}
+
+/* Initialize per-processor generic timer and memory-mapped timer(if present) */
static int __init arch_timer_acpi_init(struct acpi_table_header *table)
{
- int ret;
+ int ret, platform_timer_count;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("already initialized, skipping\n");
@@ -1066,7 +1092,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- ret = acpi_gtdt_init(table, NULL);
+ ret = acpi_gtdt_init(table, &platform_timer_count);
if (ret) {
pr_err("Failed to init GTDT table.\n");
return ret;
@@ -1099,6 +1125,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
if (ret)
return ret;
+ if (arch_timer_mem_acpi_init(platform_timer_count))
+ pr_err("Failed to initialize memory-mapped timer.\n");
+
return arch_timer_common_init();
}
CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
--
2.9.3
^ permalink raw reply related
* [PATCH v18 13/15] acpi/arm64: Add memory-mapped timer support in GTDT driver
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
On platforms booting with ACPI, architected memory-mapped timers'
configuration data is provided by firmware through the ACPI GTDT
static table.
The clocksource architected timer kernel driver requires a firmware
interface to collect timer configuration and configure its driver.
this infrastructure is present for device tree systems, but it is
missing on systems booting with ACPI.
Implement the kernel infrastructure required to parse the static
ACPI GTDT table so that the architected timer clocksource driver can
make use of it on systems booting with ACPI, therefore enabling
the corresponding timers configuration.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/acpi/arm64/gtdt.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 1 +
2 files changed, 125 insertions(+)
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
index d93a790..91ea6cb 100644
--- a/drivers/acpi/arm64/gtdt.c
+++ b/drivers/acpi/arm64/gtdt.c
@@ -37,6 +37,28 @@ struct acpi_gtdt_descriptor {
static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
+static inline void *next_platform_timer(void *platform_timer)
+{
+ struct acpi_gtdt_header *gh = platform_timer;
+
+ platform_timer += gh->length;
+ if (platform_timer < acpi_gtdt_desc.gtdt_end)
+ return platform_timer;
+
+ return NULL;
+}
+
+#define for_each_platform_timer(_g) \
+ for (_g = acpi_gtdt_desc.platform_timer; _g; \
+ _g = next_platform_timer(_g))
+
+static inline bool is_timer_block(void *platform_timer)
+{
+ struct acpi_gtdt_header *gh = platform_timer;
+
+ return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK;
+}
+
static int __init map_gt_gsi(u32 interrupt, u32 flags)
{
int trigger, polarity;
@@ -155,3 +177,105 @@ int __init acpi_gtdt_init(struct acpi_table_header *table,
return ret;
}
+
+static int __init gtdt_parse_timer_block(struct acpi_gtdt_timer_block *block,
+ struct arch_timer_mem *data)
+{
+ int i;
+ struct acpi_gtdt_timer_entry *frame;
+
+ if (!block->timer_count) {
+ pr_err(FW_BUG "GT block present, but frame count is zero.");
+ return -ENODEV;
+ }
+
+ if (block->timer_count > ARCH_TIMER_MEM_MAX_FRAMES) {
+ pr_err(FW_BUG "GT block lists %d frames, ACPI spec only allows 8\n",
+ block->timer_count);
+ return -EINVAL;
+ }
+
+ data->cntctlbase = (phys_addr_t)block->block_address;
+ /*
+ * According to "Table * CNTCTLBase memory map" of
+ * <ARM Architecture Reference Manual> for ARMv8,
+ * The size of the CNTCTLBase frame is 4KB(Offset 0x000 ? 0xFFC).
+ */
+ data->size = SZ_4K;
+ data->num_frames = block->timer_count;
+
+ frame = (void *)block + block->timer_offset;
+ if (frame + block->timer_count != (void *)block + block->header.length)
+ return -EINVAL;
+
+ /*
+ * Get the GT timer Frame data for every GT Block Timer
+ */
+ for (i = 0; i < block->timer_count; i++, frame++) {
+ if (!frame->base_address || !frame->timer_interrupt)
+ return -EINVAL;
+
+ data->frame[i].phys_irq = map_gt_gsi(frame->timer_interrupt,
+ frame->timer_flags);
+ if (data->frame[i].phys_irq <= 0) {
+ pr_warn("failed to map physical timer irq in frame %d.\n",
+ i);
+ return -EINVAL;
+ }
+
+ data->frame[i].virt_irq =
+ map_gt_gsi(frame->virtual_timer_interrupt,
+ frame->virtual_timer_flags);
+ if (data->frame[i].virt_irq <= 0) {
+ pr_warn("failed to map virtual timer irq in frame %d.\n",
+ i);
+ acpi_unregister_gsi(frame->timer_interrupt);
+ return -EINVAL;
+ }
+
+ data->frame[i].frame_nr = frame->frame_number;
+ data->frame[i].cntbase = frame->base_address;
+ /*
+ * According to "Table * CNTBaseN memory map" of
+ * <ARM Architecture Reference Manual> for ARMv8,
+ * The size of the CNTBaseN frame is 4KB(Offset 0x000 ? 0xFFC).
+ */
+ data->frame[i].size = SZ_4K;
+ }
+
+ return 0;
+}
+
+/**
+ * acpi_arch_timer_mem_init() - Get the info of all GT blocks in GTDT table.
+ * @data: the pointer to the array of struct arch_timer_mem for returning
+ * the result of parsing. The element number of this array should
+ * be platform_timer_count(the total number of platform timers).
+ * @count: The pointer of int variate for returning the number of GT
+ * blocks we have parsed.
+ *
+ * Return: 0 if success, -EINVAL/-ENODEV if error.
+ */
+int __init acpi_arch_timer_mem_init(struct arch_timer_mem *data,
+ int *timer_count)
+{
+ int ret;
+ void *platform_timer;
+
+ *timer_count = 0;
+ for_each_platform_timer(platform_timer) {
+ if (is_timer_block(platform_timer)) {
+ ret = gtdt_parse_timer_block(platform_timer, data);
+ if (ret)
+ return ret;
+ data++;
+ (*timer_count)++;
+ }
+ }
+
+ if (*timer_count)
+ pr_info("found %d memory-mapped timer block(s).\n",
+ *timer_count);
+
+ return 0;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index d201ce4..f5881de 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -581,6 +581,7 @@ int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count);
int acpi_gtdt_map_ppi(int type);
bool acpi_gtdt_c3stop(int type);
+int acpi_arch_timer_mem_init(struct arch_timer_mem *data, int *timer_count);
#endif
#else /* !CONFIG_ACPI */
--
2.9.3
^ permalink raw reply related
* [PATCH v18 12/15] clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch update arm_arch_timer driver to use the function
provided by the new GTDT driver of ACPI.
By this way, arm_arch_timer.c can be simplified, and separate
all the ACPI GTDT knowledge from this timer driver.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
drivers/clocksource/arm_arch_timer.c | 46 ++++++++++--------------------------
1 file changed, 13 insertions(+), 33 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index b02a406..7f059f9 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1053,59 +1053,36 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_of_init);
-#ifdef CONFIG_ACPI
-static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
-{
- int trigger, polarity;
-
- if (!interrupt)
- return 0;
-
- trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
- : ACPI_LEVEL_SENSITIVE;
-
- polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
- : ACPI_ACTIVE_HIGH;
-
- return acpi_register_gsi(NULL, interrupt, trigger, polarity);
-}
-
+#ifdef CONFIG_ACPI_GTDT
/* Initialize per-processor generic timer */
static int __init arch_timer_acpi_init(struct acpi_table_header *table)
{
int ret;
- struct acpi_table_gtdt *gtdt;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("already initialized, skipping\n");
return -EINVAL;
}
- gtdt = container_of(table, struct acpi_table_gtdt, header);
-
arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] =
- map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
- gtdt->secure_el1_flags);
+ ret = acpi_gtdt_init(table, NULL);
+ if (ret) {
+ pr_err("Failed to init GTDT table.\n");
+ return ret;
+ }
arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] =
- map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
- gtdt->non_secure_el1_flags);
+ acpi_gtdt_map_ppi(ARCH_TIMER_PHYS_NONSECURE_PPI);
arch_timer_ppi[ARCH_TIMER_VIRT_PPI] =
- map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
- gtdt->virtual_timer_flags);
+ acpi_gtdt_map_ppi(ARCH_TIMER_VIRT_PPI);
arch_timer_ppi[ARCH_TIMER_HYP_PPI] =
- map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
- gtdt->non_secure_el2_flags);
+ acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI);
arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
- /* Get the frequency from CNTFRQ */
- arch_timer_detect_rate();
-
arch_timer_uses_ppi = arch_timer_select_ppi();
if (!arch_timer_ppi[arch_timer_uses_ppi]) {
pr_err("No interrupt available, giving up\n");
@@ -1113,7 +1090,10 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
}
/* Always-on capability */
- arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
+ arch_timer_c3stop = acpi_gtdt_c3stop(arch_timer_uses_ppi);
+
+ /* Get the frequency from CNTFRQ */
+ arch_timer_detect_rate();
ret = arch_timer_register();
if (ret)
--
2.9.3
^ permalink raw reply related
* [PATCH v18 11/15] acpi/arm64: Add GTDT table parse driver
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
This patch adds support for parsing arch timer info in GTDT,
provides some kernel APIs to parse all the PPIs and
always-on info in GTDT and export them.
By this driver, we can simplify arm_arch_timer drivers, and
separate the ACPI GTDT knowledge from it.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
arch/arm64/Kconfig | 1 +
drivers/acpi/arm64/Kconfig | 3 +
drivers/acpi/arm64/Makefile | 1 +
drivers/acpi/arm64/gtdt.c | 157 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 6 ++
5 files changed, 168 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 969ef88..4277a21 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2,6 +2,7 @@ config ARM64
def_bool y
select ACPI_CCA_REQUIRED if ACPI
select ACPI_GENERIC_GSI if ACPI
+ select ACPI_GTDT if ACPI
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ACPI_MCFG if ACPI
select ACPI_SPCR_TABLE if ACPI
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig
index 4616da4..5a6f80f 100644
--- a/drivers/acpi/arm64/Kconfig
+++ b/drivers/acpi/arm64/Kconfig
@@ -4,3 +4,6 @@
config ACPI_IORT
bool
+
+config ACPI_GTDT
+ bool
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 72331f2..1017def 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ACPI_IORT) += iort.o
+obj-$(CONFIG_ACPI_GTDT) += gtdt.o
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
new file mode 100644
index 0000000..d93a790
--- /dev/null
+++ b/drivers/acpi/arm64/gtdt.c
@@ -0,0 +1,157 @@
+/*
+ * ARM Specific GTDT table Support
+ *
+ * Copyright (C) 2016, Linaro Ltd.
+ * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
+ * Fu Wei <fu.wei@linaro.org>
+ * 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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "ACPI GTDT: " fmt
+
+/**
+ * struct acpi_gtdt_descriptor - Store the key info of GTDT for all functions
+ * @gtdt: The pointer to the struct acpi_table_gtdt of GTDT table.
+ * @gtdt_end: The pointer to the end of GTDT table.
+ * @platform_timer: The pointer to the start of Platform Timer Structure
+ *
+ * The struct store the key info of GTDT table, it should be initialized by
+ * acpi_gtdt_init.
+ */
+struct acpi_gtdt_descriptor {
+ struct acpi_table_gtdt *gtdt;
+ void *gtdt_end;
+ void *platform_timer;
+};
+
+static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
+
+static int __init map_gt_gsi(u32 interrupt, u32 flags)
+{
+ int trigger, polarity;
+
+ trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
+ : ACPI_LEVEL_SENSITIVE;
+
+ polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
+ : ACPI_ACTIVE_HIGH;
+
+ return acpi_register_gsi(NULL, interrupt, trigger, polarity);
+}
+
+/**
+ * acpi_gtdt_map_ppi() - Map the PPIs of per-cpu arch_timer.
+ * @type: the type of PPI.
+ *
+ * Note: Linux on arm64 isn't supported on the secure side.
+ * So we only handle the non-secure timer PPIs,
+ * ARCH_TIMER_PHYS_SECURE_PPI is treated as invalid type.
+ *
+ * Return: the mapped PPI value, 0 if error.
+ */
+int __init acpi_gtdt_map_ppi(int type)
+{
+ struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt;
+
+ switch (type) {
+ case ARCH_TIMER_PHYS_NONSECURE_PPI:
+ return map_gt_gsi(gtdt->non_secure_el1_interrupt,
+ gtdt->non_secure_el1_flags);
+ case ARCH_TIMER_VIRT_PPI:
+ return map_gt_gsi(gtdt->virtual_timer_interrupt,
+ gtdt->virtual_timer_flags);
+
+ case ARCH_TIMER_HYP_PPI:
+ return map_gt_gsi(gtdt->non_secure_el2_interrupt,
+ gtdt->non_secure_el2_flags);
+ default:
+ pr_err("Failed to map timer interrupt: invalid type.\n");
+ }
+
+ return 0;
+}
+
+/**
+ * acpi_gtdt_c3stop() - Got c3stop info from GTDT according to the type of PPI.
+ * @type: the type of PPI.
+ *
+ * Return: 1 if the timer can be in deep idle state, 0 otherwise.
+ */
+bool __init acpi_gtdt_c3stop(int type)
+{
+ struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt;
+
+ switch (type) {
+ case ARCH_TIMER_PHYS_NONSECURE_PPI:
+ return !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
+
+ case ARCH_TIMER_VIRT_PPI:
+ return !(gtdt->virtual_timer_flags & ACPI_GTDT_ALWAYS_ON);
+
+ case ARCH_TIMER_HYP_PPI:
+ return !(gtdt->non_secure_el2_flags & ACPI_GTDT_ALWAYS_ON);
+
+ default:
+ pr_err("Failed to get c3stop info: invalid type.\n");
+ }
+
+ return 0;
+}
+
+/**
+ * acpi_gtdt_init() - Get the info of GTDT table to prepare for further init.
+ * @table: The pointer to GTDT table.
+ * @platform_timer_count: The pointer of int variate for returning the
+ * number of platform timers. It can be NULL, if
+ * driver don't need this info.
+ *
+ * Return: 0 if success, -EINVAL if error.
+ */
+int __init acpi_gtdt_init(struct acpi_table_header *table,
+ int *platform_timer_count)
+{
+ int ret = 0;
+ int timer_count = 0;
+ void *platform_timer = NULL;
+ struct acpi_table_gtdt *gtdt;
+
+ gtdt = container_of(table, struct acpi_table_gtdt, header);
+ acpi_gtdt_desc.gtdt = gtdt;
+ acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
+
+ if (table->revision < 2)
+ pr_debug("Revision:%d doesn't support Platform Timers.\n",
+ table->revision);
+ else if (!gtdt->platform_timer_count)
+ pr_debug("No Platform Timer.\n");
+ else
+ timer_count = gtdt->platform_timer_count;
+
+ if (timer_count) {
+ platform_timer = (void *)gtdt + gtdt->platform_timer_offset;
+ if (platform_timer < (void *)table +
+ sizeof(struct acpi_table_gtdt)) {
+ pr_err(FW_BUG "invalid timer data.\n");
+ timer_count = 0;
+ platform_timer = NULL;
+ ret = -EINVAL;
+ }
+ }
+
+ acpi_gtdt_desc.platform_timer = platform_timer;
+ if (platform_timer_count)
+ *platform_timer_count = timer_count;
+
+ return ret;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 61a3d90..d201ce4 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -577,6 +577,12 @@ enum acpi_reconfig_event {
int acpi_reconfig_notifier_register(struct notifier_block *nb);
int acpi_reconfig_notifier_unregister(struct notifier_block *nb);
+#ifdef CONFIG_ACPI_GTDT
+int acpi_gtdt_init(struct acpi_table_header *table, int *platform_timer_count);
+int acpi_gtdt_map_ppi(int type);
+bool acpi_gtdt_c3stop(int type);
+#endif
+
#else /* !CONFIG_ACPI */
#define acpi_disabled 1
--
2.9.3
^ permalink raw reply related
* [PATCH v18 10/15] clocksource/drivers/arm_arch_timer: Refactor the timer init code to prepare for GTDT
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch refactor original memory-mapped timer init code:
(1) Refactor "arch_timer_mem_init", make it become a common code for
memory-mapped timer init.
(2) Add a new function "arch_timer_mem_of_init" for DT init.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 130 ++++++++++++++++++++++++-----------
1 file changed, 88 insertions(+), 42 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 8c813da..b02a406 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -915,17 +915,17 @@ static int __init arch_timer_of_init(struct device_node *np)
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 int __init arch_timer_mem_init(struct device_node *np)
+static int __init arch_timer_mem_init(struct arch_timer_mem *timer_mem)
{
- struct device_node *frame, *best_frame = NULL;
void __iomem *cntctlbase, *base;
- unsigned int irq, ret = -EINVAL;
+ struct arch_timer_mem_frame *best_frame = NULL;
+ unsigned int irq;
u32 cnttidr;
+ int i, ret;
- arch_timers_present |= ARCH_TIMER_TYPE_MEM;
- cntctlbase = of_iomap(np, 0);
+ cntctlbase = ioremap(timer_mem->cntctlbase, timer_mem->size);
if (!cntctlbase) {
- pr_err("Can't find CNTCTLBase\n");
+ pr_err("Can't map CNTCTLBase.\n");
return -ENXIO;
}
@@ -935,26 +935,18 @@ static int __init arch_timer_mem_init(struct device_node *np)
* Try to find a virtual capable frame. Otherwise fall back to a
* physical capable frame.
*/
- for_each_available_child_of_node(np, frame) {
- int n;
- u32 cntacr;
-
- if (of_property_read_u32(frame, "frame-number", &n)) {
- pr_err("Missing frame-number\n");
- of_node_put(frame);
- goto out;
- }
+ for (i = 0; i < timer_mem->num_frames; i++) {
+ u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
+ CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
+ int n = timer_mem->frame[i].frame_nr;
/* Try enabling everything, and see what sticks */
- cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
- CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
writel_relaxed(cntacr, cntctlbase + CNTACR(n));
cntacr = readl_relaxed(cntctlbase + CNTACR(n));
if ((cnttidr & CNTTIDR_VIRT(n)) &&
!(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) {
- of_node_put(best_frame);
- best_frame = frame;
+ best_frame = &timer_mem->frame[i];
arch_timer_mem_use_virtual = true;
break;
}
@@ -962,50 +954,104 @@ static int __init arch_timer_mem_init(struct device_node *np)
if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
continue;
- of_node_put(best_frame);
- best_frame = of_node_get(frame);
+ best_frame = &timer_mem->frame[i];
}
+ iounmap(cntctlbase);
- ret= -ENXIO;
- base = arch_counter_base = of_iomap(best_frame, 0);
- if (!base) {
- pr_err("Can't map frame's registers\n");
- goto out;
+ if (!best_frame) {
+ pr_err("Can't find frame for register\n");
+ return -EINVAL;
}
if (arch_timer_mem_use_virtual)
- irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_VIRT_SPI);
+ irq = best_frame->virt_irq;
else
- irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_PHYS_SPI);
+ irq = best_frame->phys_irq;
- ret = -EINVAL;
if (!irq) {
pr_err("Frame missing %s irq",
arch_timer_mem_use_virtual ? "virt" : "phys");
- goto out;
+ return -EINVAL;
}
- /*
- * Try to determine the frequency from the device tree,
- * if fail, get the frequency from CNTFRQ.
- */
- if (!arch_timer_rate &&
- of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
- arch_timer_mem_detect_rate(base);
+ base = ioremap(best_frame->cntbase, best_frame->size);
+ if (!base) {
+ pr_err("Can't map frame's registers\n");
+ return -ENXIO;
+ }
+
+ arch_timer_mem_detect_rate(base);
ret = arch_timer_mem_register(base, irq);
- if (ret)
+ if (ret) {
+ iounmap(base);
+ return ret;
+ }
+
+ arch_counter_base = base;
+ arch_timers_present |= ARCH_TIMER_TYPE_MEM;
+
+ return 0;
+}
+
+static int __init arch_timer_mem_of_init(struct device_node *np)
+{
+ struct arch_timer_mem *timer_mem;
+ struct device_node *frame_node;
+ struct resource res;
+ int i, ret = -EINVAL;
+
+ timer_mem = kzalloc(sizeof(*timer_mem), GFP_KERNEL);
+ if (!timer_mem)
+ return -ENOMEM;
+
+ if (of_address_to_resource(np, 0, &res))
goto out;
+ timer_mem->cntctlbase = res.start;
+ timer_mem->size = resource_size(&res);
+
+ i = 0;
+ for_each_available_child_of_node(np, frame_node) {
+ int n;
+ struct arch_timer_mem_frame *frame = &timer_mem->frame[i];
+
+ if (of_property_read_u32(frame_node, "frame-number", &n)) {
+ pr_err("Missing frame-number\n");
+ of_node_put(frame_node);
+ goto out;
+ }
+ frame->frame_nr = n;
+
+ if (of_address_to_resource(frame_node, 0, &res)) {
+ of_node_put(frame_node);
+ goto out;
+ }
+ frame->cntbase = res.start;
+ frame->size = resource_size(&res);
+
+ frame->virt_irq = irq_of_parse_and_map(frame_node,
+ ARCH_TIMER_VIRT_SPI);
+ frame->phys_irq = irq_of_parse_and_map(frame_node,
+ ARCH_TIMER_PHYS_SPI);
- if (!arch_timer_needs_of_probing())
+ if (++i >= ARCH_TIMER_MEM_MAX_FRAMES)
+ break;
+ }
+ timer_mem->num_frames = i;
+
+ /* Try to determine the frequency from the device tree */
+ if (!arch_timer_rate)
+ of_property_read_u32(np, "clock-frequency", &arch_timer_rate);
+
+ ret = arch_timer_mem_init(timer_mem);
+ if (!ret && !arch_timer_needs_of_probing())
ret = arch_timer_common_init();
out:
- iounmap(cntctlbase);
- of_node_put(best_frame);
+ kfree(timer_mem);
return ret;
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
- arch_timer_mem_init);
+ arch_timer_mem_of_init);
#ifdef CONFIG_ACPI
static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
--
2.9.3
^ permalink raw reply related
* [PATCH v18 09/15] clocksource/drivers/arm_arch_timer: Introduce some new structs to prepare for GTDT
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch introduce two new structs: arch_timer_mem, arch_timer_mem_frame.
And also introduce a new define: ARCH_TIMER_MEM_MAX_FRAMES
These will be used for refactoring the memory-mapped timer init code to
prepare for GTDT
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
include/clocksource/arm_arch_timer.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 48376a5..3403247 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -57,6 +57,8 @@ enum arch_timer_spi_nr {
#define ARCH_TIMER_MEM_PHYS_ACCESS 2
#define ARCH_TIMER_MEM_VIRT_ACCESS 3
+#define ARCH_TIMER_MEM_MAX_FRAMES 8
+
#define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */
#define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */
#define ARCH_TIMER_VIRT_EVT_EN (1 << 2)
@@ -72,6 +74,21 @@ struct arch_timer_kvm_info {
int virtual_irq;
};
+struct arch_timer_mem_frame {
+ int frame_nr;
+ phys_addr_t cntbase;
+ size_t size;
+ int phys_irq;
+ int virt_irq;
+};
+
+struct arch_timer_mem {
+ phys_addr_t cntctlbase;
+ size_t size;
+ int num_frames;
+ struct arch_timer_mem_frame frame[ARCH_TIMER_MEM_MAX_FRAMES];
+};
+
#ifdef CONFIG_ARM_ARCH_TIMER
extern u32 arch_timer_get_rate(void);
--
2.9.3
^ permalink raw reply related
* [PATCH v18 08/15] clocksource/drivers/arm_arch_timer: move arch_timer_needs_of_probing into DT init call
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
Because arch_timer_needs_of_probing is only for booting with device-tree,
but arch_timer_common_init is a generic init call which shouldn't include
the FW-specific code. It's better to put arch_timer_needs_of_probing into
DT init function.
But for per-cpu timer, the arch_timer_common_init is called from
arch_timer_init. For reaching the goal above, this patch disassemble
arch_timer_init and use arch_timer_register and arch_timer_common_init
directly, just like arch_timer_mem init code is doing.
By this way, all the DT relevant code are only called from DT init call.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 46 ++++++++++++++++--------------------
1 file changed, 21 insertions(+), 25 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 2c9085a..8c813da 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -821,9 +821,6 @@ static bool __init arch_timer_needs_of_probing(void)
static int __init arch_timer_common_init(void)
{
- if (acpi_disabled && arch_timer_needs_of_probing())
- return 0;
-
arch_timer_banner(arch_timers_present);
arch_counter_register(arch_timers_present);
return arch_timer_arch_init();
@@ -861,26 +858,9 @@ static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
return ARCH_TIMER_PHYS_SECURE_PPI;
}
-static int __init arch_timer_init(void)
-{
- int ret;
-
- ret = arch_timer_register();
- if (ret)
- return ret;
-
- ret = arch_timer_common_init();
- if (ret)
- return ret;
-
- arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
-
- return 0;
-}
-
static int __init arch_timer_of_init(struct device_node *np)
{
- int i;
+ int i, ret;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("multiple nodes in dt, skipping\n");
@@ -891,6 +871,8 @@ static int __init arch_timer_of_init(struct device_node *np)
for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+ arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
+
if (!arch_timer_rate &&
of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
arch_timer_detect_rate();
@@ -921,7 +903,14 @@ static int __init arch_timer_of_init(struct device_node *np)
return -EINVAL;
}
- return arch_timer_init();
+ ret = arch_timer_register();
+ if (ret)
+ return ret;
+
+ if (arch_timer_needs_of_probing())
+ return 0;
+
+ return arch_timer_common_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);
@@ -1008,7 +997,8 @@ static int __init arch_timer_mem_init(struct device_node *np)
if (ret)
goto out;
- return arch_timer_common_init();
+ if (!arch_timer_needs_of_probing())
+ ret = arch_timer_common_init();
out:
iounmap(cntctlbase);
of_node_put(best_frame);
@@ -1037,6 +1027,7 @@ static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
/* Initialize per-processor generic timer */
static int __init arch_timer_acpi_init(struct acpi_table_header *table)
{
+ int ret;
struct acpi_table_gtdt *gtdt;
if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
@@ -1064,6 +1055,8 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
gtdt->non_secure_el2_flags);
+ arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
+
/* Get the frequency from CNTFRQ */
arch_timer_detect_rate();
@@ -1076,8 +1069,11 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
/* Always-on capability */
arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
- arch_timer_init();
- return 0;
+ ret = arch_timer_register();
+ if (ret)
+ return ret;
+
+ return arch_timer_common_init();
}
CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
#endif
--
2.9.3
^ permalink raw reply related
* [PATCH v18 07/15] clocksource/drivers/arm_arch_timer: Refactor arch_timer_needs_probing
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
When system init with device-tree, we don't know which node will be
initialized first. And the code in arch_timer_common_init should wait
until per-cpu timer and MMIO timer are both initialized. So we need
arch_timer_needs_probing to detect the init status of system.
But currently the code is dispersed in arch_timer_needs_probing and
arch_timer_common_init. And the function name doesn't specify that
it's only for device-tree. This is somewhat confusing.
This patch move all related code from arch_timer_common_init to
arch_timer_needs_probing, refactor it, and rename it to
arch_timer_needs_of_probing. And make sure that it will be called
only if acpi is disabled.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 34 +++++++++++++++++++---------------
1 file changed, 19 insertions(+), 15 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index e554081..2c9085a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -792,15 +792,28 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = {
{},
};
-static bool __init
-arch_timer_needs_probing(int type, const struct of_device_id *matches)
+static bool __init arch_timer_needs_of_probing(void)
{
struct device_node *dn;
bool needs_probing = false;
+ unsigned int mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
- dn = of_find_matching_node(NULL, matches);
- if (dn && of_device_is_available(dn) && !(arch_timers_present & type))
+ /* We have two timers, and both device-tree nodes are probed. */
+ if ((arch_timers_present & mask) == mask)
+ return false;
+
+ /*
+ * Only one type of timer is probed,
+ * check if we have another type of timer node in device-tree.
+ */
+ if (arch_timers_present & ARCH_TIMER_TYPE_CP15)
+ dn = of_find_matching_node(NULL, arch_timer_mem_of_match);
+ else
+ dn = of_find_matching_node(NULL, arch_timer_of_match);
+
+ if (dn && of_device_is_available(dn))
needs_probing = true;
+
of_node_put(dn);
return needs_probing;
@@ -808,17 +821,8 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)
static int __init arch_timer_common_init(void)
{
- unsigned mask = ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM;
-
- /* Wait until both nodes are probed if we have two timers */
- if ((arch_timers_present & mask) != mask) {
- if (arch_timer_needs_probing(ARCH_TIMER_TYPE_MEM,
- arch_timer_mem_of_match))
- return 0;
- if (arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15,
- arch_timer_of_match))
- return 0;
- }
+ if (acpi_disabled && arch_timer_needs_of_probing())
+ return 0;
arch_timer_banner(arch_timers_present);
arch_counter_register(arch_timers_present);
--
2.9.3
^ permalink raw reply related
* [PATCH v18 06/15] clocksource/drivers/arm_arch_timer: Rework counter frequency detection.
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
Currently, the counter frequency detection call(arch_timer_detect_rate)
combines all the ways to get counter frequency: device-tree property,
system coprocessor register, MMIO timer. But in the most of use cases,
we don't need all the ways to try:
For example, reading device-tree property will be needed only when
system boot with device-tree, getting frequency from MMIO timer register
will beneeded only when we init MMIO timer.
This patch separates paths to determine frequency:
Separate out device-tree code, keep them in device-tree init function.
Separate out the MMIO frequency and the sysreg frequency detection call,
and use the appropriate one for the counter.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
drivers/clocksource/arm_arch_timer.c | 49 +++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index e43be0a..e554081 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -487,27 +487,31 @@ static int arch_timer_starting_cpu(unsigned int cpu)
return 0;
}
-static void
-arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
+static void arch_timer_detect_rate(void)
{
- /* Who has more than one independent system counter? */
- if (arch_timer_rate)
- return;
+ /*
+ * Try to get the timer frequency from
+ * cntfrq_el0(system coprocessor register).
+ */
+ if (!arch_timer_rate)
+ arch_timer_rate = arch_timer_get_cntfrq();
+
+ /* Check the timer frequency. */
+ if (!arch_timer_rate)
+ pr_warn("frequency not available\n");
+}
+static void arch_timer_mem_detect_rate(void __iomem *cntbase)
+{
/*
- * Try to determine the frequency from the device tree or CNTFRQ,
- * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
+ * Try to determine the frequency from
+ * CNTFRQ in memory-mapped timer.
*/
- if (!acpi_disabled ||
- of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
- if (cntbase)
- arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
- else
- arch_timer_rate = arch_timer_get_cntfrq();
- }
+ if (!arch_timer_rate)
+ arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
/* Check the timer frequency. */
- if (arch_timer_rate == 0)
+ if (!arch_timer_rate)
pr_warn("frequency not available\n");
}
@@ -883,7 +887,9 @@ static int __init arch_timer_of_init(struct device_node *np)
for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
- arch_timer_detect_rate(NULL, np);
+ if (!arch_timer_rate &&
+ of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
+ arch_timer_detect_rate();
arch_timer_c3stop = !of_property_read_bool(np, "always-on");
@@ -986,7 +992,14 @@ static int __init arch_timer_mem_init(struct device_node *np)
goto out;
}
- arch_timer_detect_rate(base, np);
+ /*
+ * Try to determine the frequency from the device tree,
+ * if fail, get the frequency from CNTFRQ.
+ */
+ if (!arch_timer_rate &&
+ of_property_read_u32(np, "clock-frequency", &arch_timer_rate))
+ arch_timer_mem_detect_rate(base);
+
ret = arch_timer_mem_register(base, irq);
if (ret)
goto out;
@@ -1048,7 +1061,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
gtdt->non_secure_el2_flags);
/* Get the frequency from CNTFRQ */
- arch_timer_detect_rate(NULL, NULL);
+ arch_timer_detect_rate();
arch_timer_uses_ppi = arch_timer_select_ppi();
if (!arch_timer_ppi[arch_timer_uses_ppi]) {
--
2.9.3
^ permalink raw reply related
* [PATCH v18 05/15] clocksource/drivers/arm_arch_timer: rework PPI determination
From: fu.wei at linaro.org @ 2016-12-08 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
Currently, the arch timer driver uses ARCH_TIMER_PHYS_SECURE_PPI to
mean the driver will use the secure PPI *and* potentialy also use the
non-secure PPI. This is somewhat confusing.
For arm64, where it never makes sense to use the secure PPI, this
means we must always request the useless secure PPI, adding to the
confusion. For ACPI, where we may not even have a valid secure PPI
number, this is additionally problematic. We need the driver to be
able to use *only* the non-secure PPI.
The logic to choose which PPI to use is intertwined with other logic
in arch_timer_init(). This patch factors the PPI determination out
into a new function named arch_timer_select_ppi, and then reworks it
so that we can handle having only a non-secure PPI.
This patch also moves arch_timer_ppi verification out to caller,
because we can verify the configuration from device-tree for ARM by this
way.
Meanwhile, because we will select ARCH_TIMER_PHYS_NONSECURE_PPI for ARM64,
the logic in arch_timer_register also need to be updated.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
---
drivers/clocksource/arm_arch_timer.c | 77 +++++++++++++++++++++---------------
1 file changed, 46 insertions(+), 31 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 231175b..e43be0a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -699,7 +699,7 @@ static int __init arch_timer_register(void)
case ARCH_TIMER_PHYS_NONSECURE_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
- if (!err && arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]) {
+ if (!err && arch_timer_has_nonsecure_ppi()) {
ppi = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI];
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
@@ -821,39 +821,41 @@ static int __init arch_timer_common_init(void)
return arch_timer_arch_init();
}
-static int __init arch_timer_init(void)
+/**
+ * arch_timer_select_ppi() - Select suitable PPI for the current system.
+ *
+ * If HYP mode is available, we know that the physical timer
+ * has been configured to be accessible from PL1. Use it, so
+ * that a guest can use the virtual timer instead.
+ *
+ * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
+ * accesses to CNTP_*_EL1 registers are silently redirected to
+ * their CNTHP_*_EL2 counterparts, and use a different PPI
+ * number.
+ *
+ * If no interrupt provided for virtual timer, we'll have to
+ * stick to the physical timer. It'd better be accessible...
+ * For arm64 we never use the secure interrupt.
+ *
+ * Return: a suitable PPI type for the current system.
+ */
+static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
{
- int ret;
- /*
- * If HYP mode is available, we know that the physical timer
- * has been configured to be accessible from PL1. Use it, so
- * that a guest can use the virtual timer instead.
- *
- * If no interrupt provided for virtual timer, we'll have to
- * stick to the physical timer. It'd better be accessible...
- *
- * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
- * accesses to CNTP_*_EL1 registers are silently redirected to
- * their CNTHP_*_EL2 counterparts, and use a different PPI
- * number.
- */
- if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) {
- bool has_ppi;
+ if (is_hyp_mode_available() && is_kernel_in_hyp_mode())
+ return ARCH_TIMER_HYP_PPI;
- if (is_kernel_in_hyp_mode()) {
- arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
- has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI];
- } else {
- arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
- has_ppi = (!!arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] ||
- !!arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
- }
+ if (arch_timer_ppi[ARCH_TIMER_VIRT_PPI])
+ return ARCH_TIMER_VIRT_PPI;
- if (!has_ppi) {
- pr_warn("No interrupt available, giving up\n");
- return -EINVAL;
- }
- }
+ if (IS_ENABLED(CONFIG_ARM64))
+ return ARCH_TIMER_PHYS_NONSECURE_PPI;
+
+ return ARCH_TIMER_PHYS_SECURE_PPI;
+}
+
+static int __init arch_timer_init(void)
+{
+ int ret;
ret = arch_timer_register();
if (ret)
@@ -901,6 +903,13 @@ static int __init arch_timer_of_init(struct device_node *np)
if (IS_ENABLED(CONFIG_ARM) &&
of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
+ else
+ arch_timer_uses_ppi = arch_timer_select_ppi();
+
+ if (!arch_timer_ppi[arch_timer_uses_ppi]) {
+ pr_err("No interrupt available, giving up\n");
+ return -EINVAL;
+ }
return arch_timer_init();
}
@@ -1041,6 +1050,12 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
/* Get the frequency from CNTFRQ */
arch_timer_detect_rate(NULL, NULL);
+ arch_timer_uses_ppi = arch_timer_select_ppi();
+ if (!arch_timer_ppi[arch_timer_uses_ppi]) {
+ pr_err("No interrupt available, giving up\n");
+ return -EINVAL;
+ }
+
/* Always-on capability */
arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
--
2.9.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox