diff options
author | Jason Gunthorpe <jgunthorpe@obsidianresearch.com> | 2013-11-26 13:02:54 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-11-26 13:36:32 -0500 |
commit | 43a16f94445310800e39d54aaa534f2ce7dbe0a2 (patch) | |
tree | c95e9e765dbbd61731a58a534f2e59684533211d /drivers | |
parent | 2850b05c9644d0f4c9df6cc77d628d7e0598a0cc (diff) |
PCI: mvebu: Obey bridge PCI_COMMAND_MEM and PCI_COMMAND_IO bits
When PCI_COMMAND_MEMORY/PCI_COMMAND_IO are cleared, the bridge should not
allocate windows or even look at the window limit/base registers.
Otherwise we may set up bogus windows while the PCI core code performs
discovery. The core will leave PCI_COMMAND_IO cleared if it doesn't need
an IO window.
Have mvebu_pcie_handle_*_change respect the bits, and call the change
function whenever the bits changes.
Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/host/pci-mvebu.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 6f5a20f3cdf6..94294123e7bd 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c | |||
@@ -300,7 +300,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) | |||
300 | 300 | ||
301 | /* Are the new iobase/iolimit values invalid? */ | 301 | /* Are the new iobase/iolimit values invalid? */ |
302 | if (port->bridge.iolimit < port->bridge.iobase || | 302 | if (port->bridge.iolimit < port->bridge.iobase || |
303 | port->bridge.iolimitupper < port->bridge.iobaseupper) { | 303 | port->bridge.iolimitupper < port->bridge.iobaseupper || |
304 | !(port->bridge.command & PCI_COMMAND_IO)) { | ||
304 | 305 | ||
305 | /* If a window was configured, remove it */ | 306 | /* If a window was configured, remove it */ |
306 | if (port->iowin_base) { | 307 | if (port->iowin_base) { |
@@ -337,7 +338,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) | |||
337 | static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) | 338 | static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) |
338 | { | 339 | { |
339 | /* Are the new membase/memlimit values invalid? */ | 340 | /* Are the new membase/memlimit values invalid? */ |
340 | if (port->bridge.memlimit < port->bridge.membase) { | 341 | if (port->bridge.memlimit < port->bridge.membase || |
342 | !(port->bridge.command & PCI_COMMAND_MEMORY)) { | ||
341 | 343 | ||
342 | /* If a window was configured, remove it */ | 344 | /* If a window was configured, remove it */ |
343 | if (port->memwin_base) { | 345 | if (port->memwin_base) { |
@@ -485,8 +487,16 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, | |||
485 | 487 | ||
486 | switch (where & ~3) { | 488 | switch (where & ~3) { |
487 | case PCI_COMMAND: | 489 | case PCI_COMMAND: |
490 | { | ||
491 | u32 old = bridge->command; | ||
492 | |||
488 | bridge->command = value & 0xffff; | 493 | bridge->command = value & 0xffff; |
494 | if ((old ^ bridge->command) & PCI_COMMAND_IO) | ||
495 | mvebu_pcie_handle_iobase_change(port); | ||
496 | if ((old ^ bridge->command) & PCI_COMMAND_MEMORY) | ||
497 | mvebu_pcie_handle_membase_change(port); | ||
489 | break; | 498 | break; |
499 | } | ||
490 | 500 | ||
491 | case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: | 501 | case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: |
492 | bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value; | 502 | bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value; |