Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2dbefbf6 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'pcie_bridge-3.11' of git://git.infradead.org/users/jcooper/linux into next/soc



From Jason Cooper:
mvebu pcie driver (bridge) for v3.11

 - mvebu
    - allow enumeration of devices beyond physical bridges
    - remove faking the slot location
    - fix status register emulation

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>

* tag 'pcie_bridge-3.11' of git://git.infradead.org/users/jcooper/linux:
  pci: mvebu: fix the emulation of the status register
  pci: mvebu: allow the enumeration of devices beyond physical bridges
  pci: mvebu: no longer fake the slot location of downstream devices
parents ed2670b3 6eb237c4
Loading
Loading
Loading
Loading
+44 −11
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@
#define  PCIE_CTRL_X1_MODE		0x0001
#define PCIE_STAT_OFF		0x1a04
#define  PCIE_STAT_BUS                  0xff00
#define  PCIE_STAT_DEV                  0x1f0000
#define  PCIE_STAT_LINK_DOWN		BIT(0)
#define PCIE_DEBUG_CTRL         0x1a60
#define  PCIE_DEBUG_SOFT_RESET		BIT(20)
@@ -68,7 +69,6 @@ struct mvebu_sw_pci_bridge {
	u16 vendor;
	u16 device;
	u16 command;
	u16 status;
	u16 class;
	u8 interface;
	u8 revision;
@@ -148,6 +148,16 @@ static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr)
	writel(stat, port->base + PCIE_STAT_OFF);
}

static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr)
{
	u32 stat;

	stat = readl(port->base + PCIE_STAT_OFF);
	stat &= ~PCIE_STAT_DEV;
	stat |= nr << 16;
	writel(stat, port->base + PCIE_STAT_OFF);
}

/*
 * Setup PCIE BARs and Address Decode Wins:
 * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
@@ -348,7 +358,6 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)

	memset(bridge, 0, sizeof(struct mvebu_sw_pci_bridge));

	bridge->status = PCI_STATUS_CAP_LIST;
	bridge->class = PCI_CLASS_BRIDGE_PCI;
	bridge->vendor = PCI_VENDOR_ID_MARVELL;
	bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
@@ -375,7 +384,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
		break;

	case PCI_COMMAND:
		*value = bridge->status << 16 | bridge->command;
		*value = bridge->command;
		break;

	case PCI_CLASS_REVISION:
@@ -468,7 +477,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
	switch (where & ~3) {
	case PCI_COMMAND:
		bridge->command = value & 0xffff;
		bridge->status = value >> 16;
		break;

	case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
@@ -543,7 +551,8 @@ mvebu_pcie_find_port(struct mvebu_pcie *pcie, struct pci_bus *bus,
		if (bus->number == 0 && port->devfn == devfn)
			return port;
		if (bus->number != 0 &&
		    port->bridge.secondary_bus == bus->number)
		    bus->number >= port->bridge.secondary_bus &&
		    bus->number <= port->bridge.subordinate_bus)
			return port;
	}

@@ -567,13 +576,23 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
	if (bus->number == 0)
		return mvebu_sw_pci_bridge_write(port, where, size, val);

	if (!port->haslink || PCI_SLOT(devfn) != 0)
	if (!port->haslink)
		return PCIBIOS_DEVICE_NOT_FOUND;

	/*
	 * On the secondary bus, we don't want to expose any other
	 * device than the device physically connected in the PCIe
	 * slot, visible in slot 0. In slot 1, there's a special
	 * Marvell device that only makes sense when the Armada is
	 * used as a PCIe endpoint.
	 */
	if (bus->number == port->bridge.secondary_bus &&
	    PCI_SLOT(devfn) != 0)
		return PCIBIOS_DEVICE_NOT_FOUND;

	/* Access the real PCIe interface */
	spin_lock_irqsave(&port->conf_lock, flags);
	ret = mvebu_pcie_hw_wr_conf(port, bus,
				    PCI_DEVFN(1, PCI_FUNC(devfn)),
	ret = mvebu_pcie_hw_wr_conf(port, bus, devfn,
				    where, size, val);
	spin_unlock_irqrestore(&port->conf_lock, flags);

@@ -599,15 +618,27 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
	if (bus->number == 0)
		return mvebu_sw_pci_bridge_read(port, where, size, val);

	if (!port->haslink || PCI_SLOT(devfn) != 0) {
	if (!port->haslink) {
		*val = 0xffffffff;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}

	/*
	 * On the secondary bus, we don't want to expose any other
	 * device than the device physically connected in the PCIe
	 * slot, visible in slot 0. In slot 1, there's a special
	 * Marvell device that only makes sense when the Armada is
	 * used as a PCIe endpoint.
	 */
	if (bus->number == port->bridge.secondary_bus &&
	    PCI_SLOT(devfn) != 0) {
		*val = 0xffffffff;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}

	/* Access the real PCIe interface */
	spin_lock_irqsave(&port->conf_lock, flags);
	ret = mvebu_pcie_hw_rd_conf(port, bus,
				    PCI_DEVFN(1, PCI_FUNC(devfn)),
	ret = mvebu_pcie_hw_rd_conf(port, bus, devfn,
				    where, size, val);
	spin_unlock_irqrestore(&port->conf_lock, flags);

@@ -817,6 +848,8 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
			continue;
		}

		mvebu_pcie_set_local_dev_nr(port, 1);

		if (mvebu_pcie_link_up(port)) {
			port->haslink = 1;
			dev_info(&pdev->dev, "PCIe%d.%d: link up\n",