diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-11-11 01:25:02 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-12-04 04:38:40 -0500 |
commit | 12d04eef927bf61328af2c7cbe756c96f98ac3bf (patch) | |
tree | 18865369100e9059c7e883dec93ea67f7b52a287 /arch/powerpc/kernel/vio.c | |
parent | 7c719871ff4d5f15b71f0138d08b758281b58631 (diff) |
[POWERPC] Refactor 64 bits DMA operations
This patch completely refactors DMA operations for 64 bits powerpc. 32 bits
is untouched for now.
We use the new dev_archdata structure to add the dma operations pointer
and associated data to struct device. While at it, we also add the OF node
pointer and numa node. In the future, we might want to look into merging
that with pci_dn as well.
The old vio, pci-iommu and pci-direct DMA ops are gone. They are now replaced
by a set of generic iommu and direct DMA ops (non PCI specific) that can be
used by bus types. The toplevel implementation is now inline.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/vio.c')
-rw-r--r-- | arch/powerpc/kernel/vio.c | 94 |
1 files changed, 21 insertions, 73 deletions
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index ed007878d1bf..a80f8f1d2e5d 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
@@ -81,15 +81,15 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) | |||
81 | struct iommu_table *tbl; | 81 | struct iommu_table *tbl; |
82 | unsigned long offset, size; | 82 | unsigned long offset, size; |
83 | 83 | ||
84 | dma_window = get_property(dev->dev.platform_data, | 84 | dma_window = get_property(dev->dev.archdata.of_node, |
85 | "ibm,my-dma-window", NULL); | 85 | "ibm,my-dma-window", NULL); |
86 | if (!dma_window) | 86 | if (!dma_window) |
87 | return NULL; | 87 | return NULL; |
88 | 88 | ||
89 | tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); | 89 | tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); |
90 | 90 | ||
91 | of_parse_dma_window(dev->dev.platform_data, dma_window, | 91 | of_parse_dma_window(dev->dev.archdata.of_node, dma_window, |
92 | &tbl->it_index, &offset, &size); | 92 | &tbl->it_index, &offset, &size); |
93 | 93 | ||
94 | /* TCE table size - measured in tce entries */ | 94 | /* TCE table size - measured in tce entries */ |
95 | tbl->it_size = size >> IOMMU_PAGE_SHIFT; | 95 | tbl->it_size = size >> IOMMU_PAGE_SHIFT; |
@@ -117,7 +117,8 @@ static const struct vio_device_id *vio_match_device( | |||
117 | { | 117 | { |
118 | while (ids->type[0] != '\0') { | 118 | while (ids->type[0] != '\0') { |
119 | if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && | 119 | if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && |
120 | device_is_compatible(dev->dev.platform_data, ids->compat)) | 120 | device_is_compatible(dev->dev.archdata.of_node, |
121 | ids->compat)) | ||
121 | return ids; | 122 | return ids; |
122 | ids++; | 123 | ids++; |
123 | } | 124 | } |
@@ -198,9 +199,9 @@ EXPORT_SYMBOL(vio_unregister_driver); | |||
198 | /* vio_dev refcount hit 0 */ | 199 | /* vio_dev refcount hit 0 */ |
199 | static void __devinit vio_dev_release(struct device *dev) | 200 | static void __devinit vio_dev_release(struct device *dev) |
200 | { | 201 | { |
201 | if (dev->platform_data) { | 202 | if (dev->archdata.of_node) { |
202 | /* XXX free TCE table */ | 203 | /* XXX should free TCE table */ |
203 | of_node_put(dev->platform_data); | 204 | of_node_put(dev->archdata.of_node); |
204 | } | 205 | } |
205 | kfree(to_vio_dev(dev)); | 206 | kfree(to_vio_dev(dev)); |
206 | } | 207 | } |
@@ -210,7 +211,7 @@ static void __devinit vio_dev_release(struct device *dev) | |||
210 | * @of_node: The OF node for this device. | 211 | * @of_node: The OF node for this device. |
211 | * | 212 | * |
212 | * Creates and initializes a vio_dev structure from the data in | 213 | * Creates and initializes a vio_dev structure from the data in |
213 | * of_node (dev.platform_data) and adds it to the list of virtual devices. | 214 | * of_node and adds it to the list of virtual devices. |
214 | * Returns a pointer to the created vio_dev or NULL if node has | 215 | * Returns a pointer to the created vio_dev or NULL if node has |
215 | * NULL device_type or compatible fields. | 216 | * NULL device_type or compatible fields. |
216 | */ | 217 | */ |
@@ -240,8 +241,6 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) | |||
240 | if (viodev == NULL) | 241 | if (viodev == NULL) |
241 | return NULL; | 242 | return NULL; |
242 | 243 | ||
243 | viodev->dev.platform_data = of_node_get(of_node); | ||
244 | |||
245 | viodev->irq = irq_of_parse_and_map(of_node, 0); | 244 | viodev->irq = irq_of_parse_and_map(of_node, 0); |
246 | 245 | ||
247 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); | 246 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); |
@@ -254,7 +253,10 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) | |||
254 | if (unit_address != NULL) | 253 | if (unit_address != NULL) |
255 | viodev->unit_address = *unit_address; | 254 | viodev->unit_address = *unit_address; |
256 | } | 255 | } |
257 | viodev->iommu_table = vio_build_iommu_table(viodev); | 256 | viodev->dev.archdata.of_node = of_node_get(of_node); |
257 | viodev->dev.archdata.dma_ops = &dma_iommu_ops; | ||
258 | viodev->dev.archdata.dma_data = vio_build_iommu_table(viodev); | ||
259 | viodev->dev.archdata.numa_node = of_node_to_nid(of_node); | ||
258 | 260 | ||
259 | /* init generic 'struct device' fields: */ | 261 | /* init generic 'struct device' fields: */ |
260 | viodev->dev.parent = &vio_bus_device.dev; | 262 | viodev->dev.parent = &vio_bus_device.dev; |
@@ -285,10 +287,11 @@ static int __init vio_bus_init(void) | |||
285 | #ifdef CONFIG_PPC_ISERIES | 287 | #ifdef CONFIG_PPC_ISERIES |
286 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | 288 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { |
287 | iommu_vio_init(); | 289 | iommu_vio_init(); |
288 | vio_bus_device.iommu_table = &vio_iommu_table; | 290 | vio_bus_device.dev.archdata.dma_ops = &dma_iommu_ops; |
291 | vio_bus_device.dev.archdata.dma_data = &vio_iommu_table; | ||
289 | iSeries_vio_dev = &vio_bus_device.dev; | 292 | iSeries_vio_dev = &vio_bus_device.dev; |
290 | } | 293 | } |
291 | #endif | 294 | #endif /* CONFIG_PPC_ISERIES */ |
292 | 295 | ||
293 | err = bus_register(&vio_bus_type); | 296 | err = bus_register(&vio_bus_type); |
294 | if (err) { | 297 | if (err) { |
@@ -336,7 +339,7 @@ static ssize_t name_show(struct device *dev, | |||
336 | static ssize_t devspec_show(struct device *dev, | 339 | static ssize_t devspec_show(struct device *dev, |
337 | struct device_attribute *attr, char *buf) | 340 | struct device_attribute *attr, char *buf) |
338 | { | 341 | { |
339 | struct device_node *of_node = dev->platform_data; | 342 | struct device_node *of_node = dev->archdata.of_node; |
340 | 343 | ||
341 | return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none"); | 344 | return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none"); |
342 | } | 345 | } |
@@ -353,62 +356,6 @@ void __devinit vio_unregister_device(struct vio_dev *viodev) | |||
353 | } | 356 | } |
354 | EXPORT_SYMBOL(vio_unregister_device); | 357 | EXPORT_SYMBOL(vio_unregister_device); |
355 | 358 | ||
356 | static dma_addr_t vio_map_single(struct device *dev, void *vaddr, | ||
357 | size_t size, enum dma_data_direction direction) | ||
358 | { | ||
359 | return iommu_map_single(to_vio_dev(dev)->iommu_table, vaddr, size, | ||
360 | ~0ul, direction); | ||
361 | } | ||
362 | |||
363 | static void vio_unmap_single(struct device *dev, dma_addr_t dma_handle, | ||
364 | size_t size, enum dma_data_direction direction) | ||
365 | { | ||
366 | iommu_unmap_single(to_vio_dev(dev)->iommu_table, dma_handle, size, | ||
367 | direction); | ||
368 | } | ||
369 | |||
370 | static int vio_map_sg(struct device *dev, struct scatterlist *sglist, | ||
371 | int nelems, enum dma_data_direction direction) | ||
372 | { | ||
373 | return iommu_map_sg(dev, to_vio_dev(dev)->iommu_table, sglist, | ||
374 | nelems, ~0ul, direction); | ||
375 | } | ||
376 | |||
377 | static void vio_unmap_sg(struct device *dev, struct scatterlist *sglist, | ||
378 | int nelems, enum dma_data_direction direction) | ||
379 | { | ||
380 | iommu_unmap_sg(to_vio_dev(dev)->iommu_table, sglist, nelems, direction); | ||
381 | } | ||
382 | |||
383 | static void *vio_alloc_coherent(struct device *dev, size_t size, | ||
384 | dma_addr_t *dma_handle, gfp_t flag) | ||
385 | { | ||
386 | return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size, | ||
387 | dma_handle, ~0ul, flag, -1); | ||
388 | } | ||
389 | |||
390 | static void vio_free_coherent(struct device *dev, size_t size, | ||
391 | void *vaddr, dma_addr_t dma_handle) | ||
392 | { | ||
393 | iommu_free_coherent(to_vio_dev(dev)->iommu_table, size, vaddr, | ||
394 | dma_handle); | ||
395 | } | ||
396 | |||
397 | static int vio_dma_supported(struct device *dev, u64 mask) | ||
398 | { | ||
399 | return 1; | ||
400 | } | ||
401 | |||
402 | struct dma_mapping_ops vio_dma_ops = { | ||
403 | .alloc_coherent = vio_alloc_coherent, | ||
404 | .free_coherent = vio_free_coherent, | ||
405 | .map_single = vio_map_single, | ||
406 | .unmap_single = vio_unmap_single, | ||
407 | .map_sg = vio_map_sg, | ||
408 | .unmap_sg = vio_unmap_sg, | ||
409 | .dma_supported = vio_dma_supported, | ||
410 | }; | ||
411 | |||
412 | static int vio_bus_match(struct device *dev, struct device_driver *drv) | 359 | static int vio_bus_match(struct device *dev, struct device_driver *drv) |
413 | { | 360 | { |
414 | const struct vio_dev *vio_dev = to_vio_dev(dev); | 361 | const struct vio_dev *vio_dev = to_vio_dev(dev); |
@@ -422,13 +369,14 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp, | |||
422 | char *buffer, int buffer_size) | 369 | char *buffer, int buffer_size) |
423 | { | 370 | { |
424 | const struct vio_dev *vio_dev = to_vio_dev(dev); | 371 | const struct vio_dev *vio_dev = to_vio_dev(dev); |
425 | struct device_node *dn = dev->platform_data; | 372 | struct device_node *dn; |
426 | const char *cp; | 373 | const char *cp; |
427 | int length; | 374 | int length; |
428 | 375 | ||
429 | if (!num_envp) | 376 | if (!num_envp) |
430 | return -ENOMEM; | 377 | return -ENOMEM; |
431 | 378 | ||
379 | dn = dev->archdata.of_node; | ||
432 | if (!dn) | 380 | if (!dn) |
433 | return -ENODEV; | 381 | return -ENODEV; |
434 | cp = get_property(dn, "compatible", &length); | 382 | cp = get_property(dn, "compatible", &length); |
@@ -465,7 +413,7 @@ struct bus_type vio_bus_type = { | |||
465 | */ | 413 | */ |
466 | const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length) | 414 | const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length) |
467 | { | 415 | { |
468 | return get_property(vdev->dev.platform_data, which, length); | 416 | return get_property(vdev->dev.archdata.of_node, which, length); |
469 | } | 417 | } |
470 | EXPORT_SYMBOL(vio_get_attribute); | 418 | EXPORT_SYMBOL(vio_get_attribute); |
471 | 419 | ||