diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:36:42 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:36:42 -0700 | 
| commit | b9da0571050c09863e59f94d0b8594a290d61b88 (patch) | |
| tree | 3632c4fee768db9a27a5c872bd42133692e2f3d0 /drivers | |
| parent | f8cae0f03f75adb54b1d48ddbc90f84a1f5de186 (diff) | |
| parent | 5abd935661e01289ba143c3b2c1ba300c65bcc5f (diff) | |
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: (31 commits)
  driver core: Display error codes when class suspend fails
  Driver core: Add section count to memory_block struct
  Driver core: Add mutex for adding/removing memory blocks
  Driver core: Move find_memory_block routine
  hpilo: Despecificate driver from iLO generation
  driver core: Convert link_mem_sections to use find_memory_block_hinted.
  driver core: Introduce find_memory_block_hinted which utilizes kset_find_obj_hinted.
  kobject: Introduce kset_find_obj_hinted.
  driver core: fix build for CONFIG_BLOCK not enabled
  driver-core: base: change to new flag variable
  sysfs: only access bin file vm_ops with the active lock
  sysfs: Fail bin file mmap if vma close is implemented.
  FW_LOADER: fix kconfig dependency warning on HOTPLUG
  uio: Statically allocate uio_class and use class .dev_attrs.
  uio: Support 2^MINOR_BITS minors
  uio: Cleanup irq handling.
  uio: Don't clear driver data
  uio: Fix lack of locking in init_uio_class
  SYSFS: Allow boot time switching between deprecated and modern sysfs layout
  driver core: remove CONFIG_SYSFS_DEPRECATED_V2 but keep it for block devices
  ...
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/base/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/base/Makefile | 4 | ||||
| -rw-r--r-- | drivers/base/bus.c | 22 | ||||
| -rw-r--r-- | drivers/base/class.c | 23 | ||||
| -rw-r--r-- | drivers/base/core.c | 208 | ||||
| -rw-r--r-- | drivers/base/memory.c | 94 | ||||
| -rw-r--r-- | drivers/base/node.c | 8 | ||||
| -rw-r--r-- | drivers/base/platform.c | 80 | ||||
| -rw-r--r-- | drivers/base/sys.c | 8 | ||||
| -rw-r--r-- | drivers/misc/Kconfig | 22 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/misc/hpilo.c | 2 | ||||
| -rw-r--r-- | drivers/misc/pch_phub.c | 717 | ||||
| -rw-r--r-- | drivers/scsi/hosts.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/scsi_scan.c | 2 | ||||
| -rw-r--r-- | drivers/uio/uio.c | 163 | ||||
| -rw-r--r-- | drivers/uio/uio_pci_generic.c | 13 | 
17 files changed, 977 insertions, 393 deletions
| diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index ef38aff737eb..fd96345bc35c 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -71,7 +71,6 @@ config PREVENT_FIRMWARE_BUILD  config FW_LOADER  	tristate "Userspace firmware loading support" if EMBEDDED -	depends on HOTPLUG  	default y  	---help---  	  This option is provided for the case where no in-kernel-tree modules diff --git a/drivers/base/Makefile b/drivers/base/Makefile index c12c7f2f2a6f..5f51c3b4451e 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -19,7 +19,5 @@ obj-$(CONFIG_MODULES)	+= module.o  endif  obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o -ifeq ($(CONFIG_DEBUG_DRIVER),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/drivers/base/bus.c b/drivers/base/bus.c index eb1b7fa20dce..33c270a64db7 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -440,22 +440,6 @@ static void device_remove_attrs(struct bus_type *bus, struct device *dev)  	}  } -#ifdef CONFIG_SYSFS_DEPRECATED -static int make_deprecated_bus_links(struct device *dev) -{ -	return sysfs_create_link(&dev->kobj, -				 &dev->bus->p->subsys.kobj, "bus"); -} - -static void remove_deprecated_bus_links(struct device *dev) -{ -	sysfs_remove_link(&dev->kobj, "bus"); -} -#else -static inline int make_deprecated_bus_links(struct device *dev) { return 0; } -static inline void remove_deprecated_bus_links(struct device *dev) { } -#endif -  /**   * bus_add_device - add device to bus   * @dev: device being added @@ -482,15 +466,10 @@ int bus_add_device(struct device *dev)  				&dev->bus->p->subsys.kobj, "subsystem");  		if (error)  			goto out_subsys; -		error = make_deprecated_bus_links(dev); -		if (error) -			goto out_deprecated;  		klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);  	}  	return 0; -out_deprecated: -	sysfs_remove_link(&dev->kobj, "subsystem");  out_subsys:  	sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));  out_id: @@ -530,7 +509,6 @@ void bus_remove_device(struct device *dev)  {  	if (dev->bus) {  		sysfs_remove_link(&dev->kobj, "subsystem"); -		remove_deprecated_bus_links(dev);  		sysfs_remove_link(&dev->bus->p->devices_kset->kobj,  				  dev_name(dev));  		device_remove_attrs(dev->bus, dev); diff --git a/drivers/base/class.c b/drivers/base/class.c index 8e231d05b400..9c63a5687d69 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -184,9 +184,9 @@ int __class_register(struct class *cls, struct lock_class_key *key)  	if (!cls->dev_kobj)  		cls->dev_kobj = sysfs_dev_char_kobj; -#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK) +#if defined(CONFIG_BLOCK)  	/* let the block class directory show up in the root of sysfs */ -	if (cls != &block_class) +	if (!sysfs_deprecated || cls != &block_class)  		cp->class_subsys.kobj.kset = class_kset;  #else  	cp->class_subsys.kobj.kset = class_kset; @@ -276,25 +276,6 @@ void class_destroy(struct class *cls)  	class_unregister(cls);  } -#ifdef CONFIG_SYSFS_DEPRECATED -char *make_class_name(const char *name, struct kobject *kobj) -{ -	char *class_name; -	int size; - -	size = strlen(name) + strlen(kobject_name(kobj)) + 2; - -	class_name = kmalloc(size, GFP_KERNEL); -	if (!class_name) -		return NULL; - -	strcpy(class_name, name); -	strcat(class_name, ":"); -	strcat(class_name, kobject_name(kobj)); -	return class_name; -} -#endif -  /**   * class_dev_iter_init - initialize class device iterator   * @iter: class iterator to initialize diff --git a/drivers/base/core.c b/drivers/base/core.c index d1b2c9adc271..2cb49a93b1e6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -26,6 +26,19 @@  #include "base.h"  #include "power/power.h" +#ifdef CONFIG_SYSFS_DEPRECATED +#ifdef CONFIG_SYSFS_DEPRECATED_V2 +long sysfs_deprecated = 1; +#else +long sysfs_deprecated = 0; +#endif +static __init int sysfs_deprecated_setup(char *arg) +{ +	return strict_strtol(arg, 10, &sysfs_deprecated); +} +early_param("sysfs.deprecated", sysfs_deprecated_setup); +#endif +  int (*platform_notify)(struct device *dev) = NULL;  int (*platform_notify_remove)(struct device *dev) = NULL;  static struct kobject *dev_kobj; @@ -203,37 +216,6 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,  	if (dev->driver)  		add_uevent_var(env, "DRIVER=%s", dev->driver->name); -#ifdef CONFIG_SYSFS_DEPRECATED -	if (dev->class) { -		struct device *parent = dev->parent; - -		/* find first bus device in parent chain */ -		while (parent && !parent->bus) -			parent = parent->parent; -		if (parent && parent->bus) { -			const char *path; - -			path = kobject_get_path(&parent->kobj, GFP_KERNEL); -			if (path) { -				add_uevent_var(env, "PHYSDEVPATH=%s", path); -				kfree(path); -			} - -			add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); - -			if (parent->driver) -				add_uevent_var(env, "PHYSDEVDRIVER=%s", -					       parent->driver->name); -		} -	} else if (dev->bus) { -		add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); - -		if (dev->driver) -			add_uevent_var(env, "PHYSDEVDRIVER=%s", -				       dev->driver->name); -	} -#endif -  	/* have the bus specific function add its stuff */  	if (dev->bus && dev->bus->uevent) {  		retval = dev->bus->uevent(dev, env); @@ -578,24 +560,6 @@ void device_initialize(struct device *dev)  	set_dev_node(dev, -1);  } -#ifdef CONFIG_SYSFS_DEPRECATED -static struct kobject *get_device_parent(struct device *dev, -					 struct device *parent) -{ -	/* class devices without a parent live in /sys/class/<classname>/ */ -	if (dev->class && (!parent || parent->class != dev->class)) -		return &dev->class->p->class_subsys.kobj; -	/* all other devices keep their parent */ -	else if (parent) -		return &parent->kobj; - -	return NULL; -} - -static inline void cleanup_device_parent(struct device *dev) {} -static inline void cleanup_glue_dir(struct device *dev, -				    struct kobject *glue_dir) {} -#else  static struct kobject *virtual_device_parent(struct device *dev)  {  	static struct kobject *virtual_dir = NULL; @@ -666,6 +630,15 @@ static struct kobject *get_device_parent(struct device *dev,  		struct kobject *parent_kobj;  		struct kobject *k; +#ifdef CONFIG_BLOCK +		/* block disks show up in /sys/block */ +		if (sysfs_deprecated && dev->class == &block_class) { +			if (parent && parent->class == &block_class) +				return &parent->kobj; +			return &block_class.p->class_subsys.kobj; +		} +#endif +  		/*  		 * If we have no parent, we live in "virtual".  		 * Class-devices with a non class-device as parent, live @@ -719,7 +692,6 @@ static void cleanup_device_parent(struct device *dev)  {  	cleanup_glue_dir(dev, dev->kobj.parent);  } -#endif  static void setup_parent(struct device *dev, struct device *parent)  { @@ -742,70 +714,29 @@ static int device_add_class_symlinks(struct device *dev)  	if (error)  		goto out; -#ifdef CONFIG_SYSFS_DEPRECATED -	/* stacked class devices need a symlink in the class directory */ -	if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && -	    device_is_not_partition(dev)) { -		error = sysfs_create_link(&dev->class->p->class_subsys.kobj, -					  &dev->kobj, dev_name(dev)); -		if (error) -			goto out_subsys; -	} -  	if (dev->parent && device_is_not_partition(dev)) { -		struct device *parent = dev->parent; -		char *class_name; - -		/* -		 * stacked class devices have the 'device' link -		 * pointing to the bus device instead of the parent -		 */ -		while (parent->class && !parent->bus && parent->parent) -			parent = parent->parent; - -		error = sysfs_create_link(&dev->kobj, -					  &parent->kobj, +		error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,  					  "device");  		if (error) -			goto out_busid; - -		class_name = make_class_name(dev->class->name, -						&dev->kobj); -		if (class_name) -			error = sysfs_create_link(&dev->parent->kobj, -						&dev->kobj, class_name); -		kfree(class_name); -		if (error) -			goto out_device; +			goto out_subsys;  	} -	return 0; -out_device: -	if (dev->parent && device_is_not_partition(dev)) -		sysfs_remove_link(&dev->kobj, "device"); -out_busid: -	if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && -	    device_is_not_partition(dev)) -		sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, -				  dev_name(dev)); -#else +#ifdef CONFIG_BLOCK +	/* /sys/block has directories and does not need symlinks */ +	if (sysfs_deprecated && dev->class == &block_class) +		return 0; +#endif +  	/* link in the class directory pointing to the device */  	error = sysfs_create_link(&dev->class->p->class_subsys.kobj,  				  &dev->kobj, dev_name(dev));  	if (error) -		goto out_subsys; +		goto out_device; -	if (dev->parent && device_is_not_partition(dev)) { -		error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, -					  "device"); -		if (error) -			goto out_busid; -	}  	return 0; -out_busid: -	sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); -#endif +out_device: +	sysfs_remove_link(&dev->kobj, "device");  out_subsys:  	sysfs_remove_link(&dev->kobj, "subsystem"); @@ -818,30 +749,14 @@ static void device_remove_class_symlinks(struct device *dev)  	if (!dev->class)  		return; -#ifdef CONFIG_SYSFS_DEPRECATED -	if (dev->parent && device_is_not_partition(dev)) { -		char *class_name; - -		class_name = make_class_name(dev->class->name, &dev->kobj); -		if (class_name) { -			sysfs_remove_link(&dev->parent->kobj, class_name); -			kfree(class_name); -		} -		sysfs_remove_link(&dev->kobj, "device"); -	} - -	if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && -	    device_is_not_partition(dev)) -		sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, -				  dev_name(dev)); -#else  	if (dev->parent && device_is_not_partition(dev))  		sysfs_remove_link(&dev->kobj, "device"); - -	sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); -#endif -  	sysfs_remove_link(&dev->kobj, "subsystem"); +#ifdef CONFIG_BLOCK +	if (sysfs_deprecated && dev->class == &block_class) +		return; +#endif +	sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));  }  /** @@ -1613,41 +1528,23 @@ int device_rename(struct device *dev, const char *new_name)  	pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev),  		 __func__, new_name); -#ifdef CONFIG_SYSFS_DEPRECATED -	if ((dev->class) && (dev->parent)) -		old_class_name = make_class_name(dev->class->name, &dev->kobj); -#endif -  	old_device_name = kstrdup(dev_name(dev), GFP_KERNEL);  	if (!old_device_name) {  		error = -ENOMEM;  		goto out;  	} -#ifndef CONFIG_SYSFS_DEPRECATED  	if (dev->class) {  		error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,  			&dev->kobj, old_device_name, new_name);  		if (error)  			goto out;  	} -#endif +  	error = kobject_rename(&dev->kobj, new_name);  	if (error)  		goto out; -#ifdef CONFIG_SYSFS_DEPRECATED -	if (old_class_name) { -		new_class_name = make_class_name(dev->class->name, &dev->kobj); -		if (new_class_name) { -			error = sysfs_rename_link(&dev->parent->kobj, -						  &dev->kobj, -						  old_class_name, -						  new_class_name); -		} -	} -#endif -  out:  	put_device(dev); @@ -1664,40 +1561,13 @@ static int device_move_class_links(struct device *dev,  				   struct device *new_parent)  {  	int error = 0; -#ifdef CONFIG_SYSFS_DEPRECATED -	char *class_name; -	class_name = make_class_name(dev->class->name, &dev->kobj); -	if (!class_name) { -		error = -ENOMEM; -		goto out; -	} -	if (old_parent) { -		sysfs_remove_link(&dev->kobj, "device"); -		sysfs_remove_link(&old_parent->kobj, class_name); -	} -	if (new_parent) { -		error = sysfs_create_link(&dev->kobj, &new_parent->kobj, -					  "device"); -		if (error) -			goto out; -		error = sysfs_create_link(&new_parent->kobj, &dev->kobj, -					  class_name); -		if (error) -			sysfs_remove_link(&dev->kobj, "device"); -	} else -		error = 0; -out: -	kfree(class_name); -	return error; -#else  	if (old_parent)  		sysfs_remove_link(&dev->kobj, "device");  	if (new_parent)  		error = sysfs_create_link(&dev->kobj, &new_parent->kobj,  					  "device");  	return error; -#endif  }  /** diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 933442f40321..cafeaaf0428f 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -27,6 +27,8 @@  #include <asm/atomic.h>  #include <asm/uaccess.h> +static DEFINE_MUTEX(mem_sysfs_mutex); +  #define MEMORY_CLASS_NAME	"memory"  static struct sysdev_class memory_sysdev_class = { @@ -435,6 +437,45 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn)  	return 0;  } +struct memory_block *find_memory_block_hinted(struct mem_section *section, +					      struct memory_block *hint) +{ +	struct kobject *kobj; +	struct sys_device *sysdev; +	struct memory_block *mem; +	char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; + +	kobj = hint ? &hint->sysdev.kobj : NULL; + +	/* +	 * This only works because we know that section == sysdev->id +	 * slightly redundant with sysdev_register() +	 */ +	sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section)); + +	kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); +	if (!kobj) +		return NULL; + +	sysdev = container_of(kobj, struct sys_device, kobj); +	mem = container_of(sysdev, struct memory_block, sysdev); + +	return mem; +} + +/* + * For now, we have a linear search to go find the appropriate + * memory_block corresponding to a particular phys_index. If + * this gets to be a real problem, we can always use a radix + * tree or something here. + * + * This could be made generic for all sysdev classes. + */ +struct memory_block *find_memory_block(struct mem_section *section) +{ +	return find_memory_block_hinted(section, NULL); +} +  static int add_memory_block(int nid, struct mem_section *section,  			unsigned long state, enum mem_add_context context)  { @@ -445,8 +486,11 @@ static int add_memory_block(int nid, struct mem_section *section,  	if (!mem)  		return -ENOMEM; +	mutex_lock(&mem_sysfs_mutex); +  	mem->phys_index = __section_nr(section);  	mem->state = state; +	mem->section_count++;  	mutex_init(&mem->state_mutex);  	start_pfn = section_nr_to_pfn(mem->phys_index);  	mem->phys_device = arch_get_memory_phys_device(start_pfn); @@ -465,53 +509,29 @@ static int add_memory_block(int nid, struct mem_section *section,  			ret = register_mem_sect_under_node(mem, nid);  	} +	mutex_unlock(&mem_sysfs_mutex);  	return ret;  } -/* - * For now, we have a linear search to go find the appropriate - * memory_block corresponding to a particular phys_index. If - * this gets to be a real problem, we can always use a radix - * tree or something here. - * - * This could be made generic for all sysdev classes. - */ -struct memory_block *find_memory_block(struct mem_section *section) -{ -	struct kobject *kobj; -	struct sys_device *sysdev; -	struct memory_block *mem; -	char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; - -	/* -	 * This only works because we know that section == sysdev->id -	 * slightly redundant with sysdev_register() -	 */ -	sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section)); - -	kobj = kset_find_obj(&memory_sysdev_class.kset, name); -	if (!kobj) -		return NULL; - -	sysdev = container_of(kobj, struct sys_device, kobj); -	mem = container_of(sysdev, struct memory_block, sysdev); - -	return mem; -} -  int remove_memory_block(unsigned long node_id, struct mem_section *section,  		int phys_device)  {  	struct memory_block *mem; +	mutex_lock(&mem_sysfs_mutex);  	mem = find_memory_block(section); -	unregister_mem_sect_under_nodes(mem); -	mem_remove_simple_file(mem, phys_index); -	mem_remove_simple_file(mem, state); -	mem_remove_simple_file(mem, phys_device); -	mem_remove_simple_file(mem, removable); -	unregister_memory(mem, section); +	mem->section_count--; +	if (mem->section_count == 0) { +		unregister_mem_sect_under_nodes(mem); +		mem_remove_simple_file(mem, phys_index); +		mem_remove_simple_file(mem, state); +		mem_remove_simple_file(mem, phys_device); +		mem_remove_simple_file(mem, removable); +		unregister_memory(mem, section); +	} + +	mutex_unlock(&mem_sysfs_mutex);  	return 0;  } diff --git a/drivers/base/node.c b/drivers/base/node.c index 2872e86837b2..ee53558b452f 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -409,25 +409,27 @@ static int link_mem_sections(int nid)  	unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;  	unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;  	unsigned long pfn; +	struct memory_block *mem_blk = NULL;  	int err = 0;  	for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {  		unsigned long section_nr = pfn_to_section_nr(pfn);  		struct mem_section *mem_sect; -		struct memory_block *mem_blk;  		int ret;  		if (!present_section_nr(section_nr))  			continue;  		mem_sect = __nr_to_section(section_nr); -		mem_blk = find_memory_block(mem_sect); +		mem_blk = find_memory_block_hinted(mem_sect, mem_blk);  		ret = register_mem_sect_under_node(mem_blk, nid);  		if (!err)  			err = ret;  		/* discard ref obtained in find_memory_block() */ -		kobject_put(&mem_blk->sysdev.kobj);  	} + +	if (mem_blk) +		kobject_put(&mem_blk->sysdev.kobj);  	return err;  } diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c6c933f58102..3966e62ad019 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -192,6 +192,9 @@ int platform_device_add_resources(struct platform_device *pdev,  {  	struct resource *r; +	if (!res) +		return 0; +  	r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);  	if (r) {  		pdev->resource = r; @@ -215,8 +218,12 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources);  int platform_device_add_data(struct platform_device *pdev, const void *data,  			     size_t size)  { -	void *d = kmemdup(data, size, GFP_KERNEL); +	void *d; + +	if (!data) +		return 0; +	d = kmemdup(data, size, GFP_KERNEL);  	if (d) {  		pdev->dev.platform_data = d;  		return 0; @@ -373,17 +380,13 @@ struct platform_device *__init_or_module platform_device_register_resndata(  	pdev->dev.parent = parent; -	if (res) { -		ret = platform_device_add_resources(pdev, res, num); -		if (ret) -			goto err; -	} +	ret = platform_device_add_resources(pdev, res, num); +	if (ret) +		goto err; -	if (data) { -		ret = platform_device_add_data(pdev, data, size); -		if (ret) -			goto err; -	} +	ret = platform_device_add_data(pdev, data, size); +	if (ret) +		goto err;  	ret = platform_device_add(pdev);  	if (ret) { @@ -488,12 +491,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,  	 * if the probe was successful, and make sure any forced probes of  	 * new devices fail.  	 */ -	spin_lock(&platform_bus_type.p->klist_drivers.k_lock); +	spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);  	drv->probe = NULL;  	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))  		retval = -ENODEV;  	drv->driver.probe = platform_drv_probe_fail; -	spin_unlock(&platform_bus_type.p->klist_drivers.k_lock); +	spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);  	if (code != retval)  		platform_driver_unregister(drv); @@ -530,17 +533,13 @@ struct platform_device * __init_or_module platform_create_bundle(  		goto err_out;  	} -	if (res) { -		error = platform_device_add_resources(pdev, res, n_res); -		if (error) -			goto err_pdev_put; -	} +	error = platform_device_add_resources(pdev, res, n_res); +	if (error) +		goto err_pdev_put; -	if (data) { -		error = platform_device_add_data(pdev, data, size); -		if (error) -			goto err_pdev_put; -	} +	error = platform_device_add_data(pdev, data, size); +	if (error) +		goto err_pdev_put;  	error = platform_device_add(pdev);  	if (error) @@ -976,6 +975,41 @@ struct bus_type platform_bus_type = {  };  EXPORT_SYMBOL_GPL(platform_bus_type); +/** + * platform_bus_get_pm_ops() - return pointer to busses dev_pm_ops + * + * This function can be used by platform code to get the current + * set of dev_pm_ops functions used by the platform_bus_type. + */ +const struct dev_pm_ops * __init platform_bus_get_pm_ops(void) +{ +	return platform_bus_type.pm; +} + +/** + * platform_bus_set_pm_ops() - update dev_pm_ops for the platform_bus_type + * + * @pm: pointer to new dev_pm_ops struct to be used for platform_bus_type + * + * Platform code can override the dev_pm_ops methods of + * platform_bus_type by using this function.  It is expected that + * platform code will first do a platform_bus_get_pm_ops(), then + * kmemdup it, then customize selected methods and pass a pointer to + * the new struct dev_pm_ops to this function. + * + * Since platform-specific code is customizing methods for *all* + * devices (not just platform-specific devices) it is expected that + * any custom overrides of these functions will keep existing behavior + * and simply extend it.  For example, any customization of the + * runtime PM methods should continue to call the pm_generic_* + * functions as the default ones do in addition to the + * platform-specific behavior. + */ +void __init platform_bus_set_pm_ops(const struct dev_pm_ops *pm) +{ +	platform_bus_type.pm = pm; +} +  int __init platform_bus_init(void)  {  	int error; diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 9354dc10a363..1667aaf4fde6 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -432,13 +432,13 @@ int sysdev_suspend(pm_message_t state)  	/* resume current sysdev */  cls_driver:  	drv = NULL; -	printk(KERN_ERR "Class suspend failed for %s\n", -		kobject_name(&sysdev->kobj)); +	printk(KERN_ERR "Class suspend failed for %s: %d\n", +		kobject_name(&sysdev->kobj), ret);  aux_driver:  	if (drv) -		printk(KERN_ERR "Class driver suspend failed for %s\n", -				kobject_name(&sysdev->kobj)); +		printk(KERN_ERR "Class driver suspend failed for %s: %d\n", +				kobject_name(&sysdev->kobj), ret);  	list_for_each_entry(err_drv, &cls->drivers, entry) {  		if (err_drv == drv)  			break; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b74331260744..db2fbe2d4146 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -248,15 +248,15 @@ config CS5535_CLOCK_EVENT_SRC  	  generic PIT, and are suitable for use as high-res timers.  config HP_ILO -	tristate "Channel interface driver for HP iLO/iLO2 processor" +	tristate "Channel interface driver for the HP iLO processor"  	depends on PCI  	default n  	help  	  The channel interface driver allows applications to communicate -	  with iLO/iLO2 management processors present on HP ProLiant -	  servers.  Upon loading, the driver creates /dev/hpilo/dXccbN files, -	  which can be used to gather data from the management processor, -	  via read and write system calls. +	  with iLO management processors present on HP ProLiant servers. +	  Upon loading, the driver creates /dev/hpilo/dXccbN files, which +	  can be used to gather data from the management processor, via +	  read and write system calls.  	  To compile this driver as a module, choose M here: the  	  module will be called hpilo. @@ -390,6 +390,18 @@ config BMP085  	  To compile this driver as a module, choose M here: the  	  module will be called bmp085. +config PCH_PHUB +	tristate "PCH Packet Hub of Intel Topcliff" +	depends on PCI +	help +	  This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of +	  Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded +	  processor. The Topcliff has MAC address and Option ROM data in SROM. +	  This driver can access MAC address and Option ROM data in SROM. + +	  To compile this driver as a module, choose M here: the module will +	  be called pch_phub. +  source "drivers/misc/c2port/Kconfig"  source "drivers/misc/eeprom/Kconfig"  source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 42eab95cde2a..9f2986b4da2f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -35,3 +35,4 @@ obj-y				+= eeprom/  obj-y				+= cb710/  obj-$(CONFIG_VMWARE_BALLOON)	+= vmw_balloon.o  obj-$(CONFIG_ARM_CHARLCD)	+= arm-charlcd.o +obj-$(CONFIG_PCH_PHUB)		+= pch_phub.o diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 69c1f2fca141..fffc227181b0 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -1,5 +1,5 @@  /* - * Driver for HP iLO/iLO2 management processor. + * Driver for the HP iLO management processor.   *   * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.   *	David Altobelli <david.altobelli@hp.com> diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c new file mode 100644 index 000000000000..744b804aca15 --- /dev/null +++ b/drivers/misc/pch_phub.c @@ -0,0 +1,717 @@ +/* + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/if_ether.h> +#include <linux/ctype.h> + +#define PHUB_STATUS 0x00		/* Status Register offset */ +#define PHUB_CONTROL 0x04		/* Control Register offset */ +#define PHUB_TIMEOUT 0x05		/* Time out value for Status Register */ +#define PCH_PHUB_ROM_WRITE_ENABLE 0x01	/* Enabling for writing ROM */ +#define PCH_PHUB_ROM_WRITE_DISABLE 0x00	/* Disabling for writing ROM */ +#define PCH_PHUB_ROM_START_ADDR 0x14	/* ROM data area start address offset */ + +/* MAX number of INT_REDUCE_CONTROL registers */ +#define MAX_NUM_INT_REDUCE_CONTROL_REG 128 +#define PCI_DEVICE_ID_PCH1_PHUB 0x8801 +#define PCH_MINOR_NOS 1 +#define CLKCFG_CAN_50MHZ 0x12000000 +#define CLKCFG_CANCLK_MASK 0xFF000000 + +/* SROM ACCESS Macro */ +#define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) + +/* Registers address offset */ +#define PCH_PHUB_ID_REG				0x0000 +#define PCH_PHUB_QUEUE_PRI_VAL_REG		0x0004 +#define PCH_PHUB_RC_QUEUE_MAXSIZE_REG		0x0008 +#define PCH_PHUB_BRI_QUEUE_MAXSIZE_REG		0x000C +#define PCH_PHUB_COMP_RESP_TIMEOUT_REG		0x0010 +#define PCH_PHUB_BUS_SLAVE_CONTROL_REG		0x0014 +#define PCH_PHUB_DEADLOCK_AVOID_TYPE_REG	0x0018 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG0	0x0020 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG1	0x0024 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG2	0x0028 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG3	0x002C +#define PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE	0x0040 +#define CLKCFG_REG_OFFSET			0x500 + +#define PCH_PHUB_OROM_SIZE 15360 + +/** + * struct pch_phub_reg - PHUB register structure + * @phub_id_reg:			PHUB_ID register val + * @q_pri_val_reg:			QUEUE_PRI_VAL register val + * @rc_q_maxsize_reg:			RC_QUEUE_MAXSIZE register val + * @bri_q_maxsize_reg:			BRI_QUEUE_MAXSIZE register val + * @comp_resp_timeout_reg:		COMP_RESP_TIMEOUT register val + * @bus_slave_control_reg:		BUS_SLAVE_CONTROL_REG register val + * @deadlock_avoid_type_reg:		DEADLOCK_AVOID_TYPE register val + * @intpin_reg_wpermit_reg0:		INTPIN_REG_WPERMIT register 0 val + * @intpin_reg_wpermit_reg1:		INTPIN_REG_WPERMIT register 1 val + * @intpin_reg_wpermit_reg2:		INTPIN_REG_WPERMIT register 2 val + * @intpin_reg_wpermit_reg3:		INTPIN_REG_WPERMIT register 3 val + * @int_reduce_control_reg:		INT_REDUCE_CONTROL registers val + * @clkcfg_reg:				CLK CFG register val + * @pch_phub_base_address:		Register base address + * @pch_phub_extrom_base_address:	external rom base address + */ +struct pch_phub_reg { +	u32 phub_id_reg; +	u32 q_pri_val_reg; +	u32 rc_q_maxsize_reg; +	u32 bri_q_maxsize_reg; +	u32 comp_resp_timeout_reg; +	u32 bus_slave_control_reg; +	u32 deadlock_avoid_type_reg; +	u32 intpin_reg_wpermit_reg0; +	u32 intpin_reg_wpermit_reg1; +	u32 intpin_reg_wpermit_reg2; +	u32 intpin_reg_wpermit_reg3; +	u32 int_reduce_control_reg[MAX_NUM_INT_REDUCE_CONTROL_REG]; +	u32 clkcfg_reg; +	void __iomem *pch_phub_base_address; +	void __iomem *pch_phub_extrom_base_address; +}; + +/* SROM SPEC for MAC address assignment offset */ +static const int pch_phub_mac_offset[ETH_ALEN] = {0x3, 0x2, 0x1, 0x0, 0xb, 0xa}; + +static DEFINE_MUTEX(pch_phub_mutex); + +/** + * pch_phub_read_modify_write_reg() - Reading modifying and writing register + * @reg_addr_offset:	Register offset address value. + * @data:		Writing value. + * @mask:		Mask value. + */ +static void pch_phub_read_modify_write_reg(struct pch_phub_reg *chip, +					   unsigned int reg_addr_offset, +					   unsigned int data, unsigned int mask) +{ +	void __iomem *reg_addr = chip->pch_phub_base_address + reg_addr_offset; +	iowrite32(((ioread32(reg_addr) & ~mask)) | data, reg_addr); +} + +/* pch_phub_save_reg_conf - saves register configuration */ +static void pch_phub_save_reg_conf(struct pci_dev *pdev) +{ +	unsigned int i; +	struct pch_phub_reg *chip = pci_get_drvdata(pdev); + +	void __iomem *p = chip->pch_phub_base_address; + +	chip->phub_id_reg = ioread32(p + PCH_PHUB_ID_REG); +	chip->q_pri_val_reg = ioread32(p + PCH_PHUB_QUEUE_PRI_VAL_REG); +	chip->rc_q_maxsize_reg = ioread32(p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); +	chip->bri_q_maxsize_reg = ioread32(p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); +	chip->comp_resp_timeout_reg = +				ioread32(p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); +	chip->bus_slave_control_reg = +				ioread32(p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); +	chip->deadlock_avoid_type_reg = +				ioread32(p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); +	chip->intpin_reg_wpermit_reg0 = +				ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); +	chip->intpin_reg_wpermit_reg1 = +				ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); +	chip->intpin_reg_wpermit_reg2 = +				ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); +	chip->intpin_reg_wpermit_reg3 = +				ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); +	dev_dbg(&pdev->dev, "%s : " +		"chip->phub_id_reg=%x, " +		"chip->q_pri_val_reg=%x, " +		"chip->rc_q_maxsize_reg=%x, " +		"chip->bri_q_maxsize_reg=%x, " +		"chip->comp_resp_timeout_reg=%x, " +		"chip->bus_slave_control_reg=%x, " +		"chip->deadlock_avoid_type_reg=%x, " +		"chip->intpin_reg_wpermit_reg0=%x, " +		"chip->intpin_reg_wpermit_reg1=%x, " +		"chip->intpin_reg_wpermit_reg2=%x, " +		"chip->intpin_reg_wpermit_reg3=%x\n", __func__, +		chip->phub_id_reg, +		chip->q_pri_val_reg, +		chip->rc_q_maxsize_reg, +		chip->bri_q_maxsize_reg, +		chip->comp_resp_timeout_reg, +		chip->bus_slave_control_reg, +		chip->deadlock_avoid_type_reg, +		chip->intpin_reg_wpermit_reg0, +		chip->intpin_reg_wpermit_reg1, +		chip->intpin_reg_wpermit_reg2, +		chip->intpin_reg_wpermit_reg3); +	for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { +		chip->int_reduce_control_reg[i] = +		    ioread32(p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); +		dev_dbg(&pdev->dev, "%s : " +			"chip->int_reduce_control_reg[%d]=%x\n", +			__func__, i, chip->int_reduce_control_reg[i]); +	} +	chip->clkcfg_reg = ioread32(p + CLKCFG_REG_OFFSET); +} + +/* pch_phub_restore_reg_conf - restore register configuration */ +static void pch_phub_restore_reg_conf(struct pci_dev *pdev) +{ +	unsigned int i; +	struct pch_phub_reg *chip = pci_get_drvdata(pdev); +	void __iomem *p; +	p = chip->pch_phub_base_address; + +	iowrite32(chip->phub_id_reg, p + PCH_PHUB_ID_REG); +	iowrite32(chip->q_pri_val_reg, p + PCH_PHUB_QUEUE_PRI_VAL_REG); +	iowrite32(chip->rc_q_maxsize_reg, p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); +	iowrite32(chip->bri_q_maxsize_reg, p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); +	iowrite32(chip->comp_resp_timeout_reg, +					p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); +	iowrite32(chip->bus_slave_control_reg, +					p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); +	iowrite32(chip->deadlock_avoid_type_reg, +					p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); +	iowrite32(chip->intpin_reg_wpermit_reg0, +					p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); +	iowrite32(chip->intpin_reg_wpermit_reg1, +					p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); +	iowrite32(chip->intpin_reg_wpermit_reg2, +					p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); +	iowrite32(chip->intpin_reg_wpermit_reg3, +					p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); +	dev_dbg(&pdev->dev, "%s : " +		"chip->phub_id_reg=%x, " +		"chip->q_pri_val_reg=%x, " +		"chip->rc_q_maxsize_reg=%x, " +		"chip->bri_q_maxsize_reg=%x, " +		"chip->comp_resp_timeout_reg=%x, " +		"chip->bus_slave_control_reg=%x, " +		"chip->deadlock_avoid_type_reg=%x, " +		"chip->intpin_reg_wpermit_reg0=%x, " +		"chip->intpin_reg_wpermit_reg1=%x, " +		"chip->intpin_reg_wpermit_reg2=%x, " +		"chip->intpin_reg_wpermit_reg3=%x\n", __func__, +		chip->phub_id_reg, +		chip->q_pri_val_reg, +		chip->rc_q_maxsize_reg, +		chip->bri_q_maxsize_reg, +		chip->comp_resp_timeout_reg, +		chip->bus_slave_control_reg, +		chip->deadlock_avoid_type_reg, +		chip->intpin_reg_wpermit_reg0, +		chip->intpin_reg_wpermit_reg1, +		chip->intpin_reg_wpermit_reg2, +		chip->intpin_reg_wpermit_reg3); +	for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { +		iowrite32(chip->int_reduce_control_reg[i], +			p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); +		dev_dbg(&pdev->dev, "%s : " +			"chip->int_reduce_control_reg[%d]=%x\n", +			__func__, i, chip->int_reduce_control_reg[i]); +	} + +	iowrite32(chip->clkcfg_reg, p + CLKCFG_REG_OFFSET); +} + +/** + * pch_phub_read_serial_rom() - Reading Serial ROM + * @offset_address:	Serial ROM offset address to read. + * @data:		Read buffer for specified Serial ROM value. + */ +static void pch_phub_read_serial_rom(struct pch_phub_reg *chip, +				     unsigned int offset_address, u8 *data) +{ +	void __iomem *mem_addr = chip->pch_phub_extrom_base_address + +								offset_address; + +	*data = ioread8(mem_addr); +} + +/** + * pch_phub_write_serial_rom() - Writing Serial ROM + * @offset_address:	Serial ROM offset address. + * @data:		Serial ROM value to write. + */ +static int pch_phub_write_serial_rom(struct pch_phub_reg *chip, +				     unsigned int offset_address, u8 data) +{ +	void __iomem *mem_addr = chip->pch_phub_extrom_base_address + +					(offset_address & PCH_WORD_ADDR_MASK); +	int i; +	unsigned int word_data; +	unsigned int pos; +	unsigned int mask; +	pos = (offset_address % 4) * 8; +	mask = ~(0xFF << pos); + +	iowrite32(PCH_PHUB_ROM_WRITE_ENABLE, +			chip->pch_phub_extrom_base_address + PHUB_CONTROL); + +	word_data = ioread32(mem_addr); +	iowrite32((word_data & mask) | (u32)data << pos, mem_addr); + +	i = 0; +	while (ioread8(chip->pch_phub_extrom_base_address + +						PHUB_STATUS) != 0x00) { +		msleep(1); +		if (i == PHUB_TIMEOUT) +			return -ETIMEDOUT; +		i++; +	} + +	iowrite32(PCH_PHUB_ROM_WRITE_DISABLE, +			chip->pch_phub_extrom_base_address + PHUB_CONTROL); + +	return 0; +} + +/** + * pch_phub_read_serial_rom_val() - Read Serial ROM value + * @offset_address:	Serial ROM address offset value. + * @data:		Serial ROM value to read. + */ +static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip, +					 unsigned int offset_address, u8 *data) +{ +	unsigned int mem_addr; + +	mem_addr = PCH_PHUB_ROM_START_ADDR + +			pch_phub_mac_offset[offset_address]; + +	pch_phub_read_serial_rom(chip, mem_addr, data); +} + +/** + * pch_phub_write_serial_rom_val() - writing Serial ROM value + * @offset_address:	Serial ROM address offset value. + * @data:		Serial ROM value. + */ +static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip, +					 unsigned int offset_address, u8 data) +{ +	int retval; +	unsigned int mem_addr; + +	mem_addr = PCH_PHUB_ROM_START_ADDR + +			pch_phub_mac_offset[offset_address]; + +	retval = pch_phub_write_serial_rom(chip, mem_addr, data); + +	return retval; +} + +/* pch_phub_gbe_serial_rom_conf - makes Serial ROM header format configuration + * for Gigabit Ethernet MAC address + */ +static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip) +{ +	int retval; + +	retval = pch_phub_write_serial_rom(chip, 0x0b, 0xbc); +	retval |= pch_phub_write_serial_rom(chip, 0x0a, 0x10); +	retval |= pch_phub_write_serial_rom(chip, 0x09, 0x01); +	retval |= pch_phub_write_serial_rom(chip, 0x08, 0x02); + +	retval |= pch_phub_write_serial_rom(chip, 0x0f, 0x00); +	retval |= pch_phub_write_serial_rom(chip, 0x0e, 0x00); +	retval |= pch_phub_write_serial_rom(chip, 0x0d, 0x00); +	retval |= pch_phub_write_serial_rom(chip, 0x0c, 0x80); + +	retval |= pch_phub_write_serial_rom(chip, 0x13, 0xbc); +	retval |= pch_phub_write_serial_rom(chip, 0x12, 0x10); +	retval |= pch_phub_write_serial_rom(chip, 0x11, 0x01); +	retval |= pch_phub_write_serial_rom(chip, 0x10, 0x18); + +	retval |= pch_phub_write_serial_rom(chip, 0x1b, 0xbc); +	retval |= pch_phub_write_serial_rom(chip, 0x1a, 0x10); +	retval |= pch_phub_write_serial_rom(chip, 0x19, 0x01); +	retval |= pch_phub_write_serial_rom(chip, 0x18, 0x19); + +	retval |= pch_phub_write_serial_rom(chip, 0x23, 0xbc); +	retval |= pch_phub_write_serial_rom(chip, 0x22, 0x10); +	retval |= pch_phub_write_serial_rom(chip, 0x21, 0x01); +	retval |= pch_phub_write_serial_rom(chip, 0x20, 0x3a); + +	retval |= pch_phub_write_serial_rom(chip, 0x27, 0x01); +	retval |= pch_phub_write_serial_rom(chip, 0x26, 0x00); +	retval |= pch_phub_write_serial_rom(chip, 0x25, 0x00); +	retval |= pch_phub_write_serial_rom(chip, 0x24, 0x00); + +	return retval; +} + +/** + * pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address + * @offset_address:	Gigabit Ethernet MAC address offset value. + * @data:		Buffer of the Gigabit Ethernet MAC address value. + */ +static void pch_phub_read_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) +{ +	int i; +	for (i = 0; i < ETH_ALEN; i++) +		pch_phub_read_serial_rom_val(chip, i, &data[i]); +} + +/** + * pch_phub_write_gbe_mac_addr() - Write MAC address + * @offset_address:	Gigabit Ethernet MAC address offset value. + * @data:		Gigabit Ethernet MAC address value. + */ +static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) +{ +	int retval; +	int i; + +	retval = pch_phub_gbe_serial_rom_conf(chip); +	if (retval) +		return retval; + +	for (i = 0; i < ETH_ALEN; i++) { +		retval = pch_phub_write_serial_rom_val(chip, i, data[i]); +		if (retval) +			return retval; +	} + +	return retval; +} + +static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, +				 struct bin_attribute *attr, char *buf, +				 loff_t off, size_t count) +{ +	unsigned int rom_signature; +	unsigned char rom_length; +	unsigned int tmp; +	unsigned int addr_offset; +	unsigned int orom_size; +	int ret; +	int err; + +	struct pch_phub_reg *chip = +		dev_get_drvdata(container_of(kobj, struct device, kobj)); + +	ret = mutex_lock_interruptible(&pch_phub_mutex); +	if (ret) { +		err = -ERESTARTSYS; +		goto return_err_nomutex; +	} + +	/* Get Rom signature */ +	pch_phub_read_serial_rom(chip, 0x80, (unsigned char *)&rom_signature); +	rom_signature &= 0xff; +	pch_phub_read_serial_rom(chip, 0x81, (unsigned char *)&tmp); +	rom_signature |= (tmp & 0xff) << 8; +	if (rom_signature == 0xAA55) { +		pch_phub_read_serial_rom(chip, 0x82, &rom_length); +		orom_size = rom_length * 512; +		if (orom_size < off) { +			addr_offset = 0; +			goto return_ok; +		} +		if (orom_size < count) { +			addr_offset = 0; +			goto return_ok; +		} + +		for (addr_offset = 0; addr_offset < count; addr_offset++) { +			pch_phub_read_serial_rom(chip, 0x80 + addr_offset + off, +							 &buf[addr_offset]); +		} +	} else { +		err = -ENODATA; +		goto return_err; +	} +return_ok: +	mutex_unlock(&pch_phub_mutex); +	return addr_offset; + +return_err: +	mutex_unlock(&pch_phub_mutex); +return_err_nomutex: +	return err; +} + +static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, +				  struct bin_attribute *attr, +				  char *buf, loff_t off, size_t count) +{ +	int err; +	unsigned int addr_offset; +	int ret; +	struct pch_phub_reg *chip = +		dev_get_drvdata(container_of(kobj, struct device, kobj)); + +	ret = mutex_lock_interruptible(&pch_phub_mutex); +	if (ret) +		return -ERESTARTSYS; + +	if (off > PCH_PHUB_OROM_SIZE) { +		addr_offset = 0; +		goto return_ok; +	} +	if (count > PCH_PHUB_OROM_SIZE) { +		addr_offset = 0; +		goto return_ok; +	} + +	for (addr_offset = 0; addr_offset < count; addr_offset++) { +		if (PCH_PHUB_OROM_SIZE < off + addr_offset) +			goto return_ok; + +		ret = pch_phub_write_serial_rom(chip, 0x80 + addr_offset + off, +						       buf[addr_offset]); +		if (ret) { +			err = ret; +			goto return_err; +		} +	} + +return_ok: +	mutex_unlock(&pch_phub_mutex); +	return addr_offset; + +return_err: +	mutex_unlock(&pch_phub_mutex); +	return err; +} + +static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr, +			    char *buf) +{ +	u8 mac[8]; +	struct pch_phub_reg *chip = dev_get_drvdata(dev); + +	pch_phub_read_gbe_mac_addr(chip, mac); + +	return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", +				mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, +			     const char *buf, size_t count) +{ +	u8 mac[6]; +	struct pch_phub_reg *chip = dev_get_drvdata(dev); + +	if (count != 18) +		return -EINVAL; + +	sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", +		(u32 *)&mac[0], (u32 *)&mac[1], (u32 *)&mac[2], (u32 *)&mac[3], +		(u32 *)&mac[4], (u32 *)&mac[5]); + +	pch_phub_write_gbe_mac_addr(chip, mac); + +	return count; +} + +static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); + +static struct bin_attribute pch_bin_attr = { +	.attr = { +		.name = "pch_firmware", +		.mode = S_IRUGO | S_IWUSR, +	}, +	.size = PCH_PHUB_OROM_SIZE + 1, +	.read = pch_phub_bin_read, +	.write = pch_phub_bin_write, +}; + +static int __devinit pch_phub_probe(struct pci_dev *pdev, +				    const struct pci_device_id *id) +{ +	int retval; + +	int ret; +	ssize_t rom_size; +	struct pch_phub_reg *chip; + +	chip = kzalloc(sizeof(struct pch_phub_reg), GFP_KERNEL); +	if (chip == NULL) +		return -ENOMEM; + +	ret = pci_enable_device(pdev); +	if (ret) { +		dev_err(&pdev->dev, +		"%s : pci_enable_device FAILED(ret=%d)", __func__, ret); +		goto err_pci_enable_dev; +	} +	dev_dbg(&pdev->dev, "%s : pci_enable_device returns %d\n", __func__, +		ret); + +	ret = pci_request_regions(pdev, KBUILD_MODNAME); +	if (ret) { +		dev_err(&pdev->dev, +		"%s : pci_request_regions FAILED(ret=%d)", __func__, ret); +		goto err_req_regions; +	} +	dev_dbg(&pdev->dev, "%s : " +		"pci_request_regions returns %d\n", __func__, ret); + +	chip->pch_phub_base_address = pci_iomap(pdev, 1, 0); + + +	if (chip->pch_phub_base_address == 0) { +		dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); +		ret = -ENOMEM; +		goto err_pci_iomap; +	} +	dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value " +		"in pch_phub_base_address variable is %p\n", __func__, +		chip->pch_phub_base_address); +	chip->pch_phub_extrom_base_address = pci_map_rom(pdev, &rom_size); + +	if (chip->pch_phub_extrom_base_address == 0) { +		dev_err(&pdev->dev, "%s : pci_map_rom FAILED", __func__); +		ret = -ENOMEM; +		goto err_pci_map; +	} +	dev_dbg(&pdev->dev, "%s : " +		"pci_map_rom SUCCESS and value in " +		"pch_phub_extrom_base_address variable is %p\n", __func__, +		chip->pch_phub_extrom_base_address); + +	pci_set_drvdata(pdev, chip); + +	retval = sysfs_create_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); +	if (retval) +		goto err_sysfs_create; + +	retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); +	if (retval) +		goto exit_bin_attr; + +	pch_phub_read_modify_write_reg(chip, (unsigned int)CLKCFG_REG_OFFSET, +					CLKCFG_CAN_50MHZ, CLKCFG_CANCLK_MASK); + +	/* set the prefech value */ +	iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); +	/* set the interrupt delay value */ +	iowrite32(0x25, chip->pch_phub_base_address + 0x44); + +	return 0; +exit_bin_attr: +	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); + +err_sysfs_create: +	pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); +err_pci_map: +	pci_iounmap(pdev, chip->pch_phub_base_address); +err_pci_iomap: +	pci_release_regions(pdev); +err_req_regions: +	pci_disable_device(pdev); +err_pci_enable_dev: +	kfree(chip); +	dev_err(&pdev->dev, "%s returns %d\n", __func__, ret); +	return ret; +} + +static void __devexit pch_phub_remove(struct pci_dev *pdev) +{ +	struct pch_phub_reg *chip = pci_get_drvdata(pdev); + +	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); +	sysfs_remove_bin_file(&pdev->dev.kobj, &pch_bin_attr); +	pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); +	pci_iounmap(pdev, chip->pch_phub_base_address); +	pci_release_regions(pdev); +	pci_disable_device(pdev); +	kfree(chip); +} + +#ifdef CONFIG_PM + +static int pch_phub_suspend(struct pci_dev *pdev, pm_message_t state) +{ +	int ret; + +	pch_phub_save_reg_conf(pdev); +	ret = pci_save_state(pdev); +	if (ret) { +		dev_err(&pdev->dev, +			" %s -pci_save_state returns %d\n", __func__, ret); +		return ret; +	} +	pci_enable_wake(pdev, PCI_D3hot, 0); +	pci_disable_device(pdev); +	pci_set_power_state(pdev, pci_choose_state(pdev, state)); + +	return 0; +} + +static int pch_phub_resume(struct pci_dev *pdev) +{ +	int ret; + +	pci_set_power_state(pdev, PCI_D0); +	pci_restore_state(pdev); +	ret = pci_enable_device(pdev); +	if (ret) { +		dev_err(&pdev->dev, +		"%s-pci_enable_device failed(ret=%d) ", __func__, ret); +		return ret; +	} + +	pci_enable_wake(pdev, PCI_D3hot, 0); +	pch_phub_restore_reg_conf(pdev); + +	return 0; +} +#else +#define pch_phub_suspend NULL +#define pch_phub_resume NULL +#endif /* CONFIG_PM */ + +static struct pci_device_id pch_phub_pcidev_id[] = { +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH1_PHUB)}, +	{0,} +}; + +static struct pci_driver pch_phub_driver = { +	.name = "pch_phub", +	.id_table = pch_phub_pcidev_id, +	.probe = pch_phub_probe, +	.remove = __devexit_p(pch_phub_remove), +	.suspend = pch_phub_suspend, +	.resume = pch_phub_resume +}; + +static int __init pch_phub_pci_init(void) +{ +	return pci_register_driver(&pch_phub_driver); +} + +static void __exit pch_phub_pci_exit(void) +{ +	pci_unregister_driver(&pch_phub_driver); +} + +module_init(pch_phub_pci_init); +module_exit(pch_phub_pci_exit); + +MODULE_DESCRIPTION("PCH Packet Hub PCI Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 10478153641b..4f7a5829ea4c 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -412,9 +412,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)  	device_initialize(&shost->shost_gendev);  	dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); -#ifndef CONFIG_SYSFS_DEPRECATED  	shost->shost_gendev.bus = &scsi_bus_type; -#endif  	shost->shost_gendev.type = &scsi_host_type;  	device_initialize(&shost->shost_dev); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 3d0a1e6e9c48..087821fac8fe 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -417,9 +417,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,  	starget->reap_ref = 1;  	dev->parent = get_device(parent);  	dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id); -#ifndef CONFIG_SYSFS_DEPRECATED  	dev->bus = &scsi_bus_type; -#endif  	dev->type = &scsi_target_type;  	starget->id = id;  	starget->channel = channel; diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 4d3a6fd1a152..a858d2b87b94 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -23,9 +23,10 @@  #include <linux/sched.h>  #include <linux/string.h>  #include <linux/kobject.h> +#include <linux/cdev.h>  #include <linux/uio_driver.h> -#define UIO_MAX_DEVICES 255 +#define UIO_MAX_DEVICES		(1U << MINORBITS)  struct uio_device {  	struct module		*owner; @@ -41,15 +42,10 @@ struct uio_device {  };  static int uio_major; +static struct cdev *uio_cdev;  static DEFINE_IDR(uio_idr);  static const struct file_operations uio_fops; -/* UIO class infrastructure */ -static struct uio_class { -	struct kref kref; -	struct class *class; -} *uio_class; -  /* Protect idr accesses */  static DEFINE_MUTEX(minor_lock); @@ -232,45 +228,34 @@ static ssize_t show_name(struct device *dev,  			 struct device_attribute *attr, char *buf)  {  	struct uio_device *idev = dev_get_drvdata(dev); -	if (idev) -		return sprintf(buf, "%s\n", idev->info->name); -	else -		return -ENODEV; +	return sprintf(buf, "%s\n", idev->info->name);  } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);  static ssize_t show_version(struct device *dev,  			    struct device_attribute *attr, char *buf)  {  	struct uio_device *idev = dev_get_drvdata(dev); -	if (idev) -		return sprintf(buf, "%s\n", idev->info->version); -	else -		return -ENODEV; +	return sprintf(buf, "%s\n", idev->info->version);  } -static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);  static ssize_t show_event(struct device *dev,  			  struct device_attribute *attr, char *buf)  {  	struct uio_device *idev = dev_get_drvdata(dev); -	if (idev) -		return sprintf(buf, "%u\n", -				(unsigned int)atomic_read(&idev->event)); -	else -		return -ENODEV; +	return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event));  } -static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); -static struct attribute *uio_attrs[] = { -	&dev_attr_name.attr, -	&dev_attr_version.attr, -	&dev_attr_event.attr, -	NULL, +static struct device_attribute uio_class_attributes[] = { +	__ATTR(name, S_IRUGO, show_name, NULL), +	__ATTR(version, S_IRUGO, show_version, NULL), +	__ATTR(event, S_IRUGO, show_event, NULL), +	{}  }; -static struct attribute_group uio_attr_grp = { -	.attrs = uio_attrs, +/* UIO class infrastructure */ +static struct class uio_class = { +	.name = "uio", +	.dev_attrs = uio_class_attributes,  };  /* @@ -287,10 +272,6 @@ static int uio_dev_add_attributes(struct uio_device *idev)  	struct uio_port *port;  	struct uio_portio *portio; -	ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); -	if (ret) -		goto err_group; -  	for (mi = 0; mi < MAX_UIO_MAPS; mi++) {  		mem = &idev->info->mem[mi];  		if (mem->size == 0) @@ -358,8 +339,6 @@ err_map:  		kobject_put(&map->kobj);  	}  	kobject_put(idev->map_dir); -	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); -err_group:  	dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);  	return ret;  } @@ -385,8 +364,6 @@ static void uio_dev_del_attributes(struct uio_device *idev)  		kobject_put(&port->portio->kobj);  	}  	kobject_put(idev->portio_dir); - -	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);  }  static int uio_get_minor(struct uio_device *idev) @@ -525,7 +502,7 @@ static unsigned int uio_poll(struct file *filep, poll_table *wait)  	struct uio_listener *listener = filep->private_data;  	struct uio_device *idev = listener->dev; -	if (idev->info->irq == UIO_IRQ_NONE) +	if (!idev->info->irq)  		return -EIO;  	poll_wait(filep, &idev->wait, wait); @@ -543,7 +520,7 @@ static ssize_t uio_read(struct file *filep, char __user *buf,  	ssize_t retval;  	s32 event_count; -	if (idev->info->irq == UIO_IRQ_NONE) +	if (!idev->info->irq)  		return -EIO;  	if (count != sizeof(s32)) @@ -591,7 +568,7 @@ static ssize_t uio_write(struct file *filep, const char __user *buf,  	ssize_t retval;  	s32 irq_on; -	if (idev->info->irq == UIO_IRQ_NONE) +	if (!idev->info->irq)  		return -EIO;  	if (count != sizeof(s32)) @@ -745,68 +722,72 @@ static const struct file_operations uio_fops = {  static int uio_major_init(void)  { -	uio_major = register_chrdev(0, "uio", &uio_fops); -	if (uio_major < 0) -		return uio_major; -	return 0; +	static const char name[] = "uio"; +	struct cdev *cdev = NULL; +	dev_t uio_dev = 0; +	int result; + +	result = alloc_chrdev_region(&uio_dev, 0, UIO_MAX_DEVICES, name); +	if (result) +		goto out; + +	result = -ENOMEM; +	cdev = cdev_alloc(); +	if (!cdev) +		goto out_unregister; + +	cdev->owner = THIS_MODULE; +	cdev->ops = &uio_fops; +	kobject_set_name(&cdev->kobj, "%s", name); + +	result = cdev_add(cdev, uio_dev, UIO_MAX_DEVICES); +	if (result) +		goto out_put; + +	uio_major = MAJOR(uio_dev); +	uio_cdev = cdev; +	result = 0; +out: +	return result; +out_put: +	kobject_put(&cdev->kobj); +out_unregister: +	unregister_chrdev_region(uio_dev, UIO_MAX_DEVICES); +	goto out;  }  static void uio_major_cleanup(void)  { -	unregister_chrdev(uio_major, "uio"); +	unregister_chrdev_region(MKDEV(uio_major, 0), UIO_MAX_DEVICES); +	cdev_del(uio_cdev);  }  static int init_uio_class(void)  { -	int ret = 0; - -	if (uio_class != NULL) { -		kref_get(&uio_class->kref); -		goto exit; -	} +	int ret;  	/* This is the first time in here, set everything up properly */  	ret = uio_major_init();  	if (ret)  		goto exit; -	uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL); -	if (!uio_class) { -		ret = -ENOMEM; -		goto err_kzalloc; -	} - -	kref_init(&uio_class->kref); -	uio_class->class = class_create(THIS_MODULE, "uio"); -	if (IS_ERR(uio_class->class)) { -		ret = IS_ERR(uio_class->class); -		printk(KERN_ERR "class_create failed for uio\n"); -		goto err_class_create; +	ret = class_register(&uio_class); +	if (ret) { +		printk(KERN_ERR "class_register failed for uio\n"); +		goto err_class_register;  	}  	return 0; -err_class_create: -	kfree(uio_class); -	uio_class = NULL; -err_kzalloc: +err_class_register:  	uio_major_cleanup();  exit:  	return ret;  } -static void release_uio_class(struct kref *kref) +static void release_uio_class(void)  { -	/* Ok, we cheat as we know we only have one uio_class */ -	class_destroy(uio_class->class); -	kfree(uio_class); +	class_unregister(&uio_class);  	uio_major_cleanup(); -	uio_class = NULL; -} - -static void uio_class_destroy(void) -{ -	if (uio_class) -		kref_put(&uio_class->kref, release_uio_class);  }  /** @@ -829,10 +810,6 @@ int __uio_register_device(struct module *owner,  	info->uio_dev = NULL; -	ret = init_uio_class(); -	if (ret) -		return ret; -  	idev = kzalloc(sizeof(*idev), GFP_KERNEL);  	if (!idev) {  		ret = -ENOMEM; @@ -848,7 +825,7 @@ int __uio_register_device(struct module *owner,  	if (ret)  		goto err_get_minor; -	idev->dev = device_create(uio_class->class, parent, +	idev->dev = device_create(&uio_class, parent,  				  MKDEV(uio_major, idev->minor), idev,  				  "uio%d", idev->minor);  	if (IS_ERR(idev->dev)) { @@ -863,9 +840,9 @@ int __uio_register_device(struct module *owner,  	info->uio_dev = idev; -	if (idev->info->irq >= 0) { -		ret = request_irq(idev->info->irq, uio_interrupt, -				  idev->info->irq_flags, idev->info->name, idev); +	if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { +		ret = request_irq(info->irq, uio_interrupt, +				  info->irq_flags, info->name, idev);  		if (ret)  			goto err_request_irq;  	} @@ -875,13 +852,12 @@ int __uio_register_device(struct module *owner,  err_request_irq:  	uio_dev_del_attributes(idev);  err_uio_dev_add_attributes: -	device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); +	device_destroy(&uio_class, MKDEV(uio_major, idev->minor));  err_device_create:  	uio_free_minor(idev);  err_get_minor:  	kfree(idev);  err_kzalloc: -	uio_class_destroy();  	return ret;  }  EXPORT_SYMBOL_GPL(__uio_register_device); @@ -902,15 +878,13 @@ void uio_unregister_device(struct uio_info *info)  	uio_free_minor(idev); -	if (info->irq >= 0) +	if (info->irq && (info->irq != UIO_IRQ_CUSTOM))  		free_irq(info->irq, idev);  	uio_dev_del_attributes(idev); -	dev_set_drvdata(idev->dev, NULL); -	device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); +	device_destroy(&uio_class, MKDEV(uio_major, idev->minor));  	kfree(idev); -	uio_class_destroy();  	return;  } @@ -918,11 +892,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device);  static int __init uio_init(void)  { -	return 0; +	return init_uio_class();  }  static void __exit uio_exit(void)  { +	release_uio_class();  }  module_init(uio_init) diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index 85c9884a67fd..fc22e1e6f215 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c @@ -128,12 +128,6 @@ static int __devinit probe(struct pci_dev *pdev,  	struct uio_pci_generic_dev *gdev;  	int err; -	if (!pdev->irq) { -		dev_warn(&pdev->dev, "No IRQ assigned to device: " -			 "no support for interrupts?\n"); -		return -ENODEV; -	} -  	err = pci_enable_device(pdev);  	if (err) {  		dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", @@ -141,6 +135,13 @@ static int __devinit probe(struct pci_dev *pdev,  		return err;  	} +	if (!pdev->irq) { +		dev_warn(&pdev->dev, "No IRQ assigned to device: " +			 "no support for interrupts?\n"); +		pci_disable_device(pdev); +		return -ENODEV; +	} +  	err = verify_pci_2_3(pdev);  	if (err)  		goto err_verify; | 
