[linux-yocto] [PATCH 05/48] drivers/pci: Updates to the Axxia (X9, XLF) PCIe host driver

Daniel Dragomir daniel.dragomir at windriver.com
Mon Dec 11 05:13:35 PST 2017


From: John Jacques <john.jacques at intel.com>

Added support for PCIe Message Signaled Interrupts (MSI).
Fixed the PCIe Legacy (INTx) interrupt handling.
Added the proper interrupt mapping and assignments.

Signed-off-by: Palani <palaniappan.ramanathan at intel.com>
Signed-off-by: John Jacques <john.jacques at intel.com>
---
 arch/arm64/boot/dts/intel/axc67xx.dtsi |  75 ++++++++++---------
 arch/arm64/boot/dts/intel/axm56xx.dtsi |  45 +++++++++++-
 drivers/pci/host/pcie-axxia.c          | 128 ++++++++++++++++++++++++++-------
 drivers/pci/host/pcie-axxia.h          |   3 +
 4 files changed, 191 insertions(+), 60 deletions(-)

diff --git a/arch/arm64/boot/dts/intel/axc67xx.dtsi b/arch/arm64/boot/dts/intel/axc67xx.dtsi
index f6712fb..0c65b99 100644
--- a/arch/arm64/boot/dts/intel/axc67xx.dtsi
+++ b/arch/arm64/boot/dts/intel/axc67xx.dtsi
@@ -342,7 +342,7 @@
 		mtc: mtc at 8080210000 {
 			compatible = "lsi,mtc";
 			reg = <0x80 0x80210000 0 0x10000>;
-			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -370,40 +370,45 @@
 				0x03000000 0x00000000 0xa0000000
 				0xc0 0x00000000
 				0x00 0x40000000>;       /* outbound mem */
-			interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-map-mask = <0 0 0 7>;
+			interrupt-map = <0 0 0 1 &gic 0 57 4>,
+					<0 0 0 2 &gic 0 57 4>,
+					<0 0 0 3 &gic 0 57 4>,
+					<0 0 0 4 &gic 0 57 4>;
+			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 59 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 60 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 61 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 62 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 63 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 64 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 65 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 66 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 67 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 68 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 69 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 70 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 71 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 72 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 73 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 76 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 77 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 78 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 79 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 80 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 81 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 82 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 83 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 84 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 85 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 86 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 87 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 88 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 89 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
 			status = "disabled";
 		};
 
diff --git a/arch/arm64/boot/dts/intel/axm56xx.dtsi b/arch/arm64/boot/dts/intel/axm56xx.dtsi
index fc82673..e4ecab7 100644
--- a/arch/arm64/boot/dts/intel/axm56xx.dtsi
+++ b/arch/arm64/boot/dts/intel/axm56xx.dtsi
@@ -301,7 +301,40 @@
 				0xc0 0x00000000
 				0x00 0x40000000>;       /* outbound mem */
 			interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+				<GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 97 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 98 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 99 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 100 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 101 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 102 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 103 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 104 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 105 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 106 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 107 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 108 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 109 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 110 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 111 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 112 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 113 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 114 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 115 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 116 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 117 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 118 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 119 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 120 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 121 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 122 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 123 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 124 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 125 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 126 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 127 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 128 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 129 IRQ_TYPE_EDGE_RISING>;
 			status = "disabled";
 		};
 
@@ -323,6 +356,11 @@
 				0x03000000 0x00000000 0xa0000000
 				0xc8 0x00000000
 				0x00 0x40000000>;       /* outbound mem */
+			interrupt-map-mask = <0 0 0 7>;
+			interrupt-map = <0 0 0 1 &gic 0 92 4>,
+					<0 0 0 2 &gic 0 92 4>,
+					<0 0 0 3 &gic 0 92 4>,
+					<0 0 0 4 &gic 0 92 4>;
 			interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
@@ -346,6 +384,11 @@
 				0x03000000 0x00000000 0xa0000000
 				0xd0 0x00000000
 				0x00 0x40000000>;       /* outbound mem */
+			interrupt-map-mask = <0 0 0 7>;
+			interrupt-map = <0 0 0 1 &gic 0 93 4>,
+					<0 0 0 2 &gic 0 93 4>,
+					<0 0 0 3 &gic 0 93 4>,
+					<0 0 0 4 &gic 0 93 4>;
 			interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
diff --git a/drivers/pci/host/pcie-axxia.c b/drivers/pci/host/pcie-axxia.c
index fb14f1a..1abee65 100644
--- a/drivers/pci/host/pcie-axxia.c
+++ b/drivers/pci/host/pcie-axxia.c
@@ -440,12 +440,19 @@ static const struct irq_domain_ops axxia_msi_domain_ops = {
 
 void axxia_dw_pcie_msi_init(struct pcie_port *pp)
 {
+	u64 msi_target;
 	pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
 
+	msi_target = virt_to_phys((void *)pp->msi_data);
+	dev_info(pp->dev,
+		"%s: MSI addr virt: %lx, phys: %llx\n",
+		__func__, pp->msi_data, msi_target);
 	/* program the msi_data */
 	axxia_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
-			       virt_to_phys((void *)pp->msi_data));
-	axxia_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
+			    (u32)(msi_target & 0xffffffff));
+	axxia_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
+			    (u32)(msi_target >> 32 & 0xffffffff));
+
 }
 
 /* MSI int handler */
@@ -480,9 +487,55 @@ static void axxia_pcie_msi_init(struct pcie_port *pp)
 	axxia_dw_pcie_msi_init(pp);
 }
 
+void axxia_dw_pcie_handle_msi_irq(struct pcie_port *pp, int offset)
+{
+	unsigned long val;
+	int i, pos, irq;
+
+	for (i = 0; i < MAX_MSI_CTRLS; i++) {
+		axxia_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
+				(u32 *)&val);
+		if (val) {
+			pos = 0;
+			while ((pos = find_next_bit(&val, 32, pos)) != 32) {
+
+				dev_dbg(pp->dev,
+				 "msi valid i = %d, val = %lx, pos = %d\n",
+							i, val, pos);
+				irq = irq_find_mapping(pp->irq_domain,
+						i * 32 + pos);
+				axxia_pcie_wr_own_conf(pp,
+						PCIE_MSI_INTR0_STATUS + i * 12,
+						4, 1 << pos);
+				generic_handle_irq(irq);
+				pos++;
+			}
+		}
+	}
+}
+
+static void axxia_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct pcie_port *pp = irq_desc_get_handler_data(desc);
+	u32 offset = irq - pp->msi_irqs[0];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, "%s, irq %d i %d\n", __func__, irq, offset);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	axxia_dw_pcie_handle_msi_irq(pp, offset);
+	chained_irq_exit(chip, desc);
+}
+
 static void axxia_pcie_enable_interrupts(struct pcie_port *pp)
 {
 	u32 val;
+	int i;
 
 	/* Unmask */
 	axxia_cc_gpreg_readl(pp, CC_GPREG_EDG_IRQ_MASK, &val);
@@ -493,9 +546,19 @@ static void axxia_pcie_enable_interrupts(struct pcie_port *pp)
 	axxia_cc_gpreg_writel(pp, val, CC_GPREG_EDG_IRQ_MASK);
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		/* unmask MSI */
-		axxia_cc_gpreg_readl(pp, CC_GPREG_EDG_IRQ_MASK_HI, &val);
-		val |= MSI_ASSERTED;
-		axxia_cc_gpreg_writel(pp, val, CC_GPREG_EDG_IRQ_MASK_HI);
+		if (pp->num_msi_irqs == 0) {
+			axxia_cc_gpreg_readl(pp,
+				CC_GPREG_EDG_IRQ_MASK_HI, &val);
+			val |= MSI_ASSERTED;
+			axxia_cc_gpreg_writel(pp, val,
+				CC_GPREG_EDG_IRQ_MASK_HI);
+		} else {
+			for (i = 0; i < pp->num_msi_irqs; i++) {
+				irq_set_chained_handler(pp->msi_irqs[i],
+					axxia_pcie_msi_irq_handler);
+				irq_set_handler_data(pp->msi_irqs[i], pp);
+			}
+		}
 		axxia_pcie_msi_init(pp);
 	}
 }
@@ -650,12 +713,15 @@ static irqreturn_t axxia_pcie_irq_handler(int irq, void *arg)
 			      CC_GPREG_EDG_IRQ_STAT);
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		axxia_cc_gpreg_readl(pp, CC_GPREG_EDG_IRQ_STAT_HI, &val);
-		if (val & MSI_ASSERTED) {
-			ret = axxia_dw_handle_msi_irq(pp);
-			axxia_cc_gpreg_writel(pp, MSI_ASSERTED,
+		if (pp->num_msi_irqs == 0) {
+			axxia_cc_gpreg_readl(pp,
+				CC_GPREG_EDG_IRQ_STAT_HI, &val);
+			if (val & MSI_ASSERTED) {
+				ret = axxia_dw_handle_msi_irq(pp);
+				axxia_cc_gpreg_writel(pp, MSI_ASSERTED,
 					      CC_GPREG_EDG_IRQ_STAT_HI);
-			return ret;
+				return ret;
+			}
 		}
 	}
 	return IRQ_HANDLED;
@@ -672,7 +738,6 @@ static void axxia_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
 	axxia_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
 }
 
-
 static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
 			    unsigned int nvec, unsigned int pos)
 {
@@ -681,12 +746,7 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
 	for (i = 0; i < nvec; i++) {
 		irq_set_msi_desc_off(irq_base, i, NULL);
 		/* Disable corresponding interrupt on MSI controller */
-		if (!pp->ops)
-			dev_err(pp->dev, "ops not set for pcie_port\n");
-		if (pp->ops && pp->ops->msi_clear_irq)
-			pp->ops->msi_clear_irq(pp, pos + i);
-		else
-			axxia_dw_pcie_msi_clear_irq(pp, pos + i);
+		axxia_dw_pcie_msi_clear_irq(pp, pos + i);
 	}
 
 	bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec));
@@ -740,24 +800,34 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 	return -ENOSPC;
 }
 
+static void axxia_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
+{
+	struct msi_msg msg;
+	u64 msi_target;
+
+	msi_target = virt_to_phys((void *)pp->msi_data);
+	msg.address_lo = (u32)(msi_target & 0xffffffff);
+	msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+	msg.data = pos;
+
+	pci_write_msi_msg(irq, &msg);
+}
+
 static int axxia_dw_msi_setup_irq(struct msi_controller *chip,
 				  struct pci_dev *pdev,
 				  struct msi_desc *desc)
 {
 	int irq, pos;
-	struct msi_msg msg;
 	struct pcie_port *pp = pdev->bus->sysdata;
 
+	if (desc->msi_attrib.is_msix)
+		return -EINVAL;
+
 	irq = assign_irq(1, desc, &pos);
 	if (irq < 0)
 		return irq;
 
-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
-	msg.address_hi = 0x0;
-	msg.data = pos;
-
-	pci_write_msi_msg(irq, &msg);
-
+	axxia_msi_setup_msg(pp, irq, pos);
 	return 0;
 }
 
@@ -893,6 +963,16 @@ int axxia_pcie_host_init(struct pcie_port *pp)
 		dev_err(pp->dev, "failed to get irq\n");
 		return -ENODEV;
 	}
+	pp->num_msi_irqs = 0;
+	for (i = 0; i < AXXIA_MSI_IRQL; i++) {
+		pp->msi_irqs[i] = platform_get_irq(pdev, i+2);
+		if (pp->msi_irqs[i] <= 0)
+			break;
+		pp->num_msi_irqs++;
+	}
+	dev_info(pp->dev, "num_msi = %d, irq = %d\n",
+			pp->num_msi_irqs, pp->irqs);
+
 	ret = devm_request_irq(pp->dev, pp->irqs, axxia_pcie_irq_handler,
 			       IRQF_SHARED | IRQF_NO_THREAD, "axxia-pcie", pp);
 	if (ret) {
diff --git a/drivers/pci/host/pcie-axxia.h b/drivers/pci/host/pcie-axxia.h
index ffc8d73..5a965d7 100644
--- a/drivers/pci/host/pcie-axxia.h
+++ b/drivers/pci/host/pcie-axxia.h
@@ -21,6 +21,7 @@
  */
 #define MAX_MSI_IRQS			64
 #define MAX_MSI_CTRLS			(MAX_MSI_IRQS / 32)
+#define AXXIA_MSI_IRQL			32
 
 struct pcie_port {
 	struct device		*dev;
@@ -52,6 +53,8 @@ struct pcie_port {
 	struct pcie_host_ops	*ops;
 	int			irqs; /* removed 34 not sure why it's there
 					 [34]; */
+	int			msi_irqs[AXXIA_MSI_IRQL];
+	int			num_msi_irqs;
 	unsigned long		msi_data;
 	struct irq_domain	*irq_domain;
 	struct msi_controller chip;
-- 
2.7.4



More information about the linux-yocto mailing list