.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * IBM PowerPC Virtual I/O Infrastructure Support. |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | * Hollis Blanchard <hollisb@us.ibm.com> |
---|
8 | 9 | * Stephen Rothwell |
---|
9 | 10 | * Robert Jennings <rcjenn@us.ibm.com> |
---|
10 | | - * |
---|
11 | | - * This program is free software; you can redistribute it and/or |
---|
12 | | - * modify it under the terms of the GNU General Public License |
---|
13 | | - * as published by the Free Software Foundation; either version |
---|
14 | | - * 2 of the License, or (at your option) any later version. |
---|
15 | 11 | */ |
---|
16 | 12 | |
---|
17 | 13 | #include <linux/cpu.h> |
---|
.. | .. |
---|
24 | 20 | #include <linux/console.h> |
---|
25 | 21 | #include <linux/export.h> |
---|
26 | 22 | #include <linux/mm.h> |
---|
27 | | -#include <linux/dma-mapping.h> |
---|
| 23 | +#include <linux/dma-map-ops.h> |
---|
28 | 24 | #include <linux/kobject.h> |
---|
29 | 25 | |
---|
30 | 26 | #include <asm/iommu.h> |
---|
.. | .. |
---|
35 | 31 | #include <asm/tce.h> |
---|
36 | 32 | #include <asm/page.h> |
---|
37 | 33 | #include <asm/hvcall.h> |
---|
| 34 | +#include <asm/machdep.h> |
---|
38 | 35 | |
---|
39 | 36 | static struct vio_dev vio_bus_device = { /* fake "parent" device */ |
---|
40 | 37 | .name = "vio", |
---|
.. | .. |
---|
492 | 489 | return NULL; |
---|
493 | 490 | } |
---|
494 | 491 | |
---|
495 | | - ret = dma_iommu_ops.alloc(dev, size, dma_handle, flag, attrs); |
---|
| 492 | + ret = iommu_alloc_coherent(dev, get_iommu_table_base(dev), size, |
---|
| 493 | + dma_handle, dev->coherent_dma_mask, flag, |
---|
| 494 | + dev_to_node(dev)); |
---|
496 | 495 | if (unlikely(ret == NULL)) { |
---|
497 | 496 | vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE)); |
---|
498 | 497 | atomic_inc(&viodev->cmo.allocs_failed); |
---|
.. | .. |
---|
507 | 506 | { |
---|
508 | 507 | struct vio_dev *viodev = to_vio_dev(dev); |
---|
509 | 508 | |
---|
510 | | - dma_iommu_ops.free(dev, size, vaddr, dma_handle, attrs); |
---|
511 | | - |
---|
| 509 | + iommu_free_coherent(get_iommu_table_base(dev), size, vaddr, dma_handle); |
---|
512 | 510 | vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE)); |
---|
513 | 511 | } |
---|
514 | 512 | |
---|
.. | .. |
---|
518 | 516 | unsigned long attrs) |
---|
519 | 517 | { |
---|
520 | 518 | struct vio_dev *viodev = to_vio_dev(dev); |
---|
521 | | - struct iommu_table *tbl; |
---|
522 | | - dma_addr_t ret = IOMMU_MAPPING_ERROR; |
---|
| 519 | + struct iommu_table *tbl = get_iommu_table_base(dev); |
---|
| 520 | + dma_addr_t ret = DMA_MAPPING_ERROR; |
---|
523 | 521 | |
---|
524 | | - tbl = get_iommu_table_base(dev); |
---|
525 | | - if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)))) { |
---|
526 | | - atomic_inc(&viodev->cmo.allocs_failed); |
---|
527 | | - return ret; |
---|
528 | | - } |
---|
529 | | - |
---|
530 | | - ret = dma_iommu_ops.map_page(dev, page, offset, size, direction, attrs); |
---|
531 | | - if (unlikely(dma_mapping_error(dev, ret))) { |
---|
532 | | - vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))); |
---|
533 | | - atomic_inc(&viodev->cmo.allocs_failed); |
---|
534 | | - } |
---|
535 | | - |
---|
| 522 | + if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)))) |
---|
| 523 | + goto out_fail; |
---|
| 524 | + ret = iommu_map_page(dev, tbl, page, offset, size, dma_get_mask(dev), |
---|
| 525 | + direction, attrs); |
---|
| 526 | + if (unlikely(ret == DMA_MAPPING_ERROR)) |
---|
| 527 | + goto out_deallocate; |
---|
536 | 528 | return ret; |
---|
| 529 | + |
---|
| 530 | +out_deallocate: |
---|
| 531 | + vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))); |
---|
| 532 | +out_fail: |
---|
| 533 | + atomic_inc(&viodev->cmo.allocs_failed); |
---|
| 534 | + return DMA_MAPPING_ERROR; |
---|
537 | 535 | } |
---|
538 | 536 | |
---|
539 | 537 | static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle, |
---|
.. | .. |
---|
542 | 540 | unsigned long attrs) |
---|
543 | 541 | { |
---|
544 | 542 | struct vio_dev *viodev = to_vio_dev(dev); |
---|
545 | | - struct iommu_table *tbl; |
---|
| 543 | + struct iommu_table *tbl = get_iommu_table_base(dev); |
---|
546 | 544 | |
---|
547 | | - tbl = get_iommu_table_base(dev); |
---|
548 | | - dma_iommu_ops.unmap_page(dev, dma_handle, size, direction, attrs); |
---|
549 | | - |
---|
| 545 | + iommu_unmap_page(tbl, dma_handle, size, direction, attrs); |
---|
550 | 546 | vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))); |
---|
551 | 547 | } |
---|
552 | 548 | |
---|
.. | .. |
---|
555 | 551 | unsigned long attrs) |
---|
556 | 552 | { |
---|
557 | 553 | struct vio_dev *viodev = to_vio_dev(dev); |
---|
558 | | - struct iommu_table *tbl; |
---|
| 554 | + struct iommu_table *tbl = get_iommu_table_base(dev); |
---|
559 | 555 | struct scatterlist *sgl; |
---|
560 | 556 | int ret, count; |
---|
561 | 557 | size_t alloc_size = 0; |
---|
562 | 558 | |
---|
563 | | - tbl = get_iommu_table_base(dev); |
---|
564 | 559 | for_each_sg(sglist, sgl, nelems, count) |
---|
565 | 560 | alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE(tbl)); |
---|
566 | 561 | |
---|
567 | | - if (vio_cmo_alloc(viodev, alloc_size)) { |
---|
568 | | - atomic_inc(&viodev->cmo.allocs_failed); |
---|
569 | | - return 0; |
---|
570 | | - } |
---|
571 | | - |
---|
572 | | - ret = dma_iommu_ops.map_sg(dev, sglist, nelems, direction, attrs); |
---|
573 | | - |
---|
574 | | - if (unlikely(!ret)) { |
---|
575 | | - vio_cmo_dealloc(viodev, alloc_size); |
---|
576 | | - atomic_inc(&viodev->cmo.allocs_failed); |
---|
577 | | - return ret; |
---|
578 | | - } |
---|
| 562 | + if (vio_cmo_alloc(viodev, alloc_size)) |
---|
| 563 | + goto out_fail; |
---|
| 564 | + ret = ppc_iommu_map_sg(dev, tbl, sglist, nelems, dma_get_mask(dev), |
---|
| 565 | + direction, attrs); |
---|
| 566 | + if (unlikely(!ret)) |
---|
| 567 | + goto out_deallocate; |
---|
579 | 568 | |
---|
580 | 569 | for_each_sg(sglist, sgl, ret, count) |
---|
581 | 570 | alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl)); |
---|
582 | 571 | if (alloc_size) |
---|
583 | 572 | vio_cmo_dealloc(viodev, alloc_size); |
---|
584 | | - |
---|
585 | 573 | return ret; |
---|
| 574 | + |
---|
| 575 | +out_deallocate: |
---|
| 576 | + vio_cmo_dealloc(viodev, alloc_size); |
---|
| 577 | +out_fail: |
---|
| 578 | + atomic_inc(&viodev->cmo.allocs_failed); |
---|
| 579 | + return 0; |
---|
586 | 580 | } |
---|
587 | 581 | |
---|
588 | 582 | static void vio_dma_iommu_unmap_sg(struct device *dev, |
---|
.. | .. |
---|
591 | 585 | unsigned long attrs) |
---|
592 | 586 | { |
---|
593 | 587 | struct vio_dev *viodev = to_vio_dev(dev); |
---|
594 | | - struct iommu_table *tbl; |
---|
| 588 | + struct iommu_table *tbl = get_iommu_table_base(dev); |
---|
595 | 589 | struct scatterlist *sgl; |
---|
596 | 590 | size_t alloc_size = 0; |
---|
597 | 591 | int count; |
---|
598 | 592 | |
---|
599 | | - tbl = get_iommu_table_base(dev); |
---|
600 | 593 | for_each_sg(sglist, sgl, nelems, count) |
---|
601 | 594 | alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl)); |
---|
602 | 595 | |
---|
603 | | - dma_iommu_ops.unmap_sg(dev, sglist, nelems, direction, attrs); |
---|
604 | | - |
---|
| 596 | + ppc_iommu_unmap_sg(tbl, sglist, nelems, direction, attrs); |
---|
605 | 597 | vio_cmo_dealloc(viodev, alloc_size); |
---|
606 | | -} |
---|
607 | | - |
---|
608 | | -static int vio_dma_iommu_dma_supported(struct device *dev, u64 mask) |
---|
609 | | -{ |
---|
610 | | - return dma_iommu_ops.dma_supported(dev, mask); |
---|
611 | | -} |
---|
612 | | - |
---|
613 | | -static u64 vio_dma_get_required_mask(struct device *dev) |
---|
614 | | -{ |
---|
615 | | - return dma_iommu_ops.get_required_mask(dev); |
---|
616 | 598 | } |
---|
617 | 599 | |
---|
618 | 600 | static const struct dma_map_ops vio_dma_mapping_ops = { |
---|
619 | 601 | .alloc = vio_dma_iommu_alloc_coherent, |
---|
620 | 602 | .free = vio_dma_iommu_free_coherent, |
---|
621 | | - .mmap = dma_nommu_mmap_coherent, |
---|
622 | 603 | .map_sg = vio_dma_iommu_map_sg, |
---|
623 | 604 | .unmap_sg = vio_dma_iommu_unmap_sg, |
---|
624 | 605 | .map_page = vio_dma_iommu_map_page, |
---|
625 | 606 | .unmap_page = vio_dma_iommu_unmap_page, |
---|
626 | | - .dma_supported = vio_dma_iommu_dma_supported, |
---|
627 | | - .get_required_mask = vio_dma_get_required_mask, |
---|
628 | | - .mapping_error = dma_iommu_mapping_error, |
---|
| 607 | + .dma_supported = dma_iommu_dma_supported, |
---|
| 608 | + .get_required_mask = dma_iommu_get_required_mask, |
---|
| 609 | + .mmap = dma_common_mmap, |
---|
| 610 | + .get_sgtable = dma_common_get_sgtable, |
---|
| 611 | + .alloc_pages = dma_common_alloc_pages, |
---|
| 612 | + .free_pages = dma_common_free_pages, |
---|
629 | 613 | }; |
---|
630 | 614 | |
---|
631 | 615 | /** |
---|
.. | .. |
---|
1214 | 1198 | else |
---|
1215 | 1199 | tbl->it_ops = &iommu_table_pseries_ops; |
---|
1216 | 1200 | |
---|
1217 | | - return iommu_init_table(tbl, -1); |
---|
| 1201 | + return iommu_init_table(tbl, -1, 0, 0); |
---|
1218 | 1202 | } |
---|
1219 | 1203 | |
---|
1220 | 1204 | /** |
---|
.. | .. |
---|
1302 | 1286 | int __vio_register_driver(struct vio_driver *viodrv, struct module *owner, |
---|
1303 | 1287 | const char *mod_name) |
---|
1304 | 1288 | { |
---|
| 1289 | + // vio_bus_type is only initialised for pseries |
---|
| 1290 | + if (!machine_is(pseries)) |
---|
| 1291 | + return -ENODEV; |
---|
| 1292 | + |
---|
1305 | 1293 | pr_debug("%s: driver %s registering\n", __func__, viodrv->name); |
---|
1306 | 1294 | |
---|
1307 | 1295 | /* fill in 'struct driver' fields */ |
---|
.. | .. |
---|
1351 | 1339 | struct device_node *parent_node; |
---|
1352 | 1340 | const __be32 *prop; |
---|
1353 | 1341 | enum vio_dev_family family; |
---|
1354 | | - const char *of_node_name = of_node->name ? of_node->name : "<unknown>"; |
---|
1355 | 1342 | |
---|
1356 | 1343 | /* |
---|
1357 | 1344 | * Determine if this node is a under the /vdevice node or under the |
---|
.. | .. |
---|
1359 | 1346 | */ |
---|
1360 | 1347 | parent_node = of_get_parent(of_node); |
---|
1361 | 1348 | if (parent_node) { |
---|
1362 | | - if (!strcmp(parent_node->type, "ibm,platform-facilities")) |
---|
| 1349 | + if (of_node_is_type(parent_node, "ibm,platform-facilities")) |
---|
1363 | 1350 | family = PFO; |
---|
1364 | | - else if (!strcmp(parent_node->type, "vdevice")) |
---|
| 1351 | + else if (of_node_is_type(parent_node, "vdevice")) |
---|
1365 | 1352 | family = VDEVICE; |
---|
1366 | 1353 | else { |
---|
1367 | | - pr_warn("%s: parent(%pOF) of %s not recognized.\n", |
---|
| 1354 | + pr_warn("%s: parent(%pOF) of %pOFn not recognized.\n", |
---|
1368 | 1355 | __func__, |
---|
1369 | 1356 | parent_node, |
---|
1370 | | - of_node_name); |
---|
| 1357 | + of_node); |
---|
1371 | 1358 | of_node_put(parent_node); |
---|
1372 | 1359 | return NULL; |
---|
1373 | 1360 | } |
---|
1374 | 1361 | of_node_put(parent_node); |
---|
1375 | 1362 | } else { |
---|
1376 | | - pr_warn("%s: could not determine the parent of node %s.\n", |
---|
1377 | | - __func__, of_node_name); |
---|
| 1363 | + pr_warn("%s: could not determine the parent of node %pOFn.\n", |
---|
| 1364 | + __func__, of_node); |
---|
1378 | 1365 | return NULL; |
---|
1379 | 1366 | } |
---|
1380 | 1367 | |
---|
1381 | 1368 | if (family == PFO) { |
---|
1382 | 1369 | if (of_get_property(of_node, "interrupt-controller", NULL)) { |
---|
1383 | | - pr_debug("%s: Skipping the interrupt controller %s.\n", |
---|
1384 | | - __func__, of_node_name); |
---|
| 1370 | + pr_debug("%s: Skipping the interrupt controller %pOFn.\n", |
---|
| 1371 | + __func__, of_node); |
---|
1385 | 1372 | return NULL; |
---|
1386 | 1373 | } |
---|
1387 | 1374 | } |
---|
.. | .. |
---|
1398 | 1385 | if (viodev->family == VDEVICE) { |
---|
1399 | 1386 | unsigned int unit_address; |
---|
1400 | 1387 | |
---|
1401 | | - if (of_node->type != NULL) |
---|
1402 | | - viodev->type = of_node->type; |
---|
1403 | | - else { |
---|
1404 | | - pr_warn("%s: node %s is missing the 'device_type' " |
---|
1405 | | - "property.\n", __func__, of_node_name); |
---|
| 1388 | + viodev->type = of_node_get_device_type(of_node); |
---|
| 1389 | + if (!viodev->type) { |
---|
| 1390 | + pr_warn("%s: node %pOFn is missing the 'device_type' " |
---|
| 1391 | + "property.\n", __func__, of_node); |
---|
1406 | 1392 | goto out; |
---|
1407 | 1393 | } |
---|
1408 | 1394 | |
---|
1409 | 1395 | prop = of_get_property(of_node, "reg", NULL); |
---|
1410 | 1396 | if (prop == NULL) { |
---|
1411 | | - pr_warn("%s: node %s missing 'reg'\n", |
---|
1412 | | - __func__, of_node_name); |
---|
| 1397 | + pr_warn("%s: node %pOFn missing 'reg'\n", |
---|
| 1398 | + __func__, of_node); |
---|
1413 | 1399 | goto out; |
---|
1414 | 1400 | } |
---|
1415 | 1401 | unit_address = of_read_number(prop, 1); |
---|
.. | .. |
---|
1424 | 1410 | if (prop != NULL) |
---|
1425 | 1411 | viodev->resource_id = of_read_number(prop, 1); |
---|
1426 | 1412 | |
---|
1427 | | - dev_set_name(&viodev->dev, "%s", of_node_name); |
---|
1428 | | - viodev->type = of_node_name; |
---|
| 1413 | + dev_set_name(&viodev->dev, "%pOFn", of_node); |
---|
| 1414 | + viodev->type = dev_name(&viodev->dev); |
---|
1429 | 1415 | viodev->irq = 0; |
---|
1430 | 1416 | } |
---|
1431 | 1417 | |
---|
.. | .. |
---|
1534 | 1520 | |
---|
1535 | 1521 | return 0; |
---|
1536 | 1522 | } |
---|
1537 | | -postcore_initcall(vio_bus_init); |
---|
| 1523 | +machine_postcore_initcall(pseries, vio_bus_init); |
---|
1538 | 1524 | |
---|
1539 | 1525 | static int __init vio_device_init(void) |
---|
1540 | 1526 | { |
---|
.. | .. |
---|
1543 | 1529 | |
---|
1544 | 1530 | return 0; |
---|
1545 | 1531 | } |
---|
1546 | | -device_initcall(vio_device_init); |
---|
| 1532 | +machine_device_initcall(pseries, vio_device_init); |
---|
1547 | 1533 | |
---|
1548 | 1534 | static ssize_t name_show(struct device *dev, |
---|
1549 | 1535 | struct device_attribute *attr, char *buf) |
---|
.. | .. |
---|
1649 | 1635 | } |
---|
1650 | 1636 | EXPORT_SYMBOL(vio_get_attribute); |
---|
1651 | 1637 | |
---|
1652 | | -#ifdef CONFIG_PPC_PSERIES |
---|
1653 | 1638 | /* vio_find_name() - internal because only vio.c knows how we formatted the |
---|
1654 | 1639 | * kobject name |
---|
1655 | 1640 | */ |
---|
.. | .. |
---|
1675 | 1660 | { |
---|
1676 | 1661 | char kobj_name[20]; |
---|
1677 | 1662 | struct device_node *vnode_parent; |
---|
1678 | | - const char *dev_type; |
---|
1679 | 1663 | |
---|
1680 | 1664 | vnode_parent = of_get_parent(vnode); |
---|
1681 | 1665 | if (!vnode_parent) |
---|
1682 | 1666 | return NULL; |
---|
1683 | 1667 | |
---|
1684 | | - dev_type = of_get_property(vnode_parent, "device_type", NULL); |
---|
1685 | | - of_node_put(vnode_parent); |
---|
1686 | | - if (!dev_type) |
---|
1687 | | - return NULL; |
---|
1688 | | - |
---|
1689 | 1668 | /* construct the kobject name from the device node */ |
---|
1690 | | - if (!strcmp(dev_type, "vdevice")) { |
---|
| 1669 | + if (of_node_is_type(vnode_parent, "vdevice")) { |
---|
1691 | 1670 | const __be32 *prop; |
---|
1692 | 1671 | |
---|
1693 | 1672 | prop = of_get_property(vnode, "reg", NULL); |
---|
1694 | 1673 | if (!prop) |
---|
1695 | | - return NULL; |
---|
| 1674 | + goto out; |
---|
1696 | 1675 | snprintf(kobj_name, sizeof(kobj_name), "%x", |
---|
1697 | 1676 | (uint32_t)of_read_number(prop, 1)); |
---|
1698 | | - } else if (!strcmp(dev_type, "ibm,platform-facilities")) |
---|
1699 | | - snprintf(kobj_name, sizeof(kobj_name), "%s", vnode->name); |
---|
| 1677 | + } else if (of_node_is_type(vnode_parent, "ibm,platform-facilities")) |
---|
| 1678 | + snprintf(kobj_name, sizeof(kobj_name), "%pOFn", vnode); |
---|
1700 | 1679 | else |
---|
1701 | | - return NULL; |
---|
| 1680 | + goto out; |
---|
1702 | 1681 | |
---|
| 1682 | + of_node_put(vnode_parent); |
---|
1703 | 1683 | return vio_find_name(kobj_name); |
---|
| 1684 | +out: |
---|
| 1685 | + of_node_put(vnode_parent); |
---|
| 1686 | + return NULL; |
---|
1704 | 1687 | } |
---|
1705 | 1688 | EXPORT_SYMBOL(vio_find_node); |
---|
1706 | 1689 | |
---|
.. | .. |
---|
1721 | 1704 | return rc; |
---|
1722 | 1705 | } |
---|
1723 | 1706 | EXPORT_SYMBOL(vio_disable_interrupts); |
---|
1724 | | -#endif /* CONFIG_PPC_PSERIES */ |
---|
| 1707 | + |
---|
| 1708 | +static int __init vio_init(void) |
---|
| 1709 | +{ |
---|
| 1710 | + dma_debug_add_bus(&vio_bus_type); |
---|
| 1711 | + return 0; |
---|
| 1712 | +} |
---|
| 1713 | +machine_fs_initcall(pseries, vio_init); |
---|