summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/attribute_container.c2
-rw-r--r--drivers/base/bus.c12
-rw-r--r--drivers/base/core.c152
-rw-r--r--drivers/base/cpu.c46
-rw-r--r--drivers/base/dd.c13
-rw-r--r--drivers/base/firmware_class.c8
-rw-r--r--drivers/base/iommu.c100
-rw-r--r--drivers/base/isa.c7
-rw-r--r--drivers/base/memory.c19
-rw-r--r--drivers/base/node.c107
-rw-r--r--drivers/base/platform.c130
-rw-r--r--drivers/base/power/main.c21
-rw-r--r--drivers/base/power/trace.c4
-rw-r--r--drivers/base/topology.c5
16 files changed, 488 insertions, 141 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index d8e8c49c0cbd..8f006f96ff53 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -54,7 +54,7 @@ config FIRMWARE_IN_KERNEL
such firmware, and do not wish to use an initrd.
This single option controls the inclusion of firmware for
- every driver which uses request_firmare() and ships its
+ every driver which uses request_firmware() and ships its
firmware in the kernel source tree, to avoid a proliferation
of 'Include firmware for xxx device' options.
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index c66637392bbc..b5b8ba512b28 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
obj-$(CONFIG_SMP) += topology.o
+obj-$(CONFIG_IOMMU_API) += iommu.o
ifeq ($(CONFIG_SYSFS),y)
obj-$(CONFIG_MODULES) += module.o
endif
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index f57652db0a2a..b9cda053d3c0 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -167,7 +167,7 @@ attribute_container_add_device(struct device *dev,
ic->classdev.parent = get_device(dev);
ic->classdev.class = cont->class;
cont->class->dev_release = attribute_container_release;
- strcpy(ic->classdev.bus_id, dev->bus_id);
+ dev_set_name(&ic->classdev, dev_name(dev));
if (fn)
fn(cont, dev, &ic->classdev);
else
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 5aee1c0169ea..83f32b891fa9 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -333,7 +333,7 @@ static int match_name(struct device *dev, void *data)
{
const char *name = data;
- return sysfs_streq(name, dev->bus_id);
+ return sysfs_streq(name, dev_name(dev));
}
/**
@@ -461,12 +461,12 @@ int bus_add_device(struct device *dev)
int error = 0;
if (bus) {
- pr_debug("bus: '%s': add device %s\n", bus->name, dev->bus_id);
+ pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
error = device_add_attrs(bus, dev);
if (error)
goto out_put;
error = sysfs_create_link(&bus->p->devices_kset->kobj,
- &dev->kobj, dev->bus_id);
+ &dev->kobj, dev_name(dev));
if (error)
goto out_id;
error = sysfs_create_link(&dev->kobj,
@@ -482,7 +482,7 @@ int bus_add_device(struct device *dev)
out_deprecated:
sysfs_remove_link(&dev->kobj, "subsystem");
out_subsys:
- sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id);
+ sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_id:
device_remove_attrs(bus, dev);
out_put:
@@ -526,13 +526,13 @@ void bus_remove_device(struct device *dev)
sysfs_remove_link(&dev->kobj, "subsystem");
remove_deprecated_bus_links(dev);
sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
- dev->bus_id);
+ dev_name(dev));
device_remove_attrs(dev->bus, dev);
if (klist_node_attached(&dev->knode_bus))
klist_del(&dev->knode_bus);
pr_debug("bus: '%s': remove device %s\n",
- dev->bus->name, dev->bus_id);
+ dev->bus->name, dev_name(dev));
device_release_driver(dev);
bus_put(dev->bus);
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 8c2cc2648f5a..8079afca4972 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -119,7 +119,7 @@ static void device_release(struct kobject *kobj)
else
WARN(1, KERN_ERR "Device '%s' does not have a release() "
"function, it is broken and must be fixed.\n",
- dev->bus_id);
+ dev_name(dev));
}
static struct kobj_type device_ktype = {
@@ -209,7 +209,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
retval = dev->bus->uevent(dev, env);
if (retval)
pr_debug("device: '%s': %s: bus uevent() returned %d\n",
- dev->bus_id, __func__, retval);
+ dev_name(dev), __func__, retval);
}
/* have the class specific function add its stuff */
@@ -217,7 +217,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
retval = dev->class->dev_uevent(dev, env);
if (retval)
pr_debug("device: '%s': %s: class uevent() "
- "returned %d\n", dev->bus_id,
+ "returned %d\n", dev_name(dev),
__func__, retval);
}
@@ -226,7 +226,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
retval = dev->type->uevent(dev, env);
if (retval)
pr_debug("device: '%s': %s: dev_type uevent() "
- "returned %d\n", dev->bus_id,
+ "returned %d\n", dev_name(dev),
__func__, retval);
}
@@ -672,7 +672,7 @@ static int device_add_class_symlinks(struct device *dev)
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->bus_id);
+ &dev->kobj, dev_name(dev));
if (error)
goto out_subsys;
}
@@ -712,11 +712,11 @@ out_busid:
if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
device_is_not_partition(dev))
sysfs_remove_link(&dev->class->p->class_subsys.kobj,
- dev->bus_id);
+ dev_name(dev));
#else
/* link in the class directory pointing to the device */
error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
- &dev->kobj, dev->bus_id);
+ &dev->kobj, dev_name(dev));
if (error)
goto out_subsys;
@@ -729,7 +729,7 @@ out_busid:
return 0;
out_busid:
- sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id);
+ sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
#endif
out_subsys:
@@ -758,12 +758,12 @@ static void device_remove_class_symlinks(struct device *dev)
if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
device_is_not_partition(dev))
sysfs_remove_link(&dev->class->p->class_subsys.kobj,
- dev->bus_id);
+ dev_name(dev));
#else
if (dev->parent && device_is_not_partition(dev))
sysfs_remove_link(&dev->kobj, "device");
- sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id);
+ sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
#endif
sysfs_remove_link(&dev->kobj, "subsystem");
@@ -866,7 +866,7 @@ int device_add(struct device *dev)
if (!strlen(dev->bus_id))
goto done;
- pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
+ pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
parent = get_device(dev->parent);
setup_parent(dev, parent);
@@ -876,7 +876,7 @@ int device_add(struct device *dev)
set_dev_node(dev, dev_to_node(parent));
/* first, register with generic layer. */
- error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
+ error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev_name(dev));
if (error)
goto Error;
@@ -884,11 +884,6 @@ int device_add(struct device *dev)
if (platform_notify)
platform_notify(dev);
- /* notify clients of device entry (new way) */
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_ADD_DEVICE, dev);
-
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
@@ -916,6 +911,14 @@ int device_add(struct device *dev)
if (error)
goto DPMError;
device_pm_add(dev);
+
+ /* Notify clients of device addition. This call must come
+ * after dpm_sysf_add() and before kobject_uevent().
+ */
+ if (dev->bus)
+ blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+ BUS_NOTIFY_ADD_DEVICE, dev);
+
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_attach_device(dev);
if (parent)
@@ -940,9 +943,6 @@ done:
DPMError:
bus_remove_device(dev);
BusError:
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
@@ -1027,6 +1027,12 @@ void device_del(struct device *dev)
struct device *parent = dev->parent;
struct class_interface *class_intf;
+ /* Notify clients of device removal. This call must come
+ * before dpm_sysfs_remove().
+ */
+ if (dev->bus)
+ blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+ BUS_NOTIFY_DEL_DEVICE, dev);
device_pm_remove(dev);
dpm_sysfs_remove(dev);
if (parent)
@@ -1064,9 +1070,6 @@ void device_del(struct device *dev)
*/
if (platform_notify_remove)
platform_notify_remove(dev);
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_DEL_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
cleanup_device_parent(dev);
kobject_del(&dev->kobj);
@@ -1086,7 +1089,7 @@ void device_del(struct device *dev)
*/
void device_unregister(struct device *dev)
{
- pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
+ pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
device_del(dev);
put_device(dev);
}
@@ -1196,10 +1199,101 @@ EXPORT_SYMBOL_GPL(put_device);
EXPORT_SYMBOL_GPL(device_create_file);
EXPORT_SYMBOL_GPL(device_remove_file);
+struct root_device
+{
+ struct device dev;
+ struct module *owner;
+};
+
+#define to_root_device(dev) container_of(dev, struct root_device, dev)
+
+static void root_device_release(struct device *dev)
+{
+ kfree(to_root_device(dev));
+}
+
+/**
+ * __root_device_register - allocate and register a root device
+ * @name: root device name
+ * @owner: owner module of the root device, usually THIS_MODULE
+ *
+ * This function allocates a root device and registers it
+ * using device_register(). In order to free the returned
+ * device, use root_device_unregister().
+ *
+ * Root devices are dummy devices which allow other devices
+ * to be grouped under /sys/devices. Use this function to
+ * allocate a root device and then use it as the parent of
+ * any device which should appear under /sys/devices/{name}
+ *
+ * The /sys/devices/{name} directory will also contain a
+ * 'module' symlink which points to the @owner directory
+ * in sysfs.
+ *
+ * Note: You probably want to use root_device_register().
+ */
+struct device *__root_device_register(const char *name, struct module *owner)
+{
+ struct root_device *root;
+ int err = -ENOMEM;
+
+ root = kzalloc(sizeof(struct root_device), GFP_KERNEL);
+ if (!root)
+ return ERR_PTR(err);
+
+ err = dev_set_name(&root->dev, name);
+ if (err) {
+ kfree(root);
+ return ERR_PTR(err);
+ }
+
+ root->dev.release = root_device_release;
+
+ err = device_register(&root->dev);
+ if (err) {
+ put_device(&root->dev);
+ return ERR_PTR(err);
+ }
+
+#ifdef CONFIG_MODULE /* gotta find a "cleaner" way to do this */
+ if (owner) {
+ struct module_kobject *mk = &owner->mkobj;
+
+ err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module");
+ if (err) {
+ device_unregister(&root->dev);
+ return ERR_PTR(err);
+ }
+ root->owner = owner;
+ }
+#endif
+
+ return &root->dev;
+}
+EXPORT_SYMBOL_GPL(__root_device_register);
+
+/**
+ * root_device_unregister - unregister and free a root device
+ * @root: device going away.
+ *
+ * This function unregisters and cleans up a device that was created by
+ * root_device_register().
+ */
+void root_device_unregister(struct device *dev)
+{
+ struct root_device *root = to_root_device(dev);
+
+ if (root->owner)
+ sysfs_remove_link(&root->dev.kobj, "module");
+
+ device_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(root_device_unregister);
+
static void device_create_release(struct device *dev)
{
- pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
+ pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
kfree(dev);
}
@@ -1344,7 +1438,7 @@ int device_rename(struct device *dev, char *new_name)
if (!dev)
return -EINVAL;
- pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id,
+ pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev),
__func__, new_name);
#ifdef CONFIG_SYSFS_DEPRECATED
@@ -1381,7 +1475,7 @@ int device_rename(struct device *dev, char *new_name)
#else
if (dev->class) {
error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj,
- &dev->kobj, dev->bus_id);
+ &dev->kobj, dev_name(dev));
if (error)
goto out;
sysfs_remove_link(&dev->class->p->class_subsys.kobj,
@@ -1459,8 +1553,8 @@ int device_move(struct device *dev, struct device *new_parent)
new_parent = get_device(new_parent);
new_parent_kobj = get_device_parent(dev, new_parent);
- pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id,
- __func__, new_parent ? new_parent->bus_id : "<NULL>");
+ pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev),
+ __func__, new_parent ? dev_name(new_parent) : "<NULL>");
error = kobject_move(&dev->kobj, new_parent_kobj);
if (error) {
cleanup_glue_dir(dev, new_parent_kobj);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 64f5d54f7edc..719ee5c1c8d9 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -109,7 +109,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
*/
static ssize_t print_cpus_map(char *buf, cpumask_t *map)
{
- int n = cpulist_scnprintf(buf, PAGE_SIZE-2, *map);
+ int n = cpulist_scnprintf(buf, PAGE_SIZE-2, map);
buf[n++] = '\n';
buf[n] = '\0';
@@ -128,10 +128,54 @@ print_cpus_func(online);
print_cpus_func(possible);
print_cpus_func(present);
+/*
+ * Print values for NR_CPUS and offlined cpus
+ */
+static ssize_t print_cpus_kernel_max(struct sysdev_class *class, char *buf)
+{
+ int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1);
+ return n;
+}
+static SYSDEV_CLASS_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
+
+/* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */
+unsigned int total_cpus;
+
+static ssize_t print_cpus_offline(struct sysdev_class *class, char *buf)
+{
+ int n = 0, len = PAGE_SIZE-2;
+ cpumask_var_t offline;
+
+ /* display offline cpus < nr_cpu_ids */
+ if (!alloc_cpumask_var(&offline, GFP_KERNEL))
+ return -ENOMEM;
+ cpumask_complement(offline, cpu_online_mask);
+ n = cpulist_scnprintf(buf, len, offline);
+ free_cpumask_var(offline);
+
+ /* display offline cpus >= nr_cpu_ids */
+ if (total_cpus && nr_cpu_ids < total_cpus) {
+ if (n && n < len)
+ buf[n++] = ',';
+
+ if (nr_cpu_ids == total_cpus-1)
+ n += snprintf(&buf[n], len - n, "%d", nr_cpu_ids);
+ else
+ n += snprintf(&buf[n], len - n, "%d-%d",
+ nr_cpu_ids, total_cpus-1);
+ }
+
+ n += snprintf(&buf[n], len - n, "\n");
+ return n;
+}
+static SYSDEV_CLASS_ATTR(offline, 0444, print_cpus_offline, NULL);
+
static struct sysdev_class_attribute *cpu_state_attr[] = {
&attr_online_map,
&attr_possible_map,
&attr_present_map,
+ &attr_kernel_max,
+ &attr_offline,
};
static int cpu_states_init(void)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 20febc00a525..315bed8d5e7f 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -34,7 +34,7 @@ static void driver_bound(struct device *dev)
return;
}
- pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->bus_id,
+ pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
__func__, dev->driver->name);
if (dev->bus)
@@ -104,13 +104,13 @@ static int really_probe(struct device *dev, struct device_driver *drv)
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
- drv->bus->name, __func__, drv->name, dev->bus_id);
+ drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
- __func__, dev->bus_id);
+ __func__, dev_name(dev));
goto probe_failed;
}
@@ -127,7 +127,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
- drv->bus->name, __func__, dev->bus_id, drv->name);
+ drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;
probe_failed:
@@ -139,7 +139,7 @@ probe_failed:
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
- drv->name, dev->bus_id, ret);
+ drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
@@ -194,7 +194,7 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
goto done;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
- drv->bus->name, __func__, dev->bus_id, drv->name);
+ drv->bus->name, __func__, dev_name(dev), drv->name);
ret = really_probe(dev, drv);
@@ -298,7 +298,6 @@ static void __device_release_driver(struct device *dev)
drv = dev->driver;
if (drv) {
driver_sysfs_remove(dev);
- sysfs_remove_link(&dev->kobj, "driver");
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b7e571031ecd..44699d9dd85c 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -291,12 +291,6 @@ firmware_class_timeout(u_long data)
fw_load_abort(fw_priv);
}
-static inline void fw_setup_device_id(struct device *f_dev, struct device *dev)
-{
- /* XXX warning we should watch out for name collisions */
- strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE);
-}
-
static int fw_register_device(struct device **dev_p, const char *fw_name,
struct device *device)
{
@@ -321,7 +315,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
fw_priv->timeout.data = (u_long) fw_priv;
init_timer(&fw_priv->timeout);
- fw_setup_device_id(f_dev, device);
+ dev_set_name(f_dev, dev_name(device));
f_dev->parent = device;
f_dev->class = &firmware_class;
dev_set_drvdata(f_dev, fw_priv);
diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c
new file mode 100644
index 000000000000..5e039d4f877c
--- /dev/null
+++ b/drivers/base/iommu.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
+ * Author: Joerg Roedel <joerg.roedel@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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/bug.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/iommu.h>
+
+static struct iommu_ops *iommu_ops;
+
+void register_iommu(struct iommu_ops *ops)
+{
+ if (iommu_ops)
+ BUG();
+
+ iommu_ops = ops;
+}
+
+bool iommu_found()
+{
+ return iommu_ops != NULL;
+}
+EXPORT_SYMBOL_GPL(iommu_found);
+
+struct iommu_domain *iommu_domain_alloc(void)
+{
+ struct iommu_domain *domain;
+ int ret;
+
+ domain = kmalloc(sizeof(*domain), GFP_KERNEL);
+ if (!domain)
+ return NULL;
+
+ ret = iommu_ops->domain_init(domain);
+ if (ret)
+ goto out_free;
+
+ return domain;
+
+out_free:
+ kfree(domain);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iommu_domain_alloc);
+
+void iommu_domain_free(struct iommu_domain *domain)
+{
+ iommu_ops->domain_destroy(domain);
+ kfree(domain);
+}
+EXPORT_SYMBOL_GPL(iommu_domain_free);
+
+int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
+{
+ return iommu_ops->attach_dev(domain, dev);
+}
+EXPORT_SYMBOL_GPL(iommu_attach_device);
+
+void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
+{
+ iommu_ops->detach_dev(domain, dev);
+}
+EXPORT_SYMBOL_GPL(iommu_detach_device);
+
+int iommu_map_range(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot)
+{
+ return iommu_ops->map(domain, iova, paddr, size, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);
+
+void iommu_unmap_range(struct iommu_domain *domain, unsigned long iova,
+ size_t size)
+{
+ iommu_ops->unmap(domain, iova, size);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);
+
+phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
+ unsigned long iova)
+{
+ return iommu_ops->iova_to_phys(domain, iova);
+}
+EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
diff --git a/drivers/base/isa.c b/drivers/base/isa.c
index efd577574948..479694b6cbe3 100644
--- a/drivers/base/isa.c
+++ b/drivers/base/isa.c
@@ -11,7 +11,7 @@
#include <linux/isa.h>
static struct device isa_bus = {
- .bus_id = "isa"
+ .init_name = "isa"
};
struct isa_dev {
@@ -135,9 +135,8 @@ int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev)
isa_dev->dev.parent = &isa_bus;
isa_dev->dev.bus = &isa_bus_type;
- snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u",
- isa_driver->driver.name, id);
-
+ dev_set_name(&isa_dev->dev, "%s.%u",
+ isa_driver->driver.name, id);
isa_dev->dev.platform_data = isa_driver;
isa_dev->dev.release = isa_dev_release;
isa_dev->id = id;
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 5260e9e0df48..989429cfed88 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -347,8 +347,9 @@ static inline int memory_probe_init(void)
* section belongs to...
*/
-static int add_memory_block(unsigned long node_id, struct mem_section *section,
- unsigned long state, int phys_device)
+static int add_memory_block(int nid, struct mem_section *section,
+ unsigned long state, int phys_device,
+ enum mem_add_context context)
{
struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL);
int ret = 0;
@@ -370,6 +371,10 @@ static int add_memory_block(unsigned long node_id, struct mem_section *section,
ret = mem_create_simple_file(mem, phys_device);
if (!ret)
ret = mem_create_simple_file(mem, removable);
+ if (!ret) {
+ if (context == HOTPLUG)
+ ret = register_mem_sect_under_node(mem, nid);
+ }
return ret;
}
@@ -382,7 +387,7 @@ static int add_memory_block(unsigned long node_id, struct mem_section *section,
*
* This could be made generic for all sysdev classes.
*/
-static struct memory_block *find_memory_block(struct mem_section *section)
+struct memory_block *find_memory_block(struct mem_section *section)
{
struct kobject *kobj;
struct sys_device *sysdev;
@@ -411,6 +416,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
struct memory_block *mem;
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);
@@ -424,9 +430,9 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
* need an interface for the VM to add new memory regions,
* but without onlining it.
*/
-int register_new_memory(struct mem_section *section)
+int register_new_memory(int nid, struct mem_section *section)
{
- return add_memory_block(0, section, MEM_OFFLINE, 0);
+ return add_memory_block(nid, section, MEM_OFFLINE, 0, HOTPLUG);
}
int unregister_memory_section(struct mem_section *section)
@@ -458,7 +464,8 @@ int __init memory_dev_init(void)
for (i = 0; i < NR_MEM_SECTIONS; i++) {
if (!present_section_nr(i))
continue;
- err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0);
+ err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE,
+ 0, BOOT);
if (!ret)
ret = err;
}
diff --git a/drivers/base/node.c b/drivers/base/node.c
index f5207090885a..43fa90b837ee 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
+#include <linux/memory.h>
#include <linux/node.h>
#include <linux/hugetlb.h>
#include <linux/cpumask.h>
@@ -30,8 +31,8 @@ static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf)
BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1));
len = type?
- cpulist_scnprintf(buf, PAGE_SIZE-2, *mask):
- cpumask_scnprintf(buf, PAGE_SIZE-2, *mask);
+ cpulist_scnprintf(buf, PAGE_SIZE-2, mask) :
+ cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
buf[len++] = '\n';
buf[len] = '\0';
return len;
@@ -248,6 +249,105 @@ int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
return 0;
}
+#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
+#define page_initialized(page) (page->lru.next)
+
+static int get_nid_for_pfn(unsigned long pfn)
+{
+ struct page *page;
+
+ if (!pfn_valid_within(pfn))
+ return -1;
+ page = pfn_to_page(pfn);
+ if (!page_initialized(page))
+ return -1;
+ return pfn_to_nid(pfn);
+}
+
+/* register memory section under specified node if it spans that node */
+int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
+{
+ unsigned long pfn, sect_start_pfn, sect_end_pfn;
+
+ if (!mem_blk)
+ return -EFAULT;
+ if (!node_online(nid))
+ return 0;
+ sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
+ sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
+ for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
+ int page_nid;
+
+ page_nid = get_nid_for_pfn(pfn);
+ if (page_nid < 0)
+ continue;
+ if (page_nid != nid)
+ continue;
+ return sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj,
+ &mem_blk->sysdev.kobj,
+ kobject_name(&mem_blk->sysdev.kobj));
+ }
+ /* mem section does not span the specified node */
+ return 0;
+}
+
+/* unregister memory section under all nodes that it spans */
+int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
+{
+ nodemask_t unlinked_nodes;
+ unsigned long pfn, sect_start_pfn, sect_end_pfn;
+
+ if (!mem_blk)
+ return -EFAULT;
+ nodes_clear(unlinked_nodes);
+ sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
+ sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
+ for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
+ unsigned int nid;
+
+ nid = get_nid_for_pfn(pfn);
+ if (nid < 0)
+ continue;
+ if (!node_online(nid))
+ continue;
+ if (node_test_and_set(nid, unlinked_nodes))
+ continue;
+ sysfs_remove_link(&node_devices[nid].sysdev.kobj,
+ kobject_name(&mem_blk->sysdev.kobj));
+ }
+ return 0;
+}
+
+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;
+ 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);
+ 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);
+ }
+ return err;
+}
+#else
+static int link_mem_sections(int nid) { return 0; }
+#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
+
int register_one_node(int nid)
{
int error = 0;
@@ -267,6 +367,9 @@ int register_one_node(int nid)
if (cpu_to_node(cpu) == nid)
register_cpu_under_node(cpu, nid);
}
+
+ /* link memory sections under this node */
+ error = link_mem_sections(nid);
}
return error;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index dfcbfe504867..349a1013603f 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -24,7 +24,7 @@
driver))
struct device platform_bus = {
- .bus_id = "platform",
+ .init_name = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);
@@ -242,16 +242,15 @@ int platform_device_add(struct platform_device *pdev)
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1)
- snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
- pdev->id);
+ dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
else
- strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
+ dev_set_name(&pdev->dev, pdev->name);
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
- r->name = pdev->dev.bus_id;
+ r->name = dev_name(&pdev->dev);
p = r->parent;
if (!p) {
@@ -264,14 +263,14 @@ int platform_device_add(struct platform_device *pdev)
if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
- pdev->dev.bus_id, i);
+ dev_name(&pdev->dev), i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
- pdev->dev.bus_id, pdev->dev.parent->bus_id);
+ dev_name(&pdev->dev), dev_name(pdev->dev.parent));
ret = device_add(&pdev->dev);
if (ret == 0)
@@ -503,8 +502,6 @@ int platform_driver_register(struct platform_driver *drv)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
- if (drv->pm)
- drv->driver.pm = &drv->pm->base;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_register);
@@ -609,7 +606,7 @@ static int platform_match(struct device *dev, struct device_driver *drv)
struct platform_device *pdev;
pdev = container_of(dev, struct platform_device, dev);
- return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
+ return (strcmp(pdev->name, drv->name) == 0);
}
#ifdef CONFIG_PM_SLEEP
@@ -686,7 +683,10 @@ static int platform_pm_suspend(struct device *dev)
struct device_driver *drv = dev->driver;
int ret = 0;
- if (drv && drv->pm) {
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
if (drv->pm->suspend)
ret = drv->pm->suspend(dev);
} else {
@@ -698,16 +698,15 @@ static int platform_pm_suspend(struct device *dev)
static int platform_pm_suspend_noirq(struct device *dev)
{
- struct platform_driver *pdrv;
+ struct device_driver *drv = dev->driver;
int ret = 0;
- if (!dev->driver)
+ if (!drv)
return 0;
- pdrv = to_platform_driver(dev->driver);
- if (pdrv->pm) {
- if (pdrv->pm->suspend_noirq)
- ret = pdrv->pm->suspend_noirq(dev);
+ if (drv->pm) {
+ if (drv->pm->suspend_noirq)
+ ret = drv->pm->suspend_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND);
}
@@ -720,7 +719,10 @@ static int platform_pm_resume(struct device *dev)
struct device_driver *drv = dev->driver;
int ret = 0;
- if (drv && drv->pm) {
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
if (drv->pm->resume)
ret = drv->pm->resume(dev);
} else {
@@ -732,16 +734,15 @@ static int platform_pm_resume(struct device *dev)
static int platform_pm_resume_noirq(struct device *dev)
{
- struct platform_driver *pdrv;
+ struct device_driver *drv = dev->driver;
int ret = 0;
- if (!dev->driver)
+ if (!drv)
return 0;
- pdrv = to_platform_driver(dev->driver);
- if (pdrv->pm) {
- if (pdrv->pm->resume_noirq)
- ret = pdrv->pm->resume_noirq(dev);
+ if (drv->pm) {
+ if (drv->pm->resume_noirq)
+ ret = drv->pm->resume_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
}
@@ -780,16 +781,15 @@ static int platform_pm_freeze(struct device *dev)
static int platform_pm_freeze_noirq(struct device *dev)
{
- struct platform_driver *pdrv;
+ struct device_driver *drv = dev->driver;
int ret = 0;
- if (!dev->driver)
+ if (!drv)
return 0;
- pdrv = to_platform_driver(dev->driver);
- if (pdrv->pm) {
- if (pdrv->pm->freeze_noirq)
- ret = pdrv->pm->freeze_noirq(dev);
+ if (drv->pm) {
+ if (drv->pm->freeze_noirq)
+ ret = drv->pm->freeze_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_FREEZE);
}
@@ -802,7 +802,10 @@ static int platform_pm_thaw(struct device *dev)
struct device_driver *drv = dev->driver;
int ret = 0;
- if (drv && drv->pm) {
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
if (drv->pm->thaw)
ret = drv->pm->thaw(dev);
} else {
@@ -814,16 +817,15 @@ static int platform_pm_thaw(struct device *dev)
static int platform_pm_thaw_noirq(struct device *dev)
{
- struct platform_driver *pdrv;
+ struct device_driver *drv = dev->driver;
int ret = 0;
- if (!dev->driver)
+ if (!drv)
return 0;
- pdrv = to_platform_driver(dev->driver);
- if (pdrv->pm) {
- if (pdrv->pm->thaw_noirq)
- ret = pdrv->pm->thaw_noirq(dev);
+ if (drv->pm) {
+ if (drv->pm->thaw_noirq)
+ ret = drv->pm->thaw_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
}
@@ -836,7 +838,10 @@ static int platform_pm_poweroff(struct device *dev)
struct device_driver *drv = dev->driver;
int ret = 0;
- if (drv && drv->pm) {
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
if (drv->pm->poweroff)
ret = drv->pm->poweroff(dev);
} else {
@@ -848,16 +853,15 @@ static int platform_pm_poweroff(struct device *dev)
static int platform_pm_poweroff_noirq(struct device *dev)
{
- struct platform_driver *pdrv;
+ struct device_driver *drv = dev->driver;
int ret = 0;
- if (!dev->driver)
+ if (!drv)
return 0;
- pdrv = to_platform_driver(dev->driver);
- if (pdrv->pm) {
- if (pdrv->pm->poweroff_noirq)
- ret = pdrv->pm->poweroff_noirq(dev);
+ if (drv->pm) {
+ if (drv->pm->poweroff_noirq)
+ ret = drv->pm->poweroff_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE);
}
@@ -870,7 +874,10 @@ static int platform_pm_restore(struct device *dev)
struct device_driver *drv = dev->driver;
int ret = 0;
- if (drv && drv->pm) {
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
if (drv->pm->restore)
ret = drv->pm->restore(dev);
} else {
@@ -882,16 +889,15 @@ static int platform_pm_restore(struct device *dev)
static int platform_pm_restore_noirq(struct device *dev)
{
- struct platform_driver *pdrv;
+ struct device_driver *drv = dev->driver;
int ret = 0;
- if (!dev->driver)
+ if (!drv)
return 0;
- pdrv = to_platform_driver(dev->driver);
- if (pdrv->pm) {
- if (pdrv->pm->restore_noirq)
- ret = pdrv->pm->restore_noirq(dev);
+ if (drv->pm) {
+ if (drv->pm->restore_noirq)
+ ret = drv->pm->restore_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
}
@@ -912,17 +918,15 @@ static int platform_pm_restore_noirq(struct device *dev)
#endif /* !CONFIG_HIBERNATION */
-static struct pm_ext_ops platform_pm_ops = {
- .base = {
- .prepare = platform_pm_prepare,
- .complete = platform_pm_complete,
- .suspend = platform_pm_suspend,
- .resume = platform_pm_resume,
- .freeze = platform_pm_freeze,
- .thaw = platform_pm_thaw,
- .poweroff = platform_pm_poweroff,
- .restore = platform_pm_restore,
- },
+static struct dev_pm_ops platform_dev_pm_ops = {
+ .prepare = platform_pm_prepare,
+ .complete = platform_pm_complete,
+ .suspend = platform_pm_suspend,
+ .resume = platform_pm_resume,
+ .freeze = platform_pm_freeze,
+ .thaw = platform_pm_thaw,
+ .poweroff = platform_pm_poweroff,
+ .restore = platform_pm_restore,
.suspend_noirq = platform_pm_suspend_noirq,
.resume_noirq = platform_pm_resume_noirq,
.freeze_noirq = platform_pm_freeze_noirq,
@@ -931,7 +935,7 @@ static struct pm_ext_ops platform_pm_ops = {
.restore_noirq = platform_pm_restore_noirq,
};
-#define PLATFORM_PM_OPS_PTR &platform_pm_ops
+#define PLATFORM_PM_OPS_PTR (&platform_dev_pm_ops)
#else /* !CONFIG_PM_SLEEP */
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 692c20ba5144..670c9d6c1407 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -76,7 +76,7 @@ void device_pm_add(struct device *dev)
if (dev->parent) {
if (dev->parent->power.status >= DPM_SUSPENDING)
dev_warn(dev, "parent %s should not be sleeping\n",
- dev->parent->bus_id);
+ dev_name(dev->parent));
} else if (transition_started) {
/*
* We refuse to register parentless devices while a PM
@@ -112,7 +112,8 @@ void device_pm_remove(struct device *dev)
* @ops: PM operations to choose from.
* @state: PM transition of the system being carried out.
*/
-static int pm_op(struct device *dev, struct pm_ops *ops, pm_message_t state)
+static int pm_op(struct device *dev, struct dev_pm_ops *ops,
+ pm_message_t state)
{
int error = 0;
@@ -174,7 +175,7 @@ static int pm_op(struct device *dev, struct pm_ops *ops, pm_message_t state)
* The operation is executed with interrupts disabled by the only remaining
* functional CPU in the system.
*/
-static int pm_noirq_op(struct device *dev, struct pm_ext_ops *ops,
+static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops,
pm_message_t state)
{
int error = 0;
@@ -354,7 +355,7 @@ static int resume_device(struct device *dev, pm_message_t state)
if (dev->bus) {
if (dev->bus->pm) {
pm_dev_dbg(dev, state, "");
- error = pm_op(dev, &dev->bus->pm->base, state);
+ error = pm_op(dev, dev->bus->pm, state);
} else if (dev->bus->resume) {
pm_dev_dbg(dev, state, "legacy ");
error = dev->bus->resume(dev);
@@ -451,9 +452,9 @@ static void complete_device(struct device *dev, pm_message_t state)
dev->type->pm->complete(dev);
}
- if (dev->bus && dev->bus->pm && dev->bus->pm->base.complete) {
+ if (dev->bus && dev->bus->pm && dev->bus->pm->complete) {
pm_dev_dbg(dev, state, "completing ");
- dev->bus->pm->base.complete(dev);
+ dev->bus->pm->complete(dev);
}
up(&dev->sem);
@@ -624,7 +625,7 @@ static int suspend_device(struct device *dev, pm_message_t state)
if (dev->bus) {
if (dev->bus->pm) {
pm_dev_dbg(dev, state, "");
- error = pm_op(dev, &dev->bus->pm->base, state);
+ error = pm_op(dev, dev->bus->pm, state);
} else if (dev->bus->suspend) {
pm_dev_dbg(dev, state, "legacy ");
error = dev->bus->suspend(dev, state);
@@ -685,10 +686,10 @@ static int prepare_device(struct device *dev, pm_message_t state)
down(&dev->sem);
- if (dev->bus && dev->bus->pm && dev->bus->pm->base.prepare) {
+ if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) {
pm_dev_dbg(dev, state, "preparing ");
- error = dev->bus->pm->base.prepare(dev);
- suspend_report_result(dev->bus->pm->base.prepare, error);
+ error = dev->bus->pm->prepare(dev);
+ suspend_report_result(dev->bus->pm->prepare, error);
if (error)
goto End;
}
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index 2aa6e8fc4def..0a1a2c4dbc6e 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -140,7 +140,7 @@ static unsigned int hash_string(unsigned int seed, const char *data, unsigned in
void set_trace_device(struct device *dev)
{
- dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
+ dev_hash_value = hash_string(DEVSEED, dev_name(dev), DEVHASH);
}
EXPORT_SYMBOL(set_trace_device);
@@ -192,7 +192,7 @@ static int show_dev_hash(unsigned int value)
while (entry != &dpm_list) {
struct device * dev = to_device(entry);
- unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH);
+ unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH);
if (hash == value) {
dev_info(dev, "hash matches\n");
match++;
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 199cd97e32e6..a778fb52b11f 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/cpu.h>
#include <linux/module.h>
+#include <linux/hardirq.h>
#include <linux/topology.h>
#define define_one_ro(_name) \
@@ -49,8 +50,8 @@ static ssize_t show_cpumap(int type, cpumask_t *mask, char *buf)
if (len > 1) {
n = type?
- cpulist_scnprintf(buf, len-2, *mask):
- cpumask_scnprintf(buf, len-2, *mask);
+ cpulist_scnprintf(buf, len-2, mask) :
+ cpumask_scnprintf(buf, len-2, mask);
buf[n++] = '\n';
buf[n] = '\0';
}