[linux-yocto] [PATCH 12/15] Axxia PCIe: Updates to the Axxia (X9, XLF) PCIe host driver.
Daniel Dragomir
daniel.dragomir at windriver.com
Tue Jun 27 08:41:12 PDT 2017
From: Palani <palaniappan.ramanathan 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>
---
arch/arm64/boot/dts/intel/axc67xx.dtsi | 75 ++++++++++---------
arch/arm64/boot/dts/intel/axm56xx.dtsi | 50 ++++++++++++-
drivers/pci/host/pcie-axxia.c | 128 ++++++++++++++++++++++++++-------
drivers/pci/host/pcie-axxia.h | 3 +
4 files changed, 196 insertions(+), 60 deletions(-)
diff --git a/arch/arm64/boot/dts/intel/axc67xx.dtsi b/arch/arm64/boot/dts/intel/axc67xx.dtsi
index 4f5aa97..a830e4c 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 40f34a6..e08a7c3 100644
--- a/arch/arm64/boot/dts/intel/axm56xx.dtsi
+++ b/arch/arm64/boot/dts/intel/axm56xx.dtsi
@@ -309,8 +309,46 @@
0x03000000 0x00000000 0xa0000000
0xc0 0x00000000
0x00 0x40000000>; /* outbound mem */
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &gic 0 91 4>,
+ <0 0 0 2 &gic 0 91 4>,
+ <0 0 0 3 &gic 0 91 4>,
+ <0 0 0 4 &gic 0 91 4>;
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";
};
@@ -332,6 +370,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";
@@ -355,6 +398,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 7128ece..a1bebec 100644
--- a/drivers/pci/host/pcie-axxia.c
+++ b/drivers/pci/host/pcie-axxia.c
@@ -441,12 +441,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 */
@@ -481,9 +488,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);
@@ -494,9 +547,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);
}
}
@@ -651,12 +714,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;
@@ -673,7 +739,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)
{
@@ -682,12 +747,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));
@@ -741,24 +801,34 @@ no_valid_irq:
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;
}
@@ -894,6 +964,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