Merge branch 'pci/host-mvebu' into next

* pci/host-mvebu:
  PCI: mvebu: Change delay after reset to the PCIe spec mandated 100ms
  PCI: mvebu: Handle changes to the bridge windows while enabled
This commit is contained in:
Bjorn Helgaas 2017-02-21 15:15:34 -06:00
commit dda718926c
2 changed files with 61 additions and 41 deletions

View File

@ -78,7 +78,8 @@ and the following optional properties:
multiple lanes. If this property is not found, we assume that the
value is 0.
- reset-gpios: optional gpio to PERST#
- reset-delay-us: delay in us to wait after reset de-assertion
- reset-delay-us: delay in us to wait after reset de-assertion, if not
specified will default to 100ms, as required by the PCIe specification.
Example:

View File

@ -133,6 +133,12 @@ struct mvebu_pcie {
int nports;
};
struct mvebu_pcie_window {
phys_addr_t base;
phys_addr_t remap;
size_t size;
};
/* Structure representing one PCIe interface */
struct mvebu_pcie_port {
char *name;
@ -150,10 +156,8 @@ struct mvebu_pcie_port {
struct mvebu_sw_pci_bridge bridge;
struct device_node *dn;
struct mvebu_pcie *pcie;
phys_addr_t memwin_base;
size_t memwin_size;
phys_addr_t iowin_base;
size_t iowin_size;
struct mvebu_pcie_window memwin;
struct mvebu_pcie_window iowin;
u32 saved_pcie_stat;
};
@ -379,23 +383,45 @@ static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
}
}
static void mvebu_pcie_set_window(struct mvebu_pcie_port *port,
unsigned int target, unsigned int attribute,
const struct mvebu_pcie_window *desired,
struct mvebu_pcie_window *cur)
{
if (desired->base == cur->base && desired->remap == cur->remap &&
desired->size == cur->size)
return;
if (cur->size != 0) {
mvebu_pcie_del_windows(port, cur->base, cur->size);
cur->size = 0;
cur->base = 0;
/*
* If something tries to change the window while it is enabled
* the change will not be done atomically. That would be
* difficult to do in the general case.
*/
}
if (desired->size == 0)
return;
mvebu_pcie_add_windows(port, target, attribute, desired->base,
desired->size, desired->remap);
*cur = *desired;
}
static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
{
phys_addr_t iobase;
struct mvebu_pcie_window desired = {};
/* Are the new iobase/iolimit values invalid? */
if (port->bridge.iolimit < port->bridge.iobase ||
port->bridge.iolimitupper < port->bridge.iobaseupper ||
!(port->bridge.command & PCI_COMMAND_IO)) {
/* If a window was configured, remove it */
if (port->iowin_base) {
mvebu_pcie_del_windows(port, port->iowin_base,
port->iowin_size);
port->iowin_base = 0;
port->iowin_size = 0;
}
mvebu_pcie_set_window(port, port->io_target, port->io_attr,
&desired, &port->iowin);
return;
}
@ -412,32 +438,27 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
* specifications. iobase is the bus address, port->iowin_base
* is the CPU address.
*/
iobase = ((port->bridge.iobase & 0xF0) << 8) |
(port->bridge.iobaseupper << 16);
port->iowin_base = port->pcie->io.start + iobase;
port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
(port->bridge.iolimitupper << 16)) -
iobase) + 1;
desired.remap = ((port->bridge.iobase & 0xF0) << 8) |
(port->bridge.iobaseupper << 16);
desired.base = port->pcie->io.start + desired.remap;
desired.size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
(port->bridge.iolimitupper << 16)) -
desired.remap) +
1;
mvebu_pcie_add_windows(port, port->io_target, port->io_attr,
port->iowin_base, port->iowin_size,
iobase);
mvebu_pcie_set_window(port, port->io_target, port->io_attr, &desired,
&port->iowin);
}
static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
{
struct mvebu_pcie_window desired = {.remap = MVEBU_MBUS_NO_REMAP};
/* Are the new membase/memlimit values invalid? */
if (port->bridge.memlimit < port->bridge.membase ||
!(port->bridge.command & PCI_COMMAND_MEMORY)) {
/* If a window was configured, remove it */
if (port->memwin_base) {
mvebu_pcie_del_windows(port, port->memwin_base,
port->memwin_size);
port->memwin_base = 0;
port->memwin_size = 0;
}
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
&desired, &port->memwin);
return;
}
@ -447,14 +468,12 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
* window to setup, according to the PCI-to-PCI bridge
* specifications.
*/
port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16);
port->memwin_size =
(((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
port->memwin_base + 1;
desired.base = ((port->bridge.membase & 0xFFF0) << 16);
desired.size = (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
desired.base + 1;
mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr,
port->memwin_base, port->memwin_size,
MVEBU_MBUS_NO_REMAP);
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired,
&port->memwin);
}
/*
@ -1162,7 +1181,7 @@ static int mvebu_pcie_powerup(struct mvebu_pcie_port *port)
return ret;
if (port->reset_gpio) {
u32 reset_udelay = 20000;
u32 reset_udelay = PCI_PM_D3COLD_WAIT * 1000;
of_property_read_u32(port->dn, "reset-delay-us",
&reset_udelay);