* Re: [RFC 04/11] soc: amlogic: Add support for SM1 power controller
From: Neil Armstrong @ 2019-08-20 14:55 UTC (permalink / raw)
To: Kevin Hilman, jbrunet; +Cc: linux-amlogic, linux-kernel, linux-arm-kernel
In-Reply-To: <7hftlwvhdk.fsf@baylibre.com>
On 20/08/2019 01:56, Kevin Hilman wrote:
> Neil Armstrong <narmstrong@baylibre.com> writes:
>
>> Add support for the General Purpose Amlogic SM1 Power controller,
>> dedicated to the PCIe, USB, NNA and GE2D Power Domains.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>
> I like this driver in general, but as I look at all the EE power domains
> for GX, G12 and SM1 they are really very similar. I had started to
> generalize the gx-pwrc-vpu driver and it ends up looking just like this.
Yes I developed it to be generic, but when starting to fill up the GXBB/GXL/G12A
domains, except the VPU, they only need the PD parts.
>
> I think this driver could be generalized just a little bit more and then
> replace the the GX-specific VPU one, and AFAICT, then be used across all
> the 64-bit SoCs, and be called "meson-pwrc-ee" or something like that...
>
>> ---
>> drivers/soc/amlogic/Kconfig | 11 ++
>> drivers/soc/amlogic/Makefile | 1 +
>> drivers/soc/amlogic/meson-sm1-pwrc.c | 245 +++++++++++++++++++++++++++
>> 3 files changed, 257 insertions(+)
>> create mode 100644 drivers/soc/amlogic/meson-sm1-pwrc.c
>>
>> diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
>> index 5501ad5650b2..596f1afef1a7 100644
>> --- a/drivers/soc/amlogic/Kconfig
>> +++ b/drivers/soc/amlogic/Kconfig
>> @@ -36,6 +36,17 @@ config MESON_GX_PM_DOMAINS
>> Say yes to expose Amlogic Meson GX Power Domains as
>> Generic Power Domains.
>>
>> +config MESON_SM1_PM_DOMAINS
>> + bool "Amlogic Meson SM1 Power Domains driver"
>> + depends on ARCH_MESON || COMPILE_TEST
>> + depends on PM && OF
>> + default ARCH_MESON
>> + select PM_GENERIC_DOMAINS
>> + select PM_GENERIC_DOMAINS_OF
>> + help
>> + Say yes to expose Amlogic Meson SM1 Power Domains as
>> + Generic Power Domains.
>> +
>> config MESON_MX_SOCINFO
>> bool "Amlogic Meson MX SoC Information driver"
>> depends on ARCH_MESON || COMPILE_TEST
>> diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
>> index bf2d109f61e9..f99935499ee6 100644
>> --- a/drivers/soc/amlogic/Makefile
>> +++ b/drivers/soc/amlogic/Makefile
>> @@ -3,3 +3,4 @@ obj-$(CONFIG_MESON_CLK_MEASURE) += meson-clk-measure.o
>> obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
>> obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
>> obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
>> +obj-$(CONFIG_MESON_SM1_PM_DOMAINS) += meson-sm1-pwrc.o
>> diff --git a/drivers/soc/amlogic/meson-sm1-pwrc.c b/drivers/soc/amlogic/meson-sm1-pwrc.c
>> new file mode 100644
>> index 000000000000..9ece1d06f417
>> --- /dev/null
>> +++ b/drivers/soc/amlogic/meson-sm1-pwrc.c
>> @@ -0,0 +1,245 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (c) 2017 BayLibre, SAS
>> + * Author: Neil Armstrong <narmstrong@baylibre.com>
>> + */
>> +
>> +#include <linux/of_address.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_domain.h>
>> +#include <linux/bitfield.h>
>> +#include <linux/regmap.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/of_device.h>
>> +#include <dt-bindings/power/meson-sm1-power.h>
>> +
>> +/* AO Offsets */
>> +
>> +#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
>> +#define AO_RTI_GEN_PWR_ISO0 (0x3b << 2)
>> +
>> +/* HHI Offsets */
>> +
>> +#define HHI_MEM_PD_REG0 (0x40 << 2)
>> +#define HHI_NANOQ_MEM_PD_REG0 (0x46 << 2)
>> +#define HHI_NANOQ_MEM_PD_REG1 (0x47 << 2)
>> +
>> +struct meson_sm1_pwrc;
>> +
>> +struct meson_sm1_pwrc_mem_domain {
>> + unsigned int reg;
>> + unsigned int mask;
>> +};
>> +
>> +struct meson_sm1_pwrc_domain_desc {
>> + char *name;
>> + unsigned int sleep_reg;
>> + unsigned int sleep_bit;
>> + unsigned int iso_reg;
>> + unsigned int iso_bit;
>> + unsigned int mem_pd_count;
>> + struct meson_sm1_pwrc_mem_domain *mem_pd;
>> +};
>
> If you add resets and clocks (using clk bulk like my other proposed
> patch to gx-pwrc-vpu) then this could be used for VPU also. We could
> ignore my clk bulk patch and then just deprecate the old driver and use
> this one for everything.
>
> We would just need SoC-specific tables selected by compatible-string to
> select the memory pds, and the clocks and resets could (optionaly) come
> from the DT.
Could you elaborate ?
Do you mean I should slit out the memory PDs as different compatible ?
Let me try to fit the VPU stuff in it.
Neil
>
> Kevin
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 01/11] asm-generic: add dma_zone_size
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, Arnd Bergmann
Cc: phill, f.fainelli, frowand.list, linux-kernel, eric, mbrugger,
linux-rpi-kernel, akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
Some architectures have platform specific DMA addressing limitations.
This will allow for hardware description code to provide the constraints
in a generic manner, so as for arch code to properly setup it's memory
zones and DMA mask.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2: None
include/asm-generic/dma.h | 8 +++++++-
mm/page_alloc.c | 3 +++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/include/asm-generic/dma.h b/include/asm-generic/dma.h
index 43d0c8af8058..c2f39cdb64f6 100644
--- a/include/asm-generic/dma.h
+++ b/include/asm-generic/dma.h
@@ -8,7 +8,13 @@
*
* Some code relies on seeing MAX_DMA_ADDRESS though.
*/
-#define MAX_DMA_ADDRESS PAGE_OFFSET
+#define MAX_DMA_ADDRESS (PAGE_OFFSET + dma_zone_size)
+
+/*
+ * Some architectures may have platform specific DMA addressing constraints.
+ * Firmware can use this to fine tune the device's DMA memory zone.
+ */
+extern u64 dma_zone_size __ro_after_init;
extern int request_dma(unsigned int dmanr, const char *device_id);
extern void free_dma(unsigned int dmanr);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 272c6de1bf4e..b514afee5451 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -133,6 +133,9 @@ EXPORT_SYMBOL(_totalram_pages);
unsigned long totalreserve_pages __read_mostly;
unsigned long totalcma_pages __read_mostly;
+u64 dma_zone_size __ro_after_init;
+EXPORT_SYMBOL(dma_zone_size);
+
int percpu_pagelist_fraction;
gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK;
#ifdef CONFIG_INIT_ON_ALLOC_DEFAULT_ON
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 00/11] Raspberry Pi 4 DMA addressing support
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv
Cc: phill, linux-s390, f.fainelli, frowand.list, linuxppc-dev,
linux-kernel, eric, mbrugger, linux-rpi-kernel, akpm, will,
nsaenzjulienne, m.szyprowski
Hi all,
this series attempts to address some issues we found while bringing up
the new Raspberry Pi 4 in arm64 and it's intended to serve as a follow
up of these discussions:
v1: https://lkml.org/lkml/2019/7/31/922
RFC: https://lkml.org/lkml/2019/7/17/476
The new Raspberry Pi 4 has up to 4GB of memory but most peripherals can
only address the first GB: their DMA address range is
0xc0000000-0xfc000000 which is aliased to the first GB of physical
memory 0x00000000-0x3c000000. Note that only some peripherals have these
limitations: the PCIe, V3D, GENET, and 40-bit DMA channels have a wider
view of the address space by virtue of being hooked up trough a second
interconnect.
Part of this is solved in arm32 by setting up the machine specific
'.dma_zone_size = SZ_1G', which takes care of reserving the coherent
memory area at the right spot. That said no buffer bouncing (needed for
dma streaming) is available at the moment, but that's a story for
another series.
Unfortunately there is no such thing as 'dma_zone_size' in arm64. Only
ZONE_DMA32 is created which is interpreted by dma-direct and the arm64
arch code as if all peripherals where be able to address the first 4GB
of memory.
In the light of this, the series implements the following changes:
- Create generic 'dma_zone_size' in order for hardware description code
to set it up when needed.
- Add a function in early_init_dt_scan() to setup 'dma_zone_size' for
the RPi4.
- Create both DMA zones in arm64, ZONE_DMA will contain the area
addressable by all peripherals and ZONE_DMA32 the rest of the 32 bit
addressable memory. ZONE_DMA32 might be left empty.
- Reserve the CMA area in a place suitable for all peripherals.
- Inform dma-direct of the new runtime calculated min_mask.
This series has been tested on multiple devices both by checking the
zones setup matches the expectations and by double-checking physical
addresses on pages allocated on the three relevant areas GFP_DMA,
GFP_DMA32, GFP_KERNEL:
- On an RPi4 with variations on the ram memory size. But also forcing
the situation where all three memory zones are nonempty by setting a 3G
ZONE_DMA32 ceiling on a 4G setup. Both with and without NUMA support.
- On a Synquacer box[1] with 32G of memory.
- On an ACPI based Huawei TaiShan server[2] with 256G of memory.
- On a QEMU virtual machine running arm64's OpenSUSE Tumbleweed.
That's all.
Regards,
Nicolas
[1] https://www.96boards.org/product/developerbox/
[2] https://e.huawei.com/en/products/cloud-computing-dc/servers/taishan-server/taishan-2280-v2
---
Changes in v2:
- More in depth testing.
- Create new global 'dma_zone_size'.
- New approach to getting the dma_zone_size, instead of parsing the dts
we hardcode it conditionally to the machine compatible name.
- Fix ZONE_DMA and ZONE_DMA32 split, now ZONE_DMA32 remains empty if
ZONE_DMA fits the whole 32 bit addressable space.
- Take into account devices with DMA offset.
- Rename new dma-direct variable to zone_dma_bits.
- Try new approach by merging both ZONE_DMA and ZONE_DMA32 comments
in mmzone.h, add new up to date examples.
Nicolas Saenz Julienne (11):
asm-generic: add dma_zone_size
arm: use generic dma_zone_size
of/fdt: add of_fdt_machine_is_compatible function
of/fdt: add early_init_dt_get_dma_zone_size()
arm64: mm: use arm64_dma_phys_limit instead of calling
max_zone_dma_phys()
arm64: rename variables used to calculate ZONE_DMA32's size
arm64: re-introduce max_zone_dma_phys()
arm64: use both ZONE_DMA and ZONE_DMA32
dma-direct: turn ARCH_ZONE_DMA_BITS into a variable
arm64: edit zone_dma_bits to fine tune dma-direct min mask
mm: refresh ZONE_DMA and ZONE_DMA32 comments in 'enum zone_type'
arch/arm/include/asm/dma.h | 8 ++--
arch/arm/mm/init.c | 12 ++----
arch/arm64/Kconfig | 4 ++
arch/arm64/mm/init.c | 73 +++++++++++++++++++++++++--------
arch/powerpc/include/asm/page.h | 9 ----
arch/powerpc/mm/mem.c | 16 +++++---
arch/s390/include/asm/page.h | 2 -
arch/s390/mm/init.c | 1 +
drivers/of/fdt.c | 15 +++++++
include/asm-generic/dma.h | 8 +++-
include/linux/dma-direct.h | 2 +
include/linux/mmzone.h | 46 ++++++++++++---------
kernel/dma/direct.c | 13 +++---
mm/page_alloc.c | 3 ++
14 files changed, 140 insertions(+), 72 deletions(-)
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 02/11] arm: use generic dma_zone_size
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, linux-kernel
Cc: phill, f.fainelli, frowand.list, Russell King, eric, mbrugger,
linux-rpi-kernel, akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
'dma_zone_size' was created as a generic replacement to
'arm_dma_zone_size'. Use it accordingly.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2: None
arch/arm/include/asm/dma.h | 8 +++++---
arch/arm/mm/init.c | 12 ++++--------
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
index a81dda65c576..52d19ffd92b4 100644
--- a/arch/arm/include/asm/dma.h
+++ b/arch/arm/include/asm/dma.h
@@ -2,16 +2,18 @@
#ifndef __ASM_ARM_DMA_H
#define __ASM_ARM_DMA_H
+#include <asm-generic/dma.h>
+
/*
* This is the maximum virtual address which can be DMA'd from.
*/
+#undef MAX_DMA_ADDRESS
#ifndef CONFIG_ZONE_DMA
#define MAX_DMA_ADDRESS 0xffffffffUL
#else
#define MAX_DMA_ADDRESS ({ \
- extern phys_addr_t arm_dma_zone_size; \
- arm_dma_zone_size && arm_dma_zone_size < (0x10000000 - PAGE_OFFSET) ? \
- (PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; })
+ dma_zone_size && dma_zone_size < (0x10000000 - PAGE_OFFSET) ? \
+ (PAGE_OFFSET + dma_zone_size) : 0xffffffffUL; })
#endif
#ifdef CONFIG_ISA_DMA_API
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 16d373d587c4..95680bad245a 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -79,10 +79,6 @@ static void __init find_limits(unsigned long *min, unsigned long *max_low,
}
#ifdef CONFIG_ZONE_DMA
-
-phys_addr_t arm_dma_zone_size __read_mostly;
-EXPORT_SYMBOL(arm_dma_zone_size);
-
/*
* The DMA mask corresponding to the maximum bus address allocatable
* using GFP_DMA. The default here places no restriction on DMA
@@ -109,8 +105,8 @@ void __init setup_dma_zone(const struct machine_desc *mdesc)
{
#ifdef CONFIG_ZONE_DMA
if (mdesc->dma_zone_size) {
- arm_dma_zone_size = mdesc->dma_zone_size;
- arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1;
+ dma_zone_size = mdesc->dma_zone_size;
+ arm_dma_limit = PHYS_OFFSET + dma_zone_size - 1;
} else
arm_dma_limit = 0xffffffff;
arm_dma_pfn_limit = arm_dma_limit >> PAGE_SHIFT;
@@ -164,9 +160,9 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max_low,
* Adjust the sizes according to any special requirements for
* this machine type.
*/
- if (arm_dma_zone_size)
+ if (dma_zone_size)
arm_adjust_dma_zone(zone_size, zhole_size,
- arm_dma_zone_size >> PAGE_SHIFT);
+ dma_zone_size >> PAGE_SHIFT);
#endif
free_area_init_node(0, zone_size, min, zhole_size);
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 03/11] of/fdt: add of_fdt_machine_is_compatible function
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, Frank Rowand
Cc: phill, f.fainelli, linux-kernel, eric, mbrugger, linux-rpi-kernel,
akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
Provides the same functionality as of_machine_is_compatible.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2: None
drivers/of/fdt.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 9cdf14b9aaab..06ffbd39d9af 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -802,6 +802,13 @@ const char * __init of_flat_dt_get_machine_name(void)
return name;
}
+static const int __init of_fdt_machine_is_compatible(char *name)
+{
+ unsigned long dt_root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(dt_root, name);
+}
+
/**
* of_flat_dt_match_machine - Iterate match tables to find matching machine.
*
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 04/11] of/fdt: add early_init_dt_get_dma_zone_size()
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, Frank Rowand
Cc: phill, f.fainelli, linux-kernel, eric, mbrugger, linux-rpi-kernel,
akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
Some devices might have weird DMA addressing limitations that only apply
to a subset of the available peripherals. For example the Raspberry Pi 4
has two interconnects, one able to address the whole lower 4G memory
area and another one limited to the lower 1G.
Being an uncommon situation we simply hardcode the device wide DMA
addressable memory size conditionally to the machine compatible name and
set 'dma_zone_size' accordingly.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2:
- New approach to getting dma_zone_size, instead of parsing the dts we
hardcode it conditionally to the machine compatible name.
drivers/of/fdt.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 06ffbd39d9af..f756e8c05a77 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -27,6 +27,7 @@
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#include <asm/page.h>
+#include <asm/dma.h> /* for dma_zone_size */
#include "of_private.h"
@@ -1195,6 +1196,12 @@ void __init early_init_dt_scan_nodes(void)
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
}
+void __init early_init_dt_get_dma_zone_size(void)
+{
+ if (of_fdt_machine_is_compatible("brcm,bcm2711"))
+ dma_zone_size = 0x3c000000;
+}
+
bool __init early_init_dt_scan(void *params)
{
bool status;
@@ -1204,6 +1211,7 @@ bool __init early_init_dt_scan(void *params)
return false;
early_init_dt_scan_nodes();
+ early_init_dt_get_dma_zone_size();
return true;
}
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 05/11] arm64: mm: use arm64_dma_phys_limit instead of calling max_zone_dma_phys()
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, linux-kernel
Cc: phill, f.fainelli, frowand.list, eric, mbrugger, linux-rpi-kernel,
akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
By the time we call zones_sizes_init() arm64_dma_phys_limit already
contains the result of max_zone_dma_phys(). We use the variable instead
of calling the function directly to save some precious cpu time.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2: None
arch/arm64/mm/init.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index f3c795278def..6112d6c90fa8 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -181,7 +181,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};
#ifdef CONFIG_ZONE_DMA32
- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys());
+ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit);
#endif
max_zone_pfns[ZONE_NORMAL] = max;
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 06/11] arm64: rename variables used to calculate ZONE_DMA32's size
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, linux-kernel
Cc: phill, f.fainelli, frowand.list, eric, mbrugger, linux-rpi-kernel,
akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
Let the name indicate that they are used to calculate ZONE_DMA32's size
as opposed to ZONE_DMA.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2: None
arch/arm64/mm/init.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 6112d6c90fa8..8956c22634dd 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -50,7 +50,7 @@
s64 memstart_addr __ro_after_init = -1;
EXPORT_SYMBOL(memstart_addr);
-phys_addr_t arm64_dma_phys_limit __ro_after_init;
+phys_addr_t arm64_dma32_phys_limit __ro_after_init;
#ifdef CONFIG_KEXEC_CORE
/*
@@ -168,7 +168,7 @@ static void __init reserve_elfcorehdr(void)
* currently assumes that for memory starting above 4G, 32-bit devices will
* use a DMA offset.
*/
-static phys_addr_t __init max_zone_dma_phys(void)
+static phys_addr_t __init max_zone_dma32_phys(void)
{
phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
return min(offset + (1ULL << 32), memblock_end_of_DRAM());
@@ -181,7 +181,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};
#ifdef CONFIG_ZONE_DMA32
- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit);
+ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit);
#endif
max_zone_pfns[ZONE_NORMAL] = max;
@@ -194,16 +194,16 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
struct memblock_region *reg;
unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
- unsigned long max_dma = min;
+ unsigned long max_dma32 = min;
memset(zone_size, 0, sizeof(zone_size));
/* 4GB maximum for 32-bit only capable devices */
#ifdef CONFIG_ZONE_DMA32
- max_dma = PFN_DOWN(arm64_dma_phys_limit);
- zone_size[ZONE_DMA32] = max_dma - min;
+ max_dma32 = PFN_DOWN(arm64_dma32_phys_limit);
+ zone_size[ZONE_DMA32] = max_dma32 - min;
#endif
- zone_size[ZONE_NORMAL] = max - max_dma;
+ zone_size[ZONE_NORMAL] = max - max_dma32;
memcpy(zhole_size, zone_size, sizeof(zhole_size));
@@ -215,14 +215,14 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
continue;
#ifdef CONFIG_ZONE_DMA32
- if (start < max_dma) {
- unsigned long dma_end = min(end, max_dma);
+ if (start < max_dma32) {
+ unsigned long dma_end = min(end, max_dma32);
zhole_size[ZONE_DMA32] -= dma_end - start;
}
#endif
- if (end > max_dma) {
+ if (end > max_dma32) {
unsigned long normal_end = min(end, max);
- unsigned long normal_start = max(start, max_dma);
+ unsigned long normal_start = max(start, max_dma32);
zhole_size[ZONE_NORMAL] -= normal_end - normal_start;
}
}
@@ -407,9 +407,9 @@ void __init arm64_memblock_init(void)
/* 4GB maximum for 32-bit only capable devices */
if (IS_ENABLED(CONFIG_ZONE_DMA32))
- arm64_dma_phys_limit = max_zone_dma_phys();
+ arm64_dma32_phys_limit = max_zone_dma32_phys();
else
- arm64_dma_phys_limit = PHYS_MASK + 1;
+ arm64_dma32_phys_limit = PHYS_MASK + 1;
reserve_crashkernel();
@@ -417,7 +417,7 @@ void __init arm64_memblock_init(void)
high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
- dma_contiguous_reserve(arm64_dma_phys_limit);
+ dma_contiguous_reserve(arm64_dma32_phys_limit);
}
void __init bootmem_init(void)
@@ -521,7 +521,7 @@ static void __init free_unused_memmap(void)
void __init mem_init(void)
{
if (swiotlb_force == SWIOTLB_FORCE ||
- max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT))
+ max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT))
swiotlb_init(1);
else
swiotlb_force = SWIOTLB_NO_FORCE;
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 07/11] arm64: re-introduce max_zone_dma_phys()
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, linux-kernel
Cc: phill, f.fainelli, frowand.list, eric, mbrugger, linux-rpi-kernel,
akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
Some devices might have multiple interconnects with different DMA
addressing limitations. This function provides the higher physical
address accessible by all peripherals on the SoC. If such limitation
doesn't exist it'll return the maximum physical address of the 32 bit
addressable area.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2:
- Update function's behavior to fit new dma zones split
- Use dma_zone_size
- Take into account devices with a hardcoded DMA offset
arch/arm64/mm/init.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 8956c22634dd..bc7999020c71 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -174,6 +174,17 @@ static phys_addr_t __init max_zone_dma32_phys(void)
return min(offset + (1ULL << 32), memblock_end_of_DRAM());
}
+static phys_addr_t __init max_zone_dma_phys(void)
+
+{
+ phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
+
+ if (dma_zone_size)
+ return min(offset + dma_zone_size, memblock_end_of_DRAM());
+ else
+ return max_zone_dma32_phys();
+}
+
#ifdef CONFIG_NUMA
static void __init zone_sizes_init(unsigned long min, unsigned long max)
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 08/11] arm64: use both ZONE_DMA and ZONE_DMA32
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, Will Deacon
Cc: phill, f.fainelli, linux-kernel, eric, mbrugger, linux-rpi-kernel,
akpm, frowand.list, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
So far all arm64 devices have supported 32 bit DMA masks for their
peripherals. This is not true anymore for the Raspberry Pi 4 as most of
it's peripherals can only address the first GB or memory of a total of
up to 4 GB.
This goes against ZONE_DMA32's original intent, and breaks other
subsystems as it's expected for ZONE_DMA32 to be addressable with a 32
bit mask. So it was decided to use ZONE_DMA for this specific case.
ZONE_DMA will contain the memory addressable by all the SoC's
peripherals and ZONE_DMA32 the rest of the 32 bit addressable memory. If
all peripherals where able to address the whole 32 bit addressable space
ZONE_DMA32 will be left empty.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2:
- ZONE_DMA will never be left empty
- Update comment to reflect new zones split
arch/arm64/Kconfig | 4 ++++
arch/arm64/mm/init.c | 39 +++++++++++++++++++++++++++++++--------
2 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3adcec05b1f6..a9fd71d3bc8e 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -266,6 +266,10 @@ config GENERIC_CSUM
config GENERIC_CALIBRATE_DELAY
def_bool y
+config ZONE_DMA
+ bool "Support DMA zone" if EXPERT
+ default y
+
config ZONE_DMA32
bool "Support DMA32 zone" if EXPERT
default y
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index bc7999020c71..c51ce79b692b 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -50,6 +50,14 @@
s64 memstart_addr __ro_after_init = -1;
EXPORT_SYMBOL(memstart_addr);
+/*
+ * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA's size is decided based on
+ * whether all the device's peripherals are able to address the first naturally
+ * aligned 4G of memory. If not, ZONE_DMA covers the area common to all them
+ * and ZONE_DMA32 the rest. If ZONE_DMA fits the whole 4G area, ZONE_DMA32 is
+ * left empty.
+ */
+phys_addr_t arm64_dma_phys_limit __ro_after_init;
phys_addr_t arm64_dma32_phys_limit __ro_after_init;
#ifdef CONFIG_KEXEC_CORE
@@ -191,6 +199,9 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};
+#ifdef CONFIG_ZONE_DMA
+ max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit);
+#endif
#ifdef CONFIG_ZONE_DMA32
max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit);
#endif
@@ -206,13 +217,17 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
struct memblock_region *reg;
unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
unsigned long max_dma32 = min;
+ unsigned long max_dma = min;
memset(zone_size, 0, sizeof(zone_size));
- /* 4GB maximum for 32-bit only capable devices */
+#ifdef CONFIG_ZONE_DMA
+ max_dma = PFN_DOWN(arm64_dma_phys_limit);
+ zone_size[ZONE_DMA] = max_dma - min;
+#endif
#ifdef CONFIG_ZONE_DMA32
max_dma32 = PFN_DOWN(arm64_dma32_phys_limit);
- zone_size[ZONE_DMA32] = max_dma32 - min;
+ zone_size[ZONE_DMA32] = max_dma32 - max_dma;
#endif
zone_size[ZONE_NORMAL] = max - max_dma32;
@@ -224,11 +239,17 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
if (start >= max)
continue;
-
+#ifdef CONFIG_ZONE_DMA
+ if (start < max_dma) {
+ unsigned long dma_end = min_not_zero(end, max_dma);
+ zhole_size[ZONE_DMA] -= dma_end - start;
+ }
+#endif
#ifdef CONFIG_ZONE_DMA32
if (start < max_dma32) {
- unsigned long dma_end = min(end, max_dma32);
- zhole_size[ZONE_DMA32] -= dma_end - start;
+ unsigned long dma32_end = min(end, max_dma32);
+ unsigned long dma32_start = max(start, max_dma);
+ zhole_size[ZONE_DMA32] -= dma32_end - dma32_start;
}
#endif
if (end > max_dma32) {
@@ -416,7 +437,9 @@ void __init arm64_memblock_init(void)
early_init_fdt_scan_reserved_mem();
- /* 4GB maximum for 32-bit only capable devices */
+ if (IS_ENABLED(CONFIG_ZONE_DMA))
+ arm64_dma_phys_limit = max_zone_dma_phys();
+
if (IS_ENABLED(CONFIG_ZONE_DMA32))
arm64_dma32_phys_limit = max_zone_dma32_phys();
else
@@ -428,7 +451,7 @@ void __init arm64_memblock_init(void)
high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
- dma_contiguous_reserve(arm64_dma32_phys_limit);
+ dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit);
}
void __init bootmem_init(void)
@@ -531,7 +554,7 @@ static void __init free_unused_memmap(void)
*/
void __init mem_init(void)
{
- if (swiotlb_force == SWIOTLB_FORCE ||
+ if (swiotlb_force == SWIOTLB_FORCE || arm64_dma_phys_limit ||
max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT))
swiotlb_init(1);
else
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 09/11] dma-direct: turn ARCH_ZONE_DMA_BITS into a variable
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, Marek Szyprowski
Cc: phill, linux-s390, f.fainelli, Vasily Gorbik,
Christian Borntraeger, Michael Ellerman, frowand.list,
linuxppc-dev, Heiko Carstens, linux-kernel, eric, mbrugger,
Paul Mackerras, linux-rpi-kernel, Benjamin Herrenschmidt, akpm,
will, nsaenzjulienne
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
Some architectures, notably arm64, are interested in tweaking this
depending on their runtime dma addressing limitations.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2:
- Rename new variable to zone_dma_bits
- Update comment with Christoph's suggestion
- Remove old powerpc comment
arch/powerpc/include/asm/page.h | 9 ---------
arch/powerpc/mm/mem.c | 16 +++++++++++-----
arch/s390/include/asm/page.h | 2 --
arch/s390/mm/init.c | 1 +
include/linux/dma-direct.h | 2 ++
kernel/dma/direct.c | 13 ++++++-------
6 files changed, 20 insertions(+), 23 deletions(-)
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 0d52f57fca04..73668a21ae78 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -319,13 +319,4 @@ struct vm_area_struct;
#endif /* __ASSEMBLY__ */
#include <asm/slice.h>
-/*
- * Allow 30-bit DMA for very limited Broadcom wifi chips on many powerbooks.
- */
-#ifdef CONFIG_PPC32
-#define ARCH_ZONE_DMA_BITS 30
-#else
-#define ARCH_ZONE_DMA_BITS 31
-#endif
-
#endif /* _ASM_POWERPC_PAGE_H */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 9191a66b3bc5..2a69f87585df 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -31,6 +31,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/memremap.h>
+#include <linux/dma-direct.h>
#include <asm/pgalloc.h>
#include <asm/prom.h>
@@ -201,10 +202,10 @@ static int __init mark_nonram_nosave(void)
* everything else. GFP_DMA32 page allocations automatically fall back to
* ZONE_DMA.
*
- * By using 31-bit unconditionally, we can exploit ARCH_ZONE_DMA_BITS to
- * inform the generic DMA mapping code. 32-bit only devices (if not handled
- * by an IOMMU anyway) will take a first dip into ZONE_NORMAL and get
- * otherwise served by ZONE_DMA.
+ * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the
+ * generic DMA mapping code. 32-bit only devices (if not handled by an IOMMU
+ * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by
+ * ZONE_DMA.
*/
static unsigned long max_zone_pfns[MAX_NR_ZONES];
@@ -237,9 +238,14 @@ void __init paging_init(void)
printk(KERN_DEBUG "Memory hole size: %ldMB\n",
(long int)((top_of_ram - total_ram) >> 20));
+ if (IS_ENABLED(CONFIG_PPC32))
+ zone_dma_bits = 30;
+ else
+ zone_dma_bits = 31;
+
#ifdef CONFIG_ZONE_DMA
max_zone_pfns[ZONE_DMA] = min(max_low_pfn,
- 1UL << (ARCH_ZONE_DMA_BITS - PAGE_SHIFT));
+ 1UL << (zone_dma_bits - PAGE_SHIFT));
#endif
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
#ifdef CONFIG_HIGHMEM
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 823578c6b9e2..a4d38092530a 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -177,8 +177,6 @@ static inline int devmem_is_allowed(unsigned long pfn)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-#define ARCH_ZONE_DMA_BITS 31
-
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 20340a03ad90..bd98465b8b9f 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -118,6 +118,7 @@ void __init paging_init(void)
sparse_memory_present_with_active_regions(MAX_NUMNODES);
sparse_init();
+ zone_dma_bits = 31;
memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
diff --git a/include/linux/dma-direct.h b/include/linux/dma-direct.h
index adf993a3bd58..d03af3605460 100644
--- a/include/linux/dma-direct.h
+++ b/include/linux/dma-direct.h
@@ -5,6 +5,8 @@
#include <linux/dma-mapping.h>
#include <linux/mem_encrypt.h>
+extern unsigned int zone_dma_bits;
+
#ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA
#include <asm/dma-direct.h>
#else
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 795c9b095d75..b23cd65f26e0 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -16,12 +16,11 @@
#include <linux/swiotlb.h>
/*
- * Most architectures use ZONE_DMA for the first 16 Megabytes, but
- * some use it for entirely different regions:
+ * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use it
+ * it for entirely different regions. In that case the arch code needs to
+ * override the variable below for dma-direct to work properly.
*/
-#ifndef ARCH_ZONE_DMA_BITS
-#define ARCH_ZONE_DMA_BITS 24
-#endif
+unsigned int zone_dma_bits __ro_after_init = 24;
static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size)
{
@@ -69,7 +68,7 @@ static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
* Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding
* zones.
*/
- if (*phys_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
+ if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits))
return GFP_DMA;
if (*phys_mask <= DMA_BIT_MASK(32))
return GFP_DMA32;
@@ -387,7 +386,7 @@ int dma_direct_supported(struct device *dev, u64 mask)
u64 min_mask;
if (IS_ENABLED(CONFIG_ZONE_DMA))
- min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS);
+ min_mask = DMA_BIT_MASK(zone_dma_bits);
else
min_mask = DMA_BIT_MASK(32);
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 10/11] arm64: edit zone_dma_bits to fine tune dma-direct min mask
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, linux-kernel
Cc: phill, f.fainelli, frowand.list, eric, mbrugger, linux-rpi-kernel,
akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
With the introduction of ZONE_DMA in arm64 devices are not forced to
support 32 bit DMA masks. We have to inform dma-direct of this
limitation whenever it happens.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2:
- Make sure to filter the higher part of arm64_dma_phys_limit
- Rename variable to zone_dma_bits
arch/arm64/mm/init.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index c51ce79b692b..c5e619f21ad8 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -22,6 +22,7 @@
#include <linux/of_fdt.h>
#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
+#include <linux/dma-direct.h>
#include <linux/efi.h>
#include <linux/swiotlb.h>
#include <linux/vmalloc.h>
@@ -437,8 +438,10 @@ void __init arm64_memblock_init(void)
early_init_fdt_scan_reserved_mem();
- if (IS_ENABLED(CONFIG_ZONE_DMA))
+ if (IS_ENABLED(CONFIG_ZONE_DMA)) {
arm64_dma_phys_limit = max_zone_dma_phys();
+ zone_dma_bits = ilog2((arm64_dma_phys_limit - 1) & GENMASK_ULL(31, 0)) + 1;
+ }
if (IS_ENABLED(CONFIG_ZONE_DMA32))
arm64_dma32_phys_limit = max_zone_dma32_phys();
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 11/11] mm: refresh ZONE_DMA and ZONE_DMA32 comments in 'enum zone_type'
From: Nicolas Saenz Julienne @ 2019-08-20 14:58 UTC (permalink / raw)
To: catalin.marinas, hch, wahrenst, marc.zyngier, robh+dt,
Robin Murphy, linux-arm-kernel, devicetree, linux-arch, iommu,
linux-mm, linux-riscv, Paul Walmsley, Palmer Dabbelt, Albert Ou
Cc: phill, f.fainelli, frowand.list, linux-kernel, eric, mbrugger,
linux-rpi-kernel, akpm, will, nsaenzjulienne, m.szyprowski
In-Reply-To: <20190820145821.27214-1-nsaenzjulienne@suse.de>
These zones usage has evolved with time and the comments were outdated.
This joins both ZONE_DMA and ZONE_DMA32 explanation and gives up to date
examples on how they are used on different architectures.
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
Changes in v2:
- Try another approach merging both zones explanations into one
- Address Christoph's comments
- If this approach doesn't get much traction I'll just drop the patch
from the series as it's not really essential
include/linux/mmzone.h | 46 +++++++++++++++++++++++++-----------------
1 file changed, 27 insertions(+), 19 deletions(-)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index d77d717c620c..9c150223d41f 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -356,33 +356,41 @@ struct per_cpu_nodestat {
#endif /* !__GENERATING_BOUNDS.H */
enum zone_type {
-#ifdef CONFIG_ZONE_DMA
/*
- * ZONE_DMA is used when there are devices that are not able
- * to do DMA to all of addressable memory (ZONE_NORMAL). Then we
- * carve out the portion of memory that is needed for these devices.
- * The range is arch specific.
+ * ZONE_DMA and ZONE_DMA32 are used when there are peripherals not able
+ * to DMA to all of the addressable memory (ZONE_NORMAL).
+ * On architectures where this area covers the whole 32 bit address
+ * space ZONE_DMA32 is used. ZONE_DMA is left for the ones with smaller
+ * DMA addressing constraints. This distinction is important as a 32bit
+ * DMA mask is assumed when ZONE_DMA32 is defined. Some 64-bit
+ * platforms may need both zones as they support peripherals with
+ * different DMA addressing limitations.
+ *
+ * Some examples:
+ *
+ * - i386 and x86_64 have a fixed 16M ZONE_DMA and ZONE_DMA32 for the
+ * rest of the lower 4G.
+ *
+ * - arm only uses ZONE_DMA, the size, up to 4G, may vary depending on
+ * the specific device.
+ *
+ * - powerpc only uses ZONE_DMA, the size, up to 2G, may vary
+ * depending on the specific device.
*
- * Some examples
+ * - s390 uses ZONE_DMA fixed to the lower 2G.
*
- * Architecture Limit
- * ---------------------------
- * parisc, ia64, sparc <4G
- * s390, powerpc <2G
- * arm Various
- * alpha Unlimited or 0-16MB.
+ * - arm64 uses ZONE_DMA to mark the area addresable by all
+ * peripherals on the device, and ZONE_DMA32 for the rest of the
+ * lower 4G. ZONE_DMA32 might be left empty.
*
- * i386, x86_64 and multiple other arches
- * <16M.
+ * - ia64 and riscv only use ZONE_DMA32.
+ *
+ * - parisc uses neither.
*/
+#ifdef CONFIG_ZONE_DMA
ZONE_DMA,
#endif
#ifdef CONFIG_ZONE_DMA32
- /*
- * x86_64 needs two ZONE_DMAs because it supports devices that are
- * only able to do DMA to the lower 16M but also 32 bit devices that
- * can only do DMA areas below 4G.
- */
ZONE_DMA32,
#endif
/*
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [RESEND PATCHv4 0/1] drivers/amba: add reset control to amba
From: Dinh Nguyen @ 2019-08-20 14:58 UTC (permalink / raw)
To: linux-kernel
Cc: robh, daniel.thompson, tony.luck, manivannan.sadhasivam, keescook,
devicetree, linus.walleij, anton, linux, dinguyen, ccross,
frowand.list, linux-arm-kernel
Hello,
Even though this patch is a V4, I'm including more people in this review
cycle because I found that there was previous patch[1] that was discussed.
Thanks,
Dinh
[1] https://patchwork.kernel.org/patch/10845695/
Dinh Nguyen (1):
drivers/amba: add reset control to amba bus probe
drivers/amba/bus.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
--
2.20.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [RESEND PATCHv4 1/1] drivers/amba: add reset control to amba bus probe
From: Dinh Nguyen @ 2019-08-20 14:58 UTC (permalink / raw)
To: linux-kernel
Cc: robh, daniel.thompson, tony.luck, manivannan.sadhasivam, keescook,
devicetree, linus.walleij, anton, linux, dinguyen, ccross,
frowand.list, linux-arm-kernel
In-Reply-To: <20190820145834.7301-1-dinguyen@kernel.org>
The primecell controller on some SoCs, i.e. SoCFPGA, is held in reset by
default. Until recently, the DMA controller was brought out of reset by the
bootloader(i.e. U-Boot). But a recent change in U-Boot, the peripherals
that are not used are held in reset and are left to Linux to bring them
out of reset.
Add a mechanism for getting the reset property and de-assert the primecell
module from reset if found. This is a not a hard fail if the reset properti
is not present in the device tree node, so the driver will continue to
probe.
Because there are different variants of the controller that may have
multiple reset signals, the code will find all reset(s) specified and
de-assert them.
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
Reviewed-by: Rob Herring <robh@kernel.org>
---
v4: cleaned up indentation in loop
fix up a few checkpatch warnings
add Reviewed-by:
v3: add a reset_control_put()
add error handling
v2: move reset control to bus code
find all reset properties and de-assert them
---
drivers/amba/bus.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 100e798a5c82..76a1cd56a1ab 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -18,6 +18,7 @@
#include <linux/limits.h>
#include <linux/clk/clk-conf.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <asm/irq.h>
@@ -401,6 +402,26 @@ static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
ret = amba_get_enable_pclk(dev);
if (ret == 0) {
u32 pid, cid;
+ int count;
+ struct reset_control *rstc;
+
+ /*
+ * Find reset control(s) of the amba bus and de-assert them.
+ */
+ count = reset_control_get_count(&dev->dev);
+ while (count > 0) {
+ rstc = of_reset_control_get_shared_by_index(dev->dev.of_node, count - 1);
+ if (IS_ERR(rstc)) {
+ if (PTR_ERR(rstc) == -EPROBE_DEFER)
+ ret = -EPROBE_DEFER;
+ else
+ dev_err(&dev->dev, "Can't get amba reset!\n");
+ break;
+ }
+ reset_control_deassert(rstc);
+ reset_control_put(rstc);
+ count--;
+ }
/*
* Read pid and cid based on size of resource
--
2.20.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [v5,05/12] drm/modes: Rewrite the command line parser
From: Maxime Ripard @ 2019-08-20 15:00 UTC (permalink / raw)
To: Thomas Graichen
Cc: eben, David Airlie, Maarten Lankhorst, Jernej Škrabec,
Paul Kocialkowski, Sean Paul, dri-devel, Thomas Petazzoni,
Daniel Vetter, linux-arm-kernel
In-Reply-To: <CAOUEw13CCVhk9kt_z2VkguX0=TCeARkH-8+qSh_nF-J+r0Rscg@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 2431 bytes --]
Hi,
On Mon, Aug 19, 2019 at 09:20:00PM +0200, Thomas Graichen wrote:
> On Mon, Aug 19, 2019 at 8:54 PM Jernej Škrabec <jernej.skrabec@gmail.com> wrote:
> >
> > +CC: Thomas Graichen
> >
> > Dne ponedeljek, 17. junij 2019 ob 16:51:32 CEST je Maxime Ripard napisal(a):
> > > From: Maxime Ripard <maxime.ripard@free-electrons.com>
> > >
> > > Rewrite the command line parser in order to get away from the state machine
> > > parsing the video mode lines.
> > >
> > > Hopefully, this will allow to extend it more easily to support named modes
> > > and / or properties set directly on the command line.
> > >
> > > Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> >
> > Thomas reported to me that this patch breaks "video=CONNECTOR:e" kernel
> > parameter which he currently uses as a workaround for H6 HDMI monitor
> > detection issue on one STB.
> >
> > I suppose this is the same issue that Dmitry noticed.
> >
> > Thomas Graichen (in CC) can provide more information if needed.
>
> as jernej already mentioned i am currently having to use the kernel
> cmdline option video=HDMI-A-1:e to get a working hdmi output on an
> eachlink h6 mini tv box and was wondering that i did not get any hdmi
> output even with this option when switching from the
> https://github.com/megous/linux oprange-pi-5.2 to the orange-pi-5.3
> branch which seems to contain this patch.
Which kernel version is that based on?
> as i had no idea what might have caused the breakage of the hdmi
> output and did a full bisect of the kernel between those two
> versions, which ended reliably at exactly this patch - so i guess
> there is a regression at least with the video=CONNECTOR:e option
> (maybe others too?) with this patches code which makes it not
> working anymore.
I'm not sure I'll have the time to look into it this week (or the
next, unfortunately). However, the e parameter is supposed to be
parsed by drm_mode_parse_cmdline_extra, which in turn is supposed to
be called there:
https://elixir.bootlin.com/linux/v5.3-rc5/source/drivers/gpu/drm/drm_modes.c#L1810
If you can test that, having an idea of if that function is called,
which return code it returns, and if it isn't if why would be super
helpful.
Thanks!
Maxime
--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/3] serial: atmel: Don't check for mctrl_gpio_to_gpiod() returning error
From: Richard Genoud @ 2019-08-20 15:11 UTC (permalink / raw)
To: Geert Uytterhoeven, Uwe Kleine-König
Cc: Alexandre Belloni, Pengutronix Kernel Team, Geert Uytterhoeven,
open list:SERIAL DRIVERS, Richard Genoud, Greg Kroah-Hartman,
Sascha Hauer, Frieder Schrempf, Linux-Renesas, Ludovic Desroches,
NXP Linux Team, Fabio Estevam, Jiri Slaby, Shawn Guo, Linux ARM
In-Reply-To: <CAMuHMdWNj-H9B8E9=NeCgLracBuJODfPyBYJERh=vt4oNFUkGw@mail.gmail.com>
Hi,
Le 14/08/2019 à 12:20, Geert Uytterhoeven a écrit :
> Hi Uwe,
>
> On Wed, Aug 14, 2019 at 11:36 AM Uwe Kleine-König
> <u.kleine-koenig@pengutronix.de> wrote:
>> On Wed, Aug 14, 2019 at 11:29:22AM +0200, Geert Uytterhoeven wrote:
>>> Since commit 1d267ea6539f2663 ("serial: mctrl-gpio: simplify init
>>> routine"), mctrl_gpio_init() returns failure if the assignment to any
>>> member of the gpio array results in an error pointer.
>>> Since commit c359522194593815 ("serial: mctrl_gpio: Avoid probe failures
>>> in case of missing gpiolib"), mctrl_gpio_to_gpiod() returns NULL in the
>>> !CONFIG_GPIOLIB case.
>>> Hence there is no longer a need to check for mctrl_gpio_to_gpiod()
>>> returning an error value. A simple NULL check is sufficient.
>>>
>>> This follows the spirit of commit 445df7ff3fd1a0a9 ("serial: mctrl-gpio:
>>> drop usages of IS_ERR_OR_NULL") in the mctrl-gpio core.
>>>
>>> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
>>> ---
>>> drivers/tty/serial/atmel_serial.c | 12 ++++--------
>>> 1 file changed, 4 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
>>> index 19a85d6fe3d20541..e9620a81166b7dc1 100644
>>> --- a/drivers/tty/serial/atmel_serial.c
>>> +++ b/drivers/tty/serial/atmel_serial.c
>>> @@ -303,32 +303,28 @@ static unsigned int atmel_get_lines_status(struct uart_port *port)
>>>
>>> mctrl_gpio_get(atmel_port->gpios, &ret);
>>>
>>> - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
>>> - UART_GPIO_CTS))) {
>>> + if (mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
>>> if (ret & TIOCM_CTS)
>>> status &= ~ATMEL_US_CTS;
>>> else
>>> status |= ATMEL_US_CTS;
>>> }
>>
>> The change is fine, but it seems the atmel driver doesn't use mctrl_gpio
>> as expected (at least as expected by me). IMHO driving the hardware
>> function of the CTS pin shouldn't be conditional on the presence of a
>> cts-gpio. Is there a reason not to just drop the if completely?
>
> The above code returns the hardware status if CTS is not a GPIO, and
> returns (overrides with) the GPIO status if CTS is a GPIO.
> Isn't that correct, or am I missing something?
Yes, that's correct.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 1/3] dt-bindings: Add compatible for H6 RTC
From: megous @ 2019-08-20 15:19 UTC (permalink / raw)
To: Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
Maxime Ripard, Chen-Yu Tsai
Cc: Ondrej Jirman, linux-rtc, devicetree, linux-kernel, linux-sunxi,
linux-arm-kernel
In-Reply-To: <20190820151934.3860-1-megous@megous.com>
From: Ondrej Jirman <megous@megous.com>
RTC on H6 is similar to the one on H5 SoC, but incompatible in small
details. See the driver for description of differences. For example
H6 RTC needs to enable the external low speed oscillator. Add new
compatible for this RTC.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../bindings/rtc/allwinner,sun6i-a31-rtc.yaml | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
index 924622f39c44..d7a57ec4a640 100644
--- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
@@ -25,6 +25,7 @@ properties:
- items:
- const: allwinner,sun50i-a64-rtc
- const: allwinner,sun8i-h3-rtc
+ - const: allwinner,sun50i-h6-rtc
reg:
maxItems: 1
@@ -92,6 +93,18 @@ allOf:
minItems: 3
maxItems: 3
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: allwinner,sun50i-h6-rtc
+
+ then:
+ properties:
+ clock-output-names:
+ minItems: 3
+ maxItems: 3
+
- if:
properties:
compatible:
--
2.22.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 0/3] Add basic support for RTC on Allwinner H6 SoC
From: megous @ 2019-08-20 15:19 UTC (permalink / raw)
To: Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
Maxime Ripard, Chen-Yu Tsai
Cc: Ondrej Jirman, linux-rtc, devicetree, linux-kernel, linux-sunxi,
linux-arm-kernel
From: Ondrej Jirman <megous@megous.com>
I went through the datasheets for H6 and H5, and compared the differences.
RTCs are largely similar, but not entirely compatible. Incompatibilities
are in details not yet implemented by the rtc driver though.
I also corrected the clock tree in H6 DTSI.
This patchset is necessary for implementing the WiFi/Bluetooth support
on boards using H6 SoC.
There was some discussion previously of describing HOSC, DCXO and XO
oscillators and clocks as part of RTC in DT, but I decided against it
because it's not necessary, becuse information that would be provided
as a part of DT can already be determined at runtime from RTC registers,
so this woudn't add any value and would only introduce complications
to the driver. See: https://patchwork.kernel.org/cover/10898083/
Please take a look.
Thank you and regards,
Ondrej Jirman
Changes in v2:
- bindings converted to yaml
- added reviewed by tags
Ondrej Jirman (3):
dt-bindings: Add compatible for H6 RTC
rtc: sun6i: Add support for H6 RTC
arm64: dts: sun50i-h6: Add support for RTC and fix the clock tree
.../bindings/rtc/allwinner,sun6i-a31-rtc.yaml | 13 ++++++
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 30 +++++++-------
drivers/rtc/rtc-sun6i.c | 40 ++++++++++++++++++-
3 files changed, 67 insertions(+), 16 deletions(-)
--
2.22.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v2 2/3] rtc: sun6i: Add support for H6 RTC
From: megous @ 2019-08-20 15:19 UTC (permalink / raw)
To: Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
Maxime Ripard, Chen-Yu Tsai
Cc: Ondrej Jirman, linux-rtc, devicetree, linux-kernel, linux-sunxi,
linux-arm-kernel
In-Reply-To: <20190820151934.3860-1-megous@megous.com>
From: Ondrej Jirman <megous@megous.com>
RTC on H6 is mostly the same as on H5 and H3. It has slight differences
mostly in features that are not yet supported by this driver.
Some differences are already stated in the comments in existing code.
One other difference is that H6 has extra bit in LOSC_CTRL_REG, called
EXT_LOSC_EN to enable/disable external low speed crystal oscillator.
It also has bit EXT_LOSC_STA in LOSC_AUTO_SWT_STA_REG, to check whether
external low speed oscillator is working correctly.
This patch adds support for enabling LOSC when necessary:
- during reparenting
- when probing the clock
H6 also has capacbility to automatically reparent RTC clock from
external crystal oscillator, to internal RC oscillator, if external
oscillator fails. This is enabled by default. Disable it during
probe.
Signed-off-by: Ondrej Jirman <megous@megous.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/rtc/rtc-sun6i.c | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index d50ee023b559..b0c3752bed3f 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -32,9 +32,11 @@
/* Control register */
#define SUN6I_LOSC_CTRL 0x0000
#define SUN6I_LOSC_CTRL_KEY (0x16aa << 16)
+#define SUN6I_LOSC_CTRL_AUTO_SWT_BYPASS BIT(15)
#define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9)
#define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8)
#define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7)
+#define SUN6I_LOSC_CTRL_EXT_LOSC_EN BIT(4)
#define SUN6I_LOSC_CTRL_EXT_OSC BIT(0)
#define SUN6I_LOSC_CTRL_ACC_MASK GENMASK(9, 7)
@@ -128,6 +130,8 @@ struct sun6i_rtc_clk_data {
unsigned int has_prescaler : 1;
unsigned int has_out_clk : 1;
unsigned int export_iosc : 1;
+ unsigned int has_losc_en : 1;
+ unsigned int has_auto_swt : 1;
};
struct sun6i_rtc_dev {
@@ -190,6 +194,10 @@ static int sun6i_rtc_osc_set_parent(struct clk_hw *hw, u8 index)
val &= ~SUN6I_LOSC_CTRL_EXT_OSC;
val |= SUN6I_LOSC_CTRL_KEY;
val |= index ? SUN6I_LOSC_CTRL_EXT_OSC : 0;
+ if (rtc->data->has_losc_en) {
+ val &= ~SUN6I_LOSC_CTRL_EXT_LOSC_EN;
+ val |= index ? SUN6I_LOSC_CTRL_EXT_LOSC_EN : 0;
+ }
writel(val, rtc->base + SUN6I_LOSC_CTRL);
spin_unlock_irqrestore(&rtc->lock, flags);
@@ -215,6 +223,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
const char *iosc_name = "rtc-int-osc";
const char *clkout_name = "osc32k-out";
const char *parents[2];
+ u32 reg;
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
if (!rtc)
@@ -235,9 +244,18 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
goto err;
}
+ reg = SUN6I_LOSC_CTRL_KEY;
+ if (rtc->data->has_auto_swt) {
+ /* Bypass auto-switch to int osc, on ext losc failure */
+ reg |= SUN6I_LOSC_CTRL_AUTO_SWT_BYPASS;
+ writel(reg, rtc->base + SUN6I_LOSC_CTRL);
+ }
+
/* Switch to the external, more precise, oscillator */
- writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC,
- rtc->base + SUN6I_LOSC_CTRL);
+ reg |= SUN6I_LOSC_CTRL_EXT_OSC;
+ if (rtc->data->has_losc_en)
+ reg |= SUN6I_LOSC_CTRL_EXT_LOSC_EN;
+ writel(reg, rtc->base + SUN6I_LOSC_CTRL);
/* Yes, I know, this is ugly. */
sun6i_rtc = rtc;
@@ -345,6 +363,23 @@ CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc",
CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc",
sun8i_h3_rtc_clk_init);
+static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = {
+ .rc_osc_rate = 16000000,
+ .fixed_prescaler = 32,
+ .has_prescaler = 1,
+ .has_out_clk = 1,
+ .export_iosc = 1,
+ .has_losc_en = 1,
+ .has_auto_swt = 1,
+};
+
+static void __init sun50i_h6_rtc_clk_init(struct device_node *node)
+{
+ sun6i_rtc_clk_init(node, &sun50i_h6_rtc_data);
+}
+CLK_OF_DECLARE_DRIVER(sun50i_h6_rtc_clk, "allwinner,sun50i-h6-rtc",
+ sun50i_h6_rtc_clk_init);
+
static const struct sun6i_rtc_clk_data sun8i_v3_rtc_data = {
.rc_osc_rate = 32000,
.has_out_clk = 1,
@@ -675,6 +710,7 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = {
{ .compatible = "allwinner,sun8i-r40-rtc" },
{ .compatible = "allwinner,sun8i-v3-rtc" },
{ .compatible = "allwinner,sun50i-h5-rtc" },
+ { .compatible = "allwinner,sun50i-h6-rtc" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
--
2.22.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 3/3] arm64: dts: sun50i-h6: Add support for RTC and fix the clock tree
From: megous @ 2019-08-20 15:19 UTC (permalink / raw)
To: Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
Maxime Ripard, Chen-Yu Tsai
Cc: Ondrej Jirman, linux-rtc, devicetree, linux-kernel, linux-sunxi,
linux-arm-kernel
In-Reply-To: <20190820151934.3860-1-megous@megous.com>
From: Ondrej Jirman <megous@megous.com>
This patch adds RTC node and fixes the clock properties and nodes
to reflect the real clock tree.
The device nodes for the internal oscillator and osc32k are removed,
as these clocks are now provided by the RTC device. Clock references
are fixed accordingly, too.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 30 +++++++++++---------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 67b732e34091..67f920e0fc33 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -56,14 +56,6 @@
status = "disabled";
};
- iosc: internal-osc-clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <16000000>;
- clock-accuracy = <300000000>;
- clock-output-names = "iosc";
- };
-
osc24M: osc24M_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -71,11 +63,11 @@
clock-output-names = "osc24M";
};
- osc32k: osc32k_clk {
+ ext_osc32k: ext_osc32k_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <32768>;
- clock-output-names = "osc32k";
+ clock-output-names = "ext_osc32k";
};
psci {
@@ -197,7 +189,7 @@
ccu: clock@3001000 {
compatible = "allwinner,sun50i-h6-ccu";
reg = <0x03001000 0x1000>;
- clocks = <&osc24M>, <&osc32k>, <&iosc>;
+ clocks = <&osc24M>, <&rtc 0>, <&rtc 2>;
clock-names = "hosc", "losc", "iosc";
#clock-cells = <1>;
#reset-cells = <1>;
@@ -236,7 +228,7 @@
<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ccu CLK_APB1>, <&osc24M>, <&osc32k>;
+ clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc 0>;
clock-names = "apb", "hosc", "losc";
gpio-controller;
#gpio-cells = <3>;
@@ -710,10 +702,20 @@
};
};
+ rtc: rtc@7000000 {
+ compatible = "allwinner,sun50i-h6-rtc";
+ reg = <0x07000000 0x400>;
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ clock-output-names = "osc32k", "osc32k-out", "iosc";
+ clocks = <&ext_osc32k>;
+ #clock-cells = <1>;
+ };
+
r_ccu: clock@7010000 {
compatible = "allwinner,sun50i-h6-r-ccu";
reg = <0x07010000 0x400>;
- clocks = <&osc24M>, <&osc32k>, <&iosc>,
+ clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
<&ccu CLK_PLL_PERIPH0>;
clock-names = "hosc", "losc", "iosc", "pll-periph";
#clock-cells = <1>;
@@ -741,7 +743,7 @@
reg = <0x07022000 0x400>;
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&osc32k>;
+ clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>;
clock-names = "apb", "hosc", "losc";
gpio-controller;
#gpio-cells = <3>;
--
2.22.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v3 2/5] arm64: cpufeature: Add feature to detect heterogeneous systems
From: Mark Rutland @ 2019-08-20 15:23 UTC (permalink / raw)
To: Raphael Gault
Cc: raph.gault+kdev, peterz, catalin.marinas, will.deacon,
linux-kernel, acme, mingo, linux-arm-kernel
In-Reply-To: <20190816125934.18509-3-raphael.gault@arm.com>
Hi Raphael,
On Fri, Aug 16, 2019 at 01:59:31PM +0100, Raphael Gault wrote:
> This feature is required in order to enable PMU counters direct
> access from userspace only when the system is homogeneous.
> This feature checks the model of each CPU brought online and compares it
> to the boot CPU. If it differs then it is heterogeneous.
I t would be worth noting that this patch prevents heterogeneous CPUs
being brought online late if the system was uniform at boot time.
>
> Signed-off-by: Raphael Gault <raphael.gault@arm.com>
> ---
> arch/arm64/include/asm/cpucaps.h | 3 ++-
> arch/arm64/kernel/cpufeature.c | 20 ++++++++++++++++++++
> arch/arm64/kernel/perf_event.c | 1 +
> 3 files changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
> index f19fe4b9acc4..040370af38ad 100644
> --- a/arch/arm64/include/asm/cpucaps.h
> +++ b/arch/arm64/include/asm/cpucaps.h
> @@ -52,7 +52,8 @@
> #define ARM64_HAS_IRQ_PRIO_MASKING 42
> #define ARM64_HAS_DCPODP 43
> #define ARM64_WORKAROUND_1463225 44
> +#define ARM64_HAS_HETEROGENEOUS_PMU 45
>
> -#define ARM64_NCAPS 45
> +#define ARM64_NCAPS 46
>
> #endif /* __ASM_CPUCAPS_H */
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 9323bcc40a58..bbdd809f12a6 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -1260,6 +1260,15 @@ static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
> }
> #endif
>
> +static bool has_heterogeneous_pmu(const struct arm64_cpu_capabilities *entry,
> + int scope)
> +{
> + u32 model = read_cpuid_id() & MIDR_CPU_MODEL_MASK;
> + struct cpuinfo_arm64 *boot = &per_cpu(cpu_data, 0);
> +
> + return (boot->reg_midr & MIDR_CPU_MODEL_MASK) != model;
> +}
We should use boot_cpu_data rather than &per_cpu(cpu_data, 0) here. We
can make that __ro_after_init, and declare it in
arch/arm64/includ/asm/smp.h.
That caters for CPU0 being hotplugged off and then a different physical
CPU being hotplugged on in its place.
> +
> static const struct arm64_cpu_capabilities arm64_features[] = {
> {
> .desc = "GIC system register CPU interface",
> @@ -1560,6 +1569,16 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
> .min_field_value = 1,
> },
> #endif
> + {
> + /*
> + * Detect whether the system is heterogeneous or
> + * homogeneous
> + */
> + .desc = "Detect whether we have heterogeneous CPUs",
The desc gets printed in dmesg with a prefix, e.g.
[ 0.058267][ T1] CPU features: detected: Privileged Access Never
[ 0.058340][ T1] CPU features: detected: LSE atomic instructions
[ 0.058416][ T1] CPU features: detected: RAS Extension Support
[ 0.058489][ T1] CPU features: detected: CRC32 instructions
... so this should only say "Heterogeneous CPUs".
> + .capability = ARM64_HAS_HETEROGENEOUS_PMU,
> + .type = ARM64_CPUCAP_SCOPE_LOCAL_CPU | ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU,
> + .matches = has_heterogeneous_pmu,
> + },
> {},
> };
>
> @@ -1727,6 +1746,7 @@ static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
> cap_set_elf_hwcap(hwcaps);
> }
>
> +
This whitespace addition can go.
> static void update_cpu_capabilities(u16 scope_mask)
> {
> int i;
> diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
> index 2d3bdebdf6df..a0b4f1bca491 100644
> --- a/arch/arm64/kernel/perf_event.c
> +++ b/arch/arm64/kernel/perf_event.c
> @@ -19,6 +19,7 @@
> #include <linux/of.h>
> #include <linux/perf/arm_pmu.h>
> #include <linux/platform_device.h>
> +#include <linux/smp.h>
I think this should be added in a separate patch.
It looks like this is a missing include that we need today for
smp_processor_id(), so please spin that as a preparatory patch (with my
Acked-by).
Thanks,
Mark.
>
> /* ARMv8 Cortex-A53 specific event types. */
> #define ARMV8_A53_PERFCTR_PREF_LINEFILL 0xC2
> --
> 2.17.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v3 0/2] PM / devfreq: Add dev_pm_qos support
From: Leonard Crestez @ 2019-08-20 15:23 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Artur Świgoń
Cc: Jacky Bai, Saravana Kannan, linux-pm, Viresh Kumar,
Krzysztof Kozlowski, Alexandre Bailon, Georgi Djakov,
linux-arm-kernel
Add dev_pm_qos notifies to devfreq core in order to support frequency
limits via the dev_pm_qos_add_request.
Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
this is consistent with current dev_pm_qos usage for cpufreq and
allows frequencies above 2Ghz (pm_qos expresses limits as s32).
Like with cpufreq the handling of min_freq/max_freq is moved to the dev_pm_qos
mechanism and this decreases the precision of the sysfs entries.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
Changes since v2:
* Handle sysfs via dev_pm_qos (in separate patch)
* Add locking to {min,max}_freq_show
* Fix checkpatch issues (long lines etc)
Link to v2: https://patchwork.kernel.org/patch/11084279/
Changes since v1:
* Add doxygen comments for min_nb/max_nb
* Remove notifiers on error/cleanup paths. Keep gotos simple by relying on
dev_pm_qos_remove_notifier ignoring notifiers which were not added.
Link to v1: https://patchwork.kernel.org/patch/11078475/
Leonard Crestez (2):
PM / devfreq: Add dev_pm_qos support
PM / devfreq: Use dev_pm_qos for sysfs min/max_freq
drivers/devfreq/devfreq.c | 170 +++++++++++++++++++++++++++-----------
include/linux/devfreq.h | 14 +++-
2 files changed, 131 insertions(+), 53 deletions(-)
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v3 2/2] PM / devfreq: Use dev_pm_qos for sysfs min/max_freq
From: Leonard Crestez @ 2019-08-20 15:24 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Artur Świgoń
Cc: Jacky Bai, Saravana Kannan, linux-pm, Viresh Kumar,
Krzysztof Kozlowski, Alexandre Bailon, Georgi Djakov,
linux-arm-kernel
In-Reply-To: <cover.1566314535.git.leonard.crestez@nxp.com>
Now that devfreq supports dev_pm_qos requests we can use them to handle
the min/max_freq values set by userspace in sysfs, similar to cpufreq.
Since dev_pm_qos handles frequencies as kHz this change reduces the
precision of min_freq and max_freq. This shouldn't introduce problems
because frequencies which are not an integer number of kHz are likely
not an integer number of Hz either.
Try to ensure compatibilitity by rounding min values down and rounding
max values up.
Simplify the {min,max}_freq_store code by setting "null" values of 0 and
MAX_S32 respectively instead of clamping to what freq tables are
actually supported. Values are already automatically clamped on
readback.
Also simplify by droping the limitation that userspace min_freq must be
lower than userspace max_freq, it is already documented that max_freq
takes precedence.
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
drivers/devfreq/devfreq.c | 79 ++++++++++++++++-----------------------
include/linux/devfreq.h | 9 +++--
2 files changed, 38 insertions(+), 50 deletions(-)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 58deffa52a37..687deadd08ed 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -101,21 +101,21 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
static unsigned long get_effective_min_freq(struct devfreq *devfreq)
{
lockdep_assert_held(&devfreq->lock);
- return max3(devfreq->scaling_min_freq, devfreq->min_freq,
+ return max(devfreq->scaling_min_freq,
1000 * (unsigned long)dev_pm_qos_read_value(
devfreq->dev.parent,
DEV_PM_QOS_MIN_FREQUENCY));
}
static unsigned long get_effective_max_freq(struct devfreq *devfreq)
{
lockdep_assert_held(&devfreq->lock);
- return min3(devfreq->scaling_max_freq, devfreq->max_freq,
+ return min(devfreq->scaling_max_freq,
1000 * (unsigned long)dev_pm_qos_read_value(
devfreq->dev.parent,
DEV_PM_QOS_MAX_FREQUENCY));
}
@@ -644,10 +644,12 @@ static void devfreq_dev_release(struct device *dev)
dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
DEV_PM_QOS_MAX_FREQUENCY);
dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
DEV_PM_QOS_MIN_FREQUENCY);
+ dev_pm_qos_remove_request(&devfreq->max_freq_req);
+ dev_pm_qos_remove_request(&devfreq->min_freq_req);
mutex_destroy(&devfreq->lock);
kfree(devfreq);
}
/**
@@ -698,10 +700,19 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq->previous_freq = profile->initial_freq;
devfreq->last_status.current_frequency = profile->initial_freq;
devfreq->data = data;
devfreq->nb.notifier_call = devfreq_notifier_call;
+ err = dev_pm_qos_add_request(dev, &devfreq->min_freq_req,
+ DEV_PM_QOS_MIN_FREQUENCY, 0);
+ if (err < 0)
+ goto err_dev;
+ err = dev_pm_qos_add_request(dev, &devfreq->max_freq_req,
+ DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
+ if (err < 0)
+ goto err_dev;
+
/*
* notifier from pm_qos
*
* initialized outside of devfreq->lock to avoid circular warning
* between devfreq->lock and dev_pm_qos_mtx
@@ -732,19 +743,17 @@ struct devfreq *devfreq_add_device(struct device *dev,
if (!devfreq->scaling_min_freq) {
mutex_unlock(&devfreq->lock);
err = -EINVAL;
goto err_dev;
}
- devfreq->min_freq = devfreq->scaling_min_freq;
devfreq->scaling_max_freq = find_available_max_freq(devfreq);
if (!devfreq->scaling_max_freq) {
mutex_unlock(&devfreq->lock);
err = -EINVAL;
goto err_dev;
}
- devfreq->max_freq = devfreq->scaling_max_freq;
devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
atomic_set(&devfreq->suspend_count, 0);
dev_set_name(&devfreq->dev, "devfreq%d",
@@ -816,10 +825,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
err_dev:
dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
DEV_PM_QOS_MAX_FREQUENCY);
dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
DEV_PM_QOS_MIN_FREQUENCY);
+ if (dev_pm_qos_request_active(&devfreq->max_freq_req))
+ dev_pm_qos_remove_request(&devfreq->max_freq_req);
+ if (dev_pm_qos_request_active(&devfreq->min_freq_req))
+ dev_pm_qos_remove_request(&devfreq->min_freq_req);
kfree(devfreq);
err_out:
return ERR_PTR(err);
}
EXPORT_SYMBOL(devfreq_add_device);
@@ -1358,33 +1371,20 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
ret = sscanf(buf, "%lu", &value);
if (ret != 1)
return -EINVAL;
- mutex_lock(&df->lock);
-
- if (value) {
- if (value > df->max_freq) {
- ret = -EINVAL;
- goto unlock;
- }
- } else {
- unsigned long *freq_table = df->profile->freq_table;
+ if (value)
+ value = value / 1000;
+ else
+ value = 0;
- /* Get minimum frequency according to sorting order */
- if (freq_table[0] < freq_table[df->profile->max_state - 1])
- value = freq_table[0];
- else
- value = freq_table[df->profile->max_state - 1];
- }
+ ret = dev_pm_qos_update_request(&df->min_freq_req, value);
+ if (ret < 0)
+ return ret;
- df->min_freq = value;
- update_devfreq(df);
- ret = count;
-unlock:
- mutex_unlock(&df->lock);
- return ret;
+ return count;
}
static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1407,33 +1407,20 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
ret = sscanf(buf, "%lu", &value);
if (ret != 1)
return -EINVAL;
- mutex_lock(&df->lock);
-
- if (value) {
- if (value < df->min_freq) {
- ret = -EINVAL;
- goto unlock;
- }
- } else {
- unsigned long *freq_table = df->profile->freq_table;
+ if (value)
+ value = DIV_ROUND_UP(value, 1000);
+ else
+ value = S32_MAX;
- /* Get maximum frequency according to sorting order */
- if (freq_table[0] < freq_table[df->profile->max_state - 1])
- value = freq_table[df->profile->max_state - 1];
- else
- value = freq_table[0];
- }
+ ret = dev_pm_qos_update_request(&df->max_freq_req, value);
+ if (ret < 0)
+ return ret;
- df->max_freq = value;
- update_devfreq(df);
- ret = count;
-unlock:
- mutex_unlock(&df->lock);
- return ret;
+ return count;
}
static DEVICE_ATTR_RW(min_freq);
static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 8b92ccbd1962..d2c5bb7add0a 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -11,10 +11,11 @@
#define __LINUX_DEVFREQ_H__
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
#define DEVFREQ_NAME_LEN 16
/* DEVFREQ governor name */
#define DEVFREQ_GOV_SIMPLE_ONDEMAND "simple_ondemand"
@@ -121,12 +122,12 @@ struct devfreq_dev_profile {
* devfreq.nb to the corresponding register notifier call chain.
* @work: delayed work for load monitoring.
* @previous_freq: previously configured frequency value.
* @data: Private data of the governor. The devfreq framework does not
* touch this.
- * @min_freq: Limit minimum frequency requested by user (0: none)
- * @max_freq: Limit maximum frequency requested by user (0: none)
+ * @min_freq_req: Limit minimum frequency requested by user (0: none)
+ * @max_freq_req: Limit maximum frequency requested by user (0: none)
* @scaling_min_freq: Limit minimum frequency requested by OPP interface
* @scaling_max_freq: Limit maximum frequency requested by OPP interface
* @stop_polling: devfreq polling status of a device.
* @suspend_freq: frequency of a device set during suspend phase.
* @resume_freq: frequency of a device set in resume phase.
@@ -161,12 +162,12 @@ struct devfreq {
unsigned long previous_freq;
struct devfreq_dev_status last_status;
void *data; /* private data for governors */
- unsigned long min_freq;
- unsigned long max_freq;
+ struct dev_pm_qos_request min_freq_req;
+ struct dev_pm_qos_request max_freq_req;
unsigned long scaling_min_freq;
unsigned long scaling_max_freq;
bool stop_polling;
unsigned long suspend_freq;
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 1/2] PM / devfreq: Add dev_pm_qos support
From: Leonard Crestez @ 2019-08-20 15:24 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Artur Świgoń
Cc: Jacky Bai, Saravana Kannan, linux-pm, Viresh Kumar,
Krzysztof Kozlowski, Alexandre Bailon, Georgi Djakov,
linux-arm-kernel
In-Reply-To: <cover.1566314535.git.leonard.crestez@nxp.com>
Add dev_pm_qos notifies to devfreq core in order to support frequency
limits via the dev_pm_qos_add_request.
Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
this is consistent with current dev_pm_qos usage for cpufreq and
allows frequencies above 2Ghz (pm_qos expresses limits as s32).
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
---
drivers/devfreq/devfreq.c | 95 ++++++++++++++++++++++++++++++++++++---
include/linux/devfreq.h | 5 +++
2 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 784c08e4f931..58deffa52a37 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -22,10 +22,11 @@
#include <linux/platform_device.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/hrtimer.h>
#include <linux/of.h>
+#include <linux/pm_qos.h>
#include "governor.h"
#define CREATE_TRACE_POINTS
#include <trace/events/devfreq.h>
@@ -96,10 +97,30 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
dev_pm_opp_put(opp);
return max_freq;
}
+static unsigned long get_effective_min_freq(struct devfreq *devfreq)
+{
+ lockdep_assert_held(&devfreq->lock);
+
+ return max3(devfreq->scaling_min_freq, devfreq->min_freq,
+ 1000 * (unsigned long)dev_pm_qos_read_value(
+ devfreq->dev.parent,
+ DEV_PM_QOS_MIN_FREQUENCY));
+}
+
+static unsigned long get_effective_max_freq(struct devfreq *devfreq)
+{
+ lockdep_assert_held(&devfreq->lock);
+
+ return min3(devfreq->scaling_max_freq, devfreq->max_freq,
+ 1000 * (unsigned long)dev_pm_qos_read_value(
+ devfreq->dev.parent,
+ DEV_PM_QOS_MAX_FREQUENCY));
+}
+
/**
* devfreq_get_freq_level() - Lookup freq_table for the frequency
* @devfreq: the devfreq instance
* @freq: the target frequency
*/
@@ -356,12 +377,12 @@ int update_devfreq(struct devfreq *devfreq)
*
* List from the highest priority
* max_freq
* min_freq
*/
- max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
- min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
+ max_freq = get_effective_max_freq(devfreq);
+ min_freq = get_effective_min_freq(devfreq);
if (freq < min_freq) {
freq = min_freq;
flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
}
@@ -570,10 +591,37 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
mutex_unlock(&devfreq->lock);
return ret;
}
+static int devfreq_qos_notifier_call(struct devfreq *devfreq)
+{
+ int ret;
+
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+
+ return ret;
+}
+
+static int devfreq_qos_min_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ struct devfreq *devfreq = container_of(nb, struct devfreq, nb_min);
+
+ return devfreq_qos_notifier_call(devfreq);
+}
+
+static int devfreq_qos_max_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ struct devfreq *devfreq = container_of(nb, struct devfreq, nb_max);
+
+ return devfreq_qos_notifier_call(devfreq);
+}
+
/**
* devfreq_dev_release() - Callback for struct device to release the device.
* @dev: the devfreq device
*
* Remove devfreq from the list and release its resources.
@@ -592,10 +640,14 @@ static void devfreq_dev_release(struct device *dev)
mutex_unlock(&devfreq_list_lock);
if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent);
+ dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
+ DEV_PM_QOS_MAX_FREQUENCY);
+ dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
mutex_destroy(&devfreq->lock);
kfree(devfreq);
}
/**
@@ -636,21 +688,40 @@ struct devfreq *devfreq_add_device(struct device *dev,
err = -ENOMEM;
goto err_out;
}
mutex_init(&devfreq->lock);
- mutex_lock(&devfreq->lock);
devfreq->dev.parent = dev;
devfreq->dev.class = devfreq_class;
devfreq->dev.release = devfreq_dev_release;
devfreq->profile = profile;
strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
devfreq->previous_freq = profile->initial_freq;
devfreq->last_status.current_frequency = profile->initial_freq;
devfreq->data = data;
devfreq->nb.notifier_call = devfreq_notifier_call;
+ /*
+ * notifier from pm_qos
+ *
+ * initialized outside of devfreq->lock to avoid circular warning
+ * between devfreq->lock and dev_pm_qos_mtx
+ */
+ devfreq->nb_min.notifier_call = devfreq_qos_min_notifier_call;
+ devfreq->nb_max.notifier_call = devfreq_qos_max_notifier_call;
+
+ err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
+ if (err)
+ goto err_dev;
+
+ err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
+ DEV_PM_QOS_MAX_FREQUENCY);
+ if (err)
+ goto err_dev;
+
+ mutex_lock(&devfreq->lock);
if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
mutex_unlock(&devfreq->lock);
err = set_freq_table(devfreq);
if (err < 0)
goto err_dev;
@@ -741,10 +812,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
mutex_unlock(&devfreq_list_lock);
err_devfreq:
devfreq_remove_device(devfreq);
devfreq = NULL;
err_dev:
+ dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
+ DEV_PM_QOS_MAX_FREQUENCY);
+ dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
kfree(devfreq);
err_out:
return ERR_PTR(err);
}
EXPORT_SYMBOL(devfreq_add_device);
@@ -1312,12 +1387,17 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct devfreq *df = to_devfreq(dev);
+ ssize_t ret;
+
+ mutex_lock(&df->lock);
+ ret = sprintf(buf, "%lu\n", get_effective_min_freq(df));
+ mutex_unlock(&df->lock);
- return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
+ return ret;
}
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -1357,12 +1437,17 @@ static DEVICE_ATTR_RW(min_freq);
static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct devfreq *df = to_devfreq(dev);
+ ssize_t ret;
- return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
+ mutex_lock(&df->lock);
+ ret = sprintf(buf, "%lu\n", get_effective_max_freq(df));
+ mutex_unlock(&df->lock);
+
+ return ret;
}
static DEVICE_ATTR_RW(max_freq);
static ssize_t available_frequencies_show(struct device *d,
struct device_attribute *attr,
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 2bae9ed3c783..8b92ccbd1962 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -134,10 +134,12 @@ struct devfreq_dev_profile {
* @total_trans: Number of devfreq transitions
* @trans_table: Statistics of devfreq transitions
* @time_in_state: Statistics of devfreq states
* @last_stat_updated: The last time stat updated
* @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
+ * @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY
+ * @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY
*
* This structure stores the devfreq information for a give device.
*
* Note that when a governor accesses entries in struct devfreq in its
* functions except for the context of callbacks defined in struct
@@ -176,10 +178,13 @@ struct devfreq {
unsigned int *trans_table;
unsigned long *time_in_state;
unsigned long last_stat_updated;
struct srcu_notifier_head transition_notifier_list;
+
+ struct notifier_block nb_min;
+ struct notifier_block nb_max;
};
struct devfreq_freqs {
unsigned long old;
unsigned long new;
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ 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