From 90b1f963b07d05e8243e5053a910e8a47222f7a1 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 5 Jul 2013 14:54:17 +0200 Subject: [PATCH 047/203] PCI: mvebu: Adapt to the new device tree layout The new device tree layout encodes the window's target ID and attribute in the PCIe controller node's ranges property. This allows to parse such entries to obtain such information and use the recently introduced MBus API to create the windows, instead of using the current name based scheme. Acked-by: Bjorn Helgaas Signed-off-by: Thomas Petazzoni Tested-by: Andrew Lunn Tested-by: Sebastian Hesselbarth --- drivers/pci/host/pci-mvebu.c | 113 ++++++++++++++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 29 deletions(-) --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -119,6 +119,10 @@ struct mvebu_pcie_port { u32 port; u32 lane; int devfn; + unsigned int mem_target; + unsigned int mem_attr; + unsigned int io_target; + unsigned int io_attr; struct clk *clk; struct mvebu_sw_pci_bridge bridge; struct device_node *dn; @@ -303,10 +307,9 @@ static void mvebu_pcie_handle_iobase_cha (port->bridge.iolimitupper << 16)) - iobase); - mvebu_mbus_add_window_remap_flags(port->name, port->iowin_base, - port->iowin_size, - iobase, - MVEBU_MBUS_PCI_IO); + mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, + port->iowin_base, port->iowin_size, + iobase); pci_ioremap_io(iobase, port->iowin_base); } @@ -338,10 +341,8 @@ static void mvebu_pcie_handle_membase_ch (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - port->memwin_base; - mvebu_mbus_add_window_remap_flags(port->name, port->memwin_base, - port->memwin_size, - MVEBU_MBUS_NO_REMAP, - MVEBU_MBUS_PCI_MEM); + mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr, + port->memwin_base, port->memwin_size); } /* @@ -730,12 +731,54 @@ mvebu_pcie_map_registers(struct platform return devm_request_and_ioremap(&pdev->dev, ®s); } +#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03) +#define DT_TYPE_IO 0x1 +#define DT_TYPE_MEM32 0x2 +#define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF) +#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF) + +static int mvebu_get_tgt_attr(struct device_node *np, int devfn, + unsigned long type, int *tgt, int *attr) +{ + const int na = 3, ns = 2; + const __be32 *range; + int rlen, nranges, rangesz, pna, i; + + range = of_get_property(np, "ranges", &rlen); + if (!range) + return -EINVAL; + + pna = of_n_addr_cells(np); + rangesz = pna + na + ns; + nranges = rlen / sizeof(__be32) / rangesz; + + for (i = 0; i < nranges; i++) { + u32 flags = of_read_number(range, 1); + u32 slot = of_read_number(range, 2); + u64 cpuaddr = of_read_number(range + na, pna); + unsigned long rtype; + + if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_IO) + rtype = IORESOURCE_IO; + else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32) + rtype = IORESOURCE_MEM; + + if (slot == PCI_SLOT(devfn) && type == rtype) { + *tgt = DT_CPUADDR_TO_TARGET(cpuaddr); + *attr = DT_CPUADDR_TO_ATTR(cpuaddr); + return 0; + } + + range += rangesz; + } + + return -ENOENT; +} + static int __init mvebu_pcie_probe(struct platform_device *pdev) { struct mvebu_pcie *pcie; struct device_node *np = pdev->dev.of_node; - struct of_pci_range range; - struct of_pci_range_parser parser; struct device_node *child; int i, ret; @@ -746,29 +789,25 @@ static int __init mvebu_pcie_probe(struc pcie->pdev = pdev; - if (of_pci_range_parser_init(&parser, np)) + /* Get the PCIe memory and I/O aperture */ + mvebu_mbus_get_pcie_mem_aperture(&pcie->mem); + if (resource_size(&pcie->mem) == 0) { + dev_err(&pdev->dev, "invalid memory aperture size\n"); return -EINVAL; + } - /* Get the I/O and memory ranges from DT */ - for_each_of_pci_range(&parser, &range) { - unsigned long restype = range.flags & IORESOURCE_TYPE_BITS; - if (restype == IORESOURCE_IO) { - of_pci_range_to_resource(&range, np, &pcie->io); - of_pci_range_to_resource(&range, np, &pcie->realio); - pcie->io.name = "I/O"; - pcie->realio.start = max_t(resource_size_t, - PCIBIOS_MIN_IO, - range.pci_addr); - pcie->realio.end = min_t(resource_size_t, - IO_SPACE_LIMIT, - range.pci_addr + range.size); - } - if (restype == IORESOURCE_MEM) { - of_pci_range_to_resource(&range, np, &pcie->mem); - pcie->mem.name = "MEM"; - } + mvebu_mbus_get_pcie_io_aperture(&pcie->io); + if (resource_size(&pcie->io) == 0) { + dev_err(&pdev->dev, "invalid I/O aperture size\n"); + return -EINVAL; } + pcie->realio.flags = pcie->io.flags; + pcie->realio.start = PCIBIOS_MIN_IO; + pcie->realio.end = min_t(resource_size_t, + IO_SPACE_LIMIT, + resource_size(&pcie->io)); + /* Get the bus range */ ret = of_pci_parse_bus_range(np, &pcie->busn); if (ret) { @@ -816,6 +855,22 @@ static int __init mvebu_pcie_probe(struc if (port->devfn < 0) continue; + ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_MEM, + &port->mem_target, &port->mem_attr); + if (ret < 0) { + dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for mem window\n", + port->port, port->lane); + continue; + } + + ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO, + &port->io_target, &port->io_attr); + if (ret < 0) { + dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for io window\n", + port->port, port->lane); + continue; + } + port->base = mvebu_pcie_map_registers(pdev, child, port); if (!port->base) { dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",