V2->V3: - Move updated irq_reg_{readl,writel} functions back into <linux/irq.h> so they can be called by irqchip drivers - Add gc->reg_{readl,writel} function pointers so that irqchip drivers like arch/sh/boards/mach-se/{7343,7722}/irq.c can override them - CC: linux-sh list in lieu of Paul's defunct linux-sh.org email address - Fix handling of zero L2 status in bcm7120-l2.c - Rebase on Linus' head of tree - Drop GENERIC_CHIP / GENERIC_CHIP_BE compile-time optimizations For the latter item, I ran a quick benchmark to see if the extra indirection in irq_reg_{readl,write} had any perceptible effect on register access times. The MIPS BE case did show a small performance hit from using the read wrapper, but on ARM LE the only differences were attributed to the presence/absence of a barrier: BCM3384 (UBUS architecture, MIPS BE, IRQ_GC_BE_IO): irq_reg_readl : 207 ns readl : 186 ns __raw_readl : 186 ns ioread32be : 195 ns irq_reg_writel : 177 ns writel : 177 ns __raw_writel : 177 ns iowrite32be : 177 ns BCM7445 (GISB architecture, ARM LE, standard LE readl): irq_reg_readl : 519 ns readl : 519 ns __raw_readl : 482 ns ioread32be : 519 ns irq_reg_writel : 500 ns writel : 500 ns __raw_writel : 482 ns iowrite32be : 500 ns Test code (do not merge): -- 8< -- diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index e7c6155..fcbe8e8 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -14,6 +14,8 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/kconfig.h> +#include <linux/ktime.h> +#include <linux/math64.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_irq.h> @@ -21,6 +23,7 @@ #include <linux/of_platform.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/irqflags.h> #include <linux/io.h> #include <linux/irqdomain.h> #include <linux/reboot.h> @@ -120,6 +123,8 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, return 0; } +static struct irq_chip_generic *some_gc; + int __init bcm7120_l2_intc_of_init(struct device_node *dn, struct device_node *parent) { @@ -213,6 +218,7 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn, for (idx = 0; idx < data->n_words; idx++) { irq = idx * IRQS_PER_WORD; gc = irq_get_domain_generic_chip(data->domain, irq); + some_gc = gc; gc->unused = 0xffffffff & ~data->irq_map_mask[idx]; gc->reg_base = data->base[idx]; @@ -253,3 +259,58 @@ out_unmap: } IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc", bcm7120_l2_intc_of_init); + +static const int iterations = 10000000; + +static void print_elapsed(const char *tag, ktime_t start) +{ + printk("%-20s: %lld ns\n", tag, + div64_u64(ktime_to_ns(ktime_sub(ktime_get(), start)), + iterations)); +} + +static int __init reg_timetest(void) +{ + int i; + ktime_t start; + struct irq_chip_generic *gc = some_gc; + + local_irq_disable(); + for (start = ktime_get(), i = 0; i < iterations; i++) + irq_reg_readl(gc, IRQSTAT); + print_elapsed("irq_reg_readl", start); + + for (start = ktime_get(), i = 0; i < iterations; i++) + readl(gc->reg_base + IRQSTAT); + print_elapsed("readl", start); + + for (start = ktime_get(), i = 0; i < iterations; i++) + __raw_readl(gc->reg_base + IRQSTAT); + print_elapsed("__raw_readl", start); + + for (start = ktime_get(), i = 0; i < iterations; i++) + ioread32be(gc->reg_base + IRQSTAT); + print_elapsed("ioread32be", start); + + printk("\n"); + + for (start = ktime_get(), i = 0; i < iterations; i++) + irq_reg_writel(gc, 0, IRQSTAT); + print_elapsed("irq_reg_writel", start); + + for (start = ktime_get(), i = 0; i < iterations; i++) + writel(0, gc->reg_base + IRQSTAT); + print_elapsed("writel", start); + + for (start = ktime_get(), i = 0; i < iterations; i++) + __raw_writel(0, gc->reg_base + IRQSTAT); + print_elapsed("__raw_writel", start); + + for (start = ktime_get(), i = 0; i < iterations; i++) + iowrite32be(0, gc->reg_base + IRQSTAT); + print_elapsed("iowrite32be", start); + local_irq_enable(); + + return 0; +} +device_initcall(reg_timetest); -- 8< -- Kevin Cernekee (14): sh: Eliminate unused irq_reg_{readl,writel} accessors genirq: Generic chip: Change irq_reg_{readl,writel} arguments genirq: Generic chip: Allow irqchip drivers to override irq_reg_{readl,writel} genirq: Generic chip: Add big endian I/O accessors irqchip: brcmstb-l2: Eliminate dependency on ARM code irqchip: bcm7120-l2: Eliminate bad IRQ check irqchip: bcm7120-l2, brcmstb-l2: Remove ARM Kconfig dependency irqchip: bcm7120-l2: Make sure all register accesses use base+offset irqchip: bcm7120-l2: Fix missing nibble in gc->unused mask irqchip: bcm7120-l2: Use gc->mask_cache to simplify suspend/resume functions irqchip: bcm7120-l2: Extend driver to support 64+ bit controllers irqchip: bcm7120-l2: Decouple driver from brcmstb-l2 irqchip: bcm7120-l2: Convert driver to use irq_reg_{readl,writel} irqchip: brcmstb-l2: Convert driver to use irq_reg_{readl,writel} .../interrupt-controller/brcm,bcm7120-l2-intc.txt | 26 ++- arch/arm/mach-bcm/Kconfig | 1 + arch/sh/boards/mach-se/7343/irq.c | 3 - arch/sh/boards/mach-se/7722/irq.c | 3 - drivers/irqchip/Kconfig | 6 +- drivers/irqchip/Makefile | 4 +- drivers/irqchip/irq-atmel-aic.c | 40 ++--- drivers/irqchip/irq-atmel-aic5.c | 65 ++++---- drivers/irqchip/irq-bcm7120-l2.c | 174 +++++++++++++-------- drivers/irqchip/irq-brcmstb-l2.c | 41 +++-- drivers/irqchip/irq-sunxi-nmi.c | 4 +- drivers/irqchip/irq-tb10x.c | 4 +- include/linux/irq.h | 29 +++- kernel/irq/generic-chip.c | 36 +++-- 14 files changed, 260 insertions(+), 176 deletions(-) -- 2.1.1