diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 02:36:42 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 02:36:42 (GMT) |
commit | b9da0571050c09863e59f94d0b8594a290d61b88 (patch) | |
tree | 3632c4fee768db9a27a5c872bd42133692e2f3d0 | |
parent | f8cae0f03f75adb54b1d48ddbc90f84a1f5de186 (diff) | |
parent | 5abd935661e01289ba143c3b2c1ba300c65bcc5f (diff) | |
download | linux-fsl-qoriq-b9da0571050c09863e59f94d0b8594a290d61b88.tar.xz |
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
...
34 files changed, 1238 insertions, 516 deletions
diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module new file mode 100644 index 0000000..cfcec3b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-module @@ -0,0 +1,12 @@ +What: /sys/module/pch_phub/drivers/.../pch_mac +Date: August 2010 +KernelVersion: 2.6.35 +Contact: masa-korg@dsn.okisemi.com +Description: Write/read GbE MAC address. + +What: /sys/module/pch_phub/drivers/.../pch_firmware +Date: August 2010 +KernelVersion: 2.6.35 +Contact: masa-korg@dsn.okisemi.com +Description: Write/read Option ROM data. + diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt index 674c566..58ea64a 100644 --- a/Documentation/dynamic-debug-howto.txt +++ b/Documentation/dynamic-debug-howto.txt @@ -24,7 +24,7 @@ Dynamic debug has even more useful features: read to display the complete list of known debug statements, to help guide you Controlling dynamic debug Behaviour -=============================== +=================================== The behaviour of pr_debug()/dev_debug()s are controlled via writing to a control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs @@ -212,6 +212,26 @@ Note the regexp ^[-+=][scp]+$ matches a flags specification. Note also that there is no convenient syntax to remove all the flags at once, you need to use "-psc". + +Debug messages during boot process +================================== + +To be able to activate debug messages during the boot process, +even before userspace and debugfs exists, use the boot parameter: +ddebug_query="QUERY" + +QUERY follows the syntax described above, but must not exceed 1023 +characters. The enablement of debug messages is done as an arch_initcall. +Thus you can enable debug messages in all code processed after this +arch_initcall via this boot parameter. +On an x86 system for example ACPI enablement is a subsys_initcall and +ddebug_query="file ec.c +p" +will show early Embedded Controller transactions during ACPI setup if +your machine (typically a laptop) has an Embedded Controller. +PCI (or other devices) initialization also is a hot candidate for using +this boot parameter for debugging purposes. + + Examples ======== diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 02f21d9..4cd8b86 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -43,10 +43,11 @@ parameter is applicable: AVR32 AVR32 architecture is enabled. AX25 Appropriate AX.25 support is enabled. BLACKFIN Blackfin architecture is enabled. - DRM Direct Rendering Management support is enabled. EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EFI EFI Partitioning (GPT) is enabled EIDE EIDE/ATAPI support is enabled. + DRM Direct Rendering Management support is enabled. + DYNAMIC_DEBUG Build in debug messages and enable them at runtime FB The frame buffer device is enabled. GCOV GCOV profiling is enabled. HW Appropriate hardware is enabled. @@ -570,6 +571,10 @@ and is between 256 and 4096 characters. It is defined in the file Format: <port#>,<type> See also Documentation/input/joystick-parport.txt + ddebug_query= [KNL,DYNAMIC_DEBUG] Enable debug messages at early boot + time. See Documentation/dynamic-debug-howto.txt for + details. + debug [KNL] Enable kernel debugging (events log level). debug_locks_verbose= @@ -2370,6 +2375,15 @@ and is between 256 and 4096 characters. It is defined in the file switches= [HW,M68k] + sysfs.deprecated=0|1 [KNL] + Enable/disable old style sysfs layout for old udev + on older distributions. When this option is enabled + very new udev will not work anymore. When this option + is disabled (or CONFIG_SYSFS_DEPRECATED not compiled) + in older udev will not work anymore. + Default depends on CONFIG_SYSFS_DEPRECATED_V2 set in + the kernel configuration. + sysrq_always_enabled [KNL] Ignore sysrq setting - this boot parameter will diff --git a/MAINTAINERS b/MAINTAINERS index b618b1e..fd19b54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2064,14 +2064,16 @@ F: drivers/block/drbd/ F: lib/lru_cache.c F: Documentation/blockdev/drbd/ -DRIVER CORE, KOBJECTS, AND SYSFS +DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS M: Greg Kroah-Hartman <gregkh@suse.de> T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ S: Supported F: Documentation/kobject.txt F: drivers/base/ F: fs/sysfs/ +F: fs/debugfs/ F: include/linux/kobj* +F: include/linux/debugfs.h F: lib/kobj* DRM DRIVERS diff --git a/block/genhd.c b/block/genhd.c index 8313834..a8adf96 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -22,9 +22,7 @@ #include "blk.h" static DEFINE_MUTEX(block_class_lock); -#ifndef CONFIG_SYSFS_DEPRECATED struct kobject *block_depr; -#endif /* for extended dynamic devt allocation, currently only one major is used */ #define MAX_EXT_DEVT (1 << MINORBITS) @@ -810,10 +808,9 @@ static int __init genhd_device_init(void) register_blkdev(BLOCK_EXT_MAJOR, "blkext"); -#ifndef CONFIG_SYSFS_DEPRECATED /* create top-level block dir */ - block_depr = kobject_create_and_add("block", NULL); -#endif + if (!sysfs_deprecated) + block_depr = kobject_create_and_add("block", NULL); return 0; } diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index ef38aff..fd96345 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 c12c7f2..5f51c3b 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 eb1b7fa..33c270a 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 8e231d0..9c63a56 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 d1b2c9a..2cb49a9 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 933442f..cafeaaf 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 2872e86..ee53558 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 c6c933f..3966e62 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 9354dc1..1667aaf 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 b743312..db2fbe2 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 42eab95..9f2986b 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 69c1f2f..fffc227 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 0000000..744b804 --- /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 1047815..4f7a582 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 3d0a1e6..087821f 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 4d3a6fd..a858d2b 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 85c9884..fc22e1e 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; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 30f46c2..b81bfc0 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -537,14 +537,14 @@ void register_disk(struct gendisk *disk) if (device_add(ddev)) return; -#ifndef CONFIG_SYSFS_DEPRECATED - err = sysfs_create_link(block_depr, &ddev->kobj, - kobject_name(&ddev->kobj)); - if (err) { - device_del(ddev); - return; + if (!sysfs_deprecated) { + err = sysfs_create_link(block_depr, &ddev->kobj, + kobject_name(&ddev->kobj)); + if (err) { + device_del(ddev); + return; + } } -#endif disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); @@ -766,8 +766,7 @@ void del_gendisk(struct gendisk *disk) kobject_put(disk->part0.holder_dir); kobject_put(disk->slave_dir); disk->driverfs_dev = NULL; -#ifndef CONFIG_SYSFS_DEPRECATED - sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); -#endif + if (!sysfs_deprecated) + sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); device_del(disk_to_dev(disk)); } diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 4e321f7..a475983 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -179,30 +179,14 @@ static void bin_vma_open(struct vm_area_struct *vma) struct bin_buffer *bb = file->private_data; struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - if (!bb->vm_ops || !bb->vm_ops->open) - return; - - if (!sysfs_get_active(attr_sd)) - return; - - bb->vm_ops->open(vma); - - sysfs_put_active(attr_sd); -} - -static void bin_vma_close(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct bin_buffer *bb = file->private_data; - struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - - if (!bb->vm_ops || !bb->vm_ops->close) + if (!bb->vm_ops) return; if (!sysfs_get_active(attr_sd)) return; - bb->vm_ops->close(vma); + if (bb->vm_ops->open) + bb->vm_ops->open(vma); sysfs_put_active(attr_sd); } @@ -214,13 +198,15 @@ static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf) struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; int ret; - if (!bb->vm_ops || !bb->vm_ops->fault) + if (!bb->vm_ops) return VM_FAULT_SIGBUS; if (!sysfs_get_active(attr_sd)) return VM_FAULT_SIGBUS; - ret = bb->vm_ops->fault(vma, vmf); + ret = VM_FAULT_SIGBUS; + if (bb->vm_ops->fault) + ret = bb->vm_ops->fault(vma, vmf); sysfs_put_active(attr_sd); return ret; @@ -236,13 +222,12 @@ static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) if (!bb->vm_ops) return VM_FAULT_SIGBUS; - if (!bb->vm_ops->page_mkwrite) - return 0; - if (!sysfs_get_active(attr_sd)) return VM_FAULT_SIGBUS; - ret = bb->vm_ops->page_mkwrite(vma, vmf); + ret = 0; + if (bb->vm_ops->page_mkwrite) + ret = bb->vm_ops->page_mkwrite(vma, vmf); sysfs_put_active(attr_sd); return ret; @@ -256,13 +241,15 @@ static int bin_access(struct vm_area_struct *vma, unsigned long addr, struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; int ret; - if (!bb->vm_ops || !bb->vm_ops->access) + if (!bb->vm_ops) return -EINVAL; if (!sysfs_get_active(attr_sd)) return -EINVAL; - ret = bb->vm_ops->access(vma, addr, buf, len, write); + ret = -EINVAL; + if (bb->vm_ops->access) + ret = bb->vm_ops->access(vma, addr, buf, len, write); sysfs_put_active(attr_sd); return ret; @@ -276,13 +263,15 @@ static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new) struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; int ret; - if (!bb->vm_ops || !bb->vm_ops->set_policy) + if (!bb->vm_ops) return 0; if (!sysfs_get_active(attr_sd)) return -EINVAL; - ret = bb->vm_ops->set_policy(vma, new); + ret = 0; + if (bb->vm_ops->set_policy) + ret = bb->vm_ops->set_policy(vma, new); sysfs_put_active(attr_sd); return ret; @@ -296,13 +285,15 @@ static struct mempolicy *bin_get_policy(struct vm_area_struct *vma, struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; struct mempolicy *pol; - if (!bb->vm_ops || !bb->vm_ops->get_policy) + if (!bb->vm_ops) return vma->vm_policy; if (!sysfs_get_active(attr_sd)) return vma->vm_policy; - pol = bb->vm_ops->get_policy(vma, addr); + pol = vma->vm_policy; + if (bb->vm_ops->get_policy) + pol = bb->vm_ops->get_policy(vma, addr); sysfs_put_active(attr_sd); return pol; @@ -316,13 +307,15 @@ static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; int ret; - if (!bb->vm_ops || !bb->vm_ops->migrate) + if (!bb->vm_ops) return 0; if (!sysfs_get_active(attr_sd)) return 0; - ret = bb->vm_ops->migrate(vma, from, to, flags); + ret = 0; + if (bb->vm_ops->migrate) + ret = bb->vm_ops->migrate(vma, from, to, flags); sysfs_put_active(attr_sd); return ret; @@ -331,7 +324,6 @@ static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from, static const struct vm_operations_struct bin_vm_ops = { .open = bin_vma_open, - .close = bin_vma_close, .fault = bin_fault, .page_mkwrite = bin_page_mkwrite, .access = bin_access, @@ -377,6 +369,14 @@ static int mmap(struct file *file, struct vm_area_struct *vma) if (bb->mmapped && bb->vm_ops != vma->vm_ops) goto out_put; + /* + * It is not possible to successfully wrap close. + * So error if someone is trying to use close. + */ + rc = -EINVAL; + if (vma->vm_ops && vma->vm_ops->close) + goto out_put; + rc = 0; bb->mmapped = 1; bb->vm_ops = vma->vm_ops; diff --git a/include/linux/device.h b/include/linux/device.h index 516feca..dd48953 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -751,4 +751,11 @@ do { \ MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) #define MODULE_ALIAS_CHARDEV_MAJOR(major) \ MODULE_ALIAS("char-major-" __stringify(major) "-*") + +#ifdef CONFIG_SYSFS_DEPRECATED +extern long sysfs_deprecated; +#else +#define sysfs_deprecated 0 +#endif + #endif /* _DEVICE_H_ */ diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 7950a37..8f6d121 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -191,6 +191,8 @@ static inline struct kobj_type *get_ktype(struct kobject *kobj) } extern struct kobject *kset_find_obj(struct kset *, const char *); +extern struct kobject *kset_find_obj_hinted(struct kset *, const char *, + struct kobject *); /* The global /sys/kernel/ kobject for people to chain off of */ extern struct kobject *kernel_kobj; diff --git a/include/linux/memory.h b/include/linux/memory.h index 85582e1..06c1fa0 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -23,6 +23,8 @@ struct memory_block { unsigned long phys_index; unsigned long state; + int section_count; + /* * This serializes all state change requests. It isn't * held during creation because the control files are @@ -113,6 +115,8 @@ extern int memory_dev_init(void); extern int remove_memory_block(unsigned long, struct mem_section *, int); extern int memory_notify(unsigned long val, void *v); extern int memory_isolate_notify(unsigned long val, void *v); +extern struct memory_block *find_memory_block_hinted(struct mem_section *, + struct memory_block *); extern struct memory_block *find_memory_block(struct mem_section *); #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT) enum mem_add_context { BOOT, HOTPLUG }; diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index d7ecad0..2e700ec 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -138,6 +138,9 @@ extern struct platform_device *platform_create_bundle(struct platform_driver *dr struct resource *res, unsigned int n_res, const void *data, size_t size); +extern const struct dev_pm_ops * platform_bus_get_pm_ops(void); +extern void platform_bus_set_pm_ops(const struct dev_pm_ops *pm); + /* early platform driver interface */ struct early_platform_driver { const char *class_str; diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h index 5dcc9ff..d6188e5 100644 --- a/include/linux/uio_driver.h +++ b/include/linux/uio_driver.h @@ -108,7 +108,7 @@ extern void uio_event_notify(struct uio_info *info); /* defines for uio_info->irq */ #define UIO_IRQ_CUSTOM -1 -#define UIO_IRQ_NONE -2 +#define UIO_IRQ_NONE 0 /* defines for uio_mem->memtype */ #define UIO_MEM_NONE 0 diff --git a/include/sound/core.h b/include/sound/core.h index 89e0ac1..df26ebb 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -133,9 +133,7 @@ struct snd_card { int free_on_last_close; /* free in context of file_release */ wait_queue_head_t shutdown_sleep; struct device *dev; /* device assigned to this card */ -#ifndef CONFIG_SYSFS_DEPRECATED struct device *card_dev; /* cardX object for sysfs */ -#endif #ifdef CONFIG_PM unsigned int power_state; /* power state */ @@ -196,11 +194,7 @@ struct snd_minor { /* return a device pointer linked to each sound device as a parent */ static inline struct device *snd_card_get_device_link(struct snd_card *card) { -#ifdef CONFIG_SYSFS_DEPRECATED - return card ? card->dev : NULL; -#else return card ? card->card_dev : NULL; -#endif } /* sound.c */ diff --git a/init/Kconfig b/init/Kconfig index bd125a7..fdfd97e 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -686,40 +686,42 @@ config MM_OWNER bool config SYSFS_DEPRECATED - bool - -config SYSFS_DEPRECATED_V2 bool "enable deprecated sysfs features to support old userspace tools" depends on SYSFS default n - select SYSFS_DEPRECATED - help - This option switches the layout of sysfs to the deprecated - version. Do not use it on recent distributions. - - The current sysfs layout features a unified device tree at - /sys/devices/, which is able to express a hierarchy between - class devices. If the deprecated option is set to Y, the - unified device tree is split into a bus device tree at - /sys/devices/ and several individual class device trees at - /sys/class/. The class and bus devices will be connected by - "<subsystem>:<name>" and the "device" links. The "block" - class devices, will not show up in /sys/class/block/. Some - subsystems will suppress the creation of some devices which - depend on the unified device tree. - - This option is not a pure compatibility option that can - be safely enabled on newer distributions. It will change the - layout of sysfs to the non-extensible deprecated version, - and disable some features, which can not be exported without - confusing older userspace tools. Since 2007/2008 all major - distributions do not enable this option, and ship no tools which - depend on the deprecated layout or this option. - - If you are using a new kernel on an older distribution, or use - older userspace tools, you might need to say Y here. Do not say Y, - if the original kernel, that came with your distribution, has - this option set to N. + help + This option adds code that switches the layout of the "block" class + devices, to not show up in /sys/class/block/, but only in + /sys/block/. + + This switch is only active when the sysfs.deprecated=1 boot option is + passed or the SYSFS_DEPRECATED_V2 option is set. + + This option allows new kernels to run on old distributions and tools, + which might get confused by /sys/class/block/. Since 2007/2008 all + major distributions and tools handle this just fine. + + Recent distributions and userspace tools after 2009/2010 depend on + the existence of /sys/class/block/, and will not work with this + option enabled. + + Only if you are using a new kernel on an old distribution, you might + need to say Y here. + +config SYSFS_DEPRECATED_V2 + bool "enabled deprecated sysfs features by default" + default n + depends on SYSFS + depends on SYSFS_DEPRECATED + help + Enable deprecated sysfs by default. + + See the CONFIG_SYSFS_DEPRECATED option for more details about this + option. + + Only if you are using a new kernel on an old distribution, you might + need to say Y here. Even then, odds are you would not need it + enabled, you can always pass the boot option if absolutely necessary. config RELAY bool "Kernel->user space relay support (formerly relayfs)" diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 7bd6df7..3094318 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -393,6 +393,40 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp, return 0; } +static int ddebug_exec_query(char *query_string) +{ + unsigned int flags = 0, mask = 0; + struct ddebug_query query; +#define MAXWORDS 9 + int nwords; + char *words[MAXWORDS]; + + nwords = ddebug_tokenize(query_string, words, MAXWORDS); + if (nwords <= 0) + return -EINVAL; + if (ddebug_parse_query(words, nwords-1, &query)) + return -EINVAL; + if (ddebug_parse_flags(words[nwords-1], &flags, &mask)) + return -EINVAL; + + /* actually go and implement the change */ + ddebug_change(&query, flags, mask); + return 0; +} + +static __initdata char ddebug_setup_string[1024]; +static __init int ddebug_setup_query(char *str) +{ + if (strlen(str) >= 1024) { + pr_warning("ddebug boot param string too large\n"); + return 0; + } + strcpy(ddebug_setup_string, str); + return 1; +} + +__setup("ddebug_query=", ddebug_setup_query); + /* * File_ops->write method for <debugfs>/dynamic_debug/conrol. Gathers the * command text from userspace, parses and executes it. @@ -400,12 +434,8 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp, static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { - unsigned int flags = 0, mask = 0; - struct ddebug_query query; -#define MAXWORDS 9 - int nwords; - char *words[MAXWORDS]; char tmpbuf[256]; + int ret; if (len == 0) return 0; @@ -419,16 +449,9 @@ static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf, printk(KERN_INFO "%s: read %d bytes from userspace\n", __func__, (int)len); - nwords = ddebug_tokenize(tmpbuf, words, MAXWORDS); - if (nwords <= 0) - return -EINVAL; - if (ddebug_parse_query(words, nwords-1, &query)) - return -EINVAL; - if (ddebug_parse_flags(words[nwords-1], &flags, &mask)) - return -EINVAL; - - /* actually go and implement the change */ - ddebug_change(&query, flags, mask); + ret = ddebug_exec_query(tmpbuf); + if (ret) + return ret; *offp += len; return len; @@ -689,13 +712,14 @@ static void ddebug_remove_all_tables(void) mutex_unlock(&ddebug_lock); } -static int __init dynamic_debug_init(void) +static __initdata int ddebug_init_success; + +static int __init dynamic_debug_init_debugfs(void) { struct dentry *dir, *file; - struct _ddebug *iter, *iter_start; - const char *modname = NULL; - int ret = 0; - int n = 0; + + if (!ddebug_init_success) + return -ENODEV; dir = debugfs_create_dir("dynamic_debug", NULL); if (!dir) @@ -706,6 +730,16 @@ static int __init dynamic_debug_init(void) debugfs_remove(dir); return -ENOMEM; } + return 0; +} + +static int __init dynamic_debug_init(void) +{ + struct _ddebug *iter, *iter_start; + const char *modname = NULL; + int ret = 0; + int n = 0; + if (__start___verbose != __stop___verbose) { iter = __start___verbose; modname = iter->modname; @@ -723,12 +757,26 @@ static int __init dynamic_debug_init(void) } ret = ddebug_add_module(iter_start, n, modname); } + + /* ddebug_query boot param got passed -> set it up */ + if (ddebug_setup_string[0] != '\0') { + ret = ddebug_exec_query(ddebug_setup_string); + if (ret) + pr_warning("Invalid ddebug boot param %s", + ddebug_setup_string); + else + pr_info("ddebug initialized with string %s", + ddebug_setup_string); + } + out_free: - if (ret) { + if (ret) ddebug_remove_all_tables(); - debugfs_remove(dir); - debugfs_remove(file); - } + else + ddebug_init_success = 1; return 0; } -module_init(dynamic_debug_init); +/* Allow early initialization for boot messages via boot param */ +arch_initcall(dynamic_debug_init); +/* Debugfs setup must be done later */ +module_init(dynamic_debug_init_debugfs); diff --git a/lib/kobject.c b/lib/kobject.c index f07c572..82dc34c 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -746,17 +746,56 @@ void kset_unregister(struct kset *k) */ struct kobject *kset_find_obj(struct kset *kset, const char *name) { + return kset_find_obj_hinted(kset, name, NULL); +} + +/** + * kset_find_obj_hinted - search for object in kset given a predecessor hint. + * @kset: kset we're looking in. + * @name: object's name. + * @hint: hint to possible object's predecessor. + * + * Check the hint's next object and if it is a match return it directly, + * otherwise, fall back to the behavior of kset_find_obj(). Either way + * a reference for the returned object is held and the reference on the + * hinted object is released. + */ +struct kobject *kset_find_obj_hinted(struct kset *kset, const char *name, + struct kobject *hint) +{ struct kobject *k; struct kobject *ret = NULL; spin_lock(&kset->list_lock); + + if (!hint) + goto slow_search; + + /* end of list detection */ + if (hint->entry.next == kset->list.next) + goto slow_search; + + k = container_of(hint->entry.next, struct kobject, entry); + if (!kobject_name(k) || strcmp(kobject_name(k), name)) + goto slow_search; + + ret = kobject_get(k); + goto unlock_exit; + +slow_search: list_for_each_entry(k, &kset->list, entry) { if (kobject_name(k) && !strcmp(kobject_name(k), name)) { ret = kobject_get(k); break; } } + +unlock_exit: spin_unlock(&kset->list_lock); + + if (hint) + kobject_put(hint); + return ret; } diff --git a/sound/core/init.c b/sound/core/init.c index ec4a50c..f7c3df8 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -395,12 +395,10 @@ int snd_card_disconnect(struct snd_card *card) snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number); snd_info_card_disconnect(card); -#ifndef CONFIG_SYSFS_DEPRECATED if (card->card_dev) { device_unregister(card->card_dev); card->card_dev = NULL; } -#endif #ifdef CONFIG_PM wake_up(&card->power_sleep); #endif @@ -573,7 +571,6 @@ void snd_card_set_id(struct snd_card *card, const char *nid) } EXPORT_SYMBOL(snd_card_set_id); -#ifndef CONFIG_SYSFS_DEPRECATED static ssize_t card_id_show_attr(struct device *dev, struct device_attribute *attr, char *buf) @@ -630,7 +627,6 @@ card_number_show_attr(struct device *dev, static struct device_attribute card_number_attrs = __ATTR(number, S_IRUGO, card_number_show_attr, NULL); -#endif /* CONFIG_SYSFS_DEPRECATED */ /** * snd_card_register - register the soundcard @@ -649,7 +645,7 @@ int snd_card_register(struct snd_card *card) if (snd_BUG_ON(!card)) return -EINVAL; -#ifndef CONFIG_SYSFS_DEPRECATED + if (!card->card_dev) { card->card_dev = device_create(sound_class, card->dev, MKDEV(0, 0), card, @@ -657,7 +653,7 @@ int snd_card_register(struct snd_card *card) if (IS_ERR(card->card_dev)) card->card_dev = NULL; } -#endif + if ((err = snd_device_register_all(card)) < 0) return err; mutex_lock(&snd_card_mutex); @@ -674,7 +670,6 @@ int snd_card_register(struct snd_card *card) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); #endif -#ifndef CONFIG_SYSFS_DEPRECATED if (card->card_dev) { err = device_create_file(card->card_dev, &card_id_attrs); if (err < 0) @@ -683,7 +678,7 @@ int snd_card_register(struct snd_card *card) if (err < 0) return err; } -#endif + return 0; } |