Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6:
  UIO: fix specific device driver missing statement for depmod
  Driver core: remove pr_fmt() from dynamic_dev_dbg() printk
  driver core: prevent device_for_each_child from oopsing
  dynamic debug: resurrect old pr_debug() semantics as pr_devel()
  Driver Core: early platform driver
  proc: mounts_poll() make consistent to mdstat_poll
  sysfs: sysfs poll keep the poll rule of regular file.
  driver core: allow non-root users to listen to uevents
  driver core: fix driver_match_device
  sysfs: don't use global workqueue in sysfs_schedule_callback()
This commit is contained in:
Linus Torvalds 2009-04-17 13:53:16 -07:00
commit 74a205a3f1
13 changed files with 378 additions and 9 deletions

View File

@ -169,3 +169,62 @@ three different ways to find such a match:
be probed later if another device registers. (Which is OK, since
this interface is only for use with non-hotpluggable devices.)
Early Platform Devices and Drivers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The early platform interfaces provide platform data to platform device
drivers early on during the system boot. The code is built on top of the
early_param() command line parsing and can be executed very early on.
Example: "earlyprintk" class early serial console in 6 steps
1. Registering early platform device data
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The architecture code registers platform device data using the function
early_platform_add_devices(). In the case of early serial console this
should be hardware configuration for the serial port. Devices registered
at this point will later on be matched against early platform drivers.
2. Parsing kernel command line
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The architecture code calls parse_early_param() to parse the kernel
command line. This will execute all matching early_param() callbacks.
User specified early platform devices will be registered at this point.
For the early serial console case the user can specify port on the
kernel command line as "earlyprintk=serial.0" where "earlyprintk" is
the class string, "serial" is the name of the platfrom driver and
0 is the platform device id. If the id is -1 then the dot and the
id can be omitted.
3. Installing early platform drivers belonging to a certain class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The architecture code may optionally force registration of all early
platform drivers belonging to a certain class using the function
early_platform_driver_register_all(). User specified devices from
step 2 have priority over these. This step is omitted by the serial
driver example since the early serial driver code should be disabled
unless the user has specified port on the kernel command line.
4. Early platform driver registration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiled-in platform drivers making use of early_platform_init() are
automatically registered during step 2 or 3. The serial driver example
should use early_platform_init("earlyprintk", &platform_driver).
5. Probing of early platform drivers belonging to a certain class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The architecture code calls early_platform_driver_probe() to match
registered early platform devices associated with a certain class with
registered early platform drivers. Matched devices will get probed().
This step can be executed at any point during the early boot. As soon
as possible may be good for the serial port case.
6. Inside the early platform driver probe()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The driver code needs to take special care during early boot, especially
when it comes to memory allocation and interrupt registration. The code
in the probe() function can use is_early_platform_device() to check if
it is called at early platform device or at the regular platform device
time. The early serial driver performs register_console() at this point.
For further information, see <linux/platform_device.h>.

View File

@ -115,7 +115,7 @@ extern int driver_probe_device(struct device_driver *drv, struct device *dev);
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match && drv->bus->match(dev, drv);
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
extern void sysdev_shutdown(void);

View File

@ -1142,6 +1142,9 @@ int device_for_each_child(struct device *parent, void *data,
struct device *child;
int error = 0;
if (!parent->p)
return 0;
klist_iter_init(&parent->p->klist_children, &i);
while ((child = next_device(&i)) && !error)
error = fn(child, data);

View File

@ -990,6 +990,8 @@ int __init platform_bus_init(void)
{
int error;
early_platform_cleanup();
error = device_register(&platform_bus);
if (error)
return error;
@ -1020,3 +1022,240 @@ u64 dma_get_required_mask(struct device *dev)
}
EXPORT_SYMBOL_GPL(dma_get_required_mask);
#endif
static __initdata LIST_HEAD(early_platform_driver_list);
static __initdata LIST_HEAD(early_platform_device_list);
/**
* early_platform_driver_register
* @edrv: early_platform driver structure
* @buf: string passed from early_param()
*/
int __init early_platform_driver_register(struct early_platform_driver *epdrv,
char *buf)
{
unsigned long index;
int n;
/* Simply add the driver to the end of the global list.
* Drivers will by default be put on the list in compiled-in order.
*/
if (!epdrv->list.next) {
INIT_LIST_HEAD(&epdrv->list);
list_add_tail(&epdrv->list, &early_platform_driver_list);
}
/* If the user has specified device then make sure the driver
* gets prioritized. The driver of the last device specified on
* command line will be put first on the list.
*/
n = strlen(epdrv->pdrv->driver.name);
if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
list_move(&epdrv->list, &early_platform_driver_list);
if (!strcmp(buf, epdrv->pdrv->driver.name))
epdrv->requested_id = -1;
else if (buf[n] == '.' && strict_strtoul(&buf[n + 1], 10,
&index) == 0)
epdrv->requested_id = index;
else
epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
}
return 0;
}
/**
* early_platform_add_devices - add a numbers of early platform devices
* @devs: array of early platform devices to add
* @num: number of early platform devices in array
*/
void __init early_platform_add_devices(struct platform_device **devs, int num)
{
struct device *dev;
int i;
/* simply add the devices to list */
for (i = 0; i < num; i++) {
dev = &devs[i]->dev;
if (!dev->devres_head.next) {
INIT_LIST_HEAD(&dev->devres_head);
list_add_tail(&dev->devres_head,
&early_platform_device_list);
}
}
}
/**
* early_platform_driver_register_all
* @class_str: string to identify early platform driver class
*/
void __init early_platform_driver_register_all(char *class_str)
{
/* The "class_str" parameter may or may not be present on the kernel
* command line. If it is present then there may be more than one
* matching parameter.
*
* Since we register our early platform drivers using early_param()
* we need to make sure that they also get registered in the case
* when the parameter is missing from the kernel command line.
*
* We use parse_early_options() to make sure the early_param() gets
* called at least once. The early_param() may be called more than
* once since the name of the preferred device may be specified on
* the kernel command line. early_platform_driver_register() handles
* this case for us.
*/
parse_early_options(class_str);
}
/**
* early_platform_match
* @edrv: early platform driver structure
* @id: id to match against
*/
static __init struct platform_device *
early_platform_match(struct early_platform_driver *epdrv, int id)
{
struct platform_device *pd;
list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
if (pd->id == id)
return pd;
return NULL;
}
/**
* early_platform_left
* @edrv: early platform driver structure
* @id: return true if id or above exists
*/
static __init int early_platform_left(struct early_platform_driver *epdrv,
int id)
{
struct platform_device *pd;
list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
if (pd->id >= id)
return 1;
return 0;
}
/**
* early_platform_driver_probe_id
* @class_str: string to identify early platform driver class
* @id: id to match against
* @nr_probe: number of platform devices to successfully probe before exiting
*/
static int __init early_platform_driver_probe_id(char *class_str,
int id,
int nr_probe)
{
struct early_platform_driver *epdrv;
struct platform_device *match;
int match_id;
int n = 0;
int left = 0;
list_for_each_entry(epdrv, &early_platform_driver_list, list) {
/* only use drivers matching our class_str */
if (strcmp(class_str, epdrv->class_str))
continue;
if (id == -2) {
match_id = epdrv->requested_id;
left = 1;
} else {
match_id = id;
left += early_platform_left(epdrv, id);
/* skip requested id */
switch (epdrv->requested_id) {
case EARLY_PLATFORM_ID_ERROR:
case EARLY_PLATFORM_ID_UNSET:
break;
default:
if (epdrv->requested_id == id)
match_id = EARLY_PLATFORM_ID_UNSET;
}
}
switch (match_id) {
case EARLY_PLATFORM_ID_ERROR:
pr_warning("%s: unable to parse %s parameter\n",
class_str, epdrv->pdrv->driver.name);
/* fall-through */
case EARLY_PLATFORM_ID_UNSET:
match = NULL;
break;
default:
match = early_platform_match(epdrv, match_id);
}
if (match) {
if (epdrv->pdrv->probe(match))
pr_warning("%s: unable to probe %s early.\n",
class_str, match->name);
else
n++;
}
if (n >= nr_probe)
break;
}
if (left)
return n;
else
return -ENODEV;
}
/**
* early_platform_driver_probe
* @class_str: string to identify early platform driver class
* @nr_probe: number of platform devices to successfully probe before exiting
* @user_only: only probe user specified early platform devices
*/
int __init early_platform_driver_probe(char *class_str,
int nr_probe,
int user_only)
{
int k, n, i;
n = 0;
for (i = -2; n < nr_probe; i++) {
k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
if (k < 0)
break;
n += k;
if (user_only)
break;
}
return n;
}
/**
* early_platform_cleanup - clean up early platform code
*/
void __init early_platform_cleanup(void)
{
struct platform_device *pd, *pd2;
/* clean up the devres list used to chain devices */
list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
dev.devres_head) {
list_del(&pd->dev.devres_head);
memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
}
}

View File

@ -147,5 +147,6 @@ static void __exit hilscher_exit_module(void)
module_init(hilscher_init_module);
module_exit(hilscher_exit_module);
MODULE_DEVICE_TABLE(pci, hilscher_pci_ids);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");

View File

@ -648,14 +648,14 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
{
struct proc_mounts *p = file->private_data;
struct mnt_namespace *ns = p->ns;
unsigned res = 0;
unsigned res = POLLIN | POLLRDNORM;
poll_wait(file, &ns->poll, wait);
spin_lock(&vfsmount_lock);
if (p->event != ns->event) {
p->event = ns->event;
res = POLLERR;
res |= POLLERR | POLLPRI;
}
spin_unlock(&vfsmount_lock);

View File

@ -446,11 +446,11 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
if (buffer->event != atomic_read(&od->event))
goto trigger;
return 0;
return DEFAULT_POLLMASK;
trigger:
buffer->needs_read_fill = 1;
return POLLERR|POLLPRI;
return DEFAULT_POLLMASK|POLLERR|POLLPRI;
}
void sysfs_notify_dirent(struct sysfs_dirent *sd)
@ -667,6 +667,7 @@ struct sysfs_schedule_callback_struct {
struct work_struct work;
};
static struct workqueue_struct *sysfs_workqueue;
static DEFINE_MUTEX(sysfs_workq_mutex);
static LIST_HEAD(sysfs_workq);
static void sysfs_schedule_callback_work(struct work_struct *work)
@ -715,11 +716,20 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
mutex_lock(&sysfs_workq_mutex);
list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list)
if (ss->kobj == kobj) {
module_put(owner);
mutex_unlock(&sysfs_workq_mutex);
return -EAGAIN;
}
mutex_unlock(&sysfs_workq_mutex);
if (sysfs_workqueue == NULL) {
sysfs_workqueue = create_workqueue("sysfsd");
if (sysfs_workqueue == NULL) {
module_put(owner);
return -ENOMEM;
}
}
ss = kmalloc(sizeof(*ss), GFP_KERNEL);
if (!ss) {
module_put(owner);
@ -735,7 +745,7 @@ int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
mutex_lock(&sysfs_workq_mutex);
list_add_tail(&ss->workq_list, &sysfs_workq);
mutex_unlock(&sysfs_workq_mutex);
schedule_work(&ss->work);
queue_work(sysfs_workqueue, &ss->work);
return 0;
}
EXPORT_SYMBOL_GPL(sysfs_schedule_callback);

View File

@ -70,7 +70,7 @@ extern int ddebug_remove_module(char *mod_name);
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \
if (__dynamic_dbg_enabled(descriptor)) \
dev_printk(KERN_DEBUG, dev, \
KBUILD_MODNAME ": " pr_fmt(fmt),\
KBUILD_MODNAME ": " fmt, \
##__VA_ARGS__); \
} while (0)

View File

@ -247,6 +247,7 @@ struct obs_kernel_param {
/* Relies on boot_command_line being set */
void __init parse_early_param(void);
void __init parse_early_options(char *cmdline);
#endif /* __ASSEMBLY__ */
/**

View File

@ -377,6 +377,15 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
#define pr_cont(fmt, ...) \
printk(KERN_CONT fmt, ##__VA_ARGS__)
/* pr_devel() should produce zero code unless DEBUG is defined */
#ifdef DEBUG
#define pr_devel(fmt, ...) \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_devel(fmt, ...) \
({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; })
#endif
/* If you are writing a driver, please use dev_dbg instead */
#if defined(DEBUG)
#define pr_debug(fmt, ...) \

View File

@ -77,4 +77,46 @@ extern int platform_driver_probe(struct platform_driver *driver,
#define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev)
#define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data))
/* early platform driver interface */
struct early_platform_driver {
const char *class_str;
struct platform_driver *pdrv;
struct list_head list;
int requested_id;
};
#define EARLY_PLATFORM_ID_UNSET -2
#define EARLY_PLATFORM_ID_ERROR -3
extern int early_platform_driver_register(struct early_platform_driver *epdrv,
char *buf);
extern void early_platform_add_devices(struct platform_device **devs, int num);
static inline int is_early_platform_device(struct platform_device *pdev)
{
return !pdev->dev.driver;
}
extern void early_platform_driver_register_all(char *class_str);
extern int early_platform_driver_probe(char *class_str,
int nr_probe, int user_only);
extern void early_platform_cleanup(void);
#ifndef MODULE
#define early_platform_init(class_string, platform_driver) \
static __initdata struct early_platform_driver early_driver = { \
.class_str = class_string, \
.pdrv = platform_driver, \
.requested_id = EARLY_PLATFORM_ID_UNSET, \
}; \
static int __init early_platform_driver_setup_func(char *buf) \
{ \
return early_platform_driver_register(&early_driver, buf); \
} \
early_param(class_string, early_platform_driver_setup_func)
#else /* MODULE */
#define early_platform_init(class_string, platform_driver)
#endif /* MODULE */
#endif /* _PLATFORM_DEVICE_H_ */

View File

@ -492,6 +492,11 @@ static int __init do_early_param(char *param, char *val)
return 0;
}
void __init parse_early_options(char *cmdline)
{
parse_args("early options", cmdline, NULL, 0, do_early_param);
}
/* Arch code calls this early on, or if not, just before other parsing. */
void __init parse_early_param(void)
{
@ -503,7 +508,7 @@ void __init parse_early_param(void)
/* All fall through to do_early_param. */
strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
parse_args("early options", tmp_cmdline, NULL, 0, do_early_param);
parse_early_options(tmp_cmdline);
done = 1;
}

View File

@ -328,7 +328,7 @@ static int __init kobject_uevent_init(void)
"kobject_uevent: unable to create netlink socket!\n");
return -ENODEV;
}
netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV);
return 0;
}