diff options
Diffstat (limited to 'arch/powerpc/kernel/ibmebus.c')
-rw-r--r-- | arch/powerpc/kernel/ibmebus.c | 263 |
1 files changed, 71 insertions, 192 deletions
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 2e16ca5778a3..289d7e935918 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/kobject.h> | 41 | #include <linux/kobject.h> |
42 | #include <linux/dma-mapping.h> | 42 | #include <linux/dma-mapping.h> |
43 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
44 | #include <linux/of_platform.h> | ||
44 | #include <asm/ibmebus.h> | 45 | #include <asm/ibmebus.h> |
45 | #include <asm/abs_addr.h> | 46 | #include <asm/abs_addr.h> |
46 | 47 | ||
@@ -50,6 +51,13 @@ static struct device ibmebus_bus_device = { /* fake "parent" device */ | |||
50 | 51 | ||
51 | struct bus_type ibmebus_bus_type; | 52 | struct bus_type ibmebus_bus_type; |
52 | 53 | ||
54 | /* These devices will automatically be added to the bus during init */ | ||
55 | static struct of_device_id builtin_matches[] = { | ||
56 | { .compatible = "IBM,lhca" }, | ||
57 | { .compatible = "IBM,lhea" }, | ||
58 | {}, | ||
59 | }; | ||
60 | |||
53 | static void *ibmebus_alloc_coherent(struct device *dev, | 61 | static void *ibmebus_alloc_coherent(struct device *dev, |
54 | size_t size, | 62 | size_t size, |
55 | dma_addr_t *dma_handle, | 63 | dma_addr_t *dma_handle, |
@@ -124,190 +132,87 @@ static struct dma_mapping_ops ibmebus_dma_ops = { | |||
124 | .dma_supported = ibmebus_dma_supported, | 132 | .dma_supported = ibmebus_dma_supported, |
125 | }; | 133 | }; |
126 | 134 | ||
127 | static int ibmebus_bus_probe(struct device *dev) | 135 | static int ibmebus_match_path(struct device *dev, void *data) |
128 | { | 136 | { |
129 | struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); | 137 | struct device_node *dn = to_of_device(dev)->node; |
130 | struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); | 138 | return (dn->full_name && |
131 | const struct of_device_id *id; | 139 | (strcasecmp((char *)data, dn->full_name) == 0)); |
132 | int error = -ENODEV; | ||
133 | |||
134 | if (!ibmebusdrv->probe) | ||
135 | return error; | ||
136 | |||
137 | id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev); | ||
138 | if (id) { | ||
139 | error = ibmebusdrv->probe(ibmebusdev, id); | ||
140 | } | ||
141 | |||
142 | return error; | ||
143 | } | 140 | } |
144 | 141 | ||
145 | static int ibmebus_bus_remove(struct device *dev) | 142 | static int ibmebus_match_node(struct device *dev, void *data) |
146 | { | 143 | { |
147 | struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); | 144 | return to_of_device(dev)->node == data; |
148 | struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); | ||
149 | |||
150 | if (ibmebusdrv->remove) { | ||
151 | return ibmebusdrv->remove(ibmebusdev); | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | } | 145 | } |
156 | 146 | ||
157 | static void __devinit ibmebus_dev_release(struct device *dev) | 147 | static int ibmebus_create_device(struct device_node *dn) |
158 | { | 148 | { |
159 | of_node_put(to_ibmebus_dev(dev)->ofdev.node); | 149 | struct of_device *dev; |
160 | kfree(to_ibmebus_dev(dev)); | 150 | int ret; |
161 | } | ||
162 | |||
163 | static int __devinit ibmebus_register_device_common( | ||
164 | struct ibmebus_dev *dev, const char *name) | ||
165 | { | ||
166 | int err = 0; | ||
167 | |||
168 | dev->ofdev.dev.parent = &ibmebus_bus_device; | ||
169 | dev->ofdev.dev.bus = &ibmebus_bus_type; | ||
170 | dev->ofdev.dev.release = ibmebus_dev_release; | ||
171 | 151 | ||
172 | dev->ofdev.dev.archdata.of_node = dev->ofdev.node; | 152 | dev = of_device_alloc(dn, NULL, &ibmebus_bus_device); |
173 | dev->ofdev.dev.archdata.dma_ops = &ibmebus_dma_ops; | ||
174 | dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node); | ||
175 | |||
176 | /* An ibmebusdev is based on a of_device. We have to change the | ||
177 | * bus type to use our own DMA mapping operations. | ||
178 | */ | ||
179 | if ((err = of_device_register(&dev->ofdev)) != 0) { | ||
180 | printk(KERN_ERR "%s: failed to register device (%d).\n", | ||
181 | __FUNCTION__, err); | ||
182 | return -ENODEV; | ||
183 | } | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static struct ibmebus_dev* __devinit ibmebus_register_device_node( | ||
189 | struct device_node *dn) | ||
190 | { | ||
191 | struct ibmebus_dev *dev; | ||
192 | int i, len, bus_len; | ||
193 | |||
194 | dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); | ||
195 | if (!dev) | 153 | if (!dev) |
196 | return ERR_PTR(-ENOMEM); | 154 | return -ENOMEM; |
197 | |||
198 | dev->ofdev.node = of_node_get(dn); | ||
199 | |||
200 | len = strlen(dn->full_name + 1); | ||
201 | bus_len = min(len, BUS_ID_SIZE - 1); | ||
202 | memcpy(dev->ofdev.dev.bus_id, dn->full_name + 1 | ||
203 | + (len - bus_len), bus_len); | ||
204 | for (i = 0; i < bus_len; i++) | ||
205 | if (dev->ofdev.dev.bus_id[i] == '/') | ||
206 | dev->ofdev.dev.bus_id[i] = '_'; | ||
207 | |||
208 | /* Register with generic device framework. */ | ||
209 | if (ibmebus_register_device_common(dev, dn->name) != 0) { | ||
210 | kfree(dev); | ||
211 | return ERR_PTR(-ENODEV); | ||
212 | } | ||
213 | |||
214 | return dev; | ||
215 | } | ||
216 | |||
217 | static void ibmebus_probe_of_nodes(char* name) | ||
218 | { | ||
219 | struct device_node *dn = NULL; | ||
220 | |||
221 | while ((dn = of_find_node_by_name(dn, name))) { | ||
222 | if (IS_ERR(ibmebus_register_device_node(dn))) { | ||
223 | of_node_put(dn); | ||
224 | return; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | of_node_put(dn); | ||
229 | 155 | ||
230 | return; | 156 | dev->dev.bus = &ibmebus_bus_type; |
231 | } | 157 | dev->dev.archdata.dma_ops = &ibmebus_dma_ops; |
232 | 158 | ||
233 | static void ibmebus_add_devices_by_id(struct of_device_id *idt) | 159 | ret = of_device_register(dev); |
234 | { | 160 | if (ret) { |
235 | while (strlen(idt->name) > 0) { | 161 | of_device_free(dev); |
236 | ibmebus_probe_of_nodes(idt->name); | 162 | return ret; |
237 | idt++; | ||
238 | } | 163 | } |
239 | 164 | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | static int ibmebus_match_name(struct device *dev, void *data) | ||
244 | { | ||
245 | const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); | ||
246 | const char *name; | ||
247 | |||
248 | name = of_get_property(ebus_dev->ofdev.node, "name", NULL); | ||
249 | |||
250 | if (name && (strcmp(data, name) == 0)) | ||
251 | return 1; | ||
252 | |||
253 | return 0; | 165 | return 0; |
254 | } | 166 | } |
255 | 167 | ||
256 | static int ibmebus_unregister_device(struct device *dev) | 168 | static int ibmebus_create_devices(const struct of_device_id *matches) |
257 | { | 169 | { |
258 | of_device_unregister(to_of_device(dev)); | 170 | struct device_node *root, *child; |
171 | int ret = 0; | ||
259 | 172 | ||
260 | return 0; | 173 | root = of_find_node_by_path("/"); |
261 | } | ||
262 | 174 | ||
263 | static void ibmebus_remove_devices_by_id(struct of_device_id *idt) | 175 | for (child = NULL; (child = of_get_next_child(root, child)); ) { |
264 | { | 176 | if (!of_match_node(matches, child)) |
265 | struct device *dev; | 177 | continue; |
266 | 178 | ||
267 | while (strlen(idt->name) > 0) { | 179 | if (bus_find_device(&ibmebus_bus_type, NULL, child, |
268 | while ((dev = bus_find_device(&ibmebus_bus_type, NULL, | 180 | ibmebus_match_node)) |
269 | (void*)idt->name, | 181 | continue; |
270 | ibmebus_match_name))) { | 182 | |
271 | ibmebus_unregister_device(dev); | 183 | ret = ibmebus_create_device(child); |
184 | if (ret) { | ||
185 | printk(KERN_ERR "%s: failed to create device (%i)", | ||
186 | __FUNCTION__, ret); | ||
187 | of_node_put(child); | ||
188 | break; | ||
272 | } | 189 | } |
273 | idt++; | ||
274 | } | 190 | } |
275 | 191 | ||
276 | return; | 192 | of_node_put(root); |
193 | return ret; | ||
277 | } | 194 | } |
278 | 195 | ||
279 | int ibmebus_register_driver(struct ibmebus_driver *drv) | 196 | int ibmebus_register_driver(struct of_platform_driver *drv) |
280 | { | 197 | { |
281 | int err = 0; | 198 | /* If the driver uses devices that ibmebus doesn't know, add them */ |
199 | ibmebus_create_devices(drv->match_table); | ||
282 | 200 | ||
283 | drv->driver.name = drv->name; | 201 | drv->driver.name = drv->name; |
284 | drv->driver.bus = &ibmebus_bus_type; | 202 | drv->driver.bus = &ibmebus_bus_type; |
285 | drv->driver.probe = ibmebus_bus_probe; | ||
286 | drv->driver.remove = ibmebus_bus_remove; | ||
287 | 203 | ||
288 | if ((err = driver_register(&drv->driver) != 0)) | 204 | return driver_register(&drv->driver); |
289 | return err; | ||
290 | |||
291 | /* remove all supported devices first, in case someone | ||
292 | * probed them manually before registering the driver */ | ||
293 | ibmebus_remove_devices_by_id(drv->id_table); | ||
294 | ibmebus_add_devices_by_id(drv->id_table); | ||
295 | |||
296 | return 0; | ||
297 | } | 205 | } |
298 | EXPORT_SYMBOL(ibmebus_register_driver); | 206 | EXPORT_SYMBOL(ibmebus_register_driver); |
299 | 207 | ||
300 | void ibmebus_unregister_driver(struct ibmebus_driver *drv) | 208 | void ibmebus_unregister_driver(struct of_platform_driver *drv) |
301 | { | 209 | { |
302 | driver_unregister(&drv->driver); | 210 | driver_unregister(&drv->driver); |
303 | ibmebus_remove_devices_by_id(drv->id_table); | ||
304 | } | 211 | } |
305 | EXPORT_SYMBOL(ibmebus_unregister_driver); | 212 | EXPORT_SYMBOL(ibmebus_unregister_driver); |
306 | 213 | ||
307 | int ibmebus_request_irq(struct ibmebus_dev *dev, | 214 | int ibmebus_request_irq(u32 ist, irq_handler_t handler, |
308 | u32 ist, | 215 | unsigned long irq_flags, const char *devname, |
309 | irq_handler_t handler, | ||
310 | unsigned long irq_flags, const char * devname, | ||
311 | void *dev_id) | 216 | void *dev_id) |
312 | { | 217 | { |
313 | unsigned int irq = irq_create_mapping(NULL, ist); | 218 | unsigned int irq = irq_create_mapping(NULL, ist); |
@@ -315,12 +220,11 @@ int ibmebus_request_irq(struct ibmebus_dev *dev, | |||
315 | if (irq == NO_IRQ) | 220 | if (irq == NO_IRQ) |
316 | return -EINVAL; | 221 | return -EINVAL; |
317 | 222 | ||
318 | return request_irq(irq, handler, | 223 | return request_irq(irq, handler, irq_flags, devname, dev_id); |
319 | irq_flags, devname, dev_id); | ||
320 | } | 224 | } |
321 | EXPORT_SYMBOL(ibmebus_request_irq); | 225 | EXPORT_SYMBOL(ibmebus_request_irq); |
322 | 226 | ||
323 | void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id) | 227 | void ibmebus_free_irq(u32 ist, void *dev_id) |
324 | { | 228 | { |
325 | unsigned int irq = irq_find_mapping(NULL, ist); | 229 | unsigned int irq = irq_find_mapping(NULL, ist); |
326 | 230 | ||
@@ -328,29 +232,10 @@ void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id) | |||
328 | } | 232 | } |
329 | EXPORT_SYMBOL(ibmebus_free_irq); | 233 | EXPORT_SYMBOL(ibmebus_free_irq); |
330 | 234 | ||
331 | static int ibmebus_bus_match(struct device *dev, struct device_driver *drv) | ||
332 | { | ||
333 | const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); | ||
334 | struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv); | ||
335 | const struct of_device_id *ids = ebus_drv->id_table; | ||
336 | const struct of_device_id *found_id; | ||
337 | |||
338 | if (!ids) | ||
339 | return 0; | ||
340 | |||
341 | found_id = of_match_device(ids, &ebus_dev->ofdev); | ||
342 | if (found_id) | ||
343 | return 1; | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static ssize_t name_show(struct device *dev, | 235 | static ssize_t name_show(struct device *dev, |
349 | struct device_attribute *attr, char *buf) | 236 | struct device_attribute *attr, char *buf) |
350 | { | 237 | { |
351 | struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); | 238 | return sprintf(buf, "%s\n", to_of_device(dev)->node->name); |
352 | const char *name = of_get_property(ebus_dev->ofdev.node, "name", NULL); | ||
353 | return sprintf(buf, "%s\n", name); | ||
354 | } | 239 | } |
355 | 240 | ||
356 | static struct device_attribute ibmebus_dev_attrs[] = { | 241 | static struct device_attribute ibmebus_dev_attrs[] = { |
@@ -358,18 +243,6 @@ static struct device_attribute ibmebus_dev_attrs[] = { | |||
358 | __ATTR_NULL | 243 | __ATTR_NULL |
359 | }; | 244 | }; |
360 | 245 | ||
361 | static int ibmebus_match_path(struct device *dev, void *data) | ||
362 | { | ||
363 | int rc; | ||
364 | struct device_node *dn = | ||
365 | of_node_get(to_ibmebus_dev(dev)->ofdev.node); | ||
366 | |||
367 | rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0)); | ||
368 | |||
369 | of_node_put(dn); | ||
370 | return rc; | ||
371 | } | ||
372 | |||
373 | static char *ibmebus_chomp(const char *in, size_t count) | 246 | static char *ibmebus_chomp(const char *in, size_t count) |
374 | { | 247 | { |
375 | char *out = kmalloc(count + 1, GFP_KERNEL); | 248 | char *out = kmalloc(count + 1, GFP_KERNEL); |
@@ -389,9 +262,8 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus, | |||
389 | const char *buf, size_t count) | 262 | const char *buf, size_t count) |
390 | { | 263 | { |
391 | struct device_node *dn = NULL; | 264 | struct device_node *dn = NULL; |
392 | struct ibmebus_dev *dev; | ||
393 | char *path; | 265 | char *path; |
394 | ssize_t rc; | 266 | ssize_t rc = 0; |
395 | 267 | ||
396 | path = ibmebus_chomp(buf, count); | 268 | path = ibmebus_chomp(buf, count); |
397 | if (!path) | 269 | if (!path) |
@@ -406,9 +278,8 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus, | |||
406 | } | 278 | } |
407 | 279 | ||
408 | if ((dn = of_find_node_by_path(path))) { | 280 | if ((dn = of_find_node_by_path(path))) { |
409 | dev = ibmebus_register_device_node(dn); | 281 | rc = ibmebus_create_device(dn); |
410 | of_node_put(dn); | 282 | of_node_put(dn); |
411 | rc = IS_ERR(dev) ? PTR_ERR(dev) : count; | ||
412 | } else { | 283 | } else { |
413 | printk(KERN_WARNING "%s: no such device node: %s\n", | 284 | printk(KERN_WARNING "%s: no such device node: %s\n", |
414 | __FUNCTION__, path); | 285 | __FUNCTION__, path); |
@@ -417,7 +288,9 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus, | |||
417 | 288 | ||
418 | out: | 289 | out: |
419 | kfree(path); | 290 | kfree(path); |
420 | return rc; | 291 | if (rc) |
292 | return rc; | ||
293 | return count; | ||
421 | } | 294 | } |
422 | 295 | ||
423 | static ssize_t ibmebus_store_remove(struct bus_type *bus, | 296 | static ssize_t ibmebus_store_remove(struct bus_type *bus, |
@@ -432,7 +305,7 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus, | |||
432 | 305 | ||
433 | if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path, | 306 | if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path, |
434 | ibmebus_match_path))) { | 307 | ibmebus_match_path))) { |
435 | ibmebus_unregister_device(dev); | 308 | of_device_unregister(to_of_device(dev)); |
436 | 309 | ||
437 | kfree(path); | 310 | kfree(path); |
438 | return count; | 311 | return count; |
@@ -452,8 +325,7 @@ static struct bus_attribute ibmebus_bus_attrs[] = { | |||
452 | }; | 325 | }; |
453 | 326 | ||
454 | struct bus_type ibmebus_bus_type = { | 327 | struct bus_type ibmebus_bus_type = { |
455 | .name = "ibmebus", | 328 | .uevent = of_device_uevent, |
456 | .match = ibmebus_bus_match, | ||
457 | .dev_attrs = ibmebus_dev_attrs, | 329 | .dev_attrs = ibmebus_dev_attrs, |
458 | .bus_attrs = ibmebus_bus_attrs | 330 | .bus_attrs = ibmebus_bus_attrs |
459 | }; | 331 | }; |
@@ -465,9 +337,9 @@ static int __init ibmebus_bus_init(void) | |||
465 | 337 | ||
466 | printk(KERN_INFO "IBM eBus Device Driver\n"); | 338 | printk(KERN_INFO "IBM eBus Device Driver\n"); |
467 | 339 | ||
468 | err = bus_register(&ibmebus_bus_type); | 340 | err = of_bus_type_init(&ibmebus_bus_type, "ibmebus"); |
469 | if (err) { | 341 | if (err) { |
470 | printk(KERN_ERR ":%s: failed to register IBM eBus.\n", | 342 | printk(KERN_ERR "%s: failed to register IBM eBus.\n", |
471 | __FUNCTION__); | 343 | __FUNCTION__); |
472 | return err; | 344 | return err; |
473 | } | 345 | } |
@@ -481,6 +353,13 @@ static int __init ibmebus_bus_init(void) | |||
481 | return err; | 353 | return err; |
482 | } | 354 | } |
483 | 355 | ||
356 | err = ibmebus_create_devices(builtin_matches); | ||
357 | if (err) { | ||
358 | device_unregister(&ibmebus_bus_device); | ||
359 | bus_unregister(&ibmebus_bus_type); | ||
360 | return err; | ||
361 | } | ||
362 | |||
484 | return 0; | 363 | return 0; |
485 | } | 364 | } |
486 | __initcall(ibmebus_bus_init); | 365 | postcore_initcall(ibmebus_bus_init); |