Commit 641e674d authored by Jason Gunthorpe's avatar Jason Gunthorpe Committed by Bjorn Helgaas

PCI: mvebu: Support a bridge with no IO port window

Make pcie-io-aperture and the IO port MBUS ID in ranges optional.  If not
provided the bridge reports to Linux that IO space mapping is not supported
and refuses to configure an IO MBUS window.

This allows both complete disable (do not specify pcie-io-aperture) and
per-port disable (do not specify a IO target ranges entry for the port).

Most PCIe devices these days do not require IO support to function, so
having an option to disable it in the driver is useful.
Tested-by: default avatarThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: default avatarJason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Acked-by: default avatarJason Cooper <jason@lakedaemon.net>
parent 43a16f94
...@@ -150,6 +150,11 @@ static inline u32 mvebu_readl(struct mvebu_pcie_port *port, u32 reg) ...@@ -150,6 +150,11 @@ static inline u32 mvebu_readl(struct mvebu_pcie_port *port, u32 reg)
return readl(port->base + 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) static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port)
{ {
return !(mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN); return !(mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
...@@ -314,6 +319,12 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) ...@@ -314,6 +319,12 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
return; 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 * We read the PCI-to-PCI bridge emulated registers, and
* calculate the base address and size of the address decoding * calculate the base address and size of the address decoding
...@@ -428,9 +439,12 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, ...@@ -428,9 +439,12 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
break; break;
case PCI_IO_BASE: case PCI_IO_BASE:
*value = (bridge->secondary_status << 16 | if (!mvebu_has_ioport(port))
bridge->iolimit << 8 | *value = bridge->secondary_status << 16;
bridge->iobase); else
*value = (bridge->secondary_status << 16 |
bridge->iolimit << 8 |
bridge->iobase);
break; break;
case PCI_MEMORY_BASE: case PCI_MEMORY_BASE:
...@@ -490,6 +504,9 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, ...@@ -490,6 +504,9 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
{ {
u32 old = bridge->command; u32 old = bridge->command;
if (!mvebu_has_ioport(port))
value &= ~PCI_COMMAND_IO;
bridge->command = value & 0xffff; bridge->command = value & 0xffff;
if ((old ^ bridge->command) & PCI_COMMAND_IO) if ((old ^ bridge->command) & PCI_COMMAND_IO)
mvebu_pcie_handle_iobase_change(port); mvebu_pcie_handle_iobase_change(port);
...@@ -660,7 +677,9 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) ...@@ -660,7 +677,9 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
struct mvebu_pcie *pcie = sys_to_pcie(sys); struct mvebu_pcie *pcie = sys_to_pcie(sys);
int i; 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_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource(&sys->resources, &pcie->busn); pci_add_resource(&sys->resources, &pcie->busn);
...@@ -761,12 +780,17 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev, ...@@ -761,12 +780,17 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF) #define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF)
static int mvebu_get_tgt_attr(struct device_node *np, int devfn, 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 int na = 3, ns = 2;
const __be32 *range; const __be32 *range;
int rlen, nranges, rangesz, pna, i; int rlen, nranges, rangesz, pna, i;
*tgt = -1;
*attr = -1;
range = of_get_property(np, "ranges", &rlen); range = of_get_property(np, "ranges", &rlen);
if (!range) if (!range)
return -EINVAL; return -EINVAL;
...@@ -836,16 +860,15 @@ static int mvebu_pcie_probe(struct platform_device *pdev) ...@@ -836,16 +860,15 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
} }
mvebu_mbus_get_pcie_io_aperture(&pcie->io); 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; if (resource_size(&pcie->io) != 0) {
pcie->realio.start = PCIBIOS_MIN_IO; pcie->realio.flags = pcie->io.flags;
pcie->realio.end = min_t(resource_size_t, pcie->realio.start = PCIBIOS_MIN_IO;
IO_SPACE_LIMIT, pcie->realio.end = min_t(resource_size_t,
resource_size(&pcie->io)); IO_SPACE_LIMIT,
resource_size(&pcie->io));
} else
pcie->realio = pcie->io;
/* Get the bus range */ /* Get the bus range */
ret = of_pci_parse_bus_range(np, &pcie->busn); ret = of_pci_parse_bus_range(np, &pcie->busn);
...@@ -904,12 +927,12 @@ static int mvebu_pcie_probe(struct platform_device *pdev) ...@@ -904,12 +927,12 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
continue; continue;
} }
ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO, if (resource_size(&pcie->io) != 0)
&port->io_target, &port->io_attr); mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO,
if (ret < 0) { &port->io_target, &port->io_attr);
dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for io window\n", else {
port->port, port->lane); port->io_target = -1;
continue; port->io_attr = -1;
} }
port->reset_gpio = of_get_named_gpio_flags(child, port->reset_gpio = of_get_named_gpio_flags(child,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment