Skip to contentSkip to conversation

add new irq api to pcie-designware

RFC Superseded Joao Pinto 3 participants 12 messages May 12, 2017 – May 15, 2017

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Joao Pinto

author
#0 lore raw

cover add new irq api to pcie-designware

This patch series adds the new interrupt api to pcie-designware make it possible to use features like MSIX.

The work consisted of adapting the pcie-designware-host and each SoC specific driver.

Joao Pinto (8):
pci: adding new irq api to pci-designware
pci: exynos SoC driver adapted to new irq API
pci: imx6 SoC driver adapted to new irq API
pci: artpec6 SoC driver adapted to new irq API
pci: generic PCIe DW driver adapted to new irq API
pci: qcom SoC driver adapted to new irq API
pci: keystone SoC driver adapted to new irq API
pci: removing old irq api from pcie-designware

 drivers/pci/dwc/pci-exynos.c           |  18 --
 drivers/pci/dwc/pci-imx6.c             |  18 --
 drivers/pci/dwc/pci-keystone-dw.c      |  97 +--------
 drivers/pci/dwc/pci-keystone.c         |   1 +
 drivers/pci/dwc/pci-keystone.h         |   4 +-
 drivers/pci/dwc/pci-layerscape.c       |   4 +-
 drivers/pci/dwc/pcie-artpec6.c         |  18 --
 drivers/pci/dwc/pcie-designware-host.c | 349 ++++++++++++++++++---------------
 drivers/pci/dwc/pcie-designware-plat.c |  15 --
 drivers/pci/dwc/pcie-designware.h      |   8 +-
 drivers/pci/dwc/pcie-qcom.c            |  15 --
 11 files changed, 205 insertions(+), 342 deletions(-)
Signature · 1 line
2.9.3
author
#1 lore raw

RFC 1/8 pci: adding new irq api to pci-designware

This patch adds the new interrupt api to pecie-designware, keeping the old one. A define was added to toggle between the two apis (for testing purposes).

---
 drivers/pci/dwc/pcie-designware-host.c | 241 ++++++++++++++++++++++++++++++++-
 drivers/pci/dwc/pcie-designware.h      |   5 +
 2 files changed, 244 insertions(+), 2 deletions(-)
drivers/pci/dwc/pcie-designware-host.c +239 -2
index 28ed32b..6810ea10b 100644
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
@@ -19,6 +20,9 @@
 
 #include "pcie-designware.h"
 
+/* Temporary: Activate to use new IRQ API */
+/*#define CONFIG_PCIEDW_NEW_IRQ_API*/
+
 static struct pci_ops dw_pcie_ops;
 
 static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
@@ -45,6 +49,7 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
 	return dw_pcie_write(pci->dbi_base + where, size, val);
 }
 
+#ifndef CONFIG_PCIEDW_NEW_IRQ_API
 static struct irq_chip dw_msi_irq_chip = {
 	.name = "PCI-MSI",
 	.irq_enable = pci_msi_unmask_irq,
@@ -52,6 +57,29 @@ static struct irq_chip dw_msi_irq_chip = {
 	.irq_mask = pci_msi_mask_irq,
 	.irq_unmask = pci_msi_unmask_irq,
 };
+#else
+static void dw_msi_mask_irq(struct irq_data *d) {
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void dw_msi_unmask_irq(struct irq_data *d) {
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip dw_msi_irq_chip = {
+	.name = "PCI-MSI",
+	.irq_mask = dw_msi_mask_irq,
+	.irq_unmask = dw_msi_unmask_irq,
+};
+
+static struct msi_domain_info dw_pcie_msi_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+		     MSI_FLAG_PCI_MSIX),
+	.chip	= &dw_msi_irq_chip,
+};
+#endif
 
 /* MSI int handler */
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
@@ -81,6 +109,190 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 	return ret;
 }
 
+#ifdef CONFIG_PCIEDW_NEW_IRQ_API
+/* Chained MSI interrupt service routine */
+static void dw_chained_msi_isr(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct pcie_port *pp;
+	struct dw_pcie *pci;
+
+	chained_irq_enter(chip, desc);
+	pci = irq_desc_get_handler_data(desc);
+	pp = &pci->pp;
+
+	dw_handle_msi_irq(pp);
+
+	chained_irq_exit(chip, desc);
+}
+
+static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+	struct pcie_port *pp = &pci->pp;
+	u64 msi_target;
+
+	if (pp->ops->get_msi_addr)
+		msi_target = pp->ops->get_msi_addr(pp);
+	else
+		msi_target = virt_to_phys((void *)pp->msi_data);
+
+	msg->address_lo = (u32)(msi_target & 0xffffffff);
+	msg->address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+
+	if (pp->ops->get_msi_data)
+		msg->data = pp->ops->get_msi_data(pp, data->hwirq);
+	else
+		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 dw_pci_msi_set_affinity(struct irq_data *irq_data,
+				   const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+
+static void dw_pci_bottom_mask(struct irq_data *data)
+{
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+	struct pcie_port *pp = &pci->pp;
+	unsigned int res, bit, val;
+
+	mutex_lock(&pp->lock);
+
+	if (pp->ops->msi_clear_irq)
+		pp->ops->msi_clear_irq(pp, data->hwirq);
+	else {
+		res = (data->hwirq / 32) * 12;
+		bit = data->hwirq % 32;
+
+		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+		val &= ~(1 << bit);
+		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+	}
+
+	mutex_unlock(&pp->lock);
+}
+
+static void dw_pci_bottom_unmask(struct irq_data *data)
+{
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+	struct pcie_port *pp = &pci->pp;
+	unsigned int res, bit, val;
+
+	mutex_lock(&pp->lock);
+
+	if (pp->ops->msi_set_irq)
+		pp->ops->msi_set_irq(pp, data->hwirq);
+	else {
+		res = (data->hwirq / 32) * 12;
+		bit = data->hwirq % 32;
+
+		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+		val |= 1 << bit;
+		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+	}
+
+	mutex_unlock(&pp->lock);
+}
+
+static struct irq_chip dw_pci_msi_bottom_irq_chip = {
+	.name			= "DWPCI-MSI",
+	.irq_compose_msi_msg	= dw_pci_setup_msi_msg,
+	.irq_set_affinity	= dw_pci_msi_set_affinity,
+	.irq_mask		= dw_pci_bottom_mask,
+	.irq_unmask		= dw_pci_bottom_unmask,
+};
+
+static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs,
+				    void *args)
+{
+	struct dw_pcie *pci = domain->host_data;
+	struct pcie_port *pp = &pci->pp;
+	unsigned long bit;
+
+	mutex_lock(&pp->lock);
+
+	WARN_ON(nr_irqs != 1);
+
+	bit = find_first_zero_bit(pp->msi_irq_in_use, pp->num_vectors);
+	if (bit >= pp->num_vectors) {
+		mutex_unlock(&pp->lock);
+		return -ENOSPC;
+	}
+
+	set_bit(bit, pp->msi_irq_in_use);
+
+	mutex_unlock(&pp->lock);
+
+	irq_domain_set_info(domain, virq, bit, &dw_pci_msi_bottom_irq_chip,
+			    domain->host_data, handle_simple_irq,
+			    NULL, NULL);
+
+	return 0;
+}
+
+static void dw_pcie_irq_domain_free(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs)
+{
+	struct irq_data *data = irq_domain_get_irq_data(domain, virq);
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+	struct pcie_port *pp = &pci->pp;
+
+	mutex_lock(&pp->lock);
+
+	if (!test_bit(data->hwirq, pp->msi_irq_in_use))
+		dev_err(pci->dev, "trying to free unused MSI#%lu\n",
+			data->hwirq);
+	else
+		__clear_bit(data->hwirq, pp->msi_irq_in_use);
+
+	mutex_unlock(&pp->lock);
+}
+
+static const struct irq_domain_ops dw_pcie_msi_domain_ops = {
+	.alloc	= dw_pcie_irq_domain_alloc,
+	.free	= dw_pcie_irq_domain_free,
+};
+
+int dw_pcie_allocate_domains(struct dw_pcie *pci)
+{
+	struct pcie_port *pp = &pci->pp;
+	struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);
+
+	pp->irq_domain = irq_domain_add_linear(NULL, pp->num_vectors,
+					       &dw_pcie_msi_domain_ops, pci);
+	if (!pp->irq_domain) {
+		dev_err(pci->dev, "failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	pp->msi_domain = pci_msi_create_irq_domain(fwnode,
+						   &dw_pcie_msi_domain_info,
+						   pp->irq_domain);
+	if (!pp->msi_domain) {
+		dev_err(pci->dev, "failed to create MSI domain\n");
+		irq_domain_remove(pp->irq_domain);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void dw_pcie_free_msi(struct pcie_port *pp)
+{
+	irq_set_chained_handler(pp->msi_irq, NULL);
+	irq_set_handler_data(pp->msi_irq, NULL);
+
+	irq_domain_remove(pp->msi_domain);
+	irq_domain_remove(pp->irq_domain);
+}
+#endif
+
 void dw_pcie_msi_init(struct pcie_port *pp)
 {
 	u64 msi_target;
@@ -279,11 +491,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	struct device *dev = pci->dev;
 	struct device_node *np = dev->of_node;
 	struct platform_device *pdev = to_platform_device(dev);
+	struct resource_entry *win, *tmp;
 	struct pci_bus *bus, *child;
 	struct resource *cfg_res;
-	int i, ret;
+#ifndef CONFIG_PCIEDW_NEW_IRQ_API
+	int i;
+#endif
+	int ret;
 	LIST_HEAD(res);
-	struct resource_entry *win, *tmp;
+
+	mutex_init(&pci->pp.lock);
 
 	cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
 	if (cfg_res) {
@@ -378,6 +595,12 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		if (!pp->ops->msi_host_init) {
+			ret = of_property_read_u32(np, "num-vectors",
+						   &pp->num_vectors);
+			if (ret)
+				pp->num_vectors = 1;
+
+#ifndef CONFIG_PCIEDW_NEW_IRQ_API
 			pp->irq_domain = irq_domain_add_linear(dev->of_node,
 						MAX_MSI_IRQS, &msi_domain_ops,
 						&dw_pcie_msi_chip);
@@ -389,6 +612,15 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
 			for (i = 0; i < MAX_MSI_IRQS; i++)
 				irq_create_mapping(pp->irq_domain, i);
+#else
+			ret = dw_pcie_allocate_domains(pci);
+			if (ret)
+				goto error;
+
+			irq_set_chained_handler_and_data(pci->pp.msi_irq,
+							 dw_chained_msi_isr,
+							 pci);
+#endif
 		} else {
 			ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
 			if (ret < 0)
@@ -400,6 +632,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
 		pp->ops->host_init(pp);
 
 	pp->root_bus_nr = pp->busn->start;
+#ifndef CONFIG_PCIEDW_NEW_IRQ_API
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		bus = pci_scan_root_bus_msi(dev, pp->root_bus_nr,
 					    &dw_pcie_ops, pp, &res,
@@ -408,6 +641,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	} else
 		bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
 					pp, &res);
+#else
+	bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
+				pp, &res);
+#endif
 	if (!bus) {
 		ret = -ENOMEM;
 		goto error;
drivers/pci/dwc/pcie-designware.h +5 -0
index c6a8405..15481a5 100644
@@ -165,7 +165,10 @@ struct pcie_port {
 	struct dw_pcie_host_ops	*ops;
 	int			msi_irq;
 	struct irq_domain	*irq_domain;
+	struct irq_domain	*msi_domain;
 	unsigned long		msi_data;
+	u32			num_vectors;
+	struct mutex		lock;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
@@ -282,8 +285,10 @@ static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
 #ifdef CONFIG_PCIE_DW_HOST
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
+void dw_pcie_free_msi(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
+int dw_pcie_allocate_domains(struct dw_pcie *pci);
 #else
 static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 {
Signature · 1 line
2.9.3
#2 lore raw

Re: [RFC 1/8] pci: adding new irq api to pci-designware

Am Freitag, den 12.05.2017, 17:56 +0100 schrieb Joao Pinto:

Quoted 13 lines

This patch adds the new interrupt api to pecie-designware, keeping the old one. A define was added to toggle between the two apis (for testing purposes).

---
 drivers/pci/dwc/pcie-designware-host.c | 241 ++++++++++++++++++++++++++++++++-
 drivers/pci/dwc/pcie-designware.h      |   5 +
 2 files changed, 244 insertions(+), 2 deletions(-)
drivers/pci/dwc/pcie-designware-host.c +0 -0
index 28ed32b..6810ea10b 100644

[...]

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 220

Quoted 11 lines
drivers/pci/dwc/pcie-designware-host.c +11 -0
+static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs,
+				    void *args)
+{
+	struct dw_pcie *pci = domain->host_data;
+	struct pcie_port *pp = &pci->pp;
+	unsigned long bit;
+
+	mutex_lock(&pp->lock);
+
+	WARN_ON(nr_irqs != 1);

So the new API doesn't support multi MSI, where we need more than a single contiguous MSI in a range? If this is the case then this change is breaking real use-cases that work today.

Regards,
Luvas

#3 lore raw

Re: [RFC 1/8] pci: adding new irq api to pci-designware

In reply to Joao Pinto

Joao,

You seem to have dropped a number of things I had mentioned on my previous review of this patch. See below:

Quoted 22 lines · Joao Pinto

This patch adds the new interrupt api to pecie-designware, keeping the old one. A define was added to toggle between the two apis (for testing purposes).

---
 drivers/pci/dwc/pcie-designware-host.c | 241 ++++++++++++++++++++++++++++++++-
 drivers/pci/dwc/pcie-designware.h      |   5 +
 2 files changed, 244 insertions(+), 2 deletions(-)
drivers/pci/dwc/pcie-designware-host.c +1 -0
index 28ed32b..6810ea10b 100644
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>

drivers/pci/dwc/pcie-designware-host.c line 24

Quoted 5 lines
drivers/pci/dwc/pcie-designware-host.c +2 -0
@@ -19,6 +20,9 @@
 
 #include "pcie-designware.h"
 
+/* Temporary: Activate to use new IRQ API */
+/*#define CONFIG_PCIEDW_NEW_IRQ_API*/

You should be able to support both APIs at the same time until the last patch, without relying on a kernel configuration (we still want to be able to boot a single kernel that works both with the old and new methods).

Quoted 66 lines
drivers/pci/dwc/pcie-designware-host.c +45 -0
+
 static struct pci_ops dw_pcie_ops;
 
 static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
@@ -45,6 +49,7 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
 	return dw_pcie_write(pci->dbi_base + where, size, val);
 }
 
+#ifndef CONFIG_PCIEDW_NEW_IRQ_API
 static struct irq_chip dw_msi_irq_chip = {
 	.name = "PCI-MSI",
 	.irq_enable = pci_msi_unmask_irq,
@@ -52,6 +57,29 @@ static struct irq_chip dw_msi_irq_chip = {
 	.irq_mask = pci_msi_mask_irq,
 	.irq_unmask = pci_msi_unmask_irq,
 };
+#else
+static void dw_msi_mask_irq(struct irq_data *d) {
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void dw_msi_unmask_irq(struct irq_data *d) {
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip dw_msi_irq_chip = {
+	.name = "PCI-MSI",
+	.irq_mask = dw_msi_mask_irq,
+	.irq_unmask = dw_msi_unmask_irq,
+};
+
+static struct msi_domain_info dw_pcie_msi_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+		     MSI_FLAG_PCI_MSIX),
+	.chip	= &dw_msi_irq_chip,
+};
+#endif
 
 /* MSI int handler */
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
@@ -81,6 +109,190 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 	return ret;
 }
 
+#ifdef CONFIG_PCIEDW_NEW_IRQ_API
+/* Chained MSI interrupt service routine */
+static void dw_chained_msi_isr(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct pcie_port *pp;
+	struct dw_pcie *pci;
+
+	chained_irq_enter(chip, desc);
+	pci = irq_desc_get_handler_data(desc);
+	pp = &pci->pp;
+
+	dw_handle_msi_irq(pp);
+
+	chained_irq_exit(chip, desc);
+}
+
+static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 141

Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10 -0
+	struct pcie_port *pp = &pci->pp;
+	u64 msi_target;
+
+	if (pp->ops->get_msi_addr)
+		msi_target = pp->ops->get_msi_addr(pp);
+	else
+		msi_target = virt_to_phys((void *)pp->msi_data);
+
+	msg->address_lo = (u32)(msi_target & 0xffffffff);
+	msg->address_hi = (u32)(msi_target >> 32 & 0xffffffff);

Use lower_32_bit/upper_32_bit macros.

Quoted 13 lines
drivers/pci/dwc/pcie-designware-host.c +13 -0
+
+	if (pp->ops->get_msi_data)
+		msg->data = pp->ops->get_msi_data(pp, data->hwirq);
+	else
+		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 dw_pci_msi_set_affinity(struct irq_data *irq_data,
+				   const struct cpumask *mask, bool force)
+{

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 164

Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10 -0
+	return -EINVAL;
+}
+
+static void dw_pci_bottom_mask(struct irq_data *data)
+{
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+	struct pcie_port *pp = &pci->pp;
+	unsigned int res, bit, val;
+
+	mutex_lock(&pp->lock);

This is wrong. You can also end-up here from interrupt context, so you need an spin_lock_irqsave().

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 167

Quoted 3 lines
drivers/pci/dwc/pcie-designware-host.c +3 -0
+
+	if (pp->ops->msi_clear_irq)
+		pp->ops->msi_clear_irq(pp, data->hwirq);

Why do you need this? Can you have alternative implementations of mask/unmask?

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 172

Quoted 5 lines
drivers/pci/dwc/pcie-designware-host.c +5 -0
+	else {
+		res = (data->hwirq / 32) * 12;
+		bit = data->hwirq % 32;
+
+		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);

No use reading back from the HW. Just maintain a cached version in your private structure and just use that.

Quoted 17 lines
drivers/pci/dwc/pcie-designware-host.c +17 -0
+		val &= ~(1 << bit);
+		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+	}
+
+	mutex_unlock(&pp->lock);
+}
+
+static void dw_pci_bottom_unmask(struct irq_data *data)
+{
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+	struct pcie_port *pp = &pci->pp;
+	unsigned int res, bit, val;
+
+	mutex_lock(&pp->lock);
+
+	if (pp->ops->msi_set_irq)
+		pp->ops->msi_set_irq(pp, data->hwirq);

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 199

Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10 -0
+	else {
+		res = (data->hwirq / 32) * 12;
+		bit = data->hwirq % 32;
+
+		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+		val |= 1 << bit;
+		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+	}
+
+	mutex_unlock(&pp->lock);

Same comments.

Quoted 21 lines
drivers/pci/dwc/pcie-designware-host.c +21 -0
+}
+
+static struct irq_chip dw_pci_msi_bottom_irq_chip = {
+	.name			= "DWPCI-MSI",
+	.irq_compose_msi_msg	= dw_pci_setup_msi_msg,
+	.irq_set_affinity	= dw_pci_msi_set_affinity,
+	.irq_mask		= dw_pci_bottom_mask,
+	.irq_unmask		= dw_pci_bottom_unmask,
+};
+
+static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs,
+				    void *args)
+{
+	struct dw_pcie *pci = domain->host_data;
+	struct pcie_port *pp = &pci->pp;
+	unsigned long bit;
+
+	mutex_lock(&pp->lock);
+
+	WARN_ON(nr_irqs != 1);

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 230

Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10 -0
+
+	bit = find_first_zero_bit(pp->msi_irq_in_use, pp->num_vectors);
+	if (bit >= pp->num_vectors) {
+		mutex_unlock(&pp->lock);
+		return -ENOSPC;
+	}
+
+	set_bit(bit, pp->msi_irq_in_use);
+
+	mutex_unlock(&pp->lock);

As mentioned by Lucas, you probably want to support Multi-MSI.

Quoted 14 lines
drivers/pci/dwc/pcie-designware-host.c +14 -0
+
+	irq_domain_set_info(domain, virq, bit, &dw_pci_msi_bottom_irq_chip,
+			    domain->host_data, handle_simple_irq,
+			    NULL, NULL);
+
+	return 0;
+}
+
+static void dw_pcie_irq_domain_free(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs)
+{
+	struct irq_data *data = irq_domain_get_irq_data(domain, virq);
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+	struct pcie_port *pp = &pci->pp;

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 254

Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10 -0
+
+	mutex_lock(&pp->lock);
+
+	if (!test_bit(data->hwirq, pp->msi_irq_in_use))
+		dev_err(pci->dev, "trying to free unused MSI#%lu\n",
+			data->hwirq);
+	else
+		__clear_bit(data->hwirq, pp->msi_irq_in_use);
+
+	mutex_unlock(&pp->lock);

Same here.

Quoted 4 lines
drivers/pci/dwc/pcie-designware-host.c +4 -0
+}
+
+static const struct irq_domain_ops dw_pcie_msi_domain_ops = {
+	.alloc	= dw_pcie_irq_domain_alloc,

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 268

Quoted 10 lines
drivers/pci/dwc/pcie-designware-host.c +10 -0
+	.free	= dw_pcie_irq_domain_free,
+};
+
+int dw_pcie_allocate_domains(struct dw_pcie *pci)
+{
+	struct pcie_port *pp = &pci->pp;
+	struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);
+
+	pp->irq_domain = irq_domain_add_linear(NULL, pp->num_vectors,
+					       &dw_pcie_msi_domain_ops, pci);

Please use irq_domain_create_linear and pass the fwnode there as well.

Quoted 114 lines
drivers/pci/dwc/pcie-designware-host.c +54 -2
+	if (!pp->irq_domain) {
+		dev_err(pci->dev, "failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	pp->msi_domain = pci_msi_create_irq_domain(fwnode,
+						   &dw_pcie_msi_domain_info,
+						   pp->irq_domain);
+	if (!pp->msi_domain) {
+		dev_err(pci->dev, "failed to create MSI domain\n");
+		irq_domain_remove(pp->irq_domain);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void dw_pcie_free_msi(struct pcie_port *pp)
+{
+	irq_set_chained_handler(pp->msi_irq, NULL);
+	irq_set_handler_data(pp->msi_irq, NULL);
+
+	irq_domain_remove(pp->msi_domain);
+	irq_domain_remove(pp->irq_domain);
+}
+#endif
+
 void dw_pcie_msi_init(struct pcie_port *pp)
 {
 	u64 msi_target;
@@ -279,11 +491,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	struct device *dev = pci->dev;
 	struct device_node *np = dev->of_node;
 	struct platform_device *pdev = to_platform_device(dev);
+	struct resource_entry *win, *tmp;
 	struct pci_bus *bus, *child;
 	struct resource *cfg_res;
-	int i, ret;
+#ifndef CONFIG_PCIEDW_NEW_IRQ_API
+	int i;
+#endif
+	int ret;
 	LIST_HEAD(res);
-	struct resource_entry *win, *tmp;
+
+	mutex_init(&pci->pp.lock);
 
 	cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
 	if (cfg_res) {
@@ -378,6 +595,12 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		if (!pp->ops->msi_host_init) {
+			ret = of_property_read_u32(np, "num-vectors",
+						   &pp->num_vectors);
+			if (ret)
+				pp->num_vectors = 1;
+
+#ifndef CONFIG_PCIEDW_NEW_IRQ_API
 			pp->irq_domain = irq_domain_add_linear(dev->of_node,
 						MAX_MSI_IRQS, &msi_domain_ops,
 						&dw_pcie_msi_chip);
@@ -389,6 +612,15 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
 			for (i = 0; i < MAX_MSI_IRQS; i++)
 				irq_create_mapping(pp->irq_domain, i);
+#else
+			ret = dw_pcie_allocate_domains(pci);
+			if (ret)
+				goto error;
+
+			irq_set_chained_handler_and_data(pci->pp.msi_irq,
+							 dw_chained_msi_isr,
+							 pci);
+#endif
 		} else {
 			ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
 			if (ret < 0)
@@ -400,6 +632,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
 		pp->ops->host_init(pp);
 
 	pp->root_bus_nr = pp->busn->start;
+#ifndef CONFIG_PCIEDW_NEW_IRQ_API
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		bus = pci_scan_root_bus_msi(dev, pp->root_bus_nr,
 					    &dw_pcie_ops, pp, &res,
@@ -408,6 +641,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	} else
 		bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
 					pp, &res);
+#else
+	bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
+				pp, &res);
+#endif
 	if (!bus) {
 		ret = -ENOMEM;
 		goto error;
drivers/pci/dwc/pcie-designware.h +3 -0
index c6a8405..15481a5 100644
@@ -165,7 +165,10 @@ struct pcie_port {
 	struct dw_pcie_host_ops	*ops;
 	int			msi_irq;
 	struct irq_domain	*irq_domain;
+	struct irq_domain	*msi_domain;
 	unsigned long		msi_data;
+	u32			num_vectors;
+	struct mutex		lock;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 

drivers/pci/dwc/pcie-designware.h static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg) · line 294

Quoted 10 lines
drivers/pci/dwc/pcie-designware.h +2 -0
@@ -282,8 +285,10 @@ static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
 #ifdef CONFIG_PCIE_DW_HOST
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
+void dw_pcie_free_msi(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
+int dw_pcie_allocate_domains(struct dw_pcie *pci);
 #else
 static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 {

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
author
#4 lore raw

Re: [RFC 1/8] pci: adding new irq api to pci-designware

Hi Mark and Lucas,

Às 6:36 PM de 5/12/2017, Marc Zyngier escreveu:

Quoted 29 lines

Joao,

You seem to have dropped a number of things I had mentioned on my previous review of this patch. See below:

Quoted 23 lines · Joao Pinto

This patch adds the new interrupt api to pecie-designware, keeping the old one. A define was added to toggle between the two apis (for testing purposes).

---
 drivers/pci/dwc/pcie-designware-host.c | 241 ++++++++++++++++++++++++++++++++-
 drivers/pci/dwc/pcie-designware.h      |   5 +
 2 files changed, 244 insertions(+), 2 deletions(-)
drivers/pci/dwc/pcie-designware-host.c +1 -0
index 28ed32b..6810ea10b 100644
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
@@ -19,6 +20,9 @@
 
Quoted 8 lines

drivers/pci/dwc/pcie-designware-host.c line 24

Quoted 4 lines
drivers/pci/dwc/pcie-designware-host.c +2 -0
 #include "pcie-designware.h"
 
+/* Temporary: Activate to use new IRQ API */
+/*#define CONFIG_PCIEDW_NEW_IRQ_API*/

You should be able to support both APIs at the same time until the last patch, without relying on a kernel configuration (we still want to be able to boot a single kernel that works both with the old and new methods).

I think that the APIs are mutual-exclusive. pcie-designware has to initialize of one of them. Your idea is to have the new and the old API functions, but only initialize pcie-designware with the old one until the last patch?

[...]

Quoted 5 lines

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 141

Quoted 3 lines
drivers/pci/dwc/pcie-designware-host.c +3 -0
+
+	msg->address_lo = (u32)(msi_target & 0xffffffff);
+	msg->address_hi = (u32)(msi_target >> 32 & 0xffffffff);

Use lower_32_bit/upper_32_bit macros.

Right, I am going to update this.

[...]

Quoted 11 lines

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 164

Quoted 8 lines
drivers/pci/dwc/pcie-designware-host.c +8 -0
+
+static void dw_pci_bottom_mask(struct irq_data *data)
+{
+	struct dw_pcie *pci = irq_data_get_irq_chip_data(data);
+	struct pcie_port *pp = &pci->pp;
+	unsigned int res, bit, val;
+
+	mutex_lock(&pp->lock);

This is wrong. You can also end-up here from interrupt context, so you need an spin_lock_irqsave().

Right, I am going to update this.

[...]

Quoted 7 lines

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 167

Quoted 4 lines
drivers/pci/dwc/pcie-designware-host.c +3 -0
+
+	if (pp->ops->msi_clear_irq)
+		pp->ops->msi_clear_irq(pp, data->hwirq);

Why do you need this? Can you have alternative implementations of mask/unmask?

msi_clear_irq and msi_set_irq are specific SoC operations to set and clear bits in the interrupt register. In my opinion we should keep the current callbacks.

[...]

Quoted 9 lines

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 172

Quoted 6 lines
drivers/pci/dwc/pcie-designware-host.c +5 -0
+	else {
+		res = (data->hwirq / 32) * 12;
+		bit = data->hwirq % 32;
+
+		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);

No use reading back from the HW. Just maintain a cached version in your private structure and just use that.

Ok, I can do that.

[...]

Quoted 4 lines
Quoted 4 lines
drivers/pci/dwc/pcie-designware-host.c +4 -0
+
+	bit = find_first_zero_bit(pp->msi_irq_in_use, pp->num_vectors);
+	if (bit >= pp->num_vectors) {
+		mutex_unlock(&pp->lock);
Quoted 9 lines

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 230

Quoted 6 lines
drivers/pci/dwc/pcie-designware-host.c +6 -0
+		return -ENOSPC;
+	}
+
+	set_bit(bit, pp->msi_irq_in_use);
+
+	mutex_unlock(&pp->lock);

As mentioned by Lucas, you probably want to support Multi-MSI.

This could be achieved by declaring data for each virq, correct?

for (i = 0; i < nr_irqs; i++) { irq_domain_set_info(domain, virq + i, bit + i, &dw_pci_msi_bottom_irq_chip,domain->host_data, handle_simple_irq, NULL, NULL);
}

[...]

Quoted 6 lines

drivers/pci/dwc/pcie-designware-host.c irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) · line 268

Quoted 3 lines
drivers/pci/dwc/pcie-designware-host.c +3 -0
+
+	pp->irq_domain = irq_domain_add_linear(NULL, pp->num_vectors,
+					       &dw_pcie_msi_domain_ops, pci);

Please use irq_domain_create_linear and pass the fwnode there as well.

Ok, I will do that.

[...]

Quoted 8 lines
Quoted 3 lines

static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) {

Thanks,

	M.

Thank you for you feeback!

Joao

author
#5 lore raw

RFC 2/8 pci: exynos SoC driver adapted to new irq API

In reply to Joao Pinto

This patch adapts Exynos SoC specific driver to use the new interrupt api available in pcie-designware.

---
 drivers/pci/dwc/pci-exynos.c | 18 ------------------
 1 file changed, 18 deletions(-)
drivers/pci/dwc/pci-exynos.c +0 -18
index 546082a..e49c39a 100644
@@ -490,15 +490,6 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg)
-{
-	struct exynos_pcie *ep = arg;
-	struct dw_pcie *pci = ep->pci;
-	struct pcie_port *pp = &pci->pp;
-
-	return dw_handle_msi_irq(pp);
-}
-
 static void exynos_pcie_msi_init(struct exynos_pcie *ep)
 {
 	struct dw_pcie *pci = ep->pci;
@@ -622,15 +613,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
 			dev_err(dev, "failed to get msi irq\n");
 			return -ENODEV;
 		}
-
-		ret = devm_request_irq(dev, pp->msi_irq,
-					exynos_pcie_msi_irq_handler,
-					IRQF_SHARED | IRQF_NO_THREAD,
-					"exynos-pcie", ep);
-		if (ret) {
-			dev_err(dev, "failed to request msi irq\n");
-			return ret;
-		}
 	}
 
 	pp->root_bus_nr = -1;
Signature · 1 line
2.9.3
author
#6 lore raw

RFC 3/8 pci: imx6 SoC driver adapted to new irq API

In reply to Joao Pinto

This patch adapts imx6 SoC specific driver to use the new interrupt api available in pcie-designware.

---
 drivers/pci/dwc/pci-imx6.c | 18 ------------------
 1 file changed, 18 deletions(-)
drivers/pci/dwc/pci-imx6.c +0 -18
index a98cba5..f22ce1f 100644
@@ -490,15 +490,6 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
 	return -EINVAL;
 }
 
-static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg)
-{
-	struct imx6_pcie *imx6_pcie = arg;
-	struct dw_pcie *pci = imx6_pcie->pci;
-	struct pcie_port *pp = &pci->pp;
-
-	return dw_handle_msi_irq(pp);
-}
-
 static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 {
 	struct dw_pcie *pci = imx6_pcie->pci;
@@ -620,15 +611,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
 			dev_err(dev, "failed to get MSI irq\n");
 			return -ENODEV;
 		}
-
-		ret = devm_request_irq(dev, pp->msi_irq,
-				       imx6_pcie_msi_handler,
-				       IRQF_SHARED | IRQF_NO_THREAD,
-				       "mx6-pcie-msi", imx6_pcie);
-		if (ret) {
-			dev_err(dev, "failed to request MSI irq\n");
-			return ret;
-		}
 	}
 
 	pp->root_bus_nr = -1;
Signature · 1 line
2.9.3
author
#7 lore raw

RFC 4/8 pci: artpec6 SoC driver adapted to new irq API

In reply to Joao Pinto

This patch adapts artpec6 SoC specific driver to use the new interrupt api available in pcie-designware.

---
 drivers/pci/dwc/pcie-artpec6.c | 18 ------------------
 1 file changed, 18 deletions(-)
drivers/pci/dwc/pcie-artpec6.c +0 -18
index 82a04ac..d81789b 100644
@@ -188,15 +188,6 @@ static struct dw_pcie_host_ops artpec6_pcie_host_ops = {
 	.host_init = artpec6_pcie_host_init,
 };
 
-static irqreturn_t artpec6_pcie_msi_handler(int irq, void *arg)
-{
-	struct artpec6_pcie *artpec6_pcie = arg;
-	struct dw_pcie *pci = artpec6_pcie->pci;
-	struct pcie_port *pp = &pci->pp;
-
-	return dw_handle_msi_irq(pp);
-}
-
 static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
 				 struct platform_device *pdev)
 {
@@ -211,15 +202,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
 			dev_err(dev, "failed to get MSI irq\n");
 			return -ENODEV;
 		}
-
-		ret = devm_request_irq(dev, pp->msi_irq,
-				       artpec6_pcie_msi_handler,
-				       IRQF_SHARED | IRQF_NO_THREAD,
-				       "artpec6-pcie-msi", artpec6_pcie);
-		if (ret) {
-			dev_err(dev, "failed to request MSI irq\n");
-			return ret;
-		}
 	}
 
 	pp->root_bus_nr = -1;
Signature · 1 line
2.9.3
author
#8 lore raw

RFC 5/8 pci: generic PCIe DW driver adapted to new irq API

In reply to Joao Pinto

This patch adapts the generic PCIe DW driver to use the new interrupt api available in pcie-designware.

---
 drivers/pci/dwc/pcie-designware-plat.c | 15 ---------------
 1 file changed, 15 deletions(-)
drivers/pci/dwc/pcie-designware-plat.c +0 -15
index 32091b3..3b9717b 100644
@@ -28,13 +28,6 @@ struct dw_plat_pcie {
 	struct dw_pcie		*pci;
 };
 
-static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg)
-{
-	struct pcie_port *pp = arg;
-
-	return dw_handle_msi_irq(pp);
-}
-
 static void dw_plat_pcie_host_init(struct pcie_port *pp)
 {
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -64,14 +57,6 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp,
 		pp->msi_irq = platform_get_irq(pdev, 0);
 		if (pp->msi_irq < 0)
 			return pp->msi_irq;
-
-		ret = devm_request_irq(dev, pp->msi_irq,
-					dw_plat_pcie_msi_irq_handler,
-					IRQF_SHARED, "dw-plat-pcie-msi", pp);
-		if (ret) {
-			dev_err(dev, "failed to request MSI IRQ\n");
-			return ret;
-		}
 	}
 
 	pp->root_bus_nr = -1;
Signature · 1 line
2.9.3
author
#9 lore raw

RFC 6/8 pci: qcom SoC driver adapted to new irq API

In reply to Joao Pinto

This patch adapts Qcom SoC specific driver to use the new interrupt api available in pcie-designware.

---
 drivers/pci/dwc/pcie-qcom.c | 15 ---------------
 1 file changed, 15 deletions(-)
drivers/pci/dwc/pcie-qcom.c +0 -15
index 5bf23d4..4e1cc02 100644
@@ -126,13 +126,6 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
 	usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
 }
 
-static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg)
-{
-	struct pcie_port *pp = arg;
-
-	return dw_handle_msi_irq(pp);
-}
-
 static void qcom_pcie_v0_v1_ltssm_enable(struct qcom_pcie *pcie)
 {
 	u32 val;
@@ -724,14 +717,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
 		pp->msi_irq = platform_get_irq_byname(pdev, "msi");
 		if (pp->msi_irq < 0)
 			return pp->msi_irq;
-
-		ret = devm_request_irq(dev, pp->msi_irq,
-				       qcom_pcie_msi_irq_handler,
-				       IRQF_SHARED, "qcom-pcie-msi", pp);
-		if (ret) {
-			dev_err(dev, "cannot request msi irq\n");
-			return ret;
-		}
 	}
 
 	ret = phy_init(pcie->phy);
Signature · 1 line
2.9.3
author
#10 lore raw

RFC 7/8 pci: keystone SoC driver adapted to new irq API

In reply to Joao Pinto

This patch adapts Keystone SoC specific driver to use the new interrupt api available in pcie-designware. A new callback was added to dw_pcie_host_ops to handle a specific Keystone function and msi_host_init callback is changed to simplify the access to pci data structure for keystone all SoC drivers that use the structure.

---
 drivers/pci/dwc/pci-keystone-dw.c      | 97 +++-------------------------------
 drivers/pci/dwc/pci-keystone.c         |  1 +
 drivers/pci/dwc/pci-keystone.h         |  4 +-
 drivers/pci/dwc/pci-layerscape.c       |  3 +-
 drivers/pci/dwc/pcie-designware-host.c | 12 ++++-
 drivers/pci/dwc/pcie-designware.h      |  3 +-
 6 files changed, 23 insertions(+), 97 deletions(-)
drivers/pci/dwc/pci-keystone-dw.c +6 -91
index 8bc626e..da1472e 100644
@@ -124,19 +124,15 @@ void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset)
 	}
 }
 
-static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
+void ks_dw_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
 {
 	u32 offset, reg_offset, bit_pos;
 	struct keystone_pcie *ks_pcie;
-	struct msi_desc *msi;
-	struct pcie_port *pp;
 	struct dw_pcie *pci;
 
-	msi = irq_data_get_msi_desc(d);
-	pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
 	pci = to_dw_pcie_from_pp(pp);
 	ks_pcie = to_keystone_pcie(pci);
-	offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
 	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
 
 	ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4),
@@ -166,93 +162,12 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
 			 BIT(bit_pos));
 }
 
-static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
+int ks_dw_pcie_msi_host_init(struct dw_pcie *pci, struct msi_controller *chip)
 {
-	struct keystone_pcie *ks_pcie;
-	struct msi_desc *msi;
-	struct pcie_port *pp;
-	struct dw_pcie *pci;
-	u32 offset;
-
-	msi = irq_data_get_msi_desc(d);
-	pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
-	pci = to_dw_pcie_from_pp(pp);
-	ks_pcie = to_keystone_pcie(pci);
-	offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
-
-	/* Mask the end point if PVM implemented */
-	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		if (msi->msi_attrib.maskbit)
-			pci_msi_mask_irq(d);
-	}
-
-	ks_dw_pcie_msi_clear_irq(pp, offset);
-}
-
-static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
-{
-	struct keystone_pcie *ks_pcie;
-	struct msi_desc *msi;
-	struct pcie_port *pp;
-	struct dw_pcie *pci;
-	u32 offset;
-
-	msi = irq_data_get_msi_desc(d);
-	pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
-	pci = to_dw_pcie_from_pp(pp);
-	ks_pcie = to_keystone_pcie(pci);
-	offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
-
-	/* Mask the end point if PVM implemented */
-	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		if (msi->msi_attrib.maskbit)
-			pci_msi_unmask_irq(d);
-	}
-
-	ks_dw_pcie_msi_set_irq(pp, offset);
-}
+	/* overide number of vectors and sent them to Keystone Max MSI IRQs */
+	pci->pp.num_vectors = MAX_MSI_IRQS;
 
-static struct irq_chip ks_dw_pcie_msi_irq_chip = {
-	.name = "Keystone-PCIe-MSI-IRQ",
-	.irq_ack = ks_dw_pcie_msi_irq_ack,
-	.irq_mask = ks_dw_pcie_msi_irq_mask,
-	.irq_unmask = ks_dw_pcie_msi_irq_unmask,
-};
-
-static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
-			      irq_hw_number_t hwirq)
-{
-	irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
-				 handle_level_irq);
-	irq_set_chip_data(irq, domain->host_data);
-
-	return 0;
-}
-
-static const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
-	.map = ks_dw_pcie_msi_map,
-};
-
-int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_controller *chip)
-{
-	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
-	struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-	struct device *dev = pci->dev;
-	int i;
-
-	pp->irq_domain = irq_domain_add_linear(ks_pcie->msi_intc_np,
-					MAX_MSI_IRQS,
-					&ks_dw_pcie_msi_domain_ops,
-					chip);
-	if (!pp->irq_domain) {
-		dev_err(dev, "irq domain init failed\n");
-		return -ENXIO;
-	}
-
-	for (i = 0; i < MAX_MSI_IRQS; i++)
-		irq_create_mapping(pp->irq_domain, i);
-
-	return 0;
+	return dw_pcie_allocate_domains(pci);
 }
 
 void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
drivers/pci/dwc/pci-keystone.c +1 -0
index fcc9723..a59bd9b 100644
@@ -299,6 +299,7 @@ static struct dw_pcie_host_ops keystone_pcie_host_ops = {
 	.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
 	.get_msi_addr = ks_dw_pcie_get_msi_addr,
 	.msi_host_init = ks_dw_pcie_msi_host_init,
+	.msi_irq_ack = ks_dw_pcie_msi_irq_ack,
 	.scan_bus = ks_dw_pcie_v3_65_scan_bus,
 };
 
drivers/pci/dwc/pci-keystone.h +2 -2
index 74c5825..83179382 100644
@@ -55,9 +55,9 @@ int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
 		unsigned int devfn, int where, int size, u32 *val);
 void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
 void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
+void ks_dw_pcie_msi_irq_ack(int i, struct pcie_port *pp);
 void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
 void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
 void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
-int ks_dw_pcie_msi_host_init(struct pcie_port *pp,
-		struct msi_controller *chip);
+int ks_dw_pcie_msi_host_init(struct dw_pcie *pci, struct msi_controller *chip);
 int ks_dw_pcie_link_up(struct dw_pcie *pci);
drivers/pci/dwc/pci-layerscape.c +1 -2
index 27d638c..4fb491b 100644
@@ -162,10 +162,9 @@ static void ls_pcie_host_init(struct pcie_port *pp)
 	iowrite32(0, pci->dbi_base + PCIE_DBI_RO_WR_EN);
 }
 
-static int ls_pcie_msi_host_init(struct pcie_port *pp,
+static int ls_pcie_msi_host_init(struct dw_pcie *pci,
 				 struct msi_controller *chip)
 {
-	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 	struct device *dev = pci->dev;
 	struct device_node *np = dev->of_node;
 	struct device_node *msi_node;
drivers/pci/dwc/pcie-designware-host.c +11 -1
index 6810ea10b..fbea485 100644
@@ -199,8 +199,18 @@ static void dw_pci_bottom_unmask(struct irq_data *data)
 	mutex_unlock(&pp->lock);
 }
 
+static void dw_pci_bottom_ack(struct irq_data *d)
+{
+	struct msi_desc *msi = irq_data_get_msi_desc(d);
+	struct pcie_port *pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
+
+	if (pp->ops->msi_irq_ack)
+		pp->ops->msi_irq_ack(d->irq, pp);
+}
+
 static struct irq_chip dw_pci_msi_bottom_irq_chip = {
 	.name			= "DWPCI-MSI",
+	.irq_ack		= dw_pci_bottom_ack,
 	.irq_compose_msi_msg	= dw_pci_setup_msi_msg,
 	.irq_set_affinity	= dw_pci_msi_set_affinity,
 	.irq_mask		= dw_pci_bottom_mask,
@@ -622,7 +632,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
 							 pci);
 #endif
 		} else {
-			ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
+			ret = pp->ops->msi_host_init(pci, &dw_pcie_msi_chip);
 			if (ret < 0)
 				goto error;
 		}
drivers/pci/dwc/pcie-designware.h +2 -1
index 15481a5..9b621f9 100644
@@ -140,7 +140,8 @@ struct dw_pcie_host_ops {
 	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);
-	int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
+	int (*msi_host_init)(struct dw_pcie *pci, struct msi_controller *chip);
+	void (*msi_irq_ack)(int irq, struct pcie_port *pp);
 };
 
 struct pcie_port {
Signature · 1 line
2.9.3
author
#11 lore raw

RFC 8/8 pci: removing old irq api from pcie-designware

In reply to Joao Pinto

This patch removes the old interrupt API.

---
 drivers/pci/dwc/pci-keystone-dw.c      |   2 +-
 drivers/pci/dwc/pci-keystone.h         |   2 +-
 drivers/pci/dwc/pci-layerscape.c       |   3 +-
 drivers/pci/dwc/pcie-designware-host.c | 224 +--------------------------------
 drivers/pci/dwc/pcie-designware.h      |   2 +-
 5 files changed, 6 insertions(+), 227 deletions(-)
drivers/pci/dwc/pci-keystone-dw.c +1 -1
index da1472e..30a5352 100644
@@ -162,7 +162,7 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
 			 BIT(bit_pos));
 }
 
-int ks_dw_pcie_msi_host_init(struct dw_pcie *pci, struct msi_controller *chip)
+int ks_dw_pcie_msi_host_init(struct dw_pcie *pci)
 {
 	/* overide number of vectors and sent them to Keystone Max MSI IRQs */
 	pci->pp.num_vectors = MAX_MSI_IRQS;
drivers/pci/dwc/pci-keystone.h +1 -1
index 83179382..89119271 100644
@@ -59,5 +59,5 @@ void ks_dw_pcie_msi_irq_ack(int i, struct pcie_port *pp);
 void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
 void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
 void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
-int ks_dw_pcie_msi_host_init(struct dw_pcie *pci, struct msi_controller *chip);
+int ks_dw_pcie_msi_host_init(struct dw_pcie *pci);
 int ks_dw_pcie_link_up(struct dw_pcie *pci);
drivers/pci/dwc/pci-layerscape.c +1 -2
index 4fb491b..231ea75 100644
@@ -162,8 +162,7 @@ static void ls_pcie_host_init(struct pcie_port *pp)
 	iowrite32(0, pci->dbi_base + PCIE_DBI_RO_WR_EN);
 }
 
-static int ls_pcie_msi_host_init(struct dw_pcie *pci,
-				 struct msi_controller *chip)
+static int ls_pcie_msi_host_init(struct dw_pcie *pci)
 {
 	struct device *dev = pci->dev;
 	struct device_node *np = dev->of_node;
drivers/pci/dwc/pcie-designware-host.c +2 -222

287 lines not on this page · raw message

drivers/pci/dwc/pcie-designware.h +1 -1
index 9b621f9..e79c85d 100644
@@ -140,7 +140,7 @@ struct dw_pcie_host_ops {
 	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);
-	int (*msi_host_init)(struct dw_pcie *pci, struct msi_controller *chip);
+	int (*msi_host_init)(struct dw_pcie *pci);
 	void (*msi_irq_ack)(int irq, struct pcie_port *pp);
 };
 
Signature · 1 line
2.9.3