* [PATCH v15 12/13] clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped timer
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-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 | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 653374c..350d0b9 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1053,7 +1053,28 @@ 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(void)
+{
+ struct arch_timer_mem *timer_mem;
+ int ret = 0;
+ int i = 0;
+
+ timer_mem = kzalloc(sizeof(*timer_mem), GFP_KERNEL);
+ if (!timer_mem)
+ return -ENOMEM;
+
+ while (!gtdt_arch_timer_mem_init(timer_mem, i)) {
+ ret = arch_timer_mem_init(timer_mem);
+ if (ret)
+ break;
+ i++;
+ }
+
+ 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;
@@ -1090,6 +1111,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
/* Get the frequency from CNTFRQ */
arch_timer_detect_rate(NULL, NULL);
+ if (arch_timer_mem_acpi_init())
+ pr_err("Failed to initialize memory-mapped timer.\n");
+
ret = arch_timer_init();
error:
--
2.7.4
^ permalink raw reply related
* [PATCH v15 11/13] acpi/arm64: Add memory-mapped timer support in GTDT driver
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-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 | 95 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 1 +
2 files changed, 96 insertions(+)
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
index 2de79aa..08d9506 100644
--- a/drivers/acpi/arm64/gtdt.c
+++ b/drivers/acpi/arm64/gtdt.c
@@ -51,6 +51,14 @@ static inline bool is_timer_block(void *platform_timer)
return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK;
}
+static inline struct acpi_gtdt_timer_block *get_timer_block(unsigned int index)
+{
+ if (index >= acpi_gtdt_desc.timer_block_count || !timer_block)
+ return NULL;
+
+ return timer_block[index];
+}
+
static inline bool is_watchdog(void *platform_timer)
{
struct acpi_gtdt_header *gh = platform_timer;
@@ -214,3 +222,90 @@ int __init acpi_gtdt_init(struct acpi_table_header *table)
acpi_gtdt_release();
return -EINVAL;
}
+
+/*
+ * Get ONE GT block info for memory-mapped timer from GTDT table.
+ * @data: the GT block data (parsing result)
+ * @index: the index number of GT block
+ * Note: we already verify @data in caller, it can't be NULL here.
+ * Returns 0 if success, -EINVAL/-ENODEV if error.
+ */
+int __init gtdt_arch_timer_mem_init(struct arch_timer_mem *data,
+ unsigned int index)
+{
+ struct acpi_gtdt_timer_block *block;
+ struct acpi_gtdt_timer_entry *frame;
+ int i;
+
+ block = get_timer_block(index);
+ if (!block)
+ return -ENODEV;
+
+ 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;
+ /*
+ * We can NOT get the size info from GTDT table,
+ * but according to "Table * CNTCTLBase memory map" of
+ * <ARM Architecture Reference Manual> for ARMv8,
+ * it should be 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;
+ }
+
+ if (frame->virtual_timer_interrupt) {
+ 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);
+ return -EINVAL;
+ }
+ }
+
+ data->frame[i].frame_nr = frame->frame_number;
+ data->frame[i].cntbase = frame->base_address;
+ /*
+ * We can NOT get the size info from GTDT table,
+ * but according to "Table * CNTBaseN memory map" of
+ * <ARM Architecture Reference Manual> for ARMv8,
+ * it should be 4KB(Offset 0x000 ? 0xFFC).
+ */
+ data->frame[i].size = SZ_4K;
+ }
+
+ if (acpi_gtdt_desc.timer_block_count)
+ pr_info("parsed No.%d of %d memory-mapped timer block(s).\n",
+ index, acpi_gtdt_desc.timer_block_count);
+
+ return 0;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index a1611d1..44b8c1b 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -582,6 +582,7 @@ int acpi_gtdt_init(struct acpi_table_header *table);
int acpi_gtdt_map_ppi(int type);
bool acpi_gtdt_c3stop(int type);
void acpi_gtdt_release(void);
+int gtdt_arch_timer_mem_init(struct arch_timer_mem *data, unsigned int index);
#endif
#else /* !CONFIG_ACPI */
--
2.7.4
^ permalink raw reply related
* [PATCH v15 10/13] clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-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>
---
drivers/clocksource/arm_arch_timer.c | 55 +++++++++++++-----------------------
1 file changed, 19 insertions(+), 36 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index a44e44d..653374c 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1052,66 +1052,49 @@ 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);
+ 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);
-
- /* Get the frequency from CNTFRQ */
- arch_timer_detect_rate(NULL, NULL);
+ acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI);
ret = arch_timer_uses_ppi_init();
if (ret)
- return ret;
+ goto error;
/* 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);
- arch_timer_init();
- return 0;
+ /* Get the frequency from CNTFRQ */
+ arch_timer_detect_rate(NULL, NULL);
+
+ ret = arch_timer_init();
+
+error:
+ acpi_gtdt_release();
+ return ret;
}
CLOCKSOURCE_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
#endif
--
2.7.4
^ permalink raw reply related
* [PATCH v15 09/13] acpi/arm64: Add GTDT table parse driver
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
This patch adds support for parsing arch timer 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>
---
arch/arm64/Kconfig | 1 +
drivers/acpi/arm64/Kconfig | 3 +
drivers/acpi/arm64/Makefile | 1 +
drivers/acpi/arm64/gtdt.c | 216 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 7 ++
5 files changed, 228 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..2de79aa
--- /dev/null
+++ b/drivers/acpi/arm64/gtdt.c
@@ -0,0 +1,216 @@
+/*
+ * 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 {
+ struct acpi_table_gtdt *gtdt;
+ void *gtdt_end;
+ unsigned int timer_block_count;
+ unsigned int watchdog_count;
+};
+
+static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
+static struct acpi_gtdt_timer_block **timer_block __initdata;
+static struct acpi_gtdt_watchdog **watchdog __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; _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 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;
+
+ 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);
+}
+
+/*
+ * Map the PPIs of per-cpu arch_timer.
+ * @type: the type of PPI
+ * Returns 0 if error.
+ * 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.
+ */
+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
+ * @type: the type of PPI
+ * Returns 1 if the timer is powered 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;
+}
+
+/*
+ * Release the memory we have allocated in acpi_gtdt_init.
+ * This should be called, when the driver who called "acpi_gtdt_init" previously
+ * doesn't need the GTDT info anymore.
+ */
+void __init acpi_gtdt_release(void)
+{
+ kfree(timer_block);
+ kfree(watchdog);
+ timer_block = NULL;
+ watchdog = NULL;
+}
+
+/*
+ * Get some basic info from GTDT table, and init the global variables above
+ * for all timers initialization of Generic Timer.
+ * This function does some validation on GTDT table.
+ */
+int __init acpi_gtdt_init(struct acpi_table_header *table)
+{
+ int timer_count;
+ void *platform_timer;
+ struct acpi_table_gtdt *gtdt;
+
+ gtdt = container_of(table, struct acpi_table_gtdt, header);
+
+ if (table->revision < 2) {
+ pr_debug("Revision:%d doesn't support Platform Timers.\n",
+ table->revision);
+ timer_count = 0;
+ } else if (!gtdt->platform_timer_count) {
+ pr_debug("No Platform Timer.\n");
+ timer_count = 0;
+ } else {
+ timer_count = gtdt->platform_timer_count;
+ }
+
+ acpi_gtdt_desc.gtdt = gtdt;
+ acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
+
+ if (!timer_count)
+ return 0;
+
+ platform_timer = (void *)gtdt + gtdt->platform_timer_offset;
+ if (platform_timer < (void *)table + sizeof(struct acpi_table_gtdt)) {
+ pr_err(FW_BUG "Failed to retrieve timer info from firmware: invalid data.\n");
+ return -EINVAL;
+ }
+
+ timer_block = kcalloc(timer_count,
+ sizeof(struct acpi_gtdt_timer_block *),
+ GFP_KERNEL);
+ if (!timer_block)
+ return -ENOMEM;
+
+ watchdog = kcalloc(timer_count, sizeof(struct acpi_gtdt_watchdog *),
+ GFP_KERNEL);
+ if (!watchdog) {
+ kfree(timer_block);
+ timer_block = NULL;
+ return -ENOMEM;
+ }
+
+ acpi_gtdt_desc.timer_block_count = 0;
+ acpi_gtdt_desc.watchdog_count = 0;
+ for_each_platform_timer(platform_timer) {
+ if (is_timer_block(platform_timer)) {
+ timer_block[acpi_gtdt_desc.timer_block_count++] =
+ platform_timer;
+ } else if (is_watchdog(platform_timer)) {
+ watchdog[acpi_gtdt_desc.watchdog_count++] =
+ platform_timer;
+ } else {
+ pr_err(FW_BUG "Invalid platform timer type.\n");
+ goto error;
+ }
+ }
+
+ if (timer_count == acpi_gtdt_desc.watchdog_count +
+ acpi_gtdt_desc.timer_block_count)
+ return 0;
+
+ pr_err(FW_BUG "Invalid platform timer number.\n");
+error:
+ acpi_gtdt_release();
+ return -EINVAL;
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 61a3d90..a1611d1 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -577,6 +577,13 @@ 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 acpi_gtdt_map_ppi(int type);
+bool acpi_gtdt_c3stop(int type);
+void acpi_gtdt_release(void);
+#endif
+
#else /* !CONFIG_ACPI */
#define acpi_disabled 1
--
2.7.4
^ permalink raw reply related
* [PATCH v15 08/13] clocksource/drivers/arm_arch_timer: Refactor the timer init code to prepare for GTDT
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch refactor original memory-mapped timer init code:
(1) Extract a subfunction for detecting a bast time frame:
is_best_frame.
(2) Refactor "arch_timer_mem_init", make it become a common code for
memory-mapped timer init.
(3) 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 | 153 ++++++++++++++++++++++++-----------
1 file changed, 104 insertions(+), 49 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index af22953..a44e44d 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -913,17 +913,35 @@ 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 bool __init is_best_frame(void __iomem *cntctlbase, u32 cnttidr, int n)
+{
+ u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT | CNTACR_RWVT |
+ CNTACR_RVOFF | CNTACR_RVCT;
+
+ /* Try enabling everything, and see what sticks */
+ writel_relaxed(cntacr, cntctlbase + CNTACR(n));
+ cntacr = readl_relaxed(cntctlbase + CNTACR(n));
+
+ if ((cnttidr & CNTTIDR_VIRT(n)) &&
+ !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT)))
+ arch_timer_mem_use_virtual = true;
+ else if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
+ return false;
+
+ return true;
+}
+
+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;
}
@@ -933,69 +951,106 @@ 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;
- }
-
- /* 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;
- arch_timer_mem_use_virtual = true;
- break;
+ for (i = 0; i < timer_mem->num_frames; i++) {
+ if (is_best_frame(cntctlbase, cnttidr,
+ timer_mem->frame[i].frame_nr)) {
+ best_frame = &timer_mem->frame[i];
+ if (arch_timer_mem_use_virtual)
+ break;
}
-
- if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
- continue;
-
- of_node_put(best_frame);
- best_frame = of_node_get(frame);
}
+ 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;
+ }
+
+ base = ioremap(best_frame->cntbase, best_frame->size);
+ if (!base) {
+ pr_err("Can't map frame's registers\n");
+ return -ENXIO;
}
- arch_timer_detect_rate(base, np);
+ arch_timer_detect_rate(base, NULL);
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);
- return arch_timer_common_init();
+ 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 (++i >= ARCH_TIMER_MEM_MAX_FRAMES)
+ break;
+ }
+ timer_mem->num_frames = i;
+
+ arch_timer_detect_rate(NULL, np);
+ ret = arch_timer_mem_init(timer_mem);
+ if (!ret)
+ 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.7.4
^ permalink raw reply related
* [PATCH v15 07/13] clocksource/drivers/arm_arch_timer: Introduce some new structs to prepare for GTDT
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-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 2625ff1..cc986a3 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 BIT(0) /* physical counter */
#define ARCH_TIMER_USR_VCT_ACCESS_EN BIT(1) /* virtual counter */
#define ARCH_TIMER_VIRT_EVT_EN BIT(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.7.4
^ permalink raw reply related
* [PATCH v15 06/13] clocksource/drivers/arm_arch_timer: separate out arch_timer_uses_ppi init code to prepare for GTDT.
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch refactor original arch_timer_uses_ppi init code:
(1) Extract a subfunction: arch_timer_uses_ppi_init
(2) Use the new subfunction in arch_timer_of_init and
arch_timer_acpi_init
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 73 +++++++++++++++++++++---------------
1 file changed, 42 insertions(+), 31 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 6de164f..af22953 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -821,40 +821,42 @@ static int __init arch_timer_common_init(void)
return arch_timer_arch_init();
}
-static int __init arch_timer_init(void)
+/*
+ * 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 ARM64, we we only use ARCH_TIMER_PHYS_NONSECURE_PPI in Linux.
+ *
+ * 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.
+ */
+static int __init arch_timer_uses_ppi_init(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_kernel_in_hyp_mode()) {
- arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
- has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI];
- } else {
+ if (is_hyp_mode_available() && is_kernel_in_hyp_mode()) {
+ arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
+ } else if (!arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) {
+ if (IS_ENABLED(CONFIG_ARM64))
+ arch_timer_uses_ppi = ARCH_TIMER_PHYS_NONSECURE_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 (!has_ppi) {
- pr_warn("No interrupt available, giving up\n");
- return -EINVAL;
- }
}
+ if (arch_timer_ppi[arch_timer_uses_ppi])
+ return 0;
+
+ pr_warn("No interrupt available, giving up\n");
+ return -EINVAL;
+}
+
+static int __init arch_timer_init(void)
+{
+ int ret;
+
ret = arch_timer_register();
if (ret)
return ret;
@@ -870,7 +872,7 @@ static int __init arch_timer_init(void)
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");
@@ -902,6 +904,10 @@ static int __init arch_timer_of_init(struct device_node *np)
of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
+ ret = arch_timer_uses_ppi_init();
+ if (ret)
+ return ret;
+
return arch_timer_init();
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
@@ -1011,6 +1017,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) {
@@ -1041,6 +1048,10 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
/* Get the frequency from CNTFRQ */
arch_timer_detect_rate(NULL, NULL);
+ ret = arch_timer_uses_ppi_init();
+ if (ret)
+ return ret;
+
/* Always-on capability */
arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
--
2.7.4
^ permalink raw reply related
* [PATCH v15 05/13] clocksource/drivers/arm_arch_timer: fix a bug in arch_timer_register about arch_timer_uses_ppi
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
The patch fix a potential bug about arch_timer_uses_ppi in
arch_timer_register.
On ARM64, we don't use ARCH_TIMER_PHYS_SECURE_PPI in Linux, so we will
just igorne it in init code. If arch_timer_uses_ppi is
ARCH_TIMER_PHYS_NONSECURE_PPI, the orignal code of
arch_timer_uses_ppi may go wrong.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index dd1040d..6de164f 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);
--
2.7.4
^ permalink raw reply related
* [PATCH v15 04/13] clocksource/drivers/arm_arch_timer: rename some enums and defines, and some cleanups.
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
Rename some enums and defines, to unify the format of enums and defines
in arm_arch_timer.h, also update all the users of these enums and defines:
drivers/clocksource/arm_arch_timer.c
virt/kvm/arm/hyp/timer-sr.c
And do some cleanups, according to the suggestion from checkpatch.pl:
(1) using BIT(nr) instead of (1 << nr)
(2) using 'unsigned int' instead of 'unsigned'
No functional change.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
---
drivers/clocksource/arm_arch_timer.c | 111 ++++++++++++++++++-----------------
include/clocksource/arm_arch_timer.h | 40 ++++++-------
virt/kvm/arm/hyp/timer-sr.c | 6 +-
3 files changed, 81 insertions(+), 76 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index b0365043..dd1040d 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -66,11 +66,11 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
static u32 arch_timer_rate;
-static int arch_timer_ppi[MAX_TIMER_PPI];
+static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
-static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI;
+static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI;
static bool arch_timer_c3stop;
static bool arch_timer_mem_use_virtual;
@@ -340,7 +340,7 @@ static void fsl_a008585_set_sne(struct clock_event_device *clk)
if (!static_branch_unlikely(&arch_timer_read_ool_enabled))
return;
- if (arch_timer_uses_ppi == VIRT_PPI)
+ if (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI)
clk->set_next_event = fsl_a008585_set_next_event_virt;
else
clk->set_next_event = fsl_a008585_set_next_event_phys;
@@ -352,7 +352,7 @@ static void __arch_timer_setup(unsigned type,
{
clk->features = CLOCK_EVT_FEAT_ONESHOT;
- if (type == ARCH_CP15_TIMER) {
+ if (type == ARCH_TIMER_TYPE_CP15) {
if (arch_timer_c3stop)
clk->features |= CLOCK_EVT_FEAT_C3STOP;
clk->name = "arch_sys_timer";
@@ -360,14 +360,14 @@ static void __arch_timer_setup(unsigned type,
clk->cpumask = cpumask_of(smp_processor_id());
clk->irq = arch_timer_ppi[arch_timer_uses_ppi];
switch (arch_timer_uses_ppi) {
- case VIRT_PPI:
+ case ARCH_TIMER_VIRT_PPI:
clk->set_state_shutdown = arch_timer_shutdown_virt;
clk->set_state_oneshot_stopped = arch_timer_shutdown_virt;
clk->set_next_event = arch_timer_set_next_event_virt;
break;
- case PHYS_SECURE_PPI:
- case PHYS_NONSECURE_PPI:
- case HYP_PPI:
+ case ARCH_TIMER_PHYS_SECURE_PPI:
+ case ARCH_TIMER_PHYS_NONSECURE_PPI:
+ case ARCH_TIMER_HYP_PPI:
clk->set_state_shutdown = arch_timer_shutdown_phys;
clk->set_state_oneshot_stopped = arch_timer_shutdown_phys;
clk->set_next_event = arch_timer_set_next_event_phys;
@@ -447,8 +447,8 @@ static void arch_counter_set_user_access(void)
static bool arch_timer_has_nonsecure_ppi(void)
{
- return (arch_timer_uses_ppi == PHYS_SECURE_PPI &&
- arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ return (arch_timer_uses_ppi == ARCH_TIMER_PHYS_SECURE_PPI &&
+ arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
}
static u32 check_ppi_trigger(int irq)
@@ -469,14 +469,15 @@ static int arch_timer_starting_cpu(unsigned int cpu)
struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt);
u32 flags;
- __arch_timer_setup(ARCH_CP15_TIMER, clk);
+ __arch_timer_setup(ARCH_TIMER_TYPE_CP15, clk);
flags = check_ppi_trigger(arch_timer_ppi[arch_timer_uses_ppi]);
enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], flags);
if (arch_timer_has_nonsecure_ppi()) {
- flags = check_ppi_trigger(arch_timer_ppi[PHYS_NONSECURE_PPI]);
- enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], flags);
+ flags = check_ppi_trigger(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
+ enable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI],
+ flags);
}
arch_counter_set_user_access();
@@ -513,16 +514,17 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
static void arch_timer_banner(unsigned type)
{
pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
- type & ARCH_CP15_TIMER ? "cp15" : "",
- type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? " and " : "",
- type & ARCH_MEM_TIMER ? "mmio" : "",
+ type & ARCH_TIMER_TYPE_CP15 ? "cp15" : "",
+ type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ?
+ " and " : "",
+ type & ARCH_TIMER_TYPE_MEM ? "mmio" : "",
(unsigned long)arch_timer_rate / 1000000,
(unsigned long)(arch_timer_rate / 10000) % 100,
- type & ARCH_CP15_TIMER ?
- (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
+ type & ARCH_TIMER_TYPE_CP15 ?
+ (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI) ? "virt" : "phys" :
"",
- type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "",
- type & ARCH_MEM_TIMER ?
+ type == (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? "/" : "",
+ type & ARCH_TIMER_TYPE_MEM ?
arch_timer_mem_use_virtual ? "virt" : "phys" :
"");
}
@@ -588,8 +590,9 @@ static void __init arch_counter_register(unsigned type)
u64 start_count;
/* Register the CP15 based counter if we have one */
- if (type & ARCH_CP15_TIMER) {
- if (IS_ENABLED(CONFIG_ARM64) || arch_timer_uses_ppi == VIRT_PPI)
+ if (type & ARCH_TIMER_TYPE_CP15) {
+ if (IS_ENABLED(CONFIG_ARM64) ||
+ arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI)
arch_timer_read_counter = arch_counter_get_cntvct;
else
arch_timer_read_counter = arch_counter_get_cntpct;
@@ -625,7 +628,7 @@ static void arch_timer_stop(struct clock_event_device *clk)
disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]);
if (arch_timer_has_nonsecure_ppi())
- disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ disable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
clk->set_state_shutdown(clk);
}
@@ -688,24 +691,24 @@ static int __init arch_timer_register(void)
ppi = arch_timer_ppi[arch_timer_uses_ppi];
switch (arch_timer_uses_ppi) {
- case VIRT_PPI:
+ case ARCH_TIMER_VIRT_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_virt,
"arch_timer", arch_timer_evt);
break;
- case PHYS_SECURE_PPI:
- case PHYS_NONSECURE_PPI:
+ case ARCH_TIMER_PHYS_SECURE_PPI:
+ 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[PHYS_NONSECURE_PPI]) {
- ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
+ if (!err && arch_timer_ppi[ARCH_TIMER_PHYS_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);
if (err)
- free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+ free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI],
arch_timer_evt);
}
break;
- case HYP_PPI:
+ case ARCH_TIMER_HYP_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
break;
@@ -737,7 +740,7 @@ static int __init arch_timer_register(void)
out_unreg_notify:
free_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], arch_timer_evt);
if (arch_timer_has_nonsecure_ppi())
- free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
+ free_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI],
arch_timer_evt);
out_free:
@@ -758,7 +761,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
t->base = base;
t->evt.irq = irq;
- __arch_timer_setup(ARCH_MEM_TIMER, &t->evt);
+ __arch_timer_setup(ARCH_TIMER_TYPE_MEM, &t->evt);
if (arch_timer_mem_use_virtual)
func = arch_timer_handler_virt_mem;
@@ -801,13 +804,15 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches)
static int __init arch_timer_common_init(void)
{
- unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER;
+ unsigned int 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_MEM_TIMER, arch_timer_mem_of_match))
+ if (arch_timer_needs_probing(ARCH_TIMER_TYPE_MEM,
+ arch_timer_mem_of_match))
return 0;
- if (arch_timer_needs_probing(ARCH_CP15_TIMER, arch_timer_of_match))
+ if (arch_timer_needs_probing(ARCH_TIMER_TYPE_CP15,
+ arch_timer_of_match))
return 0;
}
@@ -832,16 +837,16 @@ static int __init arch_timer_init(void)
* their CNTHP_*_EL2 counterparts, and use a different PPI
* number.
*/
- if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) {
+ if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) {
bool has_ppi;
if (is_kernel_in_hyp_mode()) {
- arch_timer_uses_ppi = HYP_PPI;
- has_ppi = !!arch_timer_ppi[HYP_PPI];
+ arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
+ has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI];
} else {
- arch_timer_uses_ppi = PHYS_SECURE_PPI;
- has_ppi = (!!arch_timer_ppi[PHYS_SECURE_PPI] ||
- !!arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ 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 (!has_ppi) {
@@ -858,7 +863,7 @@ static int __init arch_timer_init(void)
if (ret)
return ret;
- arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI];
+ arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI];
return 0;
}
@@ -867,13 +872,13 @@ static int __init arch_timer_of_init(struct device_node *np)
{
int i;
- if (arch_timers_present & ARCH_CP15_TIMER) {
+ if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
pr_warn("multiple nodes in dt, skipping\n");
return 0;
}
- arch_timers_present |= ARCH_CP15_TIMER;
- for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+ arch_timers_present |= ARCH_TIMER_TYPE_CP15;
+ 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);
@@ -895,7 +900,7 @@ 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 = PHYS_SECURE_PPI;
+ arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
return arch_timer_init();
}
@@ -909,7 +914,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
unsigned int irq, ret = -EINVAL;
u32 cnttidr;
- arch_timers_present |= ARCH_MEM_TIMER;
+ arch_timers_present |= ARCH_TIMER_TYPE_MEM;
cntctlbase = of_iomap(np, 0);
if (!cntctlbase) {
pr_err("Can't find CNTCTLBase\n");
@@ -1008,28 +1013,28 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
{
struct acpi_table_gtdt *gtdt;
- if (arch_timers_present & ARCH_CP15_TIMER) {
+ 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_CP15_TIMER;
+ arch_timers_present |= ARCH_TIMER_TYPE_CP15;
- arch_timer_ppi[PHYS_SECURE_PPI] =
+ arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] =
map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
gtdt->secure_el1_flags);
- arch_timer_ppi[PHYS_NONSECURE_PPI] =
+ arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI] =
map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
gtdt->non_secure_el1_flags);
- arch_timer_ppi[VIRT_PPI] =
+ arch_timer_ppi[ARCH_TIMER_VIRT_PPI] =
map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
gtdt->virtual_timer_flags);
- arch_timer_ppi[HYP_PPI] =
+ arch_timer_ppi[ARCH_TIMER_HYP_PPI] =
map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
gtdt->non_secure_el2_flags);
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index d23c381..2625ff1 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -20,18 +20,18 @@
#include <linux/timecounter.h>
#include <linux/types.h>
-#define ARCH_CP15_TIMER BIT(0)
-#define ARCH_MEM_TIMER BIT(1)
+#define ARCH_TIMER_TYPE_CP15 BIT(0)
+#define ARCH_TIMER_TYPE_MEM BIT(1)
-#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
-#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
-#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
+#define ARCH_TIMER_CTRL_ENABLE BIT(0)
+#define ARCH_TIMER_CTRL_IT_MASK BIT(1)
+#define ARCH_TIMER_CTRL_IT_STAT BIT(2)
-#define CNTHCTL_EL1PCTEN (1 << 0)
-#define CNTHCTL_EL1PCEN (1 << 1)
-#define CNTHCTL_EVNTEN (1 << 2)
-#define CNTHCTL_EVNTDIR (1 << 3)
-#define CNTHCTL_EVNTI (0xF << 4)
+#define ARCH_TIMER_CNTHCTL_EL1PCTEN BIT(0)
+#define ARCH_TIMER_CNTHCTL_EL1PCEN BIT(1)
+#define ARCH_TIMER_CNTHCTL_EVNTEN BIT(2)
+#define ARCH_TIMER_CNTHCTL_EVNTDIR BIT(3)
+#define ARCH_TIMER_CNTHCTL_EVNTI (0xF << 4)
enum arch_timer_reg {
ARCH_TIMER_REG_CTRL,
@@ -39,11 +39,11 @@ enum arch_timer_reg {
};
enum arch_timer_ppi_nr {
- PHYS_SECURE_PPI,
- PHYS_NONSECURE_PPI,
- VIRT_PPI,
- HYP_PPI,
- MAX_TIMER_PPI
+ ARCH_TIMER_PHYS_SECURE_PPI,
+ ARCH_TIMER_PHYS_NONSECURE_PPI,
+ ARCH_TIMER_VIRT_PPI,
+ ARCH_TIMER_HYP_PPI,
+ ARCH_TIMER_MAX_TIMER_PPI
};
enum arch_timer_spi_nr {
@@ -57,13 +57,13 @@ enum arch_timer_spi_nr {
#define ARCH_TIMER_MEM_PHYS_ACCESS 2
#define ARCH_TIMER_MEM_VIRT_ACCESS 3
-#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)
+#define ARCH_TIMER_USR_PCT_ACCESS_EN BIT(0) /* physical counter */
+#define ARCH_TIMER_USR_VCT_ACCESS_EN BIT(1) /* virtual counter */
+#define ARCH_TIMER_VIRT_EVT_EN BIT(2)
#define ARCH_TIMER_EVT_TRIGGER_SHIFT (4)
#define ARCH_TIMER_EVT_TRIGGER_MASK (0xF << ARCH_TIMER_EVT_TRIGGER_SHIFT)
-#define ARCH_TIMER_USR_VT_ACCESS_EN (1 << 8) /* virtual timer registers */
-#define ARCH_TIMER_USR_PT_ACCESS_EN (1 << 9) /* physical timer registers */
+#define ARCH_TIMER_USR_VT_ACCESS_EN BIT(8) /* virtual timer registers */
+#define ARCH_TIMER_USR_PT_ACCESS_EN BIT(9) /* physical timer registers */
#define ARCH_TIMER_EVT_STREAM_FREQ 10000 /* 100us */
diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
index 798866a..695b9d9 100644
--- a/virt/kvm/arm/hyp/timer-sr.c
+++ b/virt/kvm/arm/hyp/timer-sr.c
@@ -37,7 +37,7 @@ void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
/* Allow physical timer/counter access for the host */
val = read_sysreg(cnthctl_el2);
- val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+ val |= ARCH_TIMER_CNTHCTL_EL1PCTEN | ARCH_TIMER_CNTHCTL_EL1PCEN;
write_sysreg(val, cnthctl_el2);
/* Clear cntvoff for the host */
@@ -55,8 +55,8 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
* Physical counter access is allowed
*/
val = read_sysreg(cnthctl_el2);
- val &= ~CNTHCTL_EL1PCEN;
- val |= CNTHCTL_EL1PCTEN;
+ val &= ~ARCH_TIMER_CNTHCTL_EL1PCEN;
+ val |= ARCH_TIMER_CNTHCTL_EL1PCTEN;
write_sysreg(val, cnthctl_el2);
if (timer->enabled) {
--
2.7.4
^ permalink raw reply related
* [PATCH v15 03/13] clocksource/drivers/arm_arch_timer: Improve printk relevant code
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
This patch defines pr_fmt(fmt) for all pr_* functions,
then the pr_* doesn't need to add "arch_timer:" everytime.
According to the suggestion from checkpatch.pl:
(1) delete some Blank Spaces in arch_timer_banner;
(2) delete a redundant Tab in a bland line of arch_timer_init(void)
No functional change.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
---
drivers/clocksource/arm_arch_timer.c | 49 ++++++++++++++++++------------------
1 file changed, 25 insertions(+), 24 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 96c88bb..b0365043 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -32,6 +32,9 @@
#include <clocksource/arm_arch_timer.h>
+#undef pr_fmt
+#define pr_fmt(fmt) "arch_timer: " fmt
+
#define CNTTIDR 0x08
#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))
@@ -504,22 +507,22 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
/* Check the timer frequency. */
if (arch_timer_rate == 0)
- pr_warn("Architected timer frequency not available\n");
+ pr_warn("frequency not available\n");
}
static void arch_timer_banner(unsigned type)
{
- pr_info("Architected %s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
- type & ARCH_CP15_TIMER ? "cp15" : "",
- type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? " and " : "",
- type & ARCH_MEM_TIMER ? "mmio" : "",
- (unsigned long)arch_timer_rate / 1000000,
- (unsigned long)(arch_timer_rate / 10000) % 100,
- type & ARCH_CP15_TIMER ?
- (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
+ pr_info("%s%s%s timer(s) running@%lu.%02luMHz (%s%s%s).\n",
+ type & ARCH_CP15_TIMER ? "cp15" : "",
+ type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? " and " : "",
+ type & ARCH_MEM_TIMER ? "mmio" : "",
+ (unsigned long)arch_timer_rate / 1000000,
+ (unsigned long)(arch_timer_rate / 10000) % 100,
+ type & ARCH_CP15_TIMER ?
+ (arch_timer_uses_ppi == VIRT_PPI) ? "virt" : "phys" :
"",
- type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "",
- type & ARCH_MEM_TIMER ?
+ type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "",
+ type & ARCH_MEM_TIMER ?
arch_timer_mem_use_virtual ? "virt" : "phys" :
"");
}
@@ -618,8 +621,7 @@ static void __init arch_counter_register(unsigned type)
static void arch_timer_stop(struct clock_event_device *clk)
{
- pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
- clk->irq, smp_processor_id());
+ pr_debug("disable IRQ%d cpu #%d\n", clk->irq, smp_processor_id());
disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]);
if (arch_timer_has_nonsecure_ppi())
@@ -712,8 +714,7 @@ static int __init arch_timer_register(void)
}
if (err) {
- pr_err("arch_timer: can't register interrupt %d (%d)\n",
- ppi, err);
+ pr_err("can't register interrupt %d (%d)\n", ppi, err);
goto out_free;
}
@@ -766,7 +767,7 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &t->evt);
if (ret) {
- pr_err("arch_timer: Failed to request mem timer irq\n");
+ pr_err("Failed to request mem timer irq\n");
kfree(t);
}
@@ -844,7 +845,7 @@ static int __init arch_timer_init(void)
}
if (!has_ppi) {
- pr_warn("arch_timer: No interrupt available, giving up\n");
+ pr_warn("No interrupt available, giving up\n");
return -EINVAL;
}
}
@@ -858,7 +859,7 @@ static int __init arch_timer_init(void)
return ret;
arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI];
-
+
return 0;
}
@@ -867,7 +868,7 @@ static int __init arch_timer_of_init(struct device_node *np)
int i;
if (arch_timers_present & ARCH_CP15_TIMER) {
- pr_warn("arch_timer: multiple nodes in dt, skipping\n");
+ pr_warn("multiple nodes in dt, skipping\n");
return 0;
}
@@ -911,7 +912,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
arch_timers_present |= ARCH_MEM_TIMER;
cntctlbase = of_iomap(np, 0);
if (!cntctlbase) {
- pr_err("arch_timer: Can't find CNTCTLBase\n");
+ pr_err("Can't find CNTCTLBase\n");
return -ENXIO;
}
@@ -926,7 +927,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
u32 cntacr;
if (of_property_read_u32(frame, "frame-number", &n)) {
- pr_err("arch_timer: Missing frame-number\n");
+ pr_err("Missing frame-number\n");
of_node_put(frame);
goto out;
}
@@ -955,7 +956,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
ret= -ENXIO;
base = arch_counter_base = of_iomap(best_frame, 0);
if (!base) {
- pr_err("arch_timer: Can't map frame's registers\n");
+ pr_err("Can't map frame's registers\n");
goto out;
}
@@ -966,7 +967,7 @@ static int __init arch_timer_mem_init(struct device_node *np)
ret = -EINVAL;
if (!irq) {
- pr_err("arch_timer: Frame missing %s irq",
+ pr_err("Frame missing %s irq",
arch_timer_mem_use_virtual ? "virt" : "phys");
goto out;
}
@@ -1008,7 +1009,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
struct acpi_table_gtdt *gtdt;
if (arch_timers_present & ARCH_CP15_TIMER) {
- pr_warn("arch_timer: already initialized, skipping\n");
+ pr_warn("already initialized, skipping\n");
return -EINVAL;
}
--
2.7.4
^ permalink raw reply related
* [PATCH v15 02/13] clocksource/drivers/arm_arch_timer: Add a new enum for spi type
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
This patch add a new enum "arch_timer_spi_nr" and use it in the driver.
Just for code's readability, no functional change.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
---
drivers/clocksource/arm_arch_timer.c | 4 ++--
include/clocksource/arm_arch_timer.h | 6 ++++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 9826f06..96c88bb 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -960,9 +960,9 @@ static int __init arch_timer_mem_init(struct device_node *np)
}
if (arch_timer_mem_use_virtual)
- irq = irq_of_parse_and_map(best_frame, 1);
+ irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_VIRT_SPI);
else
- irq = irq_of_parse_and_map(best_frame, 0);
+ irq = irq_of_parse_and_map(best_frame, ARCH_TIMER_PHYS_SPI);
ret = -EINVAL;
if (!irq) {
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 557f869..d23c381 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -46,6 +46,12 @@ enum arch_timer_ppi_nr {
MAX_TIMER_PPI
};
+enum arch_timer_spi_nr {
+ ARCH_TIMER_PHYS_SPI,
+ ARCH_TIMER_VIRT_SPI,
+ ARCH_TIMER_MAX_TIMER_SPI
+};
+
#define ARCH_TIMER_PHYS_ACCESS 0
#define ARCH_TIMER_VIRT_ACCESS 1
#define ARCH_TIMER_MEM_PHYS_ACCESS 2
--
2.7.4
^ permalink raw reply related
* [PATCH v15 01/13] clocksource/drivers/arm_arch_timer: Move enums and defines to header file
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479215615-26950-1-git-send-email-fu.wei@linaro.org>
From: Fu Wei <fu.wei@linaro.org>
To support the arm_arch_timer via ACPI we need to share defines and enums
between the driver and the ACPI parser code.
Split out the relevant defines and enums into arm_arch_timer.h, and
change "enum ppi_nr" to "enum arch_timer_ppi_nr" to avoid the potential
name clashes.
No functional change.
Signed-off-by: Fu Wei <fu.wei@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
---
drivers/clocksource/arm_arch_timer.c | 11 -----------
include/clocksource/arm_arch_timer.h | 12 ++++++++++++
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 73c487d..9826f06 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -51,8 +51,6 @@
#define CNTV_TVAL 0x38
#define CNTV_CTL 0x3c
-#define ARCH_CP15_TIMER BIT(0)
-#define ARCH_MEM_TIMER BIT(1)
static unsigned arch_timers_present __initdata;
static void __iomem *arch_counter_base;
@@ -65,15 +63,6 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
static u32 arch_timer_rate;
-
-enum ppi_nr {
- PHYS_SECURE_PPI,
- PHYS_NONSECURE_PPI,
- VIRT_PPI,
- HYP_PPI,
- MAX_TIMER_PPI
-};
-
static int arch_timer_ppi[MAX_TIMER_PPI];
static struct clock_event_device __percpu *arch_timer_evt;
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index caedb74..557f869 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -16,9 +16,13 @@
#ifndef __CLKSOURCE_ARM_ARCH_TIMER_H
#define __CLKSOURCE_ARM_ARCH_TIMER_H
+#include <linux/bitops.h>
#include <linux/timecounter.h>
#include <linux/types.h>
+#define ARCH_CP15_TIMER BIT(0)
+#define ARCH_MEM_TIMER BIT(1)
+
#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
@@ -34,6 +38,14 @@ enum arch_timer_reg {
ARCH_TIMER_REG_TVAL,
};
+enum arch_timer_ppi_nr {
+ PHYS_SECURE_PPI,
+ PHYS_NONSECURE_PPI,
+ VIRT_PPI,
+ HYP_PPI,
+ MAX_TIMER_PPI
+};
+
#define ARCH_TIMER_PHYS_ACCESS 0
#define ARCH_TIMER_VIRT_ACCESS 1
#define ARCH_TIMER_MEM_PHYS_ACCESS 2
--
2.7.4
^ permalink raw reply related
* [PATCH v15 00/13] acpi, clocksource: add GTDT driver and GTDT support in arm_arch_timer
From: fu.wei at linaro.org @ 2016-11-15 13:13 UTC (permalink / raw)
To: linux-arm-kernel
From: Fu Wei <fu.wei@linaro.org>
This patchset:
(1)Preparation for adding GTDT support in arm_arch_timer:
1. Move some enums and marcos to header file;
2. Add a new enum for spi type;
3. Improve printk relevant code.
4. rename some enums and defines, and some cleanups.
5. separate out arch_timer_uses_ppi init code and fix a potential bug
6. Introduce some new structs and refactor the timer init code
(2)Introduce ACPI GTDT parser: drivers/acpi/arm64/acpi_gtdt.c
Parse all kinds of timer in GTDT table of ACPI:arch timer,
memory-mapped timer and SBSA Generic Watchdog timer.
This driver can help to simplify all the relevant timer drivers,
and separate all the ACPI GTDT knowledge from them.
(3)Simplify ACPI code for arm_arch_timer
(4)Add GTDT support for ARM memory-mapped timer, also refactor
original memory-mapped timer dt support for reusing some common
code.
This patchset has been tested on the following platforms with ACPI enabled:
(1)ARM Foundation v8 model
Changelog:
v15: https://lkml.org/lkml/2016/11/15/
Re-order patches
Add arm_arch_timer refactoring patches to prepare for GTDT:
1. rename some enums and defines, and some cleanups
2. separate out arch_timer_uses_ppi init code and fix a potential bug
3. Improve some new structs, refactor the timer init code.
Since the some structs have been changed, GTDT parser for memory-mapped
timer and SBSA Generic Watchdog timer have been update.
v14: https://lkml.org/lkml/2016/9/28/573
Separate memory-mapped timer GTDT support into two patches
1. Refactor the timer init code to prepare for GTDT
2. Add GTDT support for memory-mapped timer
v13: http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1231717.html
Improve arm_arch_timer code for memory-mapped
timer GTDT support, refactor original memory-mapped timer
dt support for reusing some common code.
v12: https://lkml.org/lkml/2016/9/13/250
Rebase to latest Linux 4.8-rc6
Delete the confusing "skipping" in the error message.
V11: https://lkml.org/lkml/2016/9/6/354
Rebase to latest Linux 4.8-rc5
Delete typedef (suggested by checkpatch.pl)
V10: https://lkml.org/lkml/2016/7/26/215
Drop the "readq" patch.
Rebase to latest Linux 4.7.
V9: https://lkml.org/lkml/2016/7/25/345
Improve pr_err message in acpi gtdt driver.
Update Commit message for 7/9
shorten the irq mapping function name
Improve GTDT driver for memory-mapped timer
v8: https://lkml.org/lkml/2016/7/19/660
Improve "pr_fmt(fmt)" definition: add "ACPI" in front of "GTDT",
and also improve printk message.
Simplify is_timer_block and is_watchdog.
Merge acpi_gtdt_desc_init and gtdt_arch_timer_init into acpi_gtdt_init();
Delete __init in include/linux/acpi.h for GTDT API
Make ARM64 select GTDT.
Delete "#include <linux/module.h>" from acpi_gtdt.c
Simplify GT block parse code.
v7: https://lkml.org/lkml/2016/7/13/769
Move the GTDT driver to drivers/acpi/arm64
Add add the ARM64-specific ACPI Support maintainers in MAINTAINERS
Merge 3 patches of GTDT parser driver.
Fix the for_each_platform_timer bug.
v6: https://lkml.org/lkml/2016/6/29/580
split the GTDT driver to 4 parts: basic, arch_timer, memory-mapped timer,
and SBSA Generic Watchdog timer
Improve driver by suggestions and example code from Daniel Lezcano
v5: https://lkml.org/lkml/2016/5/24/356
Sorting out all patches, simplify the API of GTDT driver:
GTDT driver just fills the data struct for arm_arch_timer driver.
v4: https://lists.linaro.org/pipermail/linaro-acpi/2016-March/006667.html
Delete the kvm relevant patches
Separate two patches for sorting out the code for arm_arch_timer.
Improve irq info export code to allow missing irq info in GTDT table.
v3: https://lkml.org/lkml/2016/2/1/658
Improve GTDT driver code:
(1)improve pr_* by defining pr_fmt(fmt)
(2)simplify gtdt_sbsa_gwdt_init
(3)improve gtdt_arch_timer_data_init, if table is NULL, it will try
to get GTDT table.
Move enum ppi_nr to arm_arch_timer.h, and add enum spi_nr.
Add arm_arch_timer get ppi from DT and GTDT support for kvm.
v2: https://lkml.org/lkml/2015/12/2/10
Rebase to latest kernel version(4.4-rc3).
Fix the bug about the config problem,
use CONFIG_ACPI_GTDT instead of CONFIG_ACPI in arm_arch_timer.c
v1: The first upstreaming version: https://lkml.org/lkml/2015/10/28/553
Fu Wei (13):
clocksource/drivers/arm_arch_timer: Move enums and defines to header
file
clocksource/drivers/arm_arch_timer: Add a new enum for spi type
clocksource/drivers/arm_arch_timer: Improve printk relevant code
clocksource/drivers/arm_arch_timer: rename some enums and defines, and
some cleanups.
clocksource/drivers/arm_arch_timer: fix a bug in arch_timer_register
about arch_timer_uses_ppi
clocksource/drivers/arm_arch_timer: separate out arch_timer_uses_ppi
init code to prepare for GTDT.
clocksource/drivers/arm_arch_timer: Introduce some new structs to
prepare for GTDT
clocksource/drivers/arm_arch_timer: Refactor the timer init code to
prepare for GTDT
acpi/arm64: Add GTDT table parse driver
clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
acpi/arm64: Add memory-mapped timer support in GTDT driver
clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped
timer
acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver
arch/arm64/Kconfig | 1 +
drivers/acpi/arm64/Kconfig | 3 +
drivers/acpi/arm64/Makefile | 1 +
drivers/acpi/arm64/gtdt.c | 411 ++++++++++++++++++++++++++++++++++
drivers/clocksource/arm_arch_timer.c | 420 ++++++++++++++++++++---------------
drivers/watchdog/Kconfig | 1 +
include/clocksource/arm_arch_timer.h | 61 +++--
include/linux/acpi.h | 8 +
virt/kvm/arm/hyp/timer-sr.c | 6 +-
9 files changed, 720 insertions(+), 192 deletions(-)
create mode 100644 drivers/acpi/arm64/gtdt.c
--
2.7.4
^ permalink raw reply
* [RFC v3 00/10] KVM PCIe/MSI passthrough on ARM/ARM64 and IOVA reserved regions
From: Eric Auger @ 2016-11-15 13:09 UTC (permalink / raw)
To: linux-arm-kernel
Following LPC discussions, we now report reserved regions through
iommu-group sysfs reserved_regions attribute file.
Reserved regions are populated through the IOMMU get_resv_region callback
(former get_dm_regions), now implemented by amd-iommu, intel-iommu and
arm-smmu.
The intel-iommu reports the [FEE0_0000h - FEF0_000h] MSI window as an
IOMMU_RESV_NOMAP reserved region.
arm-smmu reports the MSI window (arbitrarily located at 0x8000000 and
1MB large) and the PCI host bridge windows.
The series integrates a not officially posted patch from Robin:
"iommu/dma: Allow MSI-only cookies".
This series currently does not address IRQ safety assessment.
Best Regards
Eric
Git: complete series available at
https://github.com/eauger/linux/tree/v4.9-rc5-reserved-rfc-v3
History:
RFC v2 -> v3:
- switch to an iommu-group sysfs API
- use new dummy allocator provided by Robin
- dummy allocator initialized by vfio-iommu-type1 after enumerating
the reserved regions
- at the moment ARM MSI base address/size is left unchanged compared
to v2
- we currently report reserved regions and not usable IOVA regions as
requested by Alex
RFC v1 -> v2:
- fix intel_add_reserved_regions
- add mutex lock/unlock in vfio_iommu_type1
Eric Auger (10):
iommu/dma: Allow MSI-only cookies
iommu: Rename iommu_dm_regions into iommu_resv_regions
iommu: Add new reserved IOMMU attributes
iommu: iommu_alloc_resv_region
iommu: Do not map reserved regions
iommu: iommu_get_group_resv_regions
iommu: Implement reserved_regions iommu-group sysfs file
iommu/vt-d: Implement reserved region get/put callbacks
iommu/arm-smmu: Implement reserved region get/put callbacks
vfio/type1: Get MSI cookie
drivers/iommu/amd_iommu.c | 20 +++---
drivers/iommu/arm-smmu.c | 52 +++++++++++++++
drivers/iommu/dma-iommu.c | 116 ++++++++++++++++++++++++++-------
drivers/iommu/intel-iommu.c | 50 ++++++++++----
drivers/iommu/iommu.c | 141 ++++++++++++++++++++++++++++++++++++----
drivers/vfio/vfio_iommu_type1.c | 26 ++++++++
include/linux/dma-iommu.h | 7 ++
include/linux/iommu.h | 49 ++++++++++----
8 files changed, 391 insertions(+), 70 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH 02/19] phy: stih41x-usb: Remove usb phy driver and dt binding documentation.
From: Kishon Vijay Abraham I @ 2016-11-15 13:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473859677-9231-3-git-send-email-peter.griffin@linaro.org>
Hi,
On Wednesday 14 September 2016 06:57 PM, Peter Griffin wrote:
> This phy is only used on STiH415/6 based silicon, and support for
> these SoC's is being removed from the kernel.
>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> Cc: <kishon@ti.com>
I've merged the 1st 2 patches of this series. Since Patrice has already
mentioned that he's merged the MAINTAINERS patch, I'm not merging it.
Please let me know if you know of any problems.
Thanks
Kishon
> ---
> .../devicetree/bindings/phy/phy-stih41x-usb.txt | 24 ---
> drivers/phy/Kconfig | 8 -
> drivers/phy/Makefile | 1 -
> drivers/phy/phy-stih41x-usb.c | 188 ---------------------
> 4 files changed, 221 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/phy/phy-stih41x-usb.txt
> delete mode 100644 drivers/phy/phy-stih41x-usb.c
>
> diff --git a/Documentation/devicetree/bindings/phy/phy-stih41x-usb.txt b/Documentation/devicetree/bindings/phy/phy-stih41x-usb.txt
> deleted file mode 100644
> index 744b480..0000000
> --- a/Documentation/devicetree/bindings/phy/phy-stih41x-usb.txt
> +++ /dev/null
> @@ -1,24 +0,0 @@
> -STMicroelectronics STiH41x USB PHY binding
> -------------------------------------------
> -
> -This file contains documentation for the usb phy found in STiH415/6 SoCs from
> -STMicroelectronics.
> -
> -Required properties:
> -- compatible : should be "st,stih416-usb-phy" or "st,stih415-usb-phy"
> -- st,syscfg : should be a phandle of the syscfg node
> -- clock-names : must contain "osc_phy"
> -- clocks : must contain an entry for each name in clock-names.
> -See: Documentation/devicetree/bindings/clock/clock-bindings.txt
> -- #phy-cells : must be 0 for this phy
> -See: Documentation/devicetree/bindings/phy/phy-bindings.txt
> -
> -Example:
> -
> -usb2_phy: usb2phy at 0 {
> - compatible = "st,stih416-usb-phy";
> - #phy-cells = <0>;
> - st,syscfg = <&syscfg_rear>;
> - clocks = <&clk_sysin>;
> - clock-names = "osc_phy";
> -};
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index d1f22ac..b4aa039 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -392,14 +392,6 @@ config PHY_STIH407_USB
> Enable this support to enable the picoPHY device used by USB2
> and USB3 controllers on STMicroelectronics STiH407 SoC families.
>
> -config PHY_STIH41X_USB
> - tristate "STMicroelectronics USB2 PHY driver for STiH41x series"
> - depends on ARCH_STI
> - select GENERIC_PHY
> - help
> - Enable this to support the USB transceiver that is part of
> - STMicroelectronics STiH41x SoC series.
> -
> config PHY_QCOM_UFS
> tristate "Qualcomm UFS PHY driver"
> depends on OF && ARCH_QCOM
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index d169d80..5e48741 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -45,7 +45,6 @@ obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
> obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
> obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
> obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
> -obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o
> obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
> obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
> obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
> diff --git a/drivers/phy/phy-stih41x-usb.c b/drivers/phy/phy-stih41x-usb.c
> deleted file mode 100644
> index 0ac7463..0000000
> --- a/drivers/phy/phy-stih41x-usb.c
> +++ /dev/null
> @@ -1,188 +0,0 @@
> -/*
> - * Copyright (C) 2014 STMicroelectronics
> - *
> - * STMicroelectronics PHY driver for STiH41x USB.
> - *
> - * Author: Maxime Coquelin <maxime.coquelin@st.com>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2, as
> - * published by the Free Software Foundation.
> - *
> - */
> -
> -#include <linux/platform_device.h>
> -#include <linux/io.h>
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/of.h>
> -#include <linux/of_platform.h>
> -#include <linux/clk.h>
> -#include <linux/phy/phy.h>
> -#include <linux/regmap.h>
> -#include <linux/mfd/syscon.h>
> -
> -#define SYSCFG332 0x80
> -#define SYSCFG2520 0x820
> -
> -/**
> - * struct stih41x_usb_cfg - SoC specific PHY register mapping
> - * @syscfg: Offset in syscfg registers bank
> - * @cfg_mask: Bits mask for PHY configuration
> - * @cfg: Static configuration value for PHY
> - * @oscok: Notify the PHY oscillator clock is ready
> - * Setting this bit enable the PHY
> - */
> -struct stih41x_usb_cfg {
> - u32 syscfg;
> - u32 cfg_mask;
> - u32 cfg;
> - u32 oscok;
> -};
> -
> -/**
> - * struct stih41x_usb_phy - Private data for the PHY
> - * @dev: device for this controller
> - * @regmap: Syscfg registers bank in which PHY is configured
> - * @cfg: SoC specific PHY register mapping
> - * @clk: Oscillator used by the PHY
> - */
> -struct stih41x_usb_phy {
> - struct device *dev;
> - struct regmap *regmap;
> - const struct stih41x_usb_cfg *cfg;
> - struct clk *clk;
> -};
> -
> -static struct stih41x_usb_cfg stih415_usb_phy_cfg = {
> - .syscfg = SYSCFG332,
> - .cfg_mask = 0x3f,
> - .cfg = 0x38,
> - .oscok = BIT(6),
> -};
> -
> -static struct stih41x_usb_cfg stih416_usb_phy_cfg = {
> - .syscfg = SYSCFG2520,
> - .cfg_mask = 0x33f,
> - .cfg = 0x238,
> - .oscok = BIT(6),
> -};
> -
> -static int stih41x_usb_phy_init(struct phy *phy)
> -{
> - struct stih41x_usb_phy *phy_dev = phy_get_drvdata(phy);
> -
> - return regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg,
> - phy_dev->cfg->cfg_mask, phy_dev->cfg->cfg);
> -}
> -
> -static int stih41x_usb_phy_power_on(struct phy *phy)
> -{
> - struct stih41x_usb_phy *phy_dev = phy_get_drvdata(phy);
> - int ret;
> -
> - ret = clk_prepare_enable(phy_dev->clk);
> - if (ret) {
> - dev_err(phy_dev->dev, "Failed to enable osc_phy clock\n");
> - return ret;
> - }
> -
> - ret = regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg,
> - phy_dev->cfg->oscok, phy_dev->cfg->oscok);
> - if (ret)
> - clk_disable_unprepare(phy_dev->clk);
> -
> - return ret;
> -}
> -
> -static int stih41x_usb_phy_power_off(struct phy *phy)
> -{
> - struct stih41x_usb_phy *phy_dev = phy_get_drvdata(phy);
> - int ret;
> -
> - ret = regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg,
> - phy_dev->cfg->oscok, 0);
> - if (ret) {
> - dev_err(phy_dev->dev, "Failed to clear oscok bit\n");
> - return ret;
> - }
> -
> - clk_disable_unprepare(phy_dev->clk);
> -
> - return 0;
> -}
> -
> -static const struct phy_ops stih41x_usb_phy_ops = {
> - .init = stih41x_usb_phy_init,
> - .power_on = stih41x_usb_phy_power_on,
> - .power_off = stih41x_usb_phy_power_off,
> - .owner = THIS_MODULE,
> -};
> -
> -static const struct of_device_id stih41x_usb_phy_of_match[];
> -
> -static int stih41x_usb_phy_probe(struct platform_device *pdev)
> -{
> - struct device_node *np = pdev->dev.of_node;
> - const struct of_device_id *match;
> - struct stih41x_usb_phy *phy_dev;
> - struct device *dev = &pdev->dev;
> - struct phy_provider *phy_provider;
> - struct phy *phy;
> -
> - phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL);
> - if (!phy_dev)
> - return -ENOMEM;
> -
> - match = of_match_device(stih41x_usb_phy_of_match, &pdev->dev);
> - if (!match)
> - return -ENODEV;
> -
> - phy_dev->cfg = match->data;
> -
> - phy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
> - if (IS_ERR(phy_dev->regmap)) {
> - dev_err(dev, "No syscfg phandle specified\n");
> - return PTR_ERR(phy_dev->regmap);
> - }
> -
> - phy_dev->clk = devm_clk_get(dev, "osc_phy");
> - if (IS_ERR(phy_dev->clk)) {
> - dev_err(dev, "osc_phy clk not found\n");
> - return PTR_ERR(phy_dev->clk);
> - }
> -
> - phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops);
> -
> - if (IS_ERR(phy)) {
> - dev_err(dev, "failed to create phy\n");
> - return PTR_ERR(phy);
> - }
> -
> - phy_dev->dev = dev;
> -
> - phy_set_drvdata(phy, phy_dev);
> -
> - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> - return PTR_ERR_OR_ZERO(phy_provider);
> -}
> -
> -static const struct of_device_id stih41x_usb_phy_of_match[] = {
> - { .compatible = "st,stih415-usb-phy", .data = &stih415_usb_phy_cfg },
> - { .compatible = "st,stih416-usb-phy", .data = &stih416_usb_phy_cfg },
> - { /* sentinel */ },
> -};
> -MODULE_DEVICE_TABLE(of, stih41x_usb_phy_of_match);
> -
> -static struct platform_driver stih41x_usb_phy_driver = {
> - .probe = stih41x_usb_phy_probe,
> - .driver = {
> - .name = "stih41x-usb-phy",
> - .of_match_table = stih41x_usb_phy_of_match,
> - }
> -};
> -module_platform_driver(stih41x_usb_phy_driver);
> -
> -MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@st.com>");
> -MODULE_DESCRIPTION("STMicroelectronics USB PHY driver for STiH41x series");
> -MODULE_LICENSE("GPL v2");
>
^ permalink raw reply
* [PATCH v7 00/16] ACPI IORT ARM SMMU support
From: Rafael J. Wysocki @ 2016-11-15 13:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161115101257.GB16261@red-moon>
On Tue, Nov 15, 2016 at 11:12 AM, Lorenzo Pieralisi
<lorenzo.pieralisi@arm.com> wrote:
> Hi Rafael,
>
> On Thu, Nov 10, 2016 at 12:36:12AM +0100, Rafael J. Wysocki wrote:
>> Hi Lorenzo,
>>
>> On Wed, Nov 9, 2016 at 3:19 PM, Lorenzo Pieralisi
>> <lorenzo.pieralisi@arm.com> wrote:
>> > This patch series is v7 of a previous posting:
>> >
>> > https://lkml.org/lkml/2016/10/18/506
>>
>> I don't see anything objectionable in this series.
>>
>> Please let me know which patches in particular to look at in detail.
>
> Are patches 7 and consequently 16 (that builds on top of 7) ok with
> you ? They should be equivalent to nop on anything other than ARM64
> but they touch ACPI core so they require an ACK if they are ok please.
Yes, they are. Please feel free to add my ACKs to those or I will
send them separately later today.
Thanks,
Rafael
^ permalink raw reply
* [PATCH v4 0/2] phy: rockchip-inno-usb2: correct 480MHz clk_ops callbacks and stable time
From: Kishon Vijay Abraham I @ 2016-11-15 13:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479182047-3399-1-git-send-email-wulf@rock-chips.com>
On Tuesday 15 November 2016 09:24 AM, William Wu wrote:
> This series try to correct the 480MHz output clock of USB2 PHY
> clk_ops callback and fix the delay time. It aims to make the
> 480MHz clock gate more sensible and stable.
>
> Tested on rk3366/rk3399 EVB board.
merged to phy -next.
Thanks
Kishon
>
> William Wu (2):
> phy: rockchip-inno-usb2: correct clk_ops callback
> phy: rockchip-inno-usb2: correct 480MHz output clock stable time
>
> drivers/phy/phy-rockchip-inno-usb2.c | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
^ permalink raw reply
* [PATCH v2] ARM: dma-mapping: preallocate DMA-debug hash tables in core_initcall
From: Marek Szyprowski @ 2016-11-15 12:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CGME20161115125910eucas1p2ab762d2c7336130d7d2a81150f53f1aa@eucas1p2.samsung.com>
fs_initcall is definitely too late to initialize DMA-debug hash tables,
because some drivers might get probed and use DMA mapping framework
already in core_initcall. Late initialization of DMA-debug results in
false warning about accessing memory, that was not allocated, like this
one:
------------[ cut here ]------------
WARNING: CPU: 5 PID: 1 at lib/dma-debug.c:1104 check_unmap+0xa1c/0xe50
exynos-sysmmu 10a60000.sysmmu: DMA-API: device driver tries to free DMA memory it has not allocated [device
address=0x000000006ebd0000] [size=16384 bytes]
Modules linked in:
CPU: 5 PID: 1 Comm: swapper/0 Not tainted 4.9.0-rc5-00028-g39dde3d-dirty #44
Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
[<c0119dd4>] (unwind_backtrace) from [<c01122bc>] (show_stack+0x20/0x24)
[<c01122bc>] (show_stack) from [<c062714c>] (dump_stack+0x84/0xa0)
[<c062714c>] (dump_stack) from [<c0132560>] (__warn+0x14c/0x180)
[<c0132560>] (__warn) from [<c01325dc>] (warn_slowpath_fmt+0x48/0x50)
[<c01325dc>] (warn_slowpath_fmt) from [<c06814f8>] (check_unmap+0xa1c/0xe50)
[<c06814f8>] (check_unmap) from [<c06819c4>] (debug_dma_unmap_page+0x98/0xc8)
[<c06819c4>] (debug_dma_unmap_page) from [<c076c3e8>] (exynos_iommu_domain_free+0x158/0x380)
[<c076c3e8>] (exynos_iommu_domain_free) from [<c0764a30>] (iommu_domain_free+0x34/0x60)
[<c0764a30>] (iommu_domain_free) from [<c011f168>] (release_iommu_mapping+0x30/0xb8)
[<c011f168>] (release_iommu_mapping) from [<c011f23c>] (arm_iommu_release_mapping+0x4c/0x50)
[<c011f23c>] (arm_iommu_release_mapping) from [<c0b061ac>] (s5p_mfc_probe+0x640/0x80c)
[<c0b061ac>] (s5p_mfc_probe) from [<c07e6750>] (platform_drv_probe+0x70/0x148)
[<c07e6750>] (platform_drv_probe) from [<c07e25c0>] (driver_probe_device+0x12c/0x6b0)
[<c07e25c0>] (driver_probe_device) from [<c07e2c6c>] (__driver_attach+0x128/0x17c)
[<c07e2c6c>] (__driver_attach) from [<c07df74c>] (bus_for_each_dev+0x88/0xc8)
[<c07df74c>] (bus_for_each_dev) from [<c07e1b6c>] (driver_attach+0x34/0x58)
[<c07e1b6c>] (driver_attach) from [<c07e1350>] (bus_add_driver+0x18c/0x32c)
[<c07e1350>] (bus_add_driver) from [<c07e4198>] (driver_register+0x98/0x148)
[<c07e4198>] (driver_register) from [<c07e5cb0>] (__platform_driver_register+0x58/0x74)
[<c07e5cb0>] (__platform_driver_register) from [<c174cb30>] (s5p_mfc_driver_init+0x1c/0x20)
[<c174cb30>] (s5p_mfc_driver_init) from [<c0102690>] (do_one_initcall+0x64/0x258)
[<c0102690>] (do_one_initcall) from [<c17014c0>] (kernel_init_freeable+0x3d0/0x4d0)
[<c17014c0>] (kernel_init_freeable) from [<c116eeb4>] (kernel_init+0x18/0x134)
[<c116eeb4>] (kernel_init) from [<c010bbd8>] (ret_from_fork+0x14/0x3c)
---[ end trace dc54c54bd3581296 ]---
This patch moves initialization of DMA-debug to core_initcall. This is
safe from the initialization perspective. dma_debug_do_init() internally calls
debugfs functions and debugfs also gets initialised at core_initcall(), and
that is earlier than arch code in the link order, so it will get initialized
just before the DMA-debug.
Reported-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
Changelog:
v2:
- changed to core_initcall on suggestion of Russell King
---
arch/arm/mm/dma-mapping.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index ab4f745..d1abbcf 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1167,7 +1167,7 @@ static int __init dma_debug_do_init(void)
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
return 0;
}
-fs_initcall(dma_debug_do_init);
+core_initcall(dma_debug_do_init);
#ifdef CONFIG_ARM_DMA_USE_IOMMU
--
1.9.1
^ permalink raw reply related
* [PATCH V8 0/6] thermal: bcm2835: add thermal driver
From: Zhang Rui @ 2016-11-15 12:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87oa1mar27.fsf@eliezer.anholt.net>
On Fri, 2016-11-11 at 09:01 -0800, Eric Anholt wrote:
> kernel at martin.sperl.org writes:
>
> >
> > From: Martin Sperl <kernel@martin.sperl.org>
> Since Eduardo seems to be AFK, I've pulled this series to my -next
> branches.
I will take the thermal soc patches this time if we still don't have
response from Eduardo by the end of this week.
For this patches set, will you queue them up or do you prefer to go via
thermal tree?
thanks,
rui
^ permalink raw reply
* [PATCH] ARM: dma-mapping: preallocate DMA-debug hash tables in pure_initcall
From: Russell King - ARM Linux @ 2016-11-15 12:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479204295-29773-1-git-send-email-m.szyprowski@samsung.com>
On Tue, Nov 15, 2016 at 11:04:55AM +0100, Marek Szyprowski wrote:
> fs_initcall is definitely too late to initialize DMA-debug hash tables,
> because some drivers might get probed and use DMA mapping framework
> already in core_initcall. Late initialization of DMA-debug results in
> false warning about accessing memory, that was not allocated, like this
> one:
I think using pure_initcall() is not justified here - and if you read
the comments in include/linux/init.h, you're going against its
documented purpose - it says that it exists only to allow variables
that could not be statically initialised to be so.
It's also wrong, because debugfs gets initialised at core_initcall()
time, which happens after pure_initcall(), and dma_debug_init() calls
debugfs functions.
So, I really don't like this patch - it's subsituting one initcall
ordering issue for a different ordering issue.
Core code (which includes arch/arm/mm/) gets linked before drivers, so
moving this to be a core_initcall() would result in it being initialised
before drivers - and it actually makes total sense that this is a core
initcall.
It looks like this is safe from the debugfs perspective as well -
debugfs also gets initialised at core_initcall(), and that is earlier
than arch code in the link order, so debugfs should get initialised
first and then the DMA debug.
So, I'll accept a patch to change this from fs_initcall() to
core_initcall().
--
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
* [upstream-release] [PATCH 1/2] drivers: usb: phy: Add qoriq usb 3.0 phy driver support
From: Sriram Dash @ 2016-11-15 12:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <DB5PR0401MB1928CA058CC01243457F124791BC0@DB5PR0401MB1928.eurprd04.prod.outlook.com>
>From: Scott Wood
>On 11/13/2016 11:27 PM, Sriram Dash wrote:
>> diff --git a/Documentation/devicetree/bindings/phy/phy-qoriq-usb3.txt
>> b/Documentation/devicetree/bindings/phy/phy-qoriq-usb3.txt
>> new file mode 100644
>> index 0000000..d934c80
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/phy-qoriq-usb3.txt
>> @@ -0,0 +1,36 @@
>> +Driver for Freescale USB 3.0 PHY
>> +
>> +Required properties:
>> +
>> +- compatible : fsl,qoriq-usb3-phy
>
Hi Scott,
>This is a very vague compatible. Are there versioning registers within this register
>block?
>
There are versioning registers for the phy (1.0 and 1.1). But the current erratum
A008751 does not require the mentioning of the version numbers. Was planning
to take care of the versioning when there is code diversity on the basis of the
version number.
Shall I include the versioning in the documentation now for 1.0 and 1.1?
>> +/* Parameter control */
>> +#define USB3PRM1CR 0x000
>> +#define USB3PRM1CR_VAL 0x27672b2a
>> +
>> +/*
>> + * struct qoriq_usb3_phy - driver data for USB 3.0 PHY
>> + * @dev: pointer to device instance of this platform device
>> + * @param_ctrl: usb3 phy parameter control register base
>> + * @phy_base: usb3 phy register memory base
>> + * @has_erratum_flag: keeps track of erratum applicable on device */
>> +struct qoriq_usb3_phy {
>> + struct device *dev;
>> + void __iomem *param_ctrl;
>> + void __iomem *phy_base;
>> + u32 has_erratum_flag;
>> +};
>> +
>> +static inline u32 qoriq_usb3_phy_readl(void __iomem *addr, u32
>> +offset) {
>> + return __raw_readl(addr + offset);
>> +}
>> +
>> +static inline void qoriq_usb3_phy_writel(void __iomem *addr, u32 offset,
>> + u32 data)
>> +{
>> + __raw_writel(data, addr + offset);
>> +}
>
>Why raw? Besides missing barriers, this will cause the accesses to be native-endian
>which is not correct.
>
The only reason for __raw_writel is to make the code faster. However, shall I use
writel(with both barriers and byte swap) instead and then make appropriate changes
in the value 32'h27672B2A?
>> +/*
>> + * Erratum A008751
>> + * SCFG USB3PRM1CR has incorrect default value
>> + * SCFG USB3PRM1CR reset value should be 32'h27672B2A instead of
>32'h25E72B2A.
>
>When documenting C code, can you stick with C-style numeric constants?
>
>For that matter, just put the constant in the code instead of hiding it in an overly-
>generically-named USB3PRM1CR_VAL and then you won't need to redundantly
>state the value in a comment. Normally putting magic numbers in symbolic
>constants is a good thing, but in this case it's not actually describing anything and
>the number is of no meaning outside of this one erratum workaround (it might even
>be a different value if another chip has a similar erratum).
>
The POR value of the USB3PRM1CR should be 32'h27672B2A. So, I had named it as
such. Thanks for the info. Will remove the USB3PRM1CR_VAL and during writel,
will use 0x27672b2a directly. I will take care the next time.
>> + */
>> +static void erratum_a008751(struct qoriq_usb3_phy *phy) {
>> + qoriq_usb3_phy_writel(phy->param_ctrl, USB3PRM1CR,
>> + USB3PRM1CR_VAL);
>> +}
>> +
>> +/*
>> + * qoriq_usb3_phy_erratum - List of phy erratum
>> + * @qoriq_phy_erratum - erratum application
>> + * @compat - comapt string for erratum */
>> +
>> +struct qoriq_usb3_phy_erratum {
>> + void (*qoriq_phy_erratum)(struct qoriq_usb3_phy *phy);
>> + char *compat;
>> +};
>> +
>> +/* Erratum list */
>> +struct qoriq_usb3_phy_erratum phy_erratum_tbl[] = {
>> + {&erratum_a008751, "fsl,usb-erratum-a008751"},
>> + /* Add init time erratum here */
>> +};
>
>This needs to be static.
>
Ok. Will take care next time.
>Unnecessary & on the function pointer.
>
Ok. Will change in next version.
>> +static int qoriq_usb3_phy_init(struct phy *x) {
>> + struct qoriq_usb3_phy *phy = phy_get_drvdata(x);
>> + int i;
>> +
>> + for (i = 0; i < ARRAY_SIZE(phy_erratum_tbl); i++)
>> + if (phy->has_erratum_flag & 1 << i)
>> + phy_erratum_tbl[i].qoriq_phy_erratum(phy);
>> + return 0;
>> +}
>> +
>> +static const struct phy_ops ops = {
>> + .init = qoriq_usb3_phy_init,
>> + .owner = THIS_MODULE,
>> +};
>> +
>> +static int qoriq_usb3_phy_probe(struct platform_device *pdev) {
>> + struct qoriq_usb3_phy *phy;
>> + struct phy *generic_phy;
>> + struct phy_provider *phy_provider;
>> + const struct of_device_id *of_id;
>> + struct device *dev = &pdev->dev;
>> + struct resource *res;
>> + int i, ret;
>> +
>> + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
>> + if (!phy)
>> + return -ENOMEM;
>> + phy->dev = dev;
>> +
>> + of_id = of_match_device(dev->driver->of_match_table, dev);
>> + if (!of_id) {
>> + dev_err(dev, "failed to get device match\n");
>> + ret = -EINVAL;
>> + goto err_out;
>> + }
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>"param_ctrl");
>> + if (!res) {
>> + dev_err(dev, "failed to get param_ctrl memory\n");
>> + ret = -ENOENT;
>> + goto err_out;
>> + }
>> +
>> + phy->param_ctrl = devm_ioremap_resource(dev, res);
>> + if (!phy->param_ctrl) {
>> + dev_err(dev, "failed to remap param_ctrl memory\n");
>> + ret = -ENOMEM;
>> + goto err_out;
>> + }
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>"phy_base");
>> + if (!res) {
>> + dev_err(dev, "failed to get phy_base memory\n");
>> + ret = -ENOENT;
>> + goto err_out;
>> + }
>> +
>> + phy->phy_base = devm_ioremap_resource(dev, res);
>> + if (!phy->phy_base) {
>> + dev_err(dev, "failed to remap phy_base memory\n");
>> + ret = -ENOMEM;
>> + goto err_out;
>> + }
>> +
>> + phy->has_erratum_flag = 0;
>> + for (i = 0; i < ARRAY_SIZE(phy_erratum_tbl); i++)
>> + phy->has_erratum_flag |= device_property_read_bool(dev,
>> + phy_erratum_tbl[i].compat) << i;
>
>I don't see the erratum property in either the binding or the device tree. Also, a
>property name is not a "compat".
>
Ok. Will rename "char *compat" into "char *prop".
>Is there a reason why this flag and array mechanism is needed, rather than just
>checking the erratum properties from the init function -- or, if you have a good
>reason to not want to do device tree accesses from init, just using a bool per
>erratum? How many errata are you expecting?
>
The erratum prop will be specified via the dt and parsed in the init. The idea
behind the table is that it will accommodate more errata and every time we
are adding a new erratum, and the code changes would be minimal(with this
approach, we don't have to add new variable in qoriq_usb3_phy struct
corresponding to every new erratum being added).
In my knowledge, there are more than 5 errata in pipeline, and all of them
have to be applied in the init time. So, this table will make the code more
readable and less cumbersome.
However, in future, if any other erratum comes up, and it has to be applied
at any point other than during init, then the variable has to be added in
qoriq_usb3_phy struct and the property has to be read separately.
>-Scott
^ permalink raw reply
* [PATCH v2] arm64: SMMU-v2: Workaround for Cavium ThunderX erratum 28168
From: Robin Murphy @ 2016-11-15 12:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0414d797-7134-8192-d373-b14b26edd023@arm.com>
On 15/11/16 09:26, Marc Zyngier wrote:
> On 15/11/16 07:00, Geetha sowjanya wrote:
>> From: Tirumalesh Chalamarla <Tirumalesh.Chalamarla@cavium.com>
>>
>> This patch implements Cavium ThunderX erratum 28168.
>>
>> PCI requires stores complete in order. Due to erratum #28168
>> PCI-inbound MSI-X store to the interrupt controller are delivered
>> to the interrupt controller before older PCI-inbound memory stores
>> are committed.
>> Doing a sync on SMMU will make sure all prior data transfers are
>> completed before invoking ISR.
>>
>> Signed-off-by: Tirumalesh Chalamarla <Tirumalesh.Chalamarla@cavium.com>
>> Signed-off-by: Geetha sowjanya <gakula@caviumnetworks.com>
>> ---
>> arch/arm64/Kconfig | 11 +++++++++++
>> arch/arm64/Kconfig.platforms | 1 +
>> arch/arm64/include/asm/cpufeature.h | 3 ++-
>> arch/arm64/kernel/cpu_errata.c | 16 ++++++++++++++++
>> drivers/iommu/arm-smmu.c | 24 ++++++++++++++++++++++++
>> drivers/irqchip/irq-gic-common.h | 1 +
>> drivers/irqchip/irq-gic-v3.c | 19 +++++++++++++++++++
>> 7 files changed, 74 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 30398db..751972c 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -474,6 +474,17 @@ config CAVIUM_ERRATUM_27456
>>
>> If unsure, say Y.
>>
>> +config CAVIUM_ERRATUM_28168
>> + bool "Cavium erratum 28168: Make sure DMA data transfer is done before MSIX"
>> + depends on ARCH_THUNDER && ARM64
>> + default y
>> + help
>> + Due to erratum #28168 PCI-inbound MSI-X store to the interrupt
>> + controller are delivered to the interrupt controller before older
>> + PCI-inbound memory stores are committed. Doing a sync on SMMU
>> + will make sure all prior data transfers are done before invoking ISR.
>> +
>> + If unsure, say Y.
>
> Where is the entry in Documentation/arm64/silicon-errata.txt?
>
>> endmenu
>>
>>
>> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
>> index cfbdf02..2ac4ac6 100644
>> --- a/arch/arm64/Kconfig.platforms
>> +++ b/arch/arm64/Kconfig.platforms
>> @@ -185,6 +185,7 @@ config ARCH_SPRD
>>
>> config ARCH_THUNDER
>> bool "Cavium Inc. Thunder SoC Family"
>> + select IRQ_PREFLOW_FASTEOI
>> help
>> This enables support for Cavium's Thunder Family of SoCs.
>>
>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
>> index 758d74f..821fc3c 100644
>> --- a/arch/arm64/include/asm/cpufeature.h
>> +++ b/arch/arm64/include/asm/cpufeature.h
>> @@ -40,8 +40,9 @@
>> #define ARM64_HAS_32BIT_EL0 13
>> #define ARM64_HYP_OFFSET_LOW 14
>> #define ARM64_MISMATCHED_CACHE_LINE_SIZE 15
>> +#define ARM64_WORKAROUND_CAVIUM_28168 16
>>
>> -#define ARM64_NCAPS 16
>> +#define ARM64_NCAPS 17
>>
>> #ifndef __ASSEMBLY__
>>
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index 0150394..0841a12 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -122,6 +122,22 @@ static void cpu_enable_trap_ctr_access(void *__unused)
>> MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
>> },
>> #endif
>> +#ifdef CONFIG_CAVIUM_ERRATUM_28168
>> + {
>> + /* Cavium ThunderX, T88 pass 1.x - 2.1 */
>> + .desc = "Cavium erratum 28168",
>> + .capability = ARM64_WORKAROUND_CAVIUM_28168,
>> + MIDR_RANGE(MIDR_THUNDERX, 0x00,
>> + (1 << MIDR_VARIANT_SHIFT) | 1),
>> + },
>> + {
>> + /* Cavium ThunderX, T81 pass 1.0 */
>> + .desc = "Cavium erratum 28168",
>> + .capability = ARM64_WORKAROUND_CAVIUM_28168,
>> + MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
>> + },
>> +#endif
>
> How is that a CPU bug? Shouldn't that be keyed on the SMMU version or
> the ITs version?
Seconded. I assume the actual component at fault is the PCI RC, SMMU, or
interconnect in between - are there no ID registers in those parts that
will indicate a fixed version (or ECO) in future?
>> +
>> {
>> .desc = "Mismatched cache line size",
>> .capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
>> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
>> index c841eb7..1b4555c 100644
>> --- a/drivers/iommu/arm-smmu.c
>> +++ b/drivers/iommu/arm-smmu.c
>> @@ -570,6 +570,30 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
>> }
>> }
>>
>> +/*
>> + * Cavium ThunderX erratum 28168
>> + *
>> + * Due to erratum #28168 PCI-inbound MSI-X store to the interrupt
>> + * controller are delivered to the interrupt controller before older
>> + * PCI-inbound memory stores are committed. Doing a sync on SMMU
>> + * will make sure all prior data transfers are completed before
>> + * invoking ISR.
>> + *
>> + */
>> +void cavium_arm_smmu_tlb_sync(struct device *dev)
>> +{
>> + struct iommu_fwspec *fwspec = dev->iommu_fwspec;
>> + struct arm_smmu_device *smmu;
>> +
>> + smmu = fwspec_smmu(fwspec);
>> + if (!smmu)
>> + return;
>> + __arm_smmu_tlb_sync(smmu);
Further to my questions on the last posting, is TLBGSYNC alone
guaranteed to always do something, even if there are no outstanding
invalidation requests? Will this workaround still apply if
__arm_smmu_tlb_sync() were to use CBn_TLBSYNC instead?
>> +
>> +}
>> +EXPORT_SYMBOL(cavium_arm_smmu_tlb_sync);
>
> Why does this need to be exported? The only user can only be built-in.
>
>> +
>> +
>> static void arm_smmu_tlb_sync(void *cookie)
>> {
>> struct arm_smmu_domain *smmu_domain = cookie;
>> diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
>> index 205e5fd..4e88f55 100644
>> --- a/drivers/irqchip/irq-gic-common.h
>> +++ b/drivers/irqchip/irq-gic-common.h
>> @@ -38,4 +38,5 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
>>
>> void gic_set_kvm_info(const struct gic_kvm_info *info);
>>
>> +void cavium_arm_smmu_tlb_sync(struct device *dev);
>
> Why should this be visible to GICv2 as well? I have the ugly feeling
> this should stay private to the SMMU code and that a more standard
> mechanism should be used... Robin, is there anything else we could
> piggy-back on?
I'm not sure it's actually any less horrible, but technically, one
*could* externally force a sync like so:
struct iommu_domain *dom = iommu_get_domain_for_dev(dev);
iommu_map(dom, <some reserved IOVA>, <some safe PA>, PAGE_SIZE, IOMMU_READ;
iommu_unmap(dom, <IOVA>, PAGE_SIZE);
(needs also to be error-safe and race-safe, obviously)
although there's rather a lot of extra overhead involved, and it also
relies on the driver not doing any Intel-style lazy unmapping.
The other 'generic' way which comes to mind would be some magic domain
attribute which has a sync side-effect on read (or write), but that's
utterly vile. And I'm not even going to entertain the thought of having
the SMMU driver implement a fake irqchip stacked on top of the ITS for
the sake of keeping all the code in one place...
>> #endif /* _IRQ_GIC_COMMON_H */
>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>> index 19d642e..723cebe 100644
>> --- a/drivers/irqchip/irq-gic-v3.c
>> +++ b/drivers/irqchip/irq-gic-v3.c
>> @@ -28,6 +28,8 @@
>> #include <linux/of_irq.h>
>> #include <linux/percpu.h>
>> #include <linux/slab.h>
>> +#include <linux/msi.h>
>> +#include <linux/pci.h>
>>
>> #include <linux/irqchip.h>
>> #include <linux/irqchip/arm-gic-common.h>
>> @@ -736,6 +738,20 @@ static inline void gic_cpu_pm_init(void) { }
>>
>> #define GIC_ID_NR (1U << gic_data.rdists.id_bits)
>>
>> +/*
>> + * Due to #28168 erratum in ThunderX,
>> + * we need to make sure DMA data transfer is done before MSIX.
>> + */
>> +static void cavium_irq_perflow_handler(struct irq_data *data)
perflow?
>> +{
>> + struct pci_dev *pdev;
>> +
>> + pdev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data));
>
> What happens if this is not a PCI device?
>
>> + if ((pdev->vendor != 0x177d) &&
>> + ((pdev->device & 0xA000) != 0xA000))
>> + cavium_arm_smmu_tlb_sync(&pdev->dev);
>
> I've asked that before. What makes Cavium devices so special that they
> are not sensitive to this bug?
>
>> +}
>> +
>> static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
>> irq_hw_number_t hw)
>> {
>> @@ -773,6 +789,9 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
>> return -EPERM;
>> irq_domain_set_info(d, irq, hw, chip, d->host_data,
>> handle_fasteoi_irq, NULL, NULL);
>> + if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_28168))
>> + __irq_set_preflow_handler(irq,
>> + cavium_irq_perflow_handler);
>
> What happens if SMMUv2 is not compiled in?
drivers/built-in.o: In function `cavium_irq_perflow_handler':
/work/src/linux/drivers/irqchip/irq-gic-v3.c:752: undefined reference to
`cavium_arm_smmu_tlb_sync'
make: *** [vmlinux] Error 1
Robin
> Also, since this only affects
> LPI signaling, why is this in the core GICv3 code and not in the ITS.
> And more specifically, in the PCI part of the ITS, since you seem to
> exclusively consider PCI?
>
>> }
>>
>> return 0;
>>
>
> Thanks,
>
> M.
>
^ permalink raw reply
* [PATCH V8 2/6] thermal: bcm2835: add thermal driver for bcm2835 soc
From: Zhang Rui @ 2016-11-15 12:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478081906-12009-3-git-send-email-kernel@martin.sperl.org>
On Wed, 2016-11-02 at 10:18 +0000, kernel at martin.sperl.org wrote:
> From: Martin Sperl <kernel@martin.sperl.org>
>
> Add basic thermal driver for bcm2835 SOC.
>
> This driver currently relies on the firmware setting up the
> tsense HW block and does not set it up itself.
>
> Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
> Acked-by: Eric Anholt <eric@anholt.net>
> Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
>
Acked-by: Zhang Rui <rui.zhang@intel.com>
thanks,
rui
> ChangeLog:
> ?V1 -> V2: added specific settings depending on compatiblity
> ???added trip point based on register
> ???setting up ctrl-register if HW is not enabled by firmware
> ?????as per recommendation of Eric (untested)
> ???check that clock frequency is in range
> ?????(1.9 - 5MHz - as per comment in clk-bcm2835.c)
> ?V2 -> V4: moved back to thermal (not using bcm sub-directory)
> ??????? ???set polling interval to 1second (was 0ms, so
> interrupt driven)
> ?V5 -> V6: added correct depends in KConfig
> ???removed defined default for RESET_DELAY
> ???removed obvious comments
> ???clarify HW setup comments if not set up by FW already
> ???move clk_prepare_enable to an earlier stage and add error
> handling
> ???clarify warning when TS-clock runs out of recommended range
> ???clk_disable_unprepare added in bcm2835_thermal_remove
> ???added comment on recommended temperature ranges for SOC
> ?V6 -> V7: removed depends on ARCH_BCM2836 || ARCH_BCM2837 in Kconfig
> ?V7 -> V8: rebased
> ---
> ?drivers/thermal/Kconfig???????????|???8 +
> ?drivers/thermal/Makefile??????????|???1 +
> ?drivers/thermal/bcm2835_thermal.c | 340
> ++++++++++++++++++++++++++++++++++++++
> ?3 files changed, 349 insertions(+)
> ?create mode 100644 drivers/thermal/bcm2835_thermal.c
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index a13541b..ab946ff 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -434,4 +434,12 @@ depends on (ARCH_QCOM && OF) || COMPILE_TEST
> ?source "drivers/thermal/qcom/Kconfig"
> ?endmenu
>
> +config BCM2835_THERMAL
> + tristate "Thermal sensors on bcm2835 SoC"
> + depends on ARCH_BCM2835 || COMPILE_TEST
> + depends on HAS_IOMEM
> + depends on OF
> + help
> + ??Support for thermal sensors on Broadcom bcm2835 SoCs.
> +
> ?endif
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index c92eb22..a10ebe0 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -55,3 +55,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
> ?obj-$(CONFIG_HISI_THERMAL)?????+= hisi_thermal.o
> ?obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
> ?obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
> +obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o
> diff --git a/drivers/thermal/bcm2835_thermal.c
> b/drivers/thermal/bcm2835_thermal.c
> new file mode 100644
> index 0000000..3468c7b
> --- /dev/null
> +++ b/drivers/thermal/bcm2835_thermal.c
> @@ -0,0 +1,340 @@
> +/*
> + * Driver for Broadcom BCM2835 soc temperature sensor
> + *
> + * Copyright (C) 2016 Martin Sperl
> + *
> + * This program is free software; you can redistribute it and/or
> modify
> + * it under the terms of the GNU General Public License as published
> by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.??See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/debugfs.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/thermal.h>
> +
> +#define BCM2835_TS_TSENSCTL 0x00
> +#define BCM2835_TS_TSENSSTAT 0x04
> +
> +#define BCM2835_TS_TSENSCTL_PRWDW BIT(0)
> +#define BCM2835_TS_TSENSCTL_RSTB BIT(1)
> +#define BCM2835_TS_TSENSCTL_CTRL_BITS 3
> +#define BCM2835_TS_TSENSCTL_CTRL_SHIFT 2
> +#define BCM2835_TS_TSENSCTL_CTRL_MASK ????\
> + GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS +?????\
> + BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \
> + BCM2835_TS_TSENSCTL_CTRL_SHIFT)
> +#define BCM2835_TS_TSENSCTL_CTRL_DEFAULT 1
> +#define BCM2835_TS_TSENSCTL_EN_INT BIT(5)
> +#define BCM2835_TS_TSENSCTL_DIRECT BIT(6)
> +#define BCM2835_TS_TSENSCTL_CLR_INT BIT(7)
> +#define BCM2835_TS_TSENSCTL_THOLD_SHIFT 8
> +#define BCM2835_TS_TSENSCTL_THOLD_BITS 10
> +#define BCM2835_TS_TSENSCTL_THOLD_MASK ?????\
> + GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS +?????\
> + BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \
> + BCM2835_TS_TSENSCTL_THOLD_SHIFT)
> +#define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT 18
> +#define BCM2835_TS_TSENSCTL_RSTDELAY_BITS 8
> +#define BCM2835_TS_TSENSCTL_REGULEN BIT(26)
> +
> +#define BCM2835_TS_TSENSSTAT_DATA_BITS 10
> +#define BCM2835_TS_TSENSSTAT_DATA_SHIFT 0
> +#define BCM2835_TS_TSENSSTAT_DATA_MASK ?????\
> + GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS +?????\
> + BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \
> + BCM2835_TS_TSENSSTAT_DATA_SHIFT)
> +#define BCM2835_TS_TSENSSTAT_VALID BIT(10)
> +#define BCM2835_TS_TSENSSTAT_INTERRUPT BIT(11)
> +
> +struct bcm2835_thermal_info {
> + int offset;
> + int slope;
> + int trip_temp;
> +};
> +
> +struct bcm2835_thermal_data {
> + const struct bcm2835_thermal_info *info;
> + void __iomem *regs;
> + struct clk *clk;
> + struct dentry *debugfsdir;
> +};
> +
> +static int bcm2835_thermal_adc2temp(
> + const struct bcm2835_thermal_info *info, u32 adc)
> +{
> + return info->offset + (adc * info->slope);
> +}
> +
> +static int bcm2835_thermal_temp2adc(
> + const struct bcm2835_thermal_info *info, int temp)
> +{
> + temp -= info->offset;
> + temp /= info->slope;
> +
> + if (temp < 0)
> + temp = 0;
> + if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
> + temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
> +
> + return temp;
> +}
> +
> +static int bcm2835_thermal_get_trip_type(
> + struct thermal_zone_device *tz, int trip,
> + enum thermal_trip_type *type)
> +{
> + *type = THERMAL_TRIP_CRITICAL;
> + return 0;
> +}
> +
> +static int bcm2835_thermal_get_trip_temp(
> + struct thermal_zone_device *tz, int trip, int *temp)
> +{
> + struct bcm2835_thermal_data *data = tz->devdata;
> + u32 val = readl(data->regs + BCM2835_TS_TSENSCTL);
> +
> + /* get the THOLD bits */
> + val &= BCM2835_TS_TSENSCTL_THOLD_MASK;
> + val >>= BCM2835_TS_TSENSCTL_THOLD_SHIFT;
> +
> + /* if it is zero then use the info value */
> + if (val)
> + *temp = bcm2835_thermal_adc2temp(data->info, val);
> + else
> + *temp = data->info->trip_temp;
> +
> + return 0;
> +}
> +
> +static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz,
> + ????int *temp)
> +{
> + struct bcm2835_thermal_data *data = tz->devdata;
> + u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT);
> +
> + if (!(val & BCM2835_TS_TSENSSTAT_VALID))
> + return -EIO;
> +
> + val &= BCM2835_TS_TSENSSTAT_DATA_MASK;
> +
> + *temp = bcm2835_thermal_adc2temp(data->info, val);
> +
> + return 0;
> +}
> +
> +static const struct debugfs_reg32 bcm2835_thermal_regs[] = {
> + {
> + .name = "ctl",
> + .offset = 0
> + },
> + {
> + .name = "stat",
> + .offset = 4
> + }
> +};
> +
> +static void bcm2835_thermal_debugfs(struct platform_device *pdev)
> +{
> + struct thermal_zone_device *tz = platform_get_drvdata(pdev);
> + struct bcm2835_thermal_data *data = tz->devdata;
> + struct debugfs_regset32 *regset;
> +
> + data->debugfsdir = debugfs_create_dir("bcm2835_thermal",
> NULL);
> + if (!data->debugfsdir)
> + return;
> +
> + regset = devm_kzalloc(&pdev->dev, sizeof(*regset),
> GFP_KERNEL);
> + if (!regset)
> + return;
> +
> + regset->regs = bcm2835_thermal_regs;
> + regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs);
> + regset->base = data->regs;
> +
> + debugfs_create_regset32("regset", S_IRUGO,
> + data->debugfsdir, regset);
> +}
> +
> +static struct thermal_zone_device_ops bcm2835_thermal_ops??= {
> + .get_temp = bcm2835_thermal_get_temp,
> + .get_trip_temp = bcm2835_thermal_get_trip_temp,
> + .get_trip_type = bcm2835_thermal_get_trip_type,
> +};
> +
> +static const struct of_device_id bcm2835_thermal_of_match_table[];
> +static int bcm2835_thermal_probe(struct platform_device *pdev)
> +{
> + const struct of_device_id *match;
> + struct thermal_zone_device *tz;
> + struct bcm2835_thermal_data *data;
> + struct resource *res;
> + int err;
> + u32 val;
> + unsigned long rate;
> +
> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + match = of_match_device(bcm2835_thermal_of_match_table,
> + &pdev->dev);
> + if (!match)
> + return -EINVAL;
> + data->info = match->data;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + data->regs = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(data->regs)) {
> + err = PTR_ERR(data->regs);
> + dev_err(&pdev->dev, "Could not get registers: %d\n",
> err);
> + return err;
> + }
> +
> + data->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(data->clk)) {
> + err = PTR_ERR(data->clk);
> + if (err != -EPROBE_DEFER)
> + dev_err(&pdev->dev, "Could not get clk:
> %d\n", err);
> + return err;
> + }
> +
> + err = clk_prepare_enable(data->clk);
> + if (err)
> + return err;
> +
> + rate = clk_get_rate(data->clk);
> + if ((rate < 1920000) || (rate > 5000000))
> + dev_warn(&pdev->dev,
> + ?"Clock %pCn running at %pCr Hz is outside
> of the recommended range: 1.92 to 5MHz\n",
> + ?data->clk, data->clk);
> +
> + /*
> + ?* right now the FW does set up the HW-block, so we are not
> + ?* touching the configuration registers.
> + ?* But if the HW is not enabled, then set it up
> + ?* using "sane" values used by the firmware right now.
> + ?*/
> + val = readl(data->regs + BCM2835_TS_TSENSCTL);
> + if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
> + /* the basic required flags */
> + val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT <<
> + ???????BCM2835_TS_TSENSCTL_CTRL_SHIFT) |
> + ??????BCM2835_TS_TSENSCTL_REGULEN;
> +
> + /*
> + ?* reset delay using the current firmware value of
> 14
> + ?* - units of time are unknown.
> + ?*/
> + val |= (14 << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
> +
> + /*??trip_adc value from info */
> + val |= bcm2835_thermal_temp2adc(data->info,
> + data->info-
> >trip_temp) <<
> + BCM2835_TS_TSENSCTL_THOLD_SHIFT;
> +
> + /* write the value back to the register as 2 steps
> */
> + writel(val, data->regs + BCM2835_TS_TSENSCTL);
> + val |= BCM2835_TS_TSENSCTL_RSTB;
> + writel(val, data->regs + BCM2835_TS_TSENSCTL);
> + }
> +
> + /* register thermal zone with 1 trip point an 1s polling */
> + tz = thermal_zone_device_register("bcm2835_thermal",
> + ??1, 0, data,
> + ??&bcm2835_thermal_ops,
> + ??NULL,
> + ??0, 1000);
> + if (IS_ERR(tz)) {
> + clk_disable_unprepare(data->clk);
> + err = PTR_ERR(tz);
> + dev_err(&pdev->dev,
> + "Failed to register the thermal device:
> %d\n",
> + err);
> + return err;
> + }
> +
> + platform_set_drvdata(pdev, tz);
> +
> + bcm2835_thermal_debugfs(pdev);
> +
> + return 0;
> +}
> +
> +static int bcm2835_thermal_remove(struct platform_device *pdev)
> +{
> + struct thermal_zone_device *tz = platform_get_drvdata(pdev);
> + struct bcm2835_thermal_data *data = tz->devdata;
> +
> + debugfs_remove_recursive(data->debugfsdir);
> + thermal_zone_device_unregister(tz);
> + clk_disable_unprepare(data->clk);
> +
> + return 0;
> +}
> +
> +/*
> + * Note: as per Raspberry Foundation FAQ
> + * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTempe
> rature)
> + * the recommended temperature range for the SOC -40C to +85C
> + * so the trip limit is set to 80C.
> + * this applies to all the BCM283X SOC
> + */
> +
> +static const struct of_device_id bcm2835_thermal_of_match_table[] =
> {
> + {
> + .compatible = "brcm,bcm2835-thermal",
> + .data = &(struct bcm2835_thermal_info) {
> + .offset = 407000,
> + .slope = -538,
> + .trip_temp = 80000
> + }
> + },
> + {
> + .compatible = "brcm,bcm2836-thermal",
> + .data = &(struct bcm2835_thermal_info) {
> + .offset = 407000,
> + .slope = -538,
> + .trip_temp = 80000
> + }
> + },
> + {
> + .compatible = "brcm,bcm2837-thermal",
> + .data = &(struct bcm2835_thermal_info) {
> + /* the bcm2837 needs adjustment of +5C */
> + .offset = 407000 + 5000,
> + .slope = -538,
> + .trip_temp = 80000
> + }
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
> +
> +static struct platform_driver bcm2835_thermal_driver = {
> + .probe = bcm2835_thermal_probe,
> + .remove = bcm2835_thermal_remove,
> + .driver = {
> + .name = "bcm2835_thermal",
> + .of_match_table = bcm2835_thermal_of_match_table,
> + },
> +};
> +module_platform_driver(bcm2835_thermal_driver);
> +
> +MODULE_AUTHOR("Martin Sperl");
> +MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
> +MODULE_LICENSE("GPL");
> --
> 2.1.4
^ permalink raw reply
* [PATCH 2/3] thermal: hisilicon: fix for dependency
From: Zhang Rui @ 2016-11-15 12:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161112120534.GC23848@leoy-linaro>
On Sat, 2016-11-12 at 20:05 +0800, Leo Yan wrote:
> Hi Rui, Eduardo,
>
> On Wed, Aug 31, 2016 at 04:50:16PM +0800, Leo Yan wrote:
> >
> > The thermal driver is standalone driver which is used to enable
> > thermal sensors, so it can be used with any cooling device and
> > should not bind with CPU cooling device driver.
> >
> > This original patch is suggested by Amit Kucheria; so it's to
> > polish the dependency in Kconfig, and remove the dependency with
> > CPU_THERMAL.
> Could you help review this patch? Or need me resend this patch? Sorry
> I have not tracked this patches well before, this is one missed
> patch for 96board Hikey.
>
as it still applies cleanly, the patch is queued for 4.10.
thanks,
rui
> Thanks,
> Leo Yan
>
> >
> > Signed-off-by: Leo Yan <leo.yan@linaro.org>
> > ---
> > ?drivers/thermal/Kconfig | 4 +++-
> > ?1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> > index 2d702ca..91ebab3 100644
> > --- a/drivers/thermal/Kconfig
> > +++ b/drivers/thermal/Kconfig
> > @@ -177,8 +177,10 @@ config THERMAL_EMULATION
> > ?
> > ?config HISI_THERMAL
> > ? tristate "Hisilicon thermal driver"
> > - depends on (ARCH_HISI && CPU_THERMAL && OF) ||
> > COMPILE_TEST
> > + depends on ARCH_HISI || COMPILE_TEST
> > ? depends on HAS_IOMEM
> > + depends on OF
> > + default y
> > ? help
> > ? ??Enable this to plug hisilicon's thermal sensor driver
> > into the Linux
> > ? ??thermal framework. cpufreq is used as the cooling device
> > to throttle
^ permalink raw reply
* [PATCH v4 6/6] arm64: arch_timer: acpi: add hisi timer errata data
From: Ding Tianhong @ 2016-11-15 12:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479212167-5812-1-git-send-email-dingtianhong@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
Add hisi timer specific erratum fixes.
v3: add hisilicon erratum 161601 for ACPI mode.
v4: update some data structures.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
---
drivers/clocksource/arm_arch_timer.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index d4f4a0d..649f7fe 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1078,10 +1078,28 @@ struct gtdt_arch_timer_fixup {
void *context;
};
+#ifdef CONFIG_HISILICON_ERRATUM_161601
+static void __init erratum_workaround_enable(void *context)
+{
+ u64 erratum = (u64) context;
+
+ if (erratum & HISILICON_161601) {
+ timer_unstable_counter_workaround = &arch_timer_hisi_161601;
+ static_branch_enable(&arch_timer_read_ool_enabled);
+ pr_info("Enabling workaround for HISILICON ERRATUM 161601\n");
+ }
+}
+#endif
+
/* note: this needs to be updated according to the doc of OEM ID
* and TABLE ID for different board.
*/
struct gtdt_arch_timer_fixup arch_timer_quirks[] __initdata = {
+#ifdef CONFIG_HISILICON_ERRATUM_161601
+ {"HISI", "hip05", 0, &erratum_workaround_enable, (void *) HISILICON_161601},
+ {"HISI", "hip06", 0, &erratum_workaround_enable, (void *) HISILICON_161601},
+ {"HISI", "hip07", 0, &erratum_workaround_enable, (void *) HISILICON_161601},
+#endif
};
void __init arch_timer_acpi_quirks_handler(char *oem_id,
--
1.9.0
^ 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