lkml.org 
[lkml]   [2002]   [Sep]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[BK PATCH] Representing System devices and CPUs

Hey there.

The changelogs are below, but this is the executive summary.

This beefs up the support for system devices. It introduces the following
structures:


struct sys_root {
u32 id;
struct device dev;
struct device sysdev;
};

struct sys_device {
char * name;
u32 id;
struct sys_root * root;
struct device dev;
};


The former is intended for multi-board systems (e.g. NUMA-like) so they
can accurately represent their topology. The latter is for basic
description of system-level devices, like CPUs, PICs, etc.

The idea is that the enumerators for multi-board systems will register
each board (aka 'node') on boot. They should also know what board each
system device is on, and set that in the sys_device structure.

Without ->root set, system devices will be added as a child of a pseudo
bus: 'sys'. They appear in driverfs in the root/sys/ directory. Each
alternative root gets a directory under root/, and each gets a 'sys'
subdirectory. System devices appear as children of the root's 'sysdev'.
struct sys_root::dev can be used to parent other devices and buses
discovered on that board; e.g. PCI buses on that board.


I've taken the liberty to also implement a CPU device class, and a generic
cpu structure. The device class is registered on boot, which exports all
CPUs in a common place in driverfs in class/cpu/.

For ia32, I've created a simple CPU device driver and a static array of
cpu devices of size NR_CPUS, which are manually registered on boot. The
cpus get directories under root/sys/ in driverfs, like this:

`-- root
`-- sys
|-- cpu0
|-- cpu1
...

And get symlinks in the class directory like this:

|-- class
| |-- cpu
| | |-- devices
| | | |-- 0 -> ../../../root/sys/cpu0
| | | |-- 1 -> ../../../root/sys/cpu1
...


When the CPUs are registered, driverfs files may now be created for them.
I recommend creating device interfaces for various CPU features and
registering them with the device class. When the device is registered with
the class, it will also be registered with all of the interfaces of the
class. More documentation about this is available in the
Documentation/driver-model/ directory (which is now updated!)

Pending approval/comments of the CPU device code, I will be working on
converting some of the interfaces over to use it.

Please apply,

-pat

p.s. the patch is attached for non-BK users.


Please pull from

bk://ldm.bkbits.net/linux-2.5

This will update the following files:

arch/i386/kernel/cpu/common.c | 34 +++++++++
arch/i386/kernel/i8259.c | 16 ++--
arch/i386/kernel/time.c | 15 ++--
drivers/acpi/bus.c | 120 -----------------------------------
drivers/base/Makefile | 5 -
drivers/base/core.c | 36 ++++++++--
drivers/base/cpu.c | 28 ++++++++
drivers/base/driver.c | 11 +++
drivers/base/sys.c | 144 +++++++++++++++++++++++++++++++++++++-----
include/linux/cpu.h | 28 ++++++++
include/linux/device.h | 31 ++++++---
11 files changed, 303 insertions(+), 165 deletions(-)

through these ChangeSets:

<mochel@osdl.org> (02/09/18 1.553)
driver model: add CPU device support

Declare a CPU device class, which gives CPUs a directory in driverfs under class/cpu/.

Define a generic 'struct cpu' for basic defintion of CPU devices. Declare a static array
of size NR_CPUS for ia32 and manually register each one on boot.

Declare an archtecture specific (ia32 only for now) cpu device driver for handling generic
device operations.


<mochel@osdl.org> (02/09/18 1.551)
driver model: strengthen system device support.

Introduce struct sys_root (to describe alternative system roots in multi-
board (NUMA-like) systems; and struct sys_device to better describe system
level devices.

Implement registration functions for alternative system roots (for multi-
board systems; e.g. NUMA-like systems)

Beef-up system device registration functions so it registers the device in
the root it belongs to and so it sets the bus type. It also sets the device's
bus_id based on the fields in struct sys_device.

Add a system_bus_type, so we have place to group the devices and drivers..

<mochel@osdl.org> (02/09/18 1.550)
driver model: Handle devices that have ->driver set on registration.

If a device is registered, and its driver is set, we call found_match() immediately
(and don't walk through the list of drivers of the bus).

We also handle the case where the driver hasn't been registered yet, so if we a NULL
driver from get_driver() in device_attach(), we assume the driver is awaiting a
driver_register().

<mochel@osdl.org> (02/09/18 1.549)
ACPI: get rid of the silly acpi_bus_driver, since it didn't do anything,
and won't ever do anything.

Binary files linux-2.5-virgin/arch/i386/boot/compressed/bvmlinux and linux-2.5/arch/i386/boot/compressed/bvmlinux differ
diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/arch/i386/kernel/cpu/common.c linux-2.5/arch/i386/kernel/cpu/common.c
--- linux-2.5-virgin/arch/i386/kernel/cpu/common.c Mon Sep 16 16:48:57 2002
+++ linux-2.5/arch/i386/kernel/cpu/common.c Wed Sep 18 13:37:41 2002
@@ -1,6 +1,7 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/cpu.h>
#include <linux/smp.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
@@ -506,3 +507,36 @@
current->used_math = 0;
stts();
}
+
+/*
+ * Bulk registration of the cpu devices with the system.
+ * Some of this stuff could possibly be moved into a shared
+ * location..
+ * Also, these devices should be integrated with other CPU data..
+ */
+
+static struct cpu cpu_devices[NR_CPUS];
+
+static struct device_driver cpu_driver = {
+ .name = "cpu",
+ .bus = &system_bus_type,
+ .devclass = &cpu_devclass,
+};
+
+static int __init register_cpus(void)
+{
+ int i;
+
+ driver_register(&cpu_driver);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ struct sys_device * sysdev = &cpu_devices[i].sysdev;
+ sysdev->name = "cpu";
+ sysdev->id = i;
+ sysdev->dev.driver = &cpu_driver;
+ sys_register_device(sysdev);
+ }
+ return 0;
+}
+
+subsys_initcall(register_cpus);
diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/arch/i386/kernel/i8259.c linux-2.5/arch/i386/kernel/i8259.c
--- linux-2.5-virgin/arch/i386/kernel/i8259.c Tue Aug 20 09:57:15 2002
+++ linux-2.5/arch/i386/kernel/i8259.c Wed Sep 18 12:05:16 2002
@@ -246,21 +246,25 @@
}

static struct device_driver driver_i8259A = {
+ .name = "pic",
.resume = i8259A_resume,
};

-static struct device device_i8259A = {
- .name = "i8259A",
- .bus_id = "0020",
- .driver = &driver_i8259A,
+static struct sys_device device_i8259A = {
+ .name = "pic",
+ .id = 0,
+ .dev = {
+ .name = "i8259A PIC",
+ .driver = &driver_i8259A,
+ },
};

static int __init init_8259A_devicefs(void)
{
- return register_sys_device(&device_i8259A);
+ return sys_register_device(&device_i8259A);
}

-__initcall(init_8259A_devicefs);
+device_initcall(init_8259A_devicefs);

void init_8259A(int auto_eoi)
{
diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/arch/i386/kernel/time.c linux-2.5/arch/i386/kernel/time.c
--- linux-2.5-virgin/arch/i386/kernel/time.c Tue Sep 10 16:26:10 2002
+++ linux-2.5/arch/i386/kernel/time.c Wed Sep 18 12:05:19 2002
@@ -639,17 +639,20 @@
return 0;
}

-static struct device device_i8253 = {
- .name = "i8253",
- .bus_id = "0040",
+static struct sys_device device_i8253 = {
+ .name = "rtc",
+ .id = 0,
+ .dev = {
+ .name = "i8253 Real Time Clock",
+ },
};

-static int time_init_driverfs(void)
+static int time_init_device(void)
{
- return register_sys_device(&device_i8253);
+ return sys_register_device(&device_i8253);
}

-__initcall(time_init_driverfs);
+device_initcall(time_init_device);

void __init time_init(void)
{
diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/drivers/acpi/bus.c linux-2.5/drivers/acpi/bus.c
--- linux-2.5-virgin/drivers/acpi/bus.c Tue Sep 10 16:26:10 2002
+++ linux-2.5/drivers/acpi/bus.c Wed Sep 18 11:15:28 2002
@@ -95,124 +95,6 @@
Linux Driver Model (LDM) Support
-------------------------------------------------------------------------- */

-#ifdef CONFIG_LDM
-
-static int acpi_device_probe(struct device *dev);
-static int acpi_device_remove(struct device *dev);
-static int acpi_device_suspend(struct device *dev, u32 state, u32 stage);
-static int acpi_device_resume(struct device *dev, u32 stage);
-
-static struct device_driver acpi_bus_driver = {
- .probe = acpi_device_probe,
- .remove = acpi_device_remove,
- .suspend = acpi_device_suspend,
- .resume = acpi_device_resume,
-};
-
-
-static int
-acpi_device_probe (
- struct device *dev)
-{
- ACPI_FUNCTION_TRACE("acpi_device_probe");
-
- if (!dev)
- return_VALUE(-EINVAL);
-
- /* TBD */
-
- return_VALUE(0);
-}
-
-
-static int
-acpi_device_remove (
- struct device *dev)
-{
- ACPI_FUNCTION_TRACE("acpi_device_remove");
-
- if (!dev)
- return_VALUE(-EINVAL);
-
- /* TBD */
-
- return_VALUE(0);
-}
-
-
-static int
-acpi_device_suspend (
- struct device *dev,
- u32 state,
- u32 stage)
-{
- ACPI_FUNCTION_TRACE("acpi_device_suspend");
-
- if (!dev)
- return_VALUE(-EINVAL);
-
- /* TBD */
-
- return_VALUE(0);
-}
-
-
-static int
-acpi_device_resume (
- struct device *dev,
- u32 stage)
-{
- ACPI_FUNCTION_TRACE("acpi_device_resume");
-
- if (!dev)
- return_VALUE(-EINVAL);
-
- /* TBD */
-
- return_VALUE(0);
-}
-
-#if 0 /* not used ATM */
-static int
-acpi_platform_add (
- struct device *dev)
-{
- ACPI_FUNCTION_TRACE("acpi_platform_add");
-
- if (!dev)
- return -EINVAL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s (%s) added\n",
- dev->name, dev->bus_id));
-
- /* TBD */
-
- return_VALUE(0);
-}
-
-
-static int
-acpi_platform_remove (
- struct device *dev)
-{
- ACPI_FUNCTION_TRACE("acpi_platform_add");
-
- if (!dev)
- return -EINVAL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s (%s) removed\n",
- dev->name, dev->bus_id));
-
- /* TBD */
-
- return_VALUE(0);
-}
-#endif /* unused */
-
-
-#endif /*CONFIG_LDM*/
-
-
static int
acpi_device_register (
struct acpi_device *device,
@@ -231,8 +113,6 @@
strncpy(device->dev.bus_id, device->pnp.bus_id, sizeof(acpi_bus_id));
if (parent)
device->dev.parent = &parent->dev;
- device->dev.driver = &acpi_bus_driver;
-
result = device_register(&device->dev);
#endif /*CONFIG_LDM*/

diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/drivers/base/Makefile linux-2.5/drivers/base/Makefile
--- linux-2.5-virgin/drivers/base/Makefile Wed Sep 18 09:37:42 2002
+++ linux-2.5/drivers/base/Makefile Wed Sep 18 13:34:30 2002
@@ -1,11 +1,12 @@
# Makefile for the Linux device tree

obj-y := core.o sys.o interface.o power.o bus.o \
- driver.o class.o intf.o platform.o
+ driver.o class.o intf.o platform.o \
+ cpu.o

obj-y += fs/

export-objs := core.o power.o sys.o bus.o driver.o \
- class.o intf.o
+ class.o intf.o cpu.o

include $(TOPDIR)/Rules.make
diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/drivers/base/core.c linux-2.5/drivers/base/core.c
--- linux-2.5-virgin/drivers/base/core.c Wed Sep 18 09:37:42 2002
+++ linux-2.5/drivers/base/core.c Wed Sep 18 11:23:56 2002
@@ -66,7 +66,7 @@
}

/**
- * device_attach - try to associated device with a driver
+ * do_device_attach - try to associated device with a driver
* @drv: current driver to try
* @data: device in disguise
*
@@ -80,18 +80,40 @@
struct device * dev = (struct device *)data;
int error = 0;

- if (!dev->driver) {
- if (drv->bus->match && drv->bus->match(dev,drv))
- error = found_match(dev,drv);
- }
+ if (drv->bus->match && drv->bus->match(dev,drv))
+ error = found_match(dev,drv);
return error;
}

+/**
+ * device_attach - find a driver for a device
+ * @dev: device we're trying to drive
+ *
+ * A device has been registered and we want to bind it to a driver.
+ * The common case is that the device doesn't have a driver, so we
+ * make the call to iterate over all the drivers on the bus to find a
+ * match for the device.
+ *
+ * The device may already have a driver, though, so we try to make
+ * things easy for those cases (typically system or legacy devices).
+ * We check the refcount of the driver. If it's 0, then it hasn't been
+ * registered yet, so we do that for the driver to initialize everything
+ * in the structure. We then call found_match() to do the actual
+ * between the two.
+ */
static int device_attach(struct device * dev)
{
int error = 0;
- if (dev->bus)
- error = bus_for_each_drv(dev->bus,dev,do_device_attach);
+ if (!dev->driver) {
+ if (dev->bus)
+ error = bus_for_each_drv(dev->bus,dev,do_device_attach);
+ } else {
+ struct device_driver * drv = get_driver(dev->driver);
+ if (!drv)
+ error = driver_register(dev->driver);
+ if (!error)
+ error = found_match(dev,dev->driver);
+ }
return error;
}

diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/drivers/base/cpu.c linux-2.5/drivers/base/cpu.c
--- linux-2.5-virgin/drivers/base/cpu.c Wed Dec 31 16:00:00 1969
+++ linux-2.5/drivers/base/cpu.c Wed Sep 18 13:34:30 2002
@@ -0,0 +1,28 @@
+/*
+ * cpu.c - basic cpu class support
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+
+static int cpu_add_device(struct device * dev)
+{
+ return 0;
+}
+
+struct device_class cpu_devclass = {
+ .name = "cpu",
+ .add_device = cpu_add_device,
+};
+
+
+static int __init cpu_devclass_init(void)
+{
+ return devclass_register(&cpu_devclass);
+}
+
+postcore_initcall(cpu_devclass_init);
+
+EXPORT_SYMBOL(cpu_devclass);
diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/drivers/base/driver.c linux-2.5/drivers/base/driver.c
--- linux-2.5-virgin/drivers/base/driver.c Fri Aug 16 13:20:20 2002
+++ linux-2.5/drivers/base/driver.c Wed Sep 18 11:23:56 2002
@@ -84,6 +84,16 @@
__remove_driver(drv);
}

+struct device_driver * get_driver(struct device_driver * drv)
+{
+ struct device_driver * ret = drv;
+ if (atomic_read(&drv->refcount))
+ atomic_inc(&drv->refcount);
+ else
+ ret = NULL;
+ return ret;
+}
+
/**
* put_driver - decrement driver's refcount and clean up if necessary
* @drv: driver in question
@@ -99,5 +109,6 @@

EXPORT_SYMBOL(driver_for_each_dev);
EXPORT_SYMBOL(driver_register);
+EXPORT_SYMBOL(get_driver);
EXPORT_SYMBOL(put_driver);
EXPORT_SYMBOL(remove_driver);
diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/drivers/base/sys.c linux-2.5/drivers/base/sys.c
--- linux-2.5-virgin/drivers/base/sys.c Fri Aug 16 13:20:20 2002
+++ linux-2.5/drivers/base/sys.c Wed Sep 18 13:34:30 2002
@@ -10,40 +10,154 @@
* add themselves as children of the system bus.
*/

+#define DEBUG 1
+
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/errno.h>
+#include <linux/err.h>

+/* The default system device parent. */
static struct device system_bus = {
.name = "System Bus",
.bus_id = "sys",
};

-int register_sys_device(struct device * dev)
+/**
+ * sys_register_root - add a subordinate system root
+ * @root: new root
+ *
+ * This is for NUMA-like systems so they can accurately
+ * represent the topology of the entire system.
+ * As boards are discovered, a new struct sys_root should
+ * be allocated and registered.
+ * The discovery mechanism should initialize the id field
+ * of the struture, as well as much of the embedded device
+ * structure as possible, inlcuding the name, the bus_id
+ * and parent fields.
+ *
+ * This simply calls device_register on the embedded device.
+ * On success, it will use the struct @root->sysdev
+ * device to create a pseudo-parent for system devices
+ * on that board.
+ *
+ * The platform code can then use @root to specifiy the
+ * controlling board when discovering and registering
+ * system devices.
+ */
+int sys_register_root(struct sys_root * root)
+{
+ int error = 0;
+
+ if (!root)
+ return -EINVAL;
+
+ pr_debug("Registering system board %d\n",root->id);
+
+ error = device_register(&root->dev);
+ if (!error) {
+ strncpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE);
+ strncpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE);
+ root->sysdev.parent = &root->dev;
+ error = device_register(&root->sysdev);
+ };
+
+ return error;
+}
+
+/**
+ * sys_unregister_root - remove subordinate root from tree
+ * @root: subordinate root in question.
+ *
+ * We only decrement the reference count on @root->sysdev
+ * and @root->dev.
+ * If both are 0, they will be cleaned up by the core.
+ */
+void sys_unegister_root(struct sys_root * root)
+{
+ put_device(&root->sysdev);
+ put_device(&root->dev);
+}
+
+static ssize_t
+show_boardid(struct device * dev, char * buf, size_t count, loff_t off)
{
- int error = -EINVAL;
+ struct sys_device * sysdev = container_of(dev,struct sys_device,dev);
+ return off ? 0:
+ sprintf(buf,"%u", sysdev->root ? sysdev->root->id : 0);
+}

- if (dev) {
- if (!dev->parent)
- dev->parent = &system_bus;
- error = device_register(dev);
- }
- return error;
+static DEVICE_ATTR(boardid,0444,show_boardid,NULL);
+
+/**
+ * sys_register_device - add a system device to the tree
+ * @sysdev: device in question
+ *
+ * The hardest part about this is getting the ancestry right.
+ * If the device has a parent - super! We do nothing.
+ * If the device doesn't, but @dev->root is set, then we're
+ * dealing with a NUMA like architecture where each root
+ * has a system pseudo-bus to foster the device.
+ * If not, then we fallback to system_bus (at the top of
+ * this file).
+ *
+ * One way or another, we call device_register() on it and
+ * are done.
+ *
+ * The caller is also responsible for initializing the bus_id
+ * and name fields of @sysdev->dev.
+ */
+int sys_register_device(struct sys_device * sysdev)
+{
+ int error = 0;
+
+ if (!sysdev)
+ return -EINVAL;
+
+ if (sysdev->dev.parent)
+ goto Register;
+
+ if (sysdev->root)
+ sysdev->dev.parent = &sysdev->root->sysdev;
+ else
+ sysdev->dev.parent = &system_bus;
+ Register:
+ printk("Registering system device %u:%s:%u\n",
+ sysdev->root ? sysdev->root->id : 0, sysdev->name, sysdev->id);
+
+ /* construct bus_id */
+ snprintf(sysdev->dev.bus_id,BUS_ID_SIZE,"%s%u",sysdev->name,sysdev->id);
+
+ /* make sure bus type is set */
+ if (!sysdev->dev.bus)
+ sysdev->dev.bus = &system_bus_type;
+
+ error = device_register(&sysdev->dev);
+
+ if (!error)
+ device_create_file(&sysdev->dev,&dev_attr_boardid);
+ return error;
}

-void unregister_sys_device(struct device * dev)
+void sys_unregister_device(struct sys_device * sysdev)
{
- if (dev)
- put_device(dev);
+ if (sysdev)
+ put_device(&sysdev->dev);
}

+struct bus_type system_bus_type = {
+ .name = "system",
+};
+
static int sys_bus_init(void)
{
- return device_register(&system_bus);
+ bus_register(&system_bus_type);
+ return device_register(&system_bus);
}

postcore_initcall(sys_bus_init);
-EXPORT_SYMBOL(register_sys_device);
-EXPORT_SYMBOL(unregister_sys_device);
+EXPORT_SYMBOL(system_bus_type);
+EXPORT_SYMBOL(sys_register_device);
+EXPORT_SYMBOL(sys_unregister_device);
diff -Nur -x BitKeeper -x SCCS -x ChangeSet -x ide -x scsi linux-2.5-virgin/include/linux/device.h linux-2.5/include/linux/device.h
--- linux-2.5-virgin/include/linux/device.h Wed Sep 18 09:37:42 2002
+++ linux-2.5/include/linux/device.h Wed Sep 18 12:02:33 2002
@@ -132,13 +132,7 @@

extern int driver_register(struct device_driver * drv);

-static inline struct device_driver * get_driver(struct device_driver * drv)
-{
- BUG_ON(!atomic_read(&drv->refcount));
- atomic_inc(&drv->refcount);
- return drv;
-}
-
+extern struct device_driver * get_driver(struct device_driver * drv);
extern void put_driver(struct device_driver * drv);
extern void remove_driver(struct device_driver * drv);

@@ -378,8 +372,27 @@
extern void put_device(struct device * dev);

/* drivers/base/sys.c */
-extern int register_sys_device(struct device * dev);
-extern void unregister_sys_device(struct device * dev);
+
+struct sys_root {
+ u32 id;
+ struct device dev;
+ struct device sysdev;
+};
+
+struct sys_device {
+ char * name;
+ u32 id;
+ struct sys_root * root;
+ struct device dev;
+};
+
+extern int sys_register_root(struct sys_root *);
+extern void sys_unregister_root(struct sys_root *);
+
+extern int sys_register_device(struct sys_device *);
+extern void sys_unregister_device(struct sys_device *);
+
+extern struct bus_type system_bus_type;

/* drivers/base/platform.c */
extern struct bus_type platform_bus;
\
 
 \ /
  Last update: 2005-03-22 13:25    [W:0.189 / U:0.048 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site