Skip to contentSkip to conversation

Transition /proc/cpuinfo -> sysfs

PATCH In review Deepak Saxena 5 participants 14 messages Aug 11, 2004 – Aug 15, 2004

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover Transition /proc/cpuinfo -> sysfs

Following this email will be a set of patches that provide a first pass at exporting information currently in /proc/cpuinfo to sysfs for i386 and ARM. There are applications that are dependent on /proc/cpuinfo atm, so we can't just kill it, but we should agree on a kill date and require all arches & apps to transition by that point. I've added code to proc_misc.c to remind the user that the cpuinfo interface is going away (currently using arbitrary date ~1 year from now). I've also added a pointer to struct cpu that can be used by arch code to store any information that might be needed during attribute printing.

Couple of questions:

- Do we want to standardize on a set of attributes that all CPUs must provide to sysfs? bogomips, L1 cache size/type/sets/assoc (when available), L2 cache (L3..L4), etc? This would make the output be the same across architectures for those features and would simply require adding some fields to struct cpu to carry this data and some generic ATTR entries to drivers/base/cpu.c. I am all for standardized interfaces so I'll do a first pass at this if desired.

- On an HT setup, do we want link(s) pointing to sibling(s)?

- Currently the bug and feature fields on x86 have "yes" and "no". Do we want the same in sysfs or 1|0?

- Instead of dumping the "flags" field, should we just dump cpu registers as hex strings and let the user decode (as the comment for the x86_cap_flags implies.

I'll try to do MIPS, SH, and PPC when I get a chance (all I have access to), but have other things to do for a while, so want comments on above questions first.

Tnx,
~Deepak

Signature · 4 lines
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
#1 lore raw

PATCH 1/3 Transition /proc/cpuinfo -> sysfs

- Add printk to cpuinfo_open reminding user to transition to sysfs
- Add arch_cpuinfo field to struct cpu

fs/proc/proc_misc.c +7 -0
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
@@ -258,11 +258,18 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
+#define	CPUINFO_REMOVAL_DATE "September 1st, 2005"
 extern struct seq_operations cpuinfo_op;
 static int cpuinfo_open(struct inode *inode, struct file *file)
 {
+	printk(KERN_WARNING "Using depecrated /proc/cpuinfo interface\n");
+	printk(KERN_WARNING "This interface will be deleted on %s\n", 
+			CPUINFO_REMOVAL_DATE);
+	printk(KERN_WARNING "Please use syfs interface instead\n");
+
 	return seq_open(file, &cpuinfo_op);
 }
+
 static struct file_operations proc_cpuinfo_operations = {
 	.open		= cpuinfo_open,
 	.read		= seq_read,
include/linux/cpu.h +1 -0
diff -Nru a/include/linux/cpu.h b/include/linux/cpu.h
@@ -28,6 +28,7 @@
 struct cpu {
 	int node_id;		/* The node which contains the CPU */
 	int no_control;		/* Should the sysfs control file be created? */
+	void *arch_cpuinfo;	/* Per-cpu arch data */
 	struct sys_device sysdev;
 };
 
Signature · 4 lines
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
#2 lore raw

PATCH 2/3 Transition /proc/cpuinfo -> sysfs

In reply to Deepak Saxena

Ughh..found a bug already. Should check register_cpu() return value b4 calling create_sysfs_cpu_entries().

arch/i386/kernel/cpu/Makefile +1 -1
diff -Nru a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
@@ -2,7 +2,7 @@
 # Makefile for x86-compatible CPU details and quirks
 #
 
-obj-y	:=	common.o proc.o
+obj-y	:=	common.o proc.o sysfs.o
 
 obj-y	+=	amd.o
 obj-y	+=	cyrix.o
arch/i386/kernel/cpu/proc.c +1 -46

56 lines not on this page · raw message

arch/i386/kernel/cpu/sysfs.c new file +234 -0

234 lines not on this page · raw message

include/asm-i386/cpu.h +9 -1
diff -Nru a/include/asm-i386/cpu.h b/include/asm-i386/cpu.h
@@ -12,9 +12,11 @@
 };
 extern struct i386_cpu cpu_devices[NR_CPUS];
 
+extern void create_sysfs_cpu_entries(struct cpu*);
 
 static inline int arch_register_cpu(int num){
 	struct node *parent = NULL;
+	int ret;
 	
 #ifdef CONFIG_NUMA
 	int node = cpu_to_node(num);
@@ -22,7 +24,13 @@
 		parent = &node_devices[node].node;
 #endif /* CONFIG_NUMA */
 
-	return register_cpu(&cpu_devices[num].cpu, num, parent);
+	cpu_devices[num].cpu.arch_cpuinfo = &cpu_data[num];
+
+	ret = register_cpu(&cpu_devices[num].cpu, num, parent);
+
+	create_sysfs_cpu_entries(&cpu_devices[num].cpu);
+
+	return ret;
 }
 
 #endif /* _ASM_I386_CPU_H_ */
Signature · 4 lines
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
#3 lore raw
In reply to Deepak Saxena

In case this goes into -mm, following applies to all 3 patches:

Signature · 4 lines
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
#4 lore raw
In reply to Deepak Saxena
Quoted 3 lines · Deepak Saxena

- Do we want to standardize on a set of attributes that all CPUs must provide to sysfs? bogomips, L1 cache size/type/sets/assoc (when available), L2 cache (L3..L4), etc?

For x86 at least, this can be entirely decoded in userspace using the /dev/cpu/x/cpuid interface. See x86info for example of this.

Quoted 3 lines

- Instead of dumping the "flags" field, should we just dump cpu registers as hex strings and let the user decode (as the comment for the x86_cap_flags implies.

ditto.

As these require arch specific parsers anyway, I don't think it makes too much sense making a kernel abstraction trying to make them all look 'the same', and if it can be done in userspace, why bother ?

The only other concern I have is the further expansion of sysfs with no particular gain over what we currently have. The sysfs variant *will* use more unreclaimable RAM than the proc version.

/proc/cpuinfo has done well enough for us for quite a number of years now, what makes it so urgent to kill it now that sysfs is the virtual-fs-de-jour ?

Dave

#5 lore raw

On Aug 12 2004, at 00:13, Dave Jones was caught saying:

Quoted 6 lines · Deepak Saxena
Quoted 4 lines

- Do we want to standardize on a set of attributes that all CPUs must provide to sysfs? bogomips, L1 cache size/type/sets/assoc (when available), L2 cache (L3..L4), etc?

Quoted 8 lines

For x86 at least, this can be entirely decoded in userspace using the /dev/cpu/x/cpuid interface. See x86info for example of this.

Quoted 3 lines

- Instead of dumping the "flags" field, should we just dump cpu registers as hex strings and let the user decode (as the comment for the x86_cap_flags implies.

ditto.

OK, just saw that code now and my reponse is to remove that interface in the long-term and move cpuid into sysfs (and not export all the cache info separately). In theory we don't even need the xxx_bug fields as those can be determined from looking at CPU binary data.

Quoted 3 lines

As these require arch specific parsers anyway, I don't think it makes too much sense making a kernel abstraction trying to make them all look 'the same', and if it can be done in userspace, why bother ?

If it is all done in userspace, then just having the raw binary data available via sysfs w/o kernel parsing is probably best. The question I have is are there any cross-platform userland tools/apps that just want to know things like cache-size w/o worrying about CPU specifics? Even if they do, I suppose they can be fixed to read that information from a binary blob and parse it dependent on the arch. ARM (other arch I really care about) could just output all the various ID registers into a binary blob and I am sure the same can be done for the other arches.

Quoted 3 lines

The only other concern I have is the further expansion of sysfs with no particular gain over what we currently have. The sysfs variant *will* use more unreclaimable RAM than the proc version.

Agreed, but that hasn't kept other data such as PCI and partition information from moving into sysfs.

Quoted 3 lines

/proc/cpuinfo has done well enough for us for quite a number of years now, what makes it so urgent to kill it now that sysfs is the virtual-fs-de-jour ?

Consitency in userspace interface. My understanding is that goal is to make /proc slowly return to it's original purpose (process-information) and move other data out into sysfs.

~Deepak

Signature · 4 lines
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
#6 lore raw
Quoted 7 lines · Deepak Saxena
Quoted 7 lines

For x86 at least, this can be entirely decoded in userspace using the /dev/cpu/x/cpuid interface. See x86info for example of this.

Quoted 3 lines

- Instead of dumping the "flags" field, should we just dump cpu registers as hex strings and let the user decode (as the comment for the x86_cap_flags implies.

Quoted 5 lines
Quoted 1 line

ditto.

OK, just saw that code now and my reponse is to remove that interface in the long-term and move cpuid into sysfs (and not export all the cache info separately).

but why? it's totally pointless when the same info can be obtained from userspace without the bloat.

Quoted 3 lines

In theory we don't even
need the xxx_bug fields as those can be determined from looking at CPU binary data.

not all of them you can't iirc.

Quoted 6 lines
Quoted 3 lines

As these require arch specific parsers anyway, I don't think it makes too much sense making a kernel abstraction trying to make them all look 'the same', and if it can be done in userspace, why bother ?

If it is all done in userspace, then just having the raw binary data available via sysfs w/o kernel parsing is probably best.

the raw binary is already available. in /dev/cpu/x/cpuid I repeat, duplicating this in sysfs is utterly pointless other than to bloat the kernels runtime memory usage.

Quoted 6 lines
Quoted 3 lines

The only other concern I have is the further expansion of sysfs with no particular gain over what we currently have. The sysfs variant *will* use more unreclaimable RAM than the proc version.

Agreed, but that hasn't kept other data such as PCI and partition information from moving into sysfs.

So because one subsystem decides to do it, every other should follow lemming-like ?

Quoted 5 lines
Quoted 3 lines

/proc/cpuinfo has done well enough for us for quite a number of years now, what makes it so urgent to kill it now that sysfs is the virtual-fs-de-jour ?

Consitency in userspace interface.

sorry, but I think that argument is total crap. Any userspace tool needing this info will still need to support the /dev/cpu/ interfaces if they want to also run on 2.2 / 2.4 kernels. Likewise, anything using /proc/cpuinfo. Ripping this out does nothing useful that I see other than cause headache for userspace by having yet another interface to support.

Quoted 3 lines

My understanding is that goal is to
make /proc slowly return to it's original purpose (process-information) and move other data out into sysfs.

I don't think thats a realistic goal. It'll take years just to migrate the in-kernel stuff, and there's god alone knows how much out-of-tree code doing the same, plus the add-ons from various vendor kernels etc so I doubt it'll ever be the process-only utopia you envision.

Changing userspace interfaces on a whim just causes pain for those that use them, especially when there is nothing wrong with the existing interfaces.

Dave

#7 lore raw

On Aug 12 2004, at 00:59, Dave Jones was caught saying:

Quoted 4 lines

but why? it's totally pointless when the same info can be obtained from userspace without the bloat.

<snip>

Quoted 4 lines

the raw binary is already available. in /dev/cpu/x/cpuid I repeat, duplicating this in sysfs is utterly pointless other than to bloat the kernels runtime memory usage.

I won't argue that there is no increase in memory usage. Looking at .text + .data for (i386/kernel/cpuid.c + i386/kernel/cpu/proc.c), there is a 2x increase (~1K -> ~2K) in size. I haven't looked at the runtime memory required for extra the sysfs objects atm; however, given that sysfs is going to be used in just about every system out there (even small embedded devices), that size is probably negligble compared to the memory requirements for all the other users of sysfs. If we can look at what really needs to be exported as a separate object and what can be determined by userspace via parsing of binary blob, that size diference will probably shrink considerably.

Quoted 11 lines
Quoted 5 lines
Quoted 3 lines

/proc/cpuinfo has done well enough for us for quite a number of years now, what makes it so urgent to kill it now that sysfs is the virtual-fs-de-jour ?

Consitency in userspace interface.

sorry, but I think that argument is total crap. Any userspace tool needing this info will still need to support the /dev/cpu/ interfaces if they want to also run on 2.2 / 2.4 kernels. Likewise, anything using /proc/cpuinfo. Ripping this out does nothing useful that I see other than cause headache for userspace by having yet another interface to support.

In my original email I specifically said that we cannot remove /proc/cpuinfo today b/c of application requirements, but this is something for down the road. The arbitrary date I choose (+1 year) can just as easilly be +2 years to provide more time for apps to change over. Right now there are 2 interfaces for cpu information via /proc/cpuinfo and /dev/cpu. By moving to sysfs we can have 1 interface. That in itself seems like a clear win.

Quoted 8 lines
Quoted 3 lines

My understanding is that goal is to
make /proc slowly return to it's original purpose (process-information) and move other data out into sysfs.

I don't think thats a realistic goal. It'll take years just to migrate the in-kernel stuff, and there's god alone knows how much out-of-tree code doing the same, plus the add-ons from various vendor kernels etc so I doubt it'll ever be the process-only utopia you envision.

Nothing wrong with taking time. I never said we need to get rid of stuff overnight. We can keep old interfaces around (see /proc/pci for example) as long as it takes for core apps and kernel stuff to switch over.

~Deepak

Signature · 4 lines
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
#8 lore raw
Quoted 4 lines · Deepak Saxena

If we can look at
what really needs to be exported as a separate object and what can be determined by userspace via parsing of binary blob, that size diference will probably shrink considerably.

And if we decide not to do this, the size difference shrinks even more considerably. People who don't give a rats ass about this stuff aren't wasting memory for each sysfs node.

The only justification I've seen so far for this bloat is "other subsystems have put their crap in sysfs, so I want to do the same".

Quoted 11 lines
Quoted 10 lines
Quoted 4 lines
Quoted 3 lines

/proc/cpuinfo has done well enough for us for quite a number of years now, what makes it so urgent to kill it now that sysfs is the virtual-fs-de-jour ?

Consitency in userspace interface.

sorry, but I think that argument is total crap. Any userspace tool needing this info will still need to support the /dev/cpu/ interfaces if they want to also run on 2.2 / 2.4 kernels. Likewise, anything using /proc/cpuinfo. Ripping this out does nothing useful that I see other than cause headache for userspace by having yet another interface to support.

Quoted 3 lines

In my original email I specifically said that we cannot remove /proc/cpuinfo today b/c of application requirements, but this is something for down the road.

Yes. And then when presented with the "but this is useless, because we already have /dev/cpu" argument, you decided to deprecate that for no reason too, in the name of 'consistency'.

This is madness.

This 'consistency' costs. As I already mentioned, an application that runs on any kernel would now have to support an extra method of obtaining the data it needs. Then people wonder why userspace apps are bloating up further and further each year. Then people wonder why installers suddenly need an extra xMB of RAM to install the latest version of a distro.

Quoted 4 lines

Nothing wrong with taking time. I never said we need to get rid of stuff overnight. We can keep old interfaces around (see /proc/pci for example) as long as it takes for core apps and kernel stuff to switch over.

There was a 'joke' a while ago about some corporations handing out bonuses to its engineers each time a patch was accepted that removed a user of the big kernel lock. These days I wonder if the same analogy is holding true for systfs patches.

Dave

#9 lore raw
In reply to Dave Jones
Quoted 6 lines · Dave Jones
Quoted 4 lines

My understanding is that goal is to
make /proc slowly return to it's original purpose (process-information) and move other data out into sysfs.

I don't think thats a realistic goal.

It may be realistic if we try hard enough, but I don't think it's a desirable one at this time. I'd prefer that I, Deepak and everyone else be spending cycles on higher-priority things than these patches. Sorry.

#10 lore raw
Quoted 11 lines · Andrew Morton
Quoted 6 lines · Dave Jones
Quoted 4 lines

My understanding is that goal is to
make /proc slowly return to it's original purpose (process-information) and move other data out into sysfs.

I don't think thats a realistic goal.

It may be realistic if we try hard enough, but I don't think it's a desirable one at this time. I'd prefer that I, Deepak and everyone else be spending cycles on higher-priority things than these patches. Sorry.

But things like this are fun to do at times :)

Anyway, that being said, I'm going to keep Deepak's patches around in my personal trees and see how well they work out as they are something that I've personally been interested in doing for quite some time. If, after a while, things look better, I'll ask for a trial time in the -mm tree for them.

thanks,

greg k-h

#11 lore raw

PATCH 3/3 Transition /proc/cpuinfo -> sysfs

In reply to Deepak Saxena

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

arch/arm/kernel/setup.c +280 -62
diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
@@ -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
 };
+
include/asm-arm/cpuinfo.h new file +51 -0

51 lines not on this page · raw message

Signature · 4 lines
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
#12 lore raw
In reply to Deepak Saxena
Quoted 12 lines · Deepak Saxena

Following this email will be a set of patches that provide a first pass at exporting information currently in /proc/cpuinfo to sysfs for i386 and ARM. There are applications that are dependent on /proc/cpuinfo atm, so we can't just kill it, but we should agree on a kill date and require all arches & apps to transition by that point. I've added code to proc_misc.c to remind the user that the cpuinfo interface is going away (currently using arbitrary date ~1 year from now). I've also added a pointer to struct cpu that can be used by arch code to store any information that might be needed during attribute printing.

Couple of questions:

Quoted 7 lines

- Do we want to standardize on a set of attributes that all CPUs must provide to sysfs? bogomips, L1 cache size/type/sets/assoc (when available), L2 cache (L3..L4), etc? This would make the output be the same across architectures for those features and would simply require adding some fields to struct cpu to carry this data and some generic ATTR entries to drivers/base/cpu.c. I am all for standardized interfaces so I'll do a first pass at this if desired.

I vote yes, but only to a point. You are right; standardized interfaces are a good thing. For any architecture specific information, additional fields should be available. Perhaps either always following the standardized sysfs entries or as an "extra-cpuinfo" (or "[arch]-cpuinfo"?) sysfs node.

Quoted 1 line

- On an HT setup, do we want link(s) pointing to sibling(s)?

I like this idea, even if it is not necessary because siblings should be listed sequentially together. i.e. two physical CPUs with HT would be cpu0, cpu1, cpu2 & cpu3. Obviously, cpu0 & cpu1 go together and cpu2 & cpu3 also go together.

Quoted 2 lines

- Currently the bug and feature fields on x86 have "yes" and "no". Do we want the same in sysfs or 1|0?

If the flags are not going to be decoded, then I say definitely 1|0.

Quoted 3 lines

- Instead of dumping the "flags" field, should we just dump cpu registers as hex strings and let the user decode (as the comment for the x86_cap_flags implies.

I like this. In fact, if it goes this way, then I will write a "cpuinfo" program that will do all the decoding as a generic tool.

Quoted 3 lines

I'll try to do MIPS, SH, and PPC when I get a chance (all I have access to), but have other things to do for a while, so want comments on above questions first.

When you are ready, I can also get SPARC64 & AMD64 (Opteron 242).

Signature · 3 lines
Lamont R. Peterson <[email protected]>
Senior Instructor
Guru Labs, L.C. http://www.GuruLabs.com/
#13 lore raw
Quoted 6 lines · Lamont R. Peterson
Quoted 1 line

- On an HT setup, do we want link(s) pointing to sibling(s)?

I like this idea, even if it is not necessary because siblings should be listed sequentially together. i.e. two physical CPUs with HT would be cpu0, cpu1, cpu2 & cpu3. Obviously, cpu0 & cpu1 go together and cpu2 & cpu3 also go together.

I'll bet *any* userspace code wanting to know this info would be simpler to write if you do the cpuid calls in the app and parse internally than walking sysfs to form an interpretation.

Quoted 6 lines
Quoted 3 lines

- Instead of dumping the "flags" field, should we just dump cpu registers as hex strings and let the user decode (as the comment for the x86_cap_flags implies.

I like this. In fact, if it goes this way, then I will write a "cpuinfo" program that will do all the decoding as a generic tool.

http://www.codemonkey.org.uk/projects/x86info/

Ok, its x86/amd64 specific, but it does all this parsing and the like where it should be -- userspace.

Dave