From 1a01753ed90a4fb84357b9b592e50564c07737f7 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 9 Feb 2011 12:01:12 +0000 Subject: ARM: gic: use handle_fasteoi_irq for SPIs Currently, the gic uses handle_level_irq for handling SPIs (Shared Peripheral Interrupts), requiring active interrupts to be masked at the distributor level during IRQ handling. On a virtualised system, only the CPU interfaces are virtualised in hardware. Accesses to the distributor must be trapped by the hypervisor, adding latency to the critical interrupt path in Linux. This patch modifies the GIC code to use handle_fasteoi_irq for handling interrupts, which only requires us to signal EOI to the CPU interface when handling is complete. Cascaded IRQ handling is also updated to use the chained IRQ enter/exit functions to honour the flow control of the parent chip. Note that commit 846afbd1 ("GIC: Dont disable INT in ack callback") broke cascading interrupts by forgetting to add IRQ masking. This is no longer an issue because the unmask call is now unnecessary. Tested on Versatile Express and Realview EB (1176 w/ cascaded GICs). Tested-and-reviewed-by: Abhijeet Dharmapurikar Tested-and-acked-by: Santosh Shilimkar Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm/common/gic.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index f70ec7dadeb..e9c2ff83909 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -49,7 +49,7 @@ struct gic_chip_data { * Default make them NULL. */ struct irq_chip gic_arch_extn = { - .irq_ack = NULL, + .irq_eoi = NULL, .irq_mask = NULL, .irq_unmask = NULL, .irq_retrigger = NULL, @@ -84,15 +84,6 @@ static inline unsigned int gic_irq(struct irq_data *d) /* * Routines to acknowledge, disable and enable interrupts */ -static void gic_ack_irq(struct irq_data *d) -{ - spin_lock(&irq_controller_lock); - if (gic_arch_extn.irq_ack) - gic_arch_extn.irq_ack(d); - writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); - spin_unlock(&irq_controller_lock); -} - static void gic_mask_irq(struct irq_data *d) { u32 mask = 1 << (d->irq % 32); @@ -115,6 +106,17 @@ static void gic_unmask_irq(struct irq_data *d) spin_unlock(&irq_controller_lock); } +static void gic_eoi_irq(struct irq_data *d) +{ + if (gic_arch_extn.irq_eoi) { + spin_lock(&irq_controller_lock); + gic_arch_extn.irq_eoi(d); + spin_unlock(&irq_controller_lock); + } + + writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); +} + static int gic_set_type(struct irq_data *d, unsigned int type) { void __iomem *base = gic_dist_base(d); @@ -218,8 +220,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) unsigned int cascade_irq, gic_irq; unsigned long status; - /* primary controller ack'ing */ - chip->irq_ack(&desc->irq_data); + chained_irq_enter(chip, desc); spin_lock(&irq_controller_lock); status = readl(chip_data->cpu_base + GIC_CPU_INTACK); @@ -236,15 +237,14 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) generic_handle_irq(cascade_irq); out: - /* primary controller unmasking */ - chip->irq_unmask(&desc->irq_data); + chained_irq_exit(chip, desc); } static struct irq_chip gic_chip = { .name = "GIC", - .irq_ack = gic_ack_irq, .irq_mask = gic_mask_irq, .irq_unmask = gic_unmask_irq, + .irq_eoi = gic_eoi_irq, .irq_set_type = gic_set_type, .irq_retrigger = gic_retrigger, #ifdef CONFIG_SMP @@ -319,7 +319,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic, * Setup the Linux IRQ subsystem. */ for (i = irq_start; i < irq_limit; i++) { - irq_set_chip_and_handler(i, &gic_chip, handle_level_irq); + irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq); irq_set_chip_data(i, gic); set_irq_flags(i, IRQF_VALID | IRQF_PROBE); } -- cgit v1.2.3-70-g09d2 From 6ac77e469e991e9dd91b28e503fa24b5609eedba Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 28 Mar 2011 19:27:46 +0530 Subject: ARM: GIC: Convert GIC library to use the IO relaxed operations The GIC register accesses today make use of readl()/writel() which prove to be very expensive when used along with mandatory barriers. This mandatory barriers also introduces an un-necessary and expensive l2x0_sync() operation. On Cortex-A9 MP cores, GIC IO accesses from CPU are direct and doesn't go through L2X0 write buffer. A DSB before writel_relaxed() in gic_raise_softirq() is added to be compliant with the Barrier Litmus document - the mailbox scenario. Signed-off-by: Santosh Shilimkar Acked-by: Catalin Marinas Cc: Will Deacon --- arch/arm/common/gic.c | 54 ++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index e9c2ff83909..4ddd0a6ac7f 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -89,7 +89,7 @@ static void gic_mask_irq(struct irq_data *d) u32 mask = 1 << (d->irq % 32); spin_lock(&irq_controller_lock); - writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); + writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); if (gic_arch_extn.irq_mask) gic_arch_extn.irq_mask(d); spin_unlock(&irq_controller_lock); @@ -102,7 +102,7 @@ static void gic_unmask_irq(struct irq_data *d) spin_lock(&irq_controller_lock); if (gic_arch_extn.irq_unmask) gic_arch_extn.irq_unmask(d); - writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4); + writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4); spin_unlock(&irq_controller_lock); } @@ -114,7 +114,7 @@ static void gic_eoi_irq(struct irq_data *d) spin_unlock(&irq_controller_lock); } - writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); + writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); } static int gic_set_type(struct irq_data *d, unsigned int type) @@ -140,7 +140,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) if (gic_arch_extn.irq_set_type) gic_arch_extn.irq_set_type(d, type); - val = readl(base + GIC_DIST_CONFIG + confoff); + val = readl_relaxed(base + GIC_DIST_CONFIG + confoff); if (type == IRQ_TYPE_LEVEL_HIGH) val &= ~confmask; else if (type == IRQ_TYPE_EDGE_RISING) @@ -150,15 +150,15 @@ static int gic_set_type(struct irq_data *d, unsigned int type) * As recommended by the spec, disable the interrupt before changing * the configuration */ - if (readl(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) { - writel(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff); + if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) { + writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff); enabled = true; } - writel(val, base + GIC_DIST_CONFIG + confoff); + writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); if (enabled) - writel(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); + writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); spin_unlock(&irq_controller_lock); @@ -190,8 +190,8 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, spin_lock(&irq_controller_lock); d->node = cpu; - val = readl(reg) & ~mask; - writel(val | bit, reg); + val = readl_relaxed(reg) & ~mask; + writel_relaxed(val | bit, reg); spin_unlock(&irq_controller_lock); return 0; @@ -223,7 +223,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) chained_irq_enter(chip, desc); spin_lock(&irq_controller_lock); - status = readl(chip_data->cpu_base + GIC_CPU_INTACK); + status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK); spin_unlock(&irq_controller_lock); gic_irq = (status & 0x3ff); @@ -272,13 +272,13 @@ static void __init gic_dist_init(struct gic_chip_data *gic, cpumask |= cpumask << 8; cpumask |= cpumask << 16; - writel(0, base + GIC_DIST_CTRL); + writel_relaxed(0, base + GIC_DIST_CTRL); /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ - gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f; + gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; if (gic_irqs > 1020) gic_irqs = 1020; @@ -287,26 +287,26 @@ static void __init gic_dist_init(struct gic_chip_data *gic, * Set all global interrupts to be level triggered, active low. */ for (i = 32; i < gic_irqs; i += 16) - writel(0, base + GIC_DIST_CONFIG + i * 4 / 16); + writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16); /* * Set all global interrupts to this CPU only. */ for (i = 32; i < gic_irqs; i += 4) - writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); + writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); /* * Set priority on all global interrupts. */ for (i = 32; i < gic_irqs; i += 4) - writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); + writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); /* * Disable all interrupts. Leave the PPI and SGIs alone * as these enables are banked registers. */ for (i = 32; i < gic_irqs; i += 32) - writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); + writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); /* * Limit number of interrupts registered to the platform maximum @@ -324,7 +324,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic, set_irq_flags(i, IRQF_VALID | IRQF_PROBE); } - writel(1, base + GIC_DIST_CTRL); + writel_relaxed(1, base + GIC_DIST_CTRL); } static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) @@ -337,17 +337,17 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) * Deal with the banked PPI and SGI interrupts - disable all * PPI interrupts, ensure all SGI interrupts are enabled. */ - writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR); - writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET); + writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR); + writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET); /* * Set priority on PPI and SGI interrupts */ for (i = 0; i < 32; i += 4) - writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); + writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); - writel(0xf0, base + GIC_CPU_PRIMASK); - writel(1, base + GIC_CPU_CTRL); + writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); + writel_relaxed(1, base + GIC_CPU_CTRL); } void __init gic_init(unsigned int gic_nr, unsigned int irq_start, @@ -391,7 +391,13 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) { unsigned long map = *cpus_addr(*mask); + /* + * Ensure that stores to Normal memory are visible to the + * other CPUs before issuing the IPI. + */ + dsb(); + /* this always happens on GIC0 */ - writel(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); + writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); } #endif -- cgit v1.2.3-70-g09d2 From be20902ba67de70b38c995903321f4152dee57b7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 11 May 2011 15:39:00 +0100 Subject: ARM: use ARM_DMA_ZONE_SIZE to adjust the zone sizes Rather than each platform providing its own function to adjust the zone sizes, use the new ARM_DMA_ZONE_SIZE definition to perform this adjustment. This ensures that the actual DMA zone size and the ISA_DMA_THRESHOLD/MAX_DMA_ADDRESS definitions are consistent with each other, and moves this complexity out of the platform code. Acked-by: Nicolas Pitre Acked-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/common/sa1111.c | 8 -------- arch/arm/include/asm/memory.h | 6 ------ arch/arm/mach-davinci/include/mach/memory.h | 15 --------------- arch/arm/mach-ixp4xx/common-pci.c | 23 ----------------------- arch/arm/mach-ixp4xx/include/mach/memory.h | 9 +-------- arch/arm/mach-pxa/cm-x2xx-pci.c | 27 --------------------------- arch/arm/mach-pxa/include/mach/memory.h | 7 +------ arch/arm/mach-realview/core.c | 19 ------------------- arch/arm/mach-realview/include/mach/memory.h | 6 +----- arch/arm/mach-sa1100/include/mach/memory.h | 9 --------- arch/arm/mach-shark/include/mach/memory.h | 17 ----------------- arch/arm/mm/init.c | 23 ++++++++++++++++++++++- 12 files changed, 25 insertions(+), 144 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index a12b33c0dc4..9c49a46a2b7 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -185,14 +185,6 @@ static struct sa1111_dev_info sa1111_devices[] = { }, }; -void __init sa1111_adjust_zones(unsigned long *size, unsigned long *holes) -{ - unsigned int sz = SZ_1M >> PAGE_SHIFT; - - size[1] = size[0] - sz; - size[0] = sz; -} - /* * SA1111 interrupt support. Since clearing an IRQ while there are * active IRQs causes the interrupt output to pulse, the upper levels diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index ee5ff41027a..af44a8fb348 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -215,12 +215,6 @@ static inline unsigned long __phys_to_virt(unsigned long x) #define ISA_DMA_THRESHOLD (PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1) #endif -#ifndef arch_adjust_zones -#define arch_adjust_zones(size,holes) do { } while (0) -#elif !defined(CONFIG_ZONE_DMA) -#error "custom arch_adjust_zones() requires CONFIG_ZONE_DMA" -#endif - /* * PFNs are used to describe any physical page; this means * PFN 0 == physical address 0. diff --git a/arch/arm/mach-davinci/include/mach/memory.h b/arch/arm/mach-davinci/include/mach/memory.h index 8d27246cca4..491249ef209 100644 --- a/arch/arm/mach-davinci/include/mach/memory.h +++ b/arch/arm/mach-davinci/include/mach/memory.h @@ -41,26 +41,11 @@ */ #define CONSISTENT_DMA_SIZE (14<<20) -#ifndef __ASSEMBLY__ /* * Restrict DMA-able region to workaround silicon bug. The bug * restricts buffers available for DMA to video hardware to be * below 128M */ -static inline void -__arch_adjust_zones(unsigned long *size, unsigned long *holes) -{ - unsigned int sz = (128<<20) >> PAGE_SHIFT; - - size[1] = size[0] - sz; - size[0] = sz; -} - -#define arch_adjust_zones(zone_size, holes) \ - if ((meminfo.bank[0].size >> 20) > 128) __arch_adjust_zones(zone_size, holes) - #define ARM_DMA_ZONE_SIZE SZ_128M -#endif - #endif /* __ASM_ARCH_MEMORY_H */ diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index a54b3db8036..e9a58939572 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -342,29 +342,6 @@ int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M); } -/* - * Only first 64MB of memory can be accessed via PCI. - * We use GFP_DMA to allocate safe buffers to do map/unmap. - * This is really ugly and we need a better way of specifying - * DMA-capable regions of memory. - */ -void __init ixp4xx_adjust_zones(unsigned long *zone_size, - unsigned long *zhole_size) -{ - unsigned int sz = SZ_64M >> PAGE_SHIFT; - - /* - * Only adjust if > 64M on current system - */ - if (zone_size[0] <= sz) - return; - - zone_size[1] = zone_size[0] - sz; - zone_size[0] = sz; - zhole_size[1] = zhole_size[0]; - zhole_size[0] = 0; -} - void __init ixp4xx_pci_preinit(void) { unsigned long cpuid = read_cpuid_id(); diff --git a/arch/arm/mach-ixp4xx/include/mach/memory.h b/arch/arm/mach-ixp4xx/include/mach/memory.h index a5c26f8d312..34e79404671 100644 --- a/arch/arm/mach-ixp4xx/include/mach/memory.h +++ b/arch/arm/mach-ixp4xx/include/mach/memory.h @@ -14,15 +14,8 @@ */ #define PLAT_PHYS_OFFSET UL(0x00000000) -#if !defined(__ASSEMBLY__) && defined(CONFIG_PCI) - -void ixp4xx_adjust_zones(unsigned long *size, unsigned long *holes); - -#define arch_adjust_zones(size, holes) \ - ixp4xx_adjust_zones(size, holes) - +#ifdef CONFIG_PCI #define ARM_DMA_ZONE_SIZE SZ_64M - #endif #endif diff --git a/arch/arm/mach-pxa/cm-x2xx-pci.c b/arch/arm/mach-pxa/cm-x2xx-pci.c index 8b1a30959fa..1afc0fb7d6d 100644 --- a/arch/arm/mach-pxa/cm-x2xx-pci.c +++ b/arch/arm/mach-pxa/cm-x2xx-pci.c @@ -29,33 +29,6 @@ unsigned long it8152_base_address; static int cmx2xx_it8152_irq_gpio; -/* - * Only first 64MB of memory can be accessed via PCI. - * We use GFP_DMA to allocate safe buffers to do map/unmap. - * This is really ugly and we need a better way of specifying - * DMA-capable regions of memory. - */ -void __init cmx2xx_pci_adjust_zones(unsigned long *zone_size, - unsigned long *zhole_size) -{ - unsigned int sz = SZ_64M >> PAGE_SHIFT; - - if (machine_is_armcore()) { - pr_info("Adjusting zones for CM-X2XX\n"); - - /* - * Only adjust if > 64M on current system - */ - if (zone_size[0] <= sz) - return; - - zone_size[1] = zone_size[0] - sz; - zone_size[0] = sz; - zhole_size[1] = zhole_size[0]; - zhole_size[0] = 0; - } -} - static void cmx2xx_it8152_irq_demux(unsigned int irq, struct irq_desc *desc) { /* clear our parent irq */ diff --git a/arch/arm/mach-pxa/include/mach/memory.h b/arch/arm/mach-pxa/include/mach/memory.h index 57a0b689b4d..07734f37f8f 100644 --- a/arch/arm/mach-pxa/include/mach/memory.h +++ b/arch/arm/mach-pxa/include/mach/memory.h @@ -17,12 +17,7 @@ */ #define PLAT_PHYS_OFFSET UL(0xa0000000) -#if !defined(__ASSEMBLY__) && defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI) -void cmx2xx_pci_adjust_zones(unsigned long *size, unsigned long *holes); - -#define arch_adjust_zones(size, holes) \ - cmx2xx_pci_adjust_zones(size, holes) - +#if defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI) #define ARM_DMA_ZONE_SIZE SZ_64M #endif diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 75dbc8791d0..525ad17f826 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -56,25 +56,6 @@ #include "core.h" -#ifdef CONFIG_ZONE_DMA -/* - * Adjust the zones if there are restrictions for DMA access. - */ -void __init realview_adjust_zones(unsigned long *size, unsigned long *hole) -{ - unsigned long dma_size = SZ_256M >> PAGE_SHIFT; - - if (!machine_is_realview_pbx() || size[0] <= dma_size) - return; - - size[ZONE_NORMAL] = size[0] - dma_size; - size[ZONE_DMA] = dma_size; - hole[ZONE_NORMAL] = hole[0]; - hole[ZONE_DMA] = 0; -} -#endif - - #define REALVIEW_FLASHCTRL (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_FLASH_OFFSET) static int realview_flash_init(void) diff --git a/arch/arm/mach-realview/include/mach/memory.h b/arch/arm/mach-realview/include/mach/memory.h index 973428d3f7c..1759fa673ee 100644 --- a/arch/arm/mach-realview/include/mach/memory.h +++ b/arch/arm/mach-realview/include/mach/memory.h @@ -29,11 +29,7 @@ #define PLAT_PHYS_OFFSET UL(0x00000000) #endif -#if !defined(__ASSEMBLY__) && defined(CONFIG_ZONE_DMA) -extern void realview_adjust_zones(unsigned long *size, unsigned long *hole); -#define arch_adjust_zones(size, hole) \ - realview_adjust_zones(size, hole) - +#ifdef CONFIG_ZONE_DMA #define ARM_DMA_ZONE_SIZE SZ_256M #endif diff --git a/arch/arm/mach-sa1100/include/mach/memory.h b/arch/arm/mach-sa1100/include/mach/memory.h index 090b82982ab..cff31ee246b 100644 --- a/arch/arm/mach-sa1100/include/mach/memory.h +++ b/arch/arm/mach-sa1100/include/mach/memory.h @@ -14,17 +14,8 @@ */ #define PLAT_PHYS_OFFSET UL(0xc0000000) -#ifndef __ASSEMBLY__ - #ifdef CONFIG_SA1111 -void sa1111_adjust_zones(unsigned long *size, unsigned long *holes); - -#define arch_adjust_zones(size, holes) \ - sa1111_adjust_zones(size, holes) - #define ARM_DMA_ZONE_SIZE SZ_1M - -#endif #endif /* diff --git a/arch/arm/mach-shark/include/mach/memory.h b/arch/arm/mach-shark/include/mach/memory.h index 48fe84b1f27..4c0831f83b0 100644 --- a/arch/arm/mach-shark/include/mach/memory.h +++ b/arch/arm/mach-shark/include/mach/memory.h @@ -17,25 +17,8 @@ */ #define PLAT_PHYS_OFFSET UL(0x08000000) -#ifndef __ASSEMBLY__ - -static inline void __arch_adjust_zones(unsigned long *zone_size, unsigned long *zhole_size) -{ - /* Only the first 4 MB (=1024 Pages) are usable for DMA */ - /* See dev / -> .properties in OpenFirmware. */ - zone_size[1] = zone_size[0] - 1024; - zone_size[0] = 1024; - zhole_size[1] = zhole_size[0]; - zhole_size[0] = 0; -} - -#define arch_adjust_zones(size, holes) \ - __arch_adjust_zones(size, holes) - #define ARM_DMA_ZONE_SIZE SZ_4M -#endif - /* * Cache flushing area */ diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index e5f6fc42834..49eaad9136a 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -201,6 +201,20 @@ static void __init arm_bootmem_init(unsigned long start_pfn, } } +#ifdef CONFIG_ZONE_DMA +static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole, + unsigned long dma_size) +{ + if (size[0] <= dma_size) + return; + + size[ZONE_NORMAL] = size[0] - dma_size; + size[ZONE_DMA] = dma_size; + hole[ZONE_NORMAL] = hole[0]; + hole[ZONE_DMA] = 0; +} +#endif + static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, unsigned long max_high) { @@ -243,11 +257,18 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, #endif } +#ifdef ARM_DMA_ZONE_SIZE +#ifndef CONFIG_ZONE_DMA +#error ARM_DMA_ZONE_SIZE set but no DMA zone to limit allocations +#endif + /* * Adjust the sizes according to any special requirements for * this machine type. */ - arch_adjust_zones(zone_size, zhole_size); + arm_adjust_dma_zone(zone_size, zhole_size, + ARM_DMA_ZONE_SIZE >> PAGE_SHIFT); +#endif free_area_init_node(0, zone_size, min, zhole_size); } -- cgit v1.2.3-70-g09d2 From bfe45e0be88d8a2e408226d473bff60da4a97d1f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 May 2011 15:33:30 +0100 Subject: clocksource: convert ARM 32-bit down counting clocksources Convert SP804, MXC, Nomadik and Orion 32-bit down-counting clocksources to generic mmio clocksource infrastructure. Acked-by: Catalin Marinas Cc: Sascha Hauer Cc: Alessandro Rubini Acked-by: Linus Walleij Cc: Lennert Buytenhek Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/Kconfig | 2 ++ arch/arm/common/timer-sp.c | 30 ++++++------------------------ arch/arm/plat-mxc/epit.c | 18 ++---------------- arch/arm/plat-nomadik/Kconfig | 1 + arch/arm/plat-nomadik/timer.c | 31 +++---------------------------- arch/arm/plat-orion/time.c | 21 ++------------------- 6 files changed, 16 insertions(+), 87 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9aa55149703..0a05a57449e 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1042,6 +1042,7 @@ config PLAT_IOP config PLAT_ORION bool + select CLKSRC_MMIO select HAVE_SCHED_CLOCK config PLAT_PXA @@ -1052,6 +1053,7 @@ config PLAT_VERSATILE config ARM_TIMER_SP804 bool + select CLKSRC_MMIO source arch/arm/mm/Kconfig diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 6ef3342153b..445b05ee851 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -32,35 +32,17 @@ #define TIMER_FREQ_KHZ (1000) #define TIMER_RELOAD (TIMER_FREQ_KHZ * 1000 / HZ) -static void __iomem *clksrc_base; - -static cycle_t sp804_read(struct clocksource *cs) -{ - return ~readl(clksrc_base + TIMER_VALUE); -} - -static struct clocksource clocksource_sp804 = { - .name = "timer3", - .rating = 200, - .read = sp804_read, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - void __init sp804_clocksource_init(void __iomem *base) { - struct clocksource *cs = &clocksource_sp804; - - clksrc_base = base; - /* setup timer 0 as free-running clocksource */ - writel(0, clksrc_base + TIMER_CTRL); - writel(0xffffffff, clksrc_base + TIMER_LOAD); - writel(0xffffffff, clksrc_base + TIMER_VALUE); + writel(0, base + TIMER_CTRL); + writel(0xffffffff, base + TIMER_LOAD); + writel(0xffffffff, base + TIMER_VALUE); writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, - clksrc_base + TIMER_CTRL); + base + TIMER_CTRL); - clocksource_register_khz(cs, TIMER_FREQ_KHZ); + clocksource_mmio_init(base + TIMER_VALUE, "timer3", + TIMER_FREQ_KHZ * 1000, 200, 32, clocksource_mmio_readl_down); } diff --git a/arch/arm/plat-mxc/epit.c b/arch/arm/plat-mxc/epit.c index d69d343ff61..d3467f818c3 100644 --- a/arch/arm/plat-mxc/epit.c +++ b/arch/arm/plat-mxc/epit.c @@ -83,26 +83,12 @@ static void epit_irq_acknowledge(void) __raw_writel(EPITSR_OCIF, timer_base + EPITSR); } -static cycle_t epit_read(struct clocksource *cs) -{ - return 0 - __raw_readl(timer_base + EPITCNR); -} - -static struct clocksource clocksource_epit = { - .name = "epit", - .rating = 200, - .read = epit_read, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - static int __init epit_clocksource_init(struct clk *timer_clk) { unsigned int c = clk_get_rate(timer_clk); - clocksource_register_hz(&clocksource_epit, c); - - return 0; + return clocksource_mmio_init(timer_base + EPITCNR, "epit", c, 200, 32, + clocksource_mmio_readl_down); } /* clock event */ diff --git a/arch/arm/plat-nomadik/Kconfig b/arch/arm/plat-nomadik/Kconfig index 187f4e84bb2..18296ee6880 100644 --- a/arch/arm/plat-nomadik/Kconfig +++ b/arch/arm/plat-nomadik/Kconfig @@ -5,6 +5,7 @@ config PLAT_NOMADIK bool depends on ARCH_NOMADIK || ARCH_U8500 + select CLKSRC_MMIO default y help Common platform code for Nomadik and other ST-Ericsson diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index 41723402006..ef74e157a9d 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c @@ -25,29 +25,6 @@ void __iomem *mtu_base; /* Assigned by machine code */ -/* - * Kernel assumes that sched_clock can be called early - * but the MTU may not yet be initialized. - */ -static cycle_t nmdk_read_timer_dummy(struct clocksource *cs) -{ - return 0; -} - -/* clocksource: MTU decrements, so we negate the value being read. */ -static cycle_t nmdk_read_timer(struct clocksource *cs) -{ - return -readl(mtu_base + MTU_VAL(0)); -} - -static struct clocksource nmdk_clksrc = { - .name = "mtu_0", - .rating = 200, - .read = nmdk_read_timer_dummy, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - /* * Override the global weak sched_clock symbol with this * local implementation which uses the clocksource to get some @@ -172,12 +149,10 @@ void __init nmdk_timer_init(void) writel(0, mtu_base + MTU_BGLR(0)); writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0)); - /* Now the clock source is ready */ - nmdk_clksrc.read = nmdk_read_timer; - - if (clocksource_register_hz(&nmdk_clksrc, rate)) + if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0", + rate, 200, 32, clocksource_mmio_readl_down)) pr_err("timer: failed to initialize clock source %s\n", - nmdk_clksrc.name); + "mtu_0"); init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate); diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c index 742b0323c57..69a61367e4b 100644 --- a/arch/arm/plat-orion/time.c +++ b/arch/arm/plat-orion/time.c @@ -80,24 +80,6 @@ static void __init setup_sched_clock(unsigned long tclk) init_sched_clock(&cd, orion_update_sched_clock, 32, tclk); } -/* - * Clocksource handling. - */ -static cycle_t orion_clksrc_read(struct clocksource *cs) -{ - return 0xffffffff - readl(timer_base + TIMER0_VAL_OFF); -} - -static struct clocksource orion_clksrc = { - .name = "orion_clocksource", - .rating = 300, - .read = orion_clksrc_read, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - - - /* * Clockevent handling. */ @@ -247,7 +229,8 @@ orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask, writel(u & ~BRIDGE_INT_TIMER0, bridge_base + BRIDGE_MASK_OFF); u = readl(timer_base + TIMER_CTRL_OFF); writel(u | TIMER0_EN | TIMER0_RELOAD_EN, timer_base + TIMER_CTRL_OFF); - clocksource_register_hz(&orion_clksrc, tclk); + clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, "orion_clocksource", + tclk, 300, 32, clocksource_mmio_readl_down); /* * Setup clockevent timer (interrupt-driven). -- cgit v1.2.3-70-g09d2 From fb593cf38fc426331275d761fefe13096070f56a Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 May 2011 12:08:23 +0100 Subject: clocksource: ARM sp804: allow clocksource name to be specified This allows platforms to specify the clocksource name upon registration, which is necessary should they wish to register more than one sp804 clocksource. Acked-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/common/timer-sp.c | 4 ++-- arch/arm/include/asm/hardware/timer-sp.h | 2 +- arch/arm/mach-integrator/integrator_cp.c | 2 +- arch/arm/mach-realview/core.c | 2 +- arch/arm/mach-versatile/core.c | 2 +- arch/arm/mach-vexpress/ct-ca9x4.c | 2 +- arch/arm/mach-vexpress/v2m.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 445b05ee851..f6b9011744a 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -32,7 +32,7 @@ #define TIMER_FREQ_KHZ (1000) #define TIMER_RELOAD (TIMER_FREQ_KHZ * 1000 / HZ) -void __init sp804_clocksource_init(void __iomem *base) +void __init sp804_clocksource_init(void __iomem *base, const char *name) { /* setup timer 0 as free-running clocksource */ writel(0, base + TIMER_CTRL); @@ -41,7 +41,7 @@ void __init sp804_clocksource_init(void __iomem *base) writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, base + TIMER_CTRL); - clocksource_mmio_init(base + TIMER_VALUE, "timer3", + clocksource_mmio_init(base + TIMER_VALUE, name, TIMER_FREQ_KHZ * 1000, 200, 32, clocksource_mmio_readl_down); } diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h index 21e75e30d49..11c386bbbf3 100644 --- a/arch/arm/include/asm/hardware/timer-sp.h +++ b/arch/arm/include/asm/hardware/timer-sp.h @@ -1,2 +1,2 @@ -void sp804_clocksource_init(void __iomem *); +void sp804_clocksource_init(void __iomem *, const char *); void sp804_clockevents_init(void __iomem *, unsigned int); diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 9e3ce26023e..46fb7f580fe 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -476,7 +476,7 @@ static void __init intcp_timer_init(void) writel(0, TIMER1_VA_BASE + TIMER_CTRL); writel(0, TIMER2_VA_BASE + TIMER_CTRL); - sp804_clocksource_init(TIMER2_VA_BASE); + sp804_clocksource_init(TIMER2_VA_BASE, "timer2"); sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1); } diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 75dbc8791d0..6356b5e2e11 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -545,7 +545,7 @@ void __init realview_timer_init(unsigned int timer_irq) writel(0, timer2_va_base + TIMER_CTRL); writel(0, timer3_va_base + TIMER_CTRL); - sp804_clocksource_init(timer3_va_base); + sp804_clocksource_init(timer3_va_base, "timer3"); sp804_clockevents_init(timer0_va_base, timer_irq); } diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index eb7ffa0ee8b..aad6d395be4 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -764,7 +764,7 @@ static void __init versatile_timer_init(void) writel(0, TIMER2_VA_BASE + TIMER_CTRL); writel(0, TIMER3_VA_BASE + TIMER_CTRL); - sp804_clocksource_init(TIMER3_VA_BASE); + sp804_clocksource_init(TIMER3_VA_BASE, "timer3"); sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1); } diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index ebc22e75932..c833fd9505c 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -71,7 +71,7 @@ static void __init ct_ca9x4_timer_init(void) writel(0, MMIO_P2V(CT_CA9X4_TIMER0) + TIMER_CTRL); writel(0, MMIO_P2V(CT_CA9X4_TIMER1) + TIMER_CTRL); - sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1)); + sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1), "ct-timer1"); sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0); } diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index ba46e8e0743..ccf1f899ac2 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -65,7 +65,7 @@ static void __init v2m_timer_init(void) writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL); writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL); - sp804_clocksource_init(MMIO_P2V(V2M_TIMER1)); + sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1"); sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0); } -- cgit v1.2.3-70-g09d2 From 7ff550de99141cbd3be0129d563cc4554fdde9f6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 May 2011 13:31:48 +0100 Subject: clocksource: ARM sp804: obtain sp804 timer rate via clks This allows platforms to specify the rate of the SP804 clocksource via the clk subsystem. While ARM boards clock these at 1MHz, BCMRing also has SP804 timers but are clocked at different rates. Acked-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/common/timer-sp.c | 39 +++++++++++++++++++++++++++++++- arch/arm/mach-integrator/integrator_cp.c | 7 ++++++ arch/arm/mach-realview/core.c | 9 +++++++- arch/arm/mach-versatile/core.c | 9 +++++++- arch/arm/mach-vexpress/ct-ca9x4.c | 8 +++++++ arch/arm/mach-vexpress/v2m.c | 8 +++++++ 6 files changed, 77 insertions(+), 3 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index f6b9011744a..166f892a24d 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -18,8 +18,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include +#include #include #include #include @@ -32,8 +34,43 @@ #define TIMER_FREQ_KHZ (1000) #define TIMER_RELOAD (TIMER_FREQ_KHZ * 1000 / HZ) +static long __init sp804_get_clock_rate(const char *name) +{ + struct clk *clk; + long rate; + int err; + + clk = clk_get_sys("sp804", name); + if (IS_ERR(clk)) { + pr_err("sp804: %s clock not found: %d\n", name, + (int)PTR_ERR(clk)); + return PTR_ERR(clk); + } + + err = clk_enable(clk); + if (err) { + pr_err("sp804: %s clock failed to enable: %d\n", name, err); + clk_put(clk); + return err; + } + + rate = clk_get_rate(clk); + if (rate < 0) { + pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate); + clk_disable(clk); + clk_put(clk); + } + + return rate; +} + void __init sp804_clocksource_init(void __iomem *base, const char *name) { + long rate = sp804_get_clock_rate(name); + + if (rate < 0) + return; + /* setup timer 0 as free-running clocksource */ writel(0, base + TIMER_CTRL); writel(0xffffffff, base + TIMER_LOAD); @@ -42,7 +79,7 @@ void __init sp804_clocksource_init(void __iomem *base, const char *name) base + TIMER_CTRL); clocksource_mmio_init(base + TIMER_VALUE, name, - TIMER_FREQ_KHZ * 1000, 200, 32, clocksource_mmio_readl_down); + rate, 200, 32, clocksource_mmio_readl_down); } diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 46fb7f580fe..8fb8afb014e 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -229,10 +229,17 @@ static struct clk cp_auxclk = { .vcoreg = CM_AUXOSC, }; +static struct clk sp804_clk = { + .rate = 1000000, +}; + static struct clk_lookup cp_lookups[] = { { /* CLCD */ .dev_id = "mb:c0", .clk = &cp_auxclk, + }, { /* SP804 timers */ + .dev_id = "sp804", + .clk = &sp804_clk, }, }; diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 6356b5e2e11..6a9cd1eb4c2 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -315,6 +315,10 @@ static struct clk ref24_clk = { .rate = 24000000, }; +static struct clk sp804_clk = { + .rate = 1000000, +}; + static struct clk dummy_apb_pclk; static struct clk_lookup lookups[] = { @@ -357,7 +361,10 @@ static struct clk_lookup lookups[] = { }, { /* SSP */ .dev_id = "dev:ssp0", .clk = &ref24_clk, - } + }, { /* SP804 timers */ + .dev_id = "sp804", + .clk = &sp804_clk, + }, }; void __init realview_init_early(void) diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index aad6d395be4..b0b7de6875a 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -375,6 +375,10 @@ static struct clk ref24_clk = { .rate = 24000000, }; +static struct clk sp804_clk = { + .rate = 1000000, +}; + static struct clk dummy_apb_pclk; static struct clk_lookup lookups[] = { @@ -411,7 +415,10 @@ static struct clk_lookup lookups[] = { }, { /* CLCD */ .dev_id = "dev:20", .clk = &osc4_clk, - } + }, { /* SP804 timers */ + .dev_id = "sp804", + .clk = &sp804_clk, + }, }; /* diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index c833fd9505c..6004f06cbde 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -141,10 +141,18 @@ static struct clk osc1_clk = { .rate = 24000000, }; +static struct clk ct_sp804_clk = { + .rate = 1000000, +}; + static struct clk_lookup lookups[] = { { /* CLCD */ .dev_id = "ct:clcd", .clk = &osc1_clk, + }, { /* SP804 timers */ + .dev_id = "sp804", + .con_id = "ct-timer1", + .clk = &ct_sp804_clk, }, }; diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index ccf1f899ac2..77d5db3d780 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -333,6 +333,10 @@ static struct clk osc2_clk = { .rate = 24000000, }; +static struct clk v2m_sp804_clk = { + .rate = 1000000, +}; + static struct clk dummy_apb_pclk; static struct clk_lookup v2m_lookups[] = { @@ -363,6 +367,10 @@ static struct clk_lookup v2m_lookups[] = { }, { /* CLCD */ .dev_id = "mb:clcd", .clk = &osc1_clk, + }, { /* SP804 timers */ + .dev_id = "sp804", + .con_id = "v2m-timer1", + .clk = &v2m_sp804_clk, }, }; -- cgit v1.2.3-70-g09d2 From 57cc4f7de2b896ca79185e337eaf7ff9906c4656 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 May 2011 15:31:13 +0100 Subject: clockevents: ARM sp804: allow clockevent name to be specified This allows platforms to specify the clcokevent name upon registration. Acked-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/common/timer-sp.c | 9 +++++---- arch/arm/include/asm/hardware/timer-sp.h | 2 +- arch/arm/mach-integrator/integrator_cp.c | 2 +- arch/arm/mach-realview/core.c | 2 +- arch/arm/mach-versatile/core.c | 2 +- arch/arm/mach-vexpress/ct-ca9x4.c | 3 ++- arch/arm/mach-vexpress/v2m.c | 3 ++- 7 files changed, 13 insertions(+), 10 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 166f892a24d..5b7e8c9046b 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -139,7 +139,6 @@ static int sp804_set_next_event(unsigned long next, } static struct clock_event_device sp804_clockevent = { - .name = "timer0", .shift = 32, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_mode = sp804_set_mode, @@ -155,17 +154,19 @@ static struct irqaction sp804_timer_irq = { .dev_id = &sp804_clockevent, }; -void __init sp804_clockevents_init(void __iomem *base, unsigned int timer_irq) +void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, + const char *name) { struct clock_event_device *evt = &sp804_clockevent; clkevt_base = base; - evt->irq = timer_irq; + evt->name = name; + evt->irq = irq; evt->mult = div_sc(TIMER_FREQ_KHZ, NSEC_PER_MSEC, evt->shift); evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt); evt->min_delta_ns = clockevent_delta2ns(0xf, evt); - setup_irq(timer_irq, &sp804_timer_irq); + setup_irq(irq, &sp804_timer_irq); clockevents_register_device(evt); } diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h index 11c386bbbf3..4384d81eee7 100644 --- a/arch/arm/include/asm/hardware/timer-sp.h +++ b/arch/arm/include/asm/hardware/timer-sp.h @@ -1,2 +1,2 @@ void sp804_clocksource_init(void __iomem *, const char *); -void sp804_clockevents_init(void __iomem *, unsigned int); +void sp804_clockevents_init(void __iomem *, unsigned int, const char *); diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 8fb8afb014e..c4914c69462 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -484,7 +484,7 @@ static void __init intcp_timer_init(void) writel(0, TIMER2_VA_BASE + TIMER_CTRL); sp804_clocksource_init(TIMER2_VA_BASE, "timer2"); - sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1); + sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1, "timer1"); } static struct sys_timer cp_timer = { diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 6a9cd1eb4c2..9f5155507d2 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -553,7 +553,7 @@ void __init realview_timer_init(unsigned int timer_irq) writel(0, timer3_va_base + TIMER_CTRL); sp804_clocksource_init(timer3_va_base, "timer3"); - sp804_clockevents_init(timer0_va_base, timer_irq); + sp804_clockevents_init(timer0_va_base, timer_irq, "timer0"); } /* diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index b0b7de6875a..4e78c379c5c 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -772,7 +772,7 @@ static void __init versatile_timer_init(void) writel(0, TIMER3_VA_BASE + TIMER_CTRL); sp804_clocksource_init(TIMER3_VA_BASE, "timer3"); - sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1); + sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0"); } struct sys_timer versatile_timer = { diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index 6004f06cbde..27121338420 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -72,7 +72,8 @@ static void __init ct_ca9x4_timer_init(void) writel(0, MMIO_P2V(CT_CA9X4_TIMER1) + TIMER_CTRL); sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1), "ct-timer1"); - sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0); + sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0, + "ct-timer0"); } static struct sys_timer ct_ca9x4_timer = { diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 77d5db3d780..f6fecdd0fbe 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -66,7 +66,8 @@ static void __init v2m_timer_init(void) writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL); sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1"); - sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0); + sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0, + "v2m-timer0"); } static struct sys_timer v2m_timer = { -- cgit v1.2.3-70-g09d2 From 23828a7a976eb8dbe3b5f4e83584c3fe814b295b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 May 2011 15:45:16 +0100 Subject: clockevents: ARM sp804: obtain sp804 timer rate via clks This allows platforms to specify the rate of the SP804 clockevent via the clk subsystem. While ARM boards clock these at 1MHz, BCMRing also has SP804 timers but are clocked at different rates. Acked-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/common/timer-sp.c | 16 ++++++++-------- arch/arm/mach-vexpress/ct-ca9x4.c | 4 ++++ arch/arm/mach-vexpress/v2m.c | 4 ++++ 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 5b7e8c9046b..41df4787512 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -28,12 +28,6 @@ #include -/* - * These timers are currently always setup to be clocked at 1MHz. - */ -#define TIMER_FREQ_KHZ (1000) -#define TIMER_RELOAD (TIMER_FREQ_KHZ * 1000 / HZ) - static long __init sp804_get_clock_rate(const char *name) { struct clk *clk; @@ -84,6 +78,7 @@ void __init sp804_clocksource_init(void __iomem *base, const char *name) static void __iomem *clkevt_base; +static unsigned long clkevt_reload; /* * IRQ handler for the timer @@ -109,7 +104,7 @@ static void sp804_set_mode(enum clock_event_mode mode, switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - writel(TIMER_RELOAD, clkevt_base + TIMER_LOAD); + writel(clkevt_reload, clkevt_base + TIMER_LOAD); ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; break; @@ -158,12 +153,17 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, const char *name) { struct clock_event_device *evt = &sp804_clockevent; + long rate = sp804_get_clock_rate(name); + + if (rate < 0) + return; clkevt_base = base; + clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ); evt->name = name; evt->irq = irq; - evt->mult = div_sc(TIMER_FREQ_KHZ, NSEC_PER_MSEC, evt->shift); + evt->mult = div_sc(rate, NSEC_PER_SEC, evt->shift); evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt); evt->min_delta_ns = clockevent_delta2ns(0xf, evt); diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index 27121338420..2023a9e5211 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -150,6 +150,10 @@ static struct clk_lookup lookups[] = { { /* CLCD */ .dev_id = "ct:clcd", .clk = &osc1_clk, + }, { /* SP804 timers */ + .dev_id = "sp804", + .con_id = "ct-timer0", + .clk = &ct_sp804_clk, }, { /* SP804 timers */ .dev_id = "sp804", .con_id = "ct-timer1", diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index f6fecdd0fbe..9d9d4af384e 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -368,6 +368,10 @@ static struct clk_lookup v2m_lookups[] = { }, { /* CLCD */ .dev_id = "mb:clcd", .clk = &osc1_clk, + }, { /* SP804 timers */ + .dev_id = "sp804", + .con_id = "v2m-timer0", + .clk = &v2m_sp804_clk, }, { /* SP804 timers */ .dev_id = "sp804", .con_id = "v2m-timer1", -- cgit v1.2.3-70-g09d2