Messages in this thread Patch in this message | | | Date | Wed, 18 Sep 2002 13:40:05 -0700 (PDT) | From | Patrick Mochel <> | 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;
| |