This is a note to let you know that I've just added the patch titled PCI: mvebu: split PCIe BARs into multiple MBus windows when needed to the 3.14-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: pci-mvebu-split-pcie-bars-into-multiple-mbus-windows-when-needed.patch and it can be found in the queue-3.14 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From 398f5d5e10b6b917cd9d35ef21d545b0afbada22 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni <thomas.petazzoni@xxxxxxxxxxxxxxxxxx> Date: Fri, 18 Apr 2014 14:19:53 +0200 Subject: PCI: mvebu: split PCIe BARs into multiple MBus windows when needed From: Thomas Petazzoni <thomas.petazzoni@xxxxxxxxxxxxxxxxxx> commit 398f5d5e10b6b917cd9d35ef21d545b0afbada22 upstream. MBus windows are used on Marvell platforms to map certain peripherals in the physical address space. In the PCIe context, MBus windows are needed to map PCIe I/O and memory regions in the physical address. However, those MBus windows can only have power of two sizes, while PCIe BAR do not necessarily guarantee this. For this reason, the current pci-mvebu breaks on platforms where PCIe devices have BARs that don't sum up to a power of two size at the emulated bridge level. This commit fixes this by allowing the pci-mvebu driver to create multiple contiguous MBus windows (each having a power of two size) to cover a given PCIe BAR. To achieve this, two functions are added: mvebu_pcie_add_windows() and mvebu_pcie_del_windows() to respectively add and remove all the MBus windows that are needed to map the provided PCIe region base and size. The emulated PCI bridge code now calls those functions, instead of directly calling the mvebu-mbus driver functions. Fixes: 45361a4fe446 ('pci: PCIe driver for Marvell Armada 370/XP systems') Signed-off-by: Thomas Petazzoni <thomas.petazzoni@xxxxxxxxxxxxxxxxxx> Link: https://lkml.kernel.org/r/1397823593-1932-8-git-send-email-thomas.petazzoni@xxxxxxxxxxxxxxxxxx Tested-by: Neil Greatorex <neil@xxxxxxxxxxxxxxx> Acked-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx> Signed-off-by: Jason Cooper <jason@xxxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/pci/host/pci-mvebu.c | 88 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 14 deletions(-) --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -291,6 +291,58 @@ static int mvebu_pcie_hw_wr_conf(struct return PCIBIOS_SUCCESSFUL; } +/* + * Remove windows, starting from the largest ones to the smallest + * ones. + */ +static void mvebu_pcie_del_windows(struct mvebu_pcie_port *port, + phys_addr_t base, size_t size) +{ + while (size) { + size_t sz = 1 << (fls(size) - 1); + + mvebu_mbus_del_window(base, sz); + base += sz; + size -= sz; + } +} + +/* + * MBus windows can only have a power of two size, but PCI BARs do not + * have this constraint. Therefore, we have to split the PCI BAR into + * areas each having a power of two size. We start from the largest + * one (i.e highest order bit set in the size). + */ +static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port, + unsigned int target, unsigned int attribute, + phys_addr_t base, size_t size, + phys_addr_t remap) +{ + size_t size_mapped = 0; + + while (size) { + size_t sz = 1 << (fls(size) - 1); + int ret; + + ret = mvebu_mbus_add_window_remap_by_id(target, attribute, base, + sz, remap); + if (ret) { + dev_err(&port->pcie->pdev->dev, + "Could not create MBus window at 0x%x, size 0x%x: %d\n", + base, sz, ret); + mvebu_pcie_del_windows(port, base - size_mapped, + size_mapped); + return; + } + + size -= sz; + size_mapped += sz; + base += sz; + if (remap != MVEBU_MBUS_NO_REMAP) + remap += sz; + } +} + static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) { phys_addr_t iobase; @@ -302,8 +354,8 @@ static void mvebu_pcie_handle_iobase_cha /* If a window was configured, remove it */ if (port->iowin_base) { - mvebu_mbus_del_window(port->iowin_base, - port->iowin_size); + mvebu_pcie_del_windows(port, port->iowin_base, + port->iowin_size); port->iowin_base = 0; port->iowin_size = 0; } @@ -331,9 +383,9 @@ static void mvebu_pcie_handle_iobase_cha (port->bridge.iolimitupper << 16)) - iobase) + 1; - mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, - port->iowin_base, port->iowin_size, - iobase); + mvebu_pcie_add_windows(port, port->io_target, port->io_attr, + port->iowin_base, port->iowin_size, + iobase); } static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) @@ -344,8 +396,8 @@ static void mvebu_pcie_handle_membase_ch /* If a window was configured, remove it */ if (port->memwin_base) { - mvebu_mbus_del_window(port->memwin_base, - port->memwin_size); + mvebu_pcie_del_windows(port, port->memwin_base, + port->memwin_size); port->memwin_base = 0; port->memwin_size = 0; } @@ -364,8 +416,9 @@ static void mvebu_pcie_handle_membase_ch (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - port->memwin_base + 1; - mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr, - port->memwin_base, port->memwin_size); + mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr, + port->memwin_base, port->memwin_size, + MVEBU_MBUS_NO_REMAP); } /* @@ -721,14 +774,21 @@ static resource_size_t mvebu_pcie_align_ /* * On the PCI-to-PCI bridge side, the I/O windows must have at - * least a 64 KB size and be aligned on their size, and the - * memory windows must have at least a 1 MB size and be - * aligned on their size + * least a 64 KB size and the memory windows must have at + * least a 1 MB size. Moreover, MBus windows need to have a + * base address aligned on their size, and their size must be + * a power of two. This means that if the BAR doesn't have a + * power of two size, several MBus windows will actually be + * created. We need to ensure that the biggest MBus window + * (which will be the first one) is aligned on its size, which + * explains the rounddown_pow_of_two() being done here. */ if (res->flags & IORESOURCE_IO) - return round_up(start, max_t(resource_size_t, SZ_64K, size)); + return round_up(start, max_t(resource_size_t, SZ_64K, + rounddown_pow_of_two(size))); else if (res->flags & IORESOURCE_MEM) - return round_up(start, max_t(resource_size_t, SZ_1M, size)); + return round_up(start, max_t(resource_size_t, SZ_1M, + rounddown_pow_of_two(size))); else return start; } Patches currently in stable-queue which might be from thomas.petazzoni@xxxxxxxxxxxxxxxxxx are queue-3.14/pci-mvebu-fix-off-by-one-in-the-computed-size-of-the-mbus-windows.patch queue-3.14/arm-orion5x-fix-target-id-for-crypto-sram-window.patch queue-3.14/arm-mvebu-fix-nor-bus-width-in-armada-xp-db-device-tree.patch queue-3.14/arm-mvebu-mvebu-soc-id-keep-clock-enabled-if-pcie-unit-is-enabled.patch queue-3.14/irqchip-armada-370-xp-fix-releasing-of-msis.patch queue-3.14/pci-mvebu-split-pcie-bars-into-multiple-mbus-windows-when-needed.patch queue-3.14/memory-mvebu-devbus-fix-the-conversion-of-the-bus-width.patch queue-3.14/irqchip-armada-370-xp-implement-the-check_device-msi_chip-operation.patch queue-3.14/arm-mvebu-mvebu-soc-id-add-missing-clk_put-call.patch queue-3.14/irqchip-armada-370-xp-fix-invalid-cast-of-signed-value-into-unsigned-variable.patch queue-3.14/bus-mvebu-mbus-allow-several-windows-with-the-same-target-attribute.patch queue-3.14/arm-mvebu-fix-nor-bus-width-in-armada-xp-gp-device-tree.patch queue-3.14/arm-mvebu-fix-nor-bus-width-in-armada-xp-openblocks-ax3-device-tree.patch -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html