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