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>
This commit is contained in:
Jason Gunthorpe 2013-11-26 11:02:54 -07:00 committed by Bjorn Helgaas
parent 2850b05c96
commit 43a16f9444

View File

@ -300,7 +300,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
/* Are the new iobase/iolimit values invalid? */ /* Are the new iobase/iolimit values invalid? */
if (port->bridge.iolimit < port->bridge.iobase || if (port->bridge.iolimit < port->bridge.iobase ||
port->bridge.iolimitupper < port->bridge.iobaseupper) { port->bridge.iolimitupper < port->bridge.iobaseupper ||
!(port->bridge.command & PCI_COMMAND_IO)) {
/* If a window was configured, remove it */ /* If a window was configured, remove it */
if (port->iowin_base) { if (port->iowin_base) {
@ -337,7 +338,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
{ {
/* Are the new membase/memlimit values invalid? */ /* Are the new membase/memlimit values invalid? */
if (port->bridge.memlimit < port->bridge.membase) { if (port->bridge.memlimit < port->bridge.membase ||
!(port->bridge.command & PCI_COMMAND_MEMORY)) {
/* If a window was configured, remove it */ /* If a window was configured, remove it */
if (port->memwin_base) { if (port->memwin_base) {
@ -485,8 +487,16 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
switch (where & ~3) { switch (where & ~3) {
case PCI_COMMAND: case PCI_COMMAND:
{
u32 old = bridge->command;
bridge->command = value & 0xffff; bridge->command = value & 0xffff;
if ((old ^ bridge->command) & PCI_COMMAND_IO)
mvebu_pcie_handle_iobase_change(port);
if ((old ^ bridge->command) & PCI_COMMAND_MEMORY)
mvebu_pcie_handle_membase_change(port);
break; break;
}
case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value; bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value;