aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/host/pci-mvebu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/host/pci-mvebu.c')
-rw-r--r--drivers/pci/host/pci-mvebu.c92
1 files changed, 76 insertions, 16 deletions
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index d3d1cfd51e09..e384e2534594 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -293,6 +293,58 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port,
293 return PCIBIOS_SUCCESSFUL; 293 return PCIBIOS_SUCCESSFUL;
294} 294}
295 295
296/*
297 * Remove windows, starting from the largest ones to the smallest
298 * ones.
299 */
300static void mvebu_pcie_del_windows(struct mvebu_pcie_port *port,
301 phys_addr_t base, size_t size)
302{
303 while (size) {
304 size_t sz = 1 << (fls(size) - 1);
305
306 mvebu_mbus_del_window(base, sz);
307 base += sz;
308 size -= sz;
309 }
310}
311
312/*
313 * MBus windows can only have a power of two size, but PCI BARs do not
314 * have this constraint. Therefore, we have to split the PCI BAR into
315 * areas each having a power of two size. We start from the largest
316 * one (i.e highest order bit set in the size).
317 */
318static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
319 unsigned int target, unsigned int attribute,
320 phys_addr_t base, size_t size,
321 phys_addr_t remap)
322{
323 size_t size_mapped = 0;
324
325 while (size) {
326 size_t sz = 1 << (fls(size) - 1);
327 int ret;
328
329 ret = mvebu_mbus_add_window_remap_by_id(target, attribute, base,
330 sz, remap);
331 if (ret) {
332 dev_err(&port->pcie->pdev->dev,
333 "Could not create MBus window at 0x%x, size 0x%x: %d\n",
334 base, sz, ret);
335 mvebu_pcie_del_windows(port, base - size_mapped,
336 size_mapped);
337 return;
338 }
339
340 size -= sz;
341 size_mapped += sz;
342 base += sz;
343 if (remap != MVEBU_MBUS_NO_REMAP)
344 remap += sz;
345 }
346}
347
296static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) 348static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
297{ 349{
298 phys_addr_t iobase; 350 phys_addr_t iobase;
@@ -304,8 +356,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
304 356
305 /* If a window was configured, remove it */ 357 /* If a window was configured, remove it */
306 if (port->iowin_base) { 358 if (port->iowin_base) {
307 mvebu_mbus_del_window(port->iowin_base, 359 mvebu_pcie_del_windows(port, port->iowin_base,
308 port->iowin_size); 360 port->iowin_size);
309 port->iowin_base = 0; 361 port->iowin_base = 0;
310 port->iowin_size = 0; 362 port->iowin_size = 0;
311 } 363 }
@@ -331,11 +383,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
331 port->iowin_base = port->pcie->io.start + iobase; 383 port->iowin_base = port->pcie->io.start + iobase;
332 port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) | 384 port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
333 (port->bridge.iolimitupper << 16)) - 385 (port->bridge.iolimitupper << 16)) -
334 iobase); 386 iobase) + 1;
335 387
336 mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, 388 mvebu_pcie_add_windows(port, port->io_target, port->io_attr,
337 port->iowin_base, port->iowin_size, 389 port->iowin_base, port->iowin_size,
338 iobase); 390 iobase);
339} 391}
340 392
341static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) 393static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
@@ -346,8 +398,8 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
346 398
347 /* If a window was configured, remove it */ 399 /* If a window was configured, remove it */
348 if (port->memwin_base) { 400 if (port->memwin_base) {
349 mvebu_mbus_del_window(port->memwin_base, 401 mvebu_pcie_del_windows(port, port->memwin_base,
350 port->memwin_size); 402 port->memwin_size);
351 port->memwin_base = 0; 403 port->memwin_base = 0;
352 port->memwin_size = 0; 404 port->memwin_size = 0;
353 } 405 }
@@ -364,10 +416,11 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
364 port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16); 416 port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16);
365 port->memwin_size = 417 port->memwin_size =
366 (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - 418 (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
367 port->memwin_base; 419 port->memwin_base + 1;
368 420
369 mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr, 421 mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr,
370 port->memwin_base, port->memwin_size); 422 port->memwin_base, port->memwin_size,
423 MVEBU_MBUS_NO_REMAP);
371} 424}
372 425
373/* 426/*
@@ -743,14 +796,21 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
743 796
744 /* 797 /*
745 * On the PCI-to-PCI bridge side, the I/O windows must have at 798 * On the PCI-to-PCI bridge side, the I/O windows must have at
746 * least a 64 KB size and be aligned on their size, and the 799 * least a 64 KB size and the memory windows must have at
747 * memory windows must have at least a 1 MB size and be 800 * least a 1 MB size. Moreover, MBus windows need to have a
748 * aligned on their size 801 * base address aligned on their size, and their size must be
802 * a power of two. This means that if the BAR doesn't have a
803 * power of two size, several MBus windows will actually be
804 * created. We need to ensure that the biggest MBus window
805 * (which will be the first one) is aligned on its size, which
806 * explains the rounddown_pow_of_two() being done here.
749 */ 807 */
750 if (res->flags & IORESOURCE_IO) 808 if (res->flags & IORESOURCE_IO)
751 return round_up(start, max_t(resource_size_t, SZ_64K, size)); 809 return round_up(start, max_t(resource_size_t, SZ_64K,
810 rounddown_pow_of_two(size)));
752 else if (res->flags & IORESOURCE_MEM) 811 else if (res->flags & IORESOURCE_MEM)
753 return round_up(start, max_t(resource_size_t, SZ_1M, size)); 812 return round_up(start, max_t(resource_size_t, SZ_1M,
813 rounddown_pow_of_two(size)));
754 else 814 else
755 return start; 815 return start;
756} 816}