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

Commit 249e2a38 authored by Ganesan Ramalingam's avatar Ganesan Ramalingam Committed by Ralf Baechle
Browse files

MIPS: Netlogic: MSI enable fix for XLS



MSI interrupts do not work on XLS after commit a776c491
( "PCI: msi: Disable msi interrupts when we initialize a pci device" )
because the change disables MSI interrupts on the XLS PCIe bridges
during the PCI enumeration.

Fix this by enabling MSI interrupts on the bridge in the
arch_setup_msi_irq() function. A new function xls_get_pcie_link()
has been introduced to get the PCI device corresponding to the
top level PCIe bridge on which MSI has to be enabled.

Also, update get_irq_vector() to use the new xls_get_pcie_link()
function and PCI_SLOT() macro for determining the IRQ of PCI devices.

Signed-off-by: default avatarGanesan Ramalingam <ganesanr@broadcom.com>
Signed-off-by: default avatarJayachandran C <jayachandranc@netlogicmicro.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/3753/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent ea8e867d
Loading
Loading
Loading
Loading
+50 −9
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <linux/console.h>
#include <linux/pci_regs.h>

#include <asm/io.h>

@@ -156,8 +157,27 @@ struct pci_controller nlm_pci_controller = {
	.io_offset      = 0x00000000UL,
};

/*
 * The top level PCIe links on the XLS PCIe controller appear as
 * bridges. Given a device, this function finds which link it is
 * on.
 */
static struct pci_dev *xls_get_pcie_link(const struct pci_dev *dev)
{
	struct pci_bus *bus, *p;

	/* Find the bridge on bus 0 */
	bus = dev->bus;
	for (p = bus->parent; p && p->number != 0; p = p->parent)
		bus = p;

	return p ? bus->self : NULL;
}

static int get_irq_vector(const struct pci_dev *dev)
{
	struct pci_dev *lnk;

	if (!nlm_chip_is_xls())
		return	PIC_PCIX_IRQ;	/* for XLR just one IRQ */

@@ -165,26 +185,27 @@ static int get_irq_vector(const struct pci_dev *dev)
	 * For XLS PCIe, there is an IRQ per Link, find out which
	 * link the device is on to assign interrupts
	 */
	if (dev->bus->self == NULL)
	lnk = xls_get_pcie_link(dev);
	if (lnk == NULL)
		return 0;

	switch	(dev->bus->self->devfn) {
	case 0x0:
	switch	(PCI_SLOT(lnk->devfn)) {
	case 0:
		return PIC_PCIE_LINK0_IRQ;
	case 0x8:
	case 1:
		return PIC_PCIE_LINK1_IRQ;
	case 0x10:
	case 2:
		if (nlm_chip_is_xls_b())
			return PIC_PCIE_XLSB0_LINK2_IRQ;
		else
			return PIC_PCIE_LINK2_IRQ;
	case 0x18:
	case 3:
		if (nlm_chip_is_xls_b())
			return PIC_PCIE_XLSB0_LINK3_IRQ;
		else
			return PIC_PCIE_LINK3_IRQ;
	}
	WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn);
	WARN(1, "Unexpected devfn %d\n", lnk->devfn);
	return 0;
}

@@ -202,7 +223,27 @@ void arch_teardown_msi_irq(unsigned int irq)
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{
	struct msi_msg msg;
	struct pci_dev *lnk;
	int irq, ret;
	u16 val;

	/* MSI not supported on XLR */
	if (!nlm_chip_is_xls())
		return 1;

	/*
	 * Enable MSI on the XLS PCIe controller bridge which was disabled
	 * at enumeration, the bridge MSI capability is at 0x50
	 */
	lnk = xls_get_pcie_link(dev);
	if (lnk == NULL)
		return 1;

	pci_read_config_word(lnk, 0x50 + PCI_MSI_FLAGS, &val);
	if ((val & PCI_MSI_FLAGS_ENABLE) == 0) {
		val |= PCI_MSI_FLAGS_ENABLE;
		pci_write_config_word(lnk, 0x50 + PCI_MSI_FLAGS, val);
	}

	irq = get_irq_vector(dev);
	if (irq <= 0)