[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