1 | /* |
2 | * IBM PowerPC IBM eBus Infrastructure Support. |
3 | * |
4 | * Copyright (c) 2005 IBM Corporation |
5 | * Joachim Fenkes <fenkes@de.ibm.com> |
6 | * Heiko J Schick <schickhj@de.ibm.com> |
7 | * |
8 | * All rights reserved. |
9 | * |
10 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB |
11 | * BSD. |
12 | * |
13 | * OpenIB BSD License |
14 | * |
15 | * Redistribution and use in source and binary forms, with or without |
16 | * modification, are permitted provided that the following conditions are met: |
17 | * |
18 | * Redistributions of source code must retain the above copyright notice, this |
19 | * list of conditions and the following disclaimer. |
20 | * |
21 | * Redistributions in binary form must reproduce the above copyright notice, |
22 | * this list of conditions and the following disclaimer in the documentation |
23 | * and/or other materials |
24 | * provided with the distribution. |
25 | * |
26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
33 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
34 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
35 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
36 | * POSSIBILITY OF SUCH DAMAGE. |
37 | */ |
38 | |
39 | #include <linux/init.h> |
40 | #include <linux/export.h> |
41 | #include <linux/console.h> |
42 | #include <linux/kobject.h> |
43 | #include <linux/dma-map-ops.h> |
44 | #include <linux/interrupt.h> |
45 | #include <linux/irqdomain.h> |
46 | #include <linux/of.h> |
47 | #include <linux/slab.h> |
48 | #include <linux/stat.h> |
49 | #include <linux/of_platform.h> |
50 | #include <linux/platform_device.h> |
51 | #include <asm/ibmebus.h> |
52 | #include <asm/machdep.h> |
53 | |
54 | static struct device ibmebus_bus_device = { /* fake "parent" device */ |
55 | .init_name = "ibmebus" , |
56 | }; |
57 | |
58 | const struct bus_type ibmebus_bus_type; |
59 | |
60 | /* These devices will automatically be added to the bus during init */ |
61 | static const struct of_device_id ibmebus_matches[] __initconst = { |
62 | { .compatible = "IBM,lhca" }, |
63 | { .compatible = "IBM,lhea" }, |
64 | {}, |
65 | }; |
66 | |
67 | static void *ibmebus_alloc_coherent(struct device *dev, |
68 | size_t size, |
69 | dma_addr_t *dma_handle, |
70 | gfp_t flag, |
71 | unsigned long attrs) |
72 | { |
73 | void *mem; |
74 | |
75 | mem = kmalloc(size, flags: flag); |
76 | *dma_handle = (dma_addr_t)mem; |
77 | |
78 | return mem; |
79 | } |
80 | |
81 | static void ibmebus_free_coherent(struct device *dev, |
82 | size_t size, void *vaddr, |
83 | dma_addr_t dma_handle, |
84 | unsigned long attrs) |
85 | { |
86 | kfree(objp: vaddr); |
87 | } |
88 | |
89 | static dma_addr_t ibmebus_map_page(struct device *dev, |
90 | struct page *page, |
91 | unsigned long offset, |
92 | size_t size, |
93 | enum dma_data_direction direction, |
94 | unsigned long attrs) |
95 | { |
96 | return (dma_addr_t)(page_address(page) + offset); |
97 | } |
98 | |
99 | static void ibmebus_unmap_page(struct device *dev, |
100 | dma_addr_t dma_addr, |
101 | size_t size, |
102 | enum dma_data_direction direction, |
103 | unsigned long attrs) |
104 | { |
105 | return; |
106 | } |
107 | |
108 | static int ibmebus_map_sg(struct device *dev, |
109 | struct scatterlist *sgl, |
110 | int nents, enum dma_data_direction direction, |
111 | unsigned long attrs) |
112 | { |
113 | struct scatterlist *sg; |
114 | int i; |
115 | |
116 | for_each_sg(sgl, sg, nents, i) { |
117 | sg->dma_address = (dma_addr_t) sg_virt(sg); |
118 | sg->dma_length = sg->length; |
119 | } |
120 | |
121 | return nents; |
122 | } |
123 | |
124 | static void ibmebus_unmap_sg(struct device *dev, |
125 | struct scatterlist *sg, |
126 | int nents, enum dma_data_direction direction, |
127 | unsigned long attrs) |
128 | { |
129 | return; |
130 | } |
131 | |
132 | static int ibmebus_dma_supported(struct device *dev, u64 mask) |
133 | { |
134 | return mask == DMA_BIT_MASK(64); |
135 | } |
136 | |
137 | static u64 ibmebus_dma_get_required_mask(struct device *dev) |
138 | { |
139 | return DMA_BIT_MASK(64); |
140 | } |
141 | |
142 | static const struct dma_map_ops ibmebus_dma_ops = { |
143 | .alloc = ibmebus_alloc_coherent, |
144 | .free = ibmebus_free_coherent, |
145 | .map_sg = ibmebus_map_sg, |
146 | .unmap_sg = ibmebus_unmap_sg, |
147 | .dma_supported = ibmebus_dma_supported, |
148 | .get_required_mask = ibmebus_dma_get_required_mask, |
149 | .map_page = ibmebus_map_page, |
150 | .unmap_page = ibmebus_unmap_page, |
151 | }; |
152 | |
153 | static int ibmebus_match_path(struct device *dev, const void *data) |
154 | { |
155 | struct device_node *dn = to_platform_device(dev)->dev.of_node; |
156 | struct device_node *tn = of_find_node_by_path(path: data); |
157 | |
158 | of_node_put(node: tn); |
159 | |
160 | return (tn == dn); |
161 | } |
162 | |
163 | static int ibmebus_match_node(struct device *dev, const void *data) |
164 | { |
165 | return to_platform_device(dev)->dev.of_node == data; |
166 | } |
167 | |
168 | static int ibmebus_create_device(struct device_node *dn) |
169 | { |
170 | struct platform_device *dev; |
171 | int ret; |
172 | |
173 | dev = of_device_alloc(np: dn, NULL, parent: &ibmebus_bus_device); |
174 | if (!dev) |
175 | return -ENOMEM; |
176 | |
177 | dev->dev.bus = &ibmebus_bus_type; |
178 | dev->dev.dma_ops = &ibmebus_dma_ops; |
179 | |
180 | ret = of_device_add(pdev: dev); |
181 | if (ret) |
182 | platform_device_put(pdev: dev); |
183 | return ret; |
184 | } |
185 | |
186 | static int ibmebus_create_devices(const struct of_device_id *matches) |
187 | { |
188 | struct device_node *root, *child; |
189 | struct device *dev; |
190 | int ret = 0; |
191 | |
192 | root = of_find_node_by_path(path: "/" ); |
193 | |
194 | for_each_child_of_node(root, child) { |
195 | if (!of_match_node(matches, node: child)) |
196 | continue; |
197 | |
198 | dev = bus_find_device(bus: &ibmebus_bus_type, NULL, data: child, |
199 | match: ibmebus_match_node); |
200 | if (dev) { |
201 | put_device(dev); |
202 | continue; |
203 | } |
204 | |
205 | ret = ibmebus_create_device(dn: child); |
206 | if (ret) { |
207 | printk(KERN_ERR "%s: failed to create device (%i)" , |
208 | __func__, ret); |
209 | of_node_put(node: child); |
210 | break; |
211 | } |
212 | } |
213 | |
214 | of_node_put(node: root); |
215 | return ret; |
216 | } |
217 | |
218 | int ibmebus_register_driver(struct platform_driver *drv) |
219 | { |
220 | /* If the driver uses devices that ibmebus doesn't know, add them */ |
221 | ibmebus_create_devices(matches: drv->driver.of_match_table); |
222 | |
223 | drv->driver.bus = &ibmebus_bus_type; |
224 | return driver_register(drv: &drv->driver); |
225 | } |
226 | EXPORT_SYMBOL(ibmebus_register_driver); |
227 | |
228 | void ibmebus_unregister_driver(struct platform_driver *drv) |
229 | { |
230 | driver_unregister(drv: &drv->driver); |
231 | } |
232 | EXPORT_SYMBOL(ibmebus_unregister_driver); |
233 | |
234 | int ibmebus_request_irq(u32 ist, irq_handler_t handler, |
235 | unsigned long irq_flags, const char *devname, |
236 | void *dev_id) |
237 | { |
238 | unsigned int irq = irq_create_mapping(NULL, hwirq: ist); |
239 | |
240 | if (!irq) |
241 | return -EINVAL; |
242 | |
243 | return request_irq(irq, handler, flags: irq_flags, name: devname, dev: dev_id); |
244 | } |
245 | EXPORT_SYMBOL(ibmebus_request_irq); |
246 | |
247 | void ibmebus_free_irq(u32 ist, void *dev_id) |
248 | { |
249 | unsigned int irq = irq_find_mapping(NULL, hwirq: ist); |
250 | |
251 | free_irq(irq, dev_id); |
252 | irq_dispose_mapping(virq: irq); |
253 | } |
254 | EXPORT_SYMBOL(ibmebus_free_irq); |
255 | |
256 | static char *ibmebus_chomp(const char *in, size_t count) |
257 | { |
258 | char *out = kmalloc(size: count + 1, GFP_KERNEL); |
259 | |
260 | if (!out) |
261 | return NULL; |
262 | |
263 | memcpy(out, in, count); |
264 | out[count] = '\0'; |
265 | if (out[count - 1] == '\n') |
266 | out[count - 1] = '\0'; |
267 | |
268 | return out; |
269 | } |
270 | |
271 | static ssize_t probe_store(const struct bus_type *bus, const char *buf, size_t count) |
272 | { |
273 | struct device_node *dn = NULL; |
274 | struct device *dev; |
275 | char *path; |
276 | ssize_t rc = 0; |
277 | |
278 | path = ibmebus_chomp(in: buf, count); |
279 | if (!path) |
280 | return -ENOMEM; |
281 | |
282 | dev = bus_find_device(bus: &ibmebus_bus_type, NULL, data: path, |
283 | match: ibmebus_match_path); |
284 | if (dev) { |
285 | put_device(dev); |
286 | printk(KERN_WARNING "%s: %s has already been probed\n" , |
287 | __func__, path); |
288 | rc = -EEXIST; |
289 | goto out; |
290 | } |
291 | |
292 | if ((dn = of_find_node_by_path(path))) { |
293 | rc = ibmebus_create_device(dn); |
294 | of_node_put(node: dn); |
295 | } else { |
296 | printk(KERN_WARNING "%s: no such device node: %s\n" , |
297 | __func__, path); |
298 | rc = -ENODEV; |
299 | } |
300 | |
301 | out: |
302 | kfree(objp: path); |
303 | if (rc) |
304 | return rc; |
305 | return count; |
306 | } |
307 | static BUS_ATTR_WO(probe); |
308 | |
309 | static ssize_t remove_store(const struct bus_type *bus, const char *buf, size_t count) |
310 | { |
311 | struct device *dev; |
312 | char *path; |
313 | |
314 | path = ibmebus_chomp(in: buf, count); |
315 | if (!path) |
316 | return -ENOMEM; |
317 | |
318 | if ((dev = bus_find_device(bus: &ibmebus_bus_type, NULL, data: path, |
319 | match: ibmebus_match_path))) { |
320 | of_device_unregister(to_platform_device(dev)); |
321 | put_device(dev); |
322 | |
323 | kfree(objp: path); |
324 | return count; |
325 | } else { |
326 | printk(KERN_WARNING "%s: %s not on the bus\n" , |
327 | __func__, path); |
328 | |
329 | kfree(objp: path); |
330 | return -ENODEV; |
331 | } |
332 | } |
333 | static BUS_ATTR_WO(remove); |
334 | |
335 | static struct attribute *ibmbus_bus_attrs[] = { |
336 | &bus_attr_probe.attr, |
337 | &bus_attr_remove.attr, |
338 | NULL, |
339 | }; |
340 | ATTRIBUTE_GROUPS(ibmbus_bus); |
341 | |
342 | static int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv) |
343 | { |
344 | const struct of_device_id *matches = drv->of_match_table; |
345 | |
346 | if (!matches) |
347 | return 0; |
348 | |
349 | return of_match_device(matches, dev) != NULL; |
350 | } |
351 | |
352 | static int ibmebus_bus_device_probe(struct device *dev) |
353 | { |
354 | int error = -ENODEV; |
355 | struct platform_driver *drv; |
356 | struct platform_device *of_dev; |
357 | |
358 | drv = to_platform_driver(dev->driver); |
359 | of_dev = to_platform_device(dev); |
360 | |
361 | if (!drv->probe) |
362 | return error; |
363 | |
364 | get_device(dev); |
365 | |
366 | if (of_driver_match_device(dev, dev->driver)) |
367 | error = drv->probe(of_dev); |
368 | if (error) |
369 | put_device(dev); |
370 | |
371 | return error; |
372 | } |
373 | |
374 | static void ibmebus_bus_device_remove(struct device *dev) |
375 | { |
376 | struct platform_device *of_dev = to_platform_device(dev); |
377 | struct platform_driver *drv = to_platform_driver(dev->driver); |
378 | |
379 | if (dev->driver && drv->remove) |
380 | drv->remove(of_dev); |
381 | } |
382 | |
383 | static void ibmebus_bus_device_shutdown(struct device *dev) |
384 | { |
385 | struct platform_device *of_dev = to_platform_device(dev); |
386 | struct platform_driver *drv = to_platform_driver(dev->driver); |
387 | |
388 | if (dev->driver && drv->shutdown) |
389 | drv->shutdown(of_dev); |
390 | } |
391 | |
392 | /* |
393 | * ibmebus_bus_device_attrs |
394 | */ |
395 | static ssize_t devspec_show(struct device *dev, |
396 | struct device_attribute *attr, char *buf) |
397 | { |
398 | struct platform_device *ofdev; |
399 | |
400 | ofdev = to_platform_device(dev); |
401 | return sprintf(buf, fmt: "%pOF\n" , ofdev->dev.of_node); |
402 | } |
403 | static DEVICE_ATTR_RO(devspec); |
404 | |
405 | static ssize_t name_show(struct device *dev, |
406 | struct device_attribute *attr, char *buf) |
407 | { |
408 | struct platform_device *ofdev; |
409 | |
410 | ofdev = to_platform_device(dev); |
411 | return sprintf(buf, fmt: "%pOFn\n" , ofdev->dev.of_node); |
412 | } |
413 | static DEVICE_ATTR_RO(name); |
414 | |
415 | static ssize_t modalias_show(struct device *dev, |
416 | struct device_attribute *attr, char *buf) |
417 | { |
418 | return of_device_modalias(dev, buf, PAGE_SIZE); |
419 | } |
420 | static DEVICE_ATTR_RO(modalias); |
421 | |
422 | static struct attribute *ibmebus_bus_device_attrs[] = { |
423 | &dev_attr_devspec.attr, |
424 | &dev_attr_name.attr, |
425 | &dev_attr_modalias.attr, |
426 | NULL, |
427 | }; |
428 | ATTRIBUTE_GROUPS(ibmebus_bus_device); |
429 | |
430 | static int ibmebus_bus_modalias(const struct device *dev, struct kobj_uevent_env *env) |
431 | { |
432 | return of_device_uevent_modalias(dev, env); |
433 | } |
434 | |
435 | const struct bus_type ibmebus_bus_type = { |
436 | .name = "ibmebus" , |
437 | .uevent = ibmebus_bus_modalias, |
438 | .bus_groups = ibmbus_bus_groups, |
439 | .match = ibmebus_bus_bus_match, |
440 | .probe = ibmebus_bus_device_probe, |
441 | .remove = ibmebus_bus_device_remove, |
442 | .shutdown = ibmebus_bus_device_shutdown, |
443 | .dev_groups = ibmebus_bus_device_groups, |
444 | }; |
445 | EXPORT_SYMBOL(ibmebus_bus_type); |
446 | |
447 | static int __init ibmebus_bus_init(void) |
448 | { |
449 | int err; |
450 | |
451 | printk(KERN_INFO "IBM eBus Device Driver\n" ); |
452 | |
453 | err = bus_register(bus: &ibmebus_bus_type); |
454 | if (err) { |
455 | printk(KERN_ERR "%s: failed to register IBM eBus.\n" , |
456 | __func__); |
457 | return err; |
458 | } |
459 | |
460 | err = device_register(dev: &ibmebus_bus_device); |
461 | if (err) { |
462 | printk(KERN_WARNING "%s: device_register returned %i\n" , |
463 | __func__, err); |
464 | put_device(dev: &ibmebus_bus_device); |
465 | bus_unregister(bus: &ibmebus_bus_type); |
466 | |
467 | return err; |
468 | } |
469 | |
470 | err = ibmebus_create_devices(matches: ibmebus_matches); |
471 | if (err) { |
472 | device_unregister(dev: &ibmebus_bus_device); |
473 | bus_unregister(bus: &ibmebus_bus_type); |
474 | return err; |
475 | } |
476 | |
477 | return 0; |
478 | } |
479 | machine_postcore_initcall(pseries, ibmebus_bus_init); |
480 | |