| .. | .. |
|---|
| 13 | 13 | #include <linux/sizes.h> |
|---|
| 14 | 14 | #include <linux/slab.h> |
|---|
| 15 | 15 | #include <linux/string.h> |
|---|
| 16 | +#include <linux/dma-direct.h> /* for bus_dma_region */ |
|---|
| 17 | + |
|---|
| 18 | +#include "of_private.h" |
|---|
| 16 | 19 | |
|---|
| 17 | 20 | /* Max address size we deal with */ |
|---|
| 18 | 21 | #define OF_MAX_ADDR_CELLS 4 |
|---|
| .. | .. |
|---|
| 47 | 50 | u64 (*map)(__be32 *addr, const __be32 *range, |
|---|
| 48 | 51 | int na, int ns, int pna); |
|---|
| 49 | 52 | int (*translate)(__be32 *addr, u64 offset, int na); |
|---|
| 53 | + bool has_flags; |
|---|
| 50 | 54 | unsigned int (*get_flags)(const __be32 *addr); |
|---|
| 51 | 55 | }; |
|---|
| 52 | 56 | |
|---|
| .. | .. |
|---|
| 99 | 103 | } |
|---|
| 100 | 104 | |
|---|
| 101 | 105 | #ifdef CONFIG_PCI |
|---|
| 102 | | -/* |
|---|
| 103 | | - * PCI bus specific translator |
|---|
| 104 | | - */ |
|---|
| 105 | | - |
|---|
| 106 | | -static int of_bus_pci_match(struct device_node *np) |
|---|
| 107 | | -{ |
|---|
| 108 | | - /* |
|---|
| 109 | | - * "pciex" is PCI Express |
|---|
| 110 | | - * "vci" is for the /chaos bridge on 1st-gen PCI powermacs |
|---|
| 111 | | - * "ht" is hypertransport |
|---|
| 112 | | - */ |
|---|
| 113 | | - return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex") || |
|---|
| 114 | | - !strcmp(np->type, "vci") || !strcmp(np->type, "ht"); |
|---|
| 115 | | -} |
|---|
| 116 | | - |
|---|
| 117 | | -static void of_bus_pci_count_cells(struct device_node *np, |
|---|
| 118 | | - int *addrc, int *sizec) |
|---|
| 119 | | -{ |
|---|
| 120 | | - if (addrc) |
|---|
| 121 | | - *addrc = 3; |
|---|
| 122 | | - if (sizec) |
|---|
| 123 | | - *sizec = 2; |
|---|
| 124 | | -} |
|---|
| 125 | | - |
|---|
| 126 | 106 | static unsigned int of_bus_pci_get_flags(const __be32 *addr) |
|---|
| 127 | 107 | { |
|---|
| 128 | 108 | unsigned int flags = 0; |
|---|
| 129 | 109 | u32 w = be32_to_cpup(addr); |
|---|
| 110 | + |
|---|
| 111 | + if (!IS_ENABLED(CONFIG_PCI)) |
|---|
| 112 | + return 0; |
|---|
| 130 | 113 | |
|---|
| 131 | 114 | switch((w >> 24) & 0x03) { |
|---|
| 132 | 115 | case 0x01: |
|---|
| .. | .. |
|---|
| 140 | 123 | if (w & 0x40000000) |
|---|
| 141 | 124 | flags |= IORESOURCE_PREFETCH; |
|---|
| 142 | 125 | return flags; |
|---|
| 126 | +} |
|---|
| 127 | + |
|---|
| 128 | +/* |
|---|
| 129 | + * PCI bus specific translator |
|---|
| 130 | + */ |
|---|
| 131 | + |
|---|
| 132 | +static bool of_node_is_pcie(struct device_node *np) |
|---|
| 133 | +{ |
|---|
| 134 | + bool is_pcie = of_node_name_eq(np, "pcie"); |
|---|
| 135 | + |
|---|
| 136 | + if (is_pcie) |
|---|
| 137 | + pr_warn_once("%pOF: Missing device_type\n", np); |
|---|
| 138 | + |
|---|
| 139 | + return is_pcie; |
|---|
| 140 | +} |
|---|
| 141 | + |
|---|
| 142 | +static int of_bus_pci_match(struct device_node *np) |
|---|
| 143 | +{ |
|---|
| 144 | + /* |
|---|
| 145 | + * "pciex" is PCI Express |
|---|
| 146 | + * "vci" is for the /chaos bridge on 1st-gen PCI powermacs |
|---|
| 147 | + * "ht" is hypertransport |
|---|
| 148 | + * |
|---|
| 149 | + * If none of the device_type match, and that the node name is |
|---|
| 150 | + * "pcie", accept the device as PCI (with a warning). |
|---|
| 151 | + */ |
|---|
| 152 | + return of_node_is_type(np, "pci") || of_node_is_type(np, "pciex") || |
|---|
| 153 | + of_node_is_type(np, "vci") || of_node_is_type(np, "ht") || |
|---|
| 154 | + of_node_is_pcie(np); |
|---|
| 155 | +} |
|---|
| 156 | + |
|---|
| 157 | +static void of_bus_pci_count_cells(struct device_node *np, |
|---|
| 158 | + int *addrc, int *sizec) |
|---|
| 159 | +{ |
|---|
| 160 | + if (addrc) |
|---|
| 161 | + *addrc = 3; |
|---|
| 162 | + if (sizec) |
|---|
| 163 | + *sizec = 2; |
|---|
| 143 | 164 | } |
|---|
| 144 | 165 | |
|---|
| 145 | 166 | static u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns, |
|---|
| .. | .. |
|---|
| 232 | 253 | } |
|---|
| 233 | 254 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); |
|---|
| 234 | 255 | |
|---|
| 235 | | -static int parser_init(struct of_pci_range_parser *parser, |
|---|
| 236 | | - struct device_node *node, const char *name) |
|---|
| 237 | | -{ |
|---|
| 238 | | - const int na = 3, ns = 2; |
|---|
| 239 | | - int rlen; |
|---|
| 240 | | - |
|---|
| 241 | | - parser->node = node; |
|---|
| 242 | | - parser->pna = of_n_addr_cells(node); |
|---|
| 243 | | - parser->np = parser->pna + na + ns; |
|---|
| 244 | | - |
|---|
| 245 | | - parser->range = of_get_property(node, name, &rlen); |
|---|
| 246 | | - if (parser->range == NULL) |
|---|
| 247 | | - return -ENOENT; |
|---|
| 248 | | - |
|---|
| 249 | | - parser->end = parser->range + rlen / sizeof(__be32); |
|---|
| 250 | | - |
|---|
| 251 | | - return 0; |
|---|
| 252 | | -} |
|---|
| 253 | | - |
|---|
| 254 | | -int of_pci_range_parser_init(struct of_pci_range_parser *parser, |
|---|
| 255 | | - struct device_node *node) |
|---|
| 256 | | -{ |
|---|
| 257 | | - return parser_init(parser, node, "ranges"); |
|---|
| 258 | | -} |
|---|
| 259 | | -EXPORT_SYMBOL_GPL(of_pci_range_parser_init); |
|---|
| 260 | | - |
|---|
| 261 | | -int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser, |
|---|
| 262 | | - struct device_node *node) |
|---|
| 263 | | -{ |
|---|
| 264 | | - return parser_init(parser, node, "dma-ranges"); |
|---|
| 265 | | -} |
|---|
| 266 | | -EXPORT_SYMBOL_GPL(of_pci_dma_range_parser_init); |
|---|
| 267 | | - |
|---|
| 268 | | -struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, |
|---|
| 269 | | - struct of_pci_range *range) |
|---|
| 270 | | -{ |
|---|
| 271 | | - const int na = 3, ns = 2; |
|---|
| 272 | | - |
|---|
| 273 | | - if (!range) |
|---|
| 274 | | - return NULL; |
|---|
| 275 | | - |
|---|
| 276 | | - if (!parser->range || parser->range + parser->np > parser->end) |
|---|
| 277 | | - return NULL; |
|---|
| 278 | | - |
|---|
| 279 | | - range->pci_space = be32_to_cpup(parser->range); |
|---|
| 280 | | - range->flags = of_bus_pci_get_flags(parser->range); |
|---|
| 281 | | - range->pci_addr = of_read_number(parser->range + 1, ns); |
|---|
| 282 | | - range->cpu_addr = of_translate_address(parser->node, |
|---|
| 283 | | - parser->range + na); |
|---|
| 284 | | - range->size = of_read_number(parser->range + parser->pna + na, ns); |
|---|
| 285 | | - |
|---|
| 286 | | - parser->range += parser->np; |
|---|
| 287 | | - |
|---|
| 288 | | - /* Now consume following elements while they are contiguous */ |
|---|
| 289 | | - while (parser->range + parser->np <= parser->end) { |
|---|
| 290 | | - u32 flags; |
|---|
| 291 | | - u64 pci_addr, cpu_addr, size; |
|---|
| 292 | | - |
|---|
| 293 | | - flags = of_bus_pci_get_flags(parser->range); |
|---|
| 294 | | - pci_addr = of_read_number(parser->range + 1, ns); |
|---|
| 295 | | - cpu_addr = of_translate_address(parser->node, |
|---|
| 296 | | - parser->range + na); |
|---|
| 297 | | - size = of_read_number(parser->range + parser->pna + na, ns); |
|---|
| 298 | | - |
|---|
| 299 | | - if (flags != range->flags) |
|---|
| 300 | | - break; |
|---|
| 301 | | - if (pci_addr != range->pci_addr + range->size || |
|---|
| 302 | | - cpu_addr != range->cpu_addr + range->size) |
|---|
| 303 | | - break; |
|---|
| 304 | | - |
|---|
| 305 | | - range->size += size; |
|---|
| 306 | | - parser->range += parser->np; |
|---|
| 307 | | - } |
|---|
| 308 | | - |
|---|
| 309 | | - return range; |
|---|
| 310 | | -} |
|---|
| 311 | | -EXPORT_SYMBOL_GPL(of_pci_range_parser_one); |
|---|
| 312 | | - |
|---|
| 313 | 256 | /* |
|---|
| 314 | 257 | * of_pci_range_to_resource - Create a resource from an of_pci_range |
|---|
| 315 | 258 | * @range: the PCI range that describes the resource |
|---|
| .. | .. |
|---|
| 371 | 314 | |
|---|
| 372 | 315 | static int of_bus_isa_match(struct device_node *np) |
|---|
| 373 | 316 | { |
|---|
| 374 | | - return !strcmp(np->name, "isa"); |
|---|
| 317 | + return of_node_name_eq(np, "isa"); |
|---|
| 375 | 318 | } |
|---|
| 376 | 319 | |
|---|
| 377 | 320 | static void of_bus_isa_count_cells(struct device_node *child, |
|---|
| .. | .. |
|---|
| 437 | 380 | .count_cells = of_bus_pci_count_cells, |
|---|
| 438 | 381 | .map = of_bus_pci_map, |
|---|
| 439 | 382 | .translate = of_bus_pci_translate, |
|---|
| 383 | + .has_flags = true, |
|---|
| 440 | 384 | .get_flags = of_bus_pci_get_flags, |
|---|
| 441 | 385 | }, |
|---|
| 442 | 386 | #endif /* CONFIG_PCI */ |
|---|
| .. | .. |
|---|
| 448 | 392 | .count_cells = of_bus_isa_count_cells, |
|---|
| 449 | 393 | .map = of_bus_isa_map, |
|---|
| 450 | 394 | .translate = of_bus_isa_translate, |
|---|
| 395 | + .has_flags = true, |
|---|
| 451 | 396 | .get_flags = of_bus_isa_get_flags, |
|---|
| 452 | 397 | }, |
|---|
| 453 | 398 | /* Default */ |
|---|
| .. | .. |
|---|
| 517 | 462 | * |
|---|
| 518 | 463 | * As far as we know, this damage only exists on Apple machines, so |
|---|
| 519 | 464 | * This code is only enabled on powerpc. --gcl |
|---|
| 465 | + * |
|---|
| 466 | + * This quirk also applies for 'dma-ranges' which frequently exist in |
|---|
| 467 | + * child nodes without 'dma-ranges' in the parent nodes. --RobH |
|---|
| 520 | 468 | */ |
|---|
| 521 | 469 | ranges = of_get_property(parent, rprop, &rlen); |
|---|
| 522 | | - if (ranges == NULL && !of_empty_ranges_quirk(parent)) { |
|---|
| 470 | + if (ranges == NULL && !of_empty_ranges_quirk(parent) && |
|---|
| 471 | + strcmp(rprop, "dma-ranges")) { |
|---|
| 523 | 472 | pr_debug("no ranges; cannot translate\n"); |
|---|
| 524 | 473 | return 1; |
|---|
| 525 | 474 | } |
|---|
| .. | .. |
|---|
| 569 | 518 | * relative to that node. |
|---|
| 570 | 519 | */ |
|---|
| 571 | 520 | static u64 __of_translate_address(struct device_node *dev, |
|---|
| 521 | + struct device_node *(*get_parent)(const struct device_node *), |
|---|
| 572 | 522 | const __be32 *in_addr, const char *rprop, |
|---|
| 573 | 523 | struct device_node **host) |
|---|
| 574 | 524 | { |
|---|
| .. | .. |
|---|
| 585 | 535 | |
|---|
| 586 | 536 | *host = NULL; |
|---|
| 587 | 537 | /* Get parent & match bus type */ |
|---|
| 588 | | - parent = of_get_parent(dev); |
|---|
| 538 | + parent = get_parent(dev); |
|---|
| 589 | 539 | if (parent == NULL) |
|---|
| 590 | 540 | goto bail; |
|---|
| 591 | 541 | bus = of_match_bus(parent); |
|---|
| .. | .. |
|---|
| 609 | 559 | /* Switch to parent bus */ |
|---|
| 610 | 560 | of_node_put(dev); |
|---|
| 611 | 561 | dev = parent; |
|---|
| 612 | | - parent = of_get_parent(dev); |
|---|
| 562 | + parent = get_parent(dev); |
|---|
| 613 | 563 | |
|---|
| 614 | 564 | /* If root, we have finished */ |
|---|
| 615 | 565 | if (parent == NULL) { |
|---|
| .. | .. |
|---|
| 665 | 615 | struct device_node *host; |
|---|
| 666 | 616 | u64 ret; |
|---|
| 667 | 617 | |
|---|
| 668 | | - ret = __of_translate_address(dev, in_addr, "ranges", &host); |
|---|
| 618 | + ret = __of_translate_address(dev, of_get_parent, |
|---|
| 619 | + in_addr, "ranges", &host); |
|---|
| 669 | 620 | if (host) { |
|---|
| 670 | 621 | of_node_put(host); |
|---|
| 671 | 622 | return OF_BAD_ADDR; |
|---|
| .. | .. |
|---|
| 675 | 626 | } |
|---|
| 676 | 627 | EXPORT_SYMBOL(of_translate_address); |
|---|
| 677 | 628 | |
|---|
| 629 | +static struct device_node *__of_get_dma_parent(const struct device_node *np) |
|---|
| 630 | +{ |
|---|
| 631 | + struct of_phandle_args args; |
|---|
| 632 | + int ret, index; |
|---|
| 633 | + |
|---|
| 634 | + index = of_property_match_string(np, "interconnect-names", "dma-mem"); |
|---|
| 635 | + if (index < 0) |
|---|
| 636 | + return of_get_parent(np); |
|---|
| 637 | + |
|---|
| 638 | + ret = of_parse_phandle_with_args(np, "interconnects", |
|---|
| 639 | + "#interconnect-cells", |
|---|
| 640 | + index, &args); |
|---|
| 641 | + if (ret < 0) |
|---|
| 642 | + return of_get_parent(np); |
|---|
| 643 | + |
|---|
| 644 | + return of_node_get(args.np); |
|---|
| 645 | +} |
|---|
| 646 | + |
|---|
| 647 | +static struct device_node *of_get_next_dma_parent(struct device_node *np) |
|---|
| 648 | +{ |
|---|
| 649 | + struct device_node *parent; |
|---|
| 650 | + |
|---|
| 651 | + parent = __of_get_dma_parent(np); |
|---|
| 652 | + of_node_put(np); |
|---|
| 653 | + |
|---|
| 654 | + return parent; |
|---|
| 655 | +} |
|---|
| 656 | + |
|---|
| 678 | 657 | u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) |
|---|
| 679 | 658 | { |
|---|
| 680 | 659 | struct device_node *host; |
|---|
| 681 | 660 | u64 ret; |
|---|
| 682 | 661 | |
|---|
| 683 | | - ret = __of_translate_address(dev, in_addr, "dma-ranges", &host); |
|---|
| 662 | + ret = __of_translate_address(dev, __of_get_dma_parent, |
|---|
| 663 | + in_addr, "dma-ranges", &host); |
|---|
| 684 | 664 | |
|---|
| 685 | 665 | if (host) { |
|---|
| 686 | 666 | of_node_put(host); |
|---|
| .. | .. |
|---|
| 729 | 709 | } |
|---|
| 730 | 710 | EXPORT_SYMBOL(of_get_address); |
|---|
| 731 | 711 | |
|---|
| 712 | +static int parser_init(struct of_pci_range_parser *parser, |
|---|
| 713 | + struct device_node *node, const char *name) |
|---|
| 714 | +{ |
|---|
| 715 | + int rlen; |
|---|
| 716 | + |
|---|
| 717 | + parser->node = node; |
|---|
| 718 | + parser->pna = of_n_addr_cells(node); |
|---|
| 719 | + parser->na = of_bus_n_addr_cells(node); |
|---|
| 720 | + parser->ns = of_bus_n_size_cells(node); |
|---|
| 721 | + parser->dma = !strcmp(name, "dma-ranges"); |
|---|
| 722 | + parser->bus = of_match_bus(node); |
|---|
| 723 | + |
|---|
| 724 | + parser->range = of_get_property(node, name, &rlen); |
|---|
| 725 | + if (parser->range == NULL) |
|---|
| 726 | + return -ENOENT; |
|---|
| 727 | + |
|---|
| 728 | + parser->end = parser->range + rlen / sizeof(__be32); |
|---|
| 729 | + |
|---|
| 730 | + return 0; |
|---|
| 731 | +} |
|---|
| 732 | + |
|---|
| 733 | +int of_pci_range_parser_init(struct of_pci_range_parser *parser, |
|---|
| 734 | + struct device_node *node) |
|---|
| 735 | +{ |
|---|
| 736 | + return parser_init(parser, node, "ranges"); |
|---|
| 737 | +} |
|---|
| 738 | +EXPORT_SYMBOL_GPL(of_pci_range_parser_init); |
|---|
| 739 | + |
|---|
| 740 | +int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser, |
|---|
| 741 | + struct device_node *node) |
|---|
| 742 | +{ |
|---|
| 743 | + return parser_init(parser, node, "dma-ranges"); |
|---|
| 744 | +} |
|---|
| 745 | +EXPORT_SYMBOL_GPL(of_pci_dma_range_parser_init); |
|---|
| 746 | +#define of_dma_range_parser_init of_pci_dma_range_parser_init |
|---|
| 747 | + |
|---|
| 748 | +struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, |
|---|
| 749 | + struct of_pci_range *range) |
|---|
| 750 | +{ |
|---|
| 751 | + int na = parser->na; |
|---|
| 752 | + int ns = parser->ns; |
|---|
| 753 | + int np = parser->pna + na + ns; |
|---|
| 754 | + int busflag_na = 0; |
|---|
| 755 | + |
|---|
| 756 | + if (!range) |
|---|
| 757 | + return NULL; |
|---|
| 758 | + |
|---|
| 759 | + if (!parser->range || parser->range + np > parser->end) |
|---|
| 760 | + return NULL; |
|---|
| 761 | + |
|---|
| 762 | + range->flags = parser->bus->get_flags(parser->range); |
|---|
| 763 | + |
|---|
| 764 | + /* A extra cell for resource flags */ |
|---|
| 765 | + if (parser->bus->has_flags) |
|---|
| 766 | + busflag_na = 1; |
|---|
| 767 | + |
|---|
| 768 | + range->bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na); |
|---|
| 769 | + |
|---|
| 770 | + if (parser->dma) |
|---|
| 771 | + range->cpu_addr = of_translate_dma_address(parser->node, |
|---|
| 772 | + parser->range + na); |
|---|
| 773 | + else |
|---|
| 774 | + range->cpu_addr = of_translate_address(parser->node, |
|---|
| 775 | + parser->range + na); |
|---|
| 776 | + range->size = of_read_number(parser->range + parser->pna + na, ns); |
|---|
| 777 | + |
|---|
| 778 | + parser->range += np; |
|---|
| 779 | + |
|---|
| 780 | + /* Now consume following elements while they are contiguous */ |
|---|
| 781 | + while (parser->range + np <= parser->end) { |
|---|
| 782 | + u32 flags = 0; |
|---|
| 783 | + u64 bus_addr, cpu_addr, size; |
|---|
| 784 | + |
|---|
| 785 | + flags = parser->bus->get_flags(parser->range); |
|---|
| 786 | + bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na); |
|---|
| 787 | + if (parser->dma) |
|---|
| 788 | + cpu_addr = of_translate_dma_address(parser->node, |
|---|
| 789 | + parser->range + na); |
|---|
| 790 | + else |
|---|
| 791 | + cpu_addr = of_translate_address(parser->node, |
|---|
| 792 | + parser->range + na); |
|---|
| 793 | + size = of_read_number(parser->range + parser->pna + na, ns); |
|---|
| 794 | + |
|---|
| 795 | + if (flags != range->flags) |
|---|
| 796 | + break; |
|---|
| 797 | + if (bus_addr != range->bus_addr + range->size || |
|---|
| 798 | + cpu_addr != range->cpu_addr + range->size) |
|---|
| 799 | + break; |
|---|
| 800 | + |
|---|
| 801 | + range->size += size; |
|---|
| 802 | + parser->range += np; |
|---|
| 803 | + } |
|---|
| 804 | + |
|---|
| 805 | + return range; |
|---|
| 806 | +} |
|---|
| 807 | +EXPORT_SYMBOL_GPL(of_pci_range_parser_one); |
|---|
| 808 | + |
|---|
| 732 | 809 | static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr, |
|---|
| 733 | 810 | u64 size) |
|---|
| 734 | 811 | { |
|---|
| .. | .. |
|---|
| 736 | 813 | unsigned long port; |
|---|
| 737 | 814 | struct device_node *host; |
|---|
| 738 | 815 | |
|---|
| 739 | | - taddr = __of_translate_address(dev, in_addr, "ranges", &host); |
|---|
| 816 | + taddr = __of_translate_address(dev, of_get_parent, |
|---|
| 817 | + in_addr, "ranges", &host); |
|---|
| 740 | 818 | if (host) { |
|---|
| 741 | 819 | /* host-specific port access */ |
|---|
| 742 | 820 | port = logic_pio_trans_hwaddr(&host->fwnode, taddr, size); |
|---|
| .. | .. |
|---|
| 804 | 882 | } |
|---|
| 805 | 883 | EXPORT_SYMBOL_GPL(of_address_to_resource); |
|---|
| 806 | 884 | |
|---|
| 807 | | -struct device_node *of_find_matching_node_by_address(struct device_node *from, |
|---|
| 808 | | - const struct of_device_id *matches, |
|---|
| 809 | | - u64 base_address) |
|---|
| 810 | | -{ |
|---|
| 811 | | - struct device_node *dn = of_find_matching_node(from, matches); |
|---|
| 812 | | - struct resource res; |
|---|
| 813 | | - |
|---|
| 814 | | - while (dn) { |
|---|
| 815 | | - if (!of_address_to_resource(dn, 0, &res) && |
|---|
| 816 | | - res.start == base_address) |
|---|
| 817 | | - return dn; |
|---|
| 818 | | - |
|---|
| 819 | | - dn = of_find_matching_node(dn, matches); |
|---|
| 820 | | - } |
|---|
| 821 | | - |
|---|
| 822 | | - return NULL; |
|---|
| 823 | | -} |
|---|
| 824 | | - |
|---|
| 825 | | - |
|---|
| 826 | 885 | /** |
|---|
| 827 | 886 | * of_iomap - Maps the memory mapped IO for a given device_node |
|---|
| 828 | | - * @device: the device whose io range will be mapped |
|---|
| 887 | + * @np: the device whose io range will be mapped |
|---|
| 829 | 888 | * @index: index of the io range |
|---|
| 830 | 889 | * |
|---|
| 831 | 890 | * Returns a pointer to the mapped memory |
|---|
| .. | .. |
|---|
| 879 | 938 | } |
|---|
| 880 | 939 | EXPORT_SYMBOL(of_io_request_and_map); |
|---|
| 881 | 940 | |
|---|
| 941 | +#ifdef CONFIG_HAS_DMA |
|---|
| 882 | 942 | /** |
|---|
| 883 | | - * of_dma_get_range - Get DMA range info |
|---|
| 943 | + * of_dma_get_range - Get DMA range info and put it into a map array |
|---|
| 884 | 944 | * @np: device node to get DMA range info |
|---|
| 885 | | - * @dma_addr: pointer to store initial DMA address of DMA range |
|---|
| 886 | | - * @paddr: pointer to store initial CPU address of DMA range |
|---|
| 887 | | - * @size: pointer to store size of DMA range |
|---|
| 945 | + * @map: dma range structure to return |
|---|
| 888 | 946 | * |
|---|
| 889 | 947 | * Look in bottom up direction for the first "dma-ranges" property |
|---|
| 890 | | - * and parse it. |
|---|
| 891 | | - * dma-ranges format: |
|---|
| 948 | + * and parse it. Put the information into a DMA offset map array. |
|---|
| 949 | + * |
|---|
| 950 | + * dma-ranges format: |
|---|
| 892 | 951 | * DMA addr (dma_addr) : naddr cells |
|---|
| 893 | 952 | * CPU addr (phys_addr_t) : pna cells |
|---|
| 894 | 953 | * size : nsize cells |
|---|
| 895 | 954 | * |
|---|
| 896 | | - * It returns -ENODEV if "dma-ranges" property was not found |
|---|
| 897 | | - * for this device in DT. |
|---|
| 955 | + * It returns -ENODEV if "dma-ranges" property was not found for this |
|---|
| 956 | + * device in the DT. |
|---|
| 898 | 957 | */ |
|---|
| 899 | | -int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size) |
|---|
| 958 | +int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) |
|---|
| 900 | 959 | { |
|---|
| 901 | 960 | struct device_node *node = of_node_get(np); |
|---|
| 902 | 961 | const __be32 *ranges = NULL; |
|---|
| 903 | | - int len, naddr, nsize, pna; |
|---|
| 962 | + bool found_dma_ranges = false; |
|---|
| 963 | + struct of_range_parser parser; |
|---|
| 964 | + struct of_range range; |
|---|
| 965 | + struct bus_dma_region *r; |
|---|
| 966 | + int len, num_ranges = 0; |
|---|
| 904 | 967 | int ret = 0; |
|---|
| 905 | | - u64 dmaaddr; |
|---|
| 906 | 968 | |
|---|
| 907 | | - if (!node) |
|---|
| 908 | | - return -EINVAL; |
|---|
| 909 | | - |
|---|
| 910 | | - while (1) { |
|---|
| 911 | | - naddr = of_n_addr_cells(node); |
|---|
| 912 | | - nsize = of_n_size_cells(node); |
|---|
| 913 | | - node = of_get_next_parent(node); |
|---|
| 914 | | - if (!node) |
|---|
| 915 | | - break; |
|---|
| 916 | | - |
|---|
| 969 | + while (node) { |
|---|
| 917 | 970 | ranges = of_get_property(node, "dma-ranges", &len); |
|---|
| 918 | 971 | |
|---|
| 919 | 972 | /* Ignore empty ranges, they imply no translation required */ |
|---|
| 920 | 973 | if (ranges && len > 0) |
|---|
| 921 | 974 | break; |
|---|
| 922 | 975 | |
|---|
| 923 | | - /* |
|---|
| 924 | | - * At least empty ranges has to be defined for parent node if |
|---|
| 925 | | - * DMA is supported |
|---|
| 926 | | - */ |
|---|
| 927 | | - if (!ranges) |
|---|
| 928 | | - break; |
|---|
| 976 | + /* Once we find 'dma-ranges', then a missing one is an error */ |
|---|
| 977 | + if (found_dma_ranges && !ranges) { |
|---|
| 978 | + ret = -ENODEV; |
|---|
| 979 | + goto out; |
|---|
| 980 | + } |
|---|
| 981 | + found_dma_ranges = true; |
|---|
| 982 | + |
|---|
| 983 | + node = of_get_next_dma_parent(node); |
|---|
| 929 | 984 | } |
|---|
| 930 | 985 | |
|---|
| 931 | | - if (!ranges) { |
|---|
| 986 | + if (!node || !ranges) { |
|---|
| 932 | 987 | pr_debug("no dma-ranges found for node(%pOF)\n", np); |
|---|
| 933 | 988 | ret = -ENODEV; |
|---|
| 934 | 989 | goto out; |
|---|
| 935 | 990 | } |
|---|
| 936 | 991 | |
|---|
| 937 | | - len /= sizeof(u32); |
|---|
| 992 | + of_dma_range_parser_init(&parser, node); |
|---|
| 993 | + for_each_of_range(&parser, &range) |
|---|
| 994 | + num_ranges++; |
|---|
| 938 | 995 | |
|---|
| 939 | | - pna = of_n_addr_cells(node); |
|---|
| 940 | | - |
|---|
| 941 | | - /* dma-ranges format: |
|---|
| 942 | | - * DMA addr : naddr cells |
|---|
| 943 | | - * CPU addr : pna cells |
|---|
| 944 | | - * size : nsize cells |
|---|
| 945 | | - */ |
|---|
| 946 | | - dmaaddr = of_read_number(ranges, naddr); |
|---|
| 947 | | - *paddr = of_translate_dma_address(np, ranges); |
|---|
| 948 | | - if (*paddr == OF_BAD_ADDR) { |
|---|
| 949 | | - pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n", |
|---|
| 950 | | - dma_addr, np); |
|---|
| 951 | | - ret = -EINVAL; |
|---|
| 996 | + r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL); |
|---|
| 997 | + if (!r) { |
|---|
| 998 | + ret = -ENOMEM; |
|---|
| 952 | 999 | goto out; |
|---|
| 953 | 1000 | } |
|---|
| 954 | | - *dma_addr = dmaaddr; |
|---|
| 955 | 1001 | |
|---|
| 956 | | - *size = of_read_number(ranges + naddr + pna, nsize); |
|---|
| 957 | | - |
|---|
| 958 | | - pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", |
|---|
| 959 | | - *dma_addr, *paddr, *size); |
|---|
| 960 | | - |
|---|
| 1002 | + /* |
|---|
| 1003 | + * Record all info in the generic DMA ranges array for struct device. |
|---|
| 1004 | + */ |
|---|
| 1005 | + *map = r; |
|---|
| 1006 | + of_dma_range_parser_init(&parser, node); |
|---|
| 1007 | + for_each_of_range(&parser, &range) { |
|---|
| 1008 | + pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", |
|---|
| 1009 | + range.bus_addr, range.cpu_addr, range.size); |
|---|
| 1010 | + if (range.cpu_addr == OF_BAD_ADDR) { |
|---|
| 1011 | + pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n", |
|---|
| 1012 | + range.bus_addr, node); |
|---|
| 1013 | + continue; |
|---|
| 1014 | + } |
|---|
| 1015 | + r->cpu_start = range.cpu_addr; |
|---|
| 1016 | + r->dma_start = range.bus_addr; |
|---|
| 1017 | + r->size = range.size; |
|---|
| 1018 | + r->offset = range.cpu_addr - range.bus_addr; |
|---|
| 1019 | + r++; |
|---|
| 1020 | + } |
|---|
| 961 | 1021 | out: |
|---|
| 962 | 1022 | of_node_put(node); |
|---|
| 963 | | - |
|---|
| 964 | 1023 | return ret; |
|---|
| 965 | 1024 | } |
|---|
| 966 | | -EXPORT_SYMBOL_GPL(of_dma_get_range); |
|---|
| 1025 | +#endif /* CONFIG_HAS_DMA */ |
|---|
| 1026 | + |
|---|
| 1027 | +/** |
|---|
| 1028 | + * of_dma_get_max_cpu_address - Gets highest CPU address suitable for DMA |
|---|
| 1029 | + * @np: The node to start searching from or NULL to start from the root |
|---|
| 1030 | + * |
|---|
| 1031 | + * Gets the highest CPU physical address that is addressable by all DMA masters |
|---|
| 1032 | + * in the sub-tree pointed by np, or the whole tree if NULL is passed. If no |
|---|
| 1033 | + * DMA constrained device is found, it returns PHYS_ADDR_MAX. |
|---|
| 1034 | + */ |
|---|
| 1035 | +phys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np) |
|---|
| 1036 | +{ |
|---|
| 1037 | + phys_addr_t max_cpu_addr = PHYS_ADDR_MAX; |
|---|
| 1038 | + struct of_range_parser parser; |
|---|
| 1039 | + phys_addr_t subtree_max_addr; |
|---|
| 1040 | + struct device_node *child; |
|---|
| 1041 | + struct of_range range; |
|---|
| 1042 | + const __be32 *ranges; |
|---|
| 1043 | + u64 cpu_end = 0; |
|---|
| 1044 | + int len; |
|---|
| 1045 | + |
|---|
| 1046 | + if (!np) |
|---|
| 1047 | + np = of_root; |
|---|
| 1048 | + |
|---|
| 1049 | + ranges = of_get_property(np, "dma-ranges", &len); |
|---|
| 1050 | + if (ranges && len) { |
|---|
| 1051 | + of_dma_range_parser_init(&parser, np); |
|---|
| 1052 | + for_each_of_range(&parser, &range) |
|---|
| 1053 | + if (range.cpu_addr + range.size > cpu_end) |
|---|
| 1054 | + cpu_end = range.cpu_addr + range.size - 1; |
|---|
| 1055 | + |
|---|
| 1056 | + if (max_cpu_addr > cpu_end) |
|---|
| 1057 | + max_cpu_addr = cpu_end; |
|---|
| 1058 | + } |
|---|
| 1059 | + |
|---|
| 1060 | + for_each_available_child_of_node(np, child) { |
|---|
| 1061 | + subtree_max_addr = of_dma_get_max_cpu_address(child); |
|---|
| 1062 | + if (max_cpu_addr > subtree_max_addr) |
|---|
| 1063 | + max_cpu_addr = subtree_max_addr; |
|---|
| 1064 | + } |
|---|
| 1065 | + |
|---|
| 1066 | + return max_cpu_addr; |
|---|
| 1067 | +} |
|---|
| 967 | 1068 | |
|---|
| 968 | 1069 | /** |
|---|
| 969 | 1070 | * of_dma_is_coherent - Check if device is coherent |
|---|
| .. | .. |
|---|
| 987 | 1088 | of_node_put(node); |
|---|
| 988 | 1089 | return true; |
|---|
| 989 | 1090 | } |
|---|
| 990 | | - node = of_get_next_parent(node); |
|---|
| 1091 | + node = of_get_next_dma_parent(node); |
|---|
| 991 | 1092 | } |
|---|
| 992 | 1093 | of_node_put(node); |
|---|
| 993 | 1094 | return false; |
|---|