linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/3] Tango PCIe controller support
@ 2017-05-31 13:28 Marc Gonzalez
  2017-05-31 13:30 ` [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller Marc Gonzalez
                   ` (2 more replies)
  0 siblings, 3 replies; 27+ messages in thread
From: Marc Gonzalez @ 2017-05-31 13:28 UTC (permalink / raw)
  To: Bjorn Helgaas, Marc Zyngier, Thomas Gleixner
  Cc: Robin Murphy, Lorenzo Pieralisi, Liviu Dudau, David Laight,
	linux-pci, Linux ARM, Thibaud Cornic, Phuong Nguyen, LKML, DT,
	Mason

Spin v5 to address comments from Marc and Bjorn.

Changes from v4 to v5

- Split the DT binding into a third patch
- Introduce host bridge support first
- Put all MSI stuff in the MSI patch
- Inline 2 single-use functions
- Fix tango_ack
- Allocate irq at probe start
- Print dire message in probe, and taint kernel
	("Lasciate ogne speranza, voi ch'intrate")

Marc Gonzalez (3):
  PCI: Add DT binding for tango PCIe controller
  PCI: Add tango PCIe host bridge support
  PCI: Add tango MSI controller support

 Documentation/devicetree/bindings/pci/tango-pcie.txt |  30 +++
 drivers/pci/host/Kconfig                             |   8 +
 drivers/pci/host/Makefile                            |   1 +
 drivers/pci/host/pcie-tango.c                        | 386 +++++++++++++++++++++++++++++++++++++++
 include/linux/pci_ids.h                              |   2 +
 5 files changed, 427 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/tango-pcie.txt
 create mode 100644 drivers/pci/host/pcie-tango.c

-- 
2.11.0

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

* [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller
  2017-05-31 13:28 [PATCH v5 0/3] Tango PCIe controller support Marc Gonzalez
@ 2017-05-31 13:30 ` Marc Gonzalez
  2017-06-07 21:29   ` Rob Herring
  2017-05-31 13:33 ` [PATCH v5 2/3] PCI: Add tango PCIe host bridge support Marc Gonzalez
  2017-05-31 13:35 ` [PATCH v5 3/3] PCI: Add tango MSI controller support Marc Gonzalez
  2 siblings, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-05-31 13:30 UTC (permalink / raw)
  To: Bjorn Helgaas, Marc Zyngier, Thomas Gleixner
  Cc: Robin Murphy, Lorenzo Pieralisi, Liviu Dudau, David Laight,
	linux-pci, Linux ARM, Thibaud Cornic, Phuong Nguyen, LKML, DT,
	Mason

Binding for the Sigma Designs SMP8759 SoC.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
---
 Documentation/devicetree/bindings/pci/tango-pcie.txt | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/Documentation/devicetree/bindings/pci/tango-pcie.txt b/Documentation/devicetree/bindings/pci/tango-pcie.txt
new file mode 100644
index 000000000000..35ef2c811a27
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/tango-pcie.txt
@@ -0,0 +1,30 @@
+Sigma Designs Tango PCIe controller
+
+Required properties:
+
+- compatible: "sigma,smp8759-pcie"
+- reg: address/size of PCI configuration space, address/size of register area
+- device_type: "pci"
+- #size-cells: <2>
+- #address-cells: <3>
+- msi-controller
+- ranges: translation from system to bus addresses
+- interrupts: spec for misc interrupts, spec for MSI
+
+http://elinux.org/Device_Tree_Usage#PCI_Address_Translation
+http://elinux.org/Device_Tree_Usage#Advanced_Interrupt_Mapping
+
+Example:
+
+	pcie@2e000 {
+		compatible = "sigma,smp8759-pcie";
+		reg = <0x50000000 SZ_4M>, <0x2e000 0x100>;
+		device_type = "pci";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		msi-controller;
+		ranges = <0x02000000 0x0 0x00400000  0x50400000  0x0 SZ_60M>;
+		interrupts =
+			<54 IRQ_TYPE_LEVEL_HIGH>, /* misc interrupts */
+			<55 IRQ_TYPE_LEVEL_HIGH>; /* MSI */
+	};
-- 
2.11.0

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

* [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-05-31 13:28 [PATCH v5 0/3] Tango PCIe controller support Marc Gonzalez
  2017-05-31 13:30 ` [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller Marc Gonzalez
@ 2017-05-31 13:33 ` Marc Gonzalez
  2017-06-07  8:19   ` Marc Gonzalez
  2017-07-05  9:36   ` Ard Biesheuvel
  2017-05-31 13:35 ` [PATCH v5 3/3] PCI: Add tango MSI controller support Marc Gonzalez
  2 siblings, 2 replies; 27+ messages in thread
From: Marc Gonzalez @ 2017-05-31 13:33 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Marc Zyngier, Thomas Gleixner, Robin Murphy, Lorenzo Pieralisi,
	Liviu Dudau, David Laight, linux-pci, Linux ARM, Thibaud Cornic,
	Phuong Nguyen, LKML, Mason

This driver is required to work around several hardware bugs
in the PCIe controller.

NB: Revision 1 does not support legacy interrupts, or IO space.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
---
 drivers/pci/host/Kconfig      |   8 +++
 drivers/pci/host/Makefile     |   1 +
 drivers/pci/host/pcie-tango.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci_ids.h       |   2 +
 4 files changed, 175 insertions(+)

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index d7e7c0a827c3..5183d9095c3a 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -285,6 +285,14 @@ config PCIE_ROCKCHIP
 	  There is 1 internal PCIe port available to support GEN2 with
 	  4 slots.
 
+config PCIE_TANGO
+	bool "Tango PCIe controller"
+	depends on ARCH_TANGO && PCI_MSI && OF
+	select PCI_HOST_COMMON
+	help
+	  Say Y here to enable PCIe controller support for Sigma Designs
+	  Tango systems, such as SMP8759 and later chips.
+
 config VMD
 	depends on PCI_MSI && X86_64
 	tristate "Intel Volume Management Device Driver"
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 084cb4983645..fc7ea90196f3 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -32,4 +32,5 @@ obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
 obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
 obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
+obj-$(CONFIG_PCIE_TANGO) += pcie-tango.o
 obj-$(CONFIG_VMD) += vmd.o
diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
new file mode 100644
index 000000000000..67aaadcc1c5e
--- /dev/null
+++ b/drivers/pci/host/pcie-tango.c
@@ -0,0 +1,164 @@
+#include <linux/pci-ecam.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+
+#define MSI_MAX 256
+
+#define SMP8759_MUX		0x48
+#define SMP8759_TEST_OUT	0x74
+
+struct tango_pcie {
+	void __iomem *mux;
+};
+
+/*** HOST BRIDGE SUPPORT ***/
+
+static int smp8759_config_read(struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val)
+{
+	int ret;
+	struct pci_config_window *cfg = bus->sysdata;
+	struct tango_pcie *pcie = dev_get_drvdata(cfg->parent);
+
+	/*
+	 * QUIRK #1
+	 * Reads in configuration space outside devfn 0 return garbage.
+	 */
+	if (devfn != 0)
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+	/*
+	 * QUIRK #2
+	 * Unfortunately, config and mem spaces are muxed.
+	 * Linux does not support such a setting, since drivers are free
+	 * to access mem space directly, at any time.
+	 * Therefore, we can only PRAY that config and mem space accesses
+	 * NEVER occur concurrently.
+	 */
+	writel_relaxed(1, pcie->mux);
+	ret = pci_generic_config_read(bus, devfn, where, size, val);
+	writel_relaxed(0, pcie->mux);
+
+	return ret;
+}
+
+static int smp8759_config_write(struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 val)
+{
+	int ret;
+	struct pci_config_window *cfg = bus->sysdata;
+	struct tango_pcie *pcie = dev_get_drvdata(cfg->parent);
+
+	writel_relaxed(1, pcie->mux);
+	ret = pci_generic_config_write(bus, devfn, where, size, val);
+	writel_relaxed(0, pcie->mux);
+
+	return ret;
+}
+
+static struct pci_ecam_ops smp8759_ecam_ops = {
+	.bus_shift	= 20,
+	.pci_ops	= {
+		.map_bus	= pci_ecam_map_bus,
+		.read		= smp8759_config_read,
+		.write		= smp8759_config_write,
+	}
+};
+
+static const struct of_device_id tango_pcie_ids[] = {
+	{ .compatible = "sigma,smp8759-pcie" },
+	{ /* sentinel */ },
+};
+
+static int tango_check_pcie_link(void __iomem *test_out)
+{
+	int i;
+
+	writel_relaxed(16, test_out);
+	for (i = 0; i < 10; ++i) {
+		u32 ltssm_state = readl_relaxed(test_out) >> 8;
+		if ((ltssm_state & 0x1f) == 0xf) /* L0 */
+			return 0;
+		usleep_range(3000, 4000);
+	}
+
+	return -ENODEV;
+}
+
+static int smp8759_init(struct tango_pcie *pcie, void __iomem *base)
+{
+	pcie->mux		= base + SMP8759_MUX;
+
+	return tango_check_pcie_link(base + SMP8759_TEST_OUT);
+}
+
+static int tango_pcie_probe(struct platform_device *pdev)
+{
+	int ret = -EINVAL;
+	void __iomem *base;
+	struct resource *res;
+	struct tango_pcie *pcie;
+	struct device *dev = &pdev->dev;
+
+	pr_err("MAJOR ISSUE: PCIe config and mem spaces are muxed\n");
+	pr_err("Tainting kernel... Use driver at your own risk\n");
+	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
+
+	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+	if (!pcie)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, pcie);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	if (of_device_is_compatible(dev->of_node, "sigma,smp8759-pcie"))
+		ret = smp8759_init(pcie, base);
+
+	if (ret)
+		return ret;
+
+	return pci_host_common_probe(pdev, &smp8759_ecam_ops);
+}
+
+static struct platform_driver tango_pcie_driver = {
+	.probe	= tango_pcie_probe,
+	.driver	= {
+		.name = KBUILD_MODNAME,
+		.of_match_table = tango_pcie_ids,
+	},
+};
+
+builtin_platform_driver(tango_pcie_driver);
+
+/*
+ * QUIRK #3
+ * The root complex advertizes the wrong device class.
+ * Header Type 1 is for PCI-to-PCI bridges.
+ */
+static void tango_fixup_class(struct pci_dev *dev)
+{
+	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x24, tango_fixup_class);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x28, tango_fixup_class);
+
+/*
+ * QUIRK #4
+ * The root complex exposes a "fake" BAR, which is used to filter
+ * bus-to-system accesses. Only accesses within the range defined
+ * by this BAR are forwarded to the host, others are ignored.
+ *
+ * By default, the DMA framework expects an identity mapping,
+ * and DRAM0 is mapped at 0x80000000.
+ */
+static void tango_fixup_bar(struct pci_dev *dev)
+{
+	dev->non_compliant_bars = true;
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x80000000);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x24, tango_fixup_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x28, tango_fixup_bar);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index f020ab4079d3..b577dbe46f8f 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1369,6 +1369,8 @@
 #define PCI_DEVICE_ID_TTI_HPT374	0x0008
 #define PCI_DEVICE_ID_TTI_HPT372N	0x0009	/* apparently a 372N variant? */
 
+#define PCI_VENDOR_ID_SIGMA		0x1105
+
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_8763_0	0x0198
 #define PCI_DEVICE_ID_VIA_8380_0	0x0204
-- 
2.11.0

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

* [PATCH v5 3/3] PCI: Add tango MSI controller support
  2017-05-31 13:28 [PATCH v5 0/3] Tango PCIe controller support Marc Gonzalez
  2017-05-31 13:30 ` [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller Marc Gonzalez
  2017-05-31 13:33 ` [PATCH v5 2/3] PCI: Add tango PCIe host bridge support Marc Gonzalez
@ 2017-05-31 13:35 ` Marc Gonzalez
  2017-06-13 12:09   ` Marc Zyngier
  2 siblings, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-05-31 13:35 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, Thibaud Cornic,
	Phuong Nguyen, LKML, Mason

The MSI controller in Tango supports 256 message-signaled interrupts,
and a single doorbell address.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
---
 drivers/pci/host/pcie-tango.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 222 insertions(+)

diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
index 67aaadcc1c5e..7d99ef26173f 100644
--- a/drivers/pci/host/pcie-tango.c
+++ b/drivers/pci/host/pcie-tango.c
@@ -1,16 +1,225 @@
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
 #include <linux/pci-ecam.h>
 #include <linux/delay.h>
+#include <linux/msi.h>
 #include <linux/of.h>
 
 #define MSI_MAX 256
 
 #define SMP8759_MUX		0x48
 #define SMP8759_TEST_OUT	0x74
+#define SMP8759_STATUS		0x80
+#define SMP8759_ENABLE		0xa0
+#define SMP8759_DOORBELL	0xa002e07c
 
 struct tango_pcie {
+	DECLARE_BITMAP(used, MSI_MAX);
+	spinlock_t lock;
 	void __iomem *mux;
+	void __iomem *msi_status;
+	void __iomem *msi_enable;
+	phys_addr_t msi_doorbell;
+	struct irq_domain *irq_dom;
+	struct irq_domain *msi_dom;
+	int irq;
 };
 
+/*** MSI CONTROLLER SUPPORT ***/
+
+static void tango_msi_isr(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
+	unsigned long status, base, virq, idx, pos = 0;
+
+	chained_irq_enter(chip, desc);
+
+	while ((pos = find_next_bit(pcie->used, MSI_MAX, pos)) < MSI_MAX) {
+		base = round_down(pos, 32);
+		status = readl_relaxed(pcie->msi_status + base / 8);
+		for_each_set_bit(idx, &status, 32) {
+			virq = irq_find_mapping(pcie->irq_dom, base + idx);
+			generic_handle_irq(virq);
+		}
+		pos = base + 32;
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static void tango_ack(struct irq_data *d)
+{
+	struct tango_pcie *pcie = d->chip_data;
+	u32 offset = (d->hwirq / 32) * 4;
+	u32 bit = BIT(d->hwirq % 32);
+
+	writel_relaxed(bit, pcie->msi_status + offset);
+}
+
+static void update_msi_enable(struct irq_data *d, bool unmask)
+{
+	unsigned long flags;
+	struct tango_pcie *pcie = d->chip_data;
+	u32 offset = (d->hwirq / 32) * 4;
+	u32 bit = BIT(d->hwirq % 32);
+	u32 val;
+
+	spin_lock_irqsave(&pcie->lock, flags);
+	val = readl_relaxed(pcie->msi_enable + offset);
+	val = unmask ? val | bit : val & ~bit;
+	writel_relaxed(val, pcie->msi_enable + offset);
+	spin_unlock_irqrestore(&pcie->lock, flags);
+}
+
+static void tango_mask(struct irq_data *d)
+{
+	update_msi_enable(d, false);
+}
+
+static void tango_unmask(struct irq_data *d)
+{
+	update_msi_enable(d, true);
+}
+
+static int tango_set_affinity(struct irq_data *d,
+		const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+
+static void tango_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	struct tango_pcie *pcie = d->chip_data;
+	msg->address_lo = lower_32_bits(pcie->msi_doorbell);
+	msg->address_hi = upper_32_bits(pcie->msi_doorbell);
+	msg->data = d->hwirq;
+}
+
+static struct irq_chip tango_chip = {
+	.irq_ack		= tango_ack,
+	.irq_mask		= tango_mask,
+	.irq_unmask		= tango_unmask,
+	.irq_set_affinity	= tango_set_affinity,
+	.irq_compose_msi_msg	= tango_compose_msi_msg,
+};
+
+static void msi_ack(struct irq_data *d)
+{
+	irq_chip_ack_parent(d);
+}
+
+static void msi_mask(struct irq_data *d)
+{
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void msi_unmask(struct irq_data *d)
+{
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip msi_chip = {
+	.name = "MSI",
+	.irq_ack = msi_ack,
+	.irq_mask = msi_mask,
+	.irq_unmask = msi_unmask,
+};
+
+static struct msi_domain_info msi_dom_info = {
+	.flags	= MSI_FLAG_PCI_MSIX
+		| MSI_FLAG_USE_DEF_DOM_OPS
+		| MSI_FLAG_USE_DEF_CHIP_OPS,
+	.chip	= &msi_chip,
+};
+
+static int tango_irq_domain_alloc(struct irq_domain *dom,
+		unsigned int virq, unsigned int nr_irqs, void *args)
+{
+	unsigned long flags;
+	int pos, err = -ENOSPC;
+	struct tango_pcie *pcie = dom->host_data;
+
+	spin_lock_irqsave(&pcie->lock, flags);
+	pos = find_first_zero_bit(pcie->used, MSI_MAX);
+	if (pos < MSI_MAX) {
+		err = 0;
+		__set_bit(pos, pcie->used);
+		irq_domain_set_info(dom, virq, pos,
+				&tango_chip, pcie, handle_edge_irq, NULL, NULL);
+	}
+	spin_unlock_irqrestore(&pcie->lock, flags);
+
+	return err;
+}
+
+static void tango_irq_domain_free(struct irq_domain *dom,
+		unsigned int virq, unsigned int nr_irqs)
+{
+	unsigned long flags;
+	struct irq_data *d = irq_domain_get_irq_data(dom, virq);
+	struct tango_pcie *pcie = d->chip_data;
+
+	spin_lock_irqsave(&pcie->lock, flags);
+	__clear_bit(d->hwirq, pcie->used);
+	spin_unlock_irqrestore(&pcie->lock, flags);
+}
+
+static const struct irq_domain_ops irq_dom_ops = {
+	.alloc	= tango_irq_domain_alloc,
+	.free	= tango_irq_domain_free,
+};
+
+static int tango_msi_remove(struct platform_device *pdev)
+{
+	struct tango_pcie *pcie = platform_get_drvdata(pdev);
+
+	irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+	irq_domain_remove(pcie->msi_dom);
+	irq_domain_remove(pcie->irq_dom);
+
+	return 0;
+}
+
+static int tango_msi_probe(struct platform_device *pdev, struct tango_pcie *pcie)
+{
+	int i, virq;
+	struct irq_domain *msi_dom, *irq_dom;
+	struct fwnode_handle *fwnode = of_node_to_fwnode(pdev->dev.of_node);
+
+	spin_lock_init(&pcie->lock);
+	for (i = 0; i < MSI_MAX / 32; ++i)
+		writel_relaxed(0, pcie->msi_enable + i * 4);
+
+	virq = platform_get_irq(pdev, 1);
+	if (virq <= 0) {
+		pr_err("Failed to map IRQ\n");
+		return -ENXIO;
+	}
+
+	irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &irq_dom_ops, pcie);
+	if (!irq_dom) {
+		pr_err("Failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	msi_dom = pci_msi_create_irq_domain(fwnode, &msi_dom_info, irq_dom);
+	if (!msi_dom) {
+		pr_err("Failed to create MSI domain\n");
+		return -ENOMEM;
+	}
+
+	pcie->irq_dom = irq_dom;
+	pcie->msi_dom = msi_dom;
+	pcie->irq = virq;
+
+	irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie);
+
+	return 0;
+}
+
 /*** HOST BRIDGE SUPPORT ***/
 
 static int smp8759_config_read(struct pci_bus *bus,
@@ -88,6 +297,9 @@ static int tango_check_pcie_link(void __iomem *test_out)
 static int smp8759_init(struct tango_pcie *pcie, void __iomem *base)
 {
 	pcie->mux		= base + SMP8759_MUX;
+	pcie->msi_status	= base + SMP8759_STATUS;
+	pcie->msi_enable	= base + SMP8759_ENABLE;
+	pcie->msi_doorbell	= SMP8759_DOORBELL;
 
 	return tango_check_pcie_link(base + SMP8759_TEST_OUT);
 }
@@ -121,11 +333,21 @@ static int tango_pcie_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = tango_msi_probe(pdev, pcie);
+	if (ret)
+		return ret;
+
 	return pci_host_common_probe(pdev, &smp8759_ecam_ops);
 }
 
+static int tango_pcie_remove(struct platform_device *pdev)
+{
+	return tango_msi_remove(pdev);
+}
+
 static struct platform_driver tango_pcie_driver = {
 	.probe	= tango_pcie_probe,
+	.remove	= tango_pcie_remove,
 	.driver	= {
 		.name = KBUILD_MODNAME,
 		.of_match_table = tango_pcie_ids,
-- 
2.11.0

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

* Re: [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-05-31 13:33 ` [PATCH v5 2/3] PCI: Add tango PCIe host bridge support Marc Gonzalez
@ 2017-06-07  8:19   ` Marc Gonzalez
  2017-06-19 14:50     ` Marc Gonzalez
  2017-07-05  9:36   ` Ard Biesheuvel
  1 sibling, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-07  8:19 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Marc Zyngier, Thomas Gleixner, Robin Murphy, Lorenzo Pieralisi,
	Liviu Dudau, David Laight, linux-pci, Linux ARM, Thibaud Cornic,
	Phuong Nguyen, LKML, Mason

On 31/05/2017 15:33, Marc Gonzalez wrote:

> +static int tango_pcie_probe(struct platform_device *pdev)
> +{
> +	int ret = -EINVAL;
> +	void __iomem *base;
> +	struct resource *res;
> +	struct tango_pcie *pcie;
> +	struct device *dev = &pdev->dev;
> +
> +	pr_err("MAJOR ISSUE: PCIe config and mem spaces are muxed\n");
> +	pr_err("Tainting kernel... Use driver at your own risk\n");
> +	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);

Hello Bjorn,

In v4, your only comment was
"[muxing config and mem spaces] is a major issue and possibly even
a security problem [which requires at least an error message and a
kernel taint].

Were there any other issues with the host bridge support?
Or is the HW quirk/bug too severe to mainline the driver?
(I would hate having to discard all that work though.)

Regards.

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

* Re: [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller
  2017-05-31 13:30 ` [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller Marc Gonzalez
@ 2017-06-07 21:29   ` Rob Herring
  2017-06-07 22:34     ` Mason
  2017-06-13 13:51     ` [PATCH v6 " Marc Gonzalez
  0 siblings, 2 replies; 27+ messages in thread
From: Rob Herring @ 2017-06-07 21:29 UTC (permalink / raw)
  To: Marc Gonzalez
  Cc: Bjorn Helgaas, Marc Zyngier, Thomas Gleixner, Robin Murphy,
	Lorenzo Pieralisi, Liviu Dudau, David Laight, linux-pci,
	Linux ARM, Thibaud Cornic, Phuong Nguyen, LKML, DT, Mason

On Wed, May 31, 2017 at 03:30:26PM +0200, Marc Gonzalez wrote:
> Binding for the Sigma Designs SMP8759 SoC.
> 
> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
> ---
>  Documentation/devicetree/bindings/pci/tango-pcie.txt | 30 ++++++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/pci/tango-pcie.txt b/Documentation/devicetree/bindings/pci/tango-pcie.txt
> new file mode 100644
> index 000000000000..35ef2c811a27
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/tango-pcie.txt
> @@ -0,0 +1,30 @@
> +Sigma Designs Tango PCIe controller
> +
> +Required properties:
> +
> +- compatible: "sigma,smp8759-pcie"
> +- reg: address/size of PCI configuration space, address/size of register area
> +- device_type: "pci"
> +- #size-cells: <2>
> +- #address-cells: <3>
> +- msi-controller
> +- ranges: translation from system to bus addresses
> +- interrupts: spec for misc interrupts, spec for MSI
> +
> +http://elinux.org/Device_Tree_Usage#PCI_Address_Translation
> +http://elinux.org/Device_Tree_Usage#Advanced_Interrupt_Mapping

Why are these here?

There's several standard properties you are missing like bus-range. 
Build your dts with "W=2". dtc recently gained some checks for PCI 
bindings.

> +
> +Example:
> +
> +	pcie@2e000 {
> +		compatible = "sigma,smp8759-pcie";
> +		reg = <0x50000000 SZ_4M>, <0x2e000 0x100>;
> +		device_type = "pci";
> +		#size-cells = <2>;
> +		#address-cells = <3>;
> +		msi-controller;
> +		ranges = <0x02000000 0x0 0x00400000  0x50400000  0x0 SZ_60M>;

I don't think SZ_60M exists or is available to dts files. Just put the 
number in.

> +		interrupts =
> +			<54 IRQ_TYPE_LEVEL_HIGH>, /* misc interrupts */
> +			<55 IRQ_TYPE_LEVEL_HIGH>; /* MSI */
> +	};
> -- 
> 2.11.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller
  2017-06-07 21:29   ` Rob Herring
@ 2017-06-07 22:34     ` Mason
  2017-06-13 11:55       ` Marc Zyngier
  2017-06-13 14:23       ` Rob Herring
  2017-06-13 13:51     ` [PATCH v6 " Marc Gonzalez
  1 sibling, 2 replies; 27+ messages in thread
From: Mason @ 2017-06-07 22:34 UTC (permalink / raw)
  To: Rob Herring
  Cc: Marc Gonzalez, Bjorn Helgaas, Marc Zyngier, Thomas Gleixner,
	Robin Murphy, Lorenzo Pieralisi, Liviu Dudau, David Laight,
	linux-pci, Linux ARM, Thibaud Cornic, Phuong Nguyen, LKML, DT

Hello Rob,

On 07/06/2017 23:29, Rob Herring wrote:
> On Wed, May 31, 2017 at 03:30:26PM +0200, Marc Gonzalez wrote:
>> Binding for the Sigma Designs SMP8759 SoC.
>>
>> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
>> ---
>>  Documentation/devicetree/bindings/pci/tango-pcie.txt | 30 ++++++++++++++++++++++++++++++
>>  1 file changed, 30 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/pci/tango-pcie.txt b/Documentation/devicetree/bindings/pci/tango-pcie.txt
>> new file mode 100644
>> index 000000000000..35ef2c811a27
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/tango-pcie.txt
>> @@ -0,0 +1,30 @@
>> +Sigma Designs Tango PCIe controller
>> +
>> +Required properties:
>> +
>> +- compatible: "sigma,smp8759-pcie"
>> +- reg: address/size of PCI configuration space, address/size of register area
>> +- device_type: "pci"
>> +- #size-cells: <2>
>> +- #address-cells: <3>
>> +- msi-controller
>> +- ranges: translation from system to bus addresses
>> +- interrupts: spec for misc interrupts, spec for MSI
>> +
>> +http://elinux.org/Device_Tree_Usage#PCI_Address_Translation
>> +http://elinux.org/Device_Tree_Usage#Advanced_Interrupt_Mapping
> 
> Why are these here?

I found these references very helpful when writing the node.
Where would you put them? In the example?

> There's several standard properties you are missing like bus-range.

My reasoning for omitting "bus-range" was that the PCI core computes
it by itself (1M per "bus" so SZ_4M => 4 devices). I thought redundant
information was bad form?

> Build your dts with "W=2". dtc recently gained some checks for PCI 
> bindings.

I'll give it a try. Did v4.9 already support it?

>> +Example:
>> +
>> +	pcie@2e000 {
>> +		compatible = "sigma,smp8759-pcie";
>> +		reg = <0x50000000 SZ_4M>, <0x2e000 0x100>;
>> +		device_type = "pci";
>> +		#size-cells = <2>;
>> +		#address-cells = <3>;
>> +		msi-controller;
>> +		ranges = <0x02000000 0x0 0x00400000  0x50400000  0x0 SZ_60M>;
> 
> I don't think SZ_60M exists or is available to dts files. Just put the 
> number in.

I #defined it at the top of my DTS.
Using symbolic constants in DTS is not acceptable?

Thanks for having a look.

Regards.

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

* Re: [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller
  2017-06-07 22:34     ` Mason
@ 2017-06-13 11:55       ` Marc Zyngier
  2017-06-13 14:23       ` Rob Herring
  1 sibling, 0 replies; 27+ messages in thread
From: Marc Zyngier @ 2017-06-13 11:55 UTC (permalink / raw)
  To: Mason, Rob Herring
  Cc: Marc Gonzalez, Bjorn Helgaas, Thomas Gleixner, Robin Murphy,
	Lorenzo Pieralisi, Liviu Dudau, David Laight, linux-pci,
	Linux ARM, Thibaud Cornic, Phuong Nguyen, LKML, DT

On 07/06/17 23:34, Mason wrote:
> Hello Rob,
> 
> On 07/06/2017 23:29, Rob Herring wrote:
>> On Wed, May 31, 2017 at 03:30:26PM +0200, Marc Gonzalez wrote:
>>> Binding for the Sigma Designs SMP8759 SoC.
>>>
>>> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
>>> ---
>>>  Documentation/devicetree/bindings/pci/tango-pcie.txt | 30 ++++++++++++++++++++++++++++++
>>>  1 file changed, 30 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/pci/tango-pcie.txt b/Documentation/devicetree/bindings/pci/tango-pcie.txt
>>> new file mode 100644
>>> index 000000000000..35ef2c811a27
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/pci/tango-pcie.txt
>>> @@ -0,0 +1,30 @@
>>> +Sigma Designs Tango PCIe controller
>>> +
>>> +Required properties:
>>> +
>>> +- compatible: "sigma,smp8759-pcie"
>>> +- reg: address/size of PCI configuration space, address/size of register area
>>> +- device_type: "pci"
>>> +- #size-cells: <2>
>>> +- #address-cells: <3>
>>> +- msi-controller
>>> +- ranges: translation from system to bus addresses
>>> +- interrupts: spec for misc interrupts, spec for MSI
>>> +
>>> +http://elinux.org/Device_Tree_Usage#PCI_Address_Translation
>>> +http://elinux.org/Device_Tree_Usage#Advanced_Interrupt_Mapping
>>
>> Why are these here?
> 
> I found these references very helpful when writing the node.
> Where would you put them? In the example?

I don't think they belong in this document at all.

Thanks,

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

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

* Re: [PATCH v5 3/3] PCI: Add tango MSI controller support
  2017-05-31 13:35 ` [PATCH v5 3/3] PCI: Add tango MSI controller support Marc Gonzalez
@ 2017-06-13 12:09   ` Marc Zyngier
  2017-06-13 14:01     ` [PATCH v6 " Marc Gonzalez
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Zyngier @ 2017-06-13 12:09 UTC (permalink / raw)
  To: Marc Gonzalez, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, Thibaud Cornic,
	Phuong Nguyen, LKML, Mason

On 31/05/17 14:35, Marc Gonzalez wrote:
> The MSI controller in Tango supports 256 message-signaled interrupts,
> and a single doorbell address.
> 
> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
> ---
>  drivers/pci/host/pcie-tango.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 222 insertions(+)
> 
> diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
> index 67aaadcc1c5e..7d99ef26173f 100644
> --- a/drivers/pci/host/pcie-tango.c
> +++ b/drivers/pci/host/pcie-tango.c
> @@ -1,16 +1,225 @@
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
>  #include <linux/pci-ecam.h>
>  #include <linux/delay.h>
> +#include <linux/msi.h>
>  #include <linux/of.h>
>  
>  #define MSI_MAX 256
>  
>  #define SMP8759_MUX		0x48
>  #define SMP8759_TEST_OUT	0x74
> +#define SMP8759_STATUS		0x80
> +#define SMP8759_ENABLE		0xa0
> +#define SMP8759_DOORBELL	0xa002e07c
>  
>  struct tango_pcie {
> +	DECLARE_BITMAP(used, MSI_MAX);
> +	spinlock_t lock;

These two fields have pretty generic names. Consider naming them in a
way that indicates their purpose (used_msi? used_msi_lock?).

>  	void __iomem *mux;
> +	void __iomem *msi_status;
> +	void __iomem *msi_enable;
> +	phys_addr_t msi_doorbell;
> +	struct irq_domain *irq_dom;
> +	struct irq_domain *msi_dom;
> +	int irq;
>  };
>  
> +/*** MSI CONTROLLER SUPPORT ***/
> +
> +static void tango_msi_isr(struct irq_desc *desc)
> +{
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
> +	unsigned long status, base, virq, idx, pos = 0;
> +
> +	chained_irq_enter(chip, desc);
> +
> +	while ((pos = find_next_bit(pcie->used, MSI_MAX, pos)) < MSI_MAX) {

The pcie->used bitmap read can race against another CPU accessing this
bitmap in the alloc/free paths.

> +		base = round_down(pos, 32);
> +		status = readl_relaxed(pcie->msi_status + base / 8);
> +		for_each_set_bit(idx, &status, 32) {
> +			virq = irq_find_mapping(pcie->irq_dom, base + idx);
> +			generic_handle_irq(virq);
> +		}
> +		pos = base + 32;
> +	}
> +
> +	chained_irq_exit(chip, desc);
> +}
> +
> +static void tango_ack(struct irq_data *d)
> +{
> +	struct tango_pcie *pcie = d->chip_data;
> +	u32 offset = (d->hwirq / 32) * 4;
> +	u32 bit = BIT(d->hwirq % 32);
> +
> +	writel_relaxed(bit, pcie->msi_status + offset);
> +}
> +
> +static void update_msi_enable(struct irq_data *d, bool unmask)
> +{
> +	unsigned long flags;
> +	struct tango_pcie *pcie = d->chip_data;
> +	u32 offset = (d->hwirq / 32) * 4;
> +	u32 bit = BIT(d->hwirq % 32);
> +	u32 val;
> +
> +	spin_lock_irqsave(&pcie->lock, flags);
> +	val = readl_relaxed(pcie->msi_enable + offset);
> +	val = unmask ? val | bit : val & ~bit;
> +	writel_relaxed(val, pcie->msi_enable + offset);
> +	spin_unlock_irqrestore(&pcie->lock, flags);
> +}
> +
> +static void tango_mask(struct irq_data *d)
> +{
> +	update_msi_enable(d, false);
> +}
> +
> +static void tango_unmask(struct irq_data *d)
> +{
> +	update_msi_enable(d, true);
> +}
> +
> +static int tango_set_affinity(struct irq_data *d,
> +		const struct cpumask *mask, bool force)
> +{
> +	return -EINVAL;
> +}
> +
> +static void tango_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
> +{
> +	struct tango_pcie *pcie = d->chip_data;
> +	msg->address_lo = lower_32_bits(pcie->msi_doorbell);
> +	msg->address_hi = upper_32_bits(pcie->msi_doorbell);
> +	msg->data = d->hwirq;
> +}
> +
> +static struct irq_chip tango_chip = {
> +	.irq_ack		= tango_ack,
> +	.irq_mask		= tango_mask,
> +	.irq_unmask		= tango_unmask,
> +	.irq_set_affinity	= tango_set_affinity,
> +	.irq_compose_msi_msg	= tango_compose_msi_msg,
> +};
> +
> +static void msi_ack(struct irq_data *d)
> +{
> +	irq_chip_ack_parent(d);
> +}
> +
> +static void msi_mask(struct irq_data *d)
> +{
> +	pci_msi_mask_irq(d);
> +	irq_chip_mask_parent(d);
> +}
> +
> +static void msi_unmask(struct irq_data *d)
> +{
> +	pci_msi_unmask_irq(d);
> +	irq_chip_unmask_parent(d);
> +}
> +
> +static struct irq_chip msi_chip = {
> +	.name = "MSI",
> +	.irq_ack = msi_ack,
> +	.irq_mask = msi_mask,
> +	.irq_unmask = msi_unmask,
> +};
> +
> +static struct msi_domain_info msi_dom_info = {
> +	.flags	= MSI_FLAG_PCI_MSIX
> +		| MSI_FLAG_USE_DEF_DOM_OPS
> +		| MSI_FLAG_USE_DEF_CHIP_OPS,
> +	.chip	= &msi_chip,
> +};
> +
> +static int tango_irq_domain_alloc(struct irq_domain *dom,
> +		unsigned int virq, unsigned int nr_irqs, void *args)
> +{
> +	unsigned long flags;
> +	int pos, err = -ENOSPC;
> +	struct tango_pcie *pcie = dom->host_data;
> +
> +	spin_lock_irqsave(&pcie->lock, flags);
> +	pos = find_first_zero_bit(pcie->used, MSI_MAX);
> +	if (pos < MSI_MAX) {
> +		err = 0;
> +		__set_bit(pos, pcie->used);
> +		irq_domain_set_info(dom, virq, pos,
> +				&tango_chip, pcie, handle_edge_irq, NULL, NULL);
> +	}
> +	spin_unlock_irqrestore(&pcie->lock, flags);
> +
> +	return err;
> +}
> +
> +static void tango_irq_domain_free(struct irq_domain *dom,
> +		unsigned int virq, unsigned int nr_irqs)
> +{
> +	unsigned long flags;
> +	struct irq_data *d = irq_domain_get_irq_data(dom, virq);
> +	struct tango_pcie *pcie = d->chip_data;
> +
> +	spin_lock_irqsave(&pcie->lock, flags);
> +	__clear_bit(d->hwirq, pcie->used);
> +	spin_unlock_irqrestore(&pcie->lock, flags);
> +}
> +
> +static const struct irq_domain_ops irq_dom_ops = {
> +	.alloc	= tango_irq_domain_alloc,
> +	.free	= tango_irq_domain_free,
> +};
> +
> +static int tango_msi_remove(struct platform_device *pdev)
> +{
> +	struct tango_pcie *pcie = platform_get_drvdata(pdev);
> +
> +	irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
> +	irq_domain_remove(pcie->msi_dom);
> +	irq_domain_remove(pcie->irq_dom);
> +
> +	return 0;
> +}
> +
> +static int tango_msi_probe(struct platform_device *pdev, struct tango_pcie *pcie)
> +{
> +	int i, virq;
> +	struct irq_domain *msi_dom, *irq_dom;
> +	struct fwnode_handle *fwnode = of_node_to_fwnode(pdev->dev.of_node);
> +
> +	spin_lock_init(&pcie->lock);
> +	for (i = 0; i < MSI_MAX / 32; ++i)
> +		writel_relaxed(0, pcie->msi_enable + i * 4);
> +
> +	virq = platform_get_irq(pdev, 1);
> +	if (virq <= 0) {
> +		pr_err("Failed to map IRQ\n");
> +		return -ENXIO;
> +	}
> +
> +	irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &irq_dom_ops, pcie);
> +	if (!irq_dom) {
> +		pr_err("Failed to create IRQ domain\n");
> +		return -ENOMEM;
> +	}
> +
> +	msi_dom = pci_msi_create_irq_domain(fwnode, &msi_dom_info, irq_dom);
> +	if (!msi_dom) {
> +		pr_err("Failed to create MSI domain\n");
> +		return -ENOMEM;

You're now leaking irq_dom.

> +	}
> +
> +	pcie->irq_dom = irq_dom;
> +	pcie->msi_dom = msi_dom;
> +	pcie->irq = virq;
> +
> +	irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie);
> +
> +	return 0;
> +}
> +
>  /*** HOST BRIDGE SUPPORT ***/
>  
>  static int smp8759_config_read(struct pci_bus *bus,
> @@ -88,6 +297,9 @@ static int tango_check_pcie_link(void __iomem *test_out)
>  static int smp8759_init(struct tango_pcie *pcie, void __iomem *base)
>  {
>  	pcie->mux		= base + SMP8759_MUX;
> +	pcie->msi_status	= base + SMP8759_STATUS;
> +	pcie->msi_enable	= base + SMP8759_ENABLE;
> +	pcie->msi_doorbell	= SMP8759_DOORBELL;
>  
>  	return tango_check_pcie_link(base + SMP8759_TEST_OUT);
>  }
> @@ -121,11 +333,21 @@ static int tango_pcie_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> +	ret = tango_msi_probe(pdev, pcie);
> +	if (ret)
> +		return ret;
> +
>  	return pci_host_common_probe(pdev, &smp8759_ecam_ops);
>  }
>  
> +static int tango_pcie_remove(struct platform_device *pdev)
> +{
> +	return tango_msi_remove(pdev);
> +}
> +
>  static struct platform_driver tango_pcie_driver = {
>  	.probe	= tango_pcie_probe,
> +	.remove	= tango_pcie_remove,
>  	.driver	= {
>  		.name = KBUILD_MODNAME,
>  		.of_match_table = tango_pcie_ids,
> 

Thanks,

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

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

* [PATCH v6 1/3] PCI: Add DT binding for tango PCIe controller
  2017-06-07 21:29   ` Rob Herring
  2017-06-07 22:34     ` Mason
@ 2017-06-13 13:51     ` Marc Gonzalez
  2017-06-18 14:05       ` Rob Herring
  1 sibling, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-13 13:51 UTC (permalink / raw)
  To: Rob Herring
  Cc: Bjorn Helgaas, Marc Zyngier, Thomas Gleixner, Robin Murphy,
	Lorenzo Pieralisi, Liviu Dudau, David Laight, linux-pci,
	Linux ARM, LKML, DT, Mason

Binding for the Sigma Designs SMP8759 SoC.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
---
Changes from v5 to v6
o Delete links to elinux.org
o Use explicit hex numbers instead of symbolic constants for sizes (in the example)
o Add bus-range to "Required properties"
---
 .../devicetree/bindings/pci/tango-pcie.txt         | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/tango-pcie.txt

diff --git a/Documentation/devicetree/bindings/pci/tango-pcie.txt b/Documentation/devicetree/bindings/pci/tango-pcie.txt
new file mode 100644
index 000000000000..244683836a79
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/tango-pcie.txt
@@ -0,0 +1,29 @@
+Sigma Designs Tango PCIe controller
+
+Required properties:
+
+- compatible: "sigma,smp8759-pcie"
+- reg: address/size of PCI configuration space, address/size of register area
+- bus-range: defined by size of PCI configuration space
+- device_type: "pci"
+- #size-cells: <2>
+- #address-cells: <3>
+- msi-controller
+- ranges: translation from system to bus addresses
+- interrupts: spec for misc interrupts, spec for MSI
+
+Example:
+
+	pcie@2e000 {
+		compatible = "sigma,smp8759-pcie";
+		reg = <0x50000000 0x400000>, <0x2e000 0x100>;
+		bus-range = <0 3>;
+		device_type = "pci";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		msi-controller;
+		ranges = <0x02000000 0x0 0x00400000  0x50400000  0x0 0x3c00000>;
+		interrupts =
+			<54 IRQ_TYPE_LEVEL_HIGH>, /* misc interrupts */
+			<55 IRQ_TYPE_LEVEL_HIGH>; /* MSI */
+	};
-- 
2.11.0

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

* [PATCH v6 3/3] PCI: Add tango MSI controller support
  2017-06-13 12:09   ` Marc Zyngier
@ 2017-06-13 14:01     ` Marc Gonzalez
  2017-06-13 14:22       ` Marc Zyngier
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-13 14:01 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, LKML, Mason

The MSI controller in Tango supports 256 message-signaled interrupts,
and a single doorbell address.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
---
Changes from v5 to v6
o Rename 'used' bitmap to 'used_msi'
o Rename 'lock' spinlock to 'used_msi_lock'
o Take lock in interrupt handler
o Remove irq_dom in error path
---
 drivers/pci/host/pcie-tango.c | 225 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 225 insertions(+)

diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
index 67aaadcc1c5e..b06446b23bc8 100644
--- a/drivers/pci/host/pcie-tango.c
+++ b/drivers/pci/host/pcie-tango.c
@@ -1,16 +1,228 @@
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
 #include <linux/pci-ecam.h>
 #include <linux/delay.h>
+#include <linux/msi.h>
 #include <linux/of.h>
 
 #define MSI_MAX 256
 
 #define SMP8759_MUX		0x48
 #define SMP8759_TEST_OUT	0x74
+#define SMP8759_STATUS		0x80
+#define SMP8759_ENABLE		0xa0
+#define SMP8759_DOORBELL	0xa002e07c
 
 struct tango_pcie {
+	DECLARE_BITMAP(used_msi, MSI_MAX);
+	spinlock_t used_msi_lock;
 	void __iomem *mux;
+	void __iomem *msi_status;
+	void __iomem *msi_enable;
+	phys_addr_t msi_doorbell;
+	struct irq_domain *irq_dom;
+	struct irq_domain *msi_dom;
+	int irq;
 };
 
+/*** MSI CONTROLLER SUPPORT ***/
+
+static void tango_msi_isr(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
+	unsigned long flags, status, base, virq, idx, pos = 0;
+
+	chained_irq_enter(chip, desc);
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+
+	while ((pos = find_next_bit(pcie->used_msi, MSI_MAX, pos)) < MSI_MAX) {
+		base = round_down(pos, 32);
+		status = readl_relaxed(pcie->msi_status + base / 8);
+		for_each_set_bit(idx, &status, 32) {
+			virq = irq_find_mapping(pcie->irq_dom, base + idx);
+			generic_handle_irq(virq);
+		}
+		pos = base + 32;
+	}
+
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+	chained_irq_exit(chip, desc);
+}
+
+static void tango_ack(struct irq_data *d)
+{
+	struct tango_pcie *pcie = d->chip_data;
+	u32 offset = (d->hwirq / 32) * 4;
+	u32 bit = BIT(d->hwirq % 32);
+
+	writel_relaxed(bit, pcie->msi_status + offset);
+}
+
+static void update_msi_enable(struct irq_data *d, bool unmask)
+{
+	unsigned long flags;
+	struct tango_pcie *pcie = d->chip_data;
+	u32 offset = (d->hwirq / 32) * 4;
+	u32 bit = BIT(d->hwirq % 32);
+	u32 val;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	val = readl_relaxed(pcie->msi_enable + offset);
+	val = unmask ? val | bit : val & ~bit;
+	writel_relaxed(val, pcie->msi_enable + offset);
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+}
+
+static void tango_mask(struct irq_data *d)
+{
+	update_msi_enable(d, false);
+}
+
+static void tango_unmask(struct irq_data *d)
+{
+	update_msi_enable(d, true);
+}
+
+static int tango_set_affinity(struct irq_data *d,
+		const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+
+static void tango_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	struct tango_pcie *pcie = d->chip_data;
+	msg->address_lo = lower_32_bits(pcie->msi_doorbell);
+	msg->address_hi = upper_32_bits(pcie->msi_doorbell);
+	msg->data = d->hwirq;
+}
+
+static struct irq_chip tango_chip = {
+	.irq_ack		= tango_ack,
+	.irq_mask		= tango_mask,
+	.irq_unmask		= tango_unmask,
+	.irq_set_affinity	= tango_set_affinity,
+	.irq_compose_msi_msg	= tango_compose_msi_msg,
+};
+
+static void msi_ack(struct irq_data *d)
+{
+	irq_chip_ack_parent(d);
+}
+
+static void msi_mask(struct irq_data *d)
+{
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void msi_unmask(struct irq_data *d)
+{
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip msi_chip = {
+	.name = "MSI",
+	.irq_ack = msi_ack,
+	.irq_mask = msi_mask,
+	.irq_unmask = msi_unmask,
+};
+
+static struct msi_domain_info msi_dom_info = {
+	.flags	= MSI_FLAG_PCI_MSIX
+		| MSI_FLAG_USE_DEF_DOM_OPS
+		| MSI_FLAG_USE_DEF_CHIP_OPS,
+	.chip	= &msi_chip,
+};
+
+static int tango_irq_domain_alloc(struct irq_domain *dom,
+		unsigned int virq, unsigned int nr_irqs, void *args)
+{
+	unsigned long flags;
+	int pos, err = -ENOSPC;
+	struct tango_pcie *pcie = dom->host_data;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	pos = find_first_zero_bit(pcie->used_msi, MSI_MAX);
+	if (pos < MSI_MAX) {
+		err = 0;
+		__set_bit(pos, pcie->used_msi);
+		irq_domain_set_info(dom, virq, pos,
+				&tango_chip, pcie, handle_edge_irq, NULL, NULL);
+	}
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+
+	return err;
+}
+
+static void tango_irq_domain_free(struct irq_domain *dom,
+		unsigned int virq, unsigned int nr_irqs)
+{
+	unsigned long flags;
+	struct irq_data *d = irq_domain_get_irq_data(dom, virq);
+	struct tango_pcie *pcie = d->chip_data;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	__clear_bit(d->hwirq, pcie->used_msi);
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+}
+
+static const struct irq_domain_ops irq_dom_ops = {
+	.alloc	= tango_irq_domain_alloc,
+	.free	= tango_irq_domain_free,
+};
+
+static int tango_msi_remove(struct platform_device *pdev)
+{
+	struct tango_pcie *pcie = platform_get_drvdata(pdev);
+
+	irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+	irq_domain_remove(pcie->msi_dom);
+	irq_domain_remove(pcie->irq_dom);
+
+	return 0;
+}
+
+static int tango_msi_probe(struct platform_device *pdev, struct tango_pcie *pcie)
+{
+	int i, virq;
+	struct irq_domain *msi_dom, *irq_dom;
+	struct fwnode_handle *fwnode = of_node_to_fwnode(pdev->dev.of_node);
+
+	spin_lock_init(&pcie->used_msi_lock);
+	for (i = 0; i < MSI_MAX / 32; ++i)
+		writel_relaxed(0, pcie->msi_enable + i * 4);
+
+	virq = platform_get_irq(pdev, 1);
+	if (virq <= 0) {
+		pr_err("Failed to map IRQ\n");
+		return -ENXIO;
+	}
+
+	irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &irq_dom_ops, pcie);
+	if (!irq_dom) {
+		pr_err("Failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	msi_dom = pci_msi_create_irq_domain(fwnode, &msi_dom_info, irq_dom);
+	if (!msi_dom) {
+		pr_err("Failed to create MSI domain\n");
+		irq_domain_remove(irq_dom);
+		return -ENOMEM;
+	}
+
+	pcie->irq_dom = irq_dom;
+	pcie->msi_dom = msi_dom;
+	pcie->irq = virq;
+
+	irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie);
+
+	return 0;
+}
+
 /*** HOST BRIDGE SUPPORT ***/
 
 static int smp8759_config_read(struct pci_bus *bus,
@@ -88,6 +300,9 @@ static int tango_check_pcie_link(void __iomem *test_out)
 static int smp8759_init(struct tango_pcie *pcie, void __iomem *base)
 {
 	pcie->mux		= base + SMP8759_MUX;
+	pcie->msi_status	= base + SMP8759_STATUS;
+	pcie->msi_enable	= base + SMP8759_ENABLE;
+	pcie->msi_doorbell	= SMP8759_DOORBELL;
 
 	return tango_check_pcie_link(base + SMP8759_TEST_OUT);
 }
@@ -121,11 +336,21 @@ static int tango_pcie_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = tango_msi_probe(pdev, pcie);
+	if (ret)
+		return ret;
+
 	return pci_host_common_probe(pdev, &smp8759_ecam_ops);
 }
 
+static int tango_pcie_remove(struct platform_device *pdev)
+{
+	return tango_msi_remove(pdev);
+}
+
 static struct platform_driver tango_pcie_driver = {
 	.probe	= tango_pcie_probe,
+	.remove	= tango_pcie_remove,
 	.driver	= {
 		.name = KBUILD_MODNAME,
 		.of_match_table = tango_pcie_ids,
-- 
2.11.0

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

* Re: [PATCH v6 3/3] PCI: Add tango MSI controller support
  2017-06-13 14:01     ` [PATCH v6 " Marc Gonzalez
@ 2017-06-13 14:22       ` Marc Zyngier
  2017-06-13 14:47         ` Marc Gonzalez
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Zyngier @ 2017-06-13 14:22 UTC (permalink / raw)
  To: Marc Gonzalez, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, LKML, Mason

On 13/06/17 15:01, Marc Gonzalez wrote:
> The MSI controller in Tango supports 256 message-signaled interrupts,
> and a single doorbell address.
> 
> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
> ---
> Changes from v5 to v6
> o Rename 'used' bitmap to 'used_msi'
> o Rename 'lock' spinlock to 'used_msi_lock'
> o Take lock in interrupt handler
> o Remove irq_dom in error path
> ---
>  drivers/pci/host/pcie-tango.c | 225 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 225 insertions(+)
> 
> diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
> index 67aaadcc1c5e..b06446b23bc8 100644
> --- a/drivers/pci/host/pcie-tango.c
> +++ b/drivers/pci/host/pcie-tango.c
> @@ -1,16 +1,228 @@
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
>  #include <linux/pci-ecam.h>
>  #include <linux/delay.h>
> +#include <linux/msi.h>
>  #include <linux/of.h>
>  
>  #define MSI_MAX 256
>  
>  #define SMP8759_MUX		0x48
>  #define SMP8759_TEST_OUT	0x74
> +#define SMP8759_STATUS		0x80
> +#define SMP8759_ENABLE		0xa0
> +#define SMP8759_DOORBELL	0xa002e07c
>  
>  struct tango_pcie {
> +	DECLARE_BITMAP(used_msi, MSI_MAX);
> +	spinlock_t used_msi_lock;
>  	void __iomem *mux;
> +	void __iomem *msi_status;
> +	void __iomem *msi_enable;
> +	phys_addr_t msi_doorbell;
> +	struct irq_domain *irq_dom;
> +	struct irq_domain *msi_dom;
> +	int irq;
>  };
>  
> +/*** MSI CONTROLLER SUPPORT ***/
> +
> +static void tango_msi_isr(struct irq_desc *desc)
> +{
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
> +	unsigned long flags, status, base, virq, idx, pos = 0;
> +
> +	chained_irq_enter(chip, desc);
> +	spin_lock_irqsave(&pcie->used_msi_lock, flags);

You're already in interrupt context, so there is no need to disable
interrupts any further. spin_lock() should do the trick

Thanks,

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

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

* Re: [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller
  2017-06-07 22:34     ` Mason
  2017-06-13 11:55       ` Marc Zyngier
@ 2017-06-13 14:23       ` Rob Herring
  1 sibling, 0 replies; 27+ messages in thread
From: Rob Herring @ 2017-06-13 14:23 UTC (permalink / raw)
  To: Mason
  Cc: Marc Gonzalez, Bjorn Helgaas, Marc Zyngier, Thomas Gleixner,
	Robin Murphy, Lorenzo Pieralisi, Liviu Dudau, David Laight,
	linux-pci, Linux ARM, Thibaud Cornic, Phuong Nguyen, LKML, DT

On Wed, Jun 7, 2017 at 5:34 PM, Mason <slash.tmp@free.fr> wrote:
> Hello Rob,
>
> On 07/06/2017 23:29, Rob Herring wrote:
>> On Wed, May 31, 2017 at 03:30:26PM +0200, Marc Gonzalez wrote:
>>> Binding for the Sigma Designs SMP8759 SoC.
>>>
>>> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
>>> ---
>>>  Documentation/devicetree/bindings/pci/tango-pcie.txt | 30 ++++++++++++++++++++++++++++++
>>>  1 file changed, 30 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/pci/tango-pcie.txt b/Documentation/devicetree/bindings/pci/tango-pcie.txt
>>> new file mode 100644
>>> index 000000000000..35ef2c811a27
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/pci/tango-pcie.txt
>>> @@ -0,0 +1,30 @@
>>> +Sigma Designs Tango PCIe controller
>>> +
>>> +Required properties:
>>> +
>>> +- compatible: "sigma,smp8759-pcie"
>>> +- reg: address/size of PCI configuration space, address/size of register area
>>> +- device_type: "pci"
>>> +- #size-cells: <2>
>>> +- #address-cells: <3>
>>> +- msi-controller
>>> +- ranges: translation from system to bus addresses
>>> +- interrupts: spec for misc interrupts, spec for MSI
>>> +
>>> +http://elinux.org/Device_Tree_Usage#PCI_Address_Translation
>>> +http://elinux.org/Device_Tree_Usage#Advanced_Interrupt_Mapping
>>
>> Why are these here?
>
> I found these references very helpful when writing the node.

Yes, I refer to them regularly.

> Where would you put them? In the example?

They are useful to every PCI binding. That doesn't mean we should link
to them in for every single PCI host binding doc. They belong in a DT
howto or something if not there already.

Rob

>
>> There's several standard properties you are missing like bus-range.
>
> My reasoning for omitting "bus-range" was that the PCI core computes
> it by itself (1M per "bus" so SZ_4M => 4 devices). I thought redundant
> information was bad form?
>
>> Build your dts with "W=2". dtc recently gained some checks for PCI
>> bindings.
>
> I'll give it a try. Did v4.9 already support it?

No, v4.12.

>
>>> +Example:
>>> +
>>> +    pcie@2e000 {
>>> +            compatible = "sigma,smp8759-pcie";
>>> +            reg = <0x50000000 SZ_4M>, <0x2e000 0x100>;
>>> +            device_type = "pci";
>>> +            #size-cells = <2>;
>>> +            #address-cells = <3>;
>>> +            msi-controller;
>>> +            ranges = <0x02000000 0x0 0x00400000  0x50400000  0x0 SZ_60M>;
>>
>> I don't think SZ_60M exists or is available to dts files. Just put the
>> number in.
>
> I #defined it at the top of my DTS.
> Using symbolic constants in DTS is not acceptable?

We generally don't use them here (i.e. for reg). The main use is for
things also used by drivers like GPIO flags or IDs such as clock IDs.
So please drop these.

Rob

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

* Re: [PATCH v6 3/3] PCI: Add tango MSI controller support
  2017-06-13 14:22       ` Marc Zyngier
@ 2017-06-13 14:47         ` Marc Gonzalez
  2017-06-13 16:53           ` Marc Zyngier
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-13 14:47 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, LKML, Mason

On 13/06/2017 16:22, Marc Zyngier wrote:
> On 13/06/17 15:01, Marc Gonzalez wrote:
>> The MSI controller in Tango supports 256 message-signaled interrupts,
>> and a single doorbell address.
>>
>> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
>> ---
>> Changes from v5 to v6
>> o Rename 'used' bitmap to 'used_msi'
>> o Rename 'lock' spinlock to 'used_msi_lock'
>> o Take lock in interrupt handler
>> o Remove irq_dom in error path
>> ---
>>  drivers/pci/host/pcie-tango.c | 225 ++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 225 insertions(+)
>>
>> diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
>> index 67aaadcc1c5e..b06446b23bc8 100644
>> --- a/drivers/pci/host/pcie-tango.c
>> +++ b/drivers/pci/host/pcie-tango.c
>> @@ -1,16 +1,228 @@
>> +#include <linux/irqchip/chained_irq.h>
>> +#include <linux/irqdomain.h>
>>  #include <linux/pci-ecam.h>
>>  #include <linux/delay.h>
>> +#include <linux/msi.h>
>>  #include <linux/of.h>
>>  
>>  #define MSI_MAX 256
>>  
>>  #define SMP8759_MUX		0x48
>>  #define SMP8759_TEST_OUT	0x74
>> +#define SMP8759_STATUS		0x80
>> +#define SMP8759_ENABLE		0xa0
>> +#define SMP8759_DOORBELL	0xa002e07c
>>  
>>  struct tango_pcie {
>> +	DECLARE_BITMAP(used_msi, MSI_MAX);
>> +	spinlock_t used_msi_lock;
>>  	void __iomem *mux;
>> +	void __iomem *msi_status;
>> +	void __iomem *msi_enable;
>> +	phys_addr_t msi_doorbell;
>> +	struct irq_domain *irq_dom;
>> +	struct irq_domain *msi_dom;
>> +	int irq;
>>  };
>>  
>> +/*** MSI CONTROLLER SUPPORT ***/
>> +
>> +static void tango_msi_isr(struct irq_desc *desc)
>> +{
>> +	struct irq_chip *chip = irq_desc_get_chip(desc);
>> +	struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
>> +	unsigned long flags, status, base, virq, idx, pos = 0;
>> +
>> +	chained_irq_enter(chip, desc);
>> +	spin_lock_irqsave(&pcie->used_msi_lock, flags);
> 
> You're already in interrupt context, so there is no need to disable
> interrupts any further. spin_lock() should do the trick

Thanks for the hint.

I am confused, because Documentation/locking/spinlocks.txt states:

> If you have a case where you have to protect a data structure across
> several CPU's and you want to use spinlocks you can potentially use
> cheaper versions of the spinlocks. IFF you know that the spinlocks are
> never used in interrupt handlers, you can use the non-irq versions:
> 
> 	spin_lock(&lock);
> 	...
> 	spin_unlock(&lock);
> 
> (and the equivalent read-write versions too, of course). The spinlock will
> guarantee the same kind of exclusive access, and it will be much faster.
> This is useful if you know that the data in question is only ever
> manipulated from a "process context", ie no interrupts involved.
> 
> The reasons you mustn't use these versions if you have interrupts that
> play with the spinlock is that you can get deadlocks:
> 
> 	spin_lock(&lock);
> 	...
> 		<- interrupt comes in:
> 			spin_lock(&lock);
> 
> where an interrupt tries to lock an already locked variable. This is ok if
> the other interrupt happens on another CPU, but it is _not_ ok if the
> interrupt happens on the same CPU that already holds the lock, because the
> lock will obviously never be released (because the interrupt is waiting
> for the lock, and the lock-holder is interrupted by the interrupt and will
> not continue until the interrupt has been processed).
> 
> (This is also the reason why the irq-versions of the spinlocks only need
> to disable the _local_ interrupts - it's ok to use spinlocks in interrupts
> on other CPU's, because an interrupt on another CPU doesn't interrupt the
> CPU that holds the lock, so the lock-holder can continue and eventually
> releases the lock).

Isn't this saying that it is not safe to call spin_lock() from
the interrupt handler? (Sorry if I misunderstood.)

Regards.

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

* Re: [PATCH v6 3/3] PCI: Add tango MSI controller support
  2017-06-13 14:47         ` Marc Gonzalez
@ 2017-06-13 16:53           ` Marc Zyngier
  2017-06-14  9:00             ` [PATCH v7 " Marc Gonzalez
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Zyngier @ 2017-06-13 16:53 UTC (permalink / raw)
  To: Marc Gonzalez, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, LKML, Mason

On 13/06/17 15:47, Marc Gonzalez wrote:
> On 13/06/2017 16:22, Marc Zyngier wrote:
>> On 13/06/17 15:01, Marc Gonzalez wrote:
>>> The MSI controller in Tango supports 256 message-signaled interrupts,
>>> and a single doorbell address.
>>>
>>> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
>>> ---
>>> Changes from v5 to v6
>>> o Rename 'used' bitmap to 'used_msi'
>>> o Rename 'lock' spinlock to 'used_msi_lock'
>>> o Take lock in interrupt handler
>>> o Remove irq_dom in error path
>>> ---
>>>  drivers/pci/host/pcie-tango.c | 225 ++++++++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 225 insertions(+)
>>>
>>> diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
>>> index 67aaadcc1c5e..b06446b23bc8 100644
>>> --- a/drivers/pci/host/pcie-tango.c
>>> +++ b/drivers/pci/host/pcie-tango.c
>>> @@ -1,16 +1,228 @@
>>> +#include <linux/irqchip/chained_irq.h>
>>> +#include <linux/irqdomain.h>
>>>  #include <linux/pci-ecam.h>
>>>  #include <linux/delay.h>
>>> +#include <linux/msi.h>
>>>  #include <linux/of.h>
>>>  
>>>  #define MSI_MAX 256
>>>  
>>>  #define SMP8759_MUX		0x48
>>>  #define SMP8759_TEST_OUT	0x74
>>> +#define SMP8759_STATUS		0x80
>>> +#define SMP8759_ENABLE		0xa0
>>> +#define SMP8759_DOORBELL	0xa002e07c
>>>  
>>>  struct tango_pcie {
>>> +	DECLARE_BITMAP(used_msi, MSI_MAX);
>>> +	spinlock_t used_msi_lock;
>>>  	void __iomem *mux;
>>> +	void __iomem *msi_status;
>>> +	void __iomem *msi_enable;
>>> +	phys_addr_t msi_doorbell;
>>> +	struct irq_domain *irq_dom;
>>> +	struct irq_domain *msi_dom;
>>> +	int irq;
>>>  };
>>>  
>>> +/*** MSI CONTROLLER SUPPORT ***/
>>> +
>>> +static void tango_msi_isr(struct irq_desc *desc)
>>> +{
>>> +	struct irq_chip *chip = irq_desc_get_chip(desc);
>>> +	struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
>>> +	unsigned long flags, status, base, virq, idx, pos = 0;
>>> +
>>> +	chained_irq_enter(chip, desc);
>>> +	spin_lock_irqsave(&pcie->used_msi_lock, flags);
>>
>> You're already in interrupt context, so there is no need to disable
>> interrupts any further. spin_lock() should do the trick
> 
> Thanks for the hint.
> 
> I am confused, because Documentation/locking/spinlocks.txt states:
> 
>> If you have a case where you have to protect a data structure across
>> several CPU's and you want to use spinlocks you can potentially use
>> cheaper versions of the spinlocks. IFF you know that the spinlocks are
>> never used in interrupt handlers, you can use the non-irq versions:
>>
>> 	spin_lock(&lock);
>> 	...
>> 	spin_unlock(&lock);
>>
>> (and the equivalent read-write versions too, of course). The spinlock will
>> guarantee the same kind of exclusive access, and it will be much faster.
>> This is useful if you know that the data in question is only ever
>> manipulated from a "process context", ie no interrupts involved.
>>
>> The reasons you mustn't use these versions if you have interrupts that
>> play with the spinlock is that you can get deadlocks:
>>
>> 	spin_lock(&lock);
>> 	...
>> 		<- interrupt comes in:
>> 			spin_lock(&lock);
>>
>> where an interrupt tries to lock an already locked variable. This is ok if
>> the other interrupt happens on another CPU, but it is _not_ ok if the
>> interrupt happens on the same CPU that already holds the lock, because the
>> lock will obviously never be released (because the interrupt is waiting
>> for the lock, and the lock-holder is interrupted by the interrupt and will
>> not continue until the interrupt has been processed).
>>
>> (This is also the reason why the irq-versions of the spinlocks only need
>> to disable the _local_ interrupts - it's ok to use spinlocks in interrupts
>> on other CPU's, because an interrupt on another CPU doesn't interrupt the
>> CPU that holds the lock, so the lock-holder can continue and eventually
>> releases the lock).
> 
> Isn't this saying that it is not safe to call spin_lock() from
> the interrupt handler? (Sorry if I misunderstood.)

It is saying exactly the opposite.

If you take a spinlock and can be interrupted by an interrupt that takes
the same spinlock, then you must use the irq-safe version *outside of
the interrupt handler*. That's because Linux interrupts are not
preemptible (well, in general -- it is different with RT, but let's not
get there). If you're guaranteed that no interrupt handler will take
this spinlock, then you don't have to use the irq-safe version.

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

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

* [PATCH v7 3/3] PCI: Add tango MSI controller support
  2017-06-13 16:53           ` Marc Zyngier
@ 2017-06-14  9:00             ` Marc Gonzalez
  2017-06-14  9:19               ` Marc Gonzalez
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-14  9:00 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, LKML, Mason

The MSI controller in Tango supports 256 message-signaled interrupts,
and a single doorbell address.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
---
Changes from v6 to v7
o Call spin_lock() not spin_lock_irqsave() in the ISR
---
 drivers/pci/host/pcie-tango.c | 225 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 225 insertions(+)

diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
index 67aaadcc1c5e..d4b3520b5a03 100644
--- a/drivers/pci/host/pcie-tango.c
+++ b/drivers/pci/host/pcie-tango.c
@@ -1,16 +1,228 @@
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
 #include <linux/pci-ecam.h>
 #include <linux/delay.h>
+#include <linux/msi.h>
 #include <linux/of.h>
 
 #define MSI_MAX 256
 
 #define SMP8759_MUX		0x48
 #define SMP8759_TEST_OUT	0x74
+#define SMP8759_STATUS		0x80
+#define SMP8759_ENABLE		0xa0
+#define SMP8759_DOORBELL	0xa002e07c
 
 struct tango_pcie {
+	DECLARE_BITMAP(used_msi, MSI_MAX);
+	spinlock_t used_msi_lock;
 	void __iomem *mux;
+	void __iomem *msi_status;
+	void __iomem *msi_enable;
+	phys_addr_t msi_doorbell;
+	struct irq_domain *irq_dom;
+	struct irq_domain *msi_dom;
+	int irq;
 };
 
+/*** MSI CONTROLLER SUPPORT ***/
+
+static void tango_msi_isr(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
+	unsigned long status, base, virq, idx, pos = 0;
+
+	chained_irq_enter(chip, desc);
+	spin_lock(&pcie->used_msi_lock);
+
+	while ((pos = find_next_bit(pcie->used_msi, MSI_MAX, pos)) < MSI_MAX) {
+		base = round_down(pos, 32);
+		status = readl_relaxed(pcie->msi_status + base / 8);
+		for_each_set_bit(idx, &status, 32) {
+			virq = irq_find_mapping(pcie->irq_dom, base + idx);
+			generic_handle_irq(virq);
+		}
+		pos = base + 32;
+	}
+
+	spin_unlock(&pcie->used_msi_lock);
+	chained_irq_exit(chip, desc);
+}
+
+static void tango_ack(struct irq_data *d)
+{
+	struct tango_pcie *pcie = d->chip_data;
+	u32 offset = (d->hwirq / 32) * 4;
+	u32 bit = BIT(d->hwirq % 32);
+
+	writel_relaxed(bit, pcie->msi_status + offset);
+}
+
+static void update_msi_enable(struct irq_data *d, bool unmask)
+{
+	unsigned long flags;
+	struct tango_pcie *pcie = d->chip_data;
+	u32 offset = (d->hwirq / 32) * 4;
+	u32 bit = BIT(d->hwirq % 32);
+	u32 val;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	val = readl_relaxed(pcie->msi_enable + offset);
+	val = unmask ? val | bit : val & ~bit;
+	writel_relaxed(val, pcie->msi_enable + offset);
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+}
+
+static void tango_mask(struct irq_data *d)
+{
+	update_msi_enable(d, false);
+}
+
+static void tango_unmask(struct irq_data *d)
+{
+	update_msi_enable(d, true);
+}
+
+static int tango_set_affinity(struct irq_data *d,
+		const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+
+static void tango_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	struct tango_pcie *pcie = d->chip_data;
+	msg->address_lo = lower_32_bits(pcie->msi_doorbell);
+	msg->address_hi = upper_32_bits(pcie->msi_doorbell);
+	msg->data = d->hwirq;
+}
+
+static struct irq_chip tango_chip = {
+	.irq_ack		= tango_ack,
+	.irq_mask		= tango_mask,
+	.irq_unmask		= tango_unmask,
+	.irq_set_affinity	= tango_set_affinity,
+	.irq_compose_msi_msg	= tango_compose_msi_msg,
+};
+
+static void msi_ack(struct irq_data *d)
+{
+	irq_chip_ack_parent(d);
+}
+
+static void msi_mask(struct irq_data *d)
+{
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void msi_unmask(struct irq_data *d)
+{
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip msi_chip = {
+	.name = "MSI",
+	.irq_ack = msi_ack,
+	.irq_mask = msi_mask,
+	.irq_unmask = msi_unmask,
+};
+
+static struct msi_domain_info msi_dom_info = {
+	.flags	= MSI_FLAG_PCI_MSIX
+		| MSI_FLAG_USE_DEF_DOM_OPS
+		| MSI_FLAG_USE_DEF_CHIP_OPS,
+	.chip	= &msi_chip,
+};
+
+static int tango_irq_domain_alloc(struct irq_domain *dom,
+		unsigned int virq, unsigned int nr_irqs, void *args)
+{
+	unsigned long flags;
+	int pos, err = -ENOSPC;
+	struct tango_pcie *pcie = dom->host_data;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	pos = find_first_zero_bit(pcie->used_msi, MSI_MAX);
+	if (pos < MSI_MAX) {
+		err = 0;
+		__set_bit(pos, pcie->used_msi);
+		irq_domain_set_info(dom, virq, pos,
+				&tango_chip, pcie, handle_edge_irq, NULL, NULL);
+	}
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+
+	return err;
+}
+
+static void tango_irq_domain_free(struct irq_domain *dom,
+		unsigned int virq, unsigned int nr_irqs)
+{
+	unsigned long flags;
+	struct irq_data *d = irq_domain_get_irq_data(dom, virq);
+	struct tango_pcie *pcie = d->chip_data;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	__clear_bit(d->hwirq, pcie->used_msi);
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+}
+
+static const struct irq_domain_ops irq_dom_ops = {
+	.alloc	= tango_irq_domain_alloc,
+	.free	= tango_irq_domain_free,
+};
+
+static int tango_msi_remove(struct platform_device *pdev)
+{
+	struct tango_pcie *pcie = platform_get_drvdata(pdev);
+
+	irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+	irq_domain_remove(pcie->msi_dom);
+	irq_domain_remove(pcie->irq_dom);
+
+	return 0;
+}
+
+static int tango_msi_probe(struct platform_device *pdev, struct tango_pcie *pcie)
+{
+	int i, virq;
+	struct irq_domain *msi_dom, *irq_dom;
+	struct fwnode_handle *fwnode = of_node_to_fwnode(pdev->dev.of_node);
+
+	spin_lock_init(&pcie->used_msi_lock);
+	for (i = 0; i < MSI_MAX / 32; ++i)
+		writel_relaxed(0, pcie->msi_enable + i * 4);
+
+	virq = platform_get_irq(pdev, 1);
+	if (virq <= 0) {
+		pr_err("Failed to map IRQ\n");
+		return -ENXIO;
+	}
+
+	irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &irq_dom_ops, pcie);
+	if (!irq_dom) {
+		pr_err("Failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	msi_dom = pci_msi_create_irq_domain(fwnode, &msi_dom_info, irq_dom);
+	if (!msi_dom) {
+		pr_err("Failed to create MSI domain\n");
+		irq_domain_remove(irq_dom);
+		return -ENOMEM;
+	}
+
+	pcie->irq_dom = irq_dom;
+	pcie->msi_dom = msi_dom;
+	pcie->irq = virq;
+
+	irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie);
+
+	return 0;
+}
+
 /*** HOST BRIDGE SUPPORT ***/
 
 static int smp8759_config_read(struct pci_bus *bus,
@@ -88,6 +300,9 @@ static int tango_check_pcie_link(void __iomem *test_out)
 static int smp8759_init(struct tango_pcie *pcie, void __iomem *base)
 {
 	pcie->mux		= base + SMP8759_MUX;
+	pcie->msi_status	= base + SMP8759_STATUS;
+	pcie->msi_enable	= base + SMP8759_ENABLE;
+	pcie->msi_doorbell	= SMP8759_DOORBELL;
 
 	return tango_check_pcie_link(base + SMP8759_TEST_OUT);
 }
@@ -121,11 +336,21 @@ static int tango_pcie_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = tango_msi_probe(pdev, pcie);
+	if (ret)
+		return ret;
+
 	return pci_host_common_probe(pdev, &smp8759_ecam_ops);
 }
 
+static int tango_pcie_remove(struct platform_device *pdev)
+{
+	return tango_msi_remove(pdev);
+}
+
 static struct platform_driver tango_pcie_driver = {
 	.probe	= tango_pcie_probe,
+	.remove	= tango_pcie_remove,
 	.driver	= {
 		.name = KBUILD_MODNAME,
 		.of_match_table = tango_pcie_ids,
-- 
2.11.0

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

* Re: [PATCH v7 3/3] PCI: Add tango MSI controller support
  2017-06-14  9:00             ` [PATCH v7 " Marc Gonzalez
@ 2017-06-14  9:19               ` Marc Gonzalez
  2017-06-14  9:32                 ` Marc Zyngier
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-14  9:19 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, LKML, Mason

On 14/06/2017 11:00, Marc Gonzalez wrote:

> The MSI controller in Tango supports 256 message-signaled interrupts,
> and a single doorbell address.
> 
> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
> ---
> Changes from v6 to v7
> o Call spin_lock() not spin_lock_irqsave() in the ISR
> ---
>  drivers/pci/host/pcie-tango.c | 225 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 225 insertions(+)

Someone on IRC suggested testing the driver with LOCKDEP.

If I understand the warning below correctly, I am not supposed
to call irq_domain_set_info() while holding used_msi_lock?

NB: in probe, my driver calls

	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);

This should not break LOCKDEP analysis, right?

Regards.


[    0.685615] ======================================================
[    0.685621] [ INFO: possible circular locking dependency detected ]
[    0.685632] 4.9.20-1-rc3 #2 Tainted: G          I    
[    0.685638] -------------------------------------------------------
[    0.685644] swapper/0/1 is trying to acquire lock:
[    0.685650]  (&(&pcie->used_msi_lock)->rlock){......}, at: [<c0352e5c>] update_msi_enable+0x2c/0x58

[    0.685692] but task is already holding lock:
[    0.685698]  (&irq_desc_lock_class){......}, at: [<c017586c>] __setup_irq+0xa4/0x5f0

[    0.685718] which lock already depends on the new lock.
[    0.685718] 
[    0.685725] 
[    0.685725] the existing dependency chain (in reverse order) is:
[    0.685731] 
[    0.685731] -> #1 (&irq_desc_lock_class){......}:
[    0.685758]        __irq_get_desc_lock+0x54/0x94
[    0.685768]        __irq_set_handler+0x24/0x54
[    0.685778]        irq_domain_set_info+0x38/0x4c
[    0.685786]        tango_irq_domain_alloc+0x98/0xbc
[    0.685795]        msi_domain_alloc+0x68/0x130
[    0.685802]        __irq_domain_alloc_irqs+0x11c/0x2ac
[    0.685809]        msi_domain_alloc_irqs+0x78/0x188
[    0.685816]        __pci_enable_msi_range+0x200/0x37c
[    0.685824]        pcie_port_device_register+0x3cc/0x494
[    0.685831]        pcie_portdrv_probe+0x2c/0xa4
[    0.685844]        pci_device_probe+0x8c/0xe8
[    0.685852]        driver_probe_device+0x1c8/0x2ac
[    0.685863]        bus_for_each_drv+0x60/0x94
[    0.685870]        __device_attach+0xb4/0x118
[    0.685883]        pci_bus_add_device+0x44/0x90
[    0.685891]        pci_bus_add_devices+0x3c/0x80
[    0.685898]        pci_host_common_probe+0x100/0x314
[    0.685906]        platform_drv_probe+0x50/0xb0
[    0.685912]        driver_probe_device+0x21c/0x2ac
[    0.685918]        __driver_attach+0xc0/0xc4
[    0.685926]        bus_for_each_dev+0x68/0x9c
[    0.685933]        bus_add_driver+0x108/0x214
[    0.685939]        driver_register+0x78/0xf4
[    0.685947]        do_one_initcall+0x44/0x174
[    0.685961]        kernel_init_freeable+0x158/0x1e8
[    0.685971]        kernel_init+0x8/0x10c
[    0.685980]        ret_from_fork+0x14/0x24
[    0.685985] 
[    0.685985] -> #0 (&(&pcie->used_msi_lock)->rlock){......}:
[    0.686003]        _raw_spin_lock_irqsave+0x44/0x58
[    0.686012]        update_msi_enable+0x2c/0x58
[    0.686019]        irq_enable+0x30/0x44
[    0.686025]        irq_startup+0x80/0x84
[    0.686031]        __setup_irq+0x558/0x5f0
[    0.686038]        request_threaded_irq+0xe4/0x184
[    0.686044]        pcie_pme_probe+0xc4/0x1f0
[    0.686051]        pcie_port_probe_service+0x34/0x70
[    0.686057]        driver_probe_device+0x21c/0x2ac
[    0.686065]        bus_for_each_drv+0x60/0x94
[    0.686071]        __device_attach+0xb4/0x118
[    0.686079]        bus_probe_device+0x88/0x90
[    0.686085]        device_add+0x3f4/0x584
[    0.686092]        pcie_port_device_register+0x228/0x494
[    0.686099]        pcie_portdrv_probe+0x2c/0xa4
[    0.686106]        pci_device_probe+0x8c/0xe8
[    0.686113]        driver_probe_device+0x1c8/0x2ac
[    0.686120]        bus_for_each_drv+0x60/0x94
[    0.686126]        __device_attach+0xb4/0x118
[    0.686134]        pci_bus_add_device+0x44/0x90
[    0.686141]        pci_bus_add_devices+0x3c/0x80
[    0.686149]        pci_host_common_probe+0x100/0x314
[    0.686155]        platform_drv_probe+0x50/0xb0
[    0.686161]        driver_probe_device+0x21c/0x2ac
[    0.686167]        __driver_attach+0xc0/0xc4
[    0.686175]        bus_for_each_dev+0x68/0x9c
[    0.686182]        bus_add_driver+0x108/0x214
[    0.686188]        driver_register+0x78/0xf4
[    0.686194]        do_one_initcall+0x44/0x174
[    0.686203]        kernel_init_freeable+0x158/0x1e8
[    0.686210]        kernel_init+0x8/0x10c
[    0.686218]        ret_from_fork+0x14/0x24
[    0.686222] 
[    0.686222] other info that might help us debug this:
[    0.686222] 
[    0.686229]  Possible unsafe locking scenario:
[    0.686229] 
[    0.686235]        CPU0                    CPU1
[    0.686239]        ----                    ----
[    0.686243]   lock(&irq_desc_lock_class);
[    0.686251]                                lock(&(&pcie->used_msi_lock)->rlock);
[    0.686260]                                lock(&irq_desc_lock_class);
[    0.686267]   lock(&(&pcie->used_msi_lock)->rlock);
[    0.686275] 
[    0.686275]  *** DEADLOCK ***
[    0.686275] 
[    0.686283] 5 locks held by swapper/0/1:
[    0.686288]  #0:  (&dev->mutex){......}, at: [<c03939e4>] __driver_attach+0x50/0xc4
[    0.686303]  #1:  (&dev->mutex){......}, at: [<c03939f4>] __driver_attach+0x60/0xc4
[    0.686318]  #2:  (&dev->mutex){......}, at: [<c0393574>] __device_attach+0x20/0x118
[    0.686333]  #3:  (&dev->mutex){......}, at: [<c0393574>] __device_attach+0x20/0x118
[    0.686348]  #4:  (&irq_desc_lock_class){......}, at: [<c017586c>] __setup_irq+0xa4/0x5f0
[    0.686363] 
[    0.686363] stack backtrace:
[    0.686373] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G          I     4.9.20-1-rc3 #2
[    0.686379] Hardware name: Sigma Tango DT
[    0.686398] [<c010f8a0>] (unwind_backtrace) from [<c010b540>] (show_stack+0x10/0x14)
[    0.686411] [<c010b540>] (show_stack) from [<c0309f40>] (dump_stack+0x98/0xc4)
[    0.686423] [<c0309f40>] (dump_stack) from [<c0165ce4>] (print_circular_bug+0x214/0x334)
[    0.686432] [<c0165ce4>] (print_circular_bug) from [<c016934c>] (__lock_acquire+0x171c/0x1a28)
[    0.686441] [<c016934c>] (__lock_acquire) from [<c0169a28>] (lock_acquire+0x6c/0x88)
[    0.686452] [<c0169a28>] (lock_acquire) from [<c0533004>] (_raw_spin_lock_irqsave+0x44/0x58)
[    0.686464] [<c0533004>] (_raw_spin_lock_irqsave) from [<c0352e5c>] (update_msi_enable+0x2c/0x58)
[    0.686475] [<c0352e5c>] (update_msi_enable) from [<c0177614>] (irq_enable+0x30/0x44)
[    0.686484] [<c0177614>] (irq_enable) from [<c01776a8>] (irq_startup+0x80/0x84)
[    0.686493] [<c01776a8>] (irq_startup) from [<c0175d20>] (__setup_irq+0x558/0x5f0)
[    0.686502] [<c0175d20>] (__setup_irq) from [<c0175f60>] (request_threaded_irq+0xe4/0x184)
[    0.686511] [<c0175f60>] (request_threaded_irq) from [<c034fed0>] (pcie_pme_probe+0xc4/0x1f0)
[    0.686520] [<c034fed0>] (pcie_pme_probe) from [<c034d8a8>] (pcie_port_probe_service+0x34/0x70)
[    0.686530] [<c034d8a8>] (pcie_port_probe_service) from [<c0393904>] (driver_probe_device+0x21c/0x2ac)
[    0.686540] [<c0393904>] (driver_probe_device) from [<c0391d18>] (bus_for_each_drv+0x60/0x94)
[    0.686550] [<c0391d18>] (bus_for_each_drv) from [<c0393608>] (__device_attach+0xb4/0x118)
[    0.686560] [<c0393608>] (__device_attach) from [<c0392b14>] (bus_probe_device+0x88/0x90)
[    0.686570] [<c0392b14>] (bus_probe_device) from [<c0390ef0>] (device_add+0x3f4/0x584)
[    0.686580] [<c0390ef0>] (device_add) from [<c034dba4>] (pcie_port_device_register+0x228/0x494)
[    0.686589] [<c034dba4>] (pcie_port_device_register) from [<c034e26c>] (pcie_portdrv_probe+0x2c/0xa4)
[    0.686600] [<c034e26c>] (pcie_portdrv_probe) from [<c0341ff0>] (pci_device_probe+0x8c/0xe8)
[    0.686611] [<c0341ff0>] (pci_device_probe) from [<c03938b0>] (driver_probe_device+0x1c8/0x2ac)
[    0.686620] [<c03938b0>] (driver_probe_device) from [<c0391d18>] (bus_for_each_drv+0x60/0x94)
[    0.686630] [<c0391d18>] (bus_for_each_drv) from [<c0393608>] (__device_attach+0xb4/0x118)
[    0.686641] [<c0393608>] (__device_attach) from [<c03381fc>] (pci_bus_add_device+0x44/0x90)
[    0.686651] [<c03381fc>] (pci_bus_add_device) from [<c0338284>] (pci_bus_add_devices+0x3c/0x80)
[    0.686662] [<c0338284>] (pci_bus_add_devices) from [<c0352bf4>] (pci_host_common_probe+0x100/0x314)
[    0.686673] [<c0352bf4>] (pci_host_common_probe) from [<c03950dc>] (platform_drv_probe+0x50/0xb0)
[    0.686682] [<c03950dc>] (platform_drv_probe) from [<c0393904>] (driver_probe_device+0x21c/0x2ac)
[    0.686690] [<c0393904>] (driver_probe_device) from [<c0393a54>] (__driver_attach+0xc0/0xc4)
[    0.686700] [<c0393a54>] (__driver_attach) from [<c0391c70>] (bus_for_each_dev+0x68/0x9c)
[    0.686711] [<c0391c70>] (bus_for_each_dev) from [<c0392d2c>] (bus_add_driver+0x108/0x214)
[    0.686721] [<c0392d2c>] (bus_add_driver) from [<c0394170>] (driver_register+0x78/0xf4)
[    0.686730] [<c0394170>] (driver_register) from [<c01017dc>] (do_one_initcall+0x44/0x174)
[    0.686742] [<c01017dc>] (do_one_initcall) from [<c0800dc0>] (kernel_init_freeable+0x158/0x1e8)
[    0.686754] [<c0800dc0>] (kernel_init_freeable) from [<c052c918>] (kernel_init+0x8/0x10c)
[    0.686765] [<c052c918>] (kernel_init) from [<c01077d0>] (ret_from_fork+0x14/0x24)

[    0.686824] pcieport 0000:00:00.0: Signaling PME through PCIe PME interrupt
[    0.686835] pci 0000:01:00.0: Signaling PME through PCIe PME interrupt
[    0.686849] pcie_pme 0000:00:00.0:pcie001: service driver pcie_pme loaded
[    0.687049] aer 0000:00:00.0:pcie002: service driver aer loaded
[    0.687276] pci 0000:01:00.0: enabling device (0140 -> 0142)

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

* Re: [PATCH v7 3/3] PCI: Add tango MSI controller support
  2017-06-14  9:19               ` Marc Gonzalez
@ 2017-06-14  9:32                 ` Marc Zyngier
  2017-06-14 11:06                   ` [PATCH v8 " Marc Gonzalez
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Zyngier @ 2017-06-14  9:32 UTC (permalink / raw)
  To: Marc Gonzalez, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, LKML, Mason

On 14/06/17 10:19, Marc Gonzalez wrote:
> On 14/06/2017 11:00, Marc Gonzalez wrote:
> 
>> The MSI controller in Tango supports 256 message-signaled interrupts,
>> and a single doorbell address.
>>
>> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
>> ---
>> Changes from v6 to v7
>> o Call spin_lock() not spin_lock_irqsave() in the ISR
>> ---
>>  drivers/pci/host/pcie-tango.c | 225 ++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 225 insertions(+)
> 
> Someone on IRC suggested testing the driver with LOCKDEP.
> 
> If I understand the warning below correctly, I am not supposed
> to call irq_domain_set_info() while holding used_msi_lock?

Indeed. This creates an AB/BA situation, which will eventually deadlock.
Once again, lockdep saves the day.

> NB: in probe, my driver calls
> 
> 	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
> 
> This should not break LOCKDEP analysis, right?

It doesn't. The code is provably wrong, and lockdep proved that it is wrong.

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

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

* [PATCH v8 3/3] PCI: Add tango MSI controller support
  2017-06-14  9:32                 ` Marc Zyngier
@ 2017-06-14 11:06                   ` Marc Gonzalez
  0 siblings, 0 replies; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-14 11:06 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner
  Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, LKML, Mason

The MSI controller in Tango supports 256 message-signaled interrupts,
and a single doorbell address.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
---
Changes from v7 to v8
o Reorganize tango_irq_domain_alloc() so as not to call irq_domain_set_info()
  with pcie->used_msi_lock held => Bug diagnosed by LOCKDEP
---
 drivers/pci/host/pcie-tango.c | 226 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 226 insertions(+)

diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
index 67aaadcc1c5e..5c47a4cc03e3 100644
--- a/drivers/pci/host/pcie-tango.c
+++ b/drivers/pci/host/pcie-tango.c
@@ -1,16 +1,229 @@
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
 #include <linux/pci-ecam.h>
 #include <linux/delay.h>
+#include <linux/msi.h>
 #include <linux/of.h>
 
 #define MSI_MAX 256
 
 #define SMP8759_MUX		0x48
 #define SMP8759_TEST_OUT	0x74
+#define SMP8759_STATUS		0x80
+#define SMP8759_ENABLE		0xa0
+#define SMP8759_DOORBELL	0xa002e07c
 
 struct tango_pcie {
+	DECLARE_BITMAP(used_msi, MSI_MAX);
+	spinlock_t used_msi_lock;
 	void __iomem *mux;
+	void __iomem *msi_status;
+	void __iomem *msi_enable;
+	phys_addr_t msi_doorbell;
+	struct irq_domain *irq_dom;
+	struct irq_domain *msi_dom;
+	int irq;
 };
 
+/*** MSI CONTROLLER SUPPORT ***/
+
+static void tango_msi_isr(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct tango_pcie *pcie = irq_desc_get_handler_data(desc);
+	unsigned long status, base, virq, idx, pos = 0;
+
+	chained_irq_enter(chip, desc);
+	spin_lock(&pcie->used_msi_lock);
+
+	while ((pos = find_next_bit(pcie->used_msi, MSI_MAX, pos)) < MSI_MAX) {
+		base = round_down(pos, 32);
+		status = readl_relaxed(pcie->msi_status + base / 8);
+		for_each_set_bit(idx, &status, 32) {
+			virq = irq_find_mapping(pcie->irq_dom, base + idx);
+			generic_handle_irq(virq);
+		}
+		pos = base + 32;
+	}
+
+	spin_unlock(&pcie->used_msi_lock);
+	chained_irq_exit(chip, desc);
+}
+
+static void tango_ack(struct irq_data *d)
+{
+	struct tango_pcie *pcie = d->chip_data;
+	u32 offset = (d->hwirq / 32) * 4;
+	u32 bit = BIT(d->hwirq % 32);
+
+	writel_relaxed(bit, pcie->msi_status + offset);
+}
+
+static void update_msi_enable(struct irq_data *d, bool unmask)
+{
+	unsigned long flags;
+	struct tango_pcie *pcie = d->chip_data;
+	u32 offset = (d->hwirq / 32) * 4;
+	u32 bit = BIT(d->hwirq % 32);
+	u32 val;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	val = readl_relaxed(pcie->msi_enable + offset);
+	val = unmask ? val | bit : val & ~bit;
+	writel_relaxed(val, pcie->msi_enable + offset);
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+}
+
+static void tango_mask(struct irq_data *d)
+{
+	update_msi_enable(d, false);
+}
+
+static void tango_unmask(struct irq_data *d)
+{
+	update_msi_enable(d, true);
+}
+
+static int tango_set_affinity(struct irq_data *d,
+		const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+
+static void tango_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	struct tango_pcie *pcie = d->chip_data;
+	msg->address_lo = lower_32_bits(pcie->msi_doorbell);
+	msg->address_hi = upper_32_bits(pcie->msi_doorbell);
+	msg->data = d->hwirq;
+}
+
+static struct irq_chip tango_chip = {
+	.irq_ack		= tango_ack,
+	.irq_mask		= tango_mask,
+	.irq_unmask		= tango_unmask,
+	.irq_set_affinity	= tango_set_affinity,
+	.irq_compose_msi_msg	= tango_compose_msi_msg,
+};
+
+static void msi_ack(struct irq_data *d)
+{
+	irq_chip_ack_parent(d);
+}
+
+static void msi_mask(struct irq_data *d)
+{
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void msi_unmask(struct irq_data *d)
+{
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip msi_chip = {
+	.name = "MSI",
+	.irq_ack = msi_ack,
+	.irq_mask = msi_mask,
+	.irq_unmask = msi_unmask,
+};
+
+static struct msi_domain_info msi_dom_info = {
+	.flags	= MSI_FLAG_PCI_MSIX
+		| MSI_FLAG_USE_DEF_DOM_OPS
+		| MSI_FLAG_USE_DEF_CHIP_OPS,
+	.chip	= &msi_chip,
+};
+
+static int tango_irq_domain_alloc(struct irq_domain *dom,
+		unsigned int virq, unsigned int nr_irqs, void *args)
+{
+	int pos;
+	unsigned long flags;
+	struct tango_pcie *pcie = dom->host_data;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	pos = find_first_zero_bit(pcie->used_msi, MSI_MAX);
+	if (pos >= MSI_MAX) {
+		spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+		return -ENOSPC;
+	}
+	__set_bit(pos, pcie->used_msi);
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+	irq_domain_set_info(dom, virq, pos, &tango_chip,
+			pcie, handle_edge_irq, NULL, NULL);
+
+	return 0;
+}
+
+static void tango_irq_domain_free(struct irq_domain *dom,
+		unsigned int virq, unsigned int nr_irqs)
+{
+	unsigned long flags;
+	struct irq_data *d = irq_domain_get_irq_data(dom, virq);
+	struct tango_pcie *pcie = d->chip_data;
+
+	spin_lock_irqsave(&pcie->used_msi_lock, flags);
+	__clear_bit(d->hwirq, pcie->used_msi);
+	spin_unlock_irqrestore(&pcie->used_msi_lock, flags);
+}
+
+static const struct irq_domain_ops irq_dom_ops = {
+	.alloc	= tango_irq_domain_alloc,
+	.free	= tango_irq_domain_free,
+};
+
+static int tango_msi_remove(struct platform_device *pdev)
+{
+	struct tango_pcie *pcie = platform_get_drvdata(pdev);
+
+	irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+	irq_domain_remove(pcie->msi_dom);
+	irq_domain_remove(pcie->irq_dom);
+
+	return 0;
+}
+
+static int tango_msi_probe(struct platform_device *pdev, struct tango_pcie *pcie)
+{
+	int i, virq;
+	struct irq_domain *msi_dom, *irq_dom;
+	struct fwnode_handle *fwnode = of_node_to_fwnode(pdev->dev.of_node);
+
+	spin_lock_init(&pcie->used_msi_lock);
+	for (i = 0; i < MSI_MAX / 32; ++i)
+		writel_relaxed(0, pcie->msi_enable + i * 4);
+
+	virq = platform_get_irq(pdev, 1);
+	if (virq <= 0) {
+		pr_err("Failed to map IRQ\n");
+		return -ENXIO;
+	}
+
+	irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &irq_dom_ops, pcie);
+	if (!irq_dom) {
+		pr_err("Failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	msi_dom = pci_msi_create_irq_domain(fwnode, &msi_dom_info, irq_dom);
+	if (!msi_dom) {
+		pr_err("Failed to create MSI domain\n");
+		irq_domain_remove(irq_dom);
+		return -ENOMEM;
+	}
+
+	pcie->irq_dom = irq_dom;
+	pcie->msi_dom = msi_dom;
+	pcie->irq = virq;
+
+	irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie);
+
+	return 0;
+}
+
 /*** HOST BRIDGE SUPPORT ***/
 
 static int smp8759_config_read(struct pci_bus *bus,
@@ -88,6 +301,9 @@ static int tango_check_pcie_link(void __iomem *test_out)
 static int smp8759_init(struct tango_pcie *pcie, void __iomem *base)
 {
 	pcie->mux		= base + SMP8759_MUX;
+	pcie->msi_status	= base + SMP8759_STATUS;
+	pcie->msi_enable	= base + SMP8759_ENABLE;
+	pcie->msi_doorbell	= SMP8759_DOORBELL;
 
 	return tango_check_pcie_link(base + SMP8759_TEST_OUT);
 }
@@ -121,11 +337,21 @@ static int tango_pcie_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = tango_msi_probe(pdev, pcie);
+	if (ret)
+		return ret;
+
 	return pci_host_common_probe(pdev, &smp8759_ecam_ops);
 }
 
+static int tango_pcie_remove(struct platform_device *pdev)
+{
+	return tango_msi_remove(pdev);
+}
+
 static struct platform_driver tango_pcie_driver = {
 	.probe	= tango_pcie_probe,
+	.remove	= tango_pcie_remove,
 	.driver	= {
 		.name = KBUILD_MODNAME,
 		.of_match_table = tango_pcie_ids,
-- 
2.11.0

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

* Re: [PATCH v6 1/3] PCI: Add DT binding for tango PCIe controller
  2017-06-13 13:51     ` [PATCH v6 " Marc Gonzalez
@ 2017-06-18 14:05       ` Rob Herring
  0 siblings, 0 replies; 27+ messages in thread
From: Rob Herring @ 2017-06-18 14:05 UTC (permalink / raw)
  To: Marc Gonzalez
  Cc: Bjorn Helgaas, Marc Zyngier, Thomas Gleixner, Robin Murphy,
	Lorenzo Pieralisi, Liviu Dudau, David Laight, linux-pci,
	Linux ARM, LKML, DT, Mason

On Tue, Jun 13, 2017 at 03:51:32PM +0200, Marc Gonzalez wrote:
> Binding for the Sigma Designs SMP8759 SoC.
> 
> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
> ---
> Changes from v5 to v6
> o Delete links to elinux.org
> o Use explicit hex numbers instead of symbolic constants for sizes (in the example)
> o Add bus-range to "Required properties"
> ---
>  .../devicetree/bindings/pci/tango-pcie.txt         | 29 ++++++++++++++++++++++
>  1 file changed, 29 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/tango-pcie.txt

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-06-07  8:19   ` Marc Gonzalez
@ 2017-06-19 14:50     ` Marc Gonzalez
  2017-06-19 15:58       ` Marc Zyngier
  2017-06-20  8:29       ` Marc Gonzalez
  0 siblings, 2 replies; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-19 14:50 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Marc Zyngier, Thomas Gleixner, Robin Murphy, Lorenzo Pieralisi,
	Liviu Dudau, David Laight, linux-pci, Linux ARM, Thibaud Cornic,
	LKML, Mason

On 07/06/2017 10:19, Marc Gonzalez wrote:

> On 31/05/2017 15:33, Marc Gonzalez wrote:
> 
>> +static int tango_pcie_probe(struct platform_device *pdev)
>> +{
>> +	int ret = -EINVAL;
>> +	void __iomem *base;
>> +	struct resource *res;
>> +	struct tango_pcie *pcie;
>> +	struct device *dev = &pdev->dev;
>> +
>> +	pr_err("MAJOR ISSUE: PCIe config and mem spaces are muxed\n");
>> +	pr_err("Tainting kernel... Use driver at your own risk\n");
>> +	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
> 
> Hello Bjorn,
> 
> In v4, your only comment was
> "[muxing config and mem spaces] is a major issue and possibly even
> a security problem [which requires at least an error message and a
> kernel taint].
> 
> Were there any other issues with the host bridge support?

Hello Bjorn,

I imagine you are now only waiting for Marc Z's Ack of patch 3/3 ?
(AFAIU, all issues have been addressed as of v8 3/3.)

Rob has Acked patch 1/3 -- thanks Rob.

Assuming all issues with patch 2/3 have already been addressed,
then this driver can land in time for 4.13 right?

Regards.

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

* Re: [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-06-19 14:50     ` Marc Gonzalez
@ 2017-06-19 15:58       ` Marc Zyngier
  2017-06-19 16:01         ` Marc Gonzalez
  2017-06-20  8:29       ` Marc Gonzalez
  1 sibling, 1 reply; 27+ messages in thread
From: Marc Zyngier @ 2017-06-19 15:58 UTC (permalink / raw)
  To: Marc Gonzalez, Bjorn Helgaas
  Cc: Thomas Gleixner, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, Thibaud Cornic, LKML, Mason

On 19/06/17 15:50, Marc Gonzalez wrote:
> On 07/06/2017 10:19, Marc Gonzalez wrote:
> 
>> On 31/05/2017 15:33, Marc Gonzalez wrote:
>>
>>> +static int tango_pcie_probe(struct platform_device *pdev)
>>> +{
>>> +	int ret = -EINVAL;
>>> +	void __iomem *base;
>>> +	struct resource *res;
>>> +	struct tango_pcie *pcie;
>>> +	struct device *dev = &pdev->dev;
>>> +
>>> +	pr_err("MAJOR ISSUE: PCIe config and mem spaces are muxed\n");
>>> +	pr_err("Tainting kernel... Use driver at your own risk\n");
>>> +	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
>>
>> Hello Bjorn,
>>
>> In v4, your only comment was
>> "[muxing config and mem spaces] is a major issue and possibly even
>> a security problem [which requires at least an error message and a
>> kernel taint].
>>
>> Were there any other issues with the host bridge support?
> 
> Hello Bjorn,
> 
> I imagine you are now only waiting for Marc Z's Ack of patch 3/3 ?
> (AFAIU, all issues have been addressed as of v8 3/3.)

Posting partial series is really not ideal, specially as you posted 3 of
them in less than 24 hours (and the latest was only 5 days ago).

The maintainer is not going to chase you about potentially missing
patches...

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

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

* Re: [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-06-19 15:58       ` Marc Zyngier
@ 2017-06-19 16:01         ` Marc Gonzalez
  2017-06-19 16:16           ` Marc Zyngier
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-19 16:01 UTC (permalink / raw)
  To: Marc Zyngier, Bjorn Helgaas
  Cc: Thomas Gleixner, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, Thibaud Cornic, LKML, Mason

On 19/06/2017 17:58, Marc Zyngier wrote:
> On 19/06/17 15:50, Marc Gonzalez wrote:
>> On 07/06/2017 10:19, Marc Gonzalez wrote:
>>
>>> On 31/05/2017 15:33, Marc Gonzalez wrote:
>>>
>>>> +static int tango_pcie_probe(struct platform_device *pdev)
>>>> +{
>>>> +	int ret = -EINVAL;
>>>> +	void __iomem *base;
>>>> +	struct resource *res;
>>>> +	struct tango_pcie *pcie;
>>>> +	struct device *dev = &pdev->dev;
>>>> +
>>>> +	pr_err("MAJOR ISSUE: PCIe config and mem spaces are muxed\n");
>>>> +	pr_err("Tainting kernel... Use driver at your own risk\n");
>>>> +	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
>>>
>>> Hello Bjorn,
>>>
>>> In v4, your only comment was
>>> "[muxing config and mem spaces] is a major issue and possibly even
>>> a security problem [which requires at least an error message and a
>>> kernel taint].
>>>
>>> Were there any other issues with the host bridge support?
>>
>> Hello Bjorn,
>>
>> I imagine you are now only waiting for Marc Z's Ack of patch 3/3 ?
>> (AFAIU, all issues have been addressed as of v8 3/3.)
> 
> Posting partial series is really not ideal, specially as you posted 3 of
> them in less than 24 hours (and the latest was only 5 days ago).
> 
> The maintainer is not going to chase you about potentially missing
> patches...

So the best course would be posting a new series with all patches
bumped to v8 then?

Regards.

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

* Re: [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-06-19 16:01         ` Marc Gonzalez
@ 2017-06-19 16:16           ` Marc Zyngier
  0 siblings, 0 replies; 27+ messages in thread
From: Marc Zyngier @ 2017-06-19 16:16 UTC (permalink / raw)
  To: Marc Gonzalez, Bjorn Helgaas
  Cc: Thomas Gleixner, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, Thibaud Cornic, LKML, Mason

On 19/06/17 17:01, Marc Gonzalez wrote:
> On 19/06/2017 17:58, Marc Zyngier wrote:
>> On 19/06/17 15:50, Marc Gonzalez wrote:
>>> On 07/06/2017 10:19, Marc Gonzalez wrote:
>>>
>>>> On 31/05/2017 15:33, Marc Gonzalez wrote:
>>>>
>>>>> +static int tango_pcie_probe(struct platform_device *pdev)
>>>>> +{
>>>>> +	int ret = -EINVAL;
>>>>> +	void __iomem *base;
>>>>> +	struct resource *res;
>>>>> +	struct tango_pcie *pcie;
>>>>> +	struct device *dev = &pdev->dev;
>>>>> +
>>>>> +	pr_err("MAJOR ISSUE: PCIe config and mem spaces are muxed\n");
>>>>> +	pr_err("Tainting kernel... Use driver at your own risk\n");
>>>>> +	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
>>>>
>>>> Hello Bjorn,
>>>>
>>>> In v4, your only comment was
>>>> "[muxing config and mem spaces] is a major issue and possibly even
>>>> a security problem [which requires at least an error message and a
>>>> kernel taint].
>>>>
>>>> Were there any other issues with the host bridge support?
>>>
>>> Hello Bjorn,
>>>
>>> I imagine you are now only waiting for Marc Z's Ack of patch 3/3 ?
>>> (AFAIU, all issues have been addressed as of v8 3/3.)
>>
>> Posting partial series is really not ideal, specially as you posted 3 of
>> them in less than 24 hours (and the latest was only 5 days ago).
>>
>> The maintainer is not going to chase you about potentially missing
>> patches...
> 
> So the best course would be posting a new series with all patches
> bumped to v8 then?

No, because there is still the ambiguity of *which* v8 that is. Post a
v9 that supersedes all the previously posted patches.

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

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

* Re: [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-06-19 14:50     ` Marc Gonzalez
  2017-06-19 15:58       ` Marc Zyngier
@ 2017-06-20  8:29       ` Marc Gonzalez
  1 sibling, 0 replies; 27+ messages in thread
From: Marc Gonzalez @ 2017-06-20  8:29 UTC (permalink / raw)
  To: Bjorn Helgaas, Marc Zyngier
  Cc: Thomas Gleixner, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
	David Laight, linux-pci, Linux ARM, Thibaud Cornic, LKML, Mason

On 19/06/2017 16:50, Marc Gonzalez wrote:

> On 07/06/2017 10:19, Marc Gonzalez wrote:
> 
>> On 31/05/2017 15:33, Marc Gonzalez wrote:
>>
>>> +static int tango_pcie_probe(struct platform_device *pdev)
>>> +{
>>> +	int ret = -EINVAL;
>>> +	void __iomem *base;
>>> +	struct resource *res;
>>> +	struct tango_pcie *pcie;
>>> +	struct device *dev = &pdev->dev;
>>> +
>>> +	pr_err("MAJOR ISSUE: PCIe config and mem spaces are muxed\n");
>>> +	pr_err("Tainting kernel... Use driver at your own risk\n");
>>> +	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
>>
>> Hello Bjorn,
>>
>> In v4, your only comment was
>> "[muxing config and mem spaces] is a major issue and possibly even
>> a security problem [which requires at least an error message and a
>> kernel taint].
>>
>> Were there any other issues with the host bridge support?
> 
> Hello Bjorn,
> 
> I imagine you are now only waiting for Marc Z's Ack of patch 3/3 ?
> (AFAIU, all issues have been addressed as of v8 3/3.)
> 
> Rob has Acked patch 1/3 -- thanks Rob.
> 
> Assuming all issues with patch 2/3 have already been addressed,
> then this driver can land in time for 4.13 right?

Hello Bjorn, Marc,

Patch series v9 supersedes all previously posted patches.

Regards.

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

* Re: [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-05-31 13:33 ` [PATCH v5 2/3] PCI: Add tango PCIe host bridge support Marc Gonzalez
  2017-06-07  8:19   ` Marc Gonzalez
@ 2017-07-05  9:36   ` Ard Biesheuvel
  2017-07-05 12:18     ` Marc Gonzalez
  1 sibling, 1 reply; 27+ messages in thread
From: Ard Biesheuvel @ 2017-07-05  9:36 UTC (permalink / raw)
  To: Marc Gonzalez
  Cc: Bjorn Helgaas, Lorenzo Pieralisi, Mason, Marc Zyngier, linux-pci,
	Thibaud Cornic, Liviu Dudau, LKML, David Laight, Thomas Gleixner,
	Phuong Nguyen, Robin Murphy, Linux ARM

On 31 May 2017 at 13:33, Marc Gonzalez <marc_gonzalez@sigmadesigns.com> wrote:
> This driver is required to work around several hardware bugs
> in the PCIe controller.
>
> NB: Revision 1 does not support legacy interrupts, or IO space.
>
> Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
> ---
>  drivers/pci/host/Kconfig      |   8 +++
>  drivers/pci/host/Makefile     |   1 +
>  drivers/pci/host/pcie-tango.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci_ids.h       |   2 +
>  4 files changed, 175 insertions(+)
>
[...]
> diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/host/pcie-tango.c
> new file mode 100644
> index 000000000000..67aaadcc1c5e
> --- /dev/null
> +++ b/drivers/pci/host/pcie-tango.c
> @@ -0,0 +1,164 @@
> +#include <linux/pci-ecam.h>
> +#include <linux/delay.h>
> +#include <linux/of.h>
> +
> +#define MSI_MAX 256
> +
> +#define SMP8759_MUX            0x48
> +#define SMP8759_TEST_OUT       0x74
> +
> +struct tango_pcie {
> +       void __iomem *mux;
> +};
> +
> +/*** HOST BRIDGE SUPPORT ***/
> +
> +static int smp8759_config_read(struct pci_bus *bus,
> +               unsigned int devfn, int where, int size, u32 *val)
> +{
> +       int ret;
> +       struct pci_config_window *cfg = bus->sysdata;
> +       struct tango_pcie *pcie = dev_get_drvdata(cfg->parent);
> +
> +       /*
> +        * QUIRK #1
> +        * Reads in configuration space outside devfn 0 return garbage.
> +        */
> +       if (devfn != 0)
> +               return PCIBIOS_FUNC_NOT_SUPPORTED;
> +

Does this mean multi-function devices are not supported? E.g., on my
system I have

-[0000:00]-+-00.0  Advanced Micro Devices, Inc. [AMD] Device 1a00
           +-02.0  Advanced Micro Devices, Inc. [AMD] Device 1a01
           +-02.1-[01]----00.0  Renesas Technology Corp. uPD720201 USB 3.0
           \-02.2-[02]--+-00.0  NVIDIA Corporation GT218 [GeForce 210]
                        \-00.1  NVIDIA Corporation HD Audio Controller

where the HDMI audio is on devfn 00.1 on bus 2


> +       /*
> +        * QUIRK #2
> +        * Unfortunately, config and mem spaces are muxed.
> +        * Linux does not support such a setting, since drivers are free
> +        * to access mem space directly, at any time.
> +        * Therefore, we can only PRAY that config and mem space accesses
> +        * NEVER occur concurrently.
> +        */
> +       writel_relaxed(1, pcie->mux);
> +       ret = pci_generic_config_read(bus, devfn, where, size, val);
> +       writel_relaxed(0, pcie->mux);
> +
> +       return ret;
> +}
> +
> +static int smp8759_config_write(struct pci_bus *bus,
> +               unsigned int devfn, int where, int size, u32 val)
> +{
> +       int ret;
> +       struct pci_config_window *cfg = bus->sysdata;
> +       struct tango_pcie *pcie = dev_get_drvdata(cfg->parent);
> +
> +       writel_relaxed(1, pcie->mux);
> +       ret = pci_generic_config_write(bus, devfn, where, size, val);
> +       writel_relaxed(0, pcie->mux);
> +
> +       return ret;
> +}
> +
> +static struct pci_ecam_ops smp8759_ecam_ops = {
> +       .bus_shift      = 20,
> +       .pci_ops        = {
> +               .map_bus        = pci_ecam_map_bus,
> +               .read           = smp8759_config_read,
> +               .write          = smp8759_config_write,
> +       }
> +};
> +
> +static const struct of_device_id tango_pcie_ids[] = {
> +       { .compatible = "sigma,smp8759-pcie" },
> +       { /* sentinel */ },
> +};
> +
> +static int tango_check_pcie_link(void __iomem *test_out)
> +{
> +       int i;
> +
> +       writel_relaxed(16, test_out);
> +       for (i = 0; i < 10; ++i) {
> +               u32 ltssm_state = readl_relaxed(test_out) >> 8;
> +               if ((ltssm_state & 0x1f) == 0xf) /* L0 */
> +                       return 0;
> +               usleep_range(3000, 4000);
> +       }
> +
> +       return -ENODEV;
> +}
> +
> +static int smp8759_init(struct tango_pcie *pcie, void __iomem *base)
> +{
> +       pcie->mux               = base + SMP8759_MUX;
> +
> +       return tango_check_pcie_link(base + SMP8759_TEST_OUT);
> +}
> +
> +static int tango_pcie_probe(struct platform_device *pdev)
> +{
> +       int ret = -EINVAL;
> +       void __iomem *base;
> +       struct resource *res;
> +       struct tango_pcie *pcie;
> +       struct device *dev = &pdev->dev;
> +
> +       pr_err("MAJOR ISSUE: PCIe config and mem spaces are muxed\n");
> +       pr_err("Tainting kernel... Use driver at your own risk\n");
> +       add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
> +
> +       pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
> +       if (!pcie)
> +               return -ENOMEM;
> +
> +       platform_set_drvdata(pdev, pcie);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +       base = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(base))
> +               return PTR_ERR(base);
> +
> +       if (of_device_is_compatible(dev->of_node, "sigma,smp8759-pcie"))
> +               ret = smp8759_init(pcie, base);
> +
> +       if (ret)
> +               return ret;
> +
> +       return pci_host_common_probe(pdev, &smp8759_ecam_ops);
> +}
> +
> +static struct platform_driver tango_pcie_driver = {
> +       .probe  = tango_pcie_probe,
> +       .driver = {
> +               .name = KBUILD_MODNAME,
> +               .of_match_table = tango_pcie_ids,
> +       },
> +};
> +
> +builtin_platform_driver(tango_pcie_driver);
> +
> +/*
> + * QUIRK #3
> + * The root complex advertizes the wrong device class.
> + * Header Type 1 is for PCI-to-PCI bridges.
> + */
> +static void tango_fixup_class(struct pci_dev *dev)
> +{
> +       dev->class = PCI_CLASS_BRIDGE_PCI << 8;
> +}
> +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x24, tango_fixup_class);
> +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x28, tango_fixup_class);
> +
> +/*
> + * QUIRK #4
> + * The root complex exposes a "fake" BAR, which is used to filter
> + * bus-to-system accesses. Only accesses within the range defined
> + * by this BAR are forwarded to the host, others are ignored.
> + *
> + * By default, the DMA framework expects an identity mapping,
> + * and DRAM0 is mapped at 0x80000000.
> + */
> +static void tango_fixup_bar(struct pci_dev *dev)
> +{
> +       dev->non_compliant_bars = true;
> +       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x80000000);
> +}
> +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x24, tango_fixup_bar);
> +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x28, tango_fixup_bar);
> diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> index f020ab4079d3..b577dbe46f8f 100644
> --- a/include/linux/pci_ids.h
> +++ b/include/linux/pci_ids.h
> @@ -1369,6 +1369,8 @@
>  #define PCI_DEVICE_ID_TTI_HPT374       0x0008
>  #define PCI_DEVICE_ID_TTI_HPT372N      0x0009  /* apparently a 372N variant? */
>
> +#define PCI_VENDOR_ID_SIGMA            0x1105
> +
>  #define PCI_VENDOR_ID_VIA              0x1106
>  #define PCI_DEVICE_ID_VIA_8763_0       0x0198
>  #define PCI_DEVICE_ID_VIA_8380_0       0x0204
> --
> 2.11.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 2/3] PCI: Add tango PCIe host bridge support
  2017-07-05  9:36   ` Ard Biesheuvel
@ 2017-07-05 12:18     ` Marc Gonzalez
  0 siblings, 0 replies; 27+ messages in thread
From: Marc Gonzalez @ 2017-07-05 12:18 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Bjorn Helgaas, Lorenzo Pieralisi, Mason, Marc Zyngier, linux-pci,
	Thibaud Cornic, Liviu Dudau, LKML, David Laight, Thomas Gleixner,
	Phuong Nguyen, Robin Murphy, Linux ARM

On 05/07/2017 11:36, Ard Biesheuvel wrote:

> On 31 May 2017 at 13:33, Marc Gonzalez wrote:
>
>> This driver is required to work around several hardware bugs
>> in the PCIe controller.
>>
>> NB: Revision 1 does not support legacy interrupts, or IO space.
>>
>> +       /*
>> +        * QUIRK #1
>> +        * Reads in configuration space outside devfn 0 return garbage.
>> +        */
>> +       if (devfn != 0)
>> +               return PCIBIOS_FUNC_NOT_SUPPORTED;
>> +
> 
> Does this mean multi-function devices are not supported? E.g., on my
> system I have
> 
> -[0000:00]-+-00.0  Advanced Micro Devices, Inc. [AMD] Device 1a00
>            +-02.0  Advanced Micro Devices, Inc. [AMD] Device 1a01
>            +-02.1-[01]----00.0  Renesas Technology Corp. uPD720201 USB 3.0
>            \-02.2-[02]--+-00.0  NVIDIA Corporation GT218 [GeForce 210]
>                         \-00.1  NVIDIA Corporation HD Audio Controller
> 
> where the HDMI audio is on devfn 00.1 on bus 2

Thanks for having a look. Here's the situation.

# lspci -v
00:00.0 PCI bridge: Sigma Designs, Inc. Device 0024 (rev 01) (prog-if 00 [Normal decode])
        Flags: bus master, fast devsel, latency 0, IRQ 31
        Memory at <ignored> (64-bit, non-prefetchable)
        Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
        I/O behind bridge: 00000000-00000fff
        Memory behind bridge: 00400000-004fffff
        Prefetchable memory behind bridge: 00000000-000fffff
        Capabilities: [50] MSI: Enable+ Count=1/4 Maskable- 64bit+
        Capabilities: [78] Power Management version 3
        Capabilities: [80] Express Root Port (Slot-), MSI 03
        Capabilities: [100] Virtual Channel
        Capabilities: [800] Advanced Error Reporting
        Kernel driver in use: pcieport

01:00.0 USB controller: Renesas Technology Corp. uPD720201 USB 3.0 Host Controller (rev 03) (prog-if 30 [XHCI])
        Flags: bus master, fast devsel, latency 0, IRQ 21
        Memory at 50400000 (64-bit, non-prefetchable) [size=8K]
        Capabilities: [50] Power Management version 3
        Capabilities: [70] MSI: Enable- Count=1/8 Maskable- 64bit+
        Capabilities: [90] MSI-X: Enable+ Count=8 Masked-
        Capabilities: [a0] Express Endpoint, MSI 00
        Capabilities: [100] Advanced Error Reporting
        Capabilities: [150] Latency Tolerance Reporting
        Kernel driver in use: xhci_hcd


IIUC, bus 0 will always be the PCIe host bridge.
On bus 0, reads outside of devfn 0 return garbage.
I think (?) this is not an issue, because the host bridge
is not multi-function.

There is a /separate/ erratum for bus 1. The HW returns
garbage when enumerating non-existent devfn.
IIUC, there is an OOB SoC-specific error-reporting mechanism,
so it might be possible to check for an error after every read,
and replace the garbage with -1u on error.

The errata list does not mention buses > 1 but I would assume
they are, at a minimum, affected by the "bus 1" errata --
such setups were not tested at all. (It would require some
kind of PCIe switch, I suppose.)

As a first-order approximation, I just conflated the two
errata, and ignored multi-function EPs.

NB: the "typical" use-case for the PCIe slot is adding a validated
WiFi card, because the SoC doesn't support WiFi natively.
Some customers also consider using a USB3 card, instead of the
native USB2 Chipidea controller.

Regards.

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

end of thread, other threads:[~2017-07-05 12:18 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-31 13:28 [PATCH v5 0/3] Tango PCIe controller support Marc Gonzalez
2017-05-31 13:30 ` [PATCH v5 1/3] PCI: Add DT binding for tango PCIe controller Marc Gonzalez
2017-06-07 21:29   ` Rob Herring
2017-06-07 22:34     ` Mason
2017-06-13 11:55       ` Marc Zyngier
2017-06-13 14:23       ` Rob Herring
2017-06-13 13:51     ` [PATCH v6 " Marc Gonzalez
2017-06-18 14:05       ` Rob Herring
2017-05-31 13:33 ` [PATCH v5 2/3] PCI: Add tango PCIe host bridge support Marc Gonzalez
2017-06-07  8:19   ` Marc Gonzalez
2017-06-19 14:50     ` Marc Gonzalez
2017-06-19 15:58       ` Marc Zyngier
2017-06-19 16:01         ` Marc Gonzalez
2017-06-19 16:16           ` Marc Zyngier
2017-06-20  8:29       ` Marc Gonzalez
2017-07-05  9:36   ` Ard Biesheuvel
2017-07-05 12:18     ` Marc Gonzalez
2017-05-31 13:35 ` [PATCH v5 3/3] PCI: Add tango MSI controller support Marc Gonzalez
2017-06-13 12:09   ` Marc Zyngier
2017-06-13 14:01     ` [PATCH v6 " Marc Gonzalez
2017-06-13 14:22       ` Marc Zyngier
2017-06-13 14:47         ` Marc Gonzalez
2017-06-13 16:53           ` Marc Zyngier
2017-06-14  9:00             ` [PATCH v7 " Marc Gonzalez
2017-06-14  9:19               ` Marc Gonzalez
2017-06-14  9:32                 ` Marc Zyngier
2017-06-14 11:06                   ` [PATCH v8 " Marc Gonzalez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).