Browse Source

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

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6: (158 commits)
  commit 4f705ae3e94ffaafe8d35f71ff4d5c499bb06814
  Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
  Date:   Mon Apr 3 17:09:22 2006 -0700
  
      [PATCH] DMI: move dmi_scan.c from arch/i386 to drivers/firmware/
      
      dmi_scan.c is arch-independent and is used by i386, x86_64, and ia64.
      Currently all three arches compile it from arch/i386, which means that ia64
      and x86_64 depend on things in arch/i386 that they wouldn't otherwise care
      about.
      
      This is simply "mv arch/i386/kernel/dmi_scan.c drivers/firmware/" (removing
      trailing whitespace) and the associated Makefile changes.  All three
      architectures already set CONFIG_DMI in their top-level Kconfig files.
      
      Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
      Cc: Andi Kleen <ak@muc.de>
      Cc: "Luck, Tony" <tony.luck@intel.com>
      Cc: Andrey Panin <pazke@orbita1.ru>
      Signed-off-by: Andrew Morton <akpm@osdl.org>
  ...
Linus Torvalds 19 years ago
parent
commit
754a264c42

+ 1 - 1
arch/i386/kernel/Makefile

@@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o \
 		ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
-		pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
+		pci-dma.o i386_ksyms.o i387.o bootflag.o \
 		quirks.o i8237.o topology.o alternative.o
 
 obj-y				+= cpu/

+ 1 - 2
arch/ia64/kernel/Makefile

@@ -7,7 +7,7 @@ extra-y	:= head.o init_task.o vmlinux.lds
 obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o	\
 	 irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o		\
 	 salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
-	 unwind.o mca.o mca_asm.o topology.o dmi_scan.o
+	 unwind.o mca.o mca_asm.o topology.o
 
 obj-$(CONFIG_IA64_BRL_EMU)	+= brl_emu.o
 obj-$(CONFIG_IA64_GENERIC)	+= acpi-ext.o
@@ -30,7 +30,6 @@ obj-$(CONFIG_IA64_MCA_RECOVERY)	+= mca_recovery.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o jprobes.o
 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR)	+= uncached.o
 mca_recovery-y			+= mca_drv.o mca_drv_asm.o
-dmi_scan-y			+= ../../i386/kernel/dmi_scan.o
 
 # The gate DSO image is built using a special linker script.
 targets += gate.so gate-syms.o

+ 1 - 3
arch/x86_64/kernel/Makefile

@@ -8,7 +8,7 @@ obj-y	:= process.o signal.o entry.o traps.o irq.o \
 		ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \
 		x8664_ksyms.o i387.o syscall.o vsyscall.o \
 		setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \
-		dmi_scan.o pci-dma.o pci-nommu.o
+		pci-dma.o pci-nommu.o
 
 obj-$(CONFIG_X86_MCE)         += mce.o
 obj-$(CONFIG_X86_MCE_INTEL)	+= mce_intel.o
@@ -49,5 +49,3 @@ intel_cacheinfo-y		+= ../../i386/kernel/cpu/intel_cacheinfo.o
 quirks-y			+= ../../i386/kernel/quirks.o
 i8237-y				+= ../../i386/kernel/i8237.o
 msr-$(subst m,y,$(CONFIG_X86_MSR))  += ../../i386/kernel/msr.o
-dmi_scan-y			+= ../../i386/kernel/dmi_scan.o
-

+ 5 - 0
drivers/base/bus.c

@@ -188,6 +188,11 @@ static ssize_t driver_bind(struct device_driver *drv,
 		up(&dev->sem);
 		if (dev->parent)
 			up(&dev->parent->sem);
+
+		if (err > 0) 		/* success */
+			err = count;
+		else if (err == 0)	/* driver didn't accept device */
+			err = -ENODEV;
 	}
 	put_device(dev);
 	put_bus(bus);

+ 6 - 7
drivers/base/class.c

@@ -562,14 +562,13 @@ int class_device_add(struct class_device *class_dev)
 	kobject_uevent(&class_dev->kobj, KOBJ_ADD);
 
 	/* notify any interfaces this device is now here */
-	if (parent_class) {
-		down(&parent_class->sem);
-		list_add_tail(&class_dev->node, &parent_class->children);
-		list_for_each_entry(class_intf, &parent_class->interfaces, node)
-			if (class_intf->add)
-				class_intf->add(class_dev, class_intf);
-		up(&parent_class->sem);
+	down(&parent_class->sem);
+	list_add_tail(&class_dev->node, &parent_class->children);
+	list_for_each_entry(class_intf, &parent_class->interfaces, node) {
+		if (class_intf->add)
+			class_intf->add(class_dev, class_intf);
 	}
+	up(&parent_class->sem);
 
  register_done:
 	if (error) {

+ 1 - 1
drivers/base/dd.c

@@ -209,7 +209,7 @@ static void __device_release_driver(struct device * dev)
 		sysfs_remove_link(&dev->kobj, "driver");
 		klist_remove(&dev->knode_driver);
 
-		if (dev->bus->remove)
+		if (dev->bus && dev->bus->remove)
 			dev->bus->remove(dev);
 		else if (drv->remove)
 			drv->remove(dev);

+ 12 - 0
drivers/base/power/suspend.c

@@ -10,6 +10,8 @@
 
 #include <linux/vt_kern.h>
 #include <linux/device.h>
+#include <linux/kallsyms.h>
+#include <linux/pm.h>
 #include "../base.h"
 #include "power.h"
 
@@ -58,6 +60,7 @@ int suspend_device(struct device * dev, pm_message_t state)
 	if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
 		dev_dbg(dev, "suspending\n");
 		error = dev->bus->suspend(dev, state);
+		suspend_report_result(dev->bus->suspend, error);
 	}
 	up(&dev->sem);
 	return error;
@@ -169,3 +172,12 @@ int device_power_down(pm_message_t state)
 
 EXPORT_SYMBOL_GPL(device_power_down);
 
+void __suspend_report_result(const char *function, void *fn, int ret)
+{
+	if (ret) {
+		printk(KERN_ERR "%s(): ", function);
+		print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
+		printk("%d\n", ret);
+	}
+}
+EXPORT_SYMBOL_GPL(__suspend_report_result);

+ 2 - 1
drivers/firmware/Makefile

@@ -1,7 +1,8 @@
 #
 # Makefile for the linux kernel.
 #
-obj-$(CONFIG_EDD)             	+= edd.o
+obj-$(CONFIG_DMI)		+= dmi_scan.o
+obj-$(CONFIG_EDD)		+= edd.o
 obj-$(CONFIG_EFI_VARS)		+= efivars.o
 obj-$(CONFIG_EFI_PCDP)		+= pcdp.o
 obj-$(CONFIG_DELL_RBU)          += dell_rbu.o

+ 6 - 6
arch/i386/kernel/dmi_scan.c → drivers/firmware/dmi_scan.c

@@ -27,7 +27,7 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s)
 			else
 				printk(KERN_ERR "dmi_string: out of memory.\n");
 		}
- 	}
+	}
 
 	return str;
 }
@@ -41,7 +41,7 @@ static int __init dmi_table(u32 base, int len, int num,
 {
 	u8 *buf, *data;
 	int i = 0;
-		
+
 	buf = dmi_ioremap(base, len);
 	if (buf == NULL)
 		return -1;
@@ -49,9 +49,9 @@ static int __init dmi_table(u32 base, int len, int num,
 	data = buf;
 
 	/*
- 	 *	Stop when we see all the items the table claimed to have
- 	 *	OR we run off the end of the table (also happens)
- 	 */
+	 *	Stop when we see all the items the table claimed to have
+	 *	OR we run off the end of the table (also happens)
+	 */
 	while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
 		struct dmi_header *dm = (struct dmi_header *)data;
 		/*
@@ -75,7 +75,7 @@ static int __init dmi_checksum(u8 *buf)
 {
 	u8 sum = 0;
 	int a;
-	
+
 	for (a = 0; a < 15; a++)
 		sum += buf[a];
 

+ 1 - 0
drivers/md/md.c

@@ -163,6 +163,7 @@ void md_new_event(mddev_t *mddev)
 {
 	atomic_inc(&md_event_count);
 	wake_up(&md_event_waiters);
+	sysfs_notify(&mddev->kobj, NULL, "sync_action");
 }
 EXPORT_SYMBOL_GPL(md_new_event);
 

+ 4 - 2
drivers/pci/pci-driver.c

@@ -271,10 +271,12 @@ static int pci_device_suspend(struct device * dev, pm_message_t state)
 	struct pci_driver * drv = pci_dev->driver;
 	int i = 0;
 
-	if (drv && drv->suspend)
+	if (drv && drv->suspend) {
 		i = drv->suspend(pci_dev, state);
-	else
+		suspend_report_result(drv->suspend, i);
+	} else {
 		pci_save_state(pci_dev);
+	}
 	return i;
 }
 

+ 4 - 2
drivers/pci/pci.c

@@ -307,9 +307,11 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 	 * Can enter D0 from any state, but if we can only go deeper 
 	 * to sleep if we're already in a low power state
 	 */
-	if (state != PCI_D0 && dev->current_state > state)
+	if (state != PCI_D0 && dev->current_state > state) {
+		printk(KERN_ERR "%s(): %s: state=%d, current state=%d\n",
+			__FUNCTION__, pci_name(dev), state, dev->current_state);
 		return -EINVAL;
-	else if (dev->current_state == state) 
+	} else if (dev->current_state == state)
 		return 0;        /* we're already there */
 
 	/* find PCI PM capability in list */

+ 3 - 4
drivers/usb/core/hcd-pci.c

@@ -213,11 +213,9 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 
 	if (hcd->driver->suspend) {
 		retval = hcd->driver->suspend(hcd, message);
-		if (retval) {
-			dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n",
-				retval);
+		suspend_report_result(hcd->driver->suspend, retval);
+		if (retval)
 			goto done;
-		}
 	}
 	synchronize_irq(dev->irq);
 
@@ -263,6 +261,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 		 * some device state (e.g. as part of clock reinit).
 		 */
 		retval = pci_set_power_state (dev, PCI_D3hot);
+		suspend_report_result(pci_set_power_state, retval);
 		if (retval == 0) {
 			int wake = device_can_wakeup(&hcd->self.root_hub->dev);
 

+ 30 - 8
fs/partitions/check.c

@@ -331,7 +331,9 @@ void delete_partition(struct gendisk *disk, int part)
 	devfs_remove("%s/part%d", disk->devfs_name, part);
 	if (p->holder_dir)
 		kobject_unregister(p->holder_dir);
-	kobject_unregister(&p->kobj);
+	kobject_uevent(&p->kobj, KOBJ_REMOVE);
+	kobject_del(&p->kobj);
+	kobject_put(&p->kobj);
 }
 
 void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
@@ -357,7 +359,10 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
 		snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
 	p->kobj.parent = &disk->kobj;
 	p->kobj.ktype = &ktype_part;
-	kobject_register(&p->kobj);
+	kobject_init(&p->kobj);
+	kobject_add(&p->kobj);
+	if (!disk->part_uevent_suppress)
+		kobject_uevent(&p->kobj, KOBJ_ADD);
 	partition_sysfs_add_subdir(p);
 	disk->part[part-1] = p;
 }
@@ -395,6 +400,8 @@ void register_disk(struct gendisk *disk)
 {
 	struct block_device *bdev;
 	char *s;
+	int i;
+	struct hd_struct *p;
 	int err;
 
 	strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
@@ -406,13 +413,12 @@ void register_disk(struct gendisk *disk)
 		return;
 	disk_sysfs_symlinks(disk);
  	disk_sysfs_add_subdirs(disk);
-	kobject_uevent(&disk->kobj, KOBJ_ADD);
 
 	/* No minors to use for partitions */
 	if (disk->minors == 1) {
 		if (disk->devfs_name[0] != '\0')
 			devfs_add_disk(disk);
-		return;
+		goto exit;
 	}
 
 	/* always add handle for the whole disk */
@@ -420,16 +426,32 @@ void register_disk(struct gendisk *disk)
 
 	/* No such device (e.g., media were just removed) */
 	if (!get_capacity(disk))
-		return;
+		goto exit;
 
 	bdev = bdget_disk(disk, 0);
 	if (!bdev)
-		return;
+		goto exit;
 
+	/* scan partition table, but suppress uevents */
 	bdev->bd_invalidated = 1;
-	if (blkdev_get(bdev, FMODE_READ, 0) < 0)
-		return;
+	disk->part_uevent_suppress = 1;
+	err = blkdev_get(bdev, FMODE_READ, 0);
+	disk->part_uevent_suppress = 0;
+	if (err < 0)
+		goto exit;
 	blkdev_put(bdev);
+
+exit:
+	/* announce disk after possible partitions are already created */
+	kobject_uevent(&disk->kobj, KOBJ_ADD);
+
+	/* announce possible partitions */
+	for (i = 1; i < disk->minors; i++) {
+		p = disk->part[i-1];
+		if (!p || !p->nr_sects)
+			continue;
+		kobject_uevent(&p->kobj, KOBJ_ADD);
+	}
 }
 
 int rescan_partitions(struct gendisk *disk, struct block_device *bdev)

+ 1 - 0
fs/sysfs/dir.c

@@ -43,6 +43,7 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
 
 	memset(sd, 0, sizeof(*sd));
 	atomic_set(&sd->s_count, 1);
+	atomic_set(&sd->s_event, 0);
 	INIT_LIST_HEAD(&sd->s_children);
 	list_add(&sd->s_sibling, &parent_sd->s_children);
 	sd->s_element = element;

+ 76 - 0
fs/sysfs/file.c

@@ -6,6 +6,7 @@
 #include <linux/fsnotify.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
+#include <linux/poll.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
@@ -57,6 +58,7 @@ struct sysfs_buffer {
 	struct sysfs_ops	* ops;
 	struct semaphore	sem;
 	int			needs_read_fill;
+	int			event;
 };
 
 
@@ -72,6 +74,7 @@ struct sysfs_buffer {
  */
 static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
 {
+	struct sysfs_dirent * sd = dentry->d_fsdata;
 	struct attribute * attr = to_attr(dentry);
 	struct kobject * kobj = to_kobj(dentry->d_parent);
 	struct sysfs_ops * ops = buffer->ops;
@@ -83,6 +86,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
 	if (!buffer->page)
 		return -ENOMEM;
 
+	buffer->event = atomic_read(&sd->s_event);
 	count = ops->show(kobj,attr,buffer->page);
 	buffer->needs_read_fill = 0;
 	BUG_ON(count > (ssize_t)PAGE_SIZE);
@@ -348,12 +352,84 @@ static int sysfs_release(struct inode * inode, struct file * filp)
 	return 0;
 }
 
+/* Sysfs attribute files are pollable.  The idea is that you read
+ * the content and then you use 'poll' or 'select' to wait for
+ * the content to change.  When the content changes (assuming the
+ * manager for the kobject supports notification), poll will
+ * return POLLERR|POLLPRI, and select will return the fd whether
+ * it is waiting for read, write, or exceptions.
+ * Once poll/select indicates that the value has changed, you
+ * need to close and re-open the file, as simply seeking and reading
+ * again will not get new data, or reset the state of 'poll'.
+ * Reminder: this only works for attributes which actively support
+ * it, and it is not possible to test an attribute from userspace
+ * to see if it supports poll (Nether 'poll' or 'select' return
+ * an appropriate error code).  When in doubt, set a suitable timeout value.
+ */
+static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
+{
+	struct sysfs_buffer * buffer = filp->private_data;
+	struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
+	struct sysfs_dirent * sd = filp->f_dentry->d_fsdata;
+	int res = 0;
+
+	poll_wait(filp, &kobj->poll, wait);
+
+	if (buffer->event != atomic_read(&sd->s_event)) {
+		res = POLLERR|POLLPRI;
+		buffer->needs_read_fill = 1;
+	}
+
+	return res;
+}
+
+
+static struct dentry *step_down(struct dentry *dir, const char * name)
+{
+	struct dentry * de;
+
+	if (dir == NULL || dir->d_inode == NULL)
+		return NULL;
+
+	mutex_lock(&dir->d_inode->i_mutex);
+	de = lookup_one_len(name, dir, strlen(name));
+	mutex_unlock(&dir->d_inode->i_mutex);
+	dput(dir);
+	if (IS_ERR(de))
+		return NULL;
+	if (de->d_inode == NULL) {
+		dput(de);
+		return NULL;
+	}
+	return de;
+}
+
+void sysfs_notify(struct kobject * k, char *dir, char *attr)
+{
+	struct dentry *de = k->dentry;
+	if (de)
+		dget(de);
+	if (de && dir)
+		de = step_down(de, dir);
+	if (de && attr)
+		de = step_down(de, attr);
+	if (de) {
+		struct sysfs_dirent * sd = de->d_fsdata;
+		if (sd)
+			atomic_inc(&sd->s_event);
+		wake_up_interruptible(&k->poll);
+		dput(de);
+	}
+}
+EXPORT_SYMBOL_GPL(sysfs_notify);
+
 const struct file_operations sysfs_file_operations = {
 	.read		= sysfs_read_file,
 	.write		= sysfs_write_file,
 	.llseek		= generic_file_llseek,
 	.open		= sysfs_open_file,
 	.release	= sysfs_release,
+	.poll		= sysfs_poll,
 };
 
 

+ 1 - 0
fs/sysfs/sysfs.h

@@ -11,6 +11,7 @@ extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
 
 extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
 extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
+extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
 
 extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
 extern void sysfs_remove_subdir(struct dentry *);

+ 1 - 0
include/linux/genhd.h

@@ -105,6 +105,7 @@ struct gendisk {
                                          * disks that can't be partitioned. */
 	char disk_name[32];		/* name of major driver */
 	struct hd_struct **part;	/* [indexed by minor] */
+	int part_uevent_suppress;
 	struct block_device_operations *fops;
 	struct request_queue *queue;
 	void *private_data;

+ 2 - 0
include/linux/kobject.h

@@ -24,6 +24,7 @@
 #include <linux/rwsem.h>
 #include <linux/kref.h>
 #include <linux/kernel.h>
+#include <linux/wait.h>
 #include <asm/atomic.h>
 
 #define KOBJ_NAME_LEN			20
@@ -56,6 +57,7 @@ struct kobject {
 	struct kset		* kset;
 	struct kobj_type	* ktype;
 	struct dentry		* dentry;
+	wait_queue_head_t	poll;
 };
 
 extern int kobject_set_name(struct kobject *, const char *, ...)

+ 8 - 0
include/linux/pm.h

@@ -199,6 +199,12 @@ extern int device_suspend(pm_message_t state);
 
 extern int dpm_runtime_suspend(struct device *, pm_message_t);
 extern void dpm_runtime_resume(struct device *);
+extern void __suspend_report_result(const char *function, void *fn, int ret);
+
+#define suspend_report_result(fn, ret)					\
+	do {								\
+		__suspend_report_result(__FUNCTION__, fn, ret);		\
+	} while (0)
 
 #else /* !CONFIG_PM */
 
@@ -219,6 +225,8 @@ static inline void dpm_runtime_resume(struct device * dev)
 {
 }
 
+#define suspend_report_result(fn, ret) do { } while (0)
+
 #endif
 
 /* changes to device_may_wakeup take effect on the next pm state change.

+ 6 - 0
include/linux/sysfs.h

@@ -74,6 +74,7 @@ struct sysfs_dirent {
 	umode_t			s_mode;
 	struct dentry		* s_dentry;
 	struct iattr		* s_iattr;
+	atomic_t		s_event;
 };
 
 #define SYSFS_ROOT		0x0001
@@ -117,6 +118,7 @@ int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr);
 
 int sysfs_create_group(struct kobject *, const struct attribute_group *);
 void sysfs_remove_group(struct kobject *, const struct attribute_group *);
+void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
 #else /* CONFIG_SYSFS */
 
@@ -185,6 +187,10 @@ static inline void sysfs_remove_group(struct kobject * k, const struct attribute
 	;
 }
 
+static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
+{
+}
+
 #endif /* CONFIG_SYSFS */
 
 #endif /* _SYSFS_H_ */

+ 1 - 0
lib/kobject.c

@@ -128,6 +128,7 @@ void kobject_init(struct kobject * kobj)
 {
 	kref_init(&kobj->kref);
 	INIT_LIST_HEAD(&kobj->entry);
+	init_waitqueue_head(&kobj->poll);
 	kobj->kset = kset_get(kobj->kset);
 }