Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1251631 > unrolled thread

[PATCH RESEND v6 0/4] irqchip:support mbigen interrupt controller

Started byMaJun <majun258@huawei.com>
First post2015-10-20 14:20 +0200
Last post2015-10-20 14:30 +0200
Articles 2 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH RESEND v6 0/4] irqchip:support mbigen interrupt controller MaJun <majun258@huawei.com> - 2015-10-20 14:20 +0200
    [PATCH RESEND v6 3/4] irqchip:create irq domain for each mbigen device MaJun <majun258@huawei.com> - 2015-10-20 14:30 +0200

#1251631 — [PATCH RESEND v6 0/4] irqchip:support mbigen interrupt controller

FromMaJun <majun258@huawei.com>
Date2015-10-20 14:20 +0200
Subject[PATCH RESEND v6 0/4] irqchip:support mbigen interrupt controller
Message-ID<qlE3w-3rm-21@gated-at.bofh.it>
From: Ma Jun <majun258@huawei.com>

This patch set adds the driver of mbigen and binding document for Hisilicon
Mbigen chips.

Compared with previous version, this version changed much.

Because during the time between V3 and V4 of my patch, there are two
related patches were committed by Mr.Marc Zyngier and Mr. Mark Rutland.

First, Mr. Marc Zyngier changed MSI frame and added supporting for
platform MSI.

https://lkml.org/lkml/2015/7/28/552

Second, Mr.Mark Rutland changed Generic PCI MSI + IOMMU topology bindings

https://lkml.org/lkml/2015/7/23/558 

After V5 patch posted, Mr.Marc Zyngier posted a new patch set
"Adding core support for wire-MSI bridges"

https://lkml.org/lkml/2015/10/15/545

So, mbigen v6 patch is based on this new patch even though this patch is
still under review.

Changes in v6:
--- Re-based mbigen driver on kernel 4.3.0-rc5 and Marc's new patch
--- Change the mbigen chip node definition(dts).
--- Change the interrupt cells definition(dts).
Changes in v5:
--- Split mbigen driver patch into 2 smaller patches.
--- Change mbigen chip and mbigen device initialzing sequence.
--- Initializing mbigen device instead of mbigen chip as interrupt controller
--- Remove mbigen node from driver to make this driver more easily read.
--- Change the mbigen chip node definition(dts).
--- Change the interrupt cells definition(dts).
Changes in v4:
--- Re-based mbigen driver on kernel 4.2.0-rc2 and Marc's patch
--- Changed the binding document based on Mark's patch.

Ma Jun (4):
  dt-binding:Documents of the mbigen bindings
  irqchip: add platform device driver for mbigen device
  irqchip:create irq domain for each mbigen device
  irqchip:implement the mbigen irq chip operation functions

 Documentation/devicetree/bindings/arm/mbigen.txt |   63 ++++
 drivers/irqchip/Kconfig                          |    8 +
 drivers/irqchip/Makefile                         |    1 +
 drivers/irqchip/irq-mbigen.c                     |  335 ++++++++++++++++++++++
 4 files changed, 407 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt
 create mode 100644 drivers/irqchip/irq-mbigen.c


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1251635 — [PATCH RESEND v6 3/4] irqchip:create irq domain for each mbigen device

FromMaJun <majun258@huawei.com>
Date2015-10-20 14:30 +0200
Subject[PATCH RESEND v6 3/4] irqchip:create irq domain for each mbigen device
Message-ID<qlEdc-3CF-13@gated-at.bofh.it>
In reply to#1251631
From: Ma Jun <majun258@huawei.com>

For peripheral devices which connect to mbigen,mbigen is a interrupt
controller. So, we create irq domain for each mbigen device and add
mbigen irq domain into irq hierarchy structure.

Signed-off-by: Ma Jun <majun258@huawei.com>
---
 drivers/irqchip/irq-mbigen.c |  165 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 165 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index f18132f..3a20b25 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -16,27 +16,177 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/interrupt.h>
+#include <linux/irqchip.h>
 #include <linux/module.h>
+#include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
+/* Interrupt numbers per mbigen node supported */
+#define IRQS_PER_MBIGEN_NODE		128
+
+/* 16 irqs (Pin0-pin15) are reserved for each mbigen chip */
+#define RESERVED_IRQ_PER_MBIGEN_CHIP	16
+
+/**
+ * In mbigen vector register
+ * bit[21:12]:	event id value
+ * bit[11:0]:	device id
+ */
+#define IRQ_EVENT_ID_SHIFT		12
+#define IRQ_EVENT_ID_MASK		0x3ff
+
+/* register range of each mbigen node */
+#define MBIGEN_NODE_OFFSET		0x1000
+
+/* offset of vector register in mbigen node */
+#define REG_MBIGEN_VEC_OFFSET		0x200
+
 /**
  * struct mbigen_device - holds the information of mbigen device.
  *
  * @pdev:		pointer to the platform device structure of mbigen chip.
  * @base:		mapped address of this mbigen chip.
+ * @domain:		pointer to the irq domain
  */
 struct mbigen_device {
 	struct platform_device	*pdev;
 	void __iomem		*base;
+	struct irq_domain	*domain;
+};
+
+/**
+ * struct mbigen_irq_data - private data of each irq
+ *
+ * @base:		mapped address of mbigen chip
+ * @reg_vec:		addr offset of interrupt vector register.
+ */
+struct mbigen_irq_data {
+	void __iomem		*base;
+	unsigned int		reg_vec;
+};
+
+static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
+{
+	return (offset * 4) + nid * MBIGEN_NODE_OFFSET
+			+ REG_MBIGEN_VEC_OFFSET;
+}
+
+
+static struct irq_chip mbigen_irq_chip = {
+	.name =			"mbigen-v2",
+	.irq_mask =		irq_chip_mask_parent,
+	.irq_unmask =		irq_chip_unmask_parent,
+	.irq_eoi =		mbigen_eoi_irq,
+	.irq_set_type =		mbigen_set_type,
+	.irq_set_affinity =	irq_chip_set_affinity_parent,
+};
+
+static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+	struct mbigen_irq_data *mgn_irq_data = irq_get_chip_data(desc->irq);
+	u32 val;
+
+	val = readl_relaxed(mgn_irq_data->reg_vec + mgn_irq_data->base);
+
+	val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
+	val |= (msg->data << IRQ_EVENT_ID_SHIFT);
+
+	writel_relaxed(val, mgn_irq_data->reg_vec + mgn_irq_data->base);
+}
+
+static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq)
+{
+	struct mbigen_irq_data *datap;
+	unsigned int nid, pin_offset;
+
+	datap = kzalloc(sizeof(*datap), GFP_KERNEL);
+	if (!datap)
+		return NULL;
+
+	/* get the mbigen node number */
+	nid = (hwirq - RESERVED_IRQ_PER_MBIGEN_CHIP) / IRQS_PER_MBIGEN_NODE + 1;
+
+	pin_offset = (hwirq - RESERVED_IRQ_PER_MBIGEN_CHIP)
+					% IRQS_PER_MBIGEN_NODE;
+
+	datap->reg_vec = get_mbigen_vec_reg(nid, pin_offset);
+
+	return datap;
+}
+
+static int mbigen_domain_translate(struct irq_domain *d,
+				    struct irq_fwspec *fwspec,
+				    unsigned long *hwirq,
+				    unsigned int *type)
+{
+	if (is_of_node(fwspec->fwnode)) {
+		if (fwspec->param_count != 2)
+			return -EINVAL;
+
+		*hwirq = fwspec->param[0];
+		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int mbigen_irq_domain_alloc(struct irq_domain *domain,
+					unsigned int virq,
+					unsigned int nr_irqs,
+					void *args)
+{
+	struct irq_fwspec *fwspec = args;
+	irq_hw_number_t hwirq = fwspec->param[0];
+	struct mbigen_device *mgn_chip;
+	struct mbigen_irq_data *mgn_irq_data;
+	int i, err;
+
+	err = platform_msi_domain_alloc(domain, virq, nr_irqs);
+	if (err)
+		return err;
+
+	/* set related information of this irq */
+	mgn_irq_data = set_mbigen_irq_data(hwirq);
+	if (!mgn_irq_data)
+		return err;
+
+	mgn_chip = platform_msi_get_host_data(domain);
+	mgn_irq_data->base = mgn_chip->base;
+
+	for (i = 0; i < nr_irqs; i++)
+		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+				      &mbigen_irq_chip, mgn_irq_data);
+
+	return 0;
+}
+
+static void mbigen_domain_free(struct irq_domain *domain, unsigned int virq,
+			       unsigned int nr_irqs)
+{
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+	struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(d);
+
+	kfree(mgn_irq_data);
+	irq_domain_free_irqs_common(domain, virq, nr_irqs);
+}
+
+static struct irq_domain_ops mbigen_domain_ops = {
+	.translate	= mbigen_domain_translate,
+	.alloc		= mbigen_irq_domain_alloc,
+	.free		= mbigen_domain_free,
 };
 
 static int mbigen_device_probe(struct platform_device *pdev)
 {
 	struct mbigen_device *mgn_chip;
+	struct irq_domain *domain;
+	u32 num_msis;
 
 	mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
 	if (!mgn_chip)
@@ -45,6 +195,20 @@ static int mbigen_device_probe(struct platform_device *pdev)
 	mgn_chip->pdev = pdev;
 	mgn_chip->base = of_iomap(pdev->dev.of_node, 0);
 
+	/* If there is no "num-msi" property, assume 64... */
+	if (of_property_read_u32(pdev->dev.of_node, "num-msis", &num_msis) < 0)
+		num_msis = 64;
+
+	domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
+							mbigen_write_msg,
+							&mbigen_domain_ops,
+							mgn_chip);
+
+	if (!domain)
+		return -ENOMEM;
+
+	mgn_chip->domain = domain;
+
 	platform_set_drvdata(pdev, mgn_chip);
 
 	return 0;
@@ -54,6 +218,7 @@ static int mbigen_device_remove(struct platform_device *pdev)
 {
 	struct mbigen_device *mgn_chip = platform_get_drvdata(pdev);
 
+	irq_domain_remove(mgn_chip->domain);
 	iounmap(mgn_chip->base);
 
 	return 0;
-- 
1.7.1


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web