Merge branch 'pci/host-mvebu' into next

* pci/host-mvebu:
  PCI: mvebu: Remove duplicate of_clk_get_by_name() call
  PCI: mvebu: Support a bridge with no IO port window
  PCI: mvebu: Obey bridge PCI_COMMAND_MEM and PCI_COMMAND_IO bits
  PCI: mvebu: Drop writes to bridge Secondary Status register
This commit is contained in:
Bjorn Helgaas 2013-12-18 14:04:09 -07:00
commit 7160266a26

View File

@ -150,6 +150,11 @@ static inline u32 mvebu_readl(struct mvebu_pcie_port *port, u32 reg)
return readl(port->base + reg);
}
static inline bool mvebu_has_ioport(struct mvebu_pcie_port *port)
{
return port->io_target != -1 && port->io_attr != -1;
}
static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port)
{
return !(mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
@ -300,7 +305,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
/* Are the new iobase/iolimit values invalid? */
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 (port->iowin_base) {
@ -313,6 +319,12 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
return;
}
if (!mvebu_has_ioport(port)) {
dev_WARN(&port->pcie->pdev->dev,
"Attempt to set IO when IO is disabled\n");
return;
}
/*
* We read the PCI-to-PCI bridge emulated registers, and
* calculate the base address and size of the address decoding
@ -337,7 +349,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)
{
/* 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 (port->memwin_base) {
@ -426,9 +439,12 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
break;
case PCI_IO_BASE:
*value = (bridge->secondary_status << 16 |
bridge->iolimit << 8 |
bridge->iobase);
if (!mvebu_has_ioport(port))
*value = bridge->secondary_status << 16;
else
*value = (bridge->secondary_status << 16 |
bridge->iolimit << 8 |
bridge->iobase);
break;
case PCI_MEMORY_BASE:
@ -490,8 +506,19 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
switch (where & ~3) {
case PCI_COMMAND:
{
u32 old = bridge->command;
if (!mvebu_has_ioport(port))
value &= ~PCI_COMMAND_IO;
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;
}
case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value;
@ -505,7 +532,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
*/
bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32;
bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32;
bridge->secondary_status = value >> 16;
mvebu_pcie_handle_iobase_change(port);
break;
@ -656,7 +682,9 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
struct mvebu_pcie *pcie = sys_to_pcie(sys);
int i;
pci_add_resource_offset(&sys->resources, &pcie->realio, sys->io_offset);
if (resource_size(&pcie->realio) != 0)
pci_add_resource_offset(&sys->resources, &pcie->realio,
sys->io_offset);
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource(&sys->resources, &pcie->busn);
@ -757,12 +785,17 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF)
static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
unsigned long type, int *tgt, int *attr)
unsigned long type,
unsigned int *tgt,
unsigned int *attr)
{
const int na = 3, ns = 2;
const __be32 *range;
int rlen, nranges, rangesz, pna, i;
*tgt = -1;
*attr = -1;
range = of_get_property(np, "ranges", &rlen);
if (!range)
return -EINVAL;
@ -832,16 +865,15 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
}
mvebu_mbus_get_pcie_io_aperture(&pcie->io);
if (resource_size(&pcie->io) == 0) {
dev_err(&pdev->dev, "invalid I/O aperture size\n");
return -EINVAL;
}
pcie->realio.flags = pcie->io.flags;
pcie->realio.start = PCIBIOS_MIN_IO;
pcie->realio.end = min_t(resource_size_t,
IO_SPACE_LIMIT,
resource_size(&pcie->io));
if (resource_size(&pcie->io) != 0) {
pcie->realio.flags = pcie->io.flags;
pcie->realio.start = PCIBIOS_MIN_IO;
pcie->realio.end = min_t(resource_size_t,
IO_SPACE_LIMIT,
resource_size(&pcie->io));
} else
pcie->realio = pcie->io;
/* Get the bus range */
ret = of_pci_parse_bus_range(np, &pcie->busn);
@ -900,12 +932,12 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
continue;
}
ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO,
&port->io_target, &port->io_attr);
if (ret < 0) {
dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for io window\n",
port->port, port->lane);
continue;
if (resource_size(&pcie->io) != 0)
mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO,
&port->io_target, &port->io_attr);
else {
port->io_target = -1;
port->io_attr = -1;
}
port->reset_gpio = of_get_named_gpio_flags(child,
@ -954,14 +986,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
mvebu_pcie_set_local_dev_nr(port, 1);
port->clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(port->clk)) {
dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
port->port, port->lane);
iounmap(port->base);
continue;
}
port->dn = child;
spin_lock_init(&port->conf_lock);
mvebu_sw_pci_bridge_init(port);