Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1251631 > unrolled thread
| Started by | MaJun <majun258@huawei.com> |
|---|---|
| First post | 2015-10-20 14:20 +0200 |
| Last post | 2015-10-20 14:30 +0200 |
| Articles | 2 — 1 participant |
Back to article view | Back to linux.kernel
[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
| From | MaJun <majun258@huawei.com> |
|---|---|
| Date | 2015-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]
| From | MaJun <majun258@huawei.com> |
|---|---|
| Date | 2015-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