All of lore.kernel.org
 help / color / mirror / Atom feed
From: Deepak Saxena <dsaxena@plexity.net>
To: linux-kernel@vger.kernel.org
Cc: Andrew Morton <akpm@osdl.org>, greg@kroah.com, rmk@arm.linux.org.uk
Subject: [PATCH 3/3] [ARM] Transition /proc/cpuinfo -> sysfs
Date: Wed, 11 Aug 2004 15:47:12 -0700	[thread overview]
Message-ID: <20040811224712.GC7095@plexity.net> (raw)
In-Reply-To: <20040811224117.GA6450@plexity.net>


Russell, 

Please comment. I've moved some bits to being detected at boot time
and stuffed into a structure b/c it makes the sysfs code cleaner.
We can just have a macro handling most cases now since the values
stored as int or char* in the cpuinfo structure.

~Deepak

diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
--- a/arch/arm/kernel/setup.c	Wed Aug 11 14:46:15 2004
+++ b/arch/arm/kernel/setup.c	Wed Aug 11 14:46:15 2004
@@ -27,6 +27,7 @@
 #include <asm/elf.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
+#include <asm/cpuinfo.h>
 #include <asm/procinfo.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -53,6 +54,13 @@
 __setup("fpe=", fpe_setup);
 #endif
 
+static struct arm_cpuinfo cpuinfo;
+static struct cpu cpu[1] = {
+	{
+		.arch_cpuinfo = &cpuinfo
+	}
+};
+
 extern unsigned int mem_fclk_21285;
 extern void paging_init(struct meminfo *, struct machine_desc *desc);
 extern void convert_to_tag_list(struct tag *tags);
@@ -219,6 +227,18 @@
 #define CACHE_M(y)	((y) & (1 << 2))
 #define CACHE_LINE(y)	((y) & 3)
 
+static const char *hwcap_str[] = {
+	"swp",
+	"half",
+	"thumb",
+	"26bit",
+	"fastmult",
+	"fpa",
+	"vfp",
+	"edsp",
+	NULL
+};
+
 static inline void dump_cache(const char *prefix, unsigned int cache)
 {
 	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
@@ -264,10 +284,23 @@
 	return cpu_arch;
 }
 
+#define get_cache_info(_size, _assoc, _line_size, _sets, cache)		\
+do {									\
+	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);		\
+									\
+	cpuinfo._size = mult << (8 + CACHE_SIZE(cache));		\
+	cpuinfo._assoc = (mult << CACHE_ASSOC(cache)) >> 1;		\
+	cpuinfo._line_size =  8 << CACHE_LINE(cache);			\
+	cpuinfo._sets =  						\
+		1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -	\
+			    CACHE_LINE(cache));				\
+} while(0);
+
 static void __init setup_processor(void)
 {
 	extern struct proc_info_list __proc_info_begin, __proc_info_end;
 	struct proc_info_list *list;
+	int cache_info;
 
 	/*
 	 * locate processor in the list of supported processor
@@ -314,6 +347,48 @@
 	elf_hwcap = list->elf_hwcap;
 
 	cpu_proc_init();
+
+	cpuinfo.model = cpu_name;
+	cpuinfo.revision = (int)processor_id & 15;
+	cpuinfo.elf_platform = elf_platform;
+	cpuinfo.vendor = processor_id >> 24;
+	cpuinfo.architecture = proc_arch[cpu_architecture()];
+
+	if ((processor_id & 0x0000f000) == 0x00000000) {
+		cpuinfo.part = processor_id >> 4;
+		cpuinfo.variant = 0xfffffff;
+	} else {
+		if ((processor_id & 0x0000f000) == 0x00007000) {
+			/* ARM7 */
+			cpuinfo.variant = (processor_id >> 16) & 127;
+		} else {
+			/* post-ARM7 */
+			cpuinfo.variant = (processor_id >> 20) & 15;
+		}
+		cpuinfo.part = (processor_id >> 4) & 0xfff;
+	}
+
+	cache_info = read_cpuid(CPUID_CACHETYPE);
+	if (cache_info != processor_id) {
+		cpuinfo.cache_type = cache_types[CACHE_TYPE(cache_info)];
+		cpuinfo.cache_clean = cache_clean[CACHE_TYPE(cache_info)],
+		cpuinfo.cache_lockdown = cache_lockdown[CACHE_TYPE(cache_info)];
+		cpuinfo.cache_format = 
+			CACHE_S(cache_info) ? "Harvard" : "Unified";
+
+		if (CACHE_S(cache_info)) {
+			get_cache_info(icache_size, icache_assoc, 
+					icache_line_size, icache_sets, 
+					CACHE_ISIZE(cache_info));
+			get_cache_info(dcache_size, dcache_assoc, 
+					dcache_line_size, dcache_sets, 
+					CACHE_DSIZE(cache_info));
+		} else {
+			get_cache_info(cache_size, cache_assoc, 
+					cache_line_size, cache_sets, 
+					CACHE_ISIZE(cache_info));
+		}
+	}
 }
 
 static struct machine_desc * __init setup_machine(unsigned int nr)
@@ -740,49 +815,189 @@
 #endif
 }
 
-static struct cpu cpu[1];
 
-static int __init topology_init(void)
+/*
+ * We currently can only have 1 CPU on ARM, so we theoretically
+ * don't need to touch the incoming dev and can just dereference
+ * the global cpuinfo; however, doing it right in the first place
+ * will make life easier down the road.
+ */
+#define ARM_CPU_ATTR(_field, _format)					\
+static ssize_t show_##_field(struct sys_device*dev, char *buf)		\
+{									\
+	struct cpu *cpu = 						\
+		(struct cpu*)container_of(dev, struct cpu, sysdev);	\
+	struct arm_cpuinfo *cpuinfo = 					\
+				(struct arm_cpuinfo*)cpu->arch_cpuinfo; \
+									\
+	return sprintf(buf, _format, cpuinfo->_field);			\
+}									\
+SYSDEV_ATTR(_field, 0644, show_##_field, NULL);
+
+
+ARM_CPU_ATTR(model, "%s\n");
+ARM_CPU_ATTR(part, "%07x\n");
+ARM_CPU_ATTR(variant, "%x\n");
+ARM_CPU_ATTR(revision, "%d\n");
+ARM_CPU_ATTR(elf_platform, "%s\n");
+ARM_CPU_ATTR(vendor, "%#02x\n");
+ARM_CPU_ATTR(architecture, "ARMv%s\n");
+
+ARM_CPU_ATTR(cache_type, "%s\n");
+ARM_CPU_ATTR(cache_clean, "%s\n");
+ARM_CPU_ATTR(cache_lockdown, "%s\n");
+ARM_CPU_ATTR(cache_format, "%s\n");
+
+/*
+ * Unified cache attributes
+ */
+ARM_CPU_ATTR(cache_size, "%d\n");
+ARM_CPU_ATTR(cache_assoc, "%d\n");
+ARM_CPU_ATTR(cache_line_size, "%d\n");
+ARM_CPU_ATTR(cache_sets, "%d\n");
+
+/*
+ * Harvard cache attributes
+ */
+ARM_CPU_ATTR(icache_size, "%d\n");
+ARM_CPU_ATTR(icache_assoc, "%d\n");
+ARM_CPU_ATTR(icache_line_size, "%d\n");
+ARM_CPU_ATTR(icache_sets, "%d\n");
+ARM_CPU_ATTR(dcache_size, "%d\n");
+ARM_CPU_ATTR(dcache_assoc, "%d\n");
+ARM_CPU_ATTR(dcache_line_size, "%d\n");
+ARM_CPU_ATTR(dcache_sets, "%d\n");
+
+static ssize_t show_bogomips(struct sys_device *dev, char *buf)
 {
-	return register_cpu(cpu, 0, NULL);
+	return sprintf(buf, "%lu.%02lu\n",
+		   loops_per_jiffy / (500000/HZ),
+		   (loops_per_jiffy / (5000/HZ)) % 100);
 }
+static SYSDEV_ATTR(bogomips, 0644, show_bogomips, NULL);
 
-subsys_initcall(topology_init);
+/*
+ * TODO: Should we have one file per feature with just a 1 or 0 to
+ * let userspace know specific feature exists?
+ */
+static ssize_t show_features(struct sys_device *dev, char *buf)
+{
+	ssize_t ret;
+	int i;
 
-static const char *hwcap_str[] = {
-	"swp",
-	"half",
-	"thumb",
-	"26bit",
-	"fastmult",
-	"fpa",
-	"vfp",
-	"edsp",
-	NULL
+	ret = 0;
+	for (i = 0; hwcap_str[i]; i++)
+		if (elf_hwcap & (1 << i))
+			ret += sprintf(buf + ret, "%s ", hwcap_str[i]);
+
+	ret += sprintf(buf + ret, "\n");
+
+	return ret;
+}
+static SYSDEV_ATTR(features, 0644, show_features, NULL);
+
+static ssize_t show_hardware(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%s\n", machine_name);
+}
+static SYSDEV_ATTR(hardware, 0644, show_hardware, NULL);
+
+static ssize_t show_hardware_rev(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%04x\n", system_rev);
+}
+static SYSDEV_ATTR(hardware_rev, 0644, show_hardware_rev, NULL);
+
+static ssize_t show_hardware_serial(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%08x%08x\n", system_serial_high, system_serial_low);
+}
+static SYSDEV_ATTR(hardware_serial, 0644, show_hardware_serial, NULL);
+
+static struct attribute *standard_attrs[] = {
+	&attr_bogomips.attr,
+	&attr_features.attr,
+	&attr_model.attr,
+	&attr_part.attr,
+	&attr_variant.attr,
+	&attr_elf_platform.attr,
+	&attr_vendor.attr,
+	&attr_revision.attr,
+	&attr_architecture.attr,
+	&attr_cache_type.attr,
+	&attr_cache_clean.attr,
+	&attr_cache_lockdown.attr,
+	&attr_cache_format.attr,
+	&attr_hardware.attr,
+	&attr_hardware_rev.attr,
+	&attr_hardware_serial.attr
+};
+
+static struct attribute_group standard_group = {
+	.attrs = standard_attrs
 };
 
-static void
-c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
+static struct attribute *unified_cache_attrs[] = {
+	&attr_cache_size.attr,
+	&attr_cache_assoc.attr,
+	&attr_cache_line_size.attr,
+	&attr_cache_sets.attr
+};
+
+static struct attribute_group unified_cache_group = {
+	.attrs = unified_cache_attrs
+};
+
+static struct attribute *harvard_cache_attrs[] = {
+	&attr_icache_size.attr,
+	&attr_icache_assoc.attr,
+	&attr_icache_line_size.attr,
+	&attr_icache_sets.attr,
+	&attr_dcache_size.attr,
+	&attr_dcache_assoc.attr,
+	&attr_dcache_line_size.attr,
+	&attr_dcache_sets.attr
+};
+
+static struct attribute_group harvard_cache_group = {
+	.attrs = harvard_cache_attrs
+};
+
+/*
+ * Register cpu with sysfs and fill in CPU attributes
+ */
+static int __init topology_init(void)
 {
-	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
+	int ret;
+	struct sys_device *dev = &cpu->sysdev;
+	int cache_info;
+
+	ret = register_cpu(cpu, 0, NULL);
+	if (ret) return ret;
+
+	sysfs_create_group(&dev->kobj, &standard_group);
+
+	cache_info = read_cpuid(CPUID_CACHETYPE);
+	if (cache_info != processor_id) {
+		if (CACHE_S(cache_info)) {
+			sysfs_create_group(&dev->kobj, &harvard_cache_group);
+		} else {
+			sysfs_create_group(&dev->kobj, &unified_cache_group);
+		}
+	}	
 
-	seq_printf(m, "%s size\t\t: %d\n"
-		      "%s assoc\t\t: %d\n"
-		      "%s line length\t: %d\n"
-		      "%s sets\t\t: %d\n",
-		type, mult << (8 + CACHE_SIZE(cache)),
-		type, (mult << CACHE_ASSOC(cache)) >> 1,
-		type, 8 << CACHE_LINE(cache),
-		type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
-			    CACHE_LINE(cache)));
+	return 0;
 }
 
+subsys_initcall(topology_init);
+
 static int c_show(struct seq_file *m, void *v)
 {
 	int i;
+	int cache_info;
 
 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
-		   cpu_name, (int)processor_id & 15, elf_platform);
+			cpuinfo.model, cpuinfo.revision, cpuinfo.elf_platform);
 
 	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
 		   loops_per_jiffy / (500000/HZ),
@@ -795,45 +1010,47 @@
 		if (elf_hwcap & (1 << i))
 			seq_printf(m, "%s ", hwcap_str[i]);
 
-	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
-	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
+	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", cpuinfo.vendor);
+	seq_printf(m, "CPU architecture: %s\n", cpuinfo.architecture);
 
-	if ((processor_id & 0x0000f000) == 0x00000000) {
-		/* pre-ARM7 */
-		seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4);
-	} else {
-		if ((processor_id & 0x0000f000) == 0x00007000) {
-			/* ARM7 */
-			seq_printf(m, "CPU variant\t: 0x%02x\n",
-				   (processor_id >> 16) & 127);
-		} else {
-			/* post-ARM7 */
-			seq_printf(m, "CPU variant\t: 0x%x\n",
-				   (processor_id >> 20) & 15);
-		}
-		seq_printf(m, "CPU part\t: 0x%03x\n",
-			   (processor_id >> 4) & 0xfff);
+	seq_printf(m, "CPU part\t\t: %07x\n", cpuinfo.part);
+	if ((processor_id & 0x0000f000) != 0x00000000) {
+		seq_printf(m, "CPU variant\t: 0x%x\n", cpuinfo.variant);
 	}
 	seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
 
-	{
-		unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
-		if (cache_info != processor_id) {
-			seq_printf(m, "Cache type\t: %s\n"
-				      "Cache clean\t: %s\n"
-				      "Cache lockdown\t: %s\n"
-				      "Cache format\t: %s\n",
-				   cache_types[CACHE_TYPE(cache_info)],
-				   cache_clean[CACHE_TYPE(cache_info)],
-				   cache_lockdown[CACHE_TYPE(cache_info)],
-				   CACHE_S(cache_info) ? "Harvard" : "Unified");
-
-			if (CACHE_S(cache_info)) {
-				c_show_cache(m, "I", CACHE_ISIZE(cache_info));
-				c_show_cache(m, "D", CACHE_DSIZE(cache_info));
-			} else {
-				c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
-			}
+	cache_info = read_cpuid(CPUID_CACHETYPE);
+	if (cache_info != processor_id) {
+		seq_printf(m, "Cache type\t: %s\n"
+			      "Cache clean\t: %s\n"
+			      "Cache lockdown\t: %s\n"
+			      "Cache format\t: %s\n",
+			   cpuinfo.cache_type, cpuinfo.cache_clean,
+			   cpuinfo.cache_lockdown, cpuinfo.cache_format);
+
+		if (CACHE_S(cache_info)) {
+			seq_printf(m, "I size\t\t: %d\n", cpuinfo.icache_size);
+			seq_printf(m, "I assoc\t\t: %d\n", 
+					cpuinfo.icache_assoc);
+			seq_printf(m, "I line length\t: %d\n", 
+					cpuinfo.icache_line_size);
+			seq_printf(m, "I sets\t\t: %d\n", cpuinfo.icache_sets);
+
+			seq_printf(m, "D size\t\t: %d\n", cpuinfo.dcache_size);
+			seq_printf(m, "D assoc\t\t: %d\n", 
+					cpuinfo.dcache_assoc);
+			seq_printf(m, "D line length\t: %d\n", 
+					cpuinfo.dcache_line_size);
+			seq_printf(m, "D sets\t\t: %d\n", cpuinfo.dcache_sets);
+		} else {
+			seq_printf(m, "Cache size\t\t: %d\n", 
+					cpuinfo.icache_size);
+			seq_printf(m, "Cache assoc\t\t: %d\n", 
+					cpuinfo.icache_assoc);
+			seq_printf(m, "Cache line length\t: %d\n", 
+					cpuinfo.icache_line_size);
+			seq_printf(m, "Cache sets\t\t: %d", 
+					cpuinfo.icache_sets);
 		}
 	}
 
@@ -868,3 +1085,4 @@
 	.stop	= c_stop,
 	.show	= c_show
 };
+
diff -Nru a/include/asm-arm/cpuinfo.h b/include/asm-arm/cpuinfo.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-arm/cpuinfo.h	Wed Aug 11 14:46:15 2004
@@ -0,0 +1,51 @@
+/*
+ * include/asm-arm/cpuinfo.h
+ *
+ * per-cpu information used for sysfs
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista Software, Inc. 
+ * 
+ * This file is licensed under  the terms of the GNU General Public 
+ * License version 2. This program is licensed "as is" without any 
+ * warranty of any kind, whether express or implied.
+ */
+
+
+#ifndef __ASM_CPUINFO_H__
+#define __ASM_CPUINFO_H__
+
+
+struct arm_cpuinfo {
+	const char *model;
+	unsigned long part;
+	unsigned long variant;
+	const char *elf_platform;
+	unsigned char vendor;
+	unsigned short revision;
+	const char *architecture;
+
+	const char *cache_type;
+	const char *cache_clean;
+	const char *cache_lockdown;
+	const char *cache_format;
+
+	unsigned int cache_size;
+	unsigned int cache_assoc;
+	unsigned int cache_line_size;
+	unsigned int cache_sets;	
+
+	unsigned int icache_size;
+	unsigned int icache_assoc;
+	unsigned int icache_line_size;
+	unsigned int icache_sets;	
+
+	unsigned int dcache_size;
+	unsigned int dcache_assoc;
+	unsigned int dcache_line_size;
+	unsigned int dcache_sets;	
+};
+
+#endif	/* __ASM_CPUINFO_H__ */
+

-- 
Deepak Saxena - dsaxena at plexity dot net - http://www.plexity.net/

"Unlike me, many of you have accepted the situation of your imprisonment and
 will die here like rotten cabbages." - Number 6

  parent reply	other threads:[~2004-08-11 23:32 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-08-11 22:41 [PATCH 0/3] Transition /proc/cpuinfo -> sysfs Deepak Saxena
2004-08-11 22:42 ` [PATCH 1/3] [Generic] " Deepak Saxena
2004-08-11 22:44 ` [PATCH 2/3] [i386] " Deepak Saxena
2004-08-11 22:47 ` Deepak Saxena [this message]
2004-08-11 22:47 ` [PATCH 0/3] " Deepak Saxena
2004-08-11 23:13 ` Dave Jones
2004-08-11 23:42   ` Deepak Saxena
2004-08-11 23:59     ` Dave Jones
2004-08-12  2:45       ` Deepak Saxena
2004-08-12 11:07         ` Dave Jones
2004-08-15  6:11       ` Andrew Morton
2004-08-15  6:33         ` Greg KH
2004-08-12  5:03 ` Lamont R. Peterson
2004-08-12 10:56   ` Dave Jones

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040811224712.GC7095@plexity.net \
    --to=dsaxena@plexity.net \
    --cc=akpm@osdl.org \
    --cc=greg@kroah.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rmk@arm.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.