aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-11-11 01:24:59 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-04 00:08:52 -0500
commit7eebde700fe6fd6573e80bd8e5ed82b4ae705575 (patch)
tree552f1fd982372a704f2fdf9e4dc59ca9a7caef2a /arch/powerpc
parent21fb5a1d9f554970c680b801ba32184bc7c34aa0 (diff)
[POWERPC] Souped-up of_platform_device support
This patch first splits of_device.c and of_platform.c, the later containing the bits relative to of_platform_device's. On the "breaks" side of things, drivers uisng of_platform_device(s) need to include asm/of_platform.h now and of_(un)register_driver is now of_(un)register_platform_driver. In addition to a few utility functions to locate of_platform_device(s), the main new addition is of_platform_bus_probe() which allows the platform code to trigger an automatic creation of of_platform_devices for a whole tree of devices. The function acts based on the type of the various "parent" devices encountered from a provided root, using either a default known list of bus types that can be "probed" or a passed-in list. It will only register devices on busses matching that list, which mean that typically, it will not register PCI devices, as expected (since they will be picked up by the PCI layer). This will be used by Cell platforms using 4xx-type IOs in the Axon bridge and can be used by any embedded-type device as well. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/Makefile2
-rw-r--r--arch/powerpc/kernel/of_device.c172
-rw-r--r--arch/powerpc/kernel/of_platform.c372
-rw-r--r--arch/powerpc/platforms/powermac/setup.c1
4 files changed, 401 insertions, 146 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index f34d158b9628..04fdbe568d7b 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -21,7 +21,7 @@ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
21obj-$(CONFIG_PPC64) += vdso64/ 21obj-$(CONFIG_PPC64) += vdso64/
22obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o 22obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
23obj-$(CONFIG_PPC_970_NAP) += idle_power4.o 23obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
24obj-$(CONFIG_PPC_OF) += of_device.o prom_parse.o 24obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o
25procfs-$(CONFIG_PPC64) := proc_ppc64.o 25procfs-$(CONFIG_PPC64) := proc_ppc64.o
26obj-$(CONFIG_PROC_FS) += $(procfs-y) 26obj-$(CONFIG_PROC_FS) += $(procfs-y)
27rtaspci-$(CONFIG_PPC64) := rtas_pci.o 27rtaspci-$(CONFIG_PPC64) := rtas_pci.o
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index 397c83eda20e..5c653986afa4 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -9,30 +9,26 @@
9#include <asm/of_device.h> 9#include <asm/of_device.h>
10 10
11/** 11/**
12 * of_match_device - Tell if an of_device structure has a matching 12 * of_match_node - Tell if an device_node has a matching of_match structure
13 * of_match structure
14 * @ids: array of of device match structures to search in 13 * @ids: array of of device match structures to search in
15 * @dev: the of device structure to match against 14 * @node: the of device structure to match against
16 * 15 *
17 * Used by a driver to check whether an of_device present in the 16 * Low level utility function used by device matching.
18 * system is in its list of supported devices.
19 */ 17 */
20const struct of_device_id *of_match_device(const struct of_device_id *matches, 18const struct of_device_id *of_match_node(const struct of_device_id *matches,
21 const struct of_device *dev) 19 const struct device_node *node)
22{ 20{
23 if (!dev->node)
24 return NULL;
25 while (matches->name[0] || matches->type[0] || matches->compatible[0]) { 21 while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
26 int match = 1; 22 int match = 1;
27 if (matches->name[0]) 23 if (matches->name[0])
28 match &= dev->node->name 24 match &= node->name
29 && !strcmp(matches->name, dev->node->name); 25 && !strcmp(matches->name, node->name);
30 if (matches->type[0]) 26 if (matches->type[0])
31 match &= dev->node->type 27 match &= node->type
32 && !strcmp(matches->type, dev->node->type); 28 && !strcmp(matches->type, node->type);
33 if (matches->compatible[0]) 29 if (matches->compatible[0])
34 match &= device_is_compatible(dev->node, 30 match &= device_is_compatible(node,
35 matches->compatible); 31 matches->compatible);
36 if (match) 32 if (match)
37 return matches; 33 return matches;
38 matches++; 34 matches++;
@@ -40,16 +36,21 @@ const struct of_device_id *of_match_device(const struct of_device_id *matches,
40 return NULL; 36 return NULL;
41} 37}
42 38
43static int of_platform_bus_match(struct device *dev, struct device_driver *drv) 39/**
40 * of_match_device - Tell if an of_device structure has a matching
41 * of_match structure
42 * @ids: array of of device match structures to search in
43 * @dev: the of device structure to match against
44 *
45 * Used by a driver to check whether an of_device present in the
46 * system is in its list of supported devices.
47 */
48const struct of_device_id *of_match_device(const struct of_device_id *matches,
49 const struct of_device *dev)
44{ 50{
45 struct of_device * of_dev = to_of_device(dev); 51 if (!dev->node)
46 struct of_platform_driver * of_drv = to_of_platform_driver(drv); 52 return NULL;
47 const struct of_device_id * matches = of_drv->match_table; 53 return of_match_node(matches, dev->node);
48
49 if (!matches)
50 return 0;
51
52 return of_match_device(matches, of_dev) != NULL;
53} 54}
54 55
55struct of_device *of_dev_get(struct of_device *dev) 56struct of_device *of_dev_get(struct of_device *dev)
@@ -71,96 +72,8 @@ void of_dev_put(struct of_device *dev)
71 put_device(&dev->dev); 72 put_device(&dev->dev);
72} 73}
73 74
74 75static ssize_t dev_show_devspec(struct device *dev,
75static int of_device_probe(struct device *dev) 76 struct device_attribute *attr, char *buf)
76{
77 int error = -ENODEV;
78 struct of_platform_driver *drv;
79 struct of_device *of_dev;
80 const struct of_device_id *match;
81
82 drv = to_of_platform_driver(dev->driver);
83 of_dev = to_of_device(dev);
84
85 if (!drv->probe)
86 return error;
87
88 of_dev_get(of_dev);
89
90 match = of_match_device(drv->match_table, of_dev);
91 if (match)
92 error = drv->probe(of_dev, match);
93 if (error)
94 of_dev_put(of_dev);
95
96 return error;
97}
98
99static int of_device_remove(struct device *dev)
100{
101 struct of_device * of_dev = to_of_device(dev);
102 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
103
104 if (dev->driver && drv->remove)
105 drv->remove(of_dev);
106 return 0;
107}
108
109static int of_device_suspend(struct device *dev, pm_message_t state)
110{
111 struct of_device * of_dev = to_of_device(dev);
112 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
113 int error = 0;
114
115 if (dev->driver && drv->suspend)
116 error = drv->suspend(of_dev, state);
117 return error;
118}
119
120static int of_device_resume(struct device * dev)
121{
122 struct of_device * of_dev = to_of_device(dev);
123 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
124 int error = 0;
125
126 if (dev->driver && drv->resume)
127 error = drv->resume(of_dev);
128 return error;
129}
130
131struct bus_type of_platform_bus_type = {
132 .name = "of_platform",
133 .match = of_platform_bus_match,
134 .probe = of_device_probe,
135 .remove = of_device_remove,
136 .suspend = of_device_suspend,
137 .resume = of_device_resume,
138};
139
140static int __init of_bus_driver_init(void)
141{
142 return bus_register(&of_platform_bus_type);
143}
144
145postcore_initcall(of_bus_driver_init);
146
147int of_register_driver(struct of_platform_driver *drv)
148{
149 /* initialize common driver fields */
150 drv->driver.name = drv->name;
151 drv->driver.bus = &of_platform_bus_type;
152
153 /* register with core */
154 return driver_register(&drv->driver);
155}
156
157void of_unregister_driver(struct of_platform_driver *drv)
158{
159 driver_unregister(&drv->driver);
160}
161
162
163static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
164{ 77{
165 struct of_device *ofdev; 78 struct of_device *ofdev;
166 79
@@ -208,41 +121,10 @@ void of_device_unregister(struct of_device *ofdev)
208 device_unregister(&ofdev->dev); 121 device_unregister(&ofdev->dev);
209} 122}
210 123
211struct of_device* of_platform_device_create(struct device_node *np,
212 const char *bus_id,
213 struct device *parent)
214{
215 struct of_device *dev;
216
217 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
218 if (!dev)
219 return NULL;
220 memset(dev, 0, sizeof(*dev));
221
222 dev->node = of_node_get(np);
223 dev->dma_mask = 0xffffffffUL;
224 dev->dev.dma_mask = &dev->dma_mask;
225 dev->dev.parent = parent;
226 dev->dev.bus = &of_platform_bus_type;
227 dev->dev.release = of_release_dev;
228
229 strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
230
231 if (of_device_register(dev) != 0) {
232 kfree(dev);
233 return NULL;
234 }
235
236 return dev;
237}
238 124
239EXPORT_SYMBOL(of_match_device); 125EXPORT_SYMBOL(of_match_device);
240EXPORT_SYMBOL(of_platform_bus_type);
241EXPORT_SYMBOL(of_register_driver);
242EXPORT_SYMBOL(of_unregister_driver);
243EXPORT_SYMBOL(of_device_register); 126EXPORT_SYMBOL(of_device_register);
244EXPORT_SYMBOL(of_device_unregister); 127EXPORT_SYMBOL(of_device_unregister);
245EXPORT_SYMBOL(of_dev_get); 128EXPORT_SYMBOL(of_dev_get);
246EXPORT_SYMBOL(of_dev_put); 129EXPORT_SYMBOL(of_dev_put);
247EXPORT_SYMBOL(of_platform_device_create);
248EXPORT_SYMBOL(of_release_dev); 130EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
new file mode 100644
index 000000000000..25850ade8e68
--- /dev/null
+++ b/arch/powerpc/kernel/of_platform.c
@@ -0,0 +1,372 @@
1/*
2 * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
3 * <benh@kernel.crashing.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 */
11
12#undef DEBUG
13
14#include <linux/string.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/mod_devicetable.h>
19#include <linux/slab.h>
20
21#include <asm/errno.h>
22#include <asm/dcr.h>
23#include <asm/of_device.h>
24#include <asm/of_platform.h>
25
26
27/*
28 * The list of OF IDs below is used for matching bus types in the
29 * system whose devices are to be exposed as of_platform_devices.
30 *
31 * This is the default list valid for most platforms. This file provides
32 * functions who can take an explicit list if necessary though
33 *
34 * The search is always performed recursively looking for children of
35 * the provided device_node and recursively if such a children matches
36 * a bus type in the list
37 */
38
39static struct of_device_id of_default_bus_ids[] = {
40 { .type = "soc", },
41 { .compatible = "soc", },
42 { .type = "spider", },
43 { .type = "axon", },
44 { .type = "plb5", },
45 { .type = "plb4", },
46 { .type = "opb", },
47 {},
48};
49
50/*
51 *
52 * OF platform device type definition & base infrastructure
53 *
54 */
55
56static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
57{
58 struct of_device * of_dev = to_of_device(dev);
59 struct of_platform_driver * of_drv = to_of_platform_driver(drv);
60 const struct of_device_id * matches = of_drv->match_table;
61
62 if (!matches)
63 return 0;
64
65 return of_match_device(matches, of_dev) != NULL;
66}
67
68static int of_platform_device_probe(struct device *dev)
69{
70 int error = -ENODEV;
71 struct of_platform_driver *drv;
72 struct of_device *of_dev;
73 const struct of_device_id *match;
74
75 drv = to_of_platform_driver(dev->driver);
76 of_dev = to_of_device(dev);
77
78 if (!drv->probe)
79 return error;
80
81 of_dev_get(of_dev);
82
83 match = of_match_device(drv->match_table, of_dev);
84 if (match)
85 error = drv->probe(of_dev, match);
86 if (error)
87 of_dev_put(of_dev);
88
89 return error;
90}
91
92static int of_platform_device_remove(struct device *dev)
93{
94 struct of_device * of_dev = to_of_device(dev);
95 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
96
97 if (dev->driver && drv->remove)
98 drv->remove(of_dev);
99 return 0;
100}
101
102static int of_platform_device_suspend(struct device *dev, pm_message_t state)
103{
104 struct of_device * of_dev = to_of_device(dev);
105 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
106 int error = 0;
107
108 if (dev->driver && drv->suspend)
109 error = drv->suspend(of_dev, state);
110 return error;
111}
112
113static int of_platform_device_resume(struct device * dev)
114{
115 struct of_device * of_dev = to_of_device(dev);
116 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
117 int error = 0;
118
119 if (dev->driver && drv->resume)
120 error = drv->resume(of_dev);
121 return error;
122}
123
124struct bus_type of_platform_bus_type = {
125 .name = "of_platform",
126 .match = of_platform_bus_match,
127 .probe = of_platform_device_probe,
128 .remove = of_platform_device_remove,
129 .suspend = of_platform_device_suspend,
130 .resume = of_platform_device_resume,
131};
132EXPORT_SYMBOL(of_platform_bus_type);
133
134static int __init of_bus_driver_init(void)
135{
136 return bus_register(&of_platform_bus_type);
137}
138
139postcore_initcall(of_bus_driver_init);
140
141int of_register_platform_driver(struct of_platform_driver *drv)
142{
143 /* initialize common driver fields */
144 drv->driver.name = drv->name;
145 drv->driver.bus = &of_platform_bus_type;
146
147 /* register with core */
148 return driver_register(&drv->driver);
149}
150EXPORT_SYMBOL(of_register_platform_driver);
151
152void of_unregister_platform_driver(struct of_platform_driver *drv)
153{
154 driver_unregister(&drv->driver);
155}
156EXPORT_SYMBOL(of_unregister_platform_driver);
157
158static void of_platform_make_bus_id(struct of_device *dev)
159{
160 struct device_node *node = dev->node;
161 char *name = dev->dev.bus_id;
162 const u32 *reg;
163 u64 addr;
164
165 /*
166 * If it's a DCR based device, use 'd' for native DCRs
167 * and 'D' for MMIO DCRs.
168 */
169#ifdef CONFIG_PPC_DCR
170 reg = get_property(node, "dcr-reg", NULL);
171 if (reg) {
172#ifdef CONFIG_PPC_DCR_NATIVE
173 snprintf(name, BUS_ID_SIZE, "d%x.%s",
174 *reg, node->name);
175#else /* CONFIG_PPC_DCR_NATIVE */
176 addr = of_translate_dcr_address(node, *reg, NULL);
177 if (addr != OF_BAD_ADDR) {
178 snprintf(name, BUS_ID_SIZE,
179 "D%llx.%s", (unsigned long long)addr,
180 node->name);
181 return;
182 }
183#endif /* !CONFIG_PPC_DCR_NATIVE */
184 }
185#endif /* CONFIG_PPC_DCR */
186
187 /*
188 * For MMIO, get the physical address
189 */
190 reg = get_property(node, "reg", NULL);
191 if (reg) {
192 addr = of_translate_address(node, reg);
193 if (addr != OF_BAD_ADDR) {
194 snprintf(name, BUS_ID_SIZE,
195 "%llx.%s", (unsigned long long)addr,
196 node->name);
197 return;
198 }
199 }
200
201 /*
202 * No BusID, use the node name and pray
203 */
204 snprintf(name, BUS_ID_SIZE, "%s", node->name);
205}
206
207struct of_device* of_platform_device_create(struct device_node *np,
208 const char *bus_id,
209 struct device *parent)
210{
211 struct of_device *dev;
212
213 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
214 if (!dev)
215 return NULL;
216 memset(dev, 0, sizeof(*dev));
217
218 dev->node = of_node_get(np);
219 dev->dma_mask = 0xffffffffUL;
220 dev->dev.dma_mask = &dev->dma_mask;
221 dev->dev.parent = parent;
222 dev->dev.bus = &of_platform_bus_type;
223 dev->dev.release = of_release_dev;
224
225 if (bus_id)
226 strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
227 else
228 of_platform_make_bus_id(dev);
229
230 if (of_device_register(dev) != 0) {
231 kfree(dev);
232 return NULL;
233 }
234
235 return dev;
236}
237EXPORT_SYMBOL(of_platform_device_create);
238
239
240
241/**
242 * of_platform_bus_create - Create an OF device for a bus node and all its
243 * children. Optionally recursively instanciate matching busses.
244 * @bus: device node of the bus to instanciate
245 * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
246 * disallow recursive creation of child busses
247 */
248static int of_platform_bus_create(struct device_node *bus,
249 struct of_device_id *matches,
250 struct device *parent)
251{
252 struct device_node *child;
253 struct of_device *dev;
254 int rc = 0;
255
256 for (child = NULL; (child = of_get_next_child(bus, child)); ) {
257 pr_debug(" create child: %s\n", child->full_name);
258 dev = of_platform_device_create(child, NULL, parent);
259 if (dev == NULL)
260 rc = -ENOMEM;
261 else if (!of_match_node(matches, child))
262 continue;
263 if (rc == 0) {
264 pr_debug(" and sub busses\n");
265 rc = of_platform_bus_create(child, matches, &dev->dev);
266 } if (rc) {
267 of_node_put(child);
268 break;
269 }
270 }
271 return rc;
272}
273
274/**
275 * of_platform_bus_probe - Probe the device-tree for platform busses
276 * @root: parent of the first level to probe or NULL for the root of the tree
277 * @matches: match table, NULL to use the default
278 * @parent: parent to hook devices from, NULL for toplevel
279 *
280 * Note that children of the provided root are not instanciated as devices
281 * unless the specified root itself matches the bus list and is not NULL.
282 */
283
284int of_platform_bus_probe(struct device_node *root,
285 struct of_device_id *matches,
286 struct device *parent)
287{
288 struct device_node *child;
289 struct of_device *dev;
290 int rc = 0;
291
292 if (matches == NULL)
293 matches = of_default_bus_ids;
294 if (matches == OF_NO_DEEP_PROBE)
295 return -EINVAL;
296 if (root == NULL)
297 root = of_find_node_by_path("/");
298 else
299 of_node_get(root);
300
301 pr_debug("of_platform_bus_probe()\n");
302 pr_debug(" starting at: %s\n", root->full_name);
303
304 /* Do a self check of bus type, if there's a match, create
305 * children
306 */
307 if (of_match_node(matches, root)) {
308 pr_debug(" root match, create all sub devices\n");
309 dev = of_platform_device_create(root, NULL, parent);
310 if (dev == NULL) {
311 rc = -ENOMEM;
312 goto bail;
313 }
314 pr_debug(" create all sub busses\n");
315 rc = of_platform_bus_create(root, matches, &dev->dev);
316 goto bail;
317 }
318 for (child = NULL; (child = of_get_next_child(root, child)); ) {
319 if (!of_match_node(matches, child))
320 continue;
321
322 pr_debug(" match: %s\n", child->full_name);
323 dev = of_platform_device_create(child, NULL, parent);
324 if (dev == NULL)
325 rc = -ENOMEM;
326 else
327 rc = of_platform_bus_create(child, matches, &dev->dev);
328 if (rc) {
329 of_node_put(child);
330 break;
331 }
332 }
333 bail:
334 of_node_put(root);
335 return rc;
336}
337EXPORT_SYMBOL(of_platform_bus_probe);
338
339static int of_dev_node_match(struct device *dev, void *data)
340{
341 return to_of_device(dev)->node == data;
342}
343
344struct of_device *of_find_device_by_node(struct device_node *np)
345{
346 struct device *dev;
347
348 dev = bus_find_device(&of_platform_bus_type,
349 NULL, np, of_dev_node_match);
350 if (dev)
351 return to_of_device(dev);
352 return NULL;
353}
354EXPORT_SYMBOL(of_find_device_by_node);
355
356static int of_dev_phandle_match(struct device *dev, void *data)
357{
358 phandle *ph = data;
359 return to_of_device(dev)->node->linux_phandle == *ph;
360}
361
362struct of_device *of_find_device_by_phandle(phandle ph)
363{
364 struct device *dev;
365
366 dev = bus_find_device(&of_platform_bus_type,
367 NULL, &ph, of_dev_phandle_match);
368 if (dev)
369 return to_of_device(dev);
370 return NULL;
371}
372EXPORT_SYMBOL(of_find_device_by_phandle);
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 805791d76fdf..4ec6a5a65f30 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -70,6 +70,7 @@
70#include <asm/pmac_feature.h> 70#include <asm/pmac_feature.h>
71#include <asm/time.h> 71#include <asm/time.h>
72#include <asm/of_device.h> 72#include <asm/of_device.h>
73#include <asm/of_platform.h>
73#include <asm/mmu_context.h> 74#include <asm/mmu_context.h>
74#include <asm/iommu.h> 75#include <asm/iommu.h>
75#include <asm/smu.h> 76#include <asm/smu.h>