2010-01-12 21:09:14

by tip-bot for Jack Steiner

[permalink] [raw]
Subject: [PATCH] x86, UV: Add function retrieving node controller revision number

Add function for determining the revision id of the SGI UV
node controller chip (HUB). This function is needed in a
subsequent patch.

Signed-off-by: Jack Steiner <[email protected]>

---
arch/x86/include/asm/uv/uv_hub.h | 12 ++++++++++++
arch/x86/kernel/apic/x2apic_uv_x.c | 6 ++++++
2 files changed, 18 insertions(+)

Index: linux/arch/x86/include/asm/uv/uv_hub.h
===================================================================
--- linux.orig/arch/x86/include/asm/uv/uv_hub.h 2010-01-09 19:49:39.000000000 -0600
+++ linux/arch/x86/include/asm/uv/uv_hub.h 2010-01-12 14:42:29.000000000 -0600
@@ -496,5 +496,17 @@ static inline void uv_hub_send_ipi(int p
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
}

+/*
+ * Get the minimum revision number of the hub chips within the partition.
+ * 1 - initial rev 1.0 silicon
+ * 2 - rev 2.0 production silicon
+ */
+static inline int uv_get_min_hub_revision_id(void)
+{
+ extern int uv_min_hub_revision_id;
+
+ return uv_min_hub_revision_id;
+}
+
#endif /* CONFIG_X86_64 */
#endif /* _ASM_X86_UV_UV_HUB_H */
Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
===================================================================
--- linux.orig/arch/x86/kernel/apic/x2apic_uv_x.c 2010-01-09 19:49:39.000000000 -0600
+++ linux/arch/x86/kernel/apic/x2apic_uv_x.c 2010-01-12 14:43:36.000000000 -0600
@@ -36,6 +36,8 @@ DEFINE_PER_CPU(int, x2apic_extra_bits);

static enum uv_system_type uv_system_type;
static u64 gru_start_paddr, gru_end_paddr;
+int uv_min_hub_revision_id;
+EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);

static inline bool is_GRU_range(u64 start, u64 end)
{
@@ -55,6 +57,10 @@ static int early_get_nodeid(void)
mmr = early_ioremap(UV_LOCAL_MMR_BASE | UVH_NODE_ID, sizeof(*mmr));
node_id.v = *mmr;
early_iounmap(mmr, sizeof(*mmr));
+
+ /* Currently, all blades have same revision number */
+ uv_min_hub_revision_id = node_id.s.revision;
+
return node_id.s.node_id;
}


2010-01-13 09:24:41

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] x86, UV: Add function retrieving node controller revision number


* Jack Steiner <[email protected]> wrote:

> Add function for determining the revision id of the SGI UV
> node controller chip (HUB). This function is needed in a
> subsequent patch.
>
> Signed-off-by: Jack Steiner <[email protected]>
>
> ---
> arch/x86/include/asm/uv/uv_hub.h | 12 ++++++++++++
> arch/x86/kernel/apic/x2apic_uv_x.c | 6 ++++++
> 2 files changed, 18 insertions(+)

We'd need to see those two patches together i guess.

Ingo

2010-01-20 08:10:33

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] x86, UV: Fix RTC latency bug by reading replicated cachelines


* Dimitri Sivanich <[email protected]> wrote:

> +++ linux/drivers/char/uv_mmtimer.c 2010-01-14 11:56:57.000000000 -0600
> @@ -89,12 +89,19 @@ static long uv_mmtimer_ioctl(struct file
> switch (cmd) {
> case MMTIMER_GETOFFSET: /* offset of the counter */
> /*
> - * UV RTC register is on its own page
> + * Starting with HUB rev 2.0, the UV RTC register is
> + * replicated across all cachelines of it's own page.
> + * This allows faster simultaneous reads from a given socket.
> + *
> + * The offset returned is in 64 bit units.
> */
> - if (PAGE_SIZE <= (1 << 16))
> - ret = ((UV_LOCAL_MMR_BASE | UVH_RTC) & (PAGE_SIZE-1))
> - / 8;
> - else
> + if (PAGE_SIZE <= (1 << 16)) {
> + if (uv_get_min_hub_revision_id() == 1)
> + ret = 0;
> + else
> + ret = ((uv_blade_processor_id() *
> + L1_CACHE_BYTES) % PAGE_SIZE) / 8;
> + } else

That 64K PAGE_SIZE check in the ioctl looks rather weird. What is the purpose
of it?

Ingo

2010-01-22 15:41:44

by Dimitri Sivanich

[permalink] [raw]
Subject: Re: [PATCH] x86, UV: Fix RTC latency bug by reading replicated cachelines

For SGI UV node controllers (HUB) rev 2.0 or greater, use replicated
cachelines to read the RTC timer. This optimization allows faster
simulataneous reads from a given socket.

Signed-off-by: Dimitri Sivanich <[email protected]>

---

arch/x86/kernel/uv_time.c | 13 ++++++++++++-
drivers/char/uv_mmtimer.c | 18 +++++++++++-------
2 files changed, 23 insertions(+), 8 deletions(-)

Index: linux/arch/x86/kernel/uv_time.c
===================================================================
--- linux.orig/arch/x86/kernel/uv_time.c 2010-01-22 08:09:37.000000000 -0600
+++ linux/arch/x86/kernel/uv_time.c 2010-01-22 09:14:45.000000000 -0600
@@ -282,10 +282,21 @@ static int uv_rtc_unset_timer(int cpu, i

/*
* Read the RTC.
+ *
+ * Starting with HUB rev 2.0, the UV RTC register is replicated across all
+ * cachelines of it's own page. This allows faster simultaneous reads
+ * from a given socket.
*/
static cycle_t uv_read_rtc(struct clocksource *cs)
{
- return (cycle_t)uv_read_local_mmr(UVH_RTC);
+ unsigned long offset;
+
+ if (uv_get_min_hub_revision_id() == 1)
+ offset = 0;
+ else
+ offset = (uv_blade_processor_id() * L1_CACHE_BYTES) % PAGE_SIZE;
+
+ return (cycle_t)uv_read_local_mmr(UVH_RTC | offset);
}

/*
Index: linux/drivers/char/uv_mmtimer.c
===================================================================
--- linux.orig/drivers/char/uv_mmtimer.c 2010-01-22 08:09:38.000000000 -0600
+++ linux/drivers/char/uv_mmtimer.c 2010-01-22 09:23:34.000000000 -0600
@@ -89,13 +89,17 @@ static long uv_mmtimer_ioctl(struct file
switch (cmd) {
case MMTIMER_GETOFFSET: /* offset of the counter */
/*
- * UV RTC register is on its own page
+ * Starting with HUB rev 2.0, the UV RTC register is
+ * replicated across all cachelines of it's own page.
+ * This allows faster simultaneous reads from a given socket.
+ *
+ * The offset returned is in 64 bit units.
*/
- if (PAGE_SIZE <= (1 << 16))
- ret = ((UV_LOCAL_MMR_BASE | UVH_RTC) & (PAGE_SIZE-1))
- / 8;
+ if (uv_get_min_hub_revision_id() == 1)
+ ret = 0;
else
- ret = -ENOSYS;
+ ret = ((uv_blade_processor_id() * L1_CACHE_BYTES) %
+ PAGE_SIZE) / 8;
break;

case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */
@@ -115,8 +119,8 @@ static long uv_mmtimer_ioctl(struct file
ret = hweight64(UVH_RTC_REAL_TIME_CLOCK_MASK);
break;

- case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */
- ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0;
+ case MMTIMER_MMAPAVAIL:
+ ret = 1;
break;

case MMTIMER_GETCOUNTER:

2010-01-14 18:34:32

by Dimitri Sivanich

[permalink] [raw]
Subject: [PATCH] x86, UV: Read RTC using replicated cachelines

For SGI UV node controllers (HUB) rev 2.0 or greater, use replicated
cachelines to read the RTC timer. This optimization allows faster
simulataneous reads from a given socket.

Signed-off-by: Dimitri Sivanich <[email protected]>

---

Patch requires "Add function retrieving node controller revision number" patch.

arch/x86/kernel/uv_time.c | 13 ++++++++++++-
drivers/char/uv_mmtimer.c | 17 ++++++++++++-----
2 files changed, 24 insertions(+), 6 deletions(-)

Index: linux/arch/x86/kernel/uv_time.c
===================================================================
--- linux.orig/arch/x86/kernel/uv_time.c 2010-01-14 11:52:44.000000000 -0600
+++ linux/arch/x86/kernel/uv_time.c 2010-01-14 11:56:57.000000000 -0600
@@ -282,10 +282,21 @@ static int uv_rtc_unset_timer(int cpu, i

/*
* Read the RTC.
+ *
+ * Starting with HUB rev 2.0, the UV RTC register is replicated across all
+ * cachelines of it's own page. This allows faster simultaneous reads
+ * from a given socket.
*/
static cycle_t uv_read_rtc(struct clocksource *cs)
{
- return (cycle_t)uv_read_local_mmr(UVH_RTC);
+ unsigned long offset;
+
+ if (uv_get_min_hub_revision_id() == 1)
+ offset = 0;
+ else
+ offset = (uv_blade_processor_id() * L1_CACHE_BYTES) % PAGE_SIZE;
+
+ return (cycle_t)uv_read_local_mmr(UVH_RTC | offset);
}

/*
Index: linux/drivers/char/uv_mmtimer.c
===================================================================
--- linux.orig/drivers/char/uv_mmtimer.c 2010-01-14 11:52:45.000000000 -0600
+++ linux/drivers/char/uv_mmtimer.c 2010-01-14 11:56:57.000000000 -0600
@@ -89,12 +89,19 @@ static long uv_mmtimer_ioctl(struct file
switch (cmd) {
case MMTIMER_GETOFFSET: /* offset of the counter */
/*
- * UV RTC register is on its own page
+ * Starting with HUB rev 2.0, the UV RTC register is
+ * replicated across all cachelines of it's own page.
+ * This allows faster simultaneous reads from a given socket.
+ *
+ * The offset returned is in 64 bit units.
*/
- if (PAGE_SIZE <= (1 << 16))
- ret = ((UV_LOCAL_MMR_BASE | UVH_RTC) & (PAGE_SIZE-1))
- / 8;
- else
+ if (PAGE_SIZE <= (1 << 16)) {
+ if (uv_get_min_hub_revision_id() == 1)
+ ret = 0;
+ else
+ ret = ((uv_blade_processor_id() *
+ L1_CACHE_BYTES) % PAGE_SIZE) / 8;
+ } else
ret = -ENOSYS;
break;

2010-01-19 14:41:41

by Dimitri Sivanich

[permalink] [raw]
Subject: [PATCH] x86, UV: Fix RTC latency bug by reading replicated cachelines

Fix an RTC read latency bug by using replicated cachelines to read the RTC
timer on SGI UV node controllers (HUB) rev 2.0 or greater.

Signed-off-by: Dimitri Sivanich <[email protected]>

---

Patch requires "Add function retrieving node controller revision number" patch.

arch/x86/kernel/uv_time.c | 13 ++++++++++++-
drivers/char/uv_mmtimer.c | 17 ++++++++++++-----
2 files changed, 24 insertions(+), 6 deletions(-)

Index: linux/arch/x86/kernel/uv_time.c
===================================================================
--- linux.orig/arch/x86/kernel/uv_time.c 2010-01-14 11:52:44.000000000 -0600
+++ linux/arch/x86/kernel/uv_time.c 2010-01-14 11:56:57.000000000 -0600
@@ -282,10 +282,21 @@ static int uv_rtc_unset_timer(int cpu, i

/*
* Read the RTC.
+ *
+ * Starting with HUB rev 2.0, the UV RTC register is replicated across all
+ * cachelines of it's own page. This allows faster simultaneous reads
+ * from a given socket.
*/
static cycle_t uv_read_rtc(struct clocksource *cs)
{
- return (cycle_t)uv_read_local_mmr(UVH_RTC);
+ unsigned long offset;
+
+ if (uv_get_min_hub_revision_id() == 1)
+ offset = 0;
+ else
+ offset = (uv_blade_processor_id() * L1_CACHE_BYTES) % PAGE_SIZE;
+
+ return (cycle_t)uv_read_local_mmr(UVH_RTC | offset);
}

/*
Index: linux/drivers/char/uv_mmtimer.c
===================================================================
--- linux.orig/drivers/char/uv_mmtimer.c 2010-01-14 11:52:45.000000000 -0600
+++ linux/drivers/char/uv_mmtimer.c 2010-01-14 11:56:57.000000000 -0600
@@ -89,12 +89,19 @@ static long uv_mmtimer_ioctl(struct file
switch (cmd) {
case MMTIMER_GETOFFSET: /* offset of the counter */
/*
- * UV RTC register is on its own page
+ * Starting with HUB rev 2.0, the UV RTC register is
+ * replicated across all cachelines of it's own page.
+ * This allows faster simultaneous reads from a given socket.
+ *
+ * The offset returned is in 64 bit units.
*/
- if (PAGE_SIZE <= (1 << 16))
- ret = ((UV_LOCAL_MMR_BASE | UVH_RTC) & (PAGE_SIZE-1))
- / 8;
- else
+ if (PAGE_SIZE <= (1 << 16)) {
+ if (uv_get_min_hub_revision_id() == 1)
+ ret = 0;
+ else
+ ret = ((uv_blade_processor_id() *
+ L1_CACHE_BYTES) % PAGE_SIZE) / 8;
+ } else
ret = -ENOSYS;
break;

2010-01-22 15:40:10

by Dimitri Sivanich

[permalink] [raw]
Subject: Re: [PATCH] x86, UV: Fix RTC latency bug by reading replicated cachelines

On Wed, Jan 20, 2010 at 09:10:20AM +0100, Ingo Molnar wrote:
>
> * Dimitri Sivanich <[email protected]> wrote:
>
> > +++ linux/drivers/char/uv_mmtimer.c 2010-01-14 11:56:57.000000000 -0600
> > @@ -89,12 +89,19 @@ static long uv_mmtimer_ioctl(struct file
> > switch (cmd) {
> > case MMTIMER_GETOFFSET: /* offset of the counter */
> > /*
> > - * UV RTC register is on its own page
> > + * Starting with HUB rev 2.0, the UV RTC register is
> > + * replicated across all cachelines of it's own page.
> > + * This allows faster simultaneous reads from a given socket.
> > + *
> > + * The offset returned is in 64 bit units.
> > */
> > - if (PAGE_SIZE <= (1 << 16))
> > - ret = ((UV_LOCAL_MMR_BASE | UVH_RTC) & (PAGE_SIZE-1))
> > - / 8;
> > - else
> > + if (PAGE_SIZE <= (1 << 16)) {
> > + if (uv_get_min_hub_revision_id() == 1)
> > + ret = 0;
> > + else
> > + ret = ((uv_blade_processor_id() *
> > + L1_CACHE_BYTES) % PAGE_SIZE) / 8;
> > + } else
>
> That 64K PAGE_SIZE check in the ioctl looks rather weird. What is the purpose
> of it?

Checking for > 64k pages is really a holdover from similar code on ia64. I've taken it out with a modified version of this patch that I'll send shortly.

2010-01-15 19:25:11

by tip-bot for Jack Steiner

[permalink] [raw]
Subject: [tip:x86/urgent] x86, uv: Add function retrieving node controller revision number

Commit-ID: 7a1110e861b2666ac09f5708d6fbe71d18ce64bb
Gitweb: http://git.kernel.org/tip/7a1110e861b2666ac09f5708d6fbe71d18ce64bb
Author: Jack Steiner <[email protected]>
AuthorDate: Tue, 12 Jan 2010 15:09:04 -0600
Committer: H. Peter Anvin <[email protected]>
CommitDate: Fri, 15 Jan 2010 11:08:55 -0800

x86, uv: Add function retrieving node controller revision number

Add function for determining the revision id of the SGI UV
node controller chip (HUB). This function is needed in a
subsequent patch.

Signed-off-by: Jack Steiner <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/include/asm/uv/uv_hub.h | 12 ++++++++++++
arch/x86/kernel/apic/x2apic_uv_x.c | 6 ++++++
2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index bc54fa9..40be813 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -495,5 +495,17 @@ static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
}

+/*
+ * Get the minimum revision number of the hub chips within the partition.
+ * 1 - initial rev 1.0 silicon
+ * 2 - rev 2.0 production silicon
+ */
+static inline int uv_get_min_hub_revision_id(void)
+{
+ extern int uv_min_hub_revision_id;
+
+ return uv_min_hub_revision_id;
+}
+
#endif /* CONFIG_X86_64 */
#endif /* _ASM_X86_UV_UV_HUB_H */
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index b8bb869..0e48de9 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -36,6 +36,8 @@ DEFINE_PER_CPU(int, x2apic_extra_bits);

static enum uv_system_type uv_system_type;
static u64 gru_start_paddr, gru_end_paddr;
+int uv_min_hub_revision_id;
+EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);

static inline bool is_GRU_range(u64 start, u64 end)
{
@@ -55,6 +57,10 @@ static int early_get_nodeid(void)
mmr = early_ioremap(UV_LOCAL_MMR_BASE | UVH_NODE_ID, sizeof(*mmr));
node_id.v = *mmr;
early_iounmap(mmr, sizeof(*mmr));
+
+ /* Currently, all blades have same revision number */
+ uv_min_hub_revision_id = node_id.s.revision;
+
return node_id.s.node_id;
}