From c0a9f72c156baf1e88c33c6ba4450647af1b8804 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Mon, 12 Oct 2015 10:40:43 +0100 Subject: irqchip: irq-mips-gic: Provide function to map GIC user section The GIC provides a "user-mode visible" section containing a mirror of the counter registers which can be mapped into user memory. This will be used by the VDSO time function implementations, so provide a function to map it in. When the GIC is not enabled in Kconfig a dummy inline version of this function is provided, along with "#define gic_present 0", so that we don't have to litter the VDSO code with ifdefs. [markos.chandras@imgtec.com: - Move mapping code to arch/mips/kernel/vdso.c and use a resource type to get the GIC usermode information - Avoid renaming function arguments and use __gic_base_addr to hold the base GIC address prior to ioremap.] [ralf@linux-mips.org: Fix up gic_get_usm_range() to compile and make inline again.] Signed-off-by: Alex Smith Signed-off-by: Markos Chandras Reviewed-by: Marc Zyngier Cc: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Cc: Alex Smith Cc: Markos Chandras Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/11281/ Signed-off-by: Ralf Baechle --- drivers/irqchip/irq-mips-gic.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index aeaa061f0dbf..9e17ef27a183 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -29,6 +29,7 @@ struct gic_pcpu_mask { DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS); }; +static unsigned long __gic_base_addr; static void __iomem *gic_base; static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; static DEFINE_SPINLOCK(gic_lock); @@ -301,6 +302,17 @@ int gic_get_c0_fdc_int(void) GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC)); } +int gic_get_usm_range(struct resource *gic_usm_res) +{ + if (!gic_present) + return -1; + + gic_usm_res->start = __gic_base_addr + USM_VISIBLE_SECTION_OFS; + gic_usm_res->end = gic_usm_res->start + (USM_VISIBLE_SECTION_SIZE - 1); + + return 0; +} + static void gic_handle_shared_int(bool chained) { unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4; @@ -798,6 +810,8 @@ static void __init __gic_init(unsigned long gic_base_addr, { unsigned int gicconfig; + __gic_base_addr = gic_base_addr; + gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size); gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG)); -- cgit v1.2.3 From a7f4df4e21dd8a8dab96e88acd2c9c5017b83fc6 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 21 Oct 2015 09:57:44 +0100 Subject: MIPS: VDSO: Add implementations of gettimeofday() and clock_gettime() Add user-mode implementations of gettimeofday() and clock_gettime() to the VDSO. This is currently usable with 2 clocksources: the CP0 count register, which is accessible to user-mode via RDHWR on R2 and later cores, or the MIPS Global Interrupt Controller (GIC) timer, which provides a "user-mode visible" section containing a mirror of its counter registers. This section must be mapped into user memory, which is done below the VDSO data page. When a supported clocksource is not in use, the VDSO functions will return -ENOSYS, which causes libc to fall back on the standard syscall path. When support for neither of these clocksources is compiled into the kernel at all, the VDSO still provides clock_gettime(), as the coarse realtime/monotonic clocks can still be implemented. However, gettimeofday() is not provided in this case as nothing can be done without a suitable clocksource. This causes the symbol lookup to fail in libc and it will then always use the standard syscall path. This patch includes a workaround for a bug in QEMU which results in RDHWR on the CP0 count register always returning a constant (incorrect) value. A fix for this has been submitted, and the workaround can be removed after the fix has been in stable releases for a reasonable amount of time. A simple performance test which calls gettimeofday() 1000 times in a loop and calculates the average execution time gives the following results on a Malta + I6400 (running at 20MHz): - Syscall: ~31000 ns - VDSO (GIC): ~15000 ns - VDSO (CP0): ~9500 ns [markos.chandras@imgtec.com: - Minor code re-arrangements in order for mappings to be made in the order they appear to the process' address space. - Move do_{monotonic, realtime} outside of the MIPS_CLOCK_VSYSCALL ifdef - Use gic_get_usm_range so we can do the GIC mapping in the arch/mips/kernel/vdso instead of the GIC irqchip driver] Signed-off-by: Alex Smith Signed-off-by: Markos Chandras Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11338/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 02a1945e5093..89d3e4d7900c 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -140,9 +140,10 @@ static cycle_t gic_hpt_read(struct clocksource *cs) } static struct clocksource gic_clocksource = { - .name = "GIC", - .read = gic_hpt_read, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .name = "GIC", + .read = gic_hpt_read, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .archdata = { .vdso_clock_mode = VDSO_CLOCK_GIC }, }; static void __init __gic_clocksource_init(void) -- cgit v1.2.3