[PATCH v7 2/6] pci: OF: Fix the conversion of IO ranges into IO resources.
flat view
From: arnd@arndb.de (Arnd Bergmann)
Date: 2014-03-14 18:46:42
Also in:
linux-devicetree, linux-pci, lkml
On Friday 14 March 2014, Liviu Dudau wrote:
You are right, that was lazy of me. What about this version?
Yes, that seems better. Thanks for fixing it up. But back to the more important question that I realized we have not resolved yet: You now have two completely independent allocation functions for logical I/O space numbers, and they will return different numbers for any nontrivial scenario.
quoted hunk ↗ jump to hunk
+int of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, struct resource *res) +{ + res->flags = range->flags; + res->parent = res->child = res->sibling = NULL; + res->name = np->full_name; + + if (res->flags & IORESOURCE_IO) { + unsigned long port = -1; + int err = pci_register_io_range(range->cpu_addr, range->size); + if (err) + goto invalid_range; + port = pci_address_to_pio(range->cpu_addr); + if (port == (unsigned long)-1) { + err = -EINVAL; + goto invalid_range; + } + res->start = port; + } else {
This one concatenates the I/O spaces and assumes that each space starts at bus address zero, and takes little precaution to avoid filling up IO_SPACE_LIMIT if the sizes are too big.
quoted hunk ↗ jump to hunk
+unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr) +{ + unsigned long start, len, virt_start; + int err; + + if (res->end > IO_SPACE_LIMIT) + return -EINVAL; + + /* + * try finding free space for the whole size first, + * fall back to 64K if not available + */ + len = resource_size(res); + start = bitmap_find_next_zero_area(pci_iospace, IO_SPACE_PAGES, + res->start / PAGE_SIZE, len / PAGE_SIZE, 0); + if (start == IO_SPACE_PAGES && len > SZ_64K) { + len = SZ_64K; + start = 0; + start = bitmap_find_next_zero_area(pci_iospace, IO_SPACE_PAGES, + start, len / PAGE_SIZE, 0); + } + + /* no 64K area found */ + if (start == IO_SPACE_PAGES) + return -ENOMEM; + + /* ioremap physical aperture to virtual aperture */ + virt_start = start * PAGE_SIZE + (unsigned long)PCI_IOBASE; + err = ioremap_page_range(virt_start, virt_start + len, + phys_addr, __pgprot(PROT_DEVICE_nGnRE)); + if (err) + return err; + + bitmap_set(pci_iospace, start, len / PAGE_SIZE); + + /* return io_offset */ + return start * PAGE_SIZE - res->start; +}
While this one will try to fall back to smaller sizes, and will honor nonzero bus addresses. I think we shouldn't even try to do the same thing twice, but instead just use a single allocator. I'd prefer the one I came up with, but I realize that I am biased here ;-) Arnd