Commit 55347cc9 authored by Joachim Fenkes's avatar Joachim Fenkes Committed by Paul Mackerras

[POWERPC] ibmebus: Add device creation and bus probing based on of_device

The devtree root is now searched for devices matching a built-in whitelist
during boot, so these devices appear on the bus from the beginning.  It is
still possible to manually add/remove devices to/from the bus by using the
probe/remove sysfs interface.  Also, when a device driver registers itself,
the devtree is matched against its matchlist.
Signed-off-by: default avatarJoachim Fenkes <fenkes@de.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent a988c0a6
...@@ -51,6 +51,13 @@ static struct device ibmebus_bus_device = { /* fake "parent" device */ ...@@ -51,6 +51,13 @@ static struct device ibmebus_bus_device = { /* fake "parent" device */
struct bus_type ibmebus_bus_type; struct bus_type ibmebus_bus_type;
/* These devices will automatically be added to the bus during init */
static struct of_device_id builtin_matches[] = {
{ .compatible = "IBM,lhca" },
{ .compatible = "IBM,lhea" },
{},
};
static void *ibmebus_alloc_coherent(struct device *dev, static void *ibmebus_alloc_coherent(struct device *dev,
size_t size, size_t size,
dma_addr_t *dma_handle, dma_addr_t *dma_handle,
...@@ -125,6 +132,67 @@ static struct dma_mapping_ops ibmebus_dma_ops = { ...@@ -125,6 +132,67 @@ static struct dma_mapping_ops ibmebus_dma_ops = {
.dma_supported = ibmebus_dma_supported, .dma_supported = ibmebus_dma_supported,
}; };
static int ibmebus_match_path(struct device *dev, void *data)
{
struct device_node *dn = to_of_device(dev)->node;
return (dn->full_name &&
(strcasecmp((char *)data, dn->full_name) == 0));
}
static int ibmebus_match_node(struct device *dev, void *data)
{
return to_of_device(dev)->node == data;
}
static int ibmebus_create_device(struct device_node *dn)
{
struct of_device *dev;
int ret;
dev = of_device_alloc(dn, NULL, &ibmebus_bus_device);
if (!dev)
return -ENOMEM;
dev->dev.bus = &ibmebus_bus_type;
dev->dev.archdata.dma_ops = &ibmebus_dma_ops;
ret = of_device_register(dev);
if (ret) {
of_device_free(dev);
return ret;
}
return 0;
}
static int ibmebus_create_devices(const struct of_device_id *matches)
{
struct device_node *root, *child;
int ret = 0;
root = of_find_node_by_path("/");
for (child = NULL; (child = of_get_next_child(root, child)); ) {
if (!of_match_node(matches, child))
continue;
if (bus_find_device(&ibmebus_bus_type, NULL, child,
ibmebus_match_node))
continue;
ret = ibmebus_create_device(child);
if (ret) {
printk(KERN_ERR "%s: failed to create device (%i)",
__FUNCTION__, ret);
of_node_put(child);
break;
}
}
of_node_put(root);
return ret;
}
int ibmebus_register_driver(struct ibmebus_driver *drv) int ibmebus_register_driver(struct ibmebus_driver *drv)
{ {
return 0; return 0;
...@@ -173,18 +241,6 @@ static struct device_attribute ibmebus_dev_attrs[] = { ...@@ -173,18 +241,6 @@ static struct device_attribute ibmebus_dev_attrs[] = {
__ATTR_NULL __ATTR_NULL
}; };
static int ibmebus_match_path(struct device *dev, void *data)
{
int rc;
struct device_node *dn =
of_node_get(to_ibmebus_dev(dev)->ofdev.node);
rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0));
of_node_put(dn);
return rc;
}
static char *ibmebus_chomp(const char *in, size_t count) static char *ibmebus_chomp(const char *in, size_t count)
{ {
char *out = kmalloc(count + 1, GFP_KERNEL); char *out = kmalloc(count + 1, GFP_KERNEL);
...@@ -204,9 +260,8 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus, ...@@ -204,9 +260,8 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct device_node *dn = NULL; struct device_node *dn = NULL;
struct ibmebus_dev *dev;
char *path; char *path;
ssize_t rc; ssize_t rc = 0;
path = ibmebus_chomp(buf, count); path = ibmebus_chomp(buf, count);
if (!path) if (!path)
...@@ -221,9 +276,8 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus, ...@@ -221,9 +276,8 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus,
} }
if ((dn = of_find_node_by_path(path))) { if ((dn = of_find_node_by_path(path))) {
/* dev = ibmebus_register_device_node(dn); */ rc = ibmebus_create_device(dn);
of_node_put(dn); of_node_put(dn);
rc = IS_ERR(dev) ? PTR_ERR(dev) : count;
} else { } else {
printk(KERN_WARNING "%s: no such device node: %s\n", printk(KERN_WARNING "%s: no such device node: %s\n",
__FUNCTION__, path); __FUNCTION__, path);
...@@ -232,7 +286,9 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus, ...@@ -232,7 +286,9 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus,
out: out:
kfree(path); kfree(path);
if (rc)
return rc; return rc;
return count;
} }
static ssize_t ibmebus_store_remove(struct bus_type *bus, static ssize_t ibmebus_store_remove(struct bus_type *bus,
...@@ -247,7 +303,7 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus, ...@@ -247,7 +303,7 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus,
if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path, if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
ibmebus_match_path))) { ibmebus_match_path))) {
/* ibmebus_unregister_device(dev); */ of_device_unregister(to_of_device(dev));
kfree(path); kfree(path);
return count; return count;
...@@ -267,6 +323,7 @@ static struct bus_attribute ibmebus_bus_attrs[] = { ...@@ -267,6 +323,7 @@ static struct bus_attribute ibmebus_bus_attrs[] = {
}; };
struct bus_type ibmebus_bus_type = { struct bus_type ibmebus_bus_type = {
.uevent = of_device_uevent,
.dev_attrs = ibmebus_dev_attrs, .dev_attrs = ibmebus_dev_attrs,
.bus_attrs = ibmebus_bus_attrs .bus_attrs = ibmebus_bus_attrs
}; };
...@@ -294,6 +351,13 @@ static int __init ibmebus_bus_init(void) ...@@ -294,6 +351,13 @@ static int __init ibmebus_bus_init(void)
return err; return err;
} }
err = ibmebus_create_devices(builtin_matches);
if (err) {
device_unregister(&ibmebus_bus_device);
bus_unregister(&ibmebus_bus_type);
return err;
}
return 0; return 0;
} }
postcore_initcall(ibmebus_bus_init); postcore_initcall(ibmebus_bus_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment