2018-12-19 15:30:32

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 00/10] PCI: DWC/Keystone: MSI configuration cleanup

This series tries to address the comments discussed in [1] w.r.t
removing Keystone specific callbacks defined in dw_pcie_host_ops.

This series also tries to cleanup the Keystone interrupt handling
part.

This series is created on top of
git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git
pci/dwc-msi

Tested on K2G (had to use out of tree SERDES patches). Also tested on
dra7xx to make sure there are no regressions.

[1] -> https://patchwork.kernel.org/patch/10681587/

Kishon Vijay Abraham I (10):
PCI: keystone: Cleanup interrupt related macros
PCI: keystone: Use "dummy_irq_chip" instead of new irqchip for legacy
interrupt handling
PCI: keystone: Modify legacy_irq_handler to check the IRQ_STATUS of
INTA/B/C/D
PCI: keystone: Add separate functions for configuring MSI and legacy
interrupt
PCI: keystone: Use hwirq to get the IRQ number offset
PCI: keystone: Cleanup ks_pcie_msi_irq_handler and
ks_pcie_legacy_irq_handler
PCI: dwc: Add support to use non default msi_irq_chip
PCI: keystone: Use Keystone specific msi_irq_chip
PCI: dwc: Remove Keystone specific dw_pcie_host_ops
PCI: dwc: Do not write to MSI control registers if the platform
doesn't use it

drivers/pci/controller/dwc/pci-keystone.c | 430 +++++++++---------
.../pci/controller/dwc/pcie-designware-host.c | 74 ++-
drivers/pci/controller/dwc/pcie-designware.h | 6 +-
3 files changed, 258 insertions(+), 252 deletions(-)

--
2.17.1



2018-12-19 13:15:36

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 03/10] PCI: keystone: Modify legacy_irq_handler to check the IRQ_STATUS of INTA/B/C/D

The legacy interrupt handler directly checks the IRQ_STATUS register
corresponding to a interrupt line inorder to invoke generic_handle_irq.

While this is okay for K2G platform which has separate interrupt line for
each of the 4 legacy interrupts, AM654 which uses the same PCIe wrapper
has a single interrupt line for all the legacy interrupts. So for AM654
the interrupt handler won't be able to directly check the IRQ_STATUS
register corresponding to the interrupt line.

Also the legacy interrupt handler uses 'virq' obtained from
irq_of_parse_and_map to find the correct interrupt line which raised the
interrupt. There is no guarantee that virq assigned for contiguous hardware
irq will be contiguous and the interrupt handler might end up checking
the wrong IRQ_STATUS register.

In order to overcome the above issues, read the IRQ_STATUS register of
all the 4 legacy interrupts to determine which interrupt was raised.

Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/dwc/pci-keystone.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index 1ef443009da5..e9f5387136f0 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -214,16 +214,11 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
{
struct dw_pcie *pci = ks_pcie->pci;
struct device *dev = pci->dev;
- u32 pending;
int virq;

- pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(offset));
-
- if (BIT(0) & pending) {
- virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
- dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq);
- generic_handle_irq(virq);
- }
+ virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
+ dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq);
+ generic_handle_irq(virq);

/* EOI the INTx interrupt */
ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset);
@@ -587,8 +582,9 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
struct dw_pcie *pci = ks_pcie->pci;
struct device *dev = pci->dev;
- u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned int irq_no;
+ u32 reg;

dev_dbg(dev, ": Handling legacy irq %d\n", irq);

@@ -598,7 +594,13 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
* ack operation.
*/
chained_irq_enter(chip, desc);
- ks_pcie_handle_legacy_irq(ks_pcie, irq_offset);
+ for (irq_no = 0; irq_no < PCI_NUM_INTX; irq_no++) {
+ reg = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(irq_no));
+ if (!(reg & INTx_EN))
+ continue;
+ ks_pcie_handle_legacy_irq(ks_pcie, irq_no);
+ }
+
chained_irq_exit(chip, desc);
}

--
2.17.1


2018-12-19 13:15:52

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 01/10] PCI: keystone: Cleanup interrupt related macros

No functional change. Change both MSI interrupt and legacy interrupt
related macros to take an additional argument in order to return the
correct register offset.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/dwc/pci-keystone.c | 26 +++++++++++------------
1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index 14f2b0b4ed5e..5286a480f76b 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -52,17 +52,17 @@

/* IRQ register defines */
#define IRQ_EOI 0x050
-#define IRQ_STATUS 0x184
-#define IRQ_ENABLE_SET 0x188
-#define IRQ_ENABLE_CLR 0x18c

#define MSI_IRQ 0x054
-#define MSI0_IRQ_STATUS 0x104
-#define MSI0_IRQ_ENABLE_SET 0x108
-#define MSI0_IRQ_ENABLE_CLR 0x10c
-#define IRQ_STATUS 0x184
+#define MSI_IRQ_STATUS(n) (0x104 + ((n) << 4))
+#define MSI_IRQ_ENABLE_SET(n) (0x108 + ((n) << 4))
+#define MSI_IRQ_ENABLE_CLR(n) (0x10c + ((n) << 4))
#define MSI_IRQ_OFFSET 4

+#define IRQ_STATUS(n) (0x184 + ((n) << 4))
+#define IRQ_ENABLE_SET(n) (0x188 + ((n) << 4))
+#define INTx_EN BIT(0)
+
#define ERR_IRQ_STATUS 0x1c4
#define ERR_IRQ_ENABLE_SET 0x1c8
#define ERR_AER BIT(5) /* ECRC error */
@@ -142,7 +142,7 @@ static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset)
u32 pending, vector;
int src, virq;

- pending = ks_pcie_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4));
+ pending = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset));

/*
* MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
@@ -169,7 +169,7 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
ks_pcie = to_keystone_pcie(pci);
update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);

- ks_pcie_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4),
+ ks_pcie_app_writel(ks_pcie, MSI_IRQ_STATUS(reg_offset),
BIT(bit_pos));
ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET);
}
@@ -181,7 +181,7 @@ static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq)
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);

update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
- ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4),
+ ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset),
BIT(bit_pos));
}

@@ -192,7 +192,7 @@ static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);

update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
- ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4),
+ ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset),
BIT(bit_pos));
}

@@ -206,7 +206,7 @@ static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
int i;

for (i = 0; i < PCI_NUM_INTX; i++)
- ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1);
+ ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), 0x1);
}

static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
@@ -217,7 +217,7 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
u32 pending;
int virq;

- pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS + (offset << 4));
+ pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(offset));

if (BIT(0) & pending) {
virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
--
2.17.1


2018-12-19 13:16:15

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 02/10] PCI: keystone: Use "dummy_irq_chip" instead of new irqchip for legacy interrupt handling

Instead of creating a new irqchip with empty callback functions, use
dummy_irq_chip. Since there is nothing to do in the irqchip callback
functions, use handle_simple_irq instead of handle_level_irq.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/dwc/pci-keystone.c | 24 ++---------------------
1 file changed, 2 insertions(+), 22 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index 5286a480f76b..1ef443009da5 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -266,31 +266,12 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie)
return IRQ_HANDLED;
}

-static void ks_pcie_ack_legacy_irq(struct irq_data *d)
-{
-}
-
-static void ks_pcie_mask_legacy_irq(struct irq_data *d)
-{
-}
-
-static void ks_pcie_unmask_legacy_irq(struct irq_data *d)
-{
-}
-
-static struct irq_chip ks_pcie_legacy_irq_chip = {
- .name = "Keystone-PCI-Legacy-IRQ",
- .irq_ack = ks_pcie_ack_legacy_irq,
- .irq_mask = ks_pcie_mask_legacy_irq,
- .irq_unmask = ks_pcie_unmask_legacy_irq,
-};
-
static int ks_pcie_init_legacy_irq_map(struct irq_domain *d,
unsigned int irq,
irq_hw_number_t hw_irq)
{
- irq_set_chip_and_handler(irq, &ks_pcie_legacy_irq_chip,
- handle_level_irq);
+ irq_set_chip_and_handler(irq, &dummy_irq_chip,
+ handle_simple_irq);
irq_set_chip_data(irq, d->host_data);

return 0;
@@ -298,7 +279,6 @@ static int ks_pcie_init_legacy_irq_map(struct irq_domain *d,

static const struct irq_domain_ops ks_pcie_legacy_irq_domain_ops = {
.map = ks_pcie_init_legacy_irq_map,
- .xlate = irq_domain_xlate_onetwocell,
};

/**
--
2.17.1


2018-12-19 13:17:26

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 09/10] PCI: dwc: Remove Keystone specific dw_pcie_host_ops

Now that Keystone started using it's own msi_irq_chip, remove
Keystone specific callback function defined in dw_pcie_host_ops.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
.../pci/controller/dwc/pcie-designware-host.c | 45 ++++++-------------
drivers/pci/controller/dwc/pcie-designware.h | 5 ---
2 files changed, 14 insertions(+), 36 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index db21bd11f153..dbc94f3be3d5 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -126,18 +126,12 @@ static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
u64 msi_target;

- if (pp->ops->get_msi_addr)
- msi_target = pp->ops->get_msi_addr(pp);
- else
- msi_target = (u64)pp->msi_data;
+ msi_target = (u64)pp->msi_data;

msg->address_lo = lower_32_bits(msi_target);
msg->address_hi = upper_32_bits(msi_target);

- if (pp->ops->get_msi_data)
- msg->data = pp->ops->get_msi_data(pp, data->hwirq);
- else
- msg->data = data->hwirq;
+ msg->data = data->hwirq;

dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
(int)data->hwirq, msg->address_hi, msg->address_lo);
@@ -157,17 +151,13 @@ static void dw_pci_bottom_mask(struct irq_data *data)

raw_spin_lock_irqsave(&pp->lock, flags);

- if (pp->ops->msi_clear_irq) {
- pp->ops->msi_clear_irq(pp, data->hwirq);
- } else {
- ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
- res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
- bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
+ ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
+ res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+ bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;

- pp->irq_status[ctrl] &= ~(1 << bit);
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
- ~pp->irq_status[ctrl]);
- }
+ pp->irq_status[ctrl] &= ~(1 << bit);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
+ ~pp->irq_status[ctrl]);

raw_spin_unlock_irqrestore(&pp->lock, flags);
}
@@ -180,17 +170,13 @@ static void dw_pci_bottom_unmask(struct irq_data *data)

raw_spin_lock_irqsave(&pp->lock, flags);

- if (pp->ops->msi_set_irq) {
- pp->ops->msi_set_irq(pp, data->hwirq);
- } else {
- ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
- res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
- bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
+ ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
+ res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+ bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;

- pp->irq_status[ctrl] |= 1 << bit;
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
- ~pp->irq_status[ctrl]);
- }
+ pp->irq_status[ctrl] |= 1 << bit;
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
+ ~pp->irq_status[ctrl]);

raw_spin_unlock_irqrestore(&pp->lock, flags);
}
@@ -209,9 +195,6 @@ static void dw_pci_bottom_ack(struct irq_data *d)

dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, 1 << bit);

- if (pp->ops->msi_irq_ack)
- pp->ops->msi_irq_ack(d->hwirq, pp);
-
raw_spin_unlock_irqrestore(&pp->lock, flags);
}

diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 0873ee4084aa..53cb6ab405b5 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -134,14 +134,9 @@ struct dw_pcie_host_ops {
int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 val);
int (*host_init)(struct pcie_port *pp);
- void (*msi_set_irq)(struct pcie_port *pp, int irq);
- void (*msi_clear_irq)(struct pcie_port *pp, int irq);
- phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
- u32 (*get_msi_data)(struct pcie_port *pp, int pos);
void (*scan_bus)(struct pcie_port *pp);
void (*set_num_vectors)(struct pcie_port *pp);
int (*msi_host_init)(struct pcie_port *pp);
- void (*msi_irq_ack)(int irq, struct pcie_port *pp);
};

struct pcie_port {
--
2.17.1


2018-12-19 13:18:07

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 05/10] PCI: keystone: Use hwirq to get the IRQ number offset

ks_pcie_msi_irq_handler() uses 'virq' to get the IRQ number offset.
This offset is used to get the correct MSI_IRQ_STATUS register
corresponding to the IRQ line that raised the interrupt.
There is no guarantee that 'virq' assigned for consecutive hardware
IRQ will be contiguous. And this might get us an incorrect IRQ number
offset.

Fix it here by using 'hwirq' to get the IRQ number offset. Since we
don't store the 'virq' numbers of all the IRQ numbers, stop checking
if irq count is greater than MAX_MSI_HOST_IRQS and remove
MAX_MSI_HOST_IRQS.

Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/dwc/pci-keystone.c | 24 ++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index a8712804c891..8a78307dac99 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -74,7 +74,6 @@
#define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \
ERR_NONFATAL | ERR_FATAL | ERR_SYS)

-#define MAX_MSI_HOST_IRQS 8
/* PCIE controller device IDs */
#define PCIE_RC_K2HK 0xb008
#define PCIE_RC_K2E 0xb009
@@ -89,7 +88,7 @@ struct keystone_pcie {
u32 device_id;
struct device_node *legacy_intc_np;

- int msi_host_irqs[MAX_MSI_HOST_IRQS];
+ int msi_host_irq;
int num_lanes;
u32 num_viewport;
struct phy **phy;
@@ -527,9 +526,9 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)

static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
{
- unsigned int irq = irq_desc_get_irq(desc);
+ unsigned int irq = desc->irq_data.hwirq;
struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
- u32 offset = irq - ks_pcie->msi_host_irqs[0];
+ u32 offset = irq - ks_pcie->msi_host_irq;
struct dw_pcie *pci = ks_pcie->pci;
struct device *dev = pci->dev;
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -587,6 +586,7 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie)
struct device *dev = ks_pcie->pci->dev;
struct device_node *np = ks_pcie->np;
struct device_node *intc_np;
+ struct irq_data *irq_data;
int irq_count;
int irq;
int ret;
@@ -608,19 +608,21 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie)
goto err;
}

- if (irq_count > MAX_MSI_HOST_IRQS) {
- dev_warn(dev, "Too many MSI interrupt lines defined %u\n",
- irq_count);
- irq_count = MAX_MSI_HOST_IRQS;
- }
-
for (i = 0; i < irq_count; i++) {
irq = irq_of_parse_and_map(intc_np, i);
if (!irq) {
ret = -EINVAL;
goto err;
}
- ks_pcie->msi_host_irqs[i] = irq;
+
+ if (!ks_pcie->msi_host_irq) {
+ irq_data = irq_get_irq_data(irq);
+ if (!irq_data) {
+ ret = -EINVAL;
+ goto err;
+ }
+ ks_pcie->msi_host_irq = irq_data->hwirq;
+ }

irq_set_chained_handler_and_data(irq, ks_pcie_msi_irq_handler,
ks_pcie);
--
2.17.1


2018-12-19 13:18:33

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 07/10] PCI: dwc: Add support to use non default msi_irq_chip

Platforms using Designware IP uses dw_pci_msi_bottom_irq_chip for
configuring the MSI controller logic within the Designware IP. However
certain platforms like Keystone (K2G) which uses Desingware IP has
it's own MSI controller logic. For handling such platforms,
the irqchip ops uses msi_irq_ack, msi_set_irq, msi_clear_irq callback
functions.

Add support to use different msi_irq_chip with default as
dw_pci_msi_bottom_irq_chip. This is in preparation to get rid off
msi_irq_ack, msi_set_irq, msi_clear_irq and other Keystone specific
dw_pcie_host_ops.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/dwc/pcie-designware-host.c | 5 ++++-
drivers/pci/controller/dwc/pcie-designware.h | 1 +
2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 0fa9e8fdce66..db21bd11f153 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -245,7 +245,7 @@ static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,

for (i = 0; i < nr_irqs; i++)
irq_domain_set_info(domain, virq + i, bit + i,
- &dw_pci_msi_bottom_irq_chip,
+ pp->msi_irq_chip,
pp, handle_edge_irq,
NULL, NULL);

@@ -277,6 +277,9 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);

+ if (!pp->msi_irq_chip)
+ pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip;
+
pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors,
&dw_pcie_msi_domain_ops, pp);
if (!pp->irq_domain) {
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 0989d880ac46..0873ee4084aa 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -168,6 +168,7 @@ struct pcie_port {
struct irq_domain *irq_domain;
struct irq_domain *msi_domain;
dma_addr_t msi_data;
+ struct irq_chip *msi_irq_chip;
u32 num_vectors;
u32 irq_status[MAX_MSI_CTRLS];
raw_spinlock_t lock;
--
2.17.1


2018-12-19 13:20:48

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 04/10] PCI: keystone: Add separate functions for configuring MSI and legacy interrupt

ks_pcie_get_irq_controller_info() was used to configure both MSI and
legacy interrupt. This will prevent MSI or legacy interrupt specific
intializations. Add separate functions to configure MSI and legacy
interrupts.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/dwc/pci-keystone.c | 188 +++++++++++-----------
1 file changed, 96 insertions(+), 92 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index e9f5387136f0..a8712804c891 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -87,11 +87,8 @@ struct keystone_pcie {
struct dw_pcie *pci;
/* PCI Device ID */
u32 device_id;
- int num_legacy_host_irqs;
- int legacy_host_irqs[PCI_NUM_INTX];
struct device_node *legacy_intc_np;

- int num_msi_host_irqs;
int msi_host_irqs[MAX_MSI_HOST_IRQS];
int num_lanes;
u32 num_viewport;
@@ -201,14 +198,6 @@ static int ks_pcie_msi_host_init(struct pcie_port *pp)
return dw_pcie_allocate_domains(pp);
}

-static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
-{
- int i;
-
- for (i = 0; i < PCI_NUM_INTX; i++)
- ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), 0x1);
-}
-
static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
int offset)
{
@@ -470,17 +459,6 @@ static int __init ks_pcie_dw_host_init(struct keystone_pcie *ks_pcie)

ks_pcie->app = *res;

- /* Create legacy IRQ domain */
- ks_pcie->legacy_irq_domain =
- irq_domain_add_linear(ks_pcie->legacy_intc_np,
- PCI_NUM_INTX,
- &ks_pcie_legacy_irq_domain_ops,
- NULL);
- if (!ks_pcie->legacy_irq_domain) {
- dev_err(dev, "Failed to add irq domain for legacy irqs\n");
- return -EINVAL;
- }
-
return dw_pcie_host_init(pp);
}

@@ -604,85 +582,117 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}

-static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
- char *controller, int *num_irqs)
+static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie)
{
- int temp, max_host_irqs, legacy = 1, *host_irqs;
struct device *dev = ks_pcie->pci->dev;
- struct device_node *np_pcie = dev->of_node, **np_temp;
-
- if (!strcmp(controller, "msi-interrupt-controller"))
- legacy = 0;
-
- if (legacy) {
- np_temp = &ks_pcie->legacy_intc_np;
- max_host_irqs = PCI_NUM_INTX;
- host_irqs = &ks_pcie->legacy_host_irqs[0];
- } else {
- np_temp = &ks_pcie->msi_intc_np;
- max_host_irqs = MAX_MSI_HOST_IRQS;
- host_irqs = &ks_pcie->msi_host_irqs[0];
- }
+ struct device_node *np = ks_pcie->np;
+ struct device_node *intc_np;
+ int irq_count;
+ int irq;
+ int ret;
+ int i;

- /* interrupt controller is in a child node */
- *np_temp = of_get_child_by_name(np_pcie, controller);
- if (!(*np_temp)) {
- dev_err(dev, "Node for %s is absent\n", controller);
- return -EINVAL;
- }
+ if (!IS_ENABLED(CONFIG_PCI_MSI))
+ return 0;

- temp = of_irq_count(*np_temp);
- if (!temp) {
- dev_err(dev, "No IRQ entries in %s\n", controller);
- of_node_put(*np_temp);
+ intc_np = of_get_child_by_name(np, "msi-interrupt-controller");
+ if (!intc_np) {
+ dev_WARN(dev, "msi-interrupt-controller node is absent\n");
return -EINVAL;
}

- if (temp > max_host_irqs)
- dev_warn(dev, "Too many %s interrupts defined %u\n",
- (legacy ? "legacy" : "MSI"), temp);
+ irq_count = of_irq_count(intc_np);
+ if (!irq_count) {
+ dev_err(dev, "No IRQ entries in msi-interrupt-controller\n");
+ ret = -EINVAL;
+ goto err;
+ }

- /*
- * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
- * 7 (MSI)
- */
- for (temp = 0; temp < max_host_irqs; temp++) {
- host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
- if (!host_irqs[temp])
- break;
+ if (irq_count > MAX_MSI_HOST_IRQS) {
+ dev_warn(dev, "Too many MSI interrupt lines defined %u\n",
+ irq_count);
+ irq_count = MAX_MSI_HOST_IRQS;
}

- of_node_put(*np_temp);
+ for (i = 0; i < irq_count; i++) {
+ irq = irq_of_parse_and_map(intc_np, i);
+ if (!irq) {
+ ret = -EINVAL;
+ goto err;
+ }
+ ks_pcie->msi_host_irqs[i] = irq;

- if (temp) {
- *num_irqs = temp;
- return 0;
+ irq_set_chained_handler_and_data(irq, ks_pcie_msi_irq_handler,
+ ks_pcie);
}

- return -EINVAL;
+ of_node_put(intc_np);
+ return 0;
+
+err:
+ of_node_put(intc_np);
+ return ret;
}

-static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
+static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie)
{
+ struct device *dev = ks_pcie->pci->dev;
+ struct irq_domain *legacy_irq_domain;
+ struct device_node *np = ks_pcie->np;
+ struct device_node *intc_np;
+ int irq_count;
+ int irq;
+ int ret;
int i;

- /* Legacy IRQ */
- for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
- irq_set_chained_handler_and_data(ks_pcie->legacy_host_irqs[i],
+ intc_np = of_get_child_by_name(np, "legacy-interrupt-controller");
+ if (!intc_np) {
+ dev_WARN(dev, "legacy-interrupt-controller node is absent\n");
+ return -EINVAL;
+ }
+
+ irq_count = of_irq_count(intc_np);
+ if (!irq_count) {
+ dev_err(dev, "No IRQ entries in legacy-interrupt-controller\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < irq_count; i++) {
+ irq = irq_of_parse_and_map(intc_np, i);
+ if (!irq) {
+ ret = -EINVAL;
+ goto err;
+ }
+ irq_set_chained_handler_and_data(irq,
ks_pcie_legacy_irq_handler,
ks_pcie);
}
- ks_pcie_enable_legacy_irqs(ks_pcie);
-
- /* MSI IRQ */
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
- irq_set_chained_handler_and_data(ks_pcie->msi_host_irqs[i],
- ks_pcie_msi_irq_handler,
- ks_pcie);
- }
+
+ legacy_irq_domain =
+ irq_domain_add_linear(intc_np, PCI_NUM_INTX,
+ &ks_pcie_legacy_irq_domain_ops, NULL);
+ if (!legacy_irq_domain) {
+ dev_err(dev, "Failed to add irq domain for legacy irqs\n");
+ ret = -EINVAL;
+ goto err;
}
+ ks_pcie->legacy_irq_domain = legacy_irq_domain;
+
+ for (i = 0; i < PCI_NUM_INTX; i++)
+ ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), INTx_EN);
+
+ of_node_put(intc_np);
+
+ return 0;
+
+err:
+ of_node_put(intc_np);
+ return ret;
+}

+static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
+{
if (ks_pcie->error_irq > 0)
ks_pcie_enable_error_irq(ks_pcie);
}
@@ -736,6 +746,14 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
int ret;

+ ret = ks_pcie_config_legacy_irq(ks_pcie);
+ if (ret)
+ return ret;
+
+ ret = ks_pcie_config_msi_irq(ks_pcie);
+ if (ret)
+ return ret;
+
dw_pcie_setup_rc(pp);

ks_pcie_establish_link(ks_pcie);
@@ -785,20 +803,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
struct device *dev = &pdev->dev;
int ret;

- ret = ks_pcie_get_irq_controller_info(ks_pcie,
- "legacy-interrupt-controller",
- &ks_pcie->num_legacy_host_irqs);
- if (ret)
- return ret;
-
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- ret = ks_pcie_get_irq_controller_info(ks_pcie,
- "msi-interrupt-controller",
- &ks_pcie->num_msi_host_irqs);
- if (ret)
- return ret;
- }
-
/*
* Index 0 is the platform interrupt for error interrupt
* from RC. This is optional.
--
2.17.1


2018-12-19 15:31:22

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 08/10] PCI: keystone: Use Keystone specific msi_irq_chip

Use Keystone specific msi_irq_chip to configure the MSI controller
logic in the PCIe keystone wrapper instead of using the default
Designware msi_irq chip (dw_pci_msi_bottom_irq_chip) with
callback functions for configuring the Keystone MSI controller.
This will help to remove Keystone specific callback functions
added in dw_pcie_host_ops.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/dwc/pci-keystone.c | 96 +++++++++++++++++------
1 file changed, 72 insertions(+), 24 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index 05b2bd613c68..420d30ce11f4 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -104,14 +104,6 @@ struct keystone_pcie {
struct resource app;
};

-static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp)
-{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-
- return ks_pcie->app.start + MSI_IRQ;
-}
-
static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset)
{
return readl(ks_pcie->va_app_base + offset);
@@ -123,11 +115,14 @@ static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset,
writel(val, ks_pcie->va_app_base + offset);
}

-static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
+static void ks_pcie_msi_irq_ack(struct irq_data *data)
{
- u32 reg_offset, bit_pos;
+ struct pcie_port *pp = irq_data_get_irq_chip_data(data);
struct keystone_pcie *ks_pcie;
+ u32 irq = data->hwirq;
struct dw_pcie *pci;
+ u32 reg_offset;
+ u32 bit_pos;

pci = to_dw_pcie_from_pp(pp);
ks_pcie = to_keystone_pcie(pci);
@@ -140,34 +135,91 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET);
}

-static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+static void ks_pcie_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
- u32 reg_offset, bit_pos;
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+ struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+ struct keystone_pcie *ks_pcie;
+ struct dw_pcie *pci;
+ u64 msi_target;
+
+ pci = to_dw_pcie_from_pp(pp);
+ ks_pcie = to_keystone_pcie(pci);
+
+ msi_target = ks_pcie->app.start + MSI_IRQ;
+ msg->address_lo = lower_32_bits(msi_target);
+ msg->address_hi = upper_32_bits(msi_target);
+ msg->data = data->hwirq;
+
+ dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
+ (int)data->hwirq, msg->address_hi, msg->address_lo);
+}
+
+static int ks_pcie_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+{
+ return -EINVAL;
+}
+
+static void ks_pcie_msi_mask(struct irq_data *data)
+{
+ struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+ struct keystone_pcie *ks_pcie;
+ u32 irq = data->hwirq;
+ struct dw_pcie *pci;
+ unsigned long flags;
+ u32 reg_offset;
+ u32 bit_pos;
+
+ raw_spin_lock_irqsave(&pp->lock, flags);
+
+ pci = to_dw_pcie_from_pp(pp);
+ ks_pcie = to_keystone_pcie(pci);

reg_offset = irq % 8;
bit_pos = irq >> 3;

- ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset),
+ ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset),
BIT(bit_pos));
+
+ raw_spin_unlock_irqrestore(&pp->lock, flags);
}

-static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+static void ks_pcie_msi_unmask(struct irq_data *data)
{
- u32 reg_offset, bit_pos;
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+ struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+ struct keystone_pcie *ks_pcie;
+ u32 irq = data->hwirq;
+ struct dw_pcie *pci;
+ unsigned long flags;
+ u32 reg_offset;
+ u32 bit_pos;
+
+ raw_spin_lock_irqsave(&pp->lock, flags);
+
+ pci = to_dw_pcie_from_pp(pp);
+ ks_pcie = to_keystone_pcie(pci);

reg_offset = irq % 8;
bit_pos = irq >> 3;

- ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset),
+ ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset),
BIT(bit_pos));
+
+ raw_spin_unlock_irqrestore(&pp->lock, flags);
}

+static struct irq_chip ks_pcie_msi_irq_chip = {
+ .name = "KEYSTONE-PCI-MSI",
+ .irq_ack = ks_pcie_msi_irq_ack,
+ .irq_compose_msi_msg = ks_pcie_compose_msi_msg,
+ .irq_set_affinity = ks_pcie_msi_set_affinity,
+ .irq_mask = ks_pcie_msi_mask,
+ .irq_unmask = ks_pcie_msi_unmask,
+};
+
static int ks_pcie_msi_host_init(struct pcie_port *pp)
{
+ pp->msi_irq_chip = &ks_pcie_msi_irq_chip;
return dw_pcie_allocate_domains(pp);
}

@@ -768,11 +820,7 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = {
.rd_other_conf = ks_pcie_rd_other_conf,
.wr_other_conf = ks_pcie_wr_other_conf,
.host_init = ks_pcie_host_init,
- .msi_set_irq = ks_pcie_msi_set_irq,
- .msi_clear_irq = ks_pcie_msi_clear_irq,
- .get_msi_addr = ks_pcie_get_msi_addr,
.msi_host_init = ks_pcie_msi_host_init,
- .msi_irq_ack = ks_pcie_msi_irq_ack,
.scan_bus = ks_pcie_v3_65_scan_bus,
};

--
2.17.1


2018-12-19 15:37:24

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 06/10] PCI: keystone: Cleanup ks_pcie_msi_irq_handler and ks_pcie_legacy_irq_handler

Both ks_pcie_msi_irq_handler() and ks_pcie_legacy_irq_handler() invokes
ks_pcie_handle_msi_irq() and ks_pcie_handle_legacy_irq() respectively
for handling the interrupts.

Having two functions for handling the interrupt was used when keystone
PCIe driver was implemented using two files. But with
commit b492aca35c982011500377797d2 ("PCI: keystone: Merge
pci-keystone-dw.c and pci-keystone.c"), which merged the keystone PCIe
driver to use a single file, two functions for handling the
interrupt handler is not required.

Handle both MSI interrupt and legacy interrupt in a single interrupt
handler here.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/dwc/pci-keystone.c | 92 ++++++++++-------------
1 file changed, 39 insertions(+), 53 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index 8a78307dac99..05b2bd613c68 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -104,13 +104,6 @@ struct keystone_pcie {
struct resource app;
};

-static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
- u32 *bit_pos)
-{
- *reg_offset = offset % 8;
- *bit_pos = offset >> 3;
-}
-
static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -130,31 +123,6 @@ static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset,
writel(val, ks_pcie->va_app_base + offset);
}

-static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset)
-{
- struct dw_pcie *pci = ks_pcie->pci;
- struct pcie_port *pp = &pci->pp;
- struct device *dev = pci->dev;
- u32 pending, vector;
- int src, virq;
-
- pending = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset));
-
- /*
- * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
- * shows 1, 9, 17, 25 and so forth
- */
- for (src = 0; src < 4; src++) {
- if (BIT(src) & pending) {
- vector = offset + (src << 3);
- virq = irq_linear_revmap(pp->irq_domain, vector);
- dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n",
- src, vector, virq);
- generic_handle_irq(virq);
- }
- }
-}
-
static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
{
u32 reg_offset, bit_pos;
@@ -163,7 +131,9 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp)

pci = to_dw_pcie_from_pp(pp);
ks_pcie = to_keystone_pcie(pci);
- update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+
+ reg_offset = irq % 8;
+ bit_pos = irq >> 3;

ks_pcie_app_writel(ks_pcie, MSI_IRQ_STATUS(reg_offset),
BIT(bit_pos));
@@ -176,7 +146,9 @@ static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);

- update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+ reg_offset = irq % 8;
+ bit_pos = irq >> 3;
+
ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset),
BIT(bit_pos));
}
@@ -187,7 +159,9 @@ static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);

- update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+ reg_offset = irq % 8;
+ bit_pos = irq >> 3;
+
ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset),
BIT(bit_pos));
}
@@ -197,21 +171,6 @@ static int ks_pcie_msi_host_init(struct pcie_port *pp)
return dw_pcie_allocate_domains(pp);
}

-static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
- int offset)
-{
- struct dw_pcie *pci = ks_pcie->pci;
- struct device *dev = pci->dev;
- int virq;
-
- virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
- dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq);
- generic_handle_irq(virq);
-
- /* EOI the INTx interrupt */
- ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset);
-}
-
static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie)
{
ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL);
@@ -530,8 +489,13 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
u32 offset = irq - ks_pcie->msi_host_irq;
struct dw_pcie *pci = ks_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
struct device *dev = pci->dev;
struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 vector;
+ u32 virq;
+ u32 reg;
+ u32 pos;

dev_dbg(dev, "%s, irq %d\n", __func__, irq);

@@ -541,7 +505,23 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
* ack operation.
*/
chained_irq_enter(chip, desc);
- ks_pcie_handle_msi_irq(ks_pcie, offset);
+
+ reg = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset));
+ /*
+ * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+ * shows 1, 9, 17, 25 and so forth
+ */
+ for (pos = 0; pos < 4; pos++) {
+ if (!(reg & BIT(pos)))
+ continue;
+
+ vector = offset + (pos << 3);
+ virq = irq_linear_revmap(pp->irq_domain, vector);
+ dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", pos, vector,
+ virq);
+ generic_handle_irq(virq);
+ }
+
chained_irq_exit(chip, desc);
}

@@ -561,6 +541,7 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
struct device *dev = pci->dev;
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int irq_no;
+ u32 virq;
u32 reg;

dev_dbg(dev, ": Handling legacy irq %d\n", irq);
@@ -575,9 +556,14 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
reg = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(irq_no));
if (!(reg & INTx_EN))
continue;
- ks_pcie_handle_legacy_irq(ks_pcie, irq_no);
- }

+ virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, irq_no);
+ dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", irq_no, virq);
+ generic_handle_irq(virq);
+
+ /* EOI the INTx interrupt */
+ ks_pcie_app_writel(ks_pcie, IRQ_EOI, irq_no);
+ }
chained_irq_exit(chip, desc);
}

--
2.17.1


2018-12-19 15:37:24

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 10/10] PCI: dwc: Do not write to MSI control registers if the platform doesn't use it

Platforms which populate msi_host_init, has it's own MSI controller
logic. Writing to MSI control registers on platforms which doesn't use
Designware's MSI controller logic might have side effects. To
be safe, do not write to MSI control registers if the platform uses
it's own MSI controller logic instead of Designware's MSI controller
logic.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
.../pci/controller/dwc/pcie-designware-host.c | 24 ++++++++++---------
1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index dbc94f3be3d5..6644a5683b2b 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -647,17 +647,19 @@ void dw_pcie_setup_rc(struct pcie_port *pp)

dw_pcie_setup(pci);

- num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
-
- /* Initialize IRQ Status array */
- for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
- (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
- 4, ~0);
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
- (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
- 4, ~0);
- pp->irq_status[ctrl] = 0;
+ if (!pp->ops->msi_host_init) {
+ num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
+
+ /* Initialize IRQ Status array */
+ for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
+ (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+ 4, ~0);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
+ (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+ 4, ~0);
+ pp->irq_status[ctrl] = 0;
+ }
}

/* Setup RC BARs */
--
2.17.1


2019-01-02 11:55:00

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH 10/10] PCI: dwc: Do not write to MSI control registers if the platform doesn't use it

Hi,

On 19/12/2018 12:42, Kishon Vijay Abraham I wrote:
> Platforms which populate msi_host_init, has it's own MSI controller
> logic. Writing to MSI control registers on platforms which doesn't use
> Designware's MSI controller logic might have side effects. To
> be safe, do not write to MSI control registers if the platform uses
> it's own MSI controller logic instead of Designware's MSI controller
> logic.
>
> Signed-off-by: Kishon Vijay Abraham I <[email protected]>
> ---
> .../pci/controller/dwc/pcie-designware-host.c | 24 ++++++++++---------
> 1 file changed, 13 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index dbc94f3be3d5..6644a5683b2b 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -647,17 +647,19 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
>
> dw_pcie_setup(pci);
>
> - num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
> -
> - /* Initialize IRQ Status array */
> - for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
> - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
> - (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
> - 4, ~0);
> - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
> - (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
> - 4, ~0);
> - pp->irq_status[ctrl] = 0;
> + if (!pp->ops->msi_host_init) {
> + num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
> +
> + /* Initialize IRQ Status array */
> + for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
> + (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
> + 4, ~0);
> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
> + (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
> + 4, ~0);
> + pp->irq_status[ctrl] = 0;
> + }
> }
>
> /* Setup RC BARs */
>

Acked-by: Gustavo Pimentel <[email protected]>

Regards,
Gustavo

2019-01-02 11:57:52

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH 09/10] PCI: dwc: Remove Keystone specific dw_pcie_host_ops

Hi,

On 19/12/2018 12:42, Kishon Vijay Abraham I wrote:
> Now that Keystone started using it's own msi_irq_chip, remove
> Keystone specific callback function defined in dw_pcie_host_ops.
>
> Signed-off-by: Kishon Vijay Abraham I <[email protected]>
> ---
> .../pci/controller/dwc/pcie-designware-host.c | 45 ++++++-------------
> drivers/pci/controller/dwc/pcie-designware.h | 5 ---
> 2 files changed, 14 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index db21bd11f153..dbc94f3be3d5 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -126,18 +126,12 @@ static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
> struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> u64 msi_target;
>
> - if (pp->ops->get_msi_addr)
> - msi_target = pp->ops->get_msi_addr(pp);
> - else
> - msi_target = (u64)pp->msi_data;
> + msi_target = (u64)pp->msi_data;
>
> msg->address_lo = lower_32_bits(msi_target);
> msg->address_hi = upper_32_bits(msi_target);
>
> - if (pp->ops->get_msi_data)
> - msg->data = pp->ops->get_msi_data(pp, data->hwirq);
> - else
> - msg->data = data->hwirq;
> + msg->data = data->hwirq;
>
> dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
> (int)data->hwirq, msg->address_hi, msg->address_lo);
> @@ -157,17 +151,13 @@ static void dw_pci_bottom_mask(struct irq_data *data)
>
> raw_spin_lock_irqsave(&pp->lock, flags);
>
> - if (pp->ops->msi_clear_irq) {
> - pp->ops->msi_clear_irq(pp, data->hwirq);
> - } else {
> - ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
> - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
> - bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
> + ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
> + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
> + bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
>
> - pp->irq_status[ctrl] &= ~(1 << bit);
> - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
> - ~pp->irq_status[ctrl]);
> - }
> + pp->irq_status[ctrl] &= ~(1 << bit);
> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
> + ~pp->irq_status[ctrl]);
>
> raw_spin_unlock_irqrestore(&pp->lock, flags);
> }
> @@ -180,17 +170,13 @@ static void dw_pci_bottom_unmask(struct irq_data *data)
>
> raw_spin_lock_irqsave(&pp->lock, flags);
>
> - if (pp->ops->msi_set_irq) {
> - pp->ops->msi_set_irq(pp, data->hwirq);
> - } else {
> - ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
> - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
> - bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
> + ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
> + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
> + bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
>
> - pp->irq_status[ctrl] |= 1 << bit;
> - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
> - ~pp->irq_status[ctrl]);
> - }
> + pp->irq_status[ctrl] |= 1 << bit;
> + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
> + ~pp->irq_status[ctrl]);
>
> raw_spin_unlock_irqrestore(&pp->lock, flags);
> }
> @@ -209,9 +195,6 @@ static void dw_pci_bottom_ack(struct irq_data *d)
>
> dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, 1 << bit);
>
> - if (pp->ops->msi_irq_ack)
> - pp->ops->msi_irq_ack(d->hwirq, pp);
> -
> raw_spin_unlock_irqrestore(&pp->lock, flags);
> }
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 0873ee4084aa..53cb6ab405b5 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -134,14 +134,9 @@ struct dw_pcie_host_ops {
> int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> unsigned int devfn, int where, int size, u32 val);
> int (*host_init)(struct pcie_port *pp);
> - void (*msi_set_irq)(struct pcie_port *pp, int irq);
> - void (*msi_clear_irq)(struct pcie_port *pp, int irq);
> - phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
> - u32 (*get_msi_data)(struct pcie_port *pp, int pos);
> void (*scan_bus)(struct pcie_port *pp);
> void (*set_num_vectors)(struct pcie_port *pp);
> int (*msi_host_init)(struct pcie_port *pp);
> - void (*msi_irq_ack)(int irq, struct pcie_port *pp);
> };
>
> struct pcie_port {
>

Acked-by: Gustavo Pimentel <[email protected]>

Regards,
Gustavo

2019-01-02 11:58:11

by Gustavo Pimentel

[permalink] [raw]
Subject: Re: [PATCH 07/10] PCI: dwc: Add support to use non default msi_irq_chip

Hi,

On 19/12/2018 12:42, Kishon Vijay Abraham I wrote:
> Platforms using Designware IP uses dw_pci_msi_bottom_irq_chip for
> configuring the MSI controller logic within the Designware IP. However
> certain platforms like Keystone (K2G) which uses Desingware IP has
> it's own MSI controller logic. For handling such platforms,
> the irqchip ops uses msi_irq_ack, msi_set_irq, msi_clear_irq callback
> functions.

Keystone also uses get_msi_addr and get_msi_data callbacks, do you want to
update the description to add those references as well?

>
> Add support to use different msi_irq_chip with default as
> dw_pci_msi_bottom_irq_chip. This is in preparation to get rid off
> msi_irq_ack, msi_set_irq, msi_clear_irq and other Keystone specific
> dw_pcie_host_ops.
>
> Signed-off-by: Kishon Vijay Abraham I <[email protected]>
> ---
> drivers/pci/controller/dwc/pcie-designware-host.c | 5 ++++-
> drivers/pci/controller/dwc/pcie-designware.h | 1 +
> 2 files changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 0fa9e8fdce66..db21bd11f153 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -245,7 +245,7 @@ static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
>
> for (i = 0; i < nr_irqs; i++)
> irq_domain_set_info(domain, virq + i, bit + i,
> - &dw_pci_msi_bottom_irq_chip,
> + pp->msi_irq_chip,
> pp, handle_edge_irq,
> NULL, NULL);
>
> @@ -277,6 +277,9 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
> struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);
>
> + if (!pp->msi_irq_chip)
> + pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip;
> +
> pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors,
> &dw_pcie_msi_domain_ops, pp);
> if (!pp->irq_domain) {
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 0989d880ac46..0873ee4084aa 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -168,6 +168,7 @@ struct pcie_port {
> struct irq_domain *irq_domain;
> struct irq_domain *msi_domain;
> dma_addr_t msi_data;
> + struct irq_chip *msi_irq_chip;
> u32 num_vectors;
> u32 irq_status[MAX_MSI_CTRLS];
> raw_spinlock_t lock;
>

Acked-by: Gustavo Pimentel <[email protected]>

Regards,
Gustavo

2019-01-24 12:46:37

by Lorenzo Pieralisi

[permalink] [raw]
Subject: Re: [PATCH 02/10] PCI: keystone: Use "dummy_irq_chip" instead of new irqchip for legacy interrupt handling

On Wed, Dec 19, 2018 at 06:11:59PM +0530, Kishon Vijay Abraham I wrote:
> Instead of creating a new irqchip with empty callback functions, use
> dummy_irq_chip. Since there is nothing to do in the irqchip callback
> functions, use handle_simple_irq instead of handle_level_irq.
>
> Signed-off-by: Kishon Vijay Abraham I <[email protected]>
> ---
> drivers/pci/controller/dwc/pci-keystone.c | 24 ++---------------------
> 1 file changed, 2 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
> index 5286a480f76b..1ef443009da5 100644
> --- a/drivers/pci/controller/dwc/pci-keystone.c
> +++ b/drivers/pci/controller/dwc/pci-keystone.c
> @@ -266,31 +266,12 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie)
> return IRQ_HANDLED;
> }
>
> -static void ks_pcie_ack_legacy_irq(struct irq_data *d)
> -{
> -}
> -
> -static void ks_pcie_mask_legacy_irq(struct irq_data *d)
> -{
> -}
> -
> -static void ks_pcie_unmask_legacy_irq(struct irq_data *d)
> -{
> -}
> -
> -static struct irq_chip ks_pcie_legacy_irq_chip = {
> - .name = "Keystone-PCI-Legacy-IRQ",
> - .irq_ack = ks_pcie_ack_legacy_irq,
> - .irq_mask = ks_pcie_mask_legacy_irq,
> - .irq_unmask = ks_pcie_unmask_legacy_irq,
> -};
> -
> static int ks_pcie_init_legacy_irq_map(struct irq_domain *d,
> unsigned int irq,
> irq_hw_number_t hw_irq)
> {
> - irq_set_chip_and_handler(irq, &ks_pcie_legacy_irq_chip,
> - handle_level_irq);
> + irq_set_chip_and_handler(irq, &dummy_irq_chip,
> + handle_simple_irq);

Hi Kishon,

thanks for putting it together. I think I'd rather move some of
the logic for acking the interrupt in ks_pcie_handle_legacy_irq()
into proper irq_chip methods than using a dummy_irq_chip (that
Marc wants to deprecate).

Also, the flow handler should be handle_level_irq() since that's
what legacy IRQs are.

I hope Marc can chime in when he has a minute to help you finalize this.

Overall you are doing the right thing and I would like to get this
series merged for v5.1.

Thanks,
Lorenzo

> irq_set_chip_data(irq, d->host_data);
>
> return 0;
> @@ -298,7 +279,6 @@ static int ks_pcie_init_legacy_irq_map(struct irq_domain *d,
>
> static const struct irq_domain_ops ks_pcie_legacy_irq_domain_ops = {
> .map = ks_pcie_init_legacy_irq_map,
> - .xlate = irq_domain_xlate_onetwocell,
> };
>
> /**
> --
> 2.17.1
>