Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1234004 > unrolled thread

[PATCH 0/3] MIPS VDSO support

Started byMarkos Chandras <markos.chandras@imgtec.com>
First post2015-09-28 12:10 +0200
Last post2015-09-28 15:20 +0200
Articles 9 — 6 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/3] MIPS VDSO support Markos Chandras <markos.chandras@imgtec.com> - 2015-09-28 12:10 +0200
    [PATCH 3/3] MIPS: VDSO: Add implementations of gettimeofday() and clock_gettime() Markos Chandras <markos.chandras@imgtec.com> - 2015-09-28 12:20 +0200
    [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section Markos Chandras <markos.chandras@imgtec.com> - 2015-09-28 12:20 +0200
      Re: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC  user section Marc Zyngier <marc.zyngier@arm.com> - 2015-09-28 13:00 +0200
        Re: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC  user section Qais Yousef <qais.yousef@imgtec.com> - 2015-09-28 16:20 +0200
          Re: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC  user section Marc Zyngier <marc.zyngier@arm.com> - 2015-09-28 17:10 +0200
        Re: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC  user section Markos Chandras <Markos.Chandras@imgtec.com> - 2015-10-05 10:30 +0200
    Re: [PATCH 1/3] MIPS: Initial implementation of a VDSO Alex Smith <alex@alex-smith.me.uk> - 2015-09-28 13:00 +0200
      RE: [PATCH 1/3] MIPS: Initial implementation of a VDSO Matthew Fortune <Matthew.Fortune@imgtec.com> - 2015-09-28 15:20 +0200

#1234004 — [PATCH 0/3] MIPS VDSO support

FromMarkos Chandras <markos.chandras@imgtec.com>
Date2015-09-28 12:10 +0200
Subject[PATCH 0/3] MIPS VDSO support
Message-ID<qdDxE-2zm-11@gated-at.bofh.it>
Hi,

This series adds a proper VDSO to the kernel on MIPS. The first commit
adds the basic VDSO, replacing the current signal return trampoline
page. The following commits add user implementations of gettimeofday() and
clock_gettime() which can make use of either the CP0 count or the GIC
user-mode visible section.

A tree with these changes can be found at [1]. It's based on v4.3-rc3

Use of the time functions relies on glibc modifications. A patch for
this can be found in my repository at [2] and I will soon post it to the glibc
mailing list.

[1]: http://git.linux-mips.org/cgit/mchandras/linux.git/log/?h=4.3-vdso
[2]: https://github.com/hwoarang/glibc/tree/2.22-vdso

Alex Smith (3):
  MIPS: Initial implementation of a VDSO
  irqchip: irq-mips-gic: Provide function to map GIC user section
  MIPS: VDSO: Add implementations of gettimeofday() and clock_gettime()

 arch/mips/Kbuild                     |   1 +
 arch/mips/Kconfig                    |   5 +
 arch/mips/include/asm/abi.h          |   5 +-
 arch/mips/include/asm/clocksource.h  |  29 ++++
 arch/mips/include/asm/elf.h          |   7 +
 arch/mips/include/asm/processor.h    |   8 +-
 arch/mips/include/asm/vdso.h         | 139 +++++++++++++++--
 arch/mips/include/uapi/asm/Kbuild    |   2 +-
 arch/mips/include/uapi/asm/auxvec.h  |  17 ++
 arch/mips/kernel/csrc-r4k.c          |  44 ++++++
 arch/mips/kernel/signal.c            |  12 +-
 arch/mips/kernel/signal32.c          |   7 +-
 arch/mips/kernel/signal_n32.c        |   5 +-
 arch/mips/kernel/vdso.c              | 198 ++++++++++++++---------
 arch/mips/vdso/.gitignore            |   4 +
 arch/mips/vdso/Makefile              | 142 +++++++++++++++++
 arch/mips/vdso/elf.S                 |  68 ++++++++
 arch/mips/vdso/genvdso.c             | 294 +++++++++++++++++++++++++++++++++++
 arch/mips/vdso/genvdso.h             | 188 ++++++++++++++++++++++
 arch/mips/vdso/gettimeofday.c        | 232 +++++++++++++++++++++++++++
 arch/mips/vdso/sigreturn.S           |  49 ++++++
 arch/mips/vdso/vdso.h                |  84 ++++++++++
 arch/mips/vdso/vdso.lds.S            | 103 ++++++++++++
 drivers/clocksource/mips-gic-timer.c |   7 +-
 drivers/irqchip/irq-mips-gic.c       |  27 +++-
 include/linux/irqchip/mips-gic.h     |  24 ++-
 26 files changed, 1572 insertions(+), 129 deletions(-)
 create mode 100644 arch/mips/include/asm/clocksource.h
 create mode 100644 arch/mips/include/uapi/asm/auxvec.h
 create mode 100644 arch/mips/vdso/.gitignore
 create mode 100644 arch/mips/vdso/Makefile
 create mode 100644 arch/mips/vdso/elf.S
 create mode 100644 arch/mips/vdso/genvdso.c
 create mode 100644 arch/mips/vdso/genvdso.h
 create mode 100644 arch/mips/vdso/gettimeofday.c
 create mode 100644 arch/mips/vdso/sigreturn.S
 create mode 100644 arch/mips/vdso/vdso.h
 create mode 100644 arch/mips/vdso/vdso.lds.S

-- 
2.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1234009 — [PATCH 3/3] MIPS: VDSO: Add implementations of gettimeofday() and clock_gettime()

FromMarkos Chandras <markos.chandras@imgtec.com>
Date2015-09-28 12:20 +0200
Subject[PATCH 3/3] MIPS: VDSO: Add implementations of gettimeofday() and clock_gettime()
Message-ID<qdDHj-2KC-17@gated-at.bofh.it>
In reply to#1234004
From: Alex Smith <alex.smith@imgtec.com>

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]

Cc: linux-kernel@vger.kernel.org
Signed-off-by: Alex Smith <alex.smith@imgtec.com>
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
---
 arch/mips/Kconfig                    |   5 +
 arch/mips/include/asm/clocksource.h  |  29 +++++
 arch/mips/include/asm/vdso.h         |  68 +++++++++-
 arch/mips/kernel/csrc-r4k.c          |  44 +++++++
 arch/mips/kernel/vdso.c              |  62 +++++++++-
 arch/mips/vdso/Makefile              |   2 +-
 arch/mips/vdso/gettimeofday.c        | 232 +++++++++++++++++++++++++++++++++++
 arch/mips/vdso/vdso.h                |   9 ++
 arch/mips/vdso/vdso.lds.S            |   3 +
 drivers/clocksource/mips-gic-timer.c |   7 +-
 10 files changed, 450 insertions(+), 11 deletions(-)
 create mode 100644 arch/mips/include/asm/clocksource.h
 create mode 100644 arch/mips/vdso/gettimeofday.c

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e3aa5b0b4ef1..68f4f246887c 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -60,6 +60,8 @@ config MIPS
 	select SYSCTL_EXCEPTION_TRACE
 	select HAVE_VIRT_CPU_ACCOUNTING_GEN
 	select HAVE_IRQ_TIME_ACCOUNTING
+	select GENERIC_TIME_VSYSCALL
+	select ARCH_CLOCKSOURCE_DATA
 
 menu "Machine selection"
 
@@ -1036,6 +1038,9 @@ config CSRC_R4K
 config CSRC_SB1250
 	bool
 
+config MIPS_CLOCK_VSYSCALL
+	def_bool CSRC_R4K || CLKSRC_MIPS_GIC
+
 config GPIO_TXX9
 	select ARCH_REQUIRE_GPIOLIB
 	bool
diff --git a/arch/mips/include/asm/clocksource.h b/arch/mips/include/asm/clocksource.h
new file mode 100644
index 000000000000..3deb1d0c1a94
--- /dev/null
+++ b/arch/mips/include/asm/clocksource.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * 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.
+ */
+
+#ifndef __ASM_CLOCKSOURCE_H
+#define __ASM_CLOCKSOURCE_H
+
+#include <linux/types.h>
+
+/* VDSO clocksources. */
+#define VDSO_CLOCK_NONE		0	/* No suitable clocksource. */
+#define VDSO_CLOCK_R4K		1	/* Use the coprocessor 0 count. */
+#define VDSO_CLOCK_GIC		2	/* Use the GIC. */
+
+/**
+ * struct arch_clocksource_data - Architecture-specific clocksource information.
+ * @vdso_clock_mode: Method the VDSO should use to access the clocksource.
+ */
+struct arch_clocksource_data {
+	u8 vdso_clock_mode;
+};
+
+#endif /* __ASM_CLOCKSOURCE_H */
diff --git a/arch/mips/include/asm/vdso.h b/arch/mips/include/asm/vdso.h
index db2d45be8f2e..8f4ca5dd992b 100644
--- a/arch/mips/include/asm/vdso.h
+++ b/arch/mips/include/asm/vdso.h
@@ -13,6 +13,8 @@
 
 #include <linux/mm_types.h>
 
+#include <asm/barrier.h>
+
 /**
  * struct mips_vdso_image - Details of a VDSO image.
  * @data: Pointer to VDSO image data (page-aligned).
@@ -53,18 +55,82 @@ extern struct mips_vdso_image vdso_image_n32;
 
 /**
  * union mips_vdso_data - Data provided by the kernel for the VDSO.
+ * @xtime_sec:		Current real time (seconds part).
+ * @xtime_nsec:		Current real time (nanoseconds part, shifted).
+ * @wall_to_mono_sec:	Wall-to-monotonic offset (seconds part).
+ * @wall_to_mono_nsec:	Wall-to-monotonic offset (nanoseconds part).
+ * @seq_count:		Counter to synchronise updates (odd = updating).
+ * @cs_shift:		Clocksource shift value.
+ * @clock_mode:		Clocksource to use for time functions.
+ * @cs_mult:		Clocksource multiplier value.
+ * @cs_cycle_last:	Clock cycle value at last update.
+ * @cs_mask:		Clocksource mask value.
+ * @tz_minuteswest:	Minutes west of Greenwich (from timezone).
+ * @tz_dsttime:		Type of DST correction (from timezone).
  *
  * This structure contains data needed by functions within the VDSO. It is
- * populated by the kernel and mapped read-only into user memory.
+ * populated by the kernel and mapped read-only into user memory. The time
+ * fields are mirrors of internal data from the timekeeping infrastructure.
  *
  * Note: Care should be taken when modifying as the layout must remain the same
  * for both 64- and 32-bit (for 32-bit userland on 64-bit kernel).
  */
 union mips_vdso_data {
 	struct {
+		u64 xtime_sec;
+		u64 xtime_nsec;
+		u32 wall_to_mono_sec;
+		u32 wall_to_mono_nsec;
+		u32 seq_count;
+		u32 cs_shift;
+		u8 clock_mode;
+		u32 cs_mult;
+		u64 cs_cycle_last;
+		u64 cs_mask;
+		s32 tz_minuteswest;
+		s32 tz_dsttime;
 	};
 
 	u8 page[PAGE_SIZE];
 };
 
+static inline u32 vdso_data_read_begin(const union mips_vdso_data *data)
+{
+	u32 seq;
+
+	while (true) {
+		seq = ACCESS_ONCE(data->seq_count);
+		if (likely(!(seq & 1))) {
+			/* Paired with smp_wmb() in vdso_data_write_*(). */
+			smp_rmb();
+			return seq;
+		}
+
+		cpu_relax();
+	}
+}
+
+static inline bool vdso_data_read_retry(const union mips_vdso_data *data,
+					u32 start_seq)
+{
+	/* Paired with smp_wmb() in vdso_data_write_*(). */
+	smp_rmb();
+	return unlikely(data->seq_count != start_seq);
+}
+
+static inline void vdso_data_write_begin(union mips_vdso_data *data)
+{
+	++data->seq_count;
+
+	/* Ensure sequence update is written before other data page values. */
+	smp_wmb();
+}
+
+static inline void vdso_data_write_end(union mips_vdso_data *data)
+{
+	/* Ensure data values are written before updating sequence again. */
+	smp_wmb();
+	++data->seq_count;
+}
+
 #endif /* __ASM_VDSO_H */
diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c
index e5ed7ada1433..1f910563fdf6 100644
--- a/arch/mips/kernel/csrc-r4k.c
+++ b/arch/mips/kernel/csrc-r4k.c
@@ -28,6 +28,43 @@ static u64 notrace r4k_read_sched_clock(void)
 	return read_c0_count();
 }
 
+static inline unsigned int rdhwr_count(void)
+{
+	unsigned int count;
+
+	__asm__ __volatile__(
+	"	.set push\n"
+	"	.set mips32r2\n"
+	"	rdhwr	%0, $2\n"
+	"	.set pop\n"
+	: "=r" (count));
+
+	return count;
+}
+
+static bool rdhwr_count_usable(void)
+{
+	unsigned int prev, curr, i;
+
+	/*
+	 * Older QEMUs have a broken implementation of RDHWR for the CP0 count
+	 * which always returns a constant value. Try to identify this and don't
+	 * use it in the VDSO if it is broken. This workaround can be removed
+	 * once the fix has been in QEMU stable for a reasonable amount of time.
+	 */
+	for (i = 0, prev = rdhwr_count(); i < 100; i++) {
+		curr = rdhwr_count();
+
+		if (curr != prev)
+			return true;
+
+		prev = curr;
+	}
+
+	pr_warn("Not using R4K clocksource in VDSO due to broken RDHWR\n");
+	return false;
+}
+
 int __init init_r4k_clocksource(void)
 {
 	if (!cpu_has_counter || !mips_hpt_frequency)
@@ -36,6 +73,13 @@ int __init init_r4k_clocksource(void)
 	/* Calculate a somewhat reasonable rating value */
 	clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
 
+	/*
+	 * R2 onwards makes the count accessible to user mode so it can be used
+	 * by the VDSO (HWREna is configured by configure_hwrena()).
+	 */
+	if (cpu_has_mips_r2_r6 && rdhwr_count_usable())
+		clocksource_mips.archdata.vdso_clock_mode = VDSO_CLOCK_R4K;
+
 	clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
 
 	sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
index 56cc3c4377fb..7894db0c7922 100644
--- a/arch/mips/kernel/vdso.c
+++ b/arch/mips/kernel/vdso.c
@@ -12,9 +12,11 @@
 #include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/irqchip/mips-gic.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/timekeeper_internal.h>
 
 #include <asm/abi.h>
 #include <asm/vdso.h>
@@ -23,7 +25,7 @@
 static union mips_vdso_data vdso_data __page_aligned_data;
 
 /*
- * Mapping for the VDSO data pages. The real pages are mapped manually, as
+ * Mapping for the VDSO data/GIC pages. The real pages are mapped manually, as
  * what we map and where within the area they are mapped is determined at
  * runtime.
  */
@@ -64,25 +66,66 @@ static int __init init_vdso(void)
 }
 subsys_initcall(init_vdso);
 
+void update_vsyscall(struct timekeeper *tk)
+{
+	vdso_data_write_begin(&vdso_data);
+
+	vdso_data.xtime_sec = tk->xtime_sec;
+	vdso_data.xtime_nsec = tk->tkr_mono.xtime_nsec;
+	vdso_data.wall_to_mono_sec = tk->wall_to_monotonic.tv_sec;
+	vdso_data.wall_to_mono_nsec = tk->wall_to_monotonic.tv_nsec;
+	vdso_data.cs_shift = tk->tkr_mono.shift;
+
+	vdso_data.clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode;
+	if (vdso_data.clock_mode != VDSO_CLOCK_NONE) {
+		vdso_data.cs_mult = tk->tkr_mono.mult;
+		vdso_data.cs_cycle_last = tk->tkr_mono.cycle_last;
+		vdso_data.cs_mask = tk->tkr_mono.mask;
+	}
+
+	vdso_data_write_end(&vdso_data);
+}
+
+void update_vsyscall_tz(void)
+{
+	if (vdso_data.clock_mode != VDSO_CLOCK_NONE) {
+		vdso_data.tz_minuteswest = sys_tz.tz_minuteswest;
+		vdso_data.tz_dsttime = sys_tz.tz_dsttime;
+	}
+}
+
 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mips_vdso_image *image = current->thread.abi->vdso;
 	struct mm_struct *mm = current->mm;
-	unsigned long base, vdso_addr;
+	unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr;
 	struct vm_area_struct *vma;
 	int ret;
 
 	down_write(&mm->mmap_sem);
 
-	base = get_unmapped_area(NULL, 0, PAGE_SIZE + image->size, 0, 0);
+	/*
+	 * Determine total area size. This includes the VDSO data itself, the
+	 * data page, and the GIC user page if present. Always create a mapping
+	 * for the GIC user area if the GIC is present regardless of whether it
+	 * is the current clocksource, in case it comes into use later on. We
+	 * only map a page even though the total area is 64K, as we only need
+	 * the counter registers at the start.
+	 */
+	gic_size = gic_present ? PAGE_SIZE : 0;
+	vvar_size = gic_size + PAGE_SIZE;
+	size = vvar_size + image->size;
+
+	base = get_unmapped_area(NULL, 0, size, 0, 0);
 	if (IS_ERR_VALUE(base)) {
 		ret = base;
 		goto out;
 	}
 
-	vdso_addr = base + PAGE_SIZE;
+	data_addr = base + gic_size;
+	vdso_addr = data_addr + PAGE_SIZE;
 
-	vma = _install_special_mapping(mm, base, PAGE_SIZE,
+	vma = _install_special_mapping(mm, base, vvar_size,
 				       VM_READ | VM_MAYREAD,
 				       &vdso_vvar_mapping);
 	if (IS_ERR(vma)) {
@@ -90,8 +133,15 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 		goto out;
 	}
 
+	/* Map GIC user page. */
+	if (gic_size) {
+		ret = gic_map_user_section(vma, base, gic_size);
+		if (ret)
+			goto out;
+	}
+
 	/* Map data page. */
-	ret = remap_pfn_range(vma, base,
+	ret = remap_pfn_range(vma, data_addr,
 			      virt_to_phys(&vdso_data) >> PAGE_SHIFT,
 			      PAGE_SIZE, PAGE_READONLY);
 	if (ret)
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile
index 9a8a6b373eb0..c2820997ea9b 100644
--- a/arch/mips/vdso/Makefile
+++ b/arch/mips/vdso/Makefile
@@ -1,5 +1,5 @@
 # Objects to go into the VDSO.
-obj-vdso-y := elf.o sigreturn.o
+obj-vdso-y := elf.o gettimeofday.o sigreturn.o
 
 # Common compiler flags between ABIs.
 ccflags-vdso := \
diff --git a/arch/mips/vdso/gettimeofday.c b/arch/mips/vdso/gettimeofday.c
new file mode 100644
index 000000000000..ce89c9e294f9
--- /dev/null
+++ b/arch/mips/vdso/gettimeofday.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * 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.
+ */
+
+#include "vdso.h"
+
+#include <linux/compiler.h>
+#include <linux/irqchip/mips-gic.h>
+#include <linux/time.h>
+
+#include <asm/clocksource.h>
+#include <asm/io.h>
+#include <asm/mips-cm.h>
+#include <asm/unistd.h>
+#include <asm/vdso.h>
+
+static __always_inline int do_realtime_coarse(struct timespec *ts,
+					      const union mips_vdso_data *data)
+{
+	u32 start_seq;
+
+	do {
+		start_seq = vdso_data_read_begin(data);
+
+		ts->tv_sec = data->xtime_sec;
+		ts->tv_nsec = data->xtime_nsec >> data->cs_shift;
+	} while (vdso_data_read_retry(data, start_seq));
+
+	return 0;
+}
+
+static __always_inline int do_monotonic_coarse(struct timespec *ts,
+					       const union mips_vdso_data *data)
+{
+	u32 start_seq;
+	u32 to_mono_sec;
+	u32 to_mono_nsec;
+
+	do {
+		start_seq = vdso_data_read_begin(data);
+
+		ts->tv_sec = data->xtime_sec;
+		ts->tv_nsec = data->xtime_nsec >> data->cs_shift;
+
+		to_mono_sec = data->wall_to_mono_sec;
+		to_mono_nsec = data->wall_to_mono_nsec;
+	} while (vdso_data_read_retry(data, start_seq));
+
+	ts->tv_sec += to_mono_sec;
+	timespec_add_ns(ts, to_mono_nsec);
+
+	return 0;
+}
+
+#ifdef CONFIG_CSRC_R4K
+
+static __always_inline u64 read_r4k_count(void)
+{
+	unsigned int count;
+
+	__asm__ __volatile__(
+	"	.set push\n"
+	"	.set mips32r2\n"
+	"	rdhwr	%0, $2\n"
+	"	.set pop\n"
+	: "=r" (count));
+
+	return count;
+}
+
+#endif
+
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+
+static __always_inline u64 read_gic_count(const union mips_vdso_data *data)
+{
+	void __iomem *gic = get_gic(data);
+	u32 hi, hi2, lo;
+
+	do {
+		hi = __raw_readl(gic + GIC_UMV_SH_COUNTER_63_32_OFS);
+		lo = __raw_readl(gic + GIC_UMV_SH_COUNTER_31_00_OFS);
+		hi2 = __raw_readl(gic + GIC_UMV_SH_COUNTER_63_32_OFS);
+	} while (hi2 != hi);
+
+	return (((u64)hi) << 32) + lo;
+}
+
+#endif
+
+static __always_inline u64 get_ns(const union mips_vdso_data *data)
+{
+	u64 cycle_now, delta, nsec;
+
+	switch (data->clock_mode) {
+#ifdef CONFIG_CSRC_R4K
+	case VDSO_CLOCK_R4K:
+		cycle_now = read_r4k_count();
+		break;
+#endif
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+	case VDSO_CLOCK_GIC:
+		cycle_now = read_gic_count(data);
+		break;
+#endif
+	default:
+		return 0;
+	}
+
+	delta = (cycle_now - data->cs_cycle_last) & data->cs_mask;
+
+	nsec = (delta * data->cs_mult) + data->xtime_nsec;
+	nsec >>= data->cs_shift;
+
+	return nsec;
+}
+
+static __always_inline int do_realtime(struct timespec *ts,
+				       const union mips_vdso_data *data)
+{
+	u32 start_seq;
+	u64 ns;
+
+	do {
+		start_seq = vdso_data_read_begin(data);
+
+		if (data->clock_mode == VDSO_CLOCK_NONE)
+			return -ENOSYS;
+
+		ts->tv_sec = data->xtime_sec;
+		ns = get_ns(data);
+	} while (vdso_data_read_retry(data, start_seq));
+
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, ns);
+
+	return 0;
+}
+
+static __always_inline int do_monotonic(struct timespec *ts,
+					const union mips_vdso_data *data)
+{
+	u32 start_seq;
+	u64 ns;
+	u32 to_mono_sec;
+	u32 to_mono_nsec;
+
+	do {
+		start_seq = vdso_data_read_begin(data);
+
+		if (data->clock_mode == VDSO_CLOCK_NONE)
+			return -ENOSYS;
+
+		ts->tv_sec = data->xtime_sec;
+		ns = get_ns(data);
+
+		to_mono_sec = data->wall_to_mono_sec;
+		to_mono_nsec = data->wall_to_mono_nsec;
+	} while (vdso_data_read_retry(data, start_seq));
+
+	ts->tv_sec += to_mono_sec;
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, ns + to_mono_nsec);
+
+	return 0;
+}
+
+#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
+
+/*
+ * This is behind the ifdef so that we don't provide the symbol when there's no
+ * possibility of there being a usable clocksource, because there's nothing we
+ * can do without it. When libc fails the symbol lookup it should fall back on
+ * the standard syscall path.
+ */
+int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	const union mips_vdso_data *data = get_vdso_data();
+	struct timespec ts;
+	int ret;
+
+	ret = do_realtime(&ts, data);
+	if (ret)
+		return ret;
+
+	if (tv) {
+		tv->tv_sec = ts.tv_sec;
+		tv->tv_usec = ts.tv_nsec / 1000;
+	}
+
+	if (tz) {
+		tz->tz_minuteswest = data->tz_minuteswest;
+		tz->tz_dsttime = data->tz_dsttime;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_CLKSRC_MIPS_GIC */
+
+int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+	const union mips_vdso_data *data = get_vdso_data();
+	int ret;
+
+	switch (clkid) {
+	case CLOCK_REALTIME_COARSE:
+		ret = do_realtime_coarse(ts, data);
+		break;
+	case CLOCK_MONOTONIC_COARSE:
+		ret = do_monotonic_coarse(ts, data);
+		break;
+	case CLOCK_REALTIME:
+		ret = do_realtime(ts, data);
+		break;
+	case CLOCK_MONOTONIC:
+		ret = do_monotonic(ts, data);
+		break;
+	default:
+		ret = -ENOSYS;
+		break;
+	}
+
+	/* If we return -ENOSYS libc should fall back to a syscall. */
+	return ret;
+}
diff --git a/arch/mips/vdso/vdso.h b/arch/mips/vdso/vdso.h
index 64b98967e245..1072f8634417 100644
--- a/arch/mips/vdso/vdso.h
+++ b/arch/mips/vdso/vdso.h
@@ -76,4 +76,13 @@ static inline const union mips_vdso_data *get_vdso_data(void)
 	return (const union mips_vdso_data *)(get_vdso_base() - PAGE_SIZE);
 }
 
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+
+static inline void __iomem *get_gic(const union mips_vdso_data *data)
+{
+	return (void __iomem *)data - PAGE_SIZE;
+}
+
+#endif /* CONFIG_CLKSRC_MIPS_GIC */
+
 #endif /* __ASSEMBLY__ */
diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S
index 21655b6fefc5..0bda37c5a1e6 100644
--- a/arch/mips/vdso/vdso.lds.S
+++ b/arch/mips/vdso/vdso.lds.S
@@ -95,6 +95,9 @@ PHDRS
 VERSION
 {
 	LINUX_2.6 {
+	global:
+		__vdso_clock_gettime;
+		__vdso_gettimeofday;
 	local: *;
 	};
 }
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)
-- 
2.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234011 — [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section

FromMarkos Chandras <markos.chandras@imgtec.com>
Date2015-09-28 12:20 +0200
Subject[PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section
Message-ID<qdDHj-2KC-11@gated-at.bofh.it>
In reply to#1234004
From: Alex Smith <alex.smith@imgtec.com>

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.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Alex Smith <alex.smith@imgtec.com>
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
---
 drivers/irqchip/irq-mips-gic.c   | 27 +++++++++++++++++++++------
 include/linux/irqchip/mips-gic.h | 24 ++++++++++++++++++++++--
 2 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index af2f16bb8a94..c995b199ca32 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -13,6 +13,7 @@
 #include <linux/irq.h>
 #include <linux/irqchip.h>
 #include <linux/irqchip/mips-gic.h>
+#include <linux/mm.h>
 #include <linux/of_address.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
@@ -29,6 +30,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 +303,19 @@ int gic_get_c0_fdc_int(void)
 				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
 }
 
+int gic_map_user_section(struct vm_area_struct *vma, unsigned long base,
+			 unsigned long size)
+{
+	unsigned long pfn;
+
+	BUG_ON(!gic_present);
+	BUG_ON(size > USM_VISIBLE_SECTION_SIZE);
+
+	pfn = (gic_base_addr + USM_VISIBLE_SECTION_OFS) >> PAGE_SHIFT;
+	return io_remap_pfn_range(vma, base, pfn, size,
+				  pgprot_noncached(PAGE_READONLY));
+}
+
 static void gic_handle_shared_int(bool chained)
 {
 	unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4;
@@ -783,14 +798,15 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
 	.xlate = gic_irq_domain_xlate,
 };
 
-static void __init __gic_init(unsigned long gic_base_addr,
-			      unsigned long gic_addrspace_size,
+static void __init __gic_init(unsigned long base_addr,
+			      unsigned long addrspace_size,
 			      unsigned int cpu_vec, unsigned int irqbase,
 			      struct device_node *node)
 {
 	unsigned int gicconfig;
 
-	gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size);
+	gic_base_addr = base_addr;
+	gic_base = ioremap_nocache(base_addr, addrspace_size);
 
 	gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
 	gic_shared_intrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
@@ -847,11 +863,10 @@ static void __init __gic_init(unsigned long gic_base_addr,
 	gic_ipi_init();
 }
 
-void __init gic_init(unsigned long gic_base_addr,
-		     unsigned long gic_addrspace_size,
+void __init gic_init(unsigned long base_addr, unsigned long addrspace_size,
 		     unsigned int cpu_vec, unsigned int irqbase)
 {
-	__gic_init(gic_base_addr, gic_addrspace_size, cpu_vec, irqbase, NULL);
+	__gic_init(base_addr, addrspace_size, cpu_vec, irqbase, NULL);
 }
 
 static int __init gic_of_init(struct device_node *node,
diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h
index 4e6861605050..68f2e9539204 100644
--- a/include/linux/irqchip/mips-gic.h
+++ b/include/linux/irqchip/mips-gic.h
@@ -245,10 +245,14 @@
 #define GIC_SHARED_TO_HWIRQ(x)	(GIC_SHARED_HWIRQ_BASE + (x))
 #define GIC_HWIRQ_TO_SHARED(x)	((x) - GIC_SHARED_HWIRQ_BASE)
 
+struct vm_area_struct;
+
+#ifdef CONFIG_MIPS_GIC
+
 extern unsigned int gic_present;
 
-extern void gic_init(unsigned long gic_base_addr,
-	unsigned long gic_addrspace_size, unsigned int cpu_vec,
+extern void gic_init(unsigned long base_addr,
+	unsigned long addrspace_size, unsigned int cpu_vec,
 	unsigned int irqbase);
 extern void gic_clocksource_init(unsigned int);
 extern cycle_t gic_read_count(void);
@@ -264,4 +268,20 @@ extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
 extern int gic_get_c0_compare_int(void);
 extern int gic_get_c0_perfcount_int(void);
 extern int gic_get_c0_fdc_int(void);
+extern int gic_map_user_section(struct vm_area_struct *vma, unsigned long base,
+				unsigned long size);
+
+#else /* CONFIG_MIPS_GIC */
+
+#define gic_present	0
+
+static inline int gic_map_user_section(struct vm_area_struct *vma,
+				       unsigned long base, unsigned long size)
+{
+	/* Shouldn't be called. */
+	return -1;
+}
+
+#endif /* CONFIG_MIPS_GIC */
+
 #endif /* __LINUX_IRQCHIP_MIPS_GIC_H */
-- 
2.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234050 — Re: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section

FromMarc Zyngier <marc.zyngier@arm.com>
Date2015-09-28 13:00 +0200
SubjectRe: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section
Message-ID<qdEk3-3tU-25@gated-at.bofh.it>
In reply to#1234011
On 28/09/15 11:11, Markos Chandras wrote:
> From: Alex Smith <alex.smith@imgtec.com>
> 
> 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.
> 
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Jason Cooper <jason@lakedaemon.net>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Alex Smith <alex.smith@imgtec.com>
> Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
> ---
>  drivers/irqchip/irq-mips-gic.c   | 27 +++++++++++++++++++++------
>  include/linux/irqchip/mips-gic.h | 24 ++++++++++++++++++++++--
>  2 files changed, 43 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
> index af2f16bb8a94..c995b199ca32 100644
> --- a/drivers/irqchip/irq-mips-gic.c
> +++ b/drivers/irqchip/irq-mips-gic.c
> @@ -13,6 +13,7 @@
>  #include <linux/irq.h>
>  #include <linux/irqchip.h>
>  #include <linux/irqchip/mips-gic.h>
> +#include <linux/mm.h>
>  #include <linux/of_address.h>
>  #include <linux/sched.h>
>  #include <linux/smp.h>
> @@ -29,6 +30,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 +303,19 @@ int gic_get_c0_fdc_int(void)
>  				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
>  }
>  
> +int gic_map_user_section(struct vm_area_struct *vma, unsigned long base,
> +			 unsigned long size)
> +{
> +	unsigned long pfn;
> +
> +	BUG_ON(!gic_present);

Why do you have a BUG() here, while you're just returning -1 in the case
where CONFIG_MIPS_GIC is not refined? This feels overly harsh to me.

> +	BUG_ON(size > USM_VISIBLE_SECTION_SIZE);

Same here.

> +
> +	pfn = (gic_base_addr + USM_VISIBLE_SECTION_OFS) >> PAGE_SHIFT;
> +	return io_remap_pfn_range(vma, base, pfn, size,
> +				  pgprot_noncached(PAGE_READONLY));

Two things:

- I suppose you are comfortable with making this region accessible to
userspace (obviously). Not knowing anything about it, is it guaranteed
not to trigger any unpleasant event even if the luser tries to play
dirty tricks on it (like doing unaligned or exclusive access)?

- Does this code have to be in the irqchip driver? It really feels out
of place, and I'd rather see a function that returns the mappable range
to the VDSO code, where the mapping would occur.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234197 — Re: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section

FromQais Yousef <qais.yousef@imgtec.com>
Date2015-09-28 16:20 +0200
SubjectRe: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section
Message-ID<qdHrB-1Q9-33@gated-at.bofh.it>
In reply to#1234050
On 09/28/2015 11:55 AM, Marc Zyngier wrote:
> On 28/09/15 11:11, Markos Chandras wrote:
>
>> +
>> +	pfn = (gic_base_addr + USM_VISIBLE_SECTION_OFS) >> PAGE_SHIFT;
>> +	return io_remap_pfn_range(vma, base, pfn, size,
>> +				  pgprot_noncached(PAGE_READONLY));
>
> - Does this code have to be in the irqchip driver? It really feels out
> of place, and I'd rather see a function that returns the mappable range
> to the VDSO code, where the mapping would occur.
>


I don't think it's a good idea either for the VDSO code to know about 
gic_base_addr. Maybe this function could be split to return the pfn and 
let the caller do io_remap_pfn_range(). Though I think it's nice to have 
it all there. USM stands for USer Mode - GIC wants to make some stuff 
visible to user mode and it puts them in that special section. So it 
makes sense to do it all there IMO.

Qais
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234244 — Re: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section

FromMarc Zyngier <marc.zyngier@arm.com>
Date2015-09-28 17:10 +0200
SubjectRe: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section
Message-ID<qdIdY-301-25@gated-at.bofh.it>
In reply to#1234197
On 28/09/15 15:16, Qais Yousef wrote:
> On 09/28/2015 11:55 AM, Marc Zyngier wrote:
>> On 28/09/15 11:11, Markos Chandras wrote:
>>
>>> +
>>> +	pfn = (gic_base_addr + USM_VISIBLE_SECTION_OFS) >> PAGE_SHIFT;
>>> +	return io_remap_pfn_range(vma, base, pfn, size,
>>> +				  pgprot_noncached(PAGE_READONLY));
>>
>> - Does this code have to be in the irqchip driver? It really feels out
>> of place, and I'd rather see a function that returns the mappable range
>> to the VDSO code, where the mapping would occur.
>>
> 
> 
> I don't think it's a good idea either for the VDSO code to know about 
> gic_base_addr. Maybe this function could be split to return the pfn and 
> let the caller do io_remap_pfn_range(). Though I think it's nice to have 
> it all there. USM stands for USer Mode - GIC wants to make some stuff 
> visible to user mode and it puts them in that special section. So it 
> makes sense to do it all there IMO.

Maybe I wasn't clear enough. My suggestion was to expose this in
the VDSO setup code:

@@ -90,8 +133,15 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 		goto out;
 	}
 
+	/* Map GIC user page. */
+	if (gic_size) {
+		ret = gic_map_user_section(vma, base, gic_size);
+		if (ret)
+			goto out;
+	}
+

This could easily be written as:

	if (gic_size) {
		struct resource gic_res;
		ret = gic_get_usm_range(&gic_res);
		if (ret)
			goto out;
		... and perform the mapping here...
	}

You can also rewrite the hunks above to actually get the present/size
information from the GIC. And if you have DT, you should be able to
directly find the memory region there, without involving the GIC
driver at all.

I don't really fancy having some userspace visible stuff in an
interrupt controller driver, and I tend to find it nicer to split
the responsabilities: the VDSO code deals with the userspace mapping,
and the interrupt controller deals with interrupts.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1239347 — Re: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section

FromMarkos Chandras <Markos.Chandras@imgtec.com>
Date2015-10-05 10:30 +0200
SubjectRe: [PATCH 2/3] irqchip: irq-mips-gic: Provide function to map GIC user section
Message-ID<qg9jJ-1RW-25@gated-at.bofh.it>
In reply to#1234050
Hi,

On 09/28/2015 11:55 AM, Marc Zyngier wrote:
> On 28/09/15 11:11, Markos Chandras wrote:
>> From: Alex Smith <alex.smith@imgtec.com>
>>
>> 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.
>>
>> Cc: Thomas Gleixner <tglx@linutronix.de>
>> Cc: Jason Cooper <jason@lakedaemon.net>
>> Cc: Marc Zyngier <marc.zyngier@arm.com>
>> Cc: linux-kernel@vger.kernel.org
>> Signed-off-by: Alex Smith <alex.smith@imgtec.com>
>> Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
>> ---
>>  drivers/irqchip/irq-mips-gic.c   | 27 +++++++++++++++++++++------
>>  include/linux/irqchip/mips-gic.h | 24 ++++++++++++++++++++++--
>>  2 files changed, 43 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
>> index af2f16bb8a94..c995b199ca32 100644
>> --- a/drivers/irqchip/irq-mips-gic.c
>> +++ b/drivers/irqchip/irq-mips-gic.c
>> @@ -13,6 +13,7 @@
>>  #include <linux/irq.h>
>>  #include <linux/irqchip.h>
>>  #include <linux/irqchip/mips-gic.h>
>> +#include <linux/mm.h>
>>  #include <linux/of_address.h>
>>  #include <linux/sched.h>
>>  #include <linux/smp.h>
>> @@ -29,6 +30,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 +303,19 @@ int gic_get_c0_fdc_int(void)
>>  				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
>>  }
>>  
>> +int gic_map_user_section(struct vm_area_struct *vma, unsigned long base,
>> +			 unsigned long size)
>> +{
>> +	unsigned long pfn;
>> +
>> +	BUG_ON(!gic_present);
> 
> Why do you have a BUG() here, while you're just returning -1 in the case
> where CONFIG_MIPS_GIC is not refined? This feels overly harsh to me.

I suppose i could change that to return -1 if git_present is not true.

> 
>> +	BUG_ON(size > USM_VISIBLE_SECTION_SIZE);
> 
> Same here.

But I think this is different. The size of mapping has to be less than
USM_VISIBLE_SECTION_SIZE because that's the maximum data size exposed by
the GIC chip for userspace use. So if that's not true, then BUG_ON seems
like a sensible thing to do.

> 
> - Does this code have to be in the irqchip driver? It really feels out
> of place, and I'd rather see a function that returns the mappable range
> to the VDSO code, where the mapping would occur.
> 
> Thanks,
> 

That does seem like a good idea. I will have a look


-- 
markos
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234045 — Re: [PATCH 1/3] MIPS: Initial implementation of a VDSO

FromAlex Smith <alex@alex-smith.me.uk>
Date2015-09-28 13:00 +0200
SubjectRe: [PATCH 1/3] MIPS: Initial implementation of a VDSO
Message-ID<qdEk2-3tU-1@gated-at.bofh.it>
In reply to#1234004
Hi Markos,

Thanks for finishing this off. Just got a few of minor comments.

On 28 September 2015 at 11:10, Markos Chandras
<markos.chandras@imgtec.com> wrote:
> diff --git a/arch/mips/vdso/elf.S b/arch/mips/vdso/elf.S
> new file mode 100644
> index 000000000000..60c23d0d452c
> --- /dev/null
> +++ b/arch/mips/vdso/elf.S
> @@ -0,0 +1,68 @@
> +/*
> + * Copyright (C) 2015 Imagination Technologies
> + * Author: Alex Smith <alex.smith@imgtec.com>
> + *
> + * 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.
> + */
> +
> +#include "vdso.h"
> +
> +#include <linux/elfnote.h>
> +#include <linux/version.h>
> +
> +ELFNOTE_START(Linux, 0, "a")
> +       .long LINUX_VERSION_CODE
> +ELFNOTE_END
> +
> +/*
> + * The .MIPS.abiflags section must be defined with the FP ABI flags set
> + * to 'any' to be able to link with both old and new libraries.
> + * Newer toolchains are capable of automatically generating this, but we want
> + * to work with older toolchains as well. Therefore, we define the contents of
> + * this section here (under different names), and then genvdso will patch
> + * it to have the correct name and type.
> + *
> + * We base the .MIPS.abiflags section on preprocessor definitions rather than
> + * CONFIG_* because we need to match the particular ABI we are building the
> + * VDSO for.
> + *
> + * See https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
> + * for the .MIPS.abitflags and .gnu.attributes section description.
> + */

s/abitflags/abiflags/

> diff --git a/arch/mips/vdso/vdso.h b/arch/mips/vdso/vdso.h
> new file mode 100644
> index 000000000000..64b98967e245
> --- /dev/null
> +++ b/arch/mips/vdso/vdso.h
> @@ -0,0 +1,79 @@
> +/*
> + * Copyright (C) 2015 Imagination Technologies
> + * Author: Alex Smith <alex.smith@imgtec.com>
> + *
> + * 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.
> + */
> +
> +#include <asm/sgidefs.h>
> +
> +#if _MIPS_SIM != _MIPS_SIM_ABI64 && defined(CONFIG_64BIT)
> +
> +/* Building 32-bit VDSO for the 64-bit kernel. Fake a 32-bit Kconfig. */
> +#undef CONFIG_64BIT
> +#define CONFIG_32BIT 1
> +
> +#endif
> +
> +#ifndef __ASSEMBLY__
> +
> +#include <asm/asm.h>
> +#include <asm/page.h>
> +#include <asm/vdso.h>
> +
> +static inline unsigned long get_vdso_base(void)
> +{
> +       unsigned long addr;
> +
> +       /*
> +        * Get the base load address of the VDSO. We have to avoid generating
> +        * relocations and references to the GOT because ld.so does not peform
> +        * relocations on the VDSO. We use the current offset from the VDSO base
> +        * and perform a PC-relative branch which gives the absolute address in
> +        * ra, and take the difference. The assembler chokes on
> +        * "li %0, _start - .", so embed the offset as a word and branch over
> +        * it.
> +        *
> +        * TODO: Is there a better way to do this?

Unless somebody else can come up with a better way to do this I'd say
this TODO can go :)

Also perhaps move the description of what the code is doing (from "We
use the current offset from the VDSO base" onwards) down to after the
#else since it applies  to that code rather than the R6 code which
comes first.

> +        */
> +
> +#ifdef CONFIG_CPU_MIPSR6
> +       /*
> +        * We can't use cpu_has_mips_r6 since it will create a relocation
> +        * in the VDSO because of the global cpu_data[] variable.
> +        */

I think it would be more correct to say here that cpu_data doesn't
even exist to the VDSO because it's a kernel symbol.

> +
> +       /* lapc <symbol> is an alias to addiupc reg, <symbol> - .
> +        *
> +        * We can't use addiupc because there is no label-label
> +        * support for the addiupc reloc
> +        */
> +       __asm__("lapc   %0, _start                      \n"
> +               : "=r" (addr) : :);

Just curious - if lapc is just an alias to addiupc, why does that work
but not addiupc? IIRC I did try addiupc previously but removed it
because it wasn't working, didn't know about lapc!

Thanks,
Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1234148 — RE: [PATCH 1/3] MIPS: Initial implementation of a VDSO

FromMatthew Fortune <Matthew.Fortune@imgtec.com>
Date2015-09-28 15:20 +0200
SubjectRE: [PATCH 1/3] MIPS: Initial implementation of a VDSO
Message-ID<qdGvw-6My-23@gated-at.bofh.it>
In reply to#1234045
QWxleCBTbWl0aCA8YWxleEBhbGV4LXNtaXRoLm1lLnVrPiB3cml0ZXM6DQo+ID4gKw0KPiA+ICsg
ICAgICAgLyogbGFwYyA8c3ltYm9sPiBpcyBhbiBhbGlhcyB0byBhZGRpdXBjIHJlZywgPHN5bWJv
bD4gLSAuDQo+ID4gKyAgICAgICAgKg0KPiA+ICsgICAgICAgICogV2UgY2FuJ3QgdXNlIGFkZGl1
cGMgYmVjYXVzZSB0aGVyZSBpcyBubyBsYWJlbC1sYWJlbA0KPiA+ICsgICAgICAgICogc3VwcG9y
dCBmb3IgdGhlIGFkZGl1cGMgcmVsb2MNCj4gPiArICAgICAgICAqLw0KPiA+ICsgICAgICAgX19h
c21fXygibGFwYyAgICUwLCBfc3RhcnQgICAgICAgICAgICAgICAgICAgICAgXG4iDQo+ID4gKyAg
ICAgICAgICAgICAgIDogIj1yIiAoYWRkcikgOiA6KTsNCj4gDQo+IEp1c3QgY3VyaW91cyAtIGlm
IGxhcGMgaXMganVzdCBhbiBhbGlhcyB0byBhZGRpdXBjLCB3aHkgZG9lcyB0aGF0IHdvcmsNCj4g
YnV0IG5vdCBhZGRpdXBjPyBJSVJDIEkgZGlkIHRyeSBhZGRpdXBjIHByZXZpb3VzbHkgYnV0IHJl
bW92ZWQgaXQNCj4gYmVjYXVzZSBpdCB3YXNuJ3Qgd29ya2luZywgZGlkbid0IGtub3cgYWJvdXQg
bGFwYyENCg0KVGhpcyBpcyBqdXN0IGFuIHVuZm9ydHVuYXRlIHF1aXJrIG9mIGhvdyB0aGUgaW1w
bGVtZW50YXRpb24gaXMgZG9uZSBpbg0KYmludXRpbHMuIFdlIGRvbid0IHJlY29nbmlzZSB0aGUg
c3BlY2lhbCBjYXNlIHRoYXQ6DQoNCmFkZGl1cGMgPHJlZz4sIDxzeW0+IC0gLg0KDQppcyB0aGUg
c2FtZSBhcw0KDQpsYXBjIDxyZWc+LCA8c3ltPg0KDQpBbmQgdGhlcmVmb3JlIGRvbid0IGtub3cg
dGhhdCB3ZSBjYW4ganVzdCB1c2UgdGhlIE1JUFNfUEMxOV9TMiByZWxvYw0KKG5hbWUgb2YgdGhh
dCByZWxvYyBtYXkgbm90IGJlIHBlcmZlY3RseSBjb3JyZWN0KS4gSXQgaXMgYSBzcGVjaWFsDQpj
YXNlIGFzIHRoZSBSSFMgb2YgdGhlIGV4cHJlc3Npb24gaW4gQURESVVQQyBhYm92ZSBjYW4gYmUg
dGhlb3JldGljYWxseQ0KYW55dGhpbmcgc28gd2Ugb25seSBzdXBwb3J0IGFzc2VtYmx5IHRpbWUg
Y29uc3RhbnRzIHdpdGggYWRkaXVwYy4NCg0KQXBhcnQgZnJvbSB0aGUgbmVlZCB0byBkb2N1bWVu
dCB0aGUgTEFQQyBhbGlhcyBzb21ld2hlcmUgSSdtIG5vdCBzdXJlDQp3ZSBuZWVkIGRvIGFueXRo
aW5nIHRvIGltcHJvdmUgYWRkaXVwYyBpdHNlbGYgcGFydGljdWxhcmx5Lg0KDQpUaGFua3MsDQpN
YXR0aGV3DQo=
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web