All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] pci: using new interrupt API to enable MSI and MSI-X
@ 2017-05-05 14:11 Joao Pinto
  2017-05-05 14:57 ` Marc Zyngier
  0 siblings, 1 reply; 12+ messages in thread
From: Joao Pinto @ 2017-05-05 14:11 UTC (permalink / raw)
  To: kishon, bhelgaas, jingoohan1, marc.zyngier; +Cc: linux-pci, Joao Pinto

Hello,
I am currently adding the support for both MSI and MSI-x in pcie-designware and
I am now facing a dificulty.

My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
the changes introduced by this patch we are able to enable MSI and MSI-X
in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).

The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
bogus (524288) when it should be 1, and so I am not receiving any interrupts
from the endpoint.

I would apreciate that more experienced people in this interrupt subject could
give me an hint.

I send you the "lspci -v" results and /proc/interrupts.

Thank you so much for your help.

# cat /proc/interrupts
           CPU0
  3:        755  ARC In-core Intc   3  Timer0 (per-cpu-tick)
  4:          0  dw-apb-ictl   4  eth0
  8:          1  dw-apb-ictl   8  ehci_hcd:usb1, ohci_hcd:usb2
  9:         37  dw-apb-ictl   7  dw-mci
 14:          0  dw-apb-ictl  14  e001d000.i2c
 16:          0  dw-apb-ictl  16  e001f000.i2c
 19:        145  dw-apb-ictl  19  serial
 45:          0   PCI-MSI   0  aerdrv
 46:          0   PCI-MSI 524288  xhci_hcd

# lspci -v
00:00.0 PCI bridge: Synopsys, Inc. Device eddc (rev 01) (prog-if 00 [Normal decode])
        Flags: bus master, fast devsel, latency 0, IRQ 45
        Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
        Memory behind bridge: d0400000-d04fffff
        [virtual] Expansion ROM at d0500000 [disabled] [size=64K]
        Capabilities: [40] Power Management version 3
        Capabilities: [50] MSI: Enable+ Count=1/1 Maskable- 64bit+
        Capabilities: [70] Express Root Port (Slot-), MSI 00
        Capabilities: [100] Advanced Error Reporting
        Capabilities: [148] #19
        Capabilities: [158] Vendor Specific Information: ID=0002 Rev=4 Len=100 <?>
        Kernel driver in use: pcieport

01:00.0 USB controller: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller (prog-if 30 [XHCI])
        Subsystem: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller
        Flags: bus master, fast devsel, latency 0, IRQ 46
        Memory at d0400000 (64-bit, non-prefetchable) [size=32K]
        Capabilities: [50] MSI: Enable+ Count=1/8 Maskable- 64bit+
        Capabilities: [68] MSI-X: Enable- Count=8 Masked-
        Capabilities: [78] Power Management version 3
        Capabilities: [80] Express Endpoint, MSI 00
        Capabilities: [100] Virtual Channel
        Capabilities: [200] Advanced Error Reporting
        Capabilities: [280] #19
        Capabilities: [300] Latency Tolerance Reporting
        Kernel driver in use: xhci_hcd

Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
 .../devicetree/bindings/pci/designware-pcie.txt    |   2 +
 drivers/pci/dwc/pcie-designware-host.c             | 292 ++++++++-------------
 drivers/pci/dwc/pcie-designware-plat.c             |  35 +--
 drivers/pci/dwc/pcie-designware.h                  |   7 +-
 4 files changed, 143 insertions(+), 193 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
index b2480dd..41803ea 100644
--- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
@@ -34,6 +34,8 @@ Optional properties:
 RC mode:
 - num-viewport: number of view ports configured in
   hardware. If a platform does not specify it, the driver assumes 2.
+- num-vectors: number of available interrupt vectors. If a platform does not
+  specify it, the driver assumes 1.
 - bus-range: PCI bus numbers covered (it is recommended
   for new devicetrees to specify this property, to keep backwards
   compatibility a range of 0x00-0xff is assumed if not present)
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index 28ed32b..96a5fb3 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -11,6 +11,9 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/msi.h>
 #include <linux/irqdomain.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
@@ -53,32 +56,43 @@ static struct irq_chip dw_msi_irq_chip = {
 	.irq_unmask = pci_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,
+};
+
 /* MSI int handler */
-irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
+void dw_handle_msi_irq(struct irq_desc *desc)
 {
-	u32 val;
-	int i, pos, irq;
-	irqreturn_t ret = IRQ_NONE;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct pcie_port *pp;
+	struct dw_pcie *pci;
+	int i, pos, virq;
+	u32 status;
+
+	chained_irq_enter(chip, desc);
+	pci = irq_desc_get_handler_data(desc);
+	pp = &pci->pp;
 
 	for (i = 0; i < MAX_MSI_CTRLS; i++) {
 		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
-				    &val);
-		if (!val)
+				    &status);
+		if (!status)
 			continue;
 
-		ret = IRQ_HANDLED;
 		pos = 0;
-		while ((pos = find_next_bit((unsigned long *) &val, 32,
+		while ((pos = find_next_bit((unsigned long *) &status, 32,
 					    pos)) != 32) {
-			irq = irq_find_mapping(pp->irq_domain, i * 32 + pos);
+			virq = irq_find_mapping(pp->irq_domain, i * 32 + pos);
 			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12,
 					    4, 1 << pos);
-			generic_handle_irq(irq);
+			generic_handle_irq(virq);
 			pos++;
 		}
 	}
 
-	return ret;
+	chained_irq_exit(chip, desc);
 }
 
 void dw_pcie_msi_init(struct pcie_port *pp)
@@ -95,93 +110,10 @@ void dw_pcie_msi_init(struct pcie_port *pp)
 			    (u32)(msi_target >> 32 & 0xffffffff));
 }
 
-static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
-{
-	unsigned int res, bit, val;
-
-	res = (irq / 32) * 12;
-	bit = irq % 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);
-}
-
-static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
-			    unsigned int nvec, unsigned int pos)
-{
-	unsigned int i;
-
-	for (i = 0; i < nvec; i++) {
-		irq_set_msi_desc_off(irq_base, i, NULL);
-		/* Disable corresponding interrupt on MSI controller */
-		if (pp->ops->msi_clear_irq)
-			pp->ops->msi_clear_irq(pp, pos + i);
-		else
-			dw_pcie_msi_clear_irq(pp, pos + i);
-	}
-
-	bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec));
-}
-
-static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
-{
-	unsigned int res, bit, val;
-
-	res = (irq / 32) * 12;
-	bit = irq % 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);
-}
-
-static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
-{
-	int irq, pos0, i;
-	struct pcie_port *pp;
-
-	pp = (struct pcie_port *)msi_desc_to_pci_sysdata(desc);
-	pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS,
-				       order_base_2(no_irqs));
-	if (pos0 < 0)
-		goto no_valid_irq;
-
-	irq = irq_find_mapping(pp->irq_domain, pos0);
-	if (!irq)
-		goto no_valid_irq;
-
-	/*
-	 * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
-	 * descs so there is no need to allocate descs here. We can therefore
-	 * assume that if irq_find_mapping above returns non-zero, then the
-	 * descs are also successfully allocated.
-	 */
-
-	for (i = 0; i < no_irqs; i++) {
-		if (irq_set_msi_desc_off(irq, i, desc) != 0) {
-			clear_irq_range(pp, irq, i, pos0);
-			goto no_valid_irq;
-		}
-		/*Enable corresponding interrupt in MSI interrupt controller */
-		if (pp->ops->msi_set_irq)
-			pp->ops->msi_set_irq(pp, pos0 + i);
-		else
-			dw_pcie_msi_set_irq(pp, pos0 + i);
-	}
-
-	*pos = pos0;
-	desc->nvec_used = no_irqs;
-	desc->msi_attrib.multiple = order_base_2(no_irqs);
-
-	return irq;
-
-no_valid_irq:
-	*pos = pos0;
-	return -ENOSPC;
-}
-
-static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
+static void dw_pci_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
-	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)
@@ -189,89 +121,105 @@ static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
 	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);
+	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, pos);
+		msg->data = pp->ops->get_msi_data(pp, data->hwirq);
 	else
-		msg.data = pos;
+		msg->data = data->hwirq;
 
-	pci_write_msi_msg(irq, &msg);
+	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_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
-			    struct msi_desc *desc)
+static int dw_pci_msi_set_affinity(struct irq_data *irq_data,
+				   const struct cpumask *mask, bool force)
 {
-	int irq, pos;
-	struct pcie_port *pp = pdev->bus->sysdata;
-
-	if (desc->msi_attrib.is_msix)
-		return -EINVAL;
-
-	irq = assign_irq(1, desc, &pos);
-	if (irq < 0)
-		return irq;
-
-	dw_msi_setup_msg(pp, irq, pos);
-
-	return 0;
+	return -EINVAL;
 }
 
-static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
-			     int nvec, int type)
+static struct irq_chip dw_pci_msi_bottom_irq_chip = {
+	.name			= "DW MSI",
+	.irq_compose_msi_msg	= dw_pci_compose_msi_msg,
+	.irq_set_affinity	= dw_pci_msi_set_affinity,
+};
+
+static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs,
+				    void *args)
 {
-#ifdef CONFIG_PCI_MSI
-	int irq, pos;
-	struct msi_desc *desc;
-	struct pcie_port *pp = pdev->bus->sysdata;
+	struct dw_pcie *pci = domain->host_data;
+	struct pcie_port *pp = &pci->pp;
+	unsigned long bit;
 
-	/* MSI-X interrupts are not supported */
-	if (type == PCI_CAP_ID_MSIX)
-		return -EINVAL;
+	WARN_ON(nr_irqs != 1);
 
-	WARN_ON(!list_is_singular(&pdev->dev.msi_list));
-	desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
+	bit = find_first_zero_bit(pp->msi_irq_in_use, pp->num_vectors);
+	if (bit >= pp->num_vectors) {
+		return -ENOSPC;
+	}
 
-	irq = assign_irq(nvec, desc, &pos);
-	if (irq < 0)
-		return irq;
+	set_bit(bit, pp->msi_irq_in_use);
 
-	dw_msi_setup_msg(pp, irq, pos);
+	irq_domain_set_info(domain, virq, bit, &dw_pci_msi_bottom_irq_chip,
+			    domain->host_data, handle_simple_irq,
+			    NULL, NULL);
 
 	return 0;
-#else
-	return -EINVAL;
-#endif
 }
 
-static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
+static void dw_pcie_irq_domain_free(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs)
 {
-	struct irq_data *data = irq_get_irq_data(irq);
-	struct msi_desc *msi = irq_data_get_msi_desc(data);
-	struct pcie_port *pp = (struct pcie_port *)msi_desc_to_pci_sysdata(msi);
+	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;
 
-	clear_irq_range(pp, irq, 1, data->hwirq);
+	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);
 }
 
-static struct msi_controller dw_pcie_msi_chip = {
-	.setup_irq = dw_msi_setup_irq,
-	.setup_irqs = dw_msi_setup_irqs,
-	.teardown_irq = dw_msi_teardown_irq,
+static const struct irq_domain_ops dw_pcie_msi_domain_ops = {
+	.alloc	= dw_pcie_irq_domain_alloc,
+	.free	= dw_pcie_irq_domain_free,
 };
 
-static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
-			   irq_hw_number_t hwirq)
+static int dw_pcie_allocate_domains(struct dw_pcie *pci)
 {
-	irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
-	irq_set_chip_data(irq, domain->host_data);
+	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;
 }
 
-static const struct irq_domain_ops msi_domain_ops = {
-	.map = dw_pcie_msi_map,
-};
+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);
+}
 
 int dw_pcie_host_init(struct pcie_port *pp)
 {
@@ -281,7 +229,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	struct platform_device *pdev = to_platform_device(dev);
 	struct pci_bus *bus, *child;
 	struct resource *cfg_res;
-	int i, ret;
+	int ret;
 	LIST_HEAD(res);
 	struct resource_entry *win, *tmp;
 
@@ -377,37 +325,29 @@ int dw_pcie_host_init(struct pcie_port *pp)
 		pci->num_viewport = 2;
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		if (!pp->ops->msi_host_init) {
-			pp->irq_domain = irq_domain_add_linear(dev->of_node,
-						MAX_MSI_IRQS, &msi_domain_ops,
-						&dw_pcie_msi_chip);
-			if (!pp->irq_domain) {
-				dev_err(dev, "irq domain init failed\n");
-				ret = -ENXIO;
-				goto error;
-			}
 
-			for (i = 0; i < MAX_MSI_IRQS; i++)
-				irq_create_mapping(pp->irq_domain, i);
-		} else {
-			ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
-			if (ret < 0)
-				goto error;
-		}
+		ret = of_property_read_u32(np, "num-vectors",
+					   &pp->num_vectors);
+		if (ret)
+			pp->num_vectors = 1;
+
+		ret = dw_pcie_allocate_domains(pci);
+		if (ret)
+			goto error;
+
+		if (!pp->ops->msi_host_init)
+			goto error;
+		else
+			pp->ops->msi_host_init(pci);
 	}
 
 	if (pp->ops->host_init)
 		pp->ops->host_init(pp);
 
 	pp->root_bus_nr = pp->busn->start;
-	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		bus = pci_scan_root_bus_msi(dev, pp->root_bus_nr,
-					    &dw_pcie_ops, pp, &res,
-					    &dw_pcie_msi_chip);
-		dw_pcie_msi_chip.dev = dev;
-	} else
-		bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
-					pp, &res);
+
+	bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops,
+				pp, &res);
 	if (!bus) {
 		ret = -ENOMEM;
 		goto error;
diff --git a/drivers/pci/dwc/pcie-designware-plat.c b/drivers/pci/dwc/pcie-designware-plat.c
index 32091b3..4360fc6 100644
--- a/drivers/pci/dwc/pcie-designware-plat.c
+++ b/drivers/pci/dwc/pcie-designware-plat.c
@@ -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);
@@ -46,8 +39,15 @@ static void dw_plat_pcie_host_init(struct pcie_port *pp)
 		dw_pcie_msi_init(pp);
 }
 
+static void dw_plat_msi_host_init (struct dw_pcie *pci)
+{
+	struct pcie_port *pp = &pci->pp;
+	irq_set_chained_handler_and_data(pp->msi_irq, dw_handle_msi_irq, pci);
+}
+
 static struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
 	.host_init = dw_plat_pcie_host_init,
+	.msi_host_init = dw_plat_msi_host_init,
 };
 
 static int dw_plat_add_pcie_port(struct pcie_port *pp,
@@ -64,14 +64,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;
@@ -86,6 +78,18 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp,
 	return 0;
 }
 
+static int dw_plat_pcie_remove(struct platform_device *pdev)
+{
+	struct dw_plat_pcie *dw_plat_pcie = platform_get_drvdata(pdev);
+	struct dw_pcie *pci = dw_plat_pcie->pci;
+
+	dw_pcie_free_msi(&pci->pp);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
 static const struct dw_pcie_ops dw_pcie_ops = {
 };
 
@@ -136,5 +140,6 @@ static struct platform_driver dw_plat_pcie_driver = {
 		.suppress_bind_attrs = true,
 	},
 	.probe = dw_plat_pcie_probe,
+	.remove = dw_plat_pcie_remove,
 };
 builtin_platform_driver(dw_plat_pcie_driver);
diff --git a/drivers/pci/dwc/pcie-designware.h b/drivers/pci/dwc/pcie-designware.h
index c6a8405..cd3b3cc7 100644
--- a/drivers/pci/dwc/pcie-designware.h
+++ b/drivers/pci/dwc/pcie-designware.h
@@ -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 pcie_port *pp, struct msi_controller *chip);
+	void (*msi_host_init)(struct dw_pcie *pci);
 };
 
 struct pcie_port {
@@ -165,7 +165,9 @@ 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;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
@@ -280,7 +282,8 @@ 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_handle_msi_irq(struct irq_desc *desc);
+void dw_pcie_free_msi(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-05 14:11 [RFC] pci: using new interrupt API to enable MSI and MSI-X Joao Pinto
@ 2017-05-05 14:57 ` Marc Zyngier
  2017-05-05 15:12   ` Joao Pinto
                     ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Marc Zyngier @ 2017-05-05 14:57 UTC (permalink / raw)
  To: Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

Joao,

On 05/05/17 15:11, Joao Pinto wrote:
> Hello,
> I am currently adding the support for both MSI and MSI-x in pcie-designware and
> I am now facing a dificulty.
> 
> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
> the changes introduced by this patch we are able to enable MSI and MSI-X
> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
> 
> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
> bogus (524288) when it should be 1, and so I am not receiving any interrupts
> from the endpoint.

It is not bogus at all. It is computed from the PCI requester ID in 
pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
view of that interrupt, which is completely virtual.

The real thing happens in your own irqdomain, where the hwirq for IRQ46 
is probably 1 (only you can know that). As for why it doesn't work, see 
below:

> 
> I would apreciate that more experienced people in this interrupt subject could
> give me an hint.
> 
> I send you the "lspci -v" results and /proc/interrupts.
> 
> Thank you so much for your help.
> 
> # cat /proc/interrupts
>            CPU0
>   3:        755  ARC In-core Intc   3  Timer0 (per-cpu-tick)
>   4:          0  dw-apb-ictl   4  eth0
>   8:          1  dw-apb-ictl   8  ehci_hcd:usb1, ohci_hcd:usb2
>   9:         37  dw-apb-ictl   7  dw-mci
>  14:          0  dw-apb-ictl  14  e001d000.i2c
>  16:          0  dw-apb-ictl  16  e001f000.i2c
>  19:        145  dw-apb-ictl  19  serial
>  45:          0   PCI-MSI   0  aerdrv
>  46:          0   PCI-MSI 524288  xhci_hcd
> 
> # lspci -v
> 00:00.0 PCI bridge: Synopsys, Inc. Device eddc (rev 01) (prog-if 00 [Normal decode])
>         Flags: bus master, fast devsel, latency 0, IRQ 45
>         Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
>         Memory behind bridge: d0400000-d04fffff
>         [virtual] Expansion ROM at d0500000 [disabled] [size=64K]
>         Capabilities: [40] Power Management version 3
>         Capabilities: [50] MSI: Enable+ Count=1/1 Maskable- 64bit+
>         Capabilities: [70] Express Root Port (Slot-), MSI 00
>         Capabilities: [100] Advanced Error Reporting
>         Capabilities: [148] #19
>         Capabilities: [158] Vendor Specific Information: ID=0002 Rev=4 Len=100 <?>
>         Kernel driver in use: pcieport
> 
> 01:00.0 USB controller: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller (prog-if 30 [XHCI])
>         Subsystem: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller
>         Flags: bus master, fast devsel, latency 0, IRQ 46
>         Memory at d0400000 (64-bit, non-prefetchable) [size=32K]
>         Capabilities: [50] MSI: Enable+ Count=1/8 Maskable- 64bit+
>         Capabilities: [68] MSI-X: Enable- Count=8 Masked-
>         Capabilities: [78] Power Management version 3
>         Capabilities: [80] Express Endpoint, MSI 00
>         Capabilities: [100] Virtual Channel
>         Capabilities: [200] Advanced Error Reporting
>         Capabilities: [280] #19
>         Capabilities: [300] Latency Tolerance Reporting
>         Kernel driver in use: xhci_hcd
> 
> Signed-off-by: Joao Pinto <jpinto@synopsys.com>
> ---
>  .../devicetree/bindings/pci/designware-pcie.txt    |   2 +
>  drivers/pci/dwc/pcie-designware-host.c             | 292 ++++++++-------------
>  drivers/pci/dwc/pcie-designware-plat.c             |  35 +--
>  drivers/pci/dwc/pcie-designware.h                  |   7 +-
>  4 files changed, 143 insertions(+), 193 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
> index b2480dd..41803ea 100644
> --- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
> +++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
> @@ -34,6 +34,8 @@ Optional properties:
>  RC mode:
>  - num-viewport: number of view ports configured in
>    hardware. If a platform does not specify it, the driver assumes 2.
> +- num-vectors: number of available interrupt vectors. If a platform does not
> +  specify it, the driver assumes 1.
>  - bus-range: PCI bus numbers covered (it is recommended
>    for new devicetrees to specify this property, to keep backwards
>    compatibility a range of 0x00-0xff is assumed if not present)
> diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
> index 28ed32b..96a5fb3 100644
> --- a/drivers/pci/dwc/pcie-designware-host.c
> +++ b/drivers/pci/dwc/pcie-designware-host.c
> @@ -11,6 +11,9 @@
>   * published by the Free Software Foundation.
>   */
>  
> +#include <linux/interrupt.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/msi.h>
>  #include <linux/irqdomain.h>
>  #include <linux/of_address.h>
>  #include <linux/of_pci.h>
> @@ -53,32 +56,43 @@ static struct irq_chip dw_msi_irq_chip = {
>  	.irq_unmask = pci_msi_unmask_irq,
>  };

It looks to me like the first mistake is just above. You don't seem to
propagate the mask/unmask operations into the parent domain, so your
interrupts are never enabled... You'd need something like this:

diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index 28ed32ba4f1b..d42b8b12f168 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -45,12 +45,22 @@ 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);
 }
 
+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_enable = pci_msi_unmask_irq,
-	.irq_disable = pci_msi_mask_irq,
-	.irq_mask = pci_msi_mask_irq,
-	.irq_unmask = pci_msi_unmask_irq,
+	.irq_mask = dw_msi_mask_irq,
+	.irq_unmask = dw_msi_unmask_irq,
 };

I haven't dug any further, but this should be fixed first.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-05 14:57 ` Marc Zyngier
@ 2017-05-05 15:12   ` Joao Pinto
  2017-05-05 15:54   ` Joao Pinto
  2017-05-08  9:59   ` Joao Pinto
  2 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-05 15:12 UTC (permalink / raw)
  To: Marc Zyngier, Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

Hi Mark,

Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
> Joao,
> 
> On 05/05/17 15:11, Joao Pinto wrote:
>> Hello,
>> I am currently adding the support for both MSI and MSI-x in pcie-designware and
>> I am now facing a dificulty.
>>
>> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
>> the changes introduced by this patch we are able to enable MSI and MSI-X
>> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
>>
>> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
>> bogus (524288) when it should be 1, and so I am not receiving any interrupts
>> from the endpoint.
> 
> It is not bogus at all. It is computed from the PCI requester ID in 
> pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
> view of that interrupt, which is completely virtual.
> 
> The real thing happens in your own irqdomain, where the hwirq for IRQ46 
> is probably 1 (only you can know that). As for why it doesn't work, see 
> below:
> 

snip (...)

>  static struct irq_chip dw_msi_irq_chip = {
>  	.name = "PCI-MSI",
> -	.irq_enable = pci_msi_unmask_irq,
> -	.irq_disable = pci_msi_mask_irq,
> -	.irq_mask = pci_msi_mask_irq,
> -	.irq_unmask = pci_msi_unmask_irq,
> +	.irq_mask = dw_msi_mask_irq,
> +	.irq_unmask = dw_msi_unmask_irq,
>  };
> 
> I haven't dug any further, but this should be fixed first.
> 
> Thanks,
> 
> 	M.
> 

Thanks for the help! I will check it out!

Joao

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-05 14:57 ` Marc Zyngier
  2017-05-05 15:12   ` Joao Pinto
@ 2017-05-05 15:54   ` Joao Pinto
  2017-05-06 12:45     ` Marc Zyngier
  2017-05-08  9:59   ` Joao Pinto
  2 siblings, 1 reply; 12+ messages in thread
From: Joao Pinto @ 2017-05-05 15:54 UTC (permalink / raw)
  To: Marc Zyngier, Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

Mark,

Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
> Joao,
> 
> On 05/05/17 15:11, Joao Pinto wrote:

snip (...)

> It looks to me like the first mistake is just above. You don't seem to
> propagate the mask/unmask operations into the parent domain, so your
> interrupts are never enabled... You'd need something like this:
> 
> diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
> index 28ed32ba4f1b..d42b8b12f168 100644
> --- a/drivers/pci/dwc/pcie-designware-host.c
> +++ b/drivers/pci/dwc/pcie-designware-host.c
> @@ -45,12 +45,22 @@ 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);
>  }
>  
> +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_enable = pci_msi_unmask_irq,
> -	.irq_disable = pci_msi_mask_irq,
> -	.irq_mask = pci_msi_mask_irq,
> -	.irq_unmask = pci_msi_unmask_irq,
> +	.irq_mask = dw_msi_mask_irq,
> +	.irq_unmask = dw_msi_unmask_irq,
>  };
> 
> I haven't dug any further, but this should be fixed first.
> 
> Thanks,
> 
> 	M.
> 

I added the changes that you suggested and firstly it crashed, and then I found
out that in the domain parent structure (dw_pci_msi_bottom_irq_chip) did not
have irq_mask and irq_unmask functions. I put it like this, just for testing:

static struct irq_chip dw_pci_msi_bottom_irq_chip = {
	.name			= "DW MSI",
	.irq_compose_msi_msg	= dw_pci_compose_msi_msg,
	.irq_set_affinity	= dw_pci_msi_set_affinity,
+	.irq_mask		= pci_msi_mask_irq,
+	.irq_unmask		= pci_msi_unmask_irq,
};

Maybe irq_mask and irq_unmask should not be pci_msi_mask_irq /
pci_msi_unmask_irq, but I did not find any existing case that needed it. Do we
have any documentation about IRQ domains that I can check?

Interrupts
 45:          0   PCI-MSI   0  aerdrv
 46:          0   PCI-MSI 524288  xhci_hcd

The MSI seems to be well configured in the Bridge and in the Endpoint, so some
glue is missing in the driver.

00:00.0 PCI bridge: Synopsys, Inc. Device eddc (rev 01) (prog-if 00 [Normal decode])
Capabilities: [50] MSI: Enable+ Count=1/1 Maskable- 64bit+
Address: 000000009a238000  Data: 0000


01:00.0 USB controller: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller
(prog-if 30 [XHCI])
(...)
Capabilities: [50] MSI: Enable+ Count=1/8 Maskable- 64bit+
Address: 000000009a238000  Data: 0001

Thanks for the support.

Joao

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-05 15:54   ` Joao Pinto
@ 2017-05-06 12:45     ` Marc Zyngier
  0 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2017-05-06 12:45 UTC (permalink / raw)
  To: Joao Pinto; +Cc: kishon, bhelgaas, jingoohan1, linux-pci

On Fri, 5 May 2017 16:54:30 +0100
Joao Pinto <Joao.Pinto@synopsys.com> wrote:

> Mark,
> 
> Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
> > Joao,
> > 
> > On 05/05/17 15:11, Joao Pinto wrote:  
> 
> snip (...)
> 
> > It looks to me like the first mistake is just above. You don't seem to
> > propagate the mask/unmask operations into the parent domain, so your
> > interrupts are never enabled... You'd need something like this:
> > 
> > diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
> > index 28ed32ba4f1b..d42b8b12f168 100644
> > --- a/drivers/pci/dwc/pcie-designware-host.c
> > +++ b/drivers/pci/dwc/pcie-designware-host.c
> > @@ -45,12 +45,22 @@ 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);
> >  }
> >  
> > +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_enable = pci_msi_unmask_irq,
> > -	.irq_disable = pci_msi_mask_irq,
> > -	.irq_mask = pci_msi_mask_irq,
> > -	.irq_unmask = pci_msi_unmask_irq,
> > +	.irq_mask = dw_msi_mask_irq,
> > +	.irq_unmask = dw_msi_unmask_irq,
> >  };
> > 
> > I haven't dug any further, but this should be fixed first.
> > 
> > Thanks,
> > 
> > 	M.
> >   
> 
> I added the changes that you suggested and firstly it crashed, and then I found
> out that in the domain parent structure (dw_pci_msi_bottom_irq_chip) did not
> have irq_mask and irq_unmask functions. I put it like this, just for testing:
> 
> static struct irq_chip dw_pci_msi_bottom_irq_chip = {
> 	.name			= "DW MSI",
> 	.irq_compose_msi_msg	= dw_pci_compose_msi_msg,
> 	.irq_set_affinity	= dw_pci_msi_set_affinity,
> +	.irq_mask		= pci_msi_mask_irq,
> +	.irq_unmask		= pci_msi_unmask_irq,
> };
> 
> Maybe irq_mask and irq_unmask should not be pci_msi_mask_irq /
> pci_msi_unmask_irq, but I did not find any existing case that needed it. Do we
> have any documentation about IRQ domains that I can check?

We have some documentation in Documentation/IRQ-domain.txt, though it
is old an incomplete. But there is enough there to show you your
mistake. You have two domains:

Top level domain: the PCI-MSI domain, in charge of the PCI-specific
stuff, and particularly the masking/unmasking of MSIs. That's the
purpose of the patch above.

Bottom domain: your DW-MSI domain, which is only concerned with the
details of your piece of HW. Obviously, calling pci_msi*irq is wrong
there, since it is already called by the top level domain, and is
hardly HW specific.

So what you need there is the code that masks/unmasks an MSI for your
HW, and nothing else.

> 
> Interrupts
>  45:          0   PCI-MSI   0  aerdrv
>  46:          0   PCI-MSI 524288  xhci_hcd
> 
> The MSI seems to be well configured in the Bridge and in the Endpoint, so some
> glue is missing in the driver.

Yup, see above.

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-05 14:57 ` Marc Zyngier
  2017-05-05 15:12   ` Joao Pinto
  2017-05-05 15:54   ` Joao Pinto
@ 2017-05-08  9:59   ` Joao Pinto
  2017-05-08 10:22     ` Marc Zyngier
  2 siblings, 1 reply; 12+ messages in thread
From: Joao Pinto @ 2017-05-08  9:59 UTC (permalink / raw)
  To: Marc Zyngier, Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
> Joao,
> 
> On 05/05/17 15:11, Joao Pinto wrote:
>> Hello,
>> I am currently adding the support for both MSI and MSI-x in pcie-designware and
>> I am now facing a dificulty.
>>
>> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
>> the changes introduced by this patch we are able to enable MSI and MSI-X
>> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
>>
>> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
>> bogus (524288) when it should be 1, and so I am not receiving any interrupts
>> from the endpoint.
> 
> It is not bogus at all. It is computed from the PCI requester ID in 
> pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
> view of that interrupt, which is completely virtual.
> 
> The real thing happens in your own irqdomain, where the hwirq for IRQ46 
> is probably 1 (only you can know that). As for why it doesn't work, see 
> below:
> 
>>
>> I would apreciate that more experienced people in this interrupt subject could
>> give me an hint.
>>
>> I send you the "lspci -v" results and /proc/interrupts.
>>
>> Thank you so much for your help.
>>
>> # cat /proc/interrupts
>>            CPU0
>>   3:        755  ARC In-core Intc   3  Timer0 (per-cpu-tick)
>>   4:          0  dw-apb-ictl   4  eth0
>>   8:          1  dw-apb-ictl   8  ehci_hcd:usb1, ohci_hcd:usb2
>>   9:         37  dw-apb-ictl   7  dw-mci
>>  14:          0  dw-apb-ictl  14  e001d000.i2c
>>  16:          0  dw-apb-ictl  16  e001f000.i2c
>>  19:        145  dw-apb-ictl  19  serial
>>  45:          0   PCI-MSI   0  aerdrv
>>  46:          0   PCI-MSI 524288  xhci_hcd
>>
>> # lspci -v
>> 00:00.0 PCI bridge: Synopsys, Inc. Device eddc (rev 01) (prog-if 00 [Normal decode])
>>         Flags: bus master, fast devsel, latency 0, IRQ 45
>>         Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
>>         Memory behind bridge: d0400000-d04fffff
>>         [virtual] Expansion ROM at d0500000 [disabled] [size=64K]
>>         Capabilities: [40] Power Management version 3
>>         Capabilities: [50] MSI: Enable+ Count=1/1 Maskable- 64bit+
>>         Capabilities: [70] Express Root Port (Slot-), MSI 00
>>         Capabilities: [100] Advanced Error Reporting
>>         Capabilities: [148] #19
>>         Capabilities: [158] Vendor Specific Information: ID=0002 Rev=4 Len=100 <?>
>>         Kernel driver in use: pcieport
>>
>> 01:00.0 USB controller: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller (prog-if 30 [XHCI])
>>         Subsystem: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller
>>         Flags: bus master, fast devsel, latency 0, IRQ 46
>>         Memory at d0400000 (64-bit, non-prefetchable) [size=32K]
>>         Capabilities: [50] MSI: Enable+ Count=1/8 Maskable- 64bit+
>>         Capabilities: [68] MSI-X: Enable- Count=8 Masked-
>>         Capabilities: [78] Power Management version 3
>>         Capabilities: [80] Express Endpoint, MSI 00
>>         Capabilities: [100] Virtual Channel
>>         Capabilities: [200] Advanced Error Reporting
>>         Capabilities: [280] #19
>>         Capabilities: [300] Latency Tolerance Reporting
>>         Kernel driver in use: xhci_hcd
>>
>> Signed-off-by: Joao Pinto <jpinto@synopsys.com>
>> ---
>>  .../devicetree/bindings/pci/designware-pcie.txt    |   2 +
>>  drivers/pci/dwc/pcie-designware-host.c             | 292 ++++++++-------------
>>  drivers/pci/dwc/pcie-designware-plat.c             |  35 +--
>>  drivers/pci/dwc/pcie-designware.h                  |   7 +-
>>  4 files changed, 143 insertions(+), 193 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
>> index b2480dd..41803ea 100644
>> --- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
>> +++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
>> @@ -34,6 +34,8 @@ Optional properties:
>>  RC mode:
>>  - num-viewport: number of view ports configured in
>>    hardware. If a platform does not specify it, the driver assumes 2.
>> +- num-vectors: number of available interrupt vectors. If a platform does not
>> +  specify it, the driver assumes 1.
>>  - bus-range: PCI bus numbers covered (it is recommended
>>    for new devicetrees to specify this property, to keep backwards
>>    compatibility a range of 0x00-0xff is assumed if not present)
>> diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
>> index 28ed32b..96a5fb3 100644
>> --- a/drivers/pci/dwc/pcie-designware-host.c
>> +++ b/drivers/pci/dwc/pcie-designware-host.c
>> @@ -11,6 +11,9 @@
>>   * published by the Free Software Foundation.
>>   */
>>  
>> +#include <linux/interrupt.h>
>> +#include <linux/irqchip/chained_irq.h>
>> +#include <linux/msi.h>
>>  #include <linux/irqdomain.h>
>>  #include <linux/of_address.h>
>>  #include <linux/of_pci.h>
>> @@ -53,32 +56,43 @@ static struct irq_chip dw_msi_irq_chip = {
>>  	.irq_unmask = pci_msi_unmask_irq,
>>  };
> 
> It looks to me like the first mistake is just above. You don't seem to
> propagate the mask/unmask operations into the parent domain, so your
> interrupts are never enabled... You'd need something like this:
> 
> diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
> index 28ed32ba4f1b..d42b8b12f168 100644
> --- a/drivers/pci/dwc/pcie-designware-host.c
> +++ b/drivers/pci/dwc/pcie-designware-host.c
> @@ -45,12 +45,22 @@ 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);
>  }
>  
> +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_enable = pci_msi_unmask_irq,
> -	.irq_disable = pci_msi_mask_irq,
> -	.irq_mask = pci_msi_mask_irq,
> -	.irq_unmask = pci_msi_unmask_irq,
> +	.irq_mask = dw_msi_mask_irq,
> +	.irq_unmask = dw_msi_unmask_irq,
>  };
> 
> I haven't dug any further, but this should be fixed first.
> 
> Thanks,
> 
> 	M.
> 

Yep makes perfectly sense and thanks for clearing the Domains :), I understood
them now.

Best regards,
Joao

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-08  9:59   ` Joao Pinto
@ 2017-05-08 10:22     ` Marc Zyngier
  2017-05-08 10:24       ` Joao Pinto
  0 siblings, 1 reply; 12+ messages in thread
From: Marc Zyngier @ 2017-05-08 10:22 UTC (permalink / raw)
  To: Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

On 08/05/17 10:59, Joao Pinto wrote:
> Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
>> Joao,
>>
>> On 05/05/17 15:11, Joao Pinto wrote:
>>> Hello,
>>> I am currently adding the support for both MSI and MSI-x in pcie-designware and
>>> I am now facing a dificulty.
>>>
>>> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
>>> the changes introduced by this patch we are able to enable MSI and MSI-X
>>> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
>>>
>>> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
>>> bogus (524288) when it should be 1, and so I am not receiving any interrupts
>>> from the endpoint.
>>
>> It is not bogus at all. It is computed from the PCI requester ID in 
>> pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
>> view of that interrupt, which is completely virtual.
>>
>> The real thing happens in your own irqdomain, where the hwirq for IRQ46 
>> is probably 1 (only you can know that). As for why it doesn't work, see 
>> below:
>>
>>>
>>> I would apreciate that more experienced people in this interrupt subject could
>>> give me an hint.

[...]

> Yep makes perfectly sense and thanks for clearing the Domains :), I understood
> them now.

I guess that you have your MSI controller working with MSI-X now?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-08 10:22     ` Marc Zyngier
@ 2017-05-08 10:24       ` Joao Pinto
  2017-05-08 10:59         ` Marc Zyngier
  0 siblings, 1 reply; 12+ messages in thread
From: Joao Pinto @ 2017-05-08 10:24 UTC (permalink / raw)
  To: Marc Zyngier, Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

Às 11:22 AM de 5/8/2017, Marc Zyngier escreveu:
> On 08/05/17 10:59, Joao Pinto wrote:
>> Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
>>> Joao,
>>>
>>> On 05/05/17 15:11, Joao Pinto wrote:
>>>> Hello,
>>>> I am currently adding the support for both MSI and MSI-x in pcie-designware and
>>>> I am now facing a dificulty.
>>>>
>>>> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
>>>> the changes introduced by this patch we are able to enable MSI and MSI-X
>>>> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
>>>>
>>>> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
>>>> bogus (524288) when it should be 1, and so I am not receiving any interrupts
>>>> from the endpoint.
>>>
>>> It is not bogus at all. It is computed from the PCI requester ID in 
>>> pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
>>> view of that interrupt, which is completely virtual.
>>>
>>> The real thing happens in your own irqdomain, where the hwirq for IRQ46 
>>> is probably 1 (only you can know that). As for why it doesn't work, see 
>>> below:
>>>
>>>>
>>>> I would apreciate that more experienced people in this interrupt subject could
>>>> give me an hint.
> 
> [...]
> 
>> Yep makes perfectly sense and thanks for clearing the Domains :), I understood
>> them now.
> 
> I guess that you have your MSI controller working with MSI-X now?

I started working one hour ago and still putting some subjects in order, I am
going to return to PCI in a bit. I will keep you updated. I thought you were in
US Pacific timezone.

Thanks,
Joao

> 
> Thanks,
> 
> 	M.
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-08 10:24       ` Joao Pinto
@ 2017-05-08 10:59         ` Marc Zyngier
  2017-05-08 14:40           ` Joao Pinto
  0 siblings, 1 reply; 12+ messages in thread
From: Marc Zyngier @ 2017-05-08 10:59 UTC (permalink / raw)
  To: Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

On 08/05/17 11:24, Joao Pinto wrote:
> Às 11:22 AM de 5/8/2017, Marc Zyngier escreveu:
>> On 08/05/17 10:59, Joao Pinto wrote:
>>> Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
>>>> Joao,
>>>>
>>>> On 05/05/17 15:11, Joao Pinto wrote:
>>>>> Hello,
>>>>> I am currently adding the support for both MSI and MSI-x in pcie-designware and
>>>>> I am now facing a dificulty.
>>>>>
>>>>> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
>>>>> the changes introduced by this patch we are able to enable MSI and MSI-X
>>>>> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
>>>>>
>>>>> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
>>>>> bogus (524288) when it should be 1, and so I am not receiving any interrupts
>>>>> from the endpoint.
>>>>
>>>> It is not bogus at all. It is computed from the PCI requester ID in 
>>>> pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
>>>> view of that interrupt, which is completely virtual.
>>>>
>>>> The real thing happens in your own irqdomain, where the hwirq for IRQ46 
>>>> is probably 1 (only you can know that). As for why it doesn't work, see 
>>>> below:
>>>>
>>>>>
>>>>> I would apreciate that more experienced people in this interrupt subject could
>>>>> give me an hint.
>>
>> [...]
>>
>>> Yep makes perfectly sense and thanks for clearing the Domains :), I understood
>>> them now.
>>
>> I guess that you have your MSI controller working with MSI-X now?
> 
> I started working one hour ago and still putting some subjects in order, I am
> going to return to PCI in a bit. I will keep you updated. I thought you were in
> US Pacific timezone.

I'm firmly rooted in BST! ;-)

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-08 10:59         ` Marc Zyngier
@ 2017-05-08 14:40           ` Joao Pinto
  2017-05-08 14:49             ` Marc Zyngier
  0 siblings, 1 reply; 12+ messages in thread
From: Joao Pinto @ 2017-05-08 14:40 UTC (permalink / raw)
  To: Marc Zyngier, Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

Às 11:59 AM de 5/8/2017, Marc Zyngier escreveu:
> On 08/05/17 11:24, Joao Pinto wrote:
>> Às 11:22 AM de 5/8/2017, Marc Zyngier escreveu:
>>> On 08/05/17 10:59, Joao Pinto wrote:
>>>> Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
>>>>> Joao,
>>>>>
>>>>> On 05/05/17 15:11, Joao Pinto wrote:
>>>>>> Hello,
>>>>>> I am currently adding the support for both MSI and MSI-x in pcie-designware and
>>>>>> I am now facing a dificulty.
>>>>>>
>>>>>> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
>>>>>> the changes introduced by this patch we are able to enable MSI and MSI-X
>>>>>> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
>>>>>>
>>>>>> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
>>>>>> bogus (524288) when it should be 1, and so I am not receiving any interrupts
>>>>>> from the endpoint.
>>>>>
>>>>> It is not bogus at all. It is computed from the PCI requester ID in 
>>>>> pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
>>>>> view of that interrupt, which is completely virtual.
>>>>>
>>>>> The real thing happens in your own irqdomain, where the hwirq for IRQ46 
>>>>> is probably 1 (only you can know that). As for why it doesn't work, see 
>>>>> below:
>>>>>
>>>>>>
>>>>>> I would apreciate that more experienced people in this interrupt subject could
>>>>>> give me an hint.
>>>
>>> [...]
>>>
>>>> Yep makes perfectly sense and thanks for clearing the Domains :), I understood
>>>> them now.
>>>
>>> I guess that you have your MSI controller working with MSI-X now?
>>
>> I started working one hour ago and still putting some subjects in order, I am
>> going to return to PCI in a bit. I will keep you updated. I thought you were in
>> US Pacific timezone.
> 
> I'm firmly rooted in BST! ;-)
> 
> 	M.
> 

You were right, it was missing the bottom part related to the PCie DW IP:

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;

	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);
}

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;

	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);
}

static struct irq_chip dw_pci_msi_bottom_irq_chip = {
	.name			= "DW MSI",
	.irq_compose_msi_msg	= dw_pci_compose_msi_msg,
	.irq_set_affinity	= dw_pci_msi_set_affinity,
	.irq_mask		= dw_pci_bottom_mask,
	.irq_unmask		= dw_pci_bottom_unmask,
};


With these 2 functions I was able to perform test with MSI and with MSI-X
Endpoints. I am goingo to clean this up and check the compatibility with other
SoC drivers and send a patch soon.

Thanks for the help Marc!

Regards,
Joao

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-08 14:40           ` Joao Pinto
@ 2017-05-08 14:49             ` Marc Zyngier
  2017-05-08 15:14               ` Joao Pinto
  0 siblings, 1 reply; 12+ messages in thread
From: Marc Zyngier @ 2017-05-08 14:49 UTC (permalink / raw)
  To: Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

On 08/05/17 15:40, Joao Pinto wrote:
> Às 11:59 AM de 5/8/2017, Marc Zyngier escreveu:
>> On 08/05/17 11:24, Joao Pinto wrote:
>>> Às 11:22 AM de 5/8/2017, Marc Zyngier escreveu:
>>>> On 08/05/17 10:59, Joao Pinto wrote:
>>>>> Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
>>>>>> Joao,
>>>>>>
>>>>>> On 05/05/17 15:11, Joao Pinto wrote:
>>>>>>> Hello,
>>>>>>> I am currently adding the support for both MSI and MSI-x in pcie-designware and
>>>>>>> I am now facing a dificulty.
>>>>>>>
>>>>>>> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
>>>>>>> the changes introduced by this patch we are able to enable MSI and MSI-X
>>>>>>> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
>>>>>>>
>>>>>>> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
>>>>>>> bogus (524288) when it should be 1, and so I am not receiving any interrupts
>>>>>>> from the endpoint.
>>>>>>
>>>>>> It is not bogus at all. It is computed from the PCI requester ID in 
>>>>>> pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
>>>>>> view of that interrupt, which is completely virtual.
>>>>>>
>>>>>> The real thing happens in your own irqdomain, where the hwirq for IRQ46 
>>>>>> is probably 1 (only you can know that). As for why it doesn't work, see 
>>>>>> below:
>>>>>>
>>>>>>>
>>>>>>> I would apreciate that more experienced people in this interrupt subject could
>>>>>>> give me an hint.
>>>>
>>>> [...]
>>>>
>>>>> Yep makes perfectly sense and thanks for clearing the Domains :), I understood
>>>>> them now.
>>>>
>>>> I guess that you have your MSI controller working with MSI-X now?
>>>
>>> I started working one hour ago and still putting some subjects in order, I am
>>> going to return to PCI in a bit. I will keep you updated. I thought you were in
>>> US Pacific timezone.
>>
>> I'm firmly rooted in BST! ;-)
>>
>> 	M.
>>
> 
> You were right, it was missing the bottom part related to the PCie DW IP:
> 
> 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;
> 
> 	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);

be careful: you have a horrible race here, where another CPU try to mask
another MSI at the same time. Any form of RMW should be guarded by a
spinlock.

> }
> 
> 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;
> 
> 	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);

Same here. Also, you could perfectly replace the read with a variable
that caches the most recent value (as there should be no other code
changing this register).

> }
> 
> static struct irq_chip dw_pci_msi_bottom_irq_chip = {
> 	.name			= "DW MSI",
> 	.irq_compose_msi_msg	= dw_pci_compose_msi_msg,
> 	.irq_set_affinity	= dw_pci_msi_set_affinity,
> 	.irq_mask		= dw_pci_bottom_mask,
> 	.irq_unmask		= dw_pci_bottom_unmask,
> };
> 
> 
> With these 2 functions I was able to perform test with MSI and with MSI-X
> Endpoints. I am goingo to clean this up and check the compatibility with other
> SoC drivers and send a patch soon.
> 
> Thanks for the help Marc!

No worries.

Cheers,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] pci: using new interrupt API to enable MSI and MSI-X
  2017-05-08 14:49             ` Marc Zyngier
@ 2017-05-08 15:14               ` Joao Pinto
  0 siblings, 0 replies; 12+ messages in thread
From: Joao Pinto @ 2017-05-08 15:14 UTC (permalink / raw)
  To: Marc Zyngier, Joao Pinto, kishon, bhelgaas, jingoohan1; +Cc: linux-pci

Às 3:49 PM de 5/8/2017, Marc Zyngier escreveu:
> On 08/05/17 15:40, Joao Pinto wrote:
>> Às 11:59 AM de 5/8/2017, Marc Zyngier escreveu:
>>> On 08/05/17 11:24, Joao Pinto wrote:
>>>> Às 11:22 AM de 5/8/2017, Marc Zyngier escreveu:
>>>>> On 08/05/17 10:59, Joao Pinto wrote:
>>>>>> Às 3:57 PM de 5/5/2017, Marc Zyngier escreveu:
>>>>>>> Joao,
>>>>>>>
>>>>>>> On 05/05/17 15:11, Joao Pinto wrote:
>>>>>>>> Hello,
>>>>>>>> I am currently adding the support for both MSI and MSI-x in pcie-designware and
>>>>>>>> I am now facing a dificulty.
>>>>>>>>
>>>>>>>> My test endpoint is a USB 3.1 MSI / MSI-X capable and I tested that with
>>>>>>>> the changes introduced by this patch we are able to enable MSI and MSI-X
>>>>>>>> in this endpoint (depends on the usage of the MSI_FLAG_PCI_MSIX flag).
>>>>>>>>
>>>>>>>> The problem I am facing now is that Intc for the USB 3.1 Endpoint is completely
>>>>>>>> bogus (524288) when it should be 1, and so I am not receiving any interrupts
>>>>>>>> from the endpoint.
>>>>>>>
>>>>>>> It is not bogus at all. It is computed from the PCI requester ID in 
>>>>>>> pci_msi_domain_calc_hwirq. What you're seeing is the PCI/MDI domain 
>>>>>>> view of that interrupt, which is completely virtual.
>>>>>>>
>>>>>>> The real thing happens in your own irqdomain, where the hwirq for IRQ46 
>>>>>>> is probably 1 (only you can know that). As for why it doesn't work, see 
>>>>>>> below:
>>>>>>>
>>>>>>>>
>>>>>>>> I would apreciate that more experienced people in this interrupt subject could
>>>>>>>> give me an hint.
>>>>>
>>>>> [...]
>>>>>
>>>>>> Yep makes perfectly sense and thanks for clearing the Domains :), I understood
>>>>>> them now.
>>>>>
>>>>> I guess that you have your MSI controller working with MSI-X now?
>>>>
>>>> I started working one hour ago and still putting some subjects in order, I am
>>>> going to return to PCI in a bit. I will keep you updated. I thought you were in
>>>> US Pacific timezone.
>>>
>>> I'm firmly rooted in BST! ;-)
>>>
>>> 	M.
>>>
>>
>> You were right, it was missing the bottom part related to the PCie DW IP:
>>
>> 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;
>>
>> 	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);
> 
> be careful: you have a horrible race here, where another CPU try to mask
> another MSI at the same time. Any form of RMW should be guarded by a
> spinlock.

Yes, I am going to do that. Altera's have locks.

Thanks!

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2017-05-08 15:14 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-05 14:11 [RFC] pci: using new interrupt API to enable MSI and MSI-X Joao Pinto
2017-05-05 14:57 ` Marc Zyngier
2017-05-05 15:12   ` Joao Pinto
2017-05-05 15:54   ` Joao Pinto
2017-05-06 12:45     ` Marc Zyngier
2017-05-08  9:59   ` Joao Pinto
2017-05-08 10:22     ` Marc Zyngier
2017-05-08 10:24       ` Joao Pinto
2017-05-08 10:59         ` Marc Zyngier
2017-05-08 14:40           ` Joao Pinto
2017-05-08 14:49             ` Marc Zyngier
2017-05-08 15:14               ` Joao Pinto

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.