Skip to content

Commit d9bf28e

Browse files
jgunthorpebjorn-helgaas
authored andcommitted
PCI: mvebu: Handle changes to the bridge windows while enabled
The PCI core will write to the bridge window config multiple times while they are enabled. This can lead to mbus failures like this: mvebu_mbus: cannot add window '4:e8', conflicts with another window mvebu-pcie mbus:pex@e0000000: Could not create MBus window at [mem 0xe0000000-0xe00fffff]: -22 For me this is happening during a hotplug cycle. The PCI core is not changing the values, just writing them twice while active. The patch addresses the general case of any change to an active window, but not atomically. The code is slightly refactored so io and mem can share more of the window logic. Signed-off-by: Jason Gunthorpe <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Acked-by: Jason Cooper <[email protected]>
1 parent 7ce7d89 commit d9bf28e

File tree

1 file changed

+60
-41
lines changed

1 file changed

+60
-41
lines changed

drivers/pci/host/pci-mvebu.c

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ struct mvebu_pcie {
133133
int nports;
134134
};
135135

136+
struct mvebu_pcie_window {
137+
phys_addr_t base;
138+
phys_addr_t remap;
139+
size_t size;
140+
};
141+
136142
/* Structure representing one PCIe interface */
137143
struct mvebu_pcie_port {
138144
char *name;
@@ -150,10 +156,8 @@ struct mvebu_pcie_port {
150156
struct mvebu_sw_pci_bridge bridge;
151157
struct device_node *dn;
152158
struct mvebu_pcie *pcie;
153-
phys_addr_t memwin_base;
154-
size_t memwin_size;
155-
phys_addr_t iowin_base;
156-
size_t iowin_size;
159+
struct mvebu_pcie_window memwin;
160+
struct mvebu_pcie_window iowin;
157161
u32 saved_pcie_stat;
158162
};
159163

@@ -379,23 +383,45 @@ static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
379383
}
380384
}
381385

386+
static void mvebu_pcie_set_window(struct mvebu_pcie_port *port,
387+
unsigned int target, unsigned int attribute,
388+
const struct mvebu_pcie_window *desired,
389+
struct mvebu_pcie_window *cur)
390+
{
391+
if (desired->base == cur->base && desired->remap == cur->remap &&
392+
desired->size == cur->size)
393+
return;
394+
395+
if (cur->size != 0) {
396+
mvebu_pcie_del_windows(port, cur->base, cur->size);
397+
cur->size = 0;
398+
cur->base = 0;
399+
400+
/*
401+
* If something tries to change the window while it is enabled
402+
* the change will not be done atomically. That would be
403+
* difficult to do in the general case.
404+
*/
405+
}
406+
407+
if (desired->size == 0)
408+
return;
409+
410+
mvebu_pcie_add_windows(port, target, attribute, desired->base,
411+
desired->size, desired->remap);
412+
*cur = *desired;
413+
}
414+
382415
static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
383416
{
384-
phys_addr_t iobase;
417+
struct mvebu_pcie_window desired = {};
385418

386419
/* Are the new iobase/iolimit values invalid? */
387420
if (port->bridge.iolimit < port->bridge.iobase ||
388421
port->bridge.iolimitupper < port->bridge.iobaseupper ||
389422
!(port->bridge.command & PCI_COMMAND_IO)) {
390-
391-
/* If a window was configured, remove it */
392-
if (port->iowin_base) {
393-
mvebu_pcie_del_windows(port, port->iowin_base,
394-
port->iowin_size);
395-
port->iowin_base = 0;
396-
port->iowin_size = 0;
397-
}
398-
423+
mvebu_pcie_set_window(port, port->io_target, port->io_attr,
424+
&desired, &port->iowin);
399425
return;
400426
}
401427

@@ -412,32 +438,27 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
412438
* specifications. iobase is the bus address, port->iowin_base
413439
* is the CPU address.
414440
*/
415-
iobase = ((port->bridge.iobase & 0xF0) << 8) |
416-
(port->bridge.iobaseupper << 16);
417-
port->iowin_base = port->pcie->io.start + iobase;
418-
port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
419-
(port->bridge.iolimitupper << 16)) -
420-
iobase) + 1;
421-
422-
mvebu_pcie_add_windows(port, port->io_target, port->io_attr,
423-
port->iowin_base, port->iowin_size,
424-
iobase);
441+
desired.remap = ((port->bridge.iobase & 0xF0) << 8) |
442+
(port->bridge.iobaseupper << 16);
443+
desired.base = port->pcie->io.start + desired.remap;
444+
desired.size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
445+
(port->bridge.iolimitupper << 16)) -
446+
desired.remap) +
447+
1;
448+
449+
mvebu_pcie_set_window(port, port->io_target, port->io_attr, &desired,
450+
&port->iowin);
425451
}
426452

427453
static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
428454
{
455+
struct mvebu_pcie_window desired = {.remap = MVEBU_MBUS_NO_REMAP};
456+
429457
/* Are the new membase/memlimit values invalid? */
430458
if (port->bridge.memlimit < port->bridge.membase ||
431459
!(port->bridge.command & PCI_COMMAND_MEMORY)) {
432-
433-
/* If a window was configured, remove it */
434-
if (port->memwin_base) {
435-
mvebu_pcie_del_windows(port, port->memwin_base,
436-
port->memwin_size);
437-
port->memwin_base = 0;
438-
port->memwin_size = 0;
439-
}
440-
460+
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
461+
&desired, &port->memwin);
441462
return;
442463
}
443464

@@ -447,14 +468,12 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
447468
* window to setup, according to the PCI-to-PCI bridge
448469
* specifications.
449470
*/
450-
port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16);
451-
port->memwin_size =
452-
(((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
453-
port->memwin_base + 1;
454-
455-
mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr,
456-
port->memwin_base, port->memwin_size,
457-
MVEBU_MBUS_NO_REMAP);
471+
desired.base = ((port->bridge.membase & 0xFFF0) << 16);
472+
desired.size = (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
473+
desired.base + 1;
474+
475+
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired,
476+
&port->memwin);
458477
}
459478

460479
/*

0 commit comments

Comments
 (0)