Skip to contentSkip to conversation

Framework for exporting System-on-Chip information via sysfs

PATCH New Lee Jones 4 participants 24 messages Sep 1, 2011 – Sep 7, 2011

Subsystems (4)
lore
Share & tools
lore

Lee Jones

author
#0 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

This patch introduces a new driver to drivers/base. The driver provides a means to export vital SoC data out to userspace via sysfs. Standard information applicable to all SoCs are exported to:

/sys/devices/soc/[1|2|3|...]/[family|machine|revision|soc_id].

It is possible to create SoC specific items via the soc device, which is returned post-registration, although this should be discouraged.

---
 drivers/base/Kconfig    |    3 +
 drivers/base/Makefile   |    1 +
 drivers/base/soc.c      |  103 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sys_soc.h |   27 ++++++++++++
 4 files changed, 134 insertions(+), 0 deletions(-)
 create mode 100644 drivers/base/soc.c
 create mode 100644 include/linux/sys_soc.h
drivers/base/Kconfig +3 -0
index 21cf46f..95f10c5 100644
@@ -172,6 +172,9 @@ config SYS_HYPERVISOR
 	bool
 	default n
 
+config SYS_SOC
+	bool
+
 source "drivers/base/regmap/Kconfig"
 
 endmenu
drivers/base/Makefile +1 -0
index 99a375a..a67a1e7 100644
@@ -18,6 +18,7 @@ obj-$(CONFIG_MODULES)	+= module.o
 endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)	+= regmap/
+obj-$(CONFIG_SYS_SOC) += soc.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
drivers/base/soc.c new file +103 -0

103 lines not on this page · raw message

include/linux/sys_soc.h new file +27 -0
new file mode 100644
index 0000000..811d7fe
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Lee Jones <[email protected]> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#ifndef __SYS_SOC_H
+#define __SYS_SOC_H
+
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+struct soc_device {
+	struct device dev;
+	const char *machine;
+	const char *family;
+	const char *revision;
+	const char *(*pfn_soc_id)(void);
+};
+
+/**
+ * soc_device_register - register SoC as a device
+ * @dev: Parent node '/sys/devices/soc/X'
+ */
+int soc_device_register(struct device *dev);
+
+#endif /* __SYS_SOC_H */
Signature · 1 line
1.7.4.1
author
#1 lore raw

PATCH 2/5 Add documentation for new sysfs devices/soc functionality

---
 Documentation/ABI/testing/sysfs-devices-soc |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-soc
Documentation/ABI/testing/sysfs-devices-soc new file +20 -0
new file mode 100644
index 0000000..943a20f
@@ -0,0 +1,20 @@
+What:		/sys/devices/soc
+Date:		September 2011
+contact:	Lee Jones <[email protected]>
+Description:
+		The /sys/devices/soc directory contains a sub-directory for each
+		System-on-Chip (SoC) device on a running platform. Information
+		regarding each SoC can be obtained by reading sysfs files. This
+		functionality is only available if implemented by the platform.
+		This directory contains two kinds of attributes:
+			- Common attributes:
+				* machine: SoC machine name (e.g. Ux500).
+				* family: SoC family name (e.g. DB8500).
+			- SoC-specific attributes:
+				* SoC vendor declared
+                                * ST-Ericsson delcare the following
+                                  * soc_id: SoC serial number
+                                  * revision: SoC revision number
+				   * process: the way in which the chip was manufactured
+Users:
+		Any platform dependent user-space applications or profiling tools.
Signature · 1 line
1.7.4.1
author
#2 lore raw

PATCH 3/5 mach-ux500: export System-on-Chip information ux500 via sysfs

In reply to Lee Jones

Here we make use of the new drivers/base/soc driver to export vital SoC information out to userspace via sysfs. This patch provides a data structure of strings to populate the base nodes found in:

/sys/devices/soc/[1|2|3|...]/[family|machine|revision|soc_id].

It also adds one more node as requested by ST-Ericsson. 'process' depicts the way in which the silicon was manufactured.

---
 arch/arm/mach-ux500/Kconfig              |    1 +
 arch/arm/mach-ux500/id.c                 |   77 ++++++++++++++++++++++++++++++
 arch/arm/mach-ux500/include/mach/setup.h |    1 +
 3 files changed, 79 insertions(+), 0 deletions(-)
arch/arm/mach-ux500/Kconfig +1 -0
index 86188b2..fa70f65 100644
@@ -27,6 +27,7 @@ config MACH_U8500
 	bool "U8500 Development platform"
 	depends on UX500_SOC_DB8500
 	select TPS6105X
+	select SYS_SOC
 	help
 	  Include support for the mop500 development platform.
 
arch/arm/mach-ux500/id.c +77 -0

92 lines not on this page · raw message

arch/arm/mach-ux500/include/mach/setup.h +1 -0
index a7d363f..7d4c35f 100644
@@ -35,6 +35,7 @@ extern void __init amba_add_devices(struct amba_device *devs[], int num);
 
 struct sys_timer;
 extern struct sys_timer ux500_timer;
+extern struct soc_device *soc_dev;
 
 #define __IO_DEV_DESC(x, sz)	{		\
 	.virtual	= IO_ADDRESS(x),	\
Signature · 1 line
1.7.4.1
#3 lore raw

PATCH 3/5 mach-ux500: export System-on-Chip information ux500 via sysfs

Quoted 11 lines · Lee Jones

Here we make use of the new drivers/base/soc driver to export vital SoC information out to userspace via sysfs. This patch provides a data structure of strings to populate the base nodes found in:

/sys/devices/soc/[1|2|3|...]/[family|machine|revision|soc_id].

It also adds one more node as requested by ST-Ericsson. 'process' depicts the way in which the silicon was manufactured.

The code looks much better than last time, but the description still talks about 'using the drivers/base/soc driver', which is not how you should think of or describe what you are doing.

What you do here is make the db8500 support an soc driver.

arch/arm/mach-ux500/id.c

Quoted 4 lines
arch/arm/mach-ux500/id.c +0 -0
index d35122e..8fd53c7 100644

You should probably rename this file or fold it into one of the db8500 files.

Quoted 34 lines

}

arch/arm/mach-ux500/id.c +33 -0
+
+struct soc_device *soc_dev;
+
+static const char *ux500_get_machine(void)
+{
+	return kasprintf(GFP_KERNEL, "DB%4x", dbx500_partnumber());
+}
+
+static const char *ux500_get_family(void)
+{
+	return kasprintf(GFP_KERNEL, "Ux500");
+}
+
+static const char *ux500_get_revision(void)
+{
+	unsigned int rev = dbx500_revision();
+
+	if (rev == 0x01) {
+		return kasprintf(GFP_KERNEL, "%s", "ED");
+	}
+	else if (rev >= 0xA0) {
+		return kasprintf(GFP_KERNEL, "%d.%d" , (rev >> 4) - 0xA + 1, rev & 0xf);
+	}
+
+	return kasprintf(GFP_KERNEL, "%s", "Unknown");
+}
+
+static ssize_t ux500_get_process(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	if (dbx500_id.process == 0x00)
+		return sprintf(buf, "Standard\n");

arch/arm/mach-ux500/id.c void __init ux500_map_io(void) · line 154

Quoted 10 lines
arch/arm/mach-ux500/id.c +10 -0
+
+	return sprintf(buf, "%02xnm\n", dbx500_id.process);
+}
+
+static void soc_info_populate(struct soc_device *soc_dev)
+{
+	soc_dev->machine  = ux500_get_machine();
+	soc_dev->family   = ux500_get_family();
+	soc_dev->revision = ux500_get_revision();
+}

It's often better to have multiple smaller functions than to do something too complex in just one function, but I think you are overdoing it here. Not a huge problem though, just my opinion on coding style.

Quoted 15 lines
arch/arm/mach-ux500/id.c +15 -0
+struct device_attribute ux500_soc_attrs[] = {
+	__ATTR(process,  S_IRUGO, ux500_get_process,  NULL),
+	__ATTR_NULL,
+};
+
+static int __init ux500_soc_sysfs_init(void)
+{
+	int ret;
+	int i = 0;
+
+	soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
+	if (soc_dev == NULL)
+		return -ENOMEM;
+
+	soc_info_populate(soc_dev);

arch/arm/mach-ux500/id.c void __init ux500_map_io(void) · line 180

Quoted 10 lines
arch/arm/mach-ux500/id.c +10 -0
+
+	ret = soc_device_register(&soc_dev->dev);
+
+	if (ret >= 0) {
+		while (ux500_soc_attrs[i].attr.name != NULL) {
+			ret = device_create_file(&soc_dev->dev, &ux500_soc_attrs[i++]);
+			if (ret)
+				goto out;
+		}
+	}

Better not make it too easy to add more of these, you don't want to have people add random stuff here, so I would recommend just using one device_create_file calls without the loop.

arch/arm/mach-ux500/include/mach/setup.h extern void __init amba_add_devices(struct amba_device *devs[], int num); · line 38

Quoted 9 lines
arch/arm/mach-ux500/include/mach/setup.h +1 -0
index a7d363f..7d4c35f 100644
@@ -35,6 +35,7 @@ extern void __init amba_add_devices(struct amba_device *devs[], int num);
 
 struct sys_timer;
 extern struct sys_timer ux500_timer;
+extern struct soc_device *soc_dev;

Do you really need to make this global?

The soc_dev is the central data structure describing your soc system, so you should have it available in all the places where it might be needed anyway, e.g. to get the base address, as described in the other mail.

Arnd

author
#4 lore raw

PATCH 4/5 mach-ux500: move top level platform devices in sysfs to /sys/devices/soc/X

In reply to Lee Jones

At the request of Arnd Bergmann this patch moves all SoC platform devices found in sysfs from /sys/devices/platform to /sys/devices/soc/<SoCNum>_<SocMachine>/. It is believed as the devices are SoC specific and a /sys/devices/soc node has recently become available, that this would be a more appropriate place to display the data.

---
 arch/arm/mach-ux500/board-mop500.c   |   16 ++++++++++++++++
 arch/arm/mach-ux500/board-u5500.c    |    7 +++++++
 arch/arm/mach-ux500/cpu-db5500.c     |    7 +++++++
 arch/arm/mach-ux500/cpu-db8500.c     |   13 ++++++++++++-
 arch/arm/mach-ux500/devices-common.c |   19 ++++++++++++++++---
 arch/arm/mach-ux500/usb.c            |    6 ++++++
 6 files changed, 64 insertions(+), 4 deletions(-)
arch/arm/mach-ux500/board-mop500.c +16 -0
index 4d75b0d..d3b1447 100644
@@ -29,6 +29,7 @@
 #include <linux/smsc911x.h>
 #include <linux/gpio_keys.h>
 #include <linux/delay.h>
+#include <linux/sys_soc.h>
 
 #include <linux/leds.h>
 #include <asm/mach-types.h>
@@ -602,6 +603,7 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
 static void __init mop500_init_machine(void)
 {
 	int i2c0_devs;
+	int i;
 
 	mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
 
@@ -609,6 +611,10 @@ static void __init mop500_init_machine(void)
 
 	mop500_pins_init();
 
+	if (soc_dev)
+		for (i=0; i<ARRAY_SIZE(mop500_platform_devs); i++)
+			mop500_platform_devs[i]->dev.parent = &soc_dev->dev;
+
 	platform_add_devices(mop500_platform_devs,
 			ARRAY_SIZE(mop500_platform_devs));
 
@@ -630,11 +636,16 @@ static void __init mop500_init_machine(void)
 static void __init snowball_init_machine(void)
 {
 	int i2c0_devs;
+	int i;
 
 	u8500_init_devices();
 
 	snowball_pins_init();
 
+	if (soc_dev)
+		for (i=0; i<ARRAY_SIZE(snowball_platform_devs); i++)
+			snowball_platform_devs[i]->dev.parent = &soc_dev->dev;
+
 	platform_add_devices(snowball_platform_devs,
 			ARRAY_SIZE(snowball_platform_devs));
 
@@ -655,6 +666,7 @@ static void __init snowball_init_machine(void)
 static void __init hrefv60_init_machine(void)
 {
 	int i2c0_devs;
+	int i;
 
 	/*
 	 * The HREFv60 board removed a GPIO expander and routed
@@ -667,6 +679,10 @@ static void __init hrefv60_init_machine(void)
 
 	hrefv60_pins_init();
 
+	if (soc_dev)
+		for (i=0; i<ARRAY_SIZE(mop500_platform_devs); i++)
+			mop500_platform_devs[i]->dev.parent = &soc_dev->dev;
+
 	platform_add_devices(mop500_platform_devs,
 			ARRAY_SIZE(mop500_platform_devs));
 
arch/arm/mach-ux500/board-u5500.c +7 -0
index 5c9e665..5a74a41 100644
@@ -11,6 +11,7 @@
 #include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
+#include <linux/sys_soc.h>
 #include <linux/mfd/ab5500/ab5500.h>
 
 #include <asm/mach/arch.h>
@@ -134,12 +135,18 @@ static void __init u5500_uart_init(void)
 
 static void __init u5500_init_machine(void)
 {
+	int i;
+
 	u5500_init_devices();
 	nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins));
 	u5500_i2c_init();
 	u5500_sdi_init();
 	u5500_uart_init();
 
+	if (soc_dev)
+		for (i=0; i<ARRAY_SIZE(u5500_platform_devices); i++)
+			u5500_platform_devices[i]->dev.parent = &soc_dev->dev;
+
 	platform_add_devices(u5500_platform_devices,
 		ARRAY_SIZE(u5500_platform_devices));
 }
arch/arm/mach-ux500/cpu-db5500.c +7 -0
index e532c32..1638ccc 100644
@@ -9,6 +9,7 @@
 #include <linux/amba/bus.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/sys_soc.h>
 
 #include <asm/mach/map.h>
 #include <asm/pmu.h>
@@ -222,11 +223,17 @@ static int usb_db5500_tx_dma_cfg[] = {
 
 void __init u5500_init_devices(void)
 {
+	int i;
+
 	db5500_add_gpios();
 	db5500_dma_init();
 	db5500_add_rtc();
 	db5500_add_usb(usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
 
+	if (soc_dev)
+		for (i=0; i<ARRAY_SIZE(db5500_platform_devs); i++)
+			db5500_platform_devs[i]->dev.parent = &soc_dev->dev;
+
 	platform_add_devices(db5500_platform_devs,
 			     ARRAY_SIZE(db5500_platform_devs));
 }
arch/arm/mach-ux500/cpu-db8500.c +12 -1
index 4598b06..655639e 100644
@@ -17,6 +17,7 @@
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/sys_soc.h>
 
 #include <asm/mach/map.h>
 #include <asm/pmu.h>
@@ -193,6 +194,8 @@ static int usb_db8500_tx_dma_cfg[] = {
  */
 void __init u8500_init_devices(void)
 {
+	int i;
+
 	if (cpu_is_u8500ed())
 		dma40_u8500ed_fixup();
 
@@ -200,7 +203,15 @@ void __init u8500_init_devices(void)
 	db8500_add_gpios();
 	db8500_add_usb(usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
 
-	platform_device_register_simple("cpufreq-u8500", -1, NULL, 0);
+	platform_device_register_resndata(
+		(soc_dev) ? &soc_dev->dev : NULL,
+		"cpufreq-u8500", -1, NULL, 0, NULL, 0);
+
+	if (soc_dev) {
+		for (i=0; i<ARRAY_SIZE(platform_devs); i++)
+			platform_devs[i]->dev.parent = &soc_dev->dev;
+	}
+
 	platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
 	return ;
arch/arm/mach-ux500/devices-common.c +16 -3
index 13a4ce0..74bfd1f 100644
@@ -12,10 +12,12 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/amba/bus.h>
+#include <linux/sys_soc.h>
 
 #include <plat/gpio.h>
 
 #include <mach/hardware.h>
+#include <mach/setup.h>
 
 #include "devices-common.h"
 
@@ -46,6 +48,9 @@ dbx500_add_amba_device(const char *name, resource_size_t base,
 
 	dev->dev.platform_data = pdata;
 
+	if (soc_dev)
+		dev->dev.parent = &soc_dev->dev;
+
 	ret = amba_device_register(dev, &iomem_resource);
 	if (ret) {
 		kfree(dev);
@@ -75,6 +80,9 @@ dbx500_add_platform_device(const char *name, int id, void *pdata,
 
 	dev->dev.platform_data = pdata;
 
+	if (soc_dev)
+		dev->dev.parent = &soc_dev->dev;
+
 	ret = platform_device_add(dev);
 	if (ret)
 		goto out_free;
@@ -125,9 +133,14 @@ dbx500_add_gpio(int id, resource_size_t addr, int irq,
 		}
 	};
 
-	return platform_device_register_resndata(NULL, "gpio", id,
-				resources, ARRAY_SIZE(resources),
-				pdata, sizeof(*pdata));
+	return platform_device_register_resndata(
+		(soc_dev) ? &soc_dev->dev : NULL,
+		"gpio",
+		id,
+		resources,
+		ARRAY_SIZE(resources),
+		pdata,
+		sizeof(*pdata));
 }
 
 void dbx500_add_gpios(resource_size_t *base, int num, int irq,
arch/arm/mach-ux500/usb.c +6 -0
index 0a01cbd..aa2df4a 100644
@@ -7,8 +7,11 @@
 #include <linux/platform_device.h>
 #include <linux/usb/musb.h>
 #include <linux/dma-mapping.h>
+#include <linux/sys_soc.h>
+
 #include <plat/ste_dma40.h>
 #include <mach/hardware.h>
+#include <mach/setup.h>
 #include <mach/usb.h>
 
 #define MUSB_DMA40_RX_CH { \
@@ -157,5 +160,8 @@ void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
 	ux500_usb_dma_update_rx_ch_config(dma_rx_cfg);
 	ux500_usb_dma_update_tx_ch_config(dma_tx_cfg);
 
+	if (soc_dev)
+		ux500_musb_device.dev.parent = &soc_dev->dev;
+
 	platform_device_register(&ux500_musb_device);
 }
Signature · 1 line
1.7.4.1
author
#5 lore raw

PATCH 5/5 mach-ux500: add a SoC ID (serial) callback for the u8500

In reply to Lee Jones

With this patch applied the Export SoC Information framework will be able to callback into u8500 Platform code in order to probe for the SoC's unique Identification (serial) number.

---
 arch/arm/mach-ux500/cpu-db8500.c               |   16 ++++++++++++++++
 arch/arm/mach-ux500/include/mach/db8500-regs.h |    4 ++++
 2 files changed, 20 insertions(+), 0 deletions(-)
arch/arm/mach-ux500/cpu-db8500.c +16 -0
index 655639e..9824cd3 100644
@@ -167,6 +167,20 @@ static void __init db8500_add_gpios(void)
 			 IRQ_DB8500_GPIO0, &pdata);
 }
 
+static const char *db8500_get_soc_id(void)
+{
+	void __iomem *uid_base;
+	char buf[1024];
+	ssize_t sz = 0;
+	int i;
+
+	uid_base = __io_address(U8500_BB_UID_BASE);
+	for (i = 0; i < U8500_BB_UID_LENGTH; i++) {
+		sz += sprintf(buf + sz, "%08x", readl(uid_base + i * sizeof(u32)));
+	}
+	return kasprintf(GFP_KERNEL, "%s", buf);
+}
+
 static int usb_db8500_rx_dma_cfg[] = {
 	DB8500_DMA_DEV38_USB_OTG_IEP_1_9,
 	DB8500_DMA_DEV37_USB_OTG_IEP_2_10,
@@ -208,6 +222,8 @@ void __init u8500_init_devices(void)
 		"cpufreq-u8500", -1, NULL, 0, NULL, 0);
 
 	if (soc_dev) {
+		soc_dev->pfn_soc_id = db8500_get_soc_id;
+
 		for (i=0; i<ARRAY_SIZE(platform_devs); i++)
 			platform_devs[i]->dev.parent = &soc_dev->dev;
 	}
arch/arm/mach-ux500/include/mach/db8500-regs.h +4 -0
index 0499971..f569d5c 100644
@@ -166,4 +166,8 @@
 #define U8500_MODEM_BASE	0xe000000
 #define U8500_APE_BASE		0x6000000
 
+/* SoC identification number information */
+#define U8500_BB_UID_BASE (U8500_BACKUPRAM1_BASE + 0xFC0)
+#define U8500_BB_UID_LENGTH 5
+
 #endif
Signature · 1 line
1.7.4.1
#6 lore raw

PATCH 5/5 mach-ux500: add a SoC ID (serial) callback for the u8500

arch/arm/mach-ux500/cpu-db8500.c static void __init db8500_add_gpios(void) · line 182

Quoted 13 lines · Lee Jones
arch/arm/mach-ux500/cpu-db8500.c +13 -0
+static const char *db8500_get_soc_id(void)
+{
+       void __iomem *uid_base;
+       char buf[1024];
+       ssize_t sz = 0;
+       int i;
+
+       uid_base = __io_address(U8500_BB_UID_BASE);
+       for (i = 0; i < U8500_BB_UID_LENGTH; i++) {
+               sz += sprintf(buf + sz, "%08x", readl(uid_base + i * sizeof(u32)));
+       }
+       return kasprintf(GFP_KERNEL, "%s", buf);
+}

You will get a warning from the stack checker here, about putting a 1024 byte string on the stack. Also, I still think it's bad to just access the U8500_BB_UID_BASE from a compile-time constant. Since this gets called from a function that knows the base address of the DB8500 register area, better pass the device in there so that you end up with something like

static void __devinit db8500_read_soc_id(struct db8500_dev *dev)

{
	u32 __iomem *uid = dev->base + U8500_BB_UID_OFFSET;
	snprintf(dev->soc_id, sizeof (dev->soc_id), "%08x%08x%08x%08x%08x",
		readl(uid[0]), readl(uid[1]), readl(uid[2]), readl(uid[3]), readl(uid[4]));
}

The style you use here is preexisting in the db8500 code, but you should not keep adding more of that crap. All the code like

#define db8500_add_i2c0(pdata) \
        dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
#define db8500_add_i2c1(pdata) \
        dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)

should never really have been there. What you want to do for this is to call this from the code that initializes the db8500 controller, and pass the board specific pdata into the db8500 init function, along with the i2c client data.

Arnd

author
#7 lore raw

PATCH 5/5 mach-ux500: add a SoC ID (serial) callback for the u8500

Quoted 21 lines · Arnd Bergmann

arch/arm/mach-ux500/cpu-db8500.c static void __init db8500_add_gpios(void) · line 182

Quoted 13 lines · Lee Jones
arch/arm/mach-ux500/cpu-db8500.c +13 -0
+static const char *db8500_get_soc_id(void)
+{
+       void __iomem *uid_base;
+       char buf[1024];
+       ssize_t sz = 0;
+       int i;
+
+       uid_base = __io_address(U8500_BB_UID_BASE);
+       for (i = 0; i < U8500_BB_UID_LENGTH; i++) {
+               sz += sprintf(buf + sz, "%08x", readl(uid_base + i * sizeof(u32)));
+       }
+       return kasprintf(GFP_KERNEL, "%s", buf);
+}

You will get a warning from the stack checker here, about putting a 1024 byte string on the stack. Also, I still think it's bad to just access the U8500_BB_UID_BASE from a compile-time constant. Since this gets called from a function that knows the base address of the DB8500 register area, better pass the device in there so that you end up with something like

Quoted 6 lines

static void __devinit db8500_read_soc_id(struct db8500_dev *dev)

{
	u32 __iomem *uid = dev->base + U8500_BB_UID_OFFSET;
	snprintf(dev->soc_id, sizeof (dev->soc_id), "%08x%08x%08x%08x%08x",
		readl(uid[0]), readl(uid[1]), readl(uid[2]), readl(uid[3]), readl(uid[4]));
}

No problem.

Where did you get dev->base from though?

Quoted 2 lines

The style you use here is preexisting in the db8500 code, but you should not keep adding more of that crap.

Not meaning to pass the buck at all, but this isn't my code.

It's remnant from when I took this over (starting to wish I hadn't ;))

Quoted 10 lines

All the code like

#define db8500_add_i2c0(pdata) \
        dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
#define db8500_add_i2c1(pdata) \
        dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)

should never really have been there. What you want to do for this is to call this from the code that initializes the db8500 controller, and pass the board specific pdata into the db8500 init function, along with the i2c client data.

Not my domain. Speak to Linus W. :)

Signature · 5 lines
Lee Jones
Linaro ST-Ericsson Landing Team Lead
M: +44 77 88 633 515
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
#8 lore raw

PATCH 5/5 mach-ux500: add a SoC ID (serial) callback for the u8500

Quoted 10 lines · Lee Jones
Quoted 6 lines

static void __devinit db8500_read_soc_id(struct db8500_dev *dev)

{
      u32 __iomem *uid = dev->base + U8500_BB_UID_OFFSET;
      snprintf(dev->soc_id, sizeof (dev->soc_id), "%08x%08x%08x%08x%08x",
              readl(uid[0]), readl(uid[1]), readl(uid[2]), readl(uid[3]), readl(uid[4]));
}

No problem.

Where did you get dev->base from though?

In this example, db8500_dev would be derived from soc_device. and get initialized at the time you register it to the soc subsystem. You clearly have to pass in the base address at some point, so if there is no device tree, that init function should statically set it, but you would still avoid spreading the use of these constants all over the code.

Quoted 6 lines
Quoted 2 lines

The style you use here is preexisting in the db8500 code, but you should not keep adding more of that crap.

Not meaning to pass the buck at all, but this isn't my code.

It's remnant from when I took this over (starting to wish I hadn't ;))

I feel your pain. Sorry that you got dragged in this so deeply when you only wanted a place to add a tiny bit of information.

Quoted 6 lines
Quoted 6 lines

All the code like

#define db8500_add_i2c0(pdata) \
        dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
#define db8500_add_i2c1(pdata) \
        dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
Quoted 6 lines
Quoted 4 lines

should never really have been there. What you want to do for this is to call this from the code that initializes the db8500 controller, and pass the board specific pdata into the db8500 init function, along with the i2c client data.

Not my domain. Speak to Linus W. :)

Yes, I understand. I was mostly using this as explanation about where the problem lies. I'm not expecting you to fix all of the problems of the platform, but in order to add new code the right way, we have to agree on how it should have been there to start with.

Arnd

#9 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

In reply to Lee Jones
Quoted 58 lines · Lee Jones

This patch introduces a new driver to drivers/base. The driver provides a means to export vital SoC data out to userspace via sysfs. Standard information applicable to all SoCs are exported to:

/sys/devices/soc/[1|2|3|...]/[family|machine|revision|soc_id].

It is possible to create SoC specific items via the soc device, which is returned post-registration, although this should be discouraged.

---
 drivers/base/Kconfig    |    3 +
 drivers/base/Makefile   |    1 +
 drivers/base/soc.c      |  103 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sys_soc.h |   27 ++++++++++++
 4 files changed, 134 insertions(+), 0 deletions(-)
 create mode 100644 drivers/base/soc.c
 create mode 100644 include/linux/sys_soc.h
drivers/base/Kconfig +3 -0
index 21cf46f..95f10c5 100644
@@ -172,6 +172,9 @@ config SYS_HYPERVISOR
 	bool
 	default n
 
+config SYS_SOC
+	bool
+
 source "drivers/base/regmap/Kconfig"
 
 endmenu
drivers/base/Makefile +1 -0
index 99a375a..a67a1e7 100644
@@ -18,6 +18,7 @@ obj-$(CONFIG_MODULES)	+= module.o
 endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)	+= regmap/
+obj-$(CONFIG_SYS_SOC) += soc.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
drivers/base/soc.c new file +5 -0
new file mode 100644
index 0000000..e9d908b
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Lee Jones <[email protected]> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2

drivers/base/soc.c line 15

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+ */
+
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+
+static DEFINE_SPINLOCK(register_lock);

If this is really needed, please make it a mutex as you end up calling code paths that can sleep.

drivers/base/soc.c line 16

Quoted 1 line
drivers/base/soc.c new file +1 -0
+static int soc_count = 0;

This should not be needed.

drivers/base/soc.c line 20

Quoted 4 lines
drivers/base/soc.c new file +4 -0
+
+static struct device soc_grandparent = {
+	.init_name = "soc",
+};

NEVER create a static struct device, this is totally not needed and completly wrong.

Quoted 6 lines
drivers/base/soc.c new file +6 -0
+static ssize_t soc_info_get(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+

drivers/base/soc.c line 37

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+	if (!strcmp(attr->attr.name, "machine"))
+		return sprintf(buf, "%s\n", soc_dev->machine);
+	if (!strcmp(attr->attr.name, "family"))
+		return sprintf(buf, "%s\n", soc_dev->family);
+	if (!strcmp(attr->attr.name, "revision"))
+		return sprintf(buf, "%s\n", soc_dev->revision);
+	if (!strcmp(attr->attr.name, "soc_id")) {
+		if (soc_dev->pfn_soc_id)
+			return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
+		else return sprintf(buf, "N/A \n");

Move this line

drivers/base/soc.c line 40

Quoted 3 lines
drivers/base/soc.c new file +3 -0
+	}
+
+	return -EINVAL;

To here?

Quoted 5 lines
drivers/base/soc.c new file +5 -0
+}
+
+struct device_attribute soc_attrs[] = {
+	__ATTR(machine,  S_IRUGO, soc_info_get,  NULL),
+	__ATTR(family,   S_IRUGO, soc_info_get,  NULL),

drivers/base/soc.c line 55

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+	__ATTR(soc_id,   S_IRUGO, soc_info_get,  NULL),
+	__ATTR(revision, S_IRUGO, soc_info_get,  NULL),
+	__ATTR_NULL,
+};
+
+static void soc_device_remove_files(struct device *soc, int i)
+{
+	while (i > 0)
+		device_remove_file(soc, &soc_attrs[--i]);
+}

You do know how to add multiple files, right? Oh wait, this is all not the way to do this in the first place. You just raced userspace :(

Quoted 7 lines
drivers/base/soc.c new file +7 -0
+
+static int __init soc_device_create_files(struct device *dev)
+{
+	int ret = 0;
+	int i   = 0;
+
+	while (soc_attrs[i].attr.name != NULL) {

drivers/base/soc.c line 72

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+		ret = device_create_file(dev, &soc_attrs[i++]);
+		if (ret)
+			goto out;
+	}
+	return ret;
+
+out:
+	soc_device_remove_files(dev, --i);
+	return ret;
+}

Yup, you raced userspace. Please use the proper api for defining a group of attributes for a device by default so that the driver core handles creating and destroying them correctly and in a way that will not be racy (unlike this way.)

drivers/base/soc.c line 73

Quoted 2 lines
drivers/base/soc.c new file +2 -0
+
+int __init soc_device_register(struct device *dev)

Don't pass a struct device in here, why are you making the caller create the device? This is the function that should create it for you?

drivers/base/soc.c line 79

Quoted 5 lines
drivers/base/soc.c new file +5 -0
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+	int ret;
+
+	spin_lock_irq(&register_lock);

Ok.

drivers/base/soc.c line 83

Quoted 4 lines
drivers/base/soc.c new file +4 -0
+
+	if (!soc_count) {
+		/* Register top-level SoC device '/sys/devices/soc' */
+		ret = device_register(&soc_grandparent);

device_register can't be called with a spinlock. You must have gotten lucky in your testing, if you tested this.

Anyway, this is not needed at all, please don't create "dummy" devices in the sysfs tree, properly hook up your new device to where it should be in the device tree.

drivers/base/soc.c line 90

Quoted 7 lines
drivers/base/soc.c new file +7 -0
+		if (ret) {
+			spin_unlock_irq(&register_lock);
+			return ret;
+		}
+	}
+
+	soc_count++;

Nope, don't use this, again, use the correct kernel interface for providing you with a unique number that increments as needed. Don't roll your own that will end up being wrong in the end (like this is, what happens if you remove a device in the middle?)

drivers/base/soc.c line 91

Quoted 1 line
drivers/base/soc.c new file +1 -0
+	dev->parent = &soc_grandparent;

Nope, don't do that.

drivers/base/soc.c line 100

Quoted 9 lines
drivers/base/soc.c new file +9 -0
+	dev_set_name(dev, "%i_%s", soc_count, soc_dev->machine);
+
+	spin_unlock_irq(&register_lock);
+
+	ret = device_register(dev);
+	if (ret)
+		return ret;
+
+	soc_device_create_files(dev);

Nor that.

See above for why.

Quoted 18 lines
drivers/base/soc.c new file +3 -0
+
+	return ret;
+}
include/linux/sys_soc.h new file +9 -0
new file mode 100644
index 0000000..811d7fe
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Lee Jones <[email protected]> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#ifndef __SYS_SOC_H
+#define __SYS_SOC_H
+
+#include <linux/kobject.h>

include/linux/sys_soc.h line 19

Quoted 10 lines
include/linux/sys_soc.h new file +10 -0
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+struct soc_device {
+	struct device dev;
+	const char *machine;
+	const char *family;
+	const char *revision;
+	const char *(*pfn_soc_id)(void);
+};

Nice structure, but why do you export it, you aren't using it anywhere, nor should you be...

include/linux/sys_soc.h line 25

Quoted 6 lines
include/linux/sys_soc.h new file +6 -0
+
+/**
+ * soc_device_register - register SoC as a device
+ * @dev: Parent node '/sys/devices/soc/X'
+ */
+int soc_device_register(struct device *dev);

This whole api needs to be rethunk, please, it's really wrong.

What you want is a way to create a soc device, by calling a function, not be responsible for creating it, then call the soc core, and then somehow, removing it.

Oh wait, you forgot to have a function to remove anything created with the above call, that seems really broken and wrong.

greg k-h

author
#10 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Comments and questions in-line.

Quoted 64 lines · Greg KH
Quoted 63 lines · Lee Jones

This patch introduces a new driver to drivers/base. The driver provides a means to export vital SoC data out to userspace via sysfs. Standard information applicable to all SoCs are exported to:

/sys/devices/soc/[1|2|3|...]/[family|machine|revision|soc_id].

It is possible to create SoC specific items via the soc device, which is returned post-registration, although this should be discouraged.

---
 drivers/base/Kconfig    |    3 +
 drivers/base/Makefile   |    1 +
 drivers/base/soc.c      |  103 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sys_soc.h |   27 ++++++++++++
 4 files changed, 134 insertions(+), 0 deletions(-)
 create mode 100644 drivers/base/soc.c
 create mode 100644 include/linux/sys_soc.h
drivers/base/Kconfig +3 -0
index 21cf46f..95f10c5 100644
@@ -172,6 +172,9 @@ config SYS_HYPERVISOR
 	bool
 	default n
 
+config SYS_SOC
+	bool
+
 source "drivers/base/regmap/Kconfig"
 
 endmenu
drivers/base/Makefile +1 -0
index 99a375a..a67a1e7 100644
@@ -18,6 +18,7 @@ obj-$(CONFIG_MODULES)	+= module.o
 endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)	+= regmap/
+obj-$(CONFIG_SYS_SOC) += soc.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
drivers/base/soc.c new file +10 -0
new file mode 100644
index 0000000..e9d908b
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Lee Jones <[email protected]> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
Quoted 8 lines

drivers/base/soc.c line 15

Quoted 5 lines
drivers/base/soc.c new file +5 -0
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+
+static DEFINE_SPINLOCK(register_lock);

If this is really needed, please make it a mutex as you end up calling code paths that can sleep.

If I use:

"the correct kernel interface for providing you with a unique number that increments as needed"

I'm I correct in assuming that I don't need to use locking?

Quoted 11 lines

drivers/base/soc.c line 16

Quoted 1 line
drivers/base/soc.c new file +1 -0
+static int soc_count = 0;

This should not be needed.

drivers/base/soc.c line 20

Quoted 4 lines
drivers/base/soc.c new file +4 -0
+
+static struct device soc_grandparent = {
+	.init_name = "soc",
+};

NEVER create a static struct device, this is totally not needed and completly wrong.

Noted on the static point, but I believe that it is needed.

That's how /sys/devices/platform does it, which this essentially replaces.

Quoted 19 lines
Quoted 6 lines
drivers/base/soc.c new file +6 -0
+static ssize_t soc_info_get(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+

drivers/base/soc.c line 37

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+	if (!strcmp(attr->attr.name, "machine"))
+		return sprintf(buf, "%s\n", soc_dev->machine);
+	if (!strcmp(attr->attr.name, "family"))
+		return sprintf(buf, "%s\n", soc_dev->family);
+	if (!strcmp(attr->attr.name, "revision"))
+		return sprintf(buf, "%s\n", soc_dev->revision);
+	if (!strcmp(attr->attr.name, "soc_id")) {
+		if (soc_dev->pfn_soc_id)
+			return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
+		else return sprintf(buf, "N/A \n");

Move this line

Quoted 6 lines

drivers/base/soc.c line 40

Quoted 3 lines
drivers/base/soc.c new file +3 -0
+	}
+
+	return -EINVAL;

To here?

I initially had invalid requests return a useful message, but I was told to remove it and return -EINVAL instead:

"Just return -EINVAL or similar here to propogate the error to the user."

Jamie, what say you?

Quoted 10 lines
Quoted 10 lines
drivers/base/soc.c new file +10 -0
+}
+
+struct device_attribute soc_attrs[] = {
+	__ATTR(machine,  S_IRUGO, soc_info_get,  NULL),
+	__ATTR(family,   S_IRUGO, soc_info_get,  NULL),
+	__ATTR(soc_id,   S_IRUGO, soc_info_get,  NULL),
+	__ATTR(revision, S_IRUGO, soc_info_get,  NULL),
+	__ATTR_NULL,
+};
+
Quoted 8 lines

drivers/base/soc.c line 55

Quoted 5 lines
drivers/base/soc.c new file +5 -0
+static void soc_device_remove_files(struct device *soc, int i)
+{
+	while (i > 0)
+		device_remove_file(soc, &soc_attrs[--i]);
+}

You do know how to add multiple files, right? Oh wait, this is all not the way to do this in the first place. You just raced userspace :(

I didn't, but I will soon.

Quoted 14 lines
Quoted 14 lines
drivers/base/soc.c new file +14 -0
+
+static int __init soc_device_create_files(struct device *dev)
+{
+	int ret = 0;
+	int i   = 0;
+
+	while (soc_attrs[i].attr.name != NULL) {
+		ret = device_create_file(dev, &soc_attrs[i++]);
+		if (ret)
+			goto out;
+	}
+	return ret;
+
+out:
Quoted 8 lines

drivers/base/soc.c line 72

Quoted 3 lines
drivers/base/soc.c new file +3 -0
+	soc_device_remove_files(dev, --i);
+	return ret;
+}

Yup, you raced userspace. Please use the proper api for defining a group of attributes for a device by default so that the driver core handles creating and destroying them correctly and in a way that will not be racy (unlike this way.)

No problem. I'll look it up and make the changes.

Quoted 5 lines

drivers/base/soc.c line 73

Quoted 2 lines
drivers/base/soc.c new file +2 -0
+
+int __init soc_device_register(struct device *dev)

Don't pass a struct device in here, why are you making the caller create the device? This is the function that should create it for you?

I guess I can just return it instead, so it will become:

struct device * __init soc_device_register(void)

Is that more in keeping with what you would expect to see?

Quoted 16 lines

drivers/base/soc.c line 79

Quoted 5 lines
drivers/base/soc.c new file +5 -0
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+	int ret;
+
+	spin_lock_irq(&register_lock);

Ok.

drivers/base/soc.c line 83

Quoted 4 lines
drivers/base/soc.c new file +4 -0
+
+	if (!soc_count) {
+		/* Register top-level SoC device '/sys/devices/soc' */
+		ret = device_register(&soc_grandparent);

device_register can't be called with a spinlock. You must have gotten lucky in your testing, if you tested this.

Quoted 3 lines

Anyway, this is not needed at all, please don't create "dummy" devices in the sysfs tree, properly hook up your new device to where it should be in the device tree.

We need a /sys/devices/soc, how else can this be done?

Would it make you happier if I called it a bus?

Quoted 4 lines
Quoted 4 lines
drivers/base/soc.c new file +4 -0
+		if (ret) {
+			spin_unlock_irq(&register_lock);
+			return ret;
+		}
Quoted 8 lines

drivers/base/soc.c line 90

Quoted 3 lines
drivers/base/soc.c new file +3 -0
+	}
+
+	soc_count++;

Nope, don't use this, again, use the correct kernel interface for providing you with a unique number that increments as needed. Don't roll your own that will end up being wrong in the end (like this is, what happens if you remove a device in the middle?)

Noted.

Quoted 3 lines

drivers/base/soc.c line 91

Quoted 1 line
drivers/base/soc.c new file +1 -0
+	dev->parent = &soc_grandparent;

Nope, don't do that.

As above.

Quoted 37 lines

drivers/base/soc.c line 100

Quoted 9 lines
drivers/base/soc.c new file +9 -0
+	dev_set_name(dev, "%i_%s", soc_count, soc_dev->machine);
+
+	spin_unlock_irq(&register_lock);
+
+	ret = device_register(dev);
+	if (ret)
+		return ret;
+
+	soc_device_create_files(dev);

Nor that.

See above for why.

Quoted 23 lines
drivers/base/soc.c new file +3 -0
+
+	return ret;
+}
include/linux/sys_soc.h new file +14 -0
new file mode 100644
index 0000000..811d7fe
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Lee Jones <[email protected]> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#ifndef __SYS_SOC_H
+#define __SYS_SOC_H
+
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+struct soc_device {
+	struct device dev;
Quoted 8 lines

include/linux/sys_soc.h line 19

Quoted 5 lines
include/linux/sys_soc.h new file +5 -0
+	const char *machine;
+	const char *family;
+	const char *revision;
+	const char *(*pfn_soc_id)(void);
+};

Nice structure, but why do you export it, you aren't using it anywhere, nor should you be...

Okay, I'll use the returning struct device * from soc_device_register() register instead.

Quoted 9 lines

include/linux/sys_soc.h line 25

Quoted 6 lines
include/linux/sys_soc.h new file +6 -0
+
+/**
+ * soc_device_register - register SoC as a device
+ * @dev: Parent node '/sys/devices/soc/X'
+ */
+int soc_device_register(struct device *dev);

This whole api needs to be rethunk, please, it's really wrong.

Quoted 6 lines

What you want is a way to create a soc device, by calling a function, not be responsible for creating it, then call the soc core, and then somehow, removing it.

Oh wait, you forgot to have a function to remove anything created with the above call, that seems really broken and wrong.

Again, I did have an unregister function, but I was told to remove it.

"The exit function does not make any sense if you cannot build the soc support itself as a module, which in turn makes no sense at all."

What if I put it back and removed the __exit syntax and used it as a standard unregister/free function? Would that be more to everyone's taste?

Thanks for your time.

Kind regards,
Lee

Signature · 5 lines
Lee Jones
Linaro ST-Ericsson Landing Team Lead
M: +44 77 88 633 515
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
#11 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 28 lines · Lee Jones
Quoted 20 lines · Greg KH
Quoted 6 lines · Lee Jones
drivers/base/soc.c new file +6 -0
+static ssize_t soc_info_get(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+

drivers/base/soc.c line 37

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+	if (!strcmp(attr->attr.name, "machine"))
+		return sprintf(buf, "%s\n", soc_dev->machine);
+	if (!strcmp(attr->attr.name, "family"))
+		return sprintf(buf, "%s\n", soc_dev->family);
+	if (!strcmp(attr->attr.name, "revision"))
+		return sprintf(buf, "%s\n", soc_dev->revision);
+	if (!strcmp(attr->attr.name, "soc_id")) {
+		if (soc_dev->pfn_soc_id)
+			return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
+		else return sprintf(buf, "N/A \n");

Move this line

Quoted 6 lines

drivers/base/soc.c line 40

Quoted 3 lines
drivers/base/soc.c new file +3 -0
+	}
+
+	return -EINVAL;

To here?

Quoted 6 lines

I initially had invalid requests return a useful message, but I was told to remove it and return -EINVAL instead:

"Just return -EINVAL or similar here to propogate the error to the user."

Jamie, what say you?

Well if there isn't an ID for the SoC, then I think it's better for a read() to return an error rather than have to parse for a special string like "N/A ". So rather than returning that string, perhaps something like:

	if (!strcmp(attr->attr.name, "soc_id")) {
		if (!soc_dev->pfn_soc_id)
			return -ENOENT;
		return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
	}

or if you don't think this is an error, default to an id of "0" so that it can be parsed by tools?

Jamie

author
#12 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 41 lines · Jamie Iles
Quoted 28 lines · Lee Jones
Quoted 20 lines · Greg KH
Quoted 6 lines · Lee Jones
drivers/base/soc.c new file +6 -0
+static ssize_t soc_info_get(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+

drivers/base/soc.c line 37

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+	if (!strcmp(attr->attr.name, "machine"))
+		return sprintf(buf, "%s\n", soc_dev->machine);
+	if (!strcmp(attr->attr.name, "family"))
+		return sprintf(buf, "%s\n", soc_dev->family);
+	if (!strcmp(attr->attr.name, "revision"))
+		return sprintf(buf, "%s\n", soc_dev->revision);
+	if (!strcmp(attr->attr.name, "soc_id")) {
+		if (soc_dev->pfn_soc_id)
+			return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
+		else return sprintf(buf, "N/A \n");

Move this line

Quoted 6 lines

drivers/base/soc.c line 40

Quoted 3 lines
drivers/base/soc.c new file +3 -0
+	}
+
+	return -EINVAL;

To here?

Quoted 6 lines

I initially had invalid requests return a useful message, but I was told to remove it and return -EINVAL instead:

"Just return -EINVAL or similar here to propogate the error to the user."

Jamie, what say you?

Well if there isn't an ID for the SoC, then I think it's better for a read() to return an error rather than have to parse for a special string like "N/A ". So rather than returning that string, perhaps something like:

Quoted 8 lines
	if (!strcmp(attr->attr.name, "soc_id")) {
		if (!soc_dev->pfn_soc_id)
			return -ENOENT;
		return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
	}

or if you don't think this is an error, default to an id of "0" so that it can be parsed by tools?

What about at the very end of the function?

What should we return if an inappropriate attr->attr.name is used?

Signature · 5 lines
Lee Jones
Linaro ST-Ericsson Landing Team Lead
M: +44 77 88 633 515
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
#13 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 48 lines · Lee Jones
Quoted 47 lines · Jamie Iles
Quoted 28 lines · Lee Jones
Quoted 20 lines · Greg KH
Quoted 6 lines · Lee Jones
drivers/base/soc.c new file +6 -0
+static ssize_t soc_info_get(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+

drivers/base/soc.c line 37

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+	if (!strcmp(attr->attr.name, "machine"))
+		return sprintf(buf, "%s\n", soc_dev->machine);
+	if (!strcmp(attr->attr.name, "family"))
+		return sprintf(buf, "%s\n", soc_dev->family);
+	if (!strcmp(attr->attr.name, "revision"))
+		return sprintf(buf, "%s\n", soc_dev->revision);
+	if (!strcmp(attr->attr.name, "soc_id")) {
+		if (soc_dev->pfn_soc_id)
+			return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
+		else return sprintf(buf, "N/A \n");

Move this line

Quoted 6 lines

drivers/base/soc.c line 40

Quoted 3 lines
drivers/base/soc.c new file +3 -0
+	}
+
+	return -EINVAL;

To here?

Quoted 6 lines

I initially had invalid requests return a useful message, but I was told to remove it and return -EINVAL instead:

"Just return -EINVAL or similar here to propogate the error to the user."

Jamie, what say you?

Well if there isn't an ID for the SoC, then I think it's better for a read() to return an error rather than have to parse for a special string like "N/A ". So rather than returning that string, perhaps something like:

	if (!strcmp(attr->attr.name, "soc_id")) {
		if (!soc_dev->pfn_soc_id)
			return -ENOENT;
		return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
	}
Quoted 6 lines
Quoted 2 lines

or if you don't think this is an error, default to an id of "0" so that it can be parsed by tools?

What about at the very end of the function?

What should we return if an inappropriate attr->attr.name is used?

That shouldn't happen as it is only ever registered with valid attributes. That said, you do need to return something so -EINVAL seems like a reasonable choice.

Jamie

#14 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

In reply to Lee Jones
Quoted 1 line · Lee Jones

Comments and questions in-line.

As they should be :)

Quoted 7 lines · Greg KH
Quoted 5 lines · Lee Jones
Quoted 1 line

+static DEFINE_SPINLOCK(register_lock);

If this is really needed, please make it a mutex as you end up calling code paths that can sleep.

Quoted 6 lines

If I use:

"the correct kernel interface for providing you with a unique number that increments as needed"

I'm I correct in assuming that I don't need to use locking?

Yes, don't you agree?

You do know what this interface is, right? :)

Quoted 12 lines
Quoted 11 lines
Quoted 1 line

+static int soc_count = 0;

This should not be needed.

drivers/base/soc.c line 20

Quoted 4 lines
drivers/base/soc.c new file +4 -0
+
+static struct device soc_grandparent = {
+	.init_name = "soc",
+};

NEVER create a static struct device, this is totally not needed and completly wrong.

Quoted 3 lines

Noted on the static point, but I believe that it is needed.

That's how /sys/devices/platform does it, which this essentially replaces.

NO NO NO NO NO NO

Again, no.

This does NOT replace /sys/devices/platform in any shape, manner, or form.

Platform devices are "special" in that they are the "grab-bag of devices that no one seems to know how to hook up to a sane bus so we throw them all in the same heap and try to ignore the ugliness of them."

Never repeat the platform code anywhere else, that's not acceptable at all.

If you want to make this a "bus" that's probably best, as then you would get to enumerate over all /sys/bus/soc/ devices just fine, no matter where in the device tree they live.

Quoted 26 lines
Quoted 19 lines
Quoted 6 lines
drivers/base/soc.c new file +6 -0
+static ssize_t soc_info_get(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+

drivers/base/soc.c line 37

Quoted 10 lines
drivers/base/soc.c new file +10 -0
+	if (!strcmp(attr->attr.name, "machine"))
+		return sprintf(buf, "%s\n", soc_dev->machine);
+	if (!strcmp(attr->attr.name, "family"))
+		return sprintf(buf, "%s\n", soc_dev->family);
+	if (!strcmp(attr->attr.name, "revision"))
+		return sprintf(buf, "%s\n", soc_dev->revision);
+	if (!strcmp(attr->attr.name, "soc_id")) {
+		if (soc_dev->pfn_soc_id)
+			return sprintf(buf, "%s\n", soc_dev->pfn_soc_id());
+		else return sprintf(buf, "N/A \n");

Move this line

Quoted 6 lines

drivers/base/soc.c line 40

Quoted 3 lines
drivers/base/soc.c new file +3 -0
+	}
+
+	return -EINVAL;

To here?

Quoted 4 lines

I initially had invalid requests return a useful message, but I was told to remove it and return -EINVAL instead:

"Just return -EINVAL or similar here to propogate the error to the user."

No, if a SOC doesn't have one of these attributes, then just don't create the sysfs file. Don't return -EINVAL for something that you know better than to have created in the first place, are you trying to make it hard for userspace? :)

Quoted 10 lines
Quoted 4 lines
Quoted 1 line

+int __init soc_device_register(struct device *dev)

Don't pass a struct device in here, why are you making the caller create the device? This is the function that should create it for you?

I guess I can just return it instead, so it will become:

struct device * __init soc_device_register(void)

Is that more in keeping with what you would expect to see?

no.

How did you pass the attribute data into this core so that it knows how to get to it? You didn't, which is a mess.

How about something like:

	struct soc_device *soc_device_create(struct device *parent, struct soc_device_attributes *attr);

That would have the proper way to handle lifetime rules, userspace notificatation of userpace, placement in sysfs, and all the other good stuff.

I'm feeling like it would be simpler for me to write this code than to keep providing review comments like this telling you to rewrite the whole thing over again each time :)

Anyone want to send me a device that this code is needed for so I can do it?

Quoted 16 lines
Quoted 16 lines

drivers/base/soc.c line 79

Quoted 5 lines
drivers/base/soc.c new file +5 -0
+{
+	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+	int ret;
+
+	spin_lock_irq(&register_lock);

Ok.

drivers/base/soc.c line 83

Quoted 4 lines
drivers/base/soc.c new file +4 -0
+
+	if (!soc_count) {
+		/* Register top-level SoC device '/sys/devices/soc' */
+		ret = device_register(&soc_grandparent);

device_register can't be called with a spinlock. You must have gotten lucky in your testing, if you tested this.

Quoted 5 lines
Quoted 3 lines

Anyway, this is not needed at all, please don't create "dummy" devices in the sysfs tree, properly hook up your new device to where it should be in the device tree.

We need a /sys/devices/soc, how else can this be done?

No you do not not, why would you think so?

Quoted 1 line

Would it make you happier if I called it a bus?

Yes, see the other response about creating a bus for these, which would give you /sys/bus/soc/ where you can properly enumerate your devices, which is what I think you want to be able to do, right?

thanks,

greg k-h

#15 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 11 lines · Greg KH

no.

How did you pass the attribute data into this core so that it knows how to get to it? You didn't, which is a mess.

How about something like:

        struct soc_device *soc_device_create(struct device *parent, struct soc_device_attributes *attr);

That would have the proper way to handle lifetime rules, userspace notificatation of userpace, placement in sysfs, and all the other good stuff.

I early on objected to the individual soc driver providing a set of attributes, because we really want the attributes to follow a common interface and I want to make it *hard* to add arbitrary other attributes that are not documented.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/base/soc.c line 83

Quoted 4 lines
drivers/base/soc.c new file +4 -0
+
+  if (!soc_count) {
+          /* Register top-level SoC device '/sys/devices/soc' */
+          ret = device_register(&soc_grandparent);

device_register can't be called with a spinlock. You must have gotten lucky in your testing, if you tested this.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Anyway, this is not needed at all, please don't create "dummy" devices in the sysfs tree, properly hook up your new device to where it should be in the device tree.

We need a /sys/devices/soc, how else can this be done?

No you do not not, why would you think so?

Well, where is all comes from is the desire to have a way from user space to find these devices, based on some path in the device tree. We had discussed putting it into

/sys/class/soc
/sys/bus/soc
/sys/devices/platform/soc
/sys/devices/platform/soc%d

and a few others and eventually settled on /sys/devices/soc.

Quoted 5 lines
Quoted 1 line

Would it make you happier if I called it a bus?

Yes, see the other response about creating a bus for these, which would give you /sys/bus/soc/ where you can properly enumerate your devices, which is what I think you want to be able to do, right?

I think that would be a reasonable interface, but how does this work when the device was created by of_platform_bus_probe? Should we assume that any top-level device in the flattened device tree is a soc? How about just adding a child device in each soc node that is registered to the soc_bus_type?

That would end up looking like

/sys/devices/db8500

		   /soc0   # this is the soc device
		   /i2c-0  # and here are the other platform devices below db8500 
		   /spi-0
    /bus/soc/devices/soc0 -> ../../../devices/db8500/soc0
    /bus/platform/devices/i2c-0 -> ../../../devices/db8500/i2c-0

	Arnd
#16 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 9 lines · Arnd Bergmann
Quoted 8 lines · Greg KH

no.

How did you pass the attribute data into this core so that it knows how to get to it? You didn't, which is a mess.

How about something like:

        struct soc_device *soc_device_create(struct device *parent, struct soc_device_attributes *attr);
Quoted 8 lines
Quoted 3 lines

That would have the proper way to handle lifetime rules, userspace notificatation of userpace, placement in sysfs, and all the other good stuff.

I early on objected to the individual soc driver providing a set of attributes, because we really want the attributes to follow a common interface and I want to make it *hard* to add arbitrary other attributes that are not documented.

That's fine, which is why the struct soc_device_attributes are there, those are common and well defined.

We can just do a simple return of 'int' to keep the caller from ever having access to the device at all, which, if these can never be removed, is a great way to keep anyone from messing with them.

So the interface gets even simpler:

	int soc_device_create(struct device *parent, struct soc_device_attributes *attr);

Look good?

Quoted 20 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

drivers/base/soc.c line 83

Quoted 4 lines
drivers/base/soc.c new file +4 -0
+
+  if (!soc_count) {
+          /* Register top-level SoC device '/sys/devices/soc' */
+          ret = device_register(&soc_grandparent);

device_register can't be called with a spinlock. You must have gotten lucky in your testing, if you tested this.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Anyway, this is not needed at all, please don't create "dummy" devices in the sysfs tree, properly hook up your new device to where it should be in the device tree.

We need a /sys/devices/soc, how else can this be done?

No you do not not, why would you think so?

Well, where is all comes from is the desire to have a way from user space to find these devices, based on some path in the device tree. We had discussed putting it into

Quoted 6 lines

/sys/class/soc
/sys/bus/soc
/sys/devices/platform/soc
/sys/devices/platform/soc%d

and a few others and eventually settled on /sys/devices/soc.

No, please use /sys/bus/soc as these are all of the same "type".

Quoted 11 lines
Quoted 5 lines
Quoted 1 line

Would it make you happier if I called it a bus?

Yes, see the other response about creating a bus for these, which would give you /sys/bus/soc/ where you can properly enumerate your devices, which is what I think you want to be able to do, right?

I think that would be a reasonable interface, but how does this work when the device was created by of_platform_bus_probe? Should we assume that any top-level device in the flattened device tree is a soc? How about just adding a child device in each soc node that is registered to the soc_bus_type?

Yes, that will work with the above soc_device_create() call.

Quoted 8 lines

That would end up looking like

/sys/devices/db8500

		   /soc0   # this is the soc device
		   /i2c-0  # and here are the other platform devices below db8500 
		   /spi-0
    /bus/soc/devices/soc0 -> ../../../devices/db8500/soc0
    /bus/platform/devices/i2c-0 -> ../../../devices/db8500/i2c-0

Looks good to me. Using a bus, and the above interface, will result in this.

thanks,

greg k-h

author
#17 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

In reply to Greg KH

I don't have a great deal of time at the moment, as I'm currently on the train on my way to Plumbers, but I would like to say just one thing.

Quoted 3 lines · Greg KH

I'm feeling like it would be simpler for me to write this code than to keep providing review comments like this telling you to rewrite the whole thing over again each time :)

I'd really rather you didn't.

I have put a great deal of my own time into this and I really want to see it through. Up until now I have been finding it quite difficult to please everyone. I have been trying to follow everyone's suggestions and as soon as I think we're getting close, the world flips upside down. When I return, I will sit down and go through all of your (and Arnd's) suggestions and re-write it.

Please bear with me.

Quoted 2 lines

Anyone want to send me a device that this code is needed for so I can do it?

No. ;)

Kind regards,
Lee

#18 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 8 lines · On Tuesday 06 September 2011 10:41:11 Lee Jones wrote:

I don't have a great deal of time at the moment, as I'm currently on the train on my way to Plumbers, but I would like to say just one thing.

Quoted 3 lines · Greg KH

I'm feeling like it would be simpler for me to write this code than to keep providing review comments like this telling you to rewrite the whole thing over again each time

Quoted 8 lines

I'd really rather you didn't.

I have put a great deal of my own time into this and I really want to see it through. Up until now I have been finding it quite difficult to please everyone. I have been trying to follow everyone's suggestions and as soon as I think we're getting close, the world flips upside down. When I return, I will sit down and go through all of your (and Arnd's) suggestions and re-write it.

Ok. BTW, I feel a bit guilty for making you go through all this work on code that was written by other people and you are not to blame for, but I think we on the right track now. If you have any doubts about how to go on with the next version, please contact on IRC or phone so we can discuss the details. I think that will be more productive than the past email exchanges.

Arnd

#19 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

In reply to Lee Jones
Quoted 8 lines · Lee Jones

I don't have a great deal of time at the moment, as I'm currently on the train on my way to Plumbers, but I would like to say just one thing.

Quoted 3 lines · Greg KH

I'm feeling like it would be simpler for me to write this code than to keep providing review comments like this telling you to rewrite the whole thing over again each time :)

Quoted 8 lines

I'd really rather you didn't.

I have put a great deal of my own time into this and I really want to see it through. Up until now I have been finding it quite difficult to please everyone. I have been trying to follow everyone's suggestions and as soon as I think we're getting close, the world flips upside down. When I return, I will sit down and go through all of your (and Arnd's) suggestions and re-write it.

Ok, but expect a very tough code review if you do this. :)

greg k-h

author
#20 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 11 lines · Greg KH
Quoted 10 lines · Lee Jones

I don't have a great deal of time at the moment, as I'm currently on the train on my way to Plumbers, but I would like to say just one thing.

Quoted 3 lines · Greg KH

I'm feeling like it would be simpler for me to write this code than to keep providing review comments like this telling you to rewrite the whole thing over again each time :)

I'd really rather you didn't.

Quoted 8 lines
Quoted 6 lines

I have put a great deal of my own time into this and I really want to see it through. Up until now I have been finding it quite difficult to please everyone. I have been trying to follow everyone's suggestions and as soon as I think we're getting close, the world flips upside down. When I return, I will sit down and go through all of your (and Arnd's) suggestions and re-write it.

Ok, but expect a very tough code review if you do this. :)

What's new? ;)

#21 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

In reply to Greg KH
Quoted 6 lines · Greg KH

Review

Quoted 2 lines · Lee Jones
(quoted diff) +2 -0
+
+int __init soc_device_register(struct device *dev)

Don't pass a struct device in here, why are you making the caller create the device? This is the function that should create it for you?

Well, when we have device tree based probing, the soc device might already have been created by of_bus_probe(), so we just want to pass it to the soc core code in order to create the common interfaces.

It's probably not right that soc_device_register actually calls device_register, because when you have a device that you pass in, it will already be registered.

Quoted 20 lines
Quoted 20 lines
include/linux/sys_soc.h new file +14 -0
new file mode 100644
index 0000000..811d7fe
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Lee Jones <[email protected]> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#ifndef __SYS_SOC_H
+#define __SYS_SOC_H
+
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+struct soc_device {
+	struct device dev;
Quoted 8 lines

include/linux/sys_soc.h line 19

Quoted 5 lines
include/linux/sys_soc.h new file +5 -0
+	const char *machine;
+	const char *family;
+	const char *revision;
+	const char *(*pfn_soc_id)(void);
+};

Nice structure, but why do you export it, you aren't using it anywhere, nor should you be...

This gets filled by the soc-specific code with information that is exported through the common callbacks, so it needs to be visible to the platforms.

Quoted 9 lines

include/linux/sys_soc.h line 25

Quoted 6 lines
include/linux/sys_soc.h new file +6 -0
+
+/**
+ * soc_device_register - register SoC as a device
+ * @dev: Parent node '/sys/devices/soc/X'
+ */
+int soc_device_register(struct device *dev);

This whole api needs to be rethunk, please, it's really wrong.

Quoted 3 lines

What you want is a way to create a soc device, by calling a function, not be responsible for creating it, then call the soc core, and then somehow, removing it.

Yes, it's definitely still not where it ought to be, and we've been discussing this for ages. It all started out as a way to find out information about the system, and I suggested to better make that information part of the interface for the soc node that is required anyway, rather than making up a purely fictional device.

Now, we need this to cover two scenarios:

1. The classic setup without device tree where the soc node is created by platform code. This would work great by just calling a function that creates the device and lets the soc code add the children according to compile-time tables of child devices.

2. Probing from OF device-tree, where the linux device tree is populated by walking the devices found in the flat device tree description. This doesn't really fit your suggestion, nor does it fit Lee's patch really, because it would require reparenting the soc node into /sys/devices/soc and registering it again after it's already registered.

I think the ideal solution would be to make the soc layer a class that can be set when initially adding the device (one way or another) and that adds the standard attributes. Since you don't really like classes any more, another option would be to just have a function call that adds an attribute group to the soc node, but then it's not easy to find which devices are actually soc root nodes.

Quoted 2 lines

Oh wait, you forgot to have a function to remove anything created with the above call, that seems really broken and wrong.

There is no way to remove a soc from the system, just like there is no complementary function to pcibios_scan_root that removes the PCI root bridge.

Arnd

#22 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 11 lines · Arnd Bergmann
Quoted 6 lines · Greg KH

Review

Quoted 2 lines · Lee Jones
(quoted diff) +2 -0
+
+int __init soc_device_register(struct device *dev)

Don't pass a struct device in here, why are you making the caller create the device? This is the function that should create it for you?

Well, when we have device tree based probing, the soc device might already have been created by of_bus_probe(), so we just want to pass it to the soc core code in order to create the common interfaces.

No, you want to pass the PARENT pointer in here that this new SOC device will hang off of. You can't expect to pass in any old random struct device and expect it to make any kind of sense at all.

Quoted 3 lines

It's probably not right that soc_device_register actually calls device_register, because when you have a device that you pass in, it will already be registered.

And where would it be registered? No, please don't do this, again, have this code create the struct device because it is responsible for it. That's the way the rest of the kernel works, please don't try to create new models to confuse everyone even more than is needed :)

Quoted 29 lines
Quoted 20 lines
Quoted 20 lines
include/linux/sys_soc.h new file +14 -0
new file mode 100644
index 0000000..811d7fe
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Lee Jones <[email protected]> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#ifndef __SYS_SOC_H
+#define __SYS_SOC_H
+
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+struct soc_device {
+	struct device dev;
Quoted 8 lines

include/linux/sys_soc.h line 19

Quoted 5 lines
include/linux/sys_soc.h new file +5 -0
+	const char *machine;
+	const char *family;
+	const char *revision;
+	const char *(*pfn_soc_id)(void);
+};

Nice structure, but why do you export it, you aren't using it anywhere, nor should you be...

Quoted 2 lines

This gets filled by the soc-specific code with information that is exported through the common callbacks, so it needs to be visible to the platforms.

But this api doesn't allow that to happen, so use it to create the data in the first place somehow, this is really confusing as-is.

Quoted 26 lines
Quoted 9 lines

include/linux/sys_soc.h line 25

Quoted 6 lines
include/linux/sys_soc.h new file +6 -0
+
+/**
+ * soc_device_register - register SoC as a device
+ * @dev: Parent node '/sys/devices/soc/X'
+ */
+int soc_device_register(struct device *dev);

This whole api needs to be rethunk, please, it's really wrong.

Quoted 3 lines

What you want is a way to create a soc device, by calling a function, not be responsible for creating it, then call the soc core, and then somehow, removing it.

Yes, it's definitely still not where it ought to be, and we've been discussing this for ages. It all started out as a way to find out information about the system, and I suggested to better make that information part of the interface for the soc node that is required anyway, rather than making up a purely fictional device.

Now, we need this to cover two scenarios:

1. The classic setup without device tree where the soc node is created by platform code. This would work great by just calling a function that creates the device and lets the soc code add the children according to compile-time tables of child devices.

Quoted 6 lines

2. Probing from OF device-tree, where the linux device tree is populated by walking the devices found in the flat device tree description. This doesn't really fit your suggestion, nor does it fit Lee's patch really, because it would require reparenting the soc node into /sys/devices/soc and registering it again after it's already registered.

No it would not, both of these work just fine like we handle with all other subsystems. You pass in the parent, and if it is not present, the device will show up under /sys/devices/virtual/ just fine. Please don't create new type of things here.

Quoted 7 lines

I think the ideal solution would be to make the soc layer a class that can be set when initially adding the device (one way or another) and that adds the standard attributes. Since you don't really like classes any more, another option would be to just have a function call that adds an attribute group to the soc node, but then it's not easy to find which devices are actually soc root nodes.

Then make it a bus, like it should be, which would solve all of this, right?

Quoted 6 lines
Quoted 2 lines

Oh wait, you forgot to have a function to remove anything created with the above call, that seems really broken and wrong.

There is no way to remove a soc from the system, just like there is no complementary function to pcibios_scan_root that removes the PCI root bridge.

And no one is ever going to remove the module that created the SOC device in the first place? It just really bothers me to see creation code but no removal code, as it feels wrong somehow :)

thanks,

greg k-h

#23 lore raw

PATCH 1/5 Framework for exporting System-on-Chip information via sysfs

Quoted 31 lines · Greg KH
Quoted 30 lines · Arnd Bergmann
Quoted 28 lines · Greg KH
Quoted 15 lines
include/linux/sys_soc.h new file +9 -0
new file mode 100644
index 0000000..811d7fe
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Lee Jones <[email protected]> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#ifndef __SYS_SOC_H
+#define __SYS_SOC_H
+
+#include <linux/kobject.h>

include/linux/sys_soc.h line 19

Quoted 10 lines
include/linux/sys_soc.h new file +10 -0
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+struct soc_device {
+	struct device dev;
+	const char *machine;
+	const char *family;
+	const char *revision;
+	const char *(*pfn_soc_id)(void);
+};

Nice structure, but why do you export it, you aren't using it anywhere, nor should you be...

Quoted 5 lines
Quoted 2 lines

This gets filled by the soc-specific code with information that is exported through the common callbacks, so it needs to be visible to the platforms.

But this api doesn't allow that to happen, so use it to create the data in the first place somehow, this is really confusing as-is.

Yes, that is true. I hadn't noticed the 'struct device' in the above structure. What really needs to happen is the platform code to fill out a structure with all the attribute data and to pass that into the soc common code as constant data which then gets added to the device data.

Quoted 10 lines
Quoted 7 lines

I think the ideal solution would be to make the soc layer a class that can be set when initially adding the device (one way or another) and that adds the standard attributes. Since you don't really like classes any more, another option would be to just have a function call that adds an attribute group to the soc node, but then it's not easy to find which devices are actually soc root nodes.

Then make it a bus, like it should be, which would solve all of this, right?

I'm not sure if we're talking about the same thing. Do you mean adding an artifical device (like a class_device) under the soc device node and have that be of soc_bus type? Or do you mean putting the entire soc with all its platform_device children on the soc_bus?

In the former case, it's a somewhat ugly representation. It would be really nice for the soc to be just one device, not one device to hang all the children off and another one to provide a user-space interface.

In the latter case, we would have to rewrite the way we probe SoCs from the device tree so that the root node of the soc becomes a soc_bus device instead of a platform_bus device.

Quoted 10 lines
Quoted 6 lines
Quoted 2 lines

Oh wait, you forgot to have a function to remove anything created with the above call, that seems really broken and wrong.

There is no way to remove a soc from the system, just like there is no complementary function to pcibios_scan_root that removes the PCI root bridge.

And no one is ever going to remove the module that created the SOC device in the first place? It just really bothers me to see creation code but no removal code, as it feels wrong somehow :)

SoC code fundamentally cannot be a module, since the soc contains all the basic stuff like irq controller, clocksource etc. If it didn't have those, it would not be a system-on-a-chip but rather some random multifunction device you hang off some bus.

Arnd