HI
On 15 September 2016 at 04:09, fu.wei@linaro.org wrote:
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. Also refactor original memory-mapped timer dt support for reusing some common code.
Signed-off-by: Fu Wei fu.wei@linaro.org
drivers/clocksource/arm_arch_timer.c | 238 +++++++++++++++++++++++++---------- 1 file changed, 172 insertions(+), 66 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 0197ef9..ddca6e3 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -57,6 +57,7 @@ static unsigned arch_timers_present __initdata;
static void __iomem *arch_counter_base; +static void __iomem *cntctlbase __initdata;
struct arch_timer { void __iomem *base; @@ -656,15 +657,56 @@ out: return err; }
-static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq) +static int __init arch_timer_mem_register(struct device_node *np, void *frame) {
int ret;irq_handler_t func;
struct device_node *frame_node = NULL;struct gt_timer_data *frame_data = NULL; struct arch_timer *t;void __iomem *base;irq_handler_t func;unsigned int irq;int ret;if (np) {frame_node = (struct device_node *)frame;base = of_iomap(frame_node, 0);arch_timer_detect_rate(base, np);if (arch_timer_mem_use_virtual)irq = irq_of_parse_and_map(frame_node, VIRT_SPI);elseirq = irq_of_parse_and_map(frame_node, PHYS_SPI);} else {frame_data = (struct gt_timer_data *)frame;/** According to ARMv8 Architecture Reference Manual(ARM),* the size of CNTBaseN frames of memory-mapped timer* is SZ_4K(Offset 0x000 – 0xFFF).*/base = ioremap(frame_data->cntbase_phy, SZ_4K);if (arch_timer_mem_use_virtual)irq = frame_data->virtual_irq;elseirq = frame_data->irq;}if (!base) {pr_err("Can't map frame's registers\n");return -ENXIO;}if (!irq) {pr_err("Frame missing %s irq",arch_timer_mem_use_virtual ? "virt" : "phys");ret = -EINVAL;goto out;}arch_counter_base = base; t = kzalloc(sizeof(*t), GFP_KERNEL);
if (!t)
if (!t) { return -ENOMEM;
^ my bad, it should be "ret = "
goto out;} t->base = base; t->evt.irq = irq;@@ -676,11 +718,13 @@ static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq) func = arch_timer_handler_phys_mem;
ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &t->evt);
if (ret) {pr_err("Failed to request mem timer irq\n");kfree(t);}
if (!ret)return 0;pr_err("Failed to request mem timer irq\n");kfree(t);+out:
iounmap(base); return ret;}
@@ -769,7 +813,7 @@ static int __init arch_timer_init(void) return ret;
arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI];
return 0;}
@@ -803,21 +847,56 @@ static int __init arch_timer_of_init(struct device_node *np) CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
-static int __init arch_timer_mem_init(struct device_node *np) +static int __init get_cnttidr(struct device_node *np,
struct gt_block_data *gt_block, u32 *cnttidr){
struct device_node *frame, *best_frame = NULL;void __iomem *cntctlbase, *base;unsigned int irq, ret = -EINVAL;u32 cnttidr;
if (np)cntctlbase = of_iomap(np, 0);elsecntctlbase = ioremap(gt_block->cntctlbase_phy, SZ_4K);/** According to ARMv8 Architecture Reference Manual(ARM),* the size of CNTCTLBase frame of memory-mapped timer* is SZ_4K(Offset 0x000 – 0xFFF).*/
arch_timers_present |= ARCH_MEM_TIMER;cntctlbase = of_iomap(np, 0); if (!cntctlbase) { pr_err("Can't find CNTCTLBase\n"); return -ENXIO; }cnttidr = readl_relaxed(cntctlbase + CNTTIDR);
*cnttidr = readl_relaxed(cntctlbase + CNTTIDR);return 0;+}
+static bool __init is_best_frame(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 device_node *np) +{
struct device_node *frame, *best_frame = NULL;unsigned int ret = -EINVAL;u32 cnttidr;arch_timers_present |= ARCH_MEM_TIMER;if (get_cnttidr(np, NULL, &cnttidr))return -ENXIO; /* * Try to find a virtual capable frame. Otherwise fall back to a@@ -825,60 +904,22 @@ static int __init arch_timer_mem_init(struct device_node *np) */ 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");
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))) {
if (is_best_frame(cnttidr, n)) { of_node_put(best_frame);
best_frame = frame;arch_timer_mem_use_virtual = true;break;
best_frame = of_node_get(frame);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);}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 (arch_timer_mem_use_virtual)irq = irq_of_parse_and_map(best_frame, VIRT_SPI);elseirq = irq_of_parse_and_map(best_frame, PHYS_SPI);ret = -EINVAL;if (!irq) {pr_err("Frame missing %s irq",arch_timer_mem_use_virtual ? "virt" : "phys");goto out; }arch_timer_detect_rate(base, np);ret = arch_timer_mem_register(base, irq);if (ret)goto out;return arch_timer_common_init();
ret = arch_timer_mem_register(np, best_frame);if (!ret)ret = arch_timer_common_init();out: iounmap(cntctlbase); of_node_put(best_frame); @@ -888,7 +929,72 @@ CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_init);
#ifdef CONFIG_ACPI_GTDT -/* Initialize per-processor generic timer */ +static struct gt_timer_data __init *arch_timer_mem_get_timer(
struct gt_block_data *gt_blocks)+{
struct gt_block_data *gt_block = gt_blocks;struct gt_timer_data *best_frame = NULL;u32 cnttidr;int i;if (get_cnttidr(NULL, gt_block, &cnttidr))return NULL;/** Try to find a virtual capable frame. Otherwise fall back to a* physical capable frame.*/for (i = 0; i < gt_block->timer_count; i++) {if (is_best_frame(cnttidr, gt_block->timer[i].frame_nr)) {best_frame = >_block->timer[i];if (arch_timer_mem_use_virtual)break;}}iounmap(cntctlbase);return best_frame;+}
+static int __init arch_timer_mem_acpi_init(size_t timer_count) +{
struct gt_block_data *gt_blocks;struct gt_timer_data *gt_timer;int ret = -EINVAL;/** If we don't have any Platform Timer Structures, just return.*/if (!timer_count)return 0;/** before really check all the Platform Timer Structures,* we assume they are GT block, and allocate memory for them.* We will free these memory once we finish the initialization.*/gt_blocks = kcalloc(timer_count, sizeof(*gt_blocks), GFP_KERNEL);if (!gt_blocks)return -ENOMEM;if (gtdt_arch_timer_mem_init(gt_blocks) > 0) {gt_timer = arch_timer_mem_get_timer(gt_blocks);if (!gt_timer) {pr_err("Failed to get mem timer info.\n");goto error;}ret = arch_timer_mem_register(NULL, gt_timer);if (ret) {pr_err("Failed to register mem timer.\n");goto error;}}arch_timers_present |= ARCH_MEM_TIMER;+error:
kfree(gt_blocks);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 timer_count; @@ -912,8 +1018,8 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table) /* Get the frequency from CNTFRQ */ arch_timer_detect_rate(NULL, NULL);
if (timer_count < 0)pr_err("Failed to get platform timer info.\n");
if (timer_count < 0 || arch_timer_mem_acpi_init((size_t)timer_count))pr_err("Failed to initialize memory-mapped timer.\n"); return arch_timer_init();}
2.7.4