From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752683AbdI0LiU (ORCPT ); Wed, 27 Sep 2017 07:38:20 -0400 Received: from foss.arm.com ([217.140.101.70]:44604 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750854AbdI0LiR (ORCPT ); Wed, 27 Sep 2017 07:38:17 -0400 Date: Wed, 27 Sep 2017 12:36:48 +0100 From: Mark Rutland To: Al Stone Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Catalin Marinas , Will Deacon , Suzuki K Poulose Subject: Re: [PATCH 3/3] arm64: cpuinfo: display product info in /proc/cpuinfo Message-ID: <20170927113648.GF32150@leverpostej> References: <20170926222324.17409-1-ahs3@redhat.com> <20170926222324.17409-4-ahs3@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20170926222324.17409-4-ahs3@redhat.com> User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Al, On Tue, Sep 26, 2017 at 04:23:24PM -0600, Al Stone wrote: > While it is very useful to know what CPU is being used, it is also > useful to know who made the platform being used. On servers, this > can point to the right person to contact when a server is having > trouble. > > Go get the product info -- manufacturer, product name and version -- > from DMI (aka SMBIOS) and display it in /proc/cpuinfo. To look more > like other server platforms, include the CPU type and frequency when > displaying the product info, too. As mentioned on the cover letter, NAK to modifiying /proc/cpuinfo. I note this is all DMI information, which I thought we already exposed under sysfs (in an architecture-neutral format). Is that not the case? ... or do existing tools not pick that up today? Thanks, Mark. > > Signed-off-by: Al Stone > Cc: Catalin Marinas > Cc: Will Deacon > Cc: Suzuki K Poulose > Cc: Mark Rutland > --- > arch/arm64/kernel/cpuinfo.c | 135 +++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 134 insertions(+), 1 deletion(-) > > diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c > index 0b4261884862..6a9dbad5ee3f 100644 > --- a/arch/arm64/kernel/cpuinfo.c > +++ b/arch/arm64/kernel/cpuinfo.c > @@ -19,10 +19,12 @@ > #include > #include > #include > +#include > > #include > #include > #include > +#include > #include > #include > #include > @@ -31,6 +33,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -167,6 +170,111 @@ static const char *const compat_hwcap2_str[] = { > }; > #endif /* CONFIG_COMPAT */ > > +/* Details needed when extracting fields from DMI info */ > +#define DMI_ENTRY_BASEBOARD_MIN_LENGTH 8 > +#define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48 > + > +#define DMI_BASEBOARD_MANUFACTURER 0x04 > +#define DMI_BASEBOARD_PRODUCT 0x05 > +#define DMI_BASEBOARD_VERSION 0x06 > +#define DMI_PROCESSOR_MAX_SPEED 0x14 > + > +#define DMI_MAX_STRLEN 80 > + > +/* Values captured from DMI info */ > +static u64 dmi_max_mhz; > +static char *dmi_product_info; > + > +/* Callback function used to retrieve the max frequency from DMI */ > +static void find_dmi_mhz(const struct dmi_header *dm, void *private) > +{ > + const u8 *dmi_data = (const u8 *)dm; > + u16 *mhz = (u16 *)private; > + > + if (dm->type == DMI_ENTRY_PROCESSOR && > + dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) { > + u16 val = (u16)get_unaligned((const u16 *) > + (dmi_data + DMI_PROCESSOR_MAX_SPEED)); > + *mhz = val > *mhz ? val : *mhz; > + } > +} > + > +/* Look up the max frequency in DMI */ > +static u64 get_dmi_max_mhz(void) > +{ > + u16 mhz = 0; > + > + dmi_walk(find_dmi_mhz, &mhz); > + > + /* > + * Real stupid fallback value, just in case there is no > + * actual value set. > + */ > + mhz = mhz ? mhz : 1; > + > + return (u64)mhz; > +} > + > +/* Helper function for the product info callback */ > +static char *copy_string_n(char *dst, char *table, int idx) > +{ > + char *d = dst; > + char *ptr = table; > + int ii; > + > + /* skip the first idx-1 strings */ > + for (ii = 1; ii < idx; ii++) { > + while (*ptr) > + ptr++; > + ptr++; > + } > + > + /* copy in the string we need */ > + while (*ptr && (d - dst) < (DMI_MAX_STRLEN - 2)) > + *d++ = *ptr++; > + > + return d; > +} > + > +/* Callback function used to retrieve the product info DMI */ > +static void find_dmi_product_info(const struct dmi_header *dm, void *private) > +{ > + const u8 *dmi_data = (const u8 *)dm; > + char *ptr = (char *)private; > + > + if (dm->type == DMI_ENTRY_BASEBOARD && > + dm->length >= DMI_ENTRY_BASEBOARD_MIN_LENGTH) { > + int idx; > + > + idx = (int)get_unaligned((const u8 *) > + (dmi_data + DMI_BASEBOARD_MANUFACTURER)); > + ptr = copy_string_n(ptr, (char *)(dmi_data + dm->length), idx); > + *ptr++ = ' '; > + > + idx = (int)get_unaligned((const u8 *) > + (dmi_data + DMI_BASEBOARD_PRODUCT)); > + ptr = copy_string_n(ptr, (char *)(dmi_data + dm->length), idx); > + *ptr++ = ' '; > + > + idx = (int)get_unaligned((const u8 *) > + (dmi_data + DMI_BASEBOARD_VERSION)); > + ptr = copy_string_n(ptr, (char *)(dmi_data + dm->length), idx); > + } > +} > + > +/* Look up the baseboard info in DMI */ > +static void get_dmi_product_info(void) > +{ > + if (!dmi_product_info) { > + dmi_product_info = kcalloc(DMI_MAX_STRLEN, > + sizeof(char), GFP_KERNEL); > + if (!dmi_product_info) > + return; > + } > + > + dmi_walk(find_dmi_product_info, dmi_product_info); > +} > + > static int c_show(struct seq_file *m, void *v) > { > int i, j; > @@ -190,6 +298,31 @@ static int c_show(struct seq_file *m, void *v) > seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", > MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); > > + if (IS_ENABLED(CONFIG_DMI)) { > + seq_puts(m, "product name\t: "); > + > + if (!dmi_product_info) > + get_dmi_product_info(); > + if (dmi_product_info) > + seq_printf(m, "%s", dmi_product_info); > + else > + seq_puts(m, ""); > + > + seq_printf(m, ", ARM 8.%d (r%dp%d) CPU", > + MIDR_VARIANT(midr), > + MIDR_VARIANT(midr), > + MIDR_REVISION(midr)); > + > + if (!dmi_max_mhz) > + dmi_max_mhz = get_dmi_max_mhz(); > + if (dmi_max_mhz) > + seq_printf(m, " @ %d.%02dGHz\n", > + (int)(dmi_max_mhz / 1000), > + (int)(dmi_max_mhz % 1000)); > + else > + seq_puts(m, " @ GHz\n"); > + } > + > impl = (u8) MIDR_IMPLEMENTOR(midr); > for (j = 0; hw_implementer[j].id != 0; j++) { > if (hw_implementer[j].id == impl) { > @@ -208,7 +341,7 @@ static int c_show(struct seq_file *m, void *v) > part = (u16) MIDR_PARTNUM(midr); > for (j = 0; parts[j].id != (-1); j++) { > if (parts[j].id == part) { > - seq_printf(m, "%s\n", parts[j].name); > + seq_printf(m, "%s ", parts[j].name); > break; > } > } > -- > 2.13.5 > From mboxrd@z Thu Jan 1 00:00:00 1970 From: mark.rutland@arm.com (Mark Rutland) Date: Wed, 27 Sep 2017 12:36:48 +0100 Subject: [PATCH 3/3] arm64: cpuinfo: display product info in /proc/cpuinfo In-Reply-To: <20170926222324.17409-4-ahs3@redhat.com> References: <20170926222324.17409-1-ahs3@redhat.com> <20170926222324.17409-4-ahs3@redhat.com> Message-ID: <20170927113648.GF32150@leverpostej> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi Al, On Tue, Sep 26, 2017 at 04:23:24PM -0600, Al Stone wrote: > While it is very useful to know what CPU is being used, it is also > useful to know who made the platform being used. On servers, this > can point to the right person to contact when a server is having > trouble. > > Go get the product info -- manufacturer, product name and version -- > from DMI (aka SMBIOS) and display it in /proc/cpuinfo. To look more > like other server platforms, include the CPU type and frequency when > displaying the product info, too. As mentioned on the cover letter, NAK to modifiying /proc/cpuinfo. I note this is all DMI information, which I thought we already exposed under sysfs (in an architecture-neutral format). Is that not the case? ... or do existing tools not pick that up today? Thanks, Mark. > > Signed-off-by: Al Stone > Cc: Catalin Marinas > Cc: Will Deacon > Cc: Suzuki K Poulose > Cc: Mark Rutland > --- > arch/arm64/kernel/cpuinfo.c | 135 +++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 134 insertions(+), 1 deletion(-) > > diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c > index 0b4261884862..6a9dbad5ee3f 100644 > --- a/arch/arm64/kernel/cpuinfo.c > +++ b/arch/arm64/kernel/cpuinfo.c > @@ -19,10 +19,12 @@ > #include > #include > #include > +#include > > #include > #include > #include > +#include > #include > #include > #include > @@ -31,6 +33,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -167,6 +170,111 @@ static const char *const compat_hwcap2_str[] = { > }; > #endif /* CONFIG_COMPAT */ > > +/* Details needed when extracting fields from DMI info */ > +#define DMI_ENTRY_BASEBOARD_MIN_LENGTH 8 > +#define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48 > + > +#define DMI_BASEBOARD_MANUFACTURER 0x04 > +#define DMI_BASEBOARD_PRODUCT 0x05 > +#define DMI_BASEBOARD_VERSION 0x06 > +#define DMI_PROCESSOR_MAX_SPEED 0x14 > + > +#define DMI_MAX_STRLEN 80 > + > +/* Values captured from DMI info */ > +static u64 dmi_max_mhz; > +static char *dmi_product_info; > + > +/* Callback function used to retrieve the max frequency from DMI */ > +static void find_dmi_mhz(const struct dmi_header *dm, void *private) > +{ > + const u8 *dmi_data = (const u8 *)dm; > + u16 *mhz = (u16 *)private; > + > + if (dm->type == DMI_ENTRY_PROCESSOR && > + dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) { > + u16 val = (u16)get_unaligned((const u16 *) > + (dmi_data + DMI_PROCESSOR_MAX_SPEED)); > + *mhz = val > *mhz ? val : *mhz; > + } > +} > + > +/* Look up the max frequency in DMI */ > +static u64 get_dmi_max_mhz(void) > +{ > + u16 mhz = 0; > + > + dmi_walk(find_dmi_mhz, &mhz); > + > + /* > + * Real stupid fallback value, just in case there is no > + * actual value set. > + */ > + mhz = mhz ? mhz : 1; > + > + return (u64)mhz; > +} > + > +/* Helper function for the product info callback */ > +static char *copy_string_n(char *dst, char *table, int idx) > +{ > + char *d = dst; > + char *ptr = table; > + int ii; > + > + /* skip the first idx-1 strings */ > + for (ii = 1; ii < idx; ii++) { > + while (*ptr) > + ptr++; > + ptr++; > + } > + > + /* copy in the string we need */ > + while (*ptr && (d - dst) < (DMI_MAX_STRLEN - 2)) > + *d++ = *ptr++; > + > + return d; > +} > + > +/* Callback function used to retrieve the product info DMI */ > +static void find_dmi_product_info(const struct dmi_header *dm, void *private) > +{ > + const u8 *dmi_data = (const u8 *)dm; > + char *ptr = (char *)private; > + > + if (dm->type == DMI_ENTRY_BASEBOARD && > + dm->length >= DMI_ENTRY_BASEBOARD_MIN_LENGTH) { > + int idx; > + > + idx = (int)get_unaligned((const u8 *) > + (dmi_data + DMI_BASEBOARD_MANUFACTURER)); > + ptr = copy_string_n(ptr, (char *)(dmi_data + dm->length), idx); > + *ptr++ = ' '; > + > + idx = (int)get_unaligned((const u8 *) > + (dmi_data + DMI_BASEBOARD_PRODUCT)); > + ptr = copy_string_n(ptr, (char *)(dmi_data + dm->length), idx); > + *ptr++ = ' '; > + > + idx = (int)get_unaligned((const u8 *) > + (dmi_data + DMI_BASEBOARD_VERSION)); > + ptr = copy_string_n(ptr, (char *)(dmi_data + dm->length), idx); > + } > +} > + > +/* Look up the baseboard info in DMI */ > +static void get_dmi_product_info(void) > +{ > + if (!dmi_product_info) { > + dmi_product_info = kcalloc(DMI_MAX_STRLEN, > + sizeof(char), GFP_KERNEL); > + if (!dmi_product_info) > + return; > + } > + > + dmi_walk(find_dmi_product_info, dmi_product_info); > +} > + > static int c_show(struct seq_file *m, void *v) > { > int i, j; > @@ -190,6 +298,31 @@ static int c_show(struct seq_file *m, void *v) > seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", > MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); > > + if (IS_ENABLED(CONFIG_DMI)) { > + seq_puts(m, "product name\t: "); > + > + if (!dmi_product_info) > + get_dmi_product_info(); > + if (dmi_product_info) > + seq_printf(m, "%s", dmi_product_info); > + else > + seq_puts(m, ""); > + > + seq_printf(m, ", ARM 8.%d (r%dp%d) CPU", > + MIDR_VARIANT(midr), > + MIDR_VARIANT(midr), > + MIDR_REVISION(midr)); > + > + if (!dmi_max_mhz) > + dmi_max_mhz = get_dmi_max_mhz(); > + if (dmi_max_mhz) > + seq_printf(m, " @ %d.%02dGHz\n", > + (int)(dmi_max_mhz / 1000), > + (int)(dmi_max_mhz % 1000)); > + else > + seq_puts(m, " @ GHz\n"); > + } > + > impl = (u8) MIDR_IMPLEMENTOR(midr); > for (j = 0; hw_implementer[j].id != 0; j++) { > if (hw_implementer[j].id == impl) { > @@ -208,7 +341,7 @@ static int c_show(struct seq_file *m, void *v) > part = (u16) MIDR_PARTNUM(midr); > for (j = 0; parts[j].id != (-1); j++) { > if (parts[j].id == part) { > - seq_printf(m, "%s\n", parts[j].name); > + seq_printf(m, "%s ", parts[j].name); > break; > } > } > -- > 2.13.5 >