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

2015-10-20 Thread MaJun
From: Ma Jun 

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 v7:
--- Fixed the build test error when applied patch v6 3/4
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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v7 4/4] irqchip:implement the mbigen irq chip operation functions

2015-10-20 Thread MaJun
From: Ma Jun 

Add the interrupt controller chip operation functions of mbigen chip.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |  102 +++--
 1 files changed, 97 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index a0bbc2d..729e6ac 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -47,6 +47,20 @@
 #define REG_MBIGEN_VEC_OFFSET  0x200
 
 /**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0xa00
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
+
+/**
  * struct mbigen_device - holds the information of mbigen device.
  *
  * @pdev:  pointer to the platform device structure of mbigen chip.
@@ -63,11 +77,19 @@ struct mbigen_device {
  * struct mbigen_irq_data - private data of each irq
  *
  * @base:  mapped address of mbigen chip
+ * @pin_offset:local pin offset of interrupt.
  * @reg_vec:   addr offset of interrupt vector register.
+ * @reg_type:  addr offset of interrupt trigger type register.
+ * @reg_clear: addr offset of interrupt clear register.
+ * @type:  interrupt trigger type.
  */
 struct mbigen_irq_data {
void __iomem*base;
+   unsigned intpin_offset;
unsigned intreg_vec;
+   unsigned intreg_type;
+   unsigned intreg_clear;
+   unsigned inttype;
 };
 
 static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
@@ -76,9 +98,68 @@ static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
+ REG_MBIGEN_VEC_OFFSET;
 }
 
+static int get_mbigen_type_reg(u32 nid, u32 offset)
+{
+   int ofst;
+
+   ofst = offset / 32 * 4;
+   return ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static int get_mbigen_clear_reg(u32 nid, u32 offset)
+{
+   int ofst;
+
+   ofst = offset / 32 * 4;
+   return ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(data);
+   u32 mask;
+
+   /* only level triggered interrupt need to clear status */
+   if (mgn_irq_data->type == IRQ_TYPE_LEVEL_HIGH) {
+   mask = 1 << (mgn_irq_data->pin_offset % 32);
+   writel_relaxed(mask, mgn_irq_data->reg_clear + 
mgn_irq_data->base);
+   }
+
+   irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *d, unsigned int type)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(d);
+   u32 mask;
+   int val;
+
+   if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+   return -EINVAL;
+
+   mask = 1 << (mgn_irq_data->pin_offset % 32);
+
+   val = readl_relaxed(mgn_irq_data->reg_type + mgn_irq_data->base);
+
+   if (type == IRQ_TYPE_LEVEL_HIGH)
+   val |= mask;
+   else if (type == IRQ_TYPE_EDGE_RISING)
+   val &= ~mask;
+
+   writel_relaxed(val, mgn_irq_data->reg_type + mgn_irq_data->base);
+
+   return 0;
+}
 
 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)
@@ -94,10 +175,11 @@ static void mbigen_write_msg(struct msi_desc *desc, struct 
msi_msg *msg)
writel_relaxed(val, mgn_irq_data->reg_vec + mgn_irq_data->base);
 }
 
-static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq)
+static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq,
+   unsigned int type)
 {
struct mbigen_irq_data *datap;
-   unsigned int nid, pin_offset;
+   unsigned int nid;
 
datap = kzalloc(sizeof(*datap), GFP_KERNEL);
if (!datap)
@@ -106,11 +188,20 @@ static struct mbigen_irq_data *set_mbigen_irq_data(int 
hwirq)
/* 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)
+   datap->pin_offset = (hwirq - RESERVED_IRQ_PER_MBIGEN_CHIP)
% IRQS_PER_MBIGEN_NODE;
 
-   datap->reg_vec = get_mbigen_vec_reg(nid, pin_offset);
+   datap->reg_vec = get_mbigen_vec_reg(nid, datap->pin_offset);
+   dat

[PATCH v7 1/4] dt-binding:Documents of the mbigen bindings

2015-10-20 Thread MaJun
From: Ma Jun 

Add the mbigen msi interrupt controller bindings document.

This patch based on Mark Rutland's patch
https://lkml.org/lkml/2015/7/23/558

Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   63 ++
 1 files changed, 63 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100644
index 000..eb9a7fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,63 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2"
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+- interrupt controller: Identifies the node as an interrupt controller
+- msi-parent: This property has two cells.
+   The 1st cell specifies the ITS this device connected.
+   The 2nd cell specifies the device id.
+- nr-msis:Specifies the total number of interrupt this device has.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value is 2 now.
+
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type.
+
+Examples:
+
+   mbigen_device_gmac:intc {
+   compatible = "hisilicon,mbigen-v2";
+   reg = <0x0 0xc008 0x0 0x1>;
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b1c>;
+   num-msis = <9>;
+   #interrupt-cells = <2>;
+   };
+
+Devices connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen device node which device connected.
+-interrupts:specifies the interrupt source.
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type
+
+Examples:
+   gmac0: ethernet@c208 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   reg = <0 0xc208 0 0x2>,
+ <0 0xc000 0 0x1000>;
+   interrupt-parent  = <&mbigen_device_gmac>;
+   interrupts =<656 1>,
+   <657 1>;
+   };
+
-- 
1.7.1


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


[PATCH v7 3/4] irqchip:create irq domain for each mbigen device

2015-10-20 Thread MaJun
From: Ma Jun 

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 
---
 drivers/irqchip/irq-mbigen.c |  160 ++
 1 files changed, 160 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index f18132f..a0bbc2d 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -16,27 +16,172 @@
  * along with this program.  If not, see .
  */
 
+#include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
+/* 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 intreg_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",
+};
+
+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,
+   

[PATCH v7 2/4] irqchip: add platform device driver for mbigen device

2015-10-20 Thread MaJun
From: Ma Jun 

Mbigen means Message Based Interrupt Generator(MBIGEN).

Its a kind of interrupt controller that collects
the interrupts from external devices and generate msi interrupt.
Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is
increasing much, especially on the Arm64 server SOC.

Therefore, the interrupt pin in GIC is not enough to cover so
many peripherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

Mbigen chip hardware structure shows as below:

mbigen chip
|-|---|
mgn_node0 mgn_node1 mgn_node2
 |   |---|  |---|--|
dev1dev1dev2dev1   dev3   dev4

Each mbigen chip contains several mbigen nodes.

External devices can connect to mbigen node through wire connecting way.

Because a mbigen node only can support 128 interrupt maximum, depends
on the interrupt lines number of devices, a device can connects to one
more mbigen nodes.

Also, several different devices can connect to a same mbigen node.

When devices triggered interrupt,mbigen chip detects and collects
the interrupts and generates the MBI interrupts by writing the ITS
Translator register.

To simplify mbigen driver,I used a new conception--mbigen device.
Each mbigen device is initialized as a platform device.

Mbigen device presents the parts(register, pin definition etc.) in
mbigen chip corresponding to a peripheral device.

So from software view, the structure likes below

mbigen chip
 |-|-|
mbigen device1   mbigen device2  mbigen device3
  |   ||
 dev1dev2 dev3

Signed-off-by: Ma Jun 
---
 drivers/irqchip/Kconfig  |8 
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |   83 ++
 3 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4d7294e..b205e15 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -27,6 +27,14 @@ config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
 
+config HISILICON_IRQ_MBIGEN
+   bool "Support mbigen interrupt controller"
+   default n
+   depends on ARM_GIC_V3 && ARM_GIC_V3_ITS && GENERIC_MSI_IRQ_DOMAIN
+   help
+Enable the mbigen interrupt controller used on
+Hisilicon platform.
+
 config ARM_NVIC
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 177f78f..cd76b11 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o 
irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o 
irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 000..f18132f
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * 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.
+ */
+struct mbigen_device {
+   struct platform_device  *pdev;
+   void __iomem*base;
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip;
+
+   mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+   if (!mgn_chip)
+   return -ENOMEM;
+
+   mgn_chip->pdev

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

2015-10-20 Thread MaJun
From: Ma Jun 

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 
---
 drivers/irqchip/irq-mbigen.c |  152 ++
 1 files changed, 152 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index f18132f..211b3c8 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -16,27 +16,164 @@
  * along with this program.  If not, see .
  */
 
+#include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
+/* 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 intreg_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++)
+ 

[PATCH v6 4/4] irqchip:implement the mbigen irq chip operation functions

2015-10-20 Thread MaJun
From: Ma Jun 

Add the interrupt controller chip operation functions of mbigen chip.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |  100 +++--
 1 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 211b3c8..dbda7bc 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -45,6 +45,21 @@
 
 /* offset of vector register in mbigen node */
 #define REG_MBIGEN_VEC_OFFSET  0x200
+
+/**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0xa00
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
+
 /**
  * struct mbigen_device - holds the information of mbigen device.
  *
@@ -62,11 +77,19 @@ struct mbigen_device {
  * struct mbigen_irq_data - private data of each irq
  *
  * @base:  mapped address of mbigen chip
+ * @pin_offset:local pin offset of interrupt.
  * @reg_vec:   addr offset of interrupt vector register.
+ * @reg_type:  addr offset of interrupt trigger type register.
+ * @reg_clear: addr offset of interrupt clear register.
+ * @type:  interrupt trigger type.
  */
 struct mbigen_irq_data {
void __iomem*base;
+   unsigned intpin_offset;
unsigned intreg_vec;
+   unsigned intreg_type;
+   unsigned intreg_clear;
+   unsigned inttype;
 };
 
 static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
@@ -75,6 +98,61 @@ static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
+ REG_MBIGEN_VEC_OFFSET;
 }
 
+static int get_mbigen_type_reg(u32 nid, u32 offset)
+{
+   int ofst;
+
+   ofst = offset / 32 * 4;
+   return ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static int get_mbigen_clear_reg(u32 nid, u32 offset)
+{
+   int ofst;
+
+   ofst = offset / 32 * 4;
+   return ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(data);
+   u32 mask;
+
+   /* only level triggered interrupt need to clear status */
+   if (mgn_irq_data->type == IRQ_TYPE_LEVEL_HIGH) {
+   mask = 1 << (mgn_irq_data->pin_offset % 32);
+   writel_relaxed(mask, mgn_irq_data->reg_clear + 
mgn_irq_data->base);
+   }
+
+   irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *d, unsigned int type)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(d);
+   u32 mask;
+   int val;
+
+   if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+   return -EINVAL;
+
+   mask = 1 << (mgn_irq_data->pin_offset % 32);
+
+   val = readl_relaxed(mgn_irq_data->reg_type + mgn_irq_data->base);
+
+   if (type == IRQ_TYPE_LEVEL_HIGH)
+   val |= mask;
+   else if (type == IRQ_TYPE_EDGE_RISING)
+   val &= ~mask;
+
+   writel_relaxed(val, mgn_irq_data->reg_type + mgn_irq_data->base);
+
+   return 0;
+}
+
 static struct irq_chip mbigen_irq_chip = {
.name = "mbigen-v2",
.irq_mask = irq_chip_mask_parent,
@@ -97,10 +175,11 @@ static void mbigen_write_msg(struct msi_desc *desc, struct 
msi_msg *msg)
writel_relaxed(val, mgn_irq_data->reg_vec + mgn_irq_data->base);
 }
 
-static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq)
+static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq,
+   unsigned int type)
 {
struct mbigen_irq_data *datap;
-   unsigned int nid, pin_offset;
+   unsigned int nid;
 
datap = kzalloc(sizeof(*datap), GFP_KERNEL);
if (!datap)
@@ -109,10 +188,20 @@ static struct mbigen_irq_data *set_mbigen_irq_data(int 
hwirq)
/* 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)
+   datap->pin_offset = (hwirq - RESERVED_IRQ_PER_MBIGEN_CHIP)
% IRQS_PER_MBIGEN_NODE;
 
-   datap->reg_vec = get_mbigen_vec_reg(nid, pin_offset);
+   datap->reg_type = get_mbigen_type_reg(nid, datap->pin_offset);
+   datap->reg_vec = get_mbigen_vec_reg(nid, datap->pin_offset);
+
+   /* no clear register for edge triggered interrupt */
+   if (type == IRQ_TYPE_EDGE_RISING)
+   datap->reg_clear = 0;
+   else
+   datap->reg_clear = get_mbigen_clear_reg(nid,
+   datap->pi

[PATCH v6 1/4] dt-binding:Documents of the mbigen bindings

2015-10-20 Thread MaJun
From: Ma Jun 

Add the mbigen msi interrupt controller bindings document.

This patch based on Mark Rutland's patch 
https://lkml.org/lkml/2015/7/23/558 

Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   63 ++
 1 files changed, 63 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100644
index 000..eb9a7fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,63 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2"
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+- interrupt controller: Identifies the node as an interrupt controller
+- msi-parent: This property has two cells.
+   The 1st cell specifies the ITS this device connected.
+   The 2nd cell specifies the device id.
+- nr-msis:Specifies the total number of interrupt this device has.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value is 2 now.
+
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type.
+
+Examples:
+
+   mbigen_device_gmac:intc {
+   compatible = "hisilicon,mbigen-v2";
+   reg = <0x0 0xc008 0x0 0x1>;
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b1c>;
+   num-msis = <9>;
+   #interrupt-cells = <2>;
+   };
+
+Devices connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen device node which device connected.
+-interrupts:specifies the interrupt source.
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type
+
+Examples:
+   gmac0: ethernet@c208 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   reg = <0 0xc208 0 0x2>,
+ <0 0xc000 0 0x1000>;
+   interrupt-parent  = <&mbigen_device_gmac>;
+   interrupts =<656 1>,
+   <657 1>;
+   };
+
-- 
1.7.1


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


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

2015-10-20 Thread MaJun
From: Ma Jun 

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/irq-mbigen.c |  325 ++
 2 files changed, 388 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v6 2/4] irqchip: add platform device driver for mbigen device

2015-10-20 Thread MaJun
From: Ma Jun 

Mbigen means Message Based Interrupt Generator(MBIGEN).

Its a kind of interrupt controller that collects
the interrupts from external devices and generate msi interrupt.
Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is
increasing much, especially on the Arm64 server SOC.

Therefore, the interrupt pin in GIC is not enough to cover so
many peripherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

Mbigen chip hardware structure shows as below:

mbigen chip
|-|---|
mgn_node0 mgn_node1 mgn_node2
 |   |---|  |---|--|
dev1dev1dev2dev1   dev3   dev4

Each mbigen chip contains several mbigen nodes.

External devices can connect to mbigen node through wire connecting way.

Because a mbigen node only can support 128 interrupt maximum, depends
on the interrupt lines number of devices, a device can connects to one
more mbigen nodes.

Also, several different devices can connect to a same mbigen node.

When devices triggered interrupt,mbigen chip detects and collects
the interrupts and generates the MBI interrupts by writing the ITS
Translator register.

To simplify mbigen driver,I used a new conception--mbigen device.
Each mbigen device is initialized as a platform device.

Mbigen device presents the parts(register, pin definition etc.) in
mbigen chip corresponding to a peripheral device.

So from software view, the structure likes below

mbigen chip
 |-|-|
mbigen device1   mbigen device2  mbigen device3
  |   ||
 dev1dev2 dev3

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |   83 ++
 1 files changed, 83 insertions(+), 0 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen.c

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 000..f18132f
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * 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.
+ */
+struct mbigen_device {
+   struct platform_device  *pdev;
+   void __iomem*base;
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip;
+
+   mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+   if (!mgn_chip)
+   return -ENOMEM;
+
+   mgn_chip->pdev = pdev;
+   mgn_chip->base = of_iomap(pdev->dev.of_node, 0);
+
+   platform_set_drvdata(pdev, mgn_chip);
+
+   return 0;
+}
+
+static int mbigen_device_remove(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip = platform_get_drvdata(pdev);
+
+   iounmap(mgn_chip->base);
+
+   return 0;
+}
+
+static const struct of_device_id mbigen_of_match[] = {
+   { .compatible = "hisilicon,mbigen-v2" },
+   { /* END */ }
+};
+MODULE_DEVICE_TABLE(of, mbigen_of_match);
+
+static struct platform_driver mbigen_platform_driver = {
+   .driver = {
+   .name   = "Hisilicon MBIGEN-V2",
+   .owner  = THIS_MODULE,
+   .of_match_table = mbigen_of_match,
+   },
+   .probe  = mbigen_device_probe,
+   .remove = mbigen_device_remove,
+};
+
+module_platform_driver(mbigen_platform_driver);
+
+MODULE_AUTHOR("Jun Ma ");
+MODULE_AUTHOR("Yun Wu ");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hisilicon MBI Generator driver");
-- 
1.7.1


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


[PATCH RESEND v6 1/4] dt-binding:Documents of the mbigen bindings

2015-10-20 Thread MaJun
From: Ma Jun 

Add the mbigen msi interrupt controller bindings document.

This patch based on Mark Rutland's patch 
https://lkml.org/lkml/2015/7/23/558 

Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   63 ++
 1 files changed, 63 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100644
index 000..eb9a7fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,63 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2"
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+- interrupt controller: Identifies the node as an interrupt controller
+- msi-parent: This property has two cells.
+   The 1st cell specifies the ITS this device connected.
+   The 2nd cell specifies the device id.
+- nr-msis:Specifies the total number of interrupt this device has.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value is 2 now.
+
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type.
+
+Examples:
+
+   mbigen_device_gmac:intc {
+   compatible = "hisilicon,mbigen-v2";
+   reg = <0x0 0xc008 0x0 0x1>;
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b1c>;
+   num-msis = <9>;
+   #interrupt-cells = <2>;
+   };
+
+Devices connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen device node which device connected.
+-interrupts:specifies the interrupt source.
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type
+
+Examples:
+   gmac0: ethernet@c208 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   reg = <0 0xc208 0 0x2>,
+ <0 0xc000 0 0x1000>;
+   interrupt-parent  = <&mbigen_device_gmac>;
+   interrupts =<656 1>,
+   <657 1>;
+   };
+
-- 
1.7.1


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


[PATCH RESEND v6 2/4] irqchip: add platform device driver for mbigen device

2015-10-20 Thread MaJun
From: Ma Jun 

Mbigen means Message Based Interrupt Generator(MBIGEN).

Its a kind of interrupt controller that collects
the interrupts from external devices and generate msi interrupt.
Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is
increasing much, especially on the Arm64 server SOC.

Therefore, the interrupt pin in GIC is not enough to cover so
many peripherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

Mbigen chip hardware structure shows as below:

mbigen chip
|-|---|
mgn_node0 mgn_node1 mgn_node2
 |   |---|  |---|--|
dev1dev1dev2dev1   dev3   dev4

Each mbigen chip contains several mbigen nodes.

External devices can connect to mbigen node through wire connecting way.

Because a mbigen node only can support 128 interrupt maximum, depends
on the interrupt lines number of devices, a device can connects to one
more mbigen nodes.

Also, several different devices can connect to a same mbigen node.

When devices triggered interrupt,mbigen chip detects and collects
the interrupts and generates the MBI interrupts by writing the ITS
Translator register.

To simplify mbigen driver,I used a new conception--mbigen device.
Each mbigen device is initialized as a platform device.

Mbigen device presents the parts(register, pin definition etc.) in
mbigen chip corresponding to a peripheral device.

So from software view, the structure likes below

mbigen chip
 |-|-|
mbigen device1   mbigen device2  mbigen device3
  |   ||
 dev1dev2 dev3

Signed-off-by: Ma Jun 
---
 drivers/irqchip/Kconfig  |8 
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |   83 ++
 3 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 67d8027..1f51a1b 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -27,6 +27,14 @@ config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
 
+config HISILICON_IRQ_MBIGEN
+   bool "Support mbigen interrupt controller"
+   default n
+   depends on ARM_GIC_V3 && ARM_GIC_V3_ITS && GENERIC_MSI_IRQ_DOMAIN
+   help
+Enable the mbigen interrupt controller used on
+Hisilicon platform.
+
 config ARM_NVIC
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index bb3048f..791507b 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o 
irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o 
irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 000..f18132f
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * 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.
+ */
+struct mbigen_device {
+   struct platform_device  *pdev;
+   void __iomem*base;
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip;
+
+   mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+   if (!mgn_chip)
+   return -ENOMEM;
+
+   mgn_chip->pdev

[PATCH RESEND v6 4/4] irqchip:implement the mbigen irq chip operation functions

2015-10-20 Thread MaJun
From: Ma Jun 

Add the interrupt controller chip operation functions of mbigen chip.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |   97 +++--
 1 files changed, 92 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 3a20b25..729e6ac 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -47,6 +47,20 @@
 #define REG_MBIGEN_VEC_OFFSET  0x200
 
 /**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0xa00
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
+
+/**
  * struct mbigen_device - holds the information of mbigen device.
  *
  * @pdev:  pointer to the platform device structure of mbigen chip.
@@ -63,11 +77,19 @@ struct mbigen_device {
  * struct mbigen_irq_data - private data of each irq
  *
  * @base:  mapped address of mbigen chip
+ * @pin_offset:local pin offset of interrupt.
  * @reg_vec:   addr offset of interrupt vector register.
+ * @reg_type:  addr offset of interrupt trigger type register.
+ * @reg_clear: addr offset of interrupt clear register.
+ * @type:  interrupt trigger type.
  */
 struct mbigen_irq_data {
void __iomem*base;
+   unsigned intpin_offset;
unsigned intreg_vec;
+   unsigned intreg_type;
+   unsigned intreg_clear;
+   unsigned inttype;
 };
 
 static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
@@ -76,6 +98,60 @@ static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
+ REG_MBIGEN_VEC_OFFSET;
 }
 
+static int get_mbigen_type_reg(u32 nid, u32 offset)
+{
+   int ofst;
+
+   ofst = offset / 32 * 4;
+   return ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static int get_mbigen_clear_reg(u32 nid, u32 offset)
+{
+   int ofst;
+
+   ofst = offset / 32 * 4;
+   return ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(data);
+   u32 mask;
+
+   /* only level triggered interrupt need to clear status */
+   if (mgn_irq_data->type == IRQ_TYPE_LEVEL_HIGH) {
+   mask = 1 << (mgn_irq_data->pin_offset % 32);
+   writel_relaxed(mask, mgn_irq_data->reg_clear + 
mgn_irq_data->base);
+   }
+
+   irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *d, unsigned int type)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(d);
+   u32 mask;
+   int val;
+
+   if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+   return -EINVAL;
+
+   mask = 1 << (mgn_irq_data->pin_offset % 32);
+
+   val = readl_relaxed(mgn_irq_data->reg_type + mgn_irq_data->base);
+
+   if (type == IRQ_TYPE_LEVEL_HIGH)
+   val |= mask;
+   else if (type == IRQ_TYPE_EDGE_RISING)
+   val &= ~mask;
+
+   writel_relaxed(val, mgn_irq_data->reg_type + mgn_irq_data->base);
+
+   return 0;
+}
 
 static struct irq_chip mbigen_irq_chip = {
.name = "mbigen-v2",
@@ -99,10 +175,11 @@ static void mbigen_write_msg(struct msi_desc *desc, struct 
msi_msg *msg)
writel_relaxed(val, mgn_irq_data->reg_vec + mgn_irq_data->base);
 }
 
-static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq)
+static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq,
+   unsigned int type)
 {
struct mbigen_irq_data *datap;
-   unsigned int nid, pin_offset;
+   unsigned int nid;
 
datap = kzalloc(sizeof(*datap), GFP_KERNEL);
if (!datap)
@@ -111,11 +188,20 @@ static struct mbigen_irq_data *set_mbigen_irq_data(int 
hwirq)
/* 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)
+   datap->pin_offset = (hwirq - RESERVED_IRQ_PER_MBIGEN_CHIP)
% IRQS_PER_MBIGEN_NODE;
 
-   datap->reg_vec = get_mbigen_vec_reg(nid, pin_offset);
+   datap->reg_vec = get_mbigen_vec_reg(nid, datap->pin_offset);
+   datap->reg_type = get_mbigen_type_reg(nid, datap->pin_offset);
+
+   /* no clear register for edge triggered interrupt */
+   if (type == IRQ_TYPE_EDGE_RISING)
+   datap->reg_clear = 0;
+   else
+   datap->reg_clear = get_mbigen_clear_reg(nid,
+   datap->pin_offset);
 
+   da

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

2015-10-20 Thread MaJun
From: Ma Jun 

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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


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

2015-10-20 Thread MaJun
From: Ma Jun 

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 
---
 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 .
  */
 
+#include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
+/* 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 intreg_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++)
+   

[PATCH v4 2/2] dt-binding:Documents of the mbigen bindings

2015-08-18 Thread MaJun
From: Ma Jun 

Add the mbigen msi interrupt controller bindings document.

Change since v3:
--- Change the interrupt cells definition.
--- Change the mbigen node definition.
--- Add mbigen device node as sub node of mbigen.


Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   97 ++
 1 files changed, 97 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100644
index 000..8e1203b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,97 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2"
+- interrupt controller: Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value is 4 now.
+
+  The 1st cell is the device id.
+  The 2nd cell is the mbigen node number. This value should refer to the
+  vendor Soc specification.
+  The 3rd cell is the hardware pin number of the interrupt.
+  This value depends on the Soc design.
+  The 4th cell is the interrupt trigger type, encoded as follows:
+   1 = edge triggered
+   4 = level triggered
+
+- #mbigen-node-cells :Specifies the number of cells needed to encode an
+  mbigen node information. The value is 3 now.
+
+  The 1st cell is the mbigen node number.
+  The 2nd cell is the interrupt numbers connected to.
+  The 3rd cell is the start value of pin offset.
+
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+
+Sub-nodes:
+
+Mbigen has one or more mbigen device nodes which represents the devices
+connected to this mbigen chip.
+
+These nodes must have the following properties:
+- msi-parent: This property has two cells.
+   The 1st cell specifies the ITS this device connected.
+   The 2nd cell specifies the device id.
+- nr-interrupts:Specifies the total number of interrupt this device has.
+- mbigen_node: Specifies the information of mbigen nodes this device
+  connected.Some devices with many interrupts maybe connects with several
+  mbigen nodes.
+
+Examples:
+
+   mbigen_dsa: interrupt-controller@c008 {
+   compatible = "hisilicon,mbigen-v2";
+   interrupt-controller;
+   #interrupt-cells = <5>;
+   #mbigen-node-cells = <3>;
+   reg = <0xc008 0x1>;
+
+   mbigen_device_01 {
+   msi-parent = <&its 0x40b1c>;
+   nr-interrupts = <9>;
+   mbigen_node = <1 2 0>,
+   <3 2 4>,
+   <4 5 0>;
+   }
+
+   mbigen_device_02 {
+   msi-parent = <&its 0x40b1d>;
+   nr-interrupts = <3>;
+   mbigen_node = <6 3 0>;
+   interrupt-controller;
+   }
+   };
+
+Device connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen node which device connected.
+-interrupts:specifies the interrupt source.The first cell is hwirq num, the
+  second number is trigger type.
+
+Examples:
+   smmu_dsa {
+   compatible = "arm,smmu-v3";
+   reg = <0x0 0xc004 0x0 0x2>;
+   interrupt-parent  = <&mbigen_dsa>;
+   interrupts = <0x40b20 6 78 1>,
+   <0x40b20 6 79 1>,
+   <0x40b20 6 80 1>;
+   };
+
-- 
1.7.1


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


[PATCH v4 0/2] Support Mbigen interrupt controller

2015-08-18 Thread MaJun
From: Ma Jun 

This patch 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 

Changes since v3:
--- 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 (2):
  Add the driver of mbigen interrupt controller
  dt-binding:Documents of the mbigen bindings

 Documentation/devicetree/bindings/arm/mbigen.txt |   97 +++
 drivers/irqchip/Kconfig  |8 +
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |  732 ++
 4 files changed, 838 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v4 1/2] Add the driver of mbigen interrupt controller

2015-08-18 Thread MaJun
From: Ma Jun 

Mbigen means Message Based Interrupt Generator(MBIGEN).

Its a kind of interrupt controller that collects

the interrupts from external devices and generate msi interrupt.

Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is 
increasing much, especially on the Arm64 server soc.

Therefore, the interrupt pin in gic is not enough to cover so
many peripherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

Mbigen chip hardware structure shows as below:

mbigen chip
|-|---|
mgn_node0 mgn_node1 mgn_node2
 |   |---|  |---|--|
dev1dev1dev2dev1   dev3   dev4

Each mbigen chip contains several mbigen nodes.

External devices can connects to mbigen node through wire connecting way.

Because a mbigen node only can support 128 interrupt maximum, depends
on the interrupt lines number of devices, a device can connects to one
more mbigen nodes.

Also, several different devices can connect to a same mbigen node.

When devices triggered interrupt,mbigen chip detects and collects 
the interrupts and generates the MBI interrupts by writing the ITS
Translator register.


Signed-off-by: Ma Jun 
---
 drivers/irqchip/Kconfig  |8 +
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |  732 ++
 3 files changed, 741 insertions(+), 0 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 120d815..356507f 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -27,6 +27,14 @@ config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
 
+config HISILICON_IRQ_MBIGEN
+   bool "Support mbigen interrupt controller"
+   default n
+   depends on ARM_GIC_V3 && ARM_GIC_V3_ITS
+   help
+Enable the mbigen interrupt controller used on
+Hisilicon platform.
+
 config ARM_NVIC
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 11d08c9..c6f3d66 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o 
irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o 
irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 000..4bbbd76
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,732 @@
+/*
+ * Copyright (C) 2014 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "irqchip.h"
+
+#defineMBIGEN_NODE_SHIFT   (8)
+#define MBIGEN_DEV_SHIFT   (12)
+
+/*
+ * To avoid the duplicate hwirq number problem
+ * we use device id, mbigen node number and interrupt
+ * pin offset to generate a new hwirq number in mbigen
+ * domain.
+ *
+ * hwirq[32:12]: did. device id
+ * hwirq[11:8]: nid. mbigen node number
+ * hwirq[7:0]: pin. hardware pin offset of this interrupt
+ */
+#defineCOMPOSE_MBIGEN_HWIRQ(did, nid, pin) \
+   (((did) << MBIGEN_DEV_SHIFT) | \
+   ((nid) << MBIGEN_NODE_SHIFT) | (pin))
+
+/* get the interrupt pin offset from mbigen hwirq */
+#defineGET_IRQ_PIN_OFFSET(hwirq)   ((hwirq) & 0xff)
+/* get the mbigen node number from mbigen hwirq */
+#define GET_MBIGEN_NODE_NUM(hwirq) (((hwirq) >> MBIGEN_NODE_SHIFT) & 0xf)
+/* get the mbigen device id from mbigen hwirq */
+#define GET_MBIGEN_DEVICE_ID(hwirq)\
+   (((hwirq) >> MBIGEN_DEV_SHIFT) & 0xf)
+
+/*
+ * In mbigen vector register
+ * bit[21:12]: event id value
+ 

Re: [PATCH v9 3/4] irqchip:create irq domain for each mbigen device

2015-12-06 Thread majun
Hi Marc:

On 2015/12/3 11:25, Marc Zyngier wrote:
> On 23/11/15 03:15, MaJun wrote:
>> From: Ma Jun 
>>
>> 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 
>> ---
>>  drivers/irqchip/irq-mbigen.c |  119 
>> ++
>>  1 files changed, 119 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
>> index 9f036c2..81ae61f 100644
>> --- a/drivers/irqchip/irq-mbigen.c
>> +++ b/drivers/irqchip/irq-mbigen.c
>> @@ -16,13 +16,36 @@
>>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>>  
>> +#include 
>> +#include 
>>  #include 
>> +#include 
>>  #include 
>>  #include 
>>  #include 
>>  #include 
>>  #include 
>>  
>> +/* Interrupt numbers per mbigen node supported */
>> +#define IRQS_PER_MBIGEN_NODE128
>> +
>> +/* 64 irqs (Pin0-pin63) are reserved for each mbigen chip */
>> +#define RESERVED_IRQ_PER_MBIGEN_CHIP64
>> +
>> +/**
>> + * 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.
>>   *
>> @@ -34,10 +57,94 @@ struct mbigen_device {
>>  void __iomem*base;
>>  };
>>  
>> +static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
>> +{
>> +unsigned int nid, pin;
>> +
>> +hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
>> +nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
>> +pin = hwirq % IRQS_PER_MBIGEN_NODE;
>> +
>> +return pin * 4 + nid * MBIGEN_NODE_OFFSET
>> ++ REG_MBIGEN_VEC_OFFSET;
>> +}
>> +
>> +static struct irq_chip mbigen_irq_chip = {
>> +.name = "mbigen-v2",
>> +};
>> +
>> +static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
>> +{
>> +struct irq_data *d = irq_get_irq_data(desc->irq);
>> +void __iomem *base = d->chip_data;
>> +u32 val;
>> +
>> +base += get_mbigen_vec_reg(d->hwirq);
>> +val = readl_relaxed(base);
>> +
>> +val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
>> +val |= (msg->data << IRQ_EVENT_ID_SHIFT);
>> +
>> +writel_relaxed(val, base);
> 
> nit: It would be good to have a comment explaining why you do not need
> to program the address of the doorbell...

The address of doorbell is encoded in mbigen register by default,
So, we don't need to program the doorbell address in mbigen driver.

I'll add this comment in next version.

> 
>> +}
>> +
>> +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;
>> +unsigned int type;
>> +struct mbigen_device *mgn_chip;
>> +int i, err;
>> +
>> +err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
>> +if (err)
>> +return err;
>> +
>> +err = platform_msi_domain_alloc(domain, virq, nr_irqs);
>> +if (err)
>> +return err;

Re: [PATCH v9 0/4] irqchip:support mbigen interrupt controller

2015-12-16 Thread majun
Hi Marc:
Sorry for late response.
I just came back from a business trip from American.
I'll send a new version ASAP on tomorrow.

Thanks!
Ma Jun

On 2015/12/16 6:22, Marc Zyngier wrote:
> On 23/11/15 03:15, MaJun wrote:
>> From: Ma Jun 
>>
>> This patch set adds the driver of mbigen and binding document for Hisilicon
>> Mbigen chips.
> 
> [...]
> 
> Any update on this? If this is to be 4.5 material, I'd like to see the
> various comments addressed shortly so that I can queue it.
> 
> Thanks,
> 
>   M.
> 

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


Re: [PATCH v9 1/4] dt-binding:Documents of the mbigen bindings

2015-12-16 Thread majun
Hi Mark:

On 2015/12/11 10:26, Mark Rutland wrote:
> Hi,
> 
> On Mon, Nov 23, 2015 at 11:15:10AM +0800, MaJun wrote:
>> From: Ma Jun 
>>
>> Add the mbigen msi interrupt controller bindings document.
>>
>> This patch based on Mark Rutland's patch
>> https://lkml.org/lkml/2015/7/23/558
>>
>> Signed-off-by: Ma Jun 
>> ---
>>  Documentation/devicetree/bindings/arm/mbigen.txt |   69 
>> ++
>>  1 files changed, 69 insertions(+), 0 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt
>>
>> diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
>> b/Documentation/devicetree/bindings/arm/mbigen.txt
>> new file mode 100644
>> index 000..8ae59a9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/arm/mbigen.txt
>> @@ -0,0 +1,69 @@
>> +Hisilicon mbigen device tree bindings.
>> +===
>> +
[...]
>> +- #interrupt-cells : Specifies the number of cells needed to encode an
>> +  interrupt source. The value must be 2.
>> +
>> +  The 1st cell is global hardware pin number of the interrupt.
>> +This value depends on the Soc design.
> 
> I think a little more information is required here. Presumably the
> "global hardware pin number" is actually a pin number within the
> particular mbigen instance? i.e. it is local to this instance?
> 

Maybe "global hardware pin number" is  not an accurate definition of pin number 
and
makes people confused.

I will change it to "hardware pin number" to present the real pin number of
wired interrupt(from 0 to maximum interrupt number).

So, there is no global pin number or local pin number.

Thanks!
Majun


>> +  The 2nd cell is the interrupt trigger type.
>> +The value of this cell should be:
>> +1: rising edge triggered
>> +or
>> +4: high level triggered 
>> +
>> +Examples:
>> +
>> +mbigen_device_gmac:intc {
>> +compatible = "hisilicon,mbigen-v2";
>> +reg = <0x0 0xc008 0x0 0x1>;
>> +interrupt-controller;
>> +msi-parent = <&its_dsa 0x40b1c>;
>> +num-msis = <9>;
>> +#interrupt-cells = <2>;
>> +};
>> +
>> +Devices connect to mbigen required properties:
>> +
>> +-interrupt-parent: Specifies the mbigen device node which device connected.
>> +-interrupts:specifies the interrupt source.
>> +  The 1st cell is global hardware pin number of the interrupt.
>> +This value depends on the Soc design.
>> +  The 2nd cell is the interrupt trigger type(rising edge triggered or high
>> +level triggered)
> 
> You should be able to refer to the usual interrupt bindings given you
> defined the format previously when describing #interrupt-cells.
> 
> Thanks,
> Mark.
> 
> .
> 

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


Re: [PATCH v9 3/4] irqchip:create irq domain for each mbigen device

2015-12-16 Thread majun
Hi Marc and Mark:

On 2015/12/11 10:42, Mark Rutland wrote:
> On Mon, Nov 23, 2015 at 11:15:12AM +0800, MaJun wrote:
>> From: Ma Jun 
>>
>> 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 
>> ---
>>  drivers/irqchip/irq-mbigen.c |  119 
>> ++
>>  1 files changed, 119 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
>> index 9f036c2..81ae61f 100644
>> --- a/drivers/irqchip/irq-mbigen.c
>> +++ b/drivers/irqchip/irq-mbigen.c
>> @@ -16,13 +16,36 @@
>>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>>  
>> +#include 
>> +#include 
>>  #include 
>> +#include 
>>  #include 
>>  #include 
>>  #include 
>>  #include 
>>  #include 
>>  
>> +/* Interrupt numbers per mbigen node supported */
>> +#define IRQS_PER_MBIGEN_NODE128
>> +
>> +/* 64 irqs (Pin0-pin63) are reserved for each mbigen chip */
>> +#define RESERVED_IRQ_PER_MBIGEN_CHIP64
>> +
>> +/**
>> + * 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.
>>   *
>> @@ -34,10 +57,94 @@ struct mbigen_device {
>>  void __iomem*base;
>>  };
>>  
>> +static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
>> +{
>> +unsigned int nid, pin;
>> +
>> +hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
>> +nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
>> +pin = hwirq % IRQS_PER_MBIGEN_NODE;
>> +
>> +return pin * 4 + nid * MBIGEN_NODE_OFFSET
>> ++ REG_MBIGEN_VEC_OFFSET;
>> +}
> 
> Ok. So your "global" pin id is "global" per mbigen chip.

right.

> 
> I think it may make more sense to have separate nid and pin fields in
> your interrupt-specifier, e.g. interrupt = <1 3 x> for nid 1, pin 3.
> 
> That's easier for someone to check against a datasheet that describes
> the nid and pin rather than the global number space you've come up with,
> and also makes it impossible to describe the reserved IRQs.

There are no nid and pin fields in our new datasheet now.
All we can see is hardware pin number.
So adding nid and pin fields makes the people more confused about using
mbigen.

Further more, "pin" is not a good variable name. I should name it as
"pin_offset" or just"offset" to present the interrupt pin offset to mbigen node.

> 
>> +
>> +static struct irq_chip mbigen_irq_chip = {
>> +.name = "mbigen-v2",
>> +};
>> +
>> +static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
>> +{
>> +struct irq_data *d = irq_get_irq_data(desc->irq);
>> +void __iomem *base = d->chip_data;
>> +u32 val;
>> +
>> +base += get_mbigen_vec_reg(d->hwirq);
>> +val = readl_relaxed(base);
>> +
>> +val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
>> +val |= (msg->data << IRQ_EVENT_ID_SHIFT);
>> +
>> +writel_relaxed(val, base);
>> +}
>> +
>> +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];
> 
> You should validate the hwirq here. For instance, we never expect a
> hwirq < RESERVED_IRQ_PER_MBIGEN_CHIP here.

Yes, I also think I need to check the hwirq input value.
The hwirq should be:
hwirq > RESERVED_IRQ_PER_MBIGEN_CHIP && hwirq < MAXIMUM_INTERRUPT_NUMBER

> 
>> +*type = fwspec->param[1] & IRQ_TY

[PATCH v10 1/4] dt-binding:Documents of the mbigen bindings

2015-12-17 Thread MaJun
From: Ma Jun 

Add the mbigen msi interrupt controller bindings document.

This patch based on Mark Rutland's patch
https://lkml.org/lkml/2015/7/23/558

Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   74 ++
 1 files changed, 74 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100644
index 000..3eaa678
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,74 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2"
+
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+
+- interrupt controller: Identifies the node as an interrupt controller
+
+- msi-parent: Specifies the MSI controller this mbigen use.
+  For more detail information,please refer to the generic msi-parent binding in
+  Documentation/devicetree/bindings/interrupt-controller/msi.txt.
+
+- num-msis:Specifies the total number of interrupt this device has.
+
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value must be 2.
+
+  The 1st cell is hardware pin number of the interrupt.This number is local to
+  each mbigen chip and in the range from 0 to the maximum interrupts number
+  of the mbigen.
+
+  The 2nd cell is the interrupt trigger type.
+   The value of this cell should be:
+   1: rising edge triggered
+   or
+   4: high level triggered
+
+Examples:
+
+   mbigen_device_gmac:intc {
+   compatible = "hisilicon,mbigen-v2";
+   reg = <0x0 0xc008 0x0 0x1>;
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b1c>;
+   num-msis = <9>;
+   #interrupt-cells = <2>;
+   };
+
+Devices connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen device node which device connected.
+
+-interrupts:Specifies the interrupt source.
+ For the specific information of each cell in this property,please refer to
+ the "interrupt-cells" description mentioned above.
+
+Examples:
+   gmac0: ethernet@c208 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   reg = <0 0xc208 0 0x2>,
+ <0 0xc000 0 0x1000>;
+   interrupt-parent  = <&mbigen_device_gmac>;
+   interrupts =<656 1>,
+   <657 1>;
+   };
+
-- 
1.7.1


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


[PATCH v10 4/4] irqchip:implement the mbigen irq chip operation functions

2015-12-17 Thread MaJun
From: Ma Jun 

Add the interrupt controller chip operation functions of mbigen chip.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |   81 ++
 1 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 98865b1..a6856f2 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -50,6 +50,20 @@
 #define REG_MBIGEN_VEC_OFFSET  0x200
 
 /**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0xa000
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
+
+/**
  * struct mbigen_device - holds the information of mbigen device.
  *
  * @pdev:  pointer to the platform device structure of mbigen chip.
@@ -72,8 +86,75 @@ static inline unsigned int 
get_mbigen_vec_reg(irq_hw_number_t hwirq)
+ REG_MBIGEN_VEC_OFFSET;
 }
 
+static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
+   u32 *mask, u32 *addr)
+{
+   unsigned int nid, irq_ofst, ofst;
+
+   hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+   nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
+   irq_ofst = hwirq % IRQS_PER_MBIGEN_NODE;
+
+   *mask = 1 << (irq_ofst % 32);
+   ofst = irq_ofst / 32 * 4;
+
+   *addr = ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
+   u32 *mask, u32 *addr)
+{
+   unsigned int ofst;
+
+   hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+   ofst = hwirq / 32 * 4;
+
+   *mask = 1 << (hwirq % 32);
+   *addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+   void __iomem *base = data->chip_data;
+   u32 mask, addr;
+
+   get_mbigen_clear_reg(data->hwirq, &mask, &addr);
+
+   writel_relaxed(mask, base + addr);
+
+   irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *data, unsigned int type)
+{
+   void __iomem *base = data->chip_data;
+   u32 mask, addr, val;
+
+   if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+   return -EINVAL;
+
+   get_mbigen_type_reg(data->hwirq, &mask, &addr);
+
+   val = readl_relaxed(base + addr);
+
+   if (type == IRQ_TYPE_LEVEL_HIGH)
+   val |= mask;
+   else
+   val &= ~mask;
+
+   writel_relaxed(val, base + addr);
+
+   return 0;
+}
+
 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)
-- 
1.7.1


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


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

2015-12-17 Thread MaJun
From: Ma Jun 

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 patch since v6 is based on this new patch.

Changes in v10:
--- Changed some dts file accroidng to Mark's comment.
--- Fixed some wrong variable type problem.
--- Validate the input value in translate function.
Changes in v9:
--- Fixed typo problem (dts)
--- Removed superfluous data structures
--- Changed clear register offset
Changes in v8:
--- Fixed some tiny bugs.
Changes in v7:
--- Fixed the build test error when applied patch v6 3/4
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 |   74 ++
 drivers/irqchip/Kconfig  |8 +
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |  297 ++
 4 files changed, 380 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v10 2/4] irqchip: add platform device driver for mbigen device

2015-12-17 Thread MaJun
From: Ma Jun 

Mbigen means Message Based Interrupt Generator(MBIGEN).

Its a kind of interrupt controller that collects
the interrupts from external devices and generate msi interrupt.
Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is
increasing much, especially on the Arm64 server SOC.

Therefore, the interrupt pin in GIC is not enough to cover so
many peripherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

Mbigen chip hardware structure shows as below:

mbigen chip
|-|---|
mgn_node0 mgn_node1 mgn_node2
 |   |---|  |---|--|
dev1dev1dev2dev1   dev3   dev4

Each mbigen chip contains several mbigen nodes.

External devices can connect to mbigen node through wire connecting way.

Because a mbigen node only can support 128 interrupt maximum, depends
on the interrupt lines number of devices, a device can connects to one
more mbigen nodes.

Also, several different devices can connect to a same mbigen node.

When devices triggered interrupt,mbigen chip detects and collects
the interrupts and generates the MBI interrupts by writing the ITS
Translator register.

To simplify mbigen driver,I used a new conception--mbigen device.
Each mbigen device is initialized as a platform device.

Mbigen device presents the parts(register, pin definition etc.) in
mbigen chip corresponding to a peripheral device.

So from software view, the structure likes below

mbigen chip
 |-|-|
mbigen device1   mbigen device2  mbigen device3
  |   ||
 dev1dev2 dev3

Reviewed-by: Marc Zyngier 
Signed-off-by: Ma Jun 
---
 drivers/irqchip/Kconfig  |8 
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |   78 ++
 3 files changed, 87 insertions(+), 0 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4d7294e..b205e15 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -27,6 +27,14 @@ config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
 
+config HISILICON_IRQ_MBIGEN
+   bool "Support mbigen interrupt controller"
+   default n
+   depends on ARM_GIC_V3 && ARM_GIC_V3_ITS && GENERIC_MSI_IRQ_DOMAIN
+   help
+Enable the mbigen interrupt controller used on
+Hisilicon platform.
+
 config ARM_NVIC
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 177f78f..cd76b11 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o 
irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o 
irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 000..9f036c2
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * 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.
+ */
+struct mbigen_device {
+   struct platform_device  *pdev;
+   void __iomem*base;
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip;
+   struct resource *res;
+
+   mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+   if (!mgn_chip)

[PATCH v10 3/4] irqchip:create irq domain for each mbigen device

2015-12-17 Thread MaJun
From: Ma Jun 

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 
---
 drivers/irqchip/irq-mbigen.c |  138 ++
 1 files changed, 138 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 9f036c2..98865b1 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -16,13 +16,39 @@
  * along with this program.  If not, see .
  */
 
+#include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
+/* Interrupt numbers per mbigen node supported */
+#define IRQS_PER_MBIGEN_NODE   128
+
+/* 64 irqs (Pin0-pin63) are reserved for each mbigen chip */
+#define RESERVED_IRQ_PER_MBIGEN_CHIP   64
+
+/* The maximum IRQ pin number of mbigen chip(start from 0) */
+#define MAXIMUM_IRQ_PIN_NUM1407
+
+/**
+ * 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.
  *
@@ -34,10 +60,107 @@ struct mbigen_device {
void __iomem*base;
 };
 
+static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
+{
+   unsigned int nid, pin;
+
+   hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+   nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
+   pin = hwirq % IRQS_PER_MBIGEN_NODE;
+
+   return pin * 4 + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_VEC_OFFSET;
+}
+
+static struct irq_chip mbigen_irq_chip = {
+   .name = "mbigen-v2",
+};
+
+static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+   struct irq_data *d = irq_get_irq_data(desc->irq);
+   void __iomem *base = d->chip_data;
+   u32 val;
+
+   base += get_mbigen_vec_reg(d->hwirq);
+   val = readl_relaxed(base);
+
+   val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
+   val |= (msg->data << IRQ_EVENT_ID_SHIFT);
+
+   /* The address of doorbell is encoded in mbigen register by default
+* So,we don't need to program the doorbell address at here
+*/
+   writel_relaxed(val, base);
+}
+
+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;
+
+   if ((fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM) ||
+   (fwspec->param[0] < RESERVED_IRQ_PER_MBIGEN_CHIP))
+   return -EINVAL;
+   else
+   *hwirq = fwspec->param[0];
+
+   /* If there is no valid irq type, just use the default type */
+   if ((fwspec->param[1] == IRQ_TYPE_EDGE_RISING) ||
+   (fwspec->param[1] == IRQ_TYPE_LEVEL_HIGH))
+   *type = fwspec->param[1];
+   else
+   *type = IRQ_TYPE_NONE;
+
+   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;
+   unsigned int type;
+   struct mbigen_device *mgn_chip;
+   int i, err;
+
+   err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
+   if (err)
+   return err;
+
+   err = platform_msi_domain_alloc(domain, virq, nr_irqs);
+   if (err)
+   return err;
+
+   mgn_chip = platform_msi_get_host_data(domain);
+
+   for (i = 0; i < nr_irqs; i++)
+   irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &mbigen_irq_chip, mgn_chip->base);
+
+   return 0;
+}
+
+static struct irq_domain_ops mbigen_domain_ops = {
+   .translate  = mbigen_domain_translate,
+   .alloc  = mbigen_irq_domain_alloc,
+   .free   = irq_domain_free_irqs_common,
+};
+
 static int mbigen_device_probe(struct platform_device *pdev)
 {
struct mbigen_device *mgn_chip;
struct resource *res;
+   struct irq_domain *domain;
+   u32 num_msis;
 
mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*

Re: [PATCH v10 0/4] irqchip:support mbigen interrupt controller

2015-12-18 Thread majun
Hi Marc and Mark:

On 2015/12/18 6:58, Marc Zyngier wrote:
> On 17/12/15 11:56, MaJun wrote:
>> From: Ma Jun 
>>
>> This patch set adds the driver of mbigen and binding document for Hisilicon
>> Mbigen chips.
> 
> [...]
> 
> I've reworked the nits noticed by Mark and stashed this in my
> irq/wire-msi-bridge branch.
> 

Thanks for your reviewing and great help.

Thanks again!
MaJun


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


Re: [PATCH v9 1/4] dt-binding:Documents of the mbigen bindings

2015-12-08 Thread majun
Hi Mark:
Do you have any comments about this patch?
Thanks!
Ma Jun

On 2015/12/3 11:21, Marc Zyngier wrote:
> On 23/11/15 03:15, MaJun wrote:
>> From: Ma Jun 
>>
>> Add the mbigen msi interrupt controller bindings document.
>>
>> This patch based on Mark Rutland's patch
>> https://lkml.org/lkml/2015/7/23/558
>>
>> Signed-off-by: Ma Jun 
>> ---
> 
> Mark,
> 
> Do you mind having a look at this from a DT perspective?
> 
> Thanks,
> 
>   M.
> 
>>  Documentation/devicetree/bindings/arm/mbigen.txt |   69 
>> ++
>>  1 files changed, 69 insertions(+), 0 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt
>>
>> diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
>> b/Documentation/devicetree/bindings/arm/mbigen.txt
>> new file mode 100644
>> index 000..8ae59a9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/arm/mbigen.txt
>> @@ -0,0 +1,69 @@
>> +Hisilicon mbigen device tree bindings.
>> +===
>> +
>> +Mbigen means: message based interrupt generator.
>> +
>> +MBI is kind of msi interrupt only used on Non-PCI devices.
>> +
>> +To reduce the wired interrupt number connected to GIC,
>> +Hisilicon designed mbigen to collect and generate interrupt.
>> +
>> +
>> +Non-pci devices can connect to mbigen and generate the
>> +interrupt by writing ITS register.
>> +
>> +The mbigen chip and devices connect to mbigen have the following properties:
>> +
>> +Mbigen main node required properties:
>> +---
>> +- compatible: Should be "hisilicon,mbigen-v2"
>> +- reg: Specifies the base physical address and size of the Mbigen
>> +  registers.
>> +- interrupt controller: Identifies the node as an interrupt controller
>> +- msi-parent: This property has two cells.
>> +The 1st cell specifies the ITS this device connected.
>> +The 2nd cell specifies the device id.
>> +- num-msis:Specifies the total number of interrupt this device has.
>> +- #interrupt-cells : Specifies the number of cells needed to encode an
>> +  interrupt source. The value must be 2.
>> +
>> +  The 1st cell is global hardware pin number of the interrupt.
>> +This value depends on the Soc design.
>> +
>> +  The 2nd cell is the interrupt trigger type.
>> +The value of this cell should be:
>> +1: rising edge triggered
>> +or
>> +4: high level triggered 
>> +
>> +Examples:
>> +
>> +mbigen_device_gmac:intc {
>> +compatible = "hisilicon,mbigen-v2";
>> +reg = <0x0 0xc008 0x0 0x1>;
>> +interrupt-controller;
>> +msi-parent = <&its_dsa 0x40b1c>;
>> +num-msis = <9>;
>> +#interrupt-cells = <2>;
>> +};
>> +
>> +Devices connect to mbigen required properties:
>> +
>> +-interrupt-parent: Specifies the mbigen device node which device connected.
>> +-interrupts:specifies the interrupt source.
>> +  The 1st cell is global hardware pin number of the interrupt.
>> +This value depends on the Soc design.
>> +  The 2nd cell is the interrupt trigger type(rising edge triggered or high
>> +level triggered)
>> +
>> +Examples:
>> +gmac0: ethernet@c208 {
>> +#address-cells = <1>;
>> +#size-cells = <0>;
>> +reg = <0 0xc208 0 0x2>,
>> +  <0 0xc000 0 0x1000>;
>> +interrupt-parent  = <&mbigen_device_gmac>;
>> +interrupts =<656 1>,
>> +<657 1>;
>> +};
>> +
>>
> 
> 

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


[PATCH v2 1/5] dt-binding: Change the mbigen binding file to support the mbigen-v1

2016-02-15 Thread MaJun
From: Ma Jun 

Add the "hisilicon,mbigen-v1" string in binding file.
Signed-off-by: Ma Jun 
---
 .../interrupt-controller/hisilicon,mbigen-v2.txt   |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
index 720f7c9..bdd1dea 100644
--- 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
@@ -16,7 +16,7 @@ The mbigen chip and devices connect to mbigen have the 
following properties:
 
 Mbigen main node required properties:
 ---
-- compatible: Should be "hisilicon,mbigen-v2"
+- compatible: Should be "hisilicon,mbigen-v2" or "hisilicon,mbigen-v1"
 
 - reg: Specifies the base physical address and size of the Mbigen
   registers.
-- 
1.7.1




[PATCH v2 0/5] irqchip: Add support for Hisilicon mbigen v1 chip

2016-02-15 Thread MaJun
From: Ma Jun 

This patch set is used to support the mbigen v1 chip.
Compared to mbigen v2 chip, the main difference between them is
register layout(address,format)

As a sequence of this difference, the functions used to get or calculate
register address are also changed for this reason.

Changes in v2:
--- Fixed the build test error when applied patch v1 3/5

Ma Jun (5):
  dt-binding: Change the mbigen binding file to support the mbigen-v1
  dt-binding:Rename the mbigen binding file name
  irqchip: add platform device driver for mbigen device
  irqchip:create irq domain for each mbigen device
  irqchip:implement the mbigen irq chip operation functions

 .../interrupt-controller/hisilicon,mbigen-v2.txt   |   74 -
 .../interrupt-controller/hisilicon,mbigen.txt  |   74 +
 drivers/irqchip/Makefile   |2 +-
 drivers/irqchip/irq-mbigen-v1.c|  287 
 4 files changed, 362 insertions(+), 75 deletions(-)
 delete mode 100644 
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 create mode 100644 
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt
 create mode 100644 drivers/irqchip/irq-mbigen-v1.c




[PATCH v2 5/5] irqchip:implement the mbigen irq chip operation functions

2016-02-15 Thread MaJun
From: Ma Jun 

Add the interrupt controller chip operation functions of mbigen chip.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen-v1.c |   75 +++
 1 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen-v1.c b/drivers/irqchip/irq-mbigen-v1.c
index 61e7ad0..0636165 100644
--- a/drivers/irqchip/irq-mbigen-v1.c
+++ b/drivers/irqchip/irq-mbigen-v1.c
@@ -41,6 +41,20 @@
 #define REG_MBIGEN_EXT_VEC_OFFSET  0x320
 
 /**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0x100
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
+
+/**
  * struct mbigen_device - holds the information of mbigen device.
  *
  * @pdev:  pointer to the platform device structure of mbigen chip.
@@ -77,8 +91,69 @@ static inline unsigned int 
get_mbigen_vec_reg(irq_hw_number_t hwirq)
return (nid - 4) * 4 + REG_MBIGEN_EXT_VEC_OFFSET;
 }
 
+static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
+   u32 *mask, u32 *addr)
+{
+   int ofst;
+
+   ofst = hwirq / 32 * 4;
+   *mask = 1 << (hwirq % 32);
+
+   *addr = ofst + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
+   u32 *mask, u32 *addr)
+{
+   unsigned int ofst;
+
+   ofst = hwirq / 32 * 4;
+
+   *mask = 1 << (hwirq % 32);
+   *addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+   void __iomem *base = data->chip_data;
+   u32 mask, addr;
+
+   get_mbigen_clear_reg(data->hwirq, &mask, &addr);
+
+   writel_relaxed(mask, base + addr);
+
+   irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *data, unsigned int type)
+{
+   void __iomem *base = data->chip_data;
+   u32 mask, addr, val;
+
+   if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+   return -EINVAL;
+
+   get_mbigen_type_reg(data->hwirq, &mask, &addr);
+
+   val = readl_relaxed(base + addr);
+
+   if (type == IRQ_TYPE_LEVEL_HIGH)
+   val |= mask;
+   else
+   val &= ~mask;
+
+   writel_relaxed(val, base + addr);
+
+   return 0;
+}
+
 static struct irq_chip mbigen_irq_chip = {
.name = "mbigen-v1",
+   .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)
-- 
1.7.1




[PATCH v2 4/5] irqchip:create irq domain for each mbigen device

2016-02-15 Thread MaJun
From: Ma Jun 

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 
---
 drivers/irqchip/irq-mbigen-v1.c |  136 +++
 1 files changed, 136 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen-v1.c b/drivers/irqchip/irq-mbigen-v1.c
index 9445658..61e7ad0 100644
--- a/drivers/irqchip/irq-mbigen-v1.c
+++ b/drivers/irqchip/irq-mbigen-v1.c
@@ -16,11 +16,30 @@
  * along with this program.  If not, see .
  */
 
+#include 
+#include 
 #include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
 
+/* The maximum IRQ pin number of mbigen chip(start from 0) */
+#define MAXIMUM_IRQ_PIN_NUM640
+
+/**
+ * In mbigen vector register
+ * bit[31:16]: device id
+ * bit[15:0]:  event id value
+ */
+#define IRQ_EVENT_ID_MASK  0x
+
+/* offset of vector register in mbigen node */
+#define REG_MBIGEN_VEC_OFFSET  0x300
+#define REG_MBIGEN_EXT_VEC_OFFSET  0x320
+
 /**
  * struct mbigen_device - holds the information of mbigen device.
  *
@@ -32,10 +51,112 @@ struct mbigen_device {
void __iomem*base;
 };
 
+static int get_mbigen_nid(unsigned int offset)
+{
+   int nid = 0;
+
+   if (offset < 256)
+   nid = offset / 64;
+   else if (offset < 384)
+   nid = 4;
+   else if (offset < 640)
+   nid = 5;
+
+   return nid;
+}
+
+static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
+{
+   unsigned int nid;
+
+   nid = get_mbigen_nid(hwirq);
+
+   if (nid < 4)
+   return (nid * 4) + REG_MBIGEN_VEC_OFFSET;
+   else
+   return (nid - 4) * 4 + REG_MBIGEN_EXT_VEC_OFFSET;
+}
+
+static struct irq_chip mbigen_irq_chip = {
+   .name = "mbigen-v1",
+};
+
+static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+   /* The address of doorbell is encoded in mbigen register by default
+* So,we don't need to program the doorbell address at here
+* Besides, the event ID is decided by the hardware pin number,
+* we can't change it in software.So, we don't need to encode the
+* event ID in mbigen register.
+*/
+}
+
+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;
+
+   if (fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM)
+   return -EINVAL;
+
+   *hwirq = fwspec->param[0];
+
+   /* If there is no valid irq type, just use the default type */
+   if ((fwspec->param[1] == IRQ_TYPE_EDGE_RISING) ||
+   (fwspec->param[1] == IRQ_TYPE_LEVEL_HIGH))
+   *type = fwspec->param[1];
+   else
+   return -EINVAL;
+
+   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;
+   unsigned int type;
+   struct mbigen_device *mgn_chip;
+   int i, err;
+
+   err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
+   if (err)
+   return err;
+
+   err = platform_msi_domain_alloc(domain, virq, nr_irqs);
+   if (err)
+   return err;
+
+   mgn_chip = platform_msi_get_host_data(domain);
+
+   for (i = 0; i < nr_irqs; i++)
+   irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &mbigen_irq_chip, mgn_chip->base);
+
+   return 0;
+}
+
+static struct irq_domain_ops mbigen_domain_ops = {
+   .translate  = mbigen_domain_translate,
+   .alloc  = mbigen_irq_domain_alloc,
+   .free   = irq_domain_free_irqs_common,
+};
+
 static int mbigen_device_probe(struct platform_device *pdev)
 {
struct mbigen_device *mgn_chip;
struct resource *res;
+   struct irq_domain *domain;
+   u32 num_pins;
 
mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
if (!mgn_chip)
@@ -48,8 +169,23 @@ static int mbigen_device_probe(struct platform_device *pdev)
if (IS_ERR(mgn_chip->base))
return PTR_ERR(mgn_chip->base);
 
+   if (of_property_read_u32(pdev->dev.of_node, "num-pins", &num_pins) < 0) 
{
+   dev_err(&

[PATCH v2 2/5] dt-binding:Rename the mbigen binding file name

2016-02-15 Thread MaJun
From: Ma Jun 

Because added the mbigen-v1 compatible string, the origin name is
not suitable any more. So,I remove the version number from file name.

Signed-off-by: Ma Jun 
---
 .../interrupt-controller/hisilicon,mbigen-v2.txt   |   74 
 .../interrupt-controller/hisilicon,mbigen.txt  |   74 
 2 files changed, 74 insertions(+), 74 deletions(-)
 delete mode 100644 
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 create mode 100644 
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
deleted file mode 100644
index bdd1dea..000
--- 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-Hisilicon mbigen device tree bindings.
-===
-
-Mbigen means: message based interrupt generator.
-
-MBI is kind of msi interrupt only used on Non-PCI devices.
-
-To reduce the wired interrupt number connected to GIC,
-Hisilicon designed mbigen to collect and generate interrupt.
-
-
-Non-pci devices can connect to mbigen and generate the
-interrupt by writing ITS register.
-
-The mbigen chip and devices connect to mbigen have the following properties:
-
-Mbigen main node required properties:

-- compatible: Should be "hisilicon,mbigen-v2" or "hisilicon,mbigen-v1"
-
-- reg: Specifies the base physical address and size of the Mbigen
-  registers.
-
-- interrupt controller: Identifies the node as an interrupt controller
-
-- msi-parent: Specifies the MSI controller this mbigen use.
-  For more detail information,please refer to the generic msi-parent binding in
-  Documentation/devicetree/bindings/interrupt-controller/msi.txt.
-
-- num-pins: the total number of pins implemented in this Mbigen
-  instance.
-
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source. The value must be 2.
-
-  The 1st cell is hardware pin number of the interrupt.This number is local to
-  each mbigen chip and in the range from 0 to the maximum interrupts number
-  of the mbigen.
-
-  The 2nd cell is the interrupt trigger type.
-   The value of this cell should be:
-   1: rising edge triggered
-   or
-   4: high level triggered
-
-Examples:
-
-   mbigen_device_gmac:intc {
-   compatible = "hisilicon,mbigen-v2";
-   reg = <0x0 0xc008 0x0 0x1>;
-   interrupt-controller;
-   msi-parent = <&its_dsa 0x40b1c>;
-   num-pins = <9>;
-   #interrupt-cells = <2>;
-   };
-
-Devices connect to mbigen required properties:
-
--interrupt-parent: Specifies the mbigen device node which device connected.
-
--interrupts:Specifies the interrupt source.
- For the specific information of each cell in this property,please refer to
- the "interrupt-cells" description mentioned above.
-
-Examples:
-   gmac0: ethernet@c208 {
-   #address-cells = <1>;
-   #size-cells = <0>;
-   reg = <0 0xc208 0 0x2>,
- <0 0xc000 0 0x1000>;
-   interrupt-parent  = <&mbigen_device_gmac>;
-   interrupts =<656 1>,
-   <657 1>;
-   };
diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt
new file mode 100644
index 000..bdd1dea
--- /dev/null
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt
@@ -0,0 +1,74 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2" or "hisilicon,mbigen-v1"
+
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+
+- interrupt controller: Identifies the node as an interrupt controller
+
+- msi-parent: Specifies the MSI controller this mbigen use.
+  For more detail information,please refer to the generic msi-parent binding in
+  Documentation/devicetree/bindings/interrupt-controller/msi.txt.
+
+- num-pins: the total number of pins implemented in this Mbigen
+  i

[PATCH v2 3/5] irqchip: add platform device driver for mbigen device

2016-02-15 Thread MaJun
From: Ma Jun 

Add the platform device driver for mbigen chip v1.
This patch just same as mbigen v2.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/Makefile|2 +-
 drivers/irqchip/irq-mbigen-v1.c |   76 +++
 2 files changed, 77 insertions(+), 1 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen-v1.c

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d91d99d..d4b9c7f 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_REALVIEW_DT) += irq-gic-realview.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o 
irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
-obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o irq-mbigen-v1.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen-v1.c b/drivers/irqchip/irq-mbigen-v1.c
new file mode 100644
index 000..9445658
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen-v1.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * 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.
+ */
+struct mbigen_device {
+   struct platform_device  *pdev;
+   void __iomem*base;
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip;
+   struct resource *res;
+
+   mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+   if (!mgn_chip)
+   return -ENOMEM;
+
+   mgn_chip->pdev = pdev;
+
+   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
+   if (IS_ERR(mgn_chip->base))
+   return PTR_ERR(mgn_chip->base);
+
+   platform_set_drvdata(pdev, mgn_chip);
+
+   return 0;
+}
+
+static const struct of_device_id mbigen_of_match[] = {
+   { .compatible = "hisilicon,mbigen-v1" },
+   { /* END */ }
+};
+MODULE_DEVICE_TABLE(of, mbigen_of_match);
+
+static struct platform_driver mbigen_platform_driver = {
+   .driver = {
+   .name   = "Hisilicon MBIGEN-V1",
+   .owner  = THIS_MODULE,
+   .of_match_table = mbigen_of_match,
+   },
+   .probe  = mbigen_device_probe,
+};
+
+module_platform_driver(mbigen_platform_driver);
+
+MODULE_AUTHOR("Jun Ma ");
+MODULE_AUTHOR("Yun Wu ");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hisilicon MBI Generator driver");
-- 
1.7.1




[PATCH v3 2/2] irqchip/mbigen:Change the mbigen driver based on the new mbigen node definition.

2016-03-19 Thread MaJun
From: Ma Jun 

In current mbigen driver, each mbigen device is initialized as a platform 
device.
When these devices belong to same mbigen hardware module(chip), they use the
same register definition in their device node and caused the problem of 
registers
remapped repeatedly.

Now, I try to initialize the mbigen module(chip) as a platform device and remap
the register once to fix this problem.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |   30 +-
 1 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 4dd3eb8..4d413bc 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -242,6 +242,8 @@ static int mbigen_device_probe(struct platform_device *pdev)
struct resource *res;
struct irq_domain *domain;
u32 num_pins;
+   struct platform_device *child_pdev;
+   struct device_node *np;
 
mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
if (!mgn_chip)
@@ -251,25 +253,35 @@ static int mbigen_device_probe(struct platform_device 
*pdev)
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
+
if (IS_ERR(mgn_chip->base))
return PTR_ERR(mgn_chip->base);
 
-   if (of_property_read_u32(pdev->dev.of_node, "num-pins", &num_pins) < 0) 
{
-   dev_err(&pdev->dev, "No num-pins property\n");
-   return -EINVAL;
-   }
+   for_each_child_of_node(pdev->dev.of_node, np) {
+   if (!of_property_read_bool(np, "interrupt-controller"))
+   continue;
+
+   child_pdev = of_platform_device_create(np, NULL, 
platform_bus_type.dev_root);
+   if (IS_ERR(child_pdev))
+   return PTR_ERR(child_pdev);
+
+   if (of_property_read_u32(child_pdev->dev.of_node, "num-pins", 
&num_pins) < 0) {
+   dev_err(&pdev->dev, "No num-pins property\n");
+   return -EINVAL;
+   }
 
-   domain = platform_msi_create_device_domain(&pdev->dev, num_pins,
+   domain = platform_msi_create_device_domain(&child_pdev->dev, 
num_pins,
mbigen_write_msg,
&mbigen_domain_ops,
mgn_chip);
 
-   if (!domain)
-   return -ENOMEM;
+   if (!domain)
+   return -ENOMEM;
 
-   platform_set_drvdata(pdev, mgn_chip);
+   dev_info(&child_pdev->dev, "Allocated %d MSIs\n", num_pins);
+   }
 
-   dev_info(&pdev->dev, "Allocated %d MSIs\n", num_pins);
+   platform_set_drvdata(pdev, mgn_chip);
 
return 0;
 }
-- 
1.7.1




[RFC PATCH] genirq: Change the non-balanced irq to balance irq when the cpu of the irq bounded off line

2016-03-31 Thread MaJun
From: Ma Jun 

When the CPU of a non-balanced irq bounded is off line, the irq will be 
migrated to other CPUs,
usually the first cpu on-line.

We can suppose the situation if a system has more than one non-balanced irq.
At extreme case, these irqs will be migrated to the same CPU and will cause the 
CPU run with high irq pressure, even make the system die.

So, I think maybe we need to change the non-balanced irq to a irq can be
balanced to avoid the problem descried above.

Maybe this is not a good solution for this problem, please offer me some
suggestion if you have a better one.

Signed-off-by: Ma Jun 
---
 kernel/irq/cpuhotplug.c |2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c
index 011f8c4..80d54a5 100644
--- a/kernel/irq/cpuhotplug.c
+++ b/kernel/irq/cpuhotplug.c
@@ -30,6 +30,8 @@ static bool migrate_one_irq(struct irq_desc *desc)
return false;
 
if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
+   if (irq_settings_has_no_balance_set(desc))
+   irqd_clear(d, IRQD_NO_BALANCING);
affinity = cpu_online_mask;
ret = true;
}
-- 
1.7.1




[PATCH v8 4/4] irqchip:implement the mbigen irq chip operation functions

2015-11-06 Thread MaJun
From: Ma Jun 

Add the interrupt controller chip operation functions of mbigen chip.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |  102 +++--
 1 files changed, 97 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 71291cb..155c210 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -46,6 +46,19 @@
 /* offset of vector register in mbigen node */
 #define REG_MBIGEN_VEC_OFFSET  0x200
 
+/**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0xa00
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
 
 /**
  * struct mbigen_device - holds the information of mbigen device.
@@ -64,11 +77,19 @@ struct mbigen_device {
  * struct mbigen_irq_data - private data of each irq
  *
  * @base:  mapped address of mbigen chip
+ * @pin_offset:local pin offset of interrupt.
  * @reg_vec:   addr offset of interrupt vector register.
+ * @reg_type:  addr offset of interrupt trigger type register.
+ * @reg_clear: addr offset of interrupt clear register.
+ * @type:  interrupt trigger type.
  */
 struct mbigen_irq_data {
void __iomem*base;
+   unsigned intpin_offset;
unsigned intreg_vec;
+   unsigned intreg_type;
+   unsigned intreg_clear;
+   unsigned inttype;
 };
 
 static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
@@ -77,8 +98,68 @@ static inline int get_mbigen_vec_reg(u32 nid, u32 offset)
+ REG_MBIGEN_VEC_OFFSET;
 }
 
+static int get_mbigen_type_reg(u32 nid, u32 offset)
+{
+   int ofst;
+
+   ofst = offset / 32 * 4;
+   return ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static int get_mbigen_clear_reg(u32 nid, u32 offset)
+{
+   int ofst;
+
+   ofst = offset / 32 * 4;
+   return ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(data);
+   u32 mask;
+
+   /* only level triggered interrupt need to clear status */
+   if (mgn_irq_data->type == IRQ_TYPE_LEVEL_HIGH) {
+   mask = 1 << (mgn_irq_data->pin_offset % 32);
+   writel_relaxed(mask, mgn_irq_data->reg_clear + 
mgn_irq_data->base);
+   }
+
+   irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *d, unsigned int type)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(d);
+   u32 mask;
+   int val;
+
+   if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+   return -EINVAL;
+
+   mask = 1 << (mgn_irq_data->pin_offset % 32);
+
+   val = readl_relaxed(mgn_irq_data->reg_type + mgn_irq_data->base);
+
+   if (type == IRQ_TYPE_LEVEL_HIGH)
+   val |= mask;
+   else if (type == IRQ_TYPE_EDGE_RISING)
+   val &= ~mask;
+
+   writel_relaxed(val, mgn_irq_data->reg_type + mgn_irq_data->base);
+
+   return 0;
+}
+
 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)
@@ -94,10 +175,11 @@ static void mbigen_write_msg(struct msi_desc *desc, struct 
msi_msg *msg)
writel_relaxed(val, mgn_irq_data->reg_vec + mgn_irq_data->base);
 }
 
-static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq)
+static struct mbigen_irq_data *set_mbigen_irq_data(int hwirq,
+   unsigned int type)
 {
struct mbigen_irq_data *datap;
-   unsigned int nid, pin_offset;
+   unsigned int nid;
 
datap = kzalloc(sizeof(*datap), GFP_KERNEL);
if (!datap)
@@ -106,10 +188,20 @@ static struct mbigen_irq_data *set_mbigen_irq_data(int 
hwirq)
/* 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)
+   datap->pin_offset = (hwirq - RESERVED_IRQ_PER_MBIGEN_CHIP)
% IRQS_PER_MBIGEN_NODE;
 
-   datap->reg_vec = get_mbigen_vec_reg(nid, pin_offset);
+   datap->reg_vec = get_mbigen_vec_reg(nid, datap->pin_offset);
+   datap->reg_type = get_mbigen_type_reg(ni

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

2015-11-06 Thread MaJun
From: Ma Jun 

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 v8:
--- Fixed some tiny bugs.
Changes in v7:
--- Fixed the build test error when applied patch v6 3/4
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 |  328 ++
 4 files changed, 400 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 1/4] dt-binding:Documents of the mbigen bindings

2015-11-06 Thread MaJun
From: Ma Jun 

Add the mbigen msi interrupt controller bindings document.

This patch based on Mark Rutland's patch
https://lkml.org/lkml/2015/7/23/558

Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   63 ++
 1 files changed, 63 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100644
index 000..eb9a7fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,63 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2"
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+- interrupt controller: Identifies the node as an interrupt controller
+- msi-parent: This property has two cells.
+   The 1st cell specifies the ITS this device connected.
+   The 2nd cell specifies the device id.
+- nr-msis:Specifies the total number of interrupt this device has.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value is 2 now.
+
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type.
+
+Examples:
+
+   mbigen_device_gmac:intc {
+   compatible = "hisilicon,mbigen-v2";
+   reg = <0x0 0xc008 0x0 0x1>;
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b1c>;
+   num-msis = <9>;
+   #interrupt-cells = <2>;
+   };
+
+Devices connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen device node which device connected.
+-interrupts:specifies the interrupt source.
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type
+
+Examples:
+   gmac0: ethernet@c208 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   reg = <0 0xc208 0 0x2>,
+ <0 0xc000 0 0x1000>;
+   interrupt-parent  = <&mbigen_device_gmac>;
+   interrupts =<656 1>,
+   <657 1>;
+   };
+
-- 
1.7.1


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


[PATCH v8 2/4] irqchip: add platform device driver for mbigen device

2015-11-06 Thread MaJun
From: Ma Jun 

Mbigen means Message Based Interrupt Generator(MBIGEN).

Its a kind of interrupt controller that collects
the interrupts from external devices and generate msi interrupt.
Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is
increasing much, especially on the Arm64 server SOC.

Therefore, the interrupt pin in GIC is not enough to cover so
many peripherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

Mbigen chip hardware structure shows as below:

mbigen chip
|-|---|
mgn_node0 mgn_node1 mgn_node2
 |   |---|  |---|--|
dev1dev1dev2dev1   dev3   dev4

Each mbigen chip contains several mbigen nodes.

External devices can connect to mbigen node through wire connecting way.

Because a mbigen node only can support 128 interrupt maximum, depends
on the interrupt lines number of devices, a device can connects to one
more mbigen nodes.

Also, several different devices can connect to a same mbigen node.

When devices triggered interrupt,mbigen chip detects and collects
the interrupts and generates the MBI interrupts by writing the ITS
Translator register.

To simplify mbigen driver,I used a new conception--mbigen device.
Each mbigen device is initialized as a platform device.

Mbigen device presents the parts(register, pin definition etc.) in
mbigen chip corresponding to a peripheral device.

So from software view, the structure likes below

mbigen chip
 |-|-|
mbigen device1   mbigen device2  mbigen device3
  |   ||
 dev1dev2 dev3

Signed-off-by: Ma Jun 
---
 drivers/irqchip/Kconfig  |8 
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |   73 ++
 3 files changed, 82 insertions(+), 0 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4d7294e..b205e15 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -27,6 +27,14 @@ config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
 
+config HISILICON_IRQ_MBIGEN
+   bool "Support mbigen interrupt controller"
+   default n
+   depends on ARM_GIC_V3 && ARM_GIC_V3_ITS && GENERIC_MSI_IRQ_DOMAIN
+   help
+Enable the mbigen interrupt controller used on
+Hisilicon platform.
+
 config ARM_NVIC
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 177f78f..cd76b11 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o 
irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o 
irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 000..25e4000
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * 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.
+ */
+struct mbigen_device {
+   struct platform_device  *pdev;
+   void __iomem*base;
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip;
+
+   mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+   if (!mgn_chip)
+   return -ENOMEM;
+
+   mgn_chip->pdev

[PATCH v8 3/4] irqchip:create irq domain for each mbigen device

2015-11-06 Thread MaJun
From: Ma Jun 

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 
---
 drivers/irqchip/irq-mbigen.c |  163 ++
 1 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 25e4000..71291cb 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -16,27 +16,176 @@
  * along with this program.  If not, see .
  */
 
+#include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
+/* 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 intreg_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",
+};
+
+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;
+   unsigned int type;
+   struct mbigen_device *mgn_chip;
+   struct mbigen_irq_data *mgn_irq_data;
+   int i, err;
+
+   err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
+   if (err)
+   return 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);
+
+ 

[PATCH v9 1/4] dt-binding:Documents of the mbigen bindings

2015-11-22 Thread MaJun
From: Ma Jun 

Add the mbigen msi interrupt controller bindings document.

This patch based on Mark Rutland's patch
https://lkml.org/lkml/2015/7/23/558

Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   69 ++
 1 files changed, 69 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100644
index 000..8ae59a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,69 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2"
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+- interrupt controller: Identifies the node as an interrupt controller
+- msi-parent: This property has two cells.
+   The 1st cell specifies the ITS this device connected.
+   The 2nd cell specifies the device id.
+- num-msis:Specifies the total number of interrupt this device has.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value must be 2.
+
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+
+  The 2nd cell is the interrupt trigger type.
+   The value of this cell should be:
+   1: rising edge triggered
+   or
+   4: high level triggered 
+
+Examples:
+
+   mbigen_device_gmac:intc {
+   compatible = "hisilicon,mbigen-v2";
+   reg = <0x0 0xc008 0x0 0x1>;
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b1c>;
+   num-msis = <9>;
+   #interrupt-cells = <2>;
+   };
+
+Devices connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen device node which device connected.
+-interrupts:specifies the interrupt source.
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd cell is the interrupt trigger type(rising edge triggered or high
+   level triggered)
+
+Examples:
+   gmac0: ethernet@c208 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   reg = <0 0xc208 0 0x2>,
+ <0 0xc000 0 0x1000>;
+   interrupt-parent  = <&mbigen_device_gmac>;
+   interrupts =<656 1>,
+   <657 1>;
+   };
+
-- 
1.7.1


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


[PATCH v9 2/4] irqchip: add platform device driver for mbigen device

2015-11-22 Thread MaJun
From: Ma Jun 

Mbigen means Message Based Interrupt Generator(MBIGEN).

Its a kind of interrupt controller that collects
the interrupts from external devices and generate msi interrupt.
Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is
increasing much, especially on the Arm64 server SOC.

Therefore, the interrupt pin in GIC is not enough to cover so
many peripherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

Mbigen chip hardware structure shows as below:

mbigen chip
|-|---|
mgn_node0 mgn_node1 mgn_node2
 |   |---|  |---|--|
dev1dev1dev2dev1   dev3   dev4

Each mbigen chip contains several mbigen nodes.

External devices can connect to mbigen node through wire connecting way.

Because a mbigen node only can support 128 interrupt maximum, depends
on the interrupt lines number of devices, a device can connects to one
more mbigen nodes.

Also, several different devices can connect to a same mbigen node.

When devices triggered interrupt,mbigen chip detects and collects
the interrupts and generates the MBI interrupts by writing the ITS
Translator register.

To simplify mbigen driver,I used a new conception--mbigen device.
Each mbigen device is initialized as a platform device.

Mbigen device presents the parts(register, pin definition etc.) in
mbigen chip corresponding to a peripheral device.

So from software view, the structure likes below

mbigen chip
 |-|-|
mbigen device1   mbigen device2  mbigen device3
  |   ||
 dev1dev2 dev3
Signed-off-by: Ma Jun 
---
 drivers/irqchip/Kconfig  |8 
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |   78 ++
 3 files changed, 87 insertions(+), 0 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4d7294e..b205e15 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -27,6 +27,14 @@ config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
 
+config HISILICON_IRQ_MBIGEN
+   bool "Support mbigen interrupt controller"
+   default n
+   depends on ARM_GIC_V3 && ARM_GIC_V3_ITS && GENERIC_MSI_IRQ_DOMAIN
+   help
+Enable the mbigen interrupt controller used on
+Hisilicon platform.
+
 config ARM_NVIC
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 177f78f..cd76b11 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o 
irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o 
irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 000..9f036c2
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * 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.
+ */
+struct mbigen_device {
+   struct platform_device  *pdev;
+   void __iomem*base;
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip;
+   struct resource *res;
+
+   mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+   if (!mgn_chip)
+   return -ENO

[PATCH v9 4/4] irqchip:implement the mbigen irq chip operation functions

2015-11-22 Thread MaJun
From: Ma Jun 

Add the interrupt controller chip operation functions of mbigen chip.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |   84 ++
 1 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 81ae61f..540ad05 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -47,6 +47,20 @@
 #define REG_MBIGEN_VEC_OFFSET  0x200
 
 /**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0xa000
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
+
+/**
  * struct mbigen_device - holds the information of mbigen device.
  *
  * @pdev:  pointer to the platform device structure of mbigen chip.
@@ -69,8 +83,78 @@ static inline unsigned int 
get_mbigen_vec_reg(irq_hw_number_t hwirq)
+ REG_MBIGEN_VEC_OFFSET;
 }
 
+static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
+   unsigned int *mask,
+   unsigned int *addr)
+{
+   unsigned int nid, pin, ofst;
+
+   hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+   nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
+   pin = hwirq % IRQS_PER_MBIGEN_NODE;
+
+   *mask = 1 << (pin % 32);
+   
+   ofst = pin / 32 * 4;
+   *addr = ofst + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
+   unsigned int *mask,
+   unsigned int *addr)
+{
+   unsigned int ofst;
+
+   hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+   ofst = hwirq / 32 * 4;
+
+   *mask = 1 << (hwirq % 32);
+   *addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+   void __iomem *base = data->chip_data;
+   unsigned int mask, addr;
+
+   get_mbigen_clear_reg(data->hwirq, &mask, &addr);
+
+   writel_relaxed(mask, base + addr);
+
+   irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *data, unsigned int type)
+{
+   void __iomem *base = data->chip_data;
+   unsigned int mask, addr;
+   u32 val;
+
+   if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+   return -EINVAL;
+
+   get_mbigen_type_reg(data->hwirq, &mask, &addr);
+
+   val = readl_relaxed(base + addr);
+
+   if (type == IRQ_TYPE_LEVEL_HIGH)
+   val |= mask;
+   else
+   val &= ~mask;
+
+   writel_relaxed(val, base + addr);
+
+   return 0;
+}
+
 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)
-- 
1.7.1


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


[PATCH v9 3/4] irqchip:create irq domain for each mbigen device

2015-11-22 Thread MaJun
From: Ma Jun 

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 
---
 drivers/irqchip/irq-mbigen.c |  119 ++
 1 files changed, 119 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 9f036c2..81ae61f 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -16,13 +16,36 @@
  * along with this program.  If not, see .
  */
 
+#include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
+/* Interrupt numbers per mbigen node supported */
+#define IRQS_PER_MBIGEN_NODE   128
+
+/* 64 irqs (Pin0-pin63) are reserved for each mbigen chip */
+#define RESERVED_IRQ_PER_MBIGEN_CHIP   64
+
+/**
+ * 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.
  *
@@ -34,10 +57,94 @@ struct mbigen_device {
void __iomem*base;
 };
 
+static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
+{
+   unsigned int nid, pin;
+
+   hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+   nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
+   pin = hwirq % IRQS_PER_MBIGEN_NODE;
+
+   return pin * 4 + nid * MBIGEN_NODE_OFFSET
+   + REG_MBIGEN_VEC_OFFSET;
+}
+
+static struct irq_chip mbigen_irq_chip = {
+   .name = "mbigen-v2",
+};
+
+static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+   struct irq_data *d = irq_get_irq_data(desc->irq);
+   void __iomem *base = d->chip_data;
+   u32 val;
+
+   base += get_mbigen_vec_reg(d->hwirq);
+   val = readl_relaxed(base);
+
+   val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
+   val |= (msg->data << IRQ_EVENT_ID_SHIFT);
+
+   writel_relaxed(val, base);
+}
+
+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;
+   unsigned int type;
+   struct mbigen_device *mgn_chip;
+   int i, err;
+
+   err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
+   if (err)
+   return err;
+
+   err = platform_msi_domain_alloc(domain, virq, nr_irqs);
+   if (err)
+   return err;
+
+   mgn_chip = platform_msi_get_host_data(domain);
+
+   for (i = 0; i < nr_irqs; i++)
+   irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &mbigen_irq_chip, mgn_chip->base);
+
+   return 0;
+}
+
+static struct irq_domain_ops mbigen_domain_ops = {
+   .translate  = mbigen_domain_translate,
+   .alloc  = mbigen_irq_domain_alloc,
+   .free   = irq_domain_free_irqs_common,
+};
+
 static int mbigen_device_probe(struct platform_device *pdev)
 {
struct mbigen_device *mgn_chip;
struct resource *res;
+   struct irq_domain *domain;
+   u32 num_msis;
 
mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
if (!mgn_chip)
@@ -50,6 +157,18 @@ static int mbigen_device_probe(struct platform_device *pdev)
if (IS_ERR(mgn_chip->base))
return PTR_ERR(mgn_chip->base);
 
+   /* If there is no "num-msis" 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;
+
  

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

2015-11-22 Thread MaJun
From: Ma Jun 

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 v9:
--- Fixed typo problem (dts)
--- Removed superfluous data structures
--- Changed clear register offset
Changes in v8:
--- Fixed some tiny bugs.
Changes in v7:
--- Fixed the build test error when applied patch v6 3/4
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 |   69 ++
 drivers/irqchip/Kconfig  |8 +
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |  281 ++
 4 files changed, 359 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v5 1/3] initialize each mbigen device node as a interrupt controller.

2015-09-30 Thread MaJun
From: Ma Jun 

Mbigen means Message Based Interrupt Generator(MBIGEN).

Its a kind of interrupt controller that collects

the interrupts from external devices and generate msi interrupt.

Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is 
increasing much, especially on the Arm64 server soc.

Therefore, the interrupt pin in gic is not enough to cover so
many peripherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

Mbigen chip hardware structure shows as below:

mbigen chip
|-|---|
mgn_node0 mgn_node1 mgn_node2
 |   |---|  |---|--|
dev1dev1dev2dev1   dev3   dev4

Each mbigen chip contains several mbigen nodes.

External devices can connect to mbigen node through wire connecting way.

Because a mbigen node only can support 128 interrupt maximum, depends
on the interrupt lines number of devices, a device can connects to one
more mbigen nodes.

Also, several different devices can connect to a same mbigen node.

When devices triggered interrupt,mbigen chip detects and collects 
the interrupts and generates the MBI interrupts by writing the ITS
Translator register.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |  346 ++
 1 files changed, 346 insertions(+), 0 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen.c

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 000..e05a0ed
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "irqchip.h"
+
+
+/* Interrupt numbers per mbigen node supported */
+#define IRQS_PER_MBIGEN_NODE   (128)
+
+/* Pin0-pin15 total 16 irqs are reserved for each mbigen chip*/
+#define RESERVED_IRQ_PER_MBIGEN_CHIP (16)
+
+#define MBIGEN_INDEX_SHIFT (12)
+
+/*
+ * To calculate the register addr of interrupt, the private index value
+ * also should be included except the hardware pin offset value.
+ *
+ * hwirq[23:12]: index. private index value of interrupt.
+   Start from 0 for a device.
+ * hwirq[11:0]: pin. hardware pin offset of this interrupt
+ */
+#defineCOMPOSE_MBIGEN_HWIRQ(index, pin)\
+   (((index) << MBIGEN_INDEX_SHIFT) | (pin))
+
+/* get the interrupt pin offset from mbigen hwirq */
+#defineGET_IRQ_PIN_OFFSET(hwirq)   ((hwirq) & 0xfff)
+/* get the private index value from mbigen hwirq */
+#define GET_IRQ_INDEX(hwirq)   (((hwirq) >> MBIGEN_INDEX_SHIFT) & 0xfff)
+
+/*
+ * 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 mbigen node  */
+#define MBIGEN_NODE_OFFSET 0x1000
+
+/* offset of vector register in mbigen node */
+#define REG_MBIGEN_VEC_OFFSET  0x200
+
+/* offset of clear register in mbigen node.
+ * This register is used to clear the status
+ * of interrupt.
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0xa00
+
+/*
+ * get the base address of mbigen node
+ * nid: mbigen node number
+ */
+#define MBIGEN_NODE_ADDR_BASE(nid) ((nid) * MBIGEN_NODE_OFFSET)
+
+/*
+ * struct mbigen_device--Holds the  information of devices connected
+ * to mbigen chip
+ * @domain: irq domain of this mbigen device.
+ * @global_entry: node in a global mbigen device list.
+ * @node: represents the mbigen device node defined in device tree.
+ * @mgn_data: pointer to mbigen_irq_data
+ * @nr_irqs: the total interrupt lines of this device
+ * @base: mapped address of mbigen chip which this mbigen device connected.
+*/
+struct mbigen_device {
+   struct irq_domain   *domain;
+   struct list_headglobal_entry;
+   struct device_node  *node;
+   struct mbigen_irq_data  *mgn_data;
+   unsigned intnr_irqs;
+   void __iomem*base;
+};
+
+/*
+ * struct irq_priv_info--structure of irq corresponding information.
+ *
+ * @global_pin_off

[PATCH v5 2/3] Probe mbigen chip and initial mbigen device as platform device.

2015-09-30 Thread MaJun
From: Ma Jun 

After initializing mbigen device as interrupt controller,
this patch is used to probe mbigen chip and initial mbigen
device as a platform device so as to allocate msi-irqs 
within ITS-pMSI domain.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |  203 ++
 1 files changed, 203 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index e05a0ed..5951180 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -82,22 +82,45 @@
 #define MBIGEN_NODE_ADDR_BASE(nid) ((nid) * MBIGEN_NODE_OFFSET)
 
 /*
+ * struct mbigen_chip - holds the information of mbigen
+ * chip.
+ * @lock: spin lock protecting mbigen device list
+ * @pdev: pointer to the platform device structure of mbigen chip.
+ * @local_mgn_dev_list: list of devices connected to this mbigen chip.
+ * @base: mapped address of this mbigen chip.
+ */
+struct mbigen_chip {
+   raw_spinlock_t  lock;
+   struct platform_device *pdev;
+   struct list_headlocal_mgn_dev_list;
+   void __iomem*base;
+};
+
+/*
  * struct mbigen_device--Holds the  information of devices connected
  * to mbigen chip
+ * @lock: spin lock protecting mbigen node list
  * @domain: irq domain of this mbigen device.
+ * @local_entry: node in mbigen chip's mbigen_device_list
  * @global_entry: node in a global mbigen device list.
  * @node: represents the mbigen device node defined in device tree.
  * @mgn_data: pointer to mbigen_irq_data
  * @nr_irqs: the total interrupt lines of this device
  * @base: mapped address of mbigen chip which this mbigen device connected.
+ * @chip: pointer to mbigen chip
+ * @pdev: pointer to platform device structure of this mbigen device.
 */
 struct mbigen_device {
+   raw_spinlock_t  lock;
struct irq_domain   *domain;
+   struct list_headlocal_entry;
struct list_headglobal_entry;
struct device_node  *node;
struct mbigen_irq_data  *mgn_data;
unsigned intnr_irqs;
void __iomem*base;
+   struct mbigen_chip  *chip;
+   struct platform_device *pdev;
 };
 
 /*
@@ -340,6 +363,186 @@ out_free_dev:
 }
 IRQCHIP_DECLARE(hisi_mbigen, "hisilicon,mbigen-intc-v2", mbigen_intc_of_init);
 
+static struct mbigen_device *find_mbigen_device(struct device_node *node)
+{
+   struct mbigen_device *dev = NULL, *tmp;
+
+   spin_lock(&mbigen_device_lock);
+
+   list_for_each_entry(tmp, &mbigen_device_list, global_entry) {
+   if (tmp->node == node) {
+   dev = tmp;
+   break;
+   }
+   }
+   spin_unlock(&mbigen_device_lock);
+
+   return dev;
+}
+
+static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_get_handler_data(desc->irq);
+   struct mbigen_device *mgn_dev = mgn_irq_data->dev;
+   struct irq_priv_info *info = &mgn_irq_data->info;
+   u32 val;
+
+   val = readl_relaxed(info->reg_offset + mgn_dev->base);
+
+   val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
+   val |= (msg->data << IRQ_EVENT_ID_SHIFT);
+
+   writel_relaxed(val, info->reg_offset + mgn_dev->base);
+}
+
+static void mbigen_device_free(struct mbigen_device *mgn_dev)
+{
+   struct msi_desc *desc;
+
+   for_each_msi_entry(desc, &mgn_dev->pdev->dev) {
+   free_irq(desc->irq, mgn_dev);
+   }
+
+   platform_msi_domain_free_irqs(&mgn_dev->pdev->dev);
+
+   /* delete mgn_dev from global mbigen device list*/
+   spin_lock(&mbigen_device_lock);
+   list_del(&mgn_dev->global_entry);
+   spin_unlock(&mbigen_device_lock);
+
+   irq_domain_remove(mgn_dev->domain);
+   kfree(mgn_dev->mgn_data);
+   kfree(mgn_dev);
+}
+
+static void mbigen_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
+{
+   struct mbigen_irq_data *mgn_irq_data = irq_get_handler_data(irq);
+
+   if (unlikely(!mgn_irq_data->dev_irq))
+   handle_bad_irq(mgn_irq_data->dev_irq, desc);
+   else
+   generic_handle_irq(mgn_irq_data->dev_irq);
+}
+
+
+static void mbigen_set_irq_handler_data(struct msi_desc *desc,
+   struct mbigen_device *mgn_dev)
+{
+   struct mbigen_irq_data *mgn_irq_data;
+
+   mgn_irq_data = &mgn_dev->mgn_data[desc->platform.msi_index];
+
+   mgn_irq_data->dev = mgn_dev;
+   mgn_irq_data->msi_irq = desc->irq;
+
+   irq_set_handler_data(desc->irq, mgn_irq_data);
+}
+
+/*
+ * Initial mbigen chip and mbigen device.
+ */
+static int mbigen_chip_probe(struct platform_device *pdev)
+{
+   struct mbigen_chip *mgn_chip;
+   struct device *dev = &pdev->dev;
+   struct device_node *root = dev->of_node, *child;
+   struct platform_device *mgn_pdev;
+   struct mbigen_device *mgn_dev;
+   struct ms

[PATCH v5 0/3] Support Mbigen interrupt controller

2015-09-30 Thread MaJun
From: Ma Jun 

This patch 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 

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 (3):
  initialize each mbigen device node as a interrupt controller.
  Probe mbigen chip and initial mbigen device as platform device.
  dt-binding:Documents of the mbigen bindings

 Documentation/devicetree/bindings/arm/mbigen.txt |   85 
 drivers/irqchip/irq-mbigen.c |  549 ++
 2 files changed, 634 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v5 3/3] dt-binding:Documents of the mbigen bindings

2015-09-30 Thread MaJun
From: Ma Jun 

Add the mbigen msi interrupt controller bindings document.

This patch based on Mark Rutland's patch 
https://lkml.org/lkml/2015/7/23/558 

Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   85 ++
 1 files changed, 85 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100644
index 000..f5345ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,85 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2"
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+
+Sub-nodes:
+-
+Mbigen has one or more mbigen device nodes which represents the devices
+connected to this mbigen chip.
+
+These nodes must have the following properties:
+- compatible: Should be "hisilicon,mbigen-intc-v2"
+- interrupt controller: Identifies the node as an interrupt controller
+- msi-parent: This property has two cells.
+   The 1st cell specifies the ITS this device connected.
+   The 2nd cell specifies the device id.
+- nr-interrupts:Specifies the total number of interrupt this device has.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value is 2 now.
+
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd the private index of the device. For a device with n interrupts,
+   this value is from 0 ~ n-1.
+
+Examples:
+
+   mbigen_dsa: interrupt-controller@c008 {
+   compatible = "hisilicon,mbigen-v2";
+   reg = <0xc008 0x1>;
+
+   mbigen_device_gmac0 {
+   compatible = "hisilicon,mbigen-intc-v2";
+   interrupt-controller;
+   msi-parent = <&its 0x40b1c>;
+   nr-interrupts = <9>;
+   #interrupt-cells = <2>;
+   }
+
+   mbigen_device_02 {
+   compatible = "hisilicon,mbigen-intc-v2";
+   interrupt-controller;
+   msi-parent = <&its 0x40b1d>;
+   nr-interrupts = <3>;
+   #interrupt-cells = <2>;
+   }
+   };
+
+Device connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen device node which device connected.
+-interrupts:specifies the interrupt source.
+  The 1st cell is global hardware pin number of the interrupt.
+   This value depends on the Soc design.
+  The 2nd the private index of the device. For a device with n interrupts,
+   this value is from 0 ~ n-1.
+
+Examples:
+   gmac0: ethernet@c208 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   reg = <0 0xc208 0 0x2>,
+ <0 0xc000 0 0x1000>;
+   interrupt-parent  = <&mbigen_device_gmac0>;
+   interrupts = <656 0>,
+   <657 1>;
+   };
+
-- 
1.7.1


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


[PATCH] ACPI: fix the process flow for 0 which return from acpi_register_gsi

2016-10-11 Thread MaJun
The return value 0 from acpi_register_gsi() means irq mapping failed.
So, we should process this case in else branch.

Signed-off-by: MaJun 
---
 drivers/acpi/resource.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 56241eb..9918326 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -416,7 +416,7 @@ static void acpi_dev_get_irqresource(struct resource *res, 
u32 gsi,
 
res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
-   if (irq >= 0) {
+   if (irq > 0) {
res->start = irq;
res->end = irq;
} else {
-- 
1.7.12.4




[PATCH] ACPI: fix the process flow for 0 which return from acpi_register_gsi

2016-11-30 Thread Majun
From: MaJun 

The return value 0 from acpi_register_gsi() means irq mapping failed.
So, we should process this case in else branch.

Signed-off-by: MaJun 
---
 drivers/acpi/resource.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 56241eb..9918326 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -416,7 +416,7 @@ static void acpi_dev_get_irqresource(struct resource *res, 
u32 gsi,
 
res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
-   if (irq >= 0) {
+   if (irq > 0) {
res->start = irq;
res->end = irq;
} else {
-- 
1.7.12.4




[RFC PATCH 2/3] irqchip/gicv3-its: add a new flag to control indirect route in DT mode

2016-11-30 Thread Majun
From: MaJun 

Add a new flag for ITS node in DT mode so we can disable/enable the
indirect route function.

Signed-off-by: MaJun 
---
 drivers/irqchip/irq-gic-v3-its.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index d278425..ee54133 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -46,6 +46,7 @@
 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING  (1ULL << 0)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375  (1ULL << 1)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_23144  (1ULL << 2)
+#define ITS_FLAGS_INDIRECT_ROUTE   (1ULL << 3)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING(1 << 0)
 
@@ -967,7 +968,7 @@ static bool its_parse_baser_device(struct its_node *its, 
struct its_baser *baser
bool indirect = false;
 
/* No need to enable Indirection if memory requirement < (psz*2)bytes */
-   if ((esz << ids) > (psz * 2)) {
+   if ((its->flags & ITS_FLAGS_INDIRECT_ROUTE) && ((esz << ids) > (psz * 
2))) {
/*
 * Find out whether hw supports a single or two-level table by
 * table by reading bit at offset '62' after writing '1' to it.
@@ -1673,8 +1674,8 @@ static int its_init_domain(struct fwnode_handle *handle, 
struct its_node *its)
return 0;
 }
 
-static int __init its_probe_one(struct resource *res,
-   struct fwnode_handle *handle, int numa_node)
+static int __init its_probe_one(struct resource *res, struct fwnode_handle 
*handle,
+   int numa_node, u8 flags)
 {
struct its_node *its;
void __iomem *its_base;
@@ -1716,6 +1717,7 @@ static int __init its_probe_one(struct resource *res,
its->phys_base = res->start;
its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
its->numa_node = numa_node;
+   its->flags |= flags;
 
its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
if (!its->cmd_base) {
@@ -1812,6 +1814,7 @@ static int __init its_of_probe(struct device_node *node)
 {
struct device_node *np;
struct resource res;
+   u8 flags = 0;
 
for (np = of_find_matching_node(node, its_device_id); np;
 np = of_find_matching_node(np, its_device_id)) {
@@ -1826,7 +1829,10 @@ static int __init its_of_probe(struct device_node *node)
continue;
}
 
-   its_probe_one(&res, &np->fwnode, of_node_to_nid(np));
+   if (of_property_read_bool(np, "two-level-route"))
+   flags |= ITS_FLAGS_INDIRECT_ROUTE;
+
+   its_probe_one(&res, &np->fwnode, of_node_to_nid(np), flags);
}
return 0;
 }
@@ -1863,7 +1869,7 @@ static int __init gic_acpi_parse_madt_its(struct 
acpi_subtable_header *header,
goto dom_err;
}
 
-   err = its_probe_one(&res, dom_handle, NUMA_NO_NODE);
+   err = its_probe_one(&res, dom_handle, NUMA_NO_NODE, 0);
if (!err)
return 0;
 
-- 
1.7.12.4




[RFC PATCH 0/3] Add a new flag for ITS device to control indirect route

2016-11-30 Thread Majun
From: MaJun 

For current ITS driver, two level table (indirect route) is enabled when the 
memory used
for LPI route table over the limit(64KB * 2) size. But this function impact the 
performance of LPI interrupt actually because need more time to look up the 
table.

Although this function can save the memory needed, we'd better let the user
to decide enable or disable this function.

MaJun (3):
  Binding: Add a new property string in ITS node to control the two-level route 
function
  irqchip/gicv3-its:irqchip/gicv3-its: add a new flag to control indirect route 
in DT mode
  irqchip/gicv3-its:irqchip/gicv3-its: Add a new flag to control indirect route 
function in ACPI mode.

 .../bindings/interrupt-controller/arm,gic-v3.txt  |  3 +++
 drivers/irqchip/irq-gic-v3-its.c  | 19 ++-
 include/acpi/actbl1.h |  3 ++-
 3 files changed, 19 insertions(+), 6 deletions(-)

-- 
1.7.12.4




[RFC PATCH 1/3]Binding: Add a new property string in ITS node to control the two-level route function

2016-11-30 Thread Majun
From: MaJun 

Add the two-level-route property in ITS node.
When this property string defined, two-level route(indirect) function
will be enabled in ITS driver, otherwise disable it.

Signed-off-by: MaJun 
---
 Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt 
b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
index 4c29cda..e9f4a9c 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
@@ -74,6 +74,8 @@ These nodes must have the following properties:
   which will generate the MSI.
 - reg: Specifies the base physical address and size of the ITS
   registers.
+- two-level-route: This is an optional property which means enable the two 
level
+  route property when look up route table.
 
 The main GIC node must contain the appropriate #address-cells,
 #size-cells and ranges properties for the reg property of all ITS
@@ -97,6 +99,7 @@ Examples:
 
gic-its@2c20 {
compatible = "arm,gic-v3-its";
+   two-level-route;
msi-controller;
#msi-cells = <1>;
reg = <0x0 0x2c20 0 0x20>;
-- 
1.7.12.4




[RFC PATCH 3/3]irqchip/gicv3-its: Add a new flag to control indirect route in ACPI mode.

2016-11-30 Thread Majun
From: MaJun 

Add a new flag to control indirect route function for ACPI mode.
To carry the user defined flags information, we used the reserved byte
in ITS MADT table

Signed-off-by: MaJun 
---
 drivers/irqchip/irq-gic-v3-its.c | 5 -
 include/acpi/actbl1.h| 3 ++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index ee54133..4420283 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1848,6 +1848,7 @@ static int __init gic_acpi_parse_madt_its(struct 
acpi_subtable_header *header,
struct fwnode_handle *dom_handle;
struct resource res;
int err;
+   u8 flags = 0;
 
its_entry = (struct acpi_madt_generic_translator *)header;
memset(&res, 0, sizeof(res));
@@ -1855,6 +1856,8 @@ static int __init gic_acpi_parse_madt_its(struct 
acpi_subtable_header *header,
res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1;
res.flags = IORESOURCE_MEM;
 
+   flags = its_entry->flags;
+
dom_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address);
if (!dom_handle) {
pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n",
@@ -1869,7 +1872,7 @@ static int __init gic_acpi_parse_madt_its(struct 
acpi_subtable_header *header,
goto dom_err;
}
 
-   err = its_probe_one(&res, dom_handle, NUMA_NO_NODE, 0);
+   err = its_probe_one(&res, dom_handle, NUMA_NO_NODE, flags);
if (!err)
return 0;
 
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 796d6ba..42a08ae 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -930,7 +930,8 @@ struct acpi_madt_generic_translator {
u16 reserved;   /* reserved - must be zero */
u32 translation_id;
u64 base_address;
-   u32 reserved2;
+   u8 flags;
+   u8 reserved2[3];
 };
 
 /*
-- 
1.7.12.4




[PATCH] generic: Add the exception case checking routine for ppi interrupt

2016-08-29 Thread MaJun
From: Ma Jun 

During system booting, if the interrupt which has no action registered
is triggered, it would cause system panic when try to access the
action member.

Signed-off-by: Ma Jun 
---
 kernel/irq/chip.c |   20 
 1 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 8114d06..9a0e872 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -766,11 +766,23 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
  */
 void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc)
 {
-   struct irq_chip *chip = irq_desc_get_chip(desc);
-   struct irqaction *action = desc->action;
-   void *dev_id = raw_cpu_ptr(action->percpu_dev_id);
+   struct irq_chip *chip = NULL;
+   struct irqaction *action;
+   void *dev_id;
irqreturn_t res;
 
+   action = desc->action;
+
+   /* Unexpected interrupt in some execption case
+* we just send eoi to end this interrupt
+*/
+   if (unlikely(!action)) {
+   mask_irq(desc);
+   goto out;
+   }
+   dev_id = raw_cpu_ptr(action->percpu_dev_id);
+
+   chip = irq_desc_get_chip(desc);
kstat_incr_irqs_this_cpu(irq, desc);
 
if (chip->irq_ack)
@@ -779,7 +791,7 @@ void handle_percpu_devid_irq(unsigned int irq, struct 
irq_desc *desc)
trace_irq_handler_entry(irq, action);
res = action->handler(irq, dev_id);
trace_irq_handler_exit(irq, action, res);
-
+out:
if (chip->irq_eoi)
chip->irq_eoi(&desc->irq_data);
 }
-- 
1.7.1




[PATCH v2 0/2] Irq/Mbigen: fix the IO remap problem in mbigen driver.

2016-03-13 Thread MaJun
From: Ma Jun 

This patch set is used to fix the problem of remap a set of registers
repeatedly.

Changes in v2:
--- Change the mbigen device node definition
--- Change the mbigen driver based on the new mbigen dts structure.

Ma Jun (2):
  Irq/mbigen:Change the mbigen node definition in dt binding file
  Irq/mbigen:Change the mbigen driver based on the new mbigen node definition

 .../interrupt-controller/hisilicon,mbigen-v2.txt   |   22 +++---
 drivers/irqchip/irq-mbigen.c   |   30 ++--
 2 files changed, 38 insertions(+), 14 deletions(-)




[PATCH v2 1/2] Irq/mbigen:Change the mbigen node definition in dt binding file

2016-03-13 Thread MaJun
From: Ma Jun 

For mbigen module, there is a special case that more than one mbigen
device nodes use the same reg definition in DTS when these devices
exist in the same mbigen hardware module.

To fix the mbigen IO remap problem, the mbigen node definition and
structure are changed based on Mark Rutland's suggestion.

Signed-off-by: Ma Jun 
---
 .../interrupt-controller/hisilicon,mbigen-v2.txt   |   22 +++
 1 files changed, 17 insertions(+), 5 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
index 720f7c9..3b2f4c4 100644
--- 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
@@ -21,6 +21,8 @@ Mbigen main node required properties:
 - reg: Specifies the base physical address and size of the Mbigen
   registers.
 
+Mbigen sub node required properties:
+--
 - interrupt controller: Identifies the node as an interrupt controller
 
 - msi-parent: Specifies the MSI controller this mbigen use.
@@ -45,13 +47,23 @@ Mbigen main node required properties:
 
 Examples:
 
-   mbigen_device_gmac:intc {
+   mbigen_chip_dsa {
compatible = "hisilicon,mbigen-v2";
reg = <0x0 0xc008 0x0 0x1>;
-   interrupt-controller;
-   msi-parent = <&its_dsa 0x40b1c>;
-   num-pins = <9>;
-   #interrupt-cells = <2>;
+
+   mbigen_gmac:intc_gmac {
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b1c>;
+   num-pins = <9>;
+   #interrupt-cells = <2>;
+   };
+
+   mbigen_i2c:intc_i2c {
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b0e>;
+   num-pins = <2>;
+   #interrupt-cells = <2>;
+   };
};
 
 Devices connect to mbigen required properties:
-- 
1.7.1




[PATCH v2 2/2] Irq/mbigen:Change the mbigen driver based on the new mbigen node definition.

2016-03-13 Thread MaJun
From: Ma Jun 

To fix the IO remap problem, change the mbigen driver based on the
new mbigen node definition.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |   30 +-
 1 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 4dd3eb8..4d413bc 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -242,6 +242,8 @@ static int mbigen_device_probe(struct platform_device *pdev)
struct resource *res;
struct irq_domain *domain;
u32 num_pins;
+   struct platform_device *child_pdev;
+   struct device_node *np;
 
mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
if (!mgn_chip)
@@ -251,25 +253,35 @@ static int mbigen_device_probe(struct platform_device 
*pdev)
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
+
if (IS_ERR(mgn_chip->base))
return PTR_ERR(mgn_chip->base);
 
-   if (of_property_read_u32(pdev->dev.of_node, "num-pins", &num_pins) < 0) 
{
-   dev_err(&pdev->dev, "No num-pins property\n");
-   return -EINVAL;
-   }
+   for_each_child_of_node(pdev->dev.of_node, np) {
+   if (!of_property_read_bool(np, "interrupt-controller"))
+   continue;
+
+   child_pdev = of_platform_device_create(np, NULL, 
platform_bus_type.dev_root);
+   if (IS_ERR(child_pdev))
+   return PTR_ERR(child_pdev);
+
+   if (of_property_read_u32(child_pdev->dev.of_node, "num-pins", 
&num_pins) < 0) {
+   dev_err(&pdev->dev, "No num-pins property\n");
+   return -EINVAL;
+   }
 
-   domain = platform_msi_create_device_domain(&pdev->dev, num_pins,
+   domain = platform_msi_create_device_domain(&child_pdev->dev, 
num_pins,
mbigen_write_msg,
&mbigen_domain_ops,
mgn_chip);
 
-   if (!domain)
-   return -ENOMEM;
+   if (!domain)
+   return -ENOMEM;
 
-   platform_set_drvdata(pdev, mgn_chip);
+   dev_info(&child_pdev->dev, "Allocated %d MSIs\n", num_pins);
+   }
 
-   dev_info(&pdev->dev, "Allocated %d MSIs\n", num_pins);
+   platform_set_drvdata(pdev, mgn_chip);
 
return 0;
 }
-- 
1.7.1




[PATCH 2/2] irqchip/mbigen:Change the config option of mbigen driver to non-configurable

2016-03-23 Thread MaJun
From: Ma Jun 

This config is selected by CONFIG_ARCH_HISI, So we change
this config to non-configurable.

I also adjust the mbigen config position try to sort the configs
in alphabetical order.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/Kconfig |   14 ++
 1 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 7e8c441..3e12479 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -32,14 +32,6 @@ config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
 
-config HISILICON_IRQ_MBIGEN
-   bool "Support mbigen interrupt controller"
-   default n
-   depends on ARM_GIC_V3 && ARM_GIC_V3_ITS && GENERIC_MSI_IRQ_DOMAIN
-   help
-Enable the mbigen interrupt controller used on
-Hisilicon platform.
-
 config ARM_NVIC
bool
select IRQ_DOMAIN
@@ -114,6 +106,12 @@ config DW_APB_ICTL
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
 
+config HISILICON_IRQ_MBIGEN
+   bool
+   select ARM_GIC_V3
+   select ARM_GIC_V3_ITS
+   select GENERIC_MSI_IRQ_DOMAIN
+
 config IMGPDC_IRQ
bool
select GENERIC_IRQ_CHIP
-- 
1.7.1




[PATCH 0/2] Change the the config option of mbigen driver.

2016-03-23 Thread MaJun
From: Ma Jun 

In current driver, the config of mbigen driver is a configurable option and
have nothing to do with CONFIG_ARCH_HISI.

As a module of Hisilicon SOC, the config of mbigen driver should be selected
by CONFIG_ARCH_HISI on Hisilicon platform, but not a configurable option.

This patch set is applied to fix this problem.

Ma Jun (2):
  ARM64: Enable mbigen interrupt controller on Hisilicon platform
  irqchip/mbigen:Change the config option of mbigen driver to non-configurable

 arch/arm64/Kconfig.platforms |1 +
 drivers/irqchip/Kconfig  |   14 ++
 2 files changed, 7 insertions(+), 8 deletions(-)




[PATCH 1/2]ARM64: Enable mbigen interrupt controller on Hisilicon platform

2016-03-23 Thread MaJun
From: Ma Jun 

As a interrupt controller used on some of hisilicon SOCs(660,1610 etc.),
mbigen driver should be enabled when CONFIG_ARCH_HISI is enabled.
Signed-off-by: Ma Jun 
---
 arch/arm64/Kconfig.platforms |1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 21074f6..fdfd526 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -37,6 +37,7 @@ config ARCH_LAYERSCAPE
 
 config ARCH_HISI
bool "Hisilicon SoC Family"
+   select HISILICON_IRQ_MBIGEN
help
  This enables support for Hisilicon ARMv8 SoC family
 
-- 
1.7.1




[PATCH v3 0/2] irqchip/mbigen: fix the IO remap problem in mbigen driver.

2016-03-19 Thread MaJun
From: Ma Jun 

This patch set is used to fix the problem of remap a set of registers
repeatedly in current mbigen driver.

Changes in v3:
--- Change the log to make more detail description about
the IO remap problem.

Changes in v2:
--- Change the mbigen device node definition as Mark suggested.
--- Change the mbigen driver based on the new mbigen dts structure.

Ma Jun (2):
  irqchip/mbigen:Change the mbigen node definition in dt binding file
  irqchip/mbigen:Change the mbigen driver based on the new mbigen node 
definition

 .../interrupt-controller/hisilicon,mbigen-v2.txt   |   22 +++---
 drivers/irqchip/irq-mbigen.c   |   30 ++--
 2 files changed, 38 insertions(+), 14 deletions(-)




[PATCH v3 1/2] irqchip/mbigen:Change the mbigen node definition in dt binding file

2016-03-19 Thread MaJun
From: Ma Jun 

For mbigen module, there is a special case that more than one mbigen
device nodes use the same reg definition in DTS when these devices
exist in the same mbigen hardware module.

In current mbigen driver, these mbigen devices definition as below:
mbigen_dev1:intc_dev1 {
...
reg = <0x0 0xc008 0x0 0x1>;
...
};

mbigen_dev2:intc_dev2 {
...
reg = <0x0 0xc008 0x0 0x1>;
...
};

On this case, devm_ioremap_resource() returns fail with info
"can't request region for resource" because of memory region check.

To fix this problem, the mbigen node definition and
structure are changed as Mark Rutland suggested in v1 patch[1].

[1] 
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-February/403691.html

Signed-off-by: Ma Jun 
---
 .../interrupt-controller/hisilicon,mbigen-v2.txt   |   22 +++
 1 files changed, 17 insertions(+), 5 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
index 720f7c9..3b2f4c4 100644
--- 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
@@ -21,6 +21,8 @@ Mbigen main node required properties:
 - reg: Specifies the base physical address and size of the Mbigen
   registers.
 
+Mbigen sub node required properties:
+--
 - interrupt controller: Identifies the node as an interrupt controller
 
 - msi-parent: Specifies the MSI controller this mbigen use.
@@ -45,13 +47,23 @@ Mbigen main node required properties:
 
 Examples:
 
-   mbigen_device_gmac:intc {
+   mbigen_chip_dsa {
compatible = "hisilicon,mbigen-v2";
reg = <0x0 0xc008 0x0 0x1>;
-   interrupt-controller;
-   msi-parent = <&its_dsa 0x40b1c>;
-   num-pins = <9>;
-   #interrupt-cells = <2>;
+
+   mbigen_gmac:intc_gmac {
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b1c>;
+   num-pins = <9>;
+   #interrupt-cells = <2>;
+   };
+
+   mbigen_i2c:intc_i2c {
+   interrupt-controller;
+   msi-parent = <&its_dsa 0x40b0e>;
+   num-pins = <2>;
+   #interrupt-cells = <2>;
+   };
};
 
 Devices connect to mbigen required properties:
-- 
1.7.1




[PATCH] Irq/mbigen:Promote the mbigen driver register timing

2016-02-22 Thread MaJun
From: Ma Jun 

Using module_platform_driver() to register mbigen driver is
too late for some driver to apply irq, because the mbigen irq
domain is not created yet. 

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen.c |9 -
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 4dd3eb8..4df359c 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -289,7 +289,14 @@ static struct platform_driver mbigen_platform_driver = {
.probe  = mbigen_device_probe,
 };
 
-module_platform_driver(mbigen_platform_driver);
+static __init int mbigen_init(void)
+
+{
+   return platform_driver_register(&mbigen_platform_driver);
+
+}
+
+arch_initcall(mbigen_init);
 
 MODULE_AUTHOR("Jun Ma ");
 MODULE_AUTHOR("Yun Wu ");
-- 
1.7.1




[PATCH 1/5] dt-binding: Change the mbigen binding file to support the mbigen-v1

2016-02-13 Thread MaJun
From: Ma Jun 

Add the "hisilicon,mbigen-v1" string in binding file.
Signed-off-by: Ma Jun 
---
 .../interrupt-controller/hisilicon,mbigen-v2.txt   |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
index 720f7c9..bdd1dea 100644
--- 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
@@ -16,7 +16,7 @@ The mbigen chip and devices connect to mbigen have the 
following properties:
 
 Mbigen main node required properties:
 ---
-- compatible: Should be "hisilicon,mbigen-v2"
+- compatible: Should be "hisilicon,mbigen-v2" or "hisilicon,mbigen-v1"
 
 - reg: Specifies the base physical address and size of the Mbigen
   registers.
-- 
1.7.1




[PATCH 3/5] irqchip: add platform device driver for mbigen device

2016-02-13 Thread MaJun
From: Ma Jun 

Add the platform device driver for mbigen chip v1.
This patch just same as mbigen v2.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/Makefile|2 +-
 drivers/irqchip/irq-mbigen-v1.c |   76 +++
 2 files changed, 77 insertions(+), 1 deletions(-)
 create mode 100644 drivers/irqchip/irq-mbigen-v1.c

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 83d1fce..3152450 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_REALVIEW_DT) += irq-gic-realview.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o 
irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
-obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o irq-mbigen-v1.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen-v1.c b/drivers/irqchip/irq-mbigen-v1.c
new file mode 100644
index 000..9445658
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen-v1.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma 
+ * Author: Yun Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * 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.
+ */
+struct mbigen_device {
+   struct platform_device  *pdev;
+   void __iomem*base;
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+   struct mbigen_device *mgn_chip;
+   struct resource *res;
+
+   mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+   if (!mgn_chip)
+   return -ENOMEM;
+
+   mgn_chip->pdev = pdev;
+
+   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   mgn_chip->base = devm_ioremap(&pdev->dev, res->start, 
resource_size(res));
+   if (IS_ERR(mgn_chip->base))
+   return PTR_ERR(mgn_chip->base);
+
+   platform_set_drvdata(pdev, mgn_chip);
+
+   return 0;
+}
+
+static const struct of_device_id mbigen_of_match[] = {
+   { .compatible = "hisilicon,mbigen-v1" },
+   { /* END */ }
+};
+MODULE_DEVICE_TABLE(of, mbigen_of_match);
+
+static struct platform_driver mbigen_platform_driver = {
+   .driver = {
+   .name   = "Hisilicon MBIGEN-V1",
+   .owner  = THIS_MODULE,
+   .of_match_table = mbigen_of_match,
+   },
+   .probe  = mbigen_device_probe,
+};
+
+module_platform_driver(mbigen_platform_driver);
+
+MODULE_AUTHOR("Jun Ma ");
+MODULE_AUTHOR("Yun Wu ");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hisilicon MBI Generator driver");
-- 
1.7.1




[PATCH 4/5] irqchip:create irq domain for each mbigen device

2016-02-13 Thread MaJun
From: Ma Jun 

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 
---
 drivers/irqchip/irq-mbigen-v1.c |  144 +++
 1 files changed, 144 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen-v1.c b/drivers/irqchip/irq-mbigen-v1.c
index 9445658..6bbb82a 100644
--- a/drivers/irqchip/irq-mbigen-v1.c
+++ b/drivers/irqchip/irq-mbigen-v1.c
@@ -16,11 +16,30 @@
  * along with this program.  If not, see .
  */
 
+#include 
+#include 
 #include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
 
+/* The maximum IRQ pin number of mbigen chip(start from 0) */
+#define MAXIMUM_IRQ_PIN_NUM640
+
+/**
+ * In mbigen vector register
+ * bit[31:16]: device id
+ * bit[15:0]:  event id value
+ */
+#define IRQ_EVENT_ID_MASK  0x
+
+/* offset of vector register in mbigen node */
+#define REG_MBIGEN_VEC_OFFSET  0x300
+#define REG_MBIGEN_EXT_VEC_OFFSET  0x320
+
 /**
  * struct mbigen_device - holds the information of mbigen device.
  *
@@ -32,10 +51,120 @@ struct mbigen_device {
void __iomem*base;
 };
 
+static int get_mbigen_nid(unsigned int offset)
+{
+   int nid = 0;
+
+   if (offset < 256)
+   nid = offset / 64;
+   else if (offset < 384)
+   nid = 4;
+   else if (offset < 640)
+   nid = 5;
+
+   return nid;
+}
+
+static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
+{
+   unsigned int nid;
+
+   nid = get_mbigen_nid(hwirq);
+
+   if (nid < 4)
+   return (nid * 4) + REG_MBIGEN_VEC_OFFSET;
+   else
+   return (nid - 4) * 4 + REG_MBIGEN_EXT_VEC_OFFSET;
+}
+
+static struct irq_chip mbigen_irq_chip = {
+   .name = "mbigen-v1",
+};
+
+static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+   struct irq_data *d = irq_get_irq_data(desc->irq);
+   void __iomem *base = d->chip_data;
+   u32 val;
+
+   base += get_mbigen_vec_reg(d->hwirq);
+   val = readl_relaxed(base);
+
+   val &= ~IRQ_EVENT_ID_MASK;
+   val |= msg->data;
+
+   /* The address of doorbell is encoded in mbigen register by default
+* So,we don't need to program the doorbell address at here
+*/
+   writel_relaxed(val, base);
+}
+
+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;
+
+   if (fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM)
+   return -EINVAL;
+
+   *hwirq = fwspec->param[0];
+
+   /* If there is no valid irq type, just use the default type */
+   if ((fwspec->param[1] == IRQ_TYPE_EDGE_RISING) ||
+   (fwspec->param[1] == IRQ_TYPE_LEVEL_HIGH))
+   *type = fwspec->param[1];
+   else
+   return -EINVAL;
+
+   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;
+   unsigned int type;
+   struct mbigen_device *mgn_chip;
+   int i, err;
+
+   err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
+   if (err)
+   return err;
+
+   err = platform_msi_domain_alloc(domain, virq, nr_irqs);
+   if (err)
+   return err;
+
+   mgn_chip = platform_msi_get_host_data(domain);
+
+   for (i = 0; i < nr_irqs; i++)
+   irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &mbigen_irq_chip, mgn_chip->base);
+
+   return 0;
+}
+
+static struct irq_domain_ops mbigen_domain_ops = {
+   .translate  = mbigen_domain_translate,
+   .alloc  = mbigen_irq_domain_alloc,
+   .free   = irq_domain_free_irqs_common,
+};
+
 static int mbigen_device_probe(struct platform_device *pdev)
 {
struct mbigen_device *mgn_chip;
struct resource *res;
+   struct irq_domain *domain;
+   u32 num_pins;
 
mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
if (!mgn_chip)
@@ -48,8 +177,23 @@ static int mbigen_device_probe(struct platform_device *pdev)
if (IS_ERR(mgn_chip->base))
return PTR_ERR(mgn_chip->ba

[PATCH 2/5] dt-binding:Rename the mbigen binding file name

2016-02-13 Thread MaJun
From: Ma Jun 

Because added the mbigen-v1 compatible string, the origin name is
not suitable any more. So,I remove the version number from file name.

Signed-off-by: Ma Jun 
---
 .../interrupt-controller/hisilicon,mbigen-v2.txt   |   74 
 .../interrupt-controller/hisilicon,mbigen.txt  |   74 
 2 files changed, 74 insertions(+), 74 deletions(-)
 delete mode 100644 
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 create mode 100644 
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
deleted file mode 100644
index bdd1dea..000
--- 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-Hisilicon mbigen device tree bindings.
-===
-
-Mbigen means: message based interrupt generator.
-
-MBI is kind of msi interrupt only used on Non-PCI devices.
-
-To reduce the wired interrupt number connected to GIC,
-Hisilicon designed mbigen to collect and generate interrupt.
-
-
-Non-pci devices can connect to mbigen and generate the
-interrupt by writing ITS register.
-
-The mbigen chip and devices connect to mbigen have the following properties:
-
-Mbigen main node required properties:

-- compatible: Should be "hisilicon,mbigen-v2" or "hisilicon,mbigen-v1"
-
-- reg: Specifies the base physical address and size of the Mbigen
-  registers.
-
-- interrupt controller: Identifies the node as an interrupt controller
-
-- msi-parent: Specifies the MSI controller this mbigen use.
-  For more detail information,please refer to the generic msi-parent binding in
-  Documentation/devicetree/bindings/interrupt-controller/msi.txt.
-
-- num-pins: the total number of pins implemented in this Mbigen
-  instance.
-
-- #interrupt-cells : Specifies the number of cells needed to encode an
-  interrupt source. The value must be 2.
-
-  The 1st cell is hardware pin number of the interrupt.This number is local to
-  each mbigen chip and in the range from 0 to the maximum interrupts number
-  of the mbigen.
-
-  The 2nd cell is the interrupt trigger type.
-   The value of this cell should be:
-   1: rising edge triggered
-   or
-   4: high level triggered
-
-Examples:
-
-   mbigen_device_gmac:intc {
-   compatible = "hisilicon,mbigen-v2";
-   reg = <0x0 0xc008 0x0 0x1>;
-   interrupt-controller;
-   msi-parent = <&its_dsa 0x40b1c>;
-   num-pins = <9>;
-   #interrupt-cells = <2>;
-   };
-
-Devices connect to mbigen required properties:
-
--interrupt-parent: Specifies the mbigen device node which device connected.
-
--interrupts:Specifies the interrupt source.
- For the specific information of each cell in this property,please refer to
- the "interrupt-cells" description mentioned above.
-
-Examples:
-   gmac0: ethernet@c208 {
-   #address-cells = <1>;
-   #size-cells = <0>;
-   reg = <0 0xc208 0 0x2>,
- <0 0xc000 0 0x1000>;
-   interrupt-parent  = <&mbigen_device_gmac>;
-   interrupts =<656 1>,
-   <657 1>;
-   };
diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt
new file mode 100644
index 000..bdd1dea
--- /dev/null
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt
@@ -0,0 +1,74 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+---
+- compatible: Should be "hisilicon,mbigen-v2" or "hisilicon,mbigen-v1"
+
+- reg: Specifies the base physical address and size of the Mbigen
+  registers.
+
+- interrupt controller: Identifies the node as an interrupt controller
+
+- msi-parent: Specifies the MSI controller this mbigen use.
+  For more detail information,please refer to the generic msi-parent binding in
+  Documentation/devicetree/bindings/interrupt-controller/msi.txt.
+
+- num-pins: the total number of pins implemented in this Mbigen
+  i

[PATCH 5/5] irqchip:implement the mbigen irq chip operation functions

2016-02-13 Thread MaJun
From: Ma Jun 

Add the interrupt controller chip operation functions of mbigen chip.

Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-mbigen-v1.c |   75 +++
 1 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/drivers/irqchip/irq-mbigen-v1.c b/drivers/irqchip/irq-mbigen-v1.c
index 6bbb82a..8291a47 100644
--- a/drivers/irqchip/irq-mbigen-v1.c
+++ b/drivers/irqchip/irq-mbigen-v1.c
@@ -41,6 +41,20 @@
 #define REG_MBIGEN_EXT_VEC_OFFSET  0x320
 
 /**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET0x100
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
+
+/**
  * struct mbigen_device - holds the information of mbigen device.
  *
  * @pdev:  pointer to the platform device structure of mbigen chip.
@@ -77,8 +91,69 @@ static inline unsigned int 
get_mbigen_vec_reg(irq_hw_number_t hwirq)
return (nid - 4) * 4 + REG_MBIGEN_EXT_VEC_OFFSET;
 }
 
+static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
+   u32 *mask, u32 *addr)
+{
+   int ofst;
+
+   ofst = hwirq / 32 * 4;
+   *mask = 1 << (hwirq % 32);
+
+   *addr = ofst + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
+   u32 *mask, u32 *addr)
+{
+   unsigned int ofst;
+
+   ofst = hwirq / 32 * 4;
+
+   *mask = 1 << (hwirq % 32);
+   *addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+   void __iomem *base = data->chip_data;
+   u32 mask, addr;
+
+   get_mbigen_clear_reg(data->hwirq, &mask, &addr);
+
+   writel_relaxed(mask, base + addr);
+
+   irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *data, unsigned int type)
+{
+   void __iomem *base = data->chip_data;
+   u32 mask, addr, val;
+
+   if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+   return -EINVAL;
+
+   get_mbigen_type_reg(data->hwirq, &mask, &addr);
+
+   val = readl_relaxed(base + addr);
+
+   if (type == IRQ_TYPE_LEVEL_HIGH)
+   val |= mask;
+   else
+   val &= ~mask;
+
+   writel_relaxed(val, base + addr);
+
+   return 0;
+}
+
 static struct irq_chip mbigen_irq_chip = {
.name = "mbigen-v1",
+   .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)
-- 
1.7.1




[PATCH 0/5] irqchip: Add support for Hisilicon mbigen v1 chip

2016-02-13 Thread MaJun
From: Ma Jun 

This patch set is used to support the mbigen v1 chip.
Compared to mbigen v2 chip, the main difference between them is
register layout(address,format)

As a sequence of this difference, the functions used to get or calculate
register address are also changed for this reason.

I posted this driver as a independent patch set but not change the mbigen-v2
driver to support mbigen-v1 hardware.

Ma Jun (5):
  dt-binding: Change the mbigen bindding file to support the mbigen-v1
  dt-binding:Rename the mbigen binding file name
  irqchip: add platform device driver for mbigen device
  irqchip:create irq domain for each mbigen device
  irqchip:implement the mbigen irq chip operation functions

 .../interrupt-controller/hisilicon,mbigen-v2.txt   |   74 -
 .../interrupt-controller/hisilicon,mbigen.txt  |   74 +
 drivers/irqchip/Makefile   |2 +-
 drivers/irqchip/irq-mbigen-v1.c|  295 
 4 files changed, 370 insertions(+), 75 deletions(-)
 delete mode 100644 
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
 create mode 100644 
Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen.txt
 create mode 100644 drivers/irqchip/irq-mbigen-v1.c




[PATCH] Change the spin_lock/unlock_irq interface in proc_alloc_inum() function

2016-03-01 Thread MaJun
From: Ma Jun 

The spin_lock/unlock_irq interface is not safe when this function is called
at some case which need irq disabled.

For example:
spin_lock_irqsave()
|
request_irq() --> proc_alloc_inum()
|
spin_unlock_irqrestore()

Reported-by: Fan Jinke 
Signed-off-by: Ma Jun 
---
 fs/proc/generic.c |9 +
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index ff3ffc7..4fc1502 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -191,23 +191,24 @@ int proc_alloc_inum(unsigned int *inum)
 {
unsigned int i;
int error;
+   unsigned long flags;
 
 retry:
if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL))
return -ENOMEM;
 
-   spin_lock_irq(&proc_inum_lock);
+   spin_lock_irqsave(&proc_inum_lock, flags);
error = ida_get_new(&proc_inum_ida, &i);
-   spin_unlock_irq(&proc_inum_lock);
+   spin_unlock_irqrestore(&proc_inum_lock, flags);
if (error == -EAGAIN)
goto retry;
else if (error)
return error;
 
if (i > UINT_MAX - PROC_DYNAMIC_FIRST) {
-   spin_lock_irq(&proc_inum_lock);
+   spin_lock_irqsave(&proc_inum_lock, flags);
ida_remove(&proc_inum_ida, i);
-   spin_unlock_irq(&proc_inum_lock);
+   spin_unlock_irqrestore(&proc_inum_lock, flags);
return -ENOSPC;
}
*inum = PROC_DYNAMIC_FIRST + i;
-- 
1.7.1




[PATCH] IRQ/Platform-MSI:Increase the maximum MSIs the MSI framework can support.

2015-12-20 Thread MaJun
From: Ma Jun 

The current MSI framework can only support 256 platform MSIs.

But on Hisilicon platform, some network related devices has about 500
wired interrupts.

To support these devices, we need a new maximum value more than 256.

Signed-off-by: Ma Jun 
---
 drivers/base/platform-msi.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index a203896..9c00d3f 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -24,7 +24,7 @@
 #include 
 #include 
 
-#define DEV_ID_SHIFT   24
+#define DEV_ID_SHIFT   22
 #define MAX_DEV_MSIS   (1 << (32 - DEV_ID_SHIFT))
 
 /*
-- 
1.7.1


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


[PATCH v2] Irq/Platform-MSI:Increase the maximum MSIs the MSI framework can support.

2015-12-21 Thread MaJun
From: Ma Jun 

The current MSI framework can only support 256 platform MSIs.

But on Hisilicon platform, some network related devices has about 500
wired interrupts.

To support these devices and align with MSI-X, this value is changed
to 2048.

Signed-off-by: Ma Jun 
---
 drivers/base/platform-msi.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index a203896..47c4338 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -24,7 +24,7 @@
 #include 
 #include 
 
-#define DEV_ID_SHIFT   24
+#define DEV_ID_SHIFT   21
 #define MAX_DEV_MSIS   (1 << (32 - DEV_ID_SHIFT))
 
 /*
-- 
1.7.1


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


[PATCH] irqchip/mbigen: Fix the clear register offset

2017-04-24 Thread Majun
From: MaJun 

Don't minus reserved interrupts (64) when get the clear register offset,because
the clear register space includes the space of these 64 interrupts.

Signed-off-by: MaJun 
---
 drivers/irqchip/irq-mbigen.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 061cdb8..75818a5 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -108,7 +108,6 @@ static inline void get_mbigen_clear_reg(irq_hw_number_t 
hwirq,
 {
unsigned int ofst;
 
-   hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
ofst = hwirq / 32 * 4;
 
*mask = 1 << (hwirq % 32);
-- 
1.7.12.4



[PATCH] irqchip/gicv3-its: skip irq affinity setting when target cpu is the same as current setting

2017-05-18 Thread Majun
From: MaJun 

Just skip the irq affinity setting when the target cpu is the same as
current setting.
This is a small optimization for irq affinity setting logic.

Signed-off-by: MaJun 
---
 drivers/irqchip/irq-gic-v3-its.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 45ea1933..b335280 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -644,9 +644,12 @@ static int its_set_affinity(struct irq_data *d, const 
struct cpumask *mask_val,
if (cpu >= nr_cpu_ids)
return -EINVAL;
 
-   target_col = &its_dev->its->collections[cpu];
-   its_send_movi(its_dev, target_col, id);
-   its_dev->event_map.col_map[id] = cpu;
+   /* don't set the affinity when the target cpu is same as current one */
+   if (cpu != its_dev->event_map.col_map[id]) {
+   target_col = &its_dev->its->collections[cpu];
+   its_send_movi(its_dev, target_col, id);
+   its_dev->event_map.col_map[id] = cpu;
+   }
 
return IRQ_SET_MASK_OK_DONE;
 }
-- 
1.7.12.4




Re: [PATCH] generic: Add the exception case checking routine for ppi interrupt

2016-08-30 Thread majun (F)
Hi Marc & Mark:

在 2016/8/30 19:21, Mark Rutland 写道:
> On Tue, Aug 30, 2016 at 12:07:36PM +0100, Marc Zyngier wrote:
>> +Mark
>> On 30/08/16 11:35, majun (F) wrote:
>>> 在 2016/8/30 16:50, Marc Zyngier 写道:
>>>> On 30/08/16 05:17, MaJun wrote:
>>>>> From: Ma Jun 
>>>>>
>>>>> During system booting, if the interrupt which has no action registered
>>>>> is triggered, it would cause system panic when try to access the
>>>>> action member.
>>>>
>>>> And why would that interrupt be enabled? If you enable a PPI before
>>>> registering a handler, you're doing something wrong.
>>>
>>> Actually,the problem described above happened during the capture
>>> kernel booting.
>>>
>>> In my system, sometimes there is a pending physical timer
>>> interrupt(30) when the first kernel panic and the status is kept
>>> until the capture kernel booting.
>>
>> And that's perfectly fine. The interrupt can be pending forever, as it
>> shouldn't get enabled.
>>
>>> So, this interrupt will be handled during capture kernel booting.
>>
>> Why? Who enables it?
>>
>>> Becasue we use virt timer interrupt but not physical timer interrupt
>>> in capture kernel, the interrupt 30 has no action handler.
>>
>> Again: who enables this interrupt? Whichever driver enables it should be
>> fixed.
> 
> I'm also at a loss.
> 
> In this case, arch_timer_uses_ppi must be VIRT_PPI. So in
> arch_timer_register(), we'll only request_percpu_irq the virt PPI.
> arch_timer_has_nonsecure_ppi() will be false, given arch_timer_uses_ppi
> is VIRT_PPI, so in arch_timer_starting_cpu() we'll only
> enable_percpu_irq() the virt PPI.
> 
> We don't fiddle with arch_timer_uses_ppi after calling
> arch_timer_register(). So I can't see how we could enable another IRQ in
> this case.
> 
> Looking at the driver in virt/kvm/arm/arch_timer.c, we only enable what
> we've succesfully requested, so it doesnt' seem like there's an issue
> there.
> 
>>From a quick look at teh GIC driver, it looks like we reset PPIs
> correctly, so it doesn't look like we have a "latent enable".
> 

I just checked the status of irq 30 during capture kernel booting.

The irq 30 status is: mask, pending after arch_timer_starting_cpu() called.
Because irq 30 triggered only 1 time during capture kernel booting,
I think this problem maybe happened in the case like:
1:irq 30 triggered, but not acked by cpu yet.
2:local_irq_disable() called
3:system reboot -->capture kernel booting
4:local_irq_enable()
5:irq 30 acked by CPU.

Is this case possible?

Thanks
MaJun

> Thanks,
> Mark.
> 
> .
> 



Re: [PATCH] generic: Add the exception case checking routine for ppi interrupt

2016-09-01 Thread majun (F)


在 2016/8/31 16:35, Marc Zyngier 写道:
> On 31/08/16 07:35, majun (F) wrote:
[...]
>>>
>>
>> I just checked the status of irq 30 during capture kernel booting.
>>
>> The irq 30 status is: mask, pending after arch_timer_starting_cpu() called.
>> Because irq 30 triggered only 1 time during capture kernel booting,
>> I think this problem maybe happened in the case like:
>> 1:irq 30 triggered, but not acked by cpu yet.
>> 2:local_irq_disable() called
>> 3:system reboot -->capture kernel booting
>> 4:local_irq_enable()
>> 5:irq 30 acked by CPU.
>>
>> Is this case possible?
> 
> I can't see how, because you've missed:
> 
> 3b: All PPIs are disabled as each CPU comes up
> 
> So for (5) to occur, I can only see two possibilities:
> (a) either something else is enabling the timer PPI

I checked the whole process, the irq 30 alway keeping disabled.

> (b) your GIC doesn't correctly retire a pending PPI that is being disabled

According to our hardware guy said, GIC in our system has problem in this case.
Usually, when we mask irq 30, the interrupt which in pending status but not 
acked by cpu
should be released/cleared by hardware, but actually, we did't do like this in 
our system.

So, this conclusion just same as you assumption.

Do you have any suggestion or workaround for this problem?

Thanks!
Majun

> 
> I'm discounting (b) because I can't see how the system would work
> otherwise, so (a) must be happening somehow.
> 


> Thanks,
> 
>   M.
> 



Re: [PATCH v4 1/2] Add the driver of mbigen interrupt controller

2015-08-31 Thread majun (F)
Hi Alexey:

在 2015/8/29 11:13, Alexey Klimov 写道:
> Hi Ma Jun,
> 
> On Wed, Aug 19, 2015 at 5:55 AM, MaJun  wrote:
>> From: Ma Jun 
>>
>> Mbigen means Message Based Interrupt Generator(MBIGEN).
>>
>> Its a kind of interrupt controller that collects
>>
>> the interrupts from external devices and generate msi interrupt.
>>


>> +
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
> 
> What do you think about sorting this?
ok
> 
> 
>> +#include "irqchip.h"
>> +
[...]
>> +*/
>> +static u32 calc_irq_index(struct mbigen_device *dev, u32 nid, u32 offset)
>> +{
>> +   struct mbigen_node *mgn_node = NULL, *tmp;
>> +   unsigned long flags;
>> +   u32 index = 0;
>> +
>> +   raw_spin_lock_irqsave(&dev->lock, flags);
>> +   list_for_each_entry(tmp, &dev->mbigen_node_list, entry) {
>> +   if (tmp->node_num == nid)
>> +   mgn_node = tmp;
>> +   }
>> +   raw_spin_unlock_irqrestore(&dev->lock, flags);
>> +
>> +   if (mgn_node == NULL) {
>> +   pr_err("No mbigen node found in device:%s\n",
>> +dev->node->full_name);
>> +   return -ENXIO;
>> +   }
>> +
>> +   if ((offset <= (mgn_node->pin_offset + mgn_node->irq_nr))
>> +   && (offset >= mgn_node->pin_offset))
>> +   index = mgn_node->index_offset + (offset - 
>> mgn_node->pin_offset);
>> +   else {
>> +   pr_err("Err: no invalid index\n");
> 
> Please check this message.
> 1. I don't know all details about this driver but is it really correct
> "no invalid index"? Maybe you mean "no vaild index" or just "invalid
> index"?
> Just checking if i correctly understand this.
> 
You are right.  This should be "no valid index"
> 2. Imagine what info user/dmesg reader gets when she or he will see
> such message? I suggest to add some info about driver that printed
> this message.
> You already have nice name in mbigen_irq_chip: "MBIGEN-v2". What do
> you think about using it as prefix in your printk-based messages?
> Please also consider revisiting other messages in this patch.
> 
good suggestion.
> 
>> +   index = -EINVAL;
>> +   }
>> +
>> +   return index;
>> +}
[...]
>> +   INIT_LIST_HEAD(dev_to_msi_list(&mgn_dev->dev));
>> +
>> +   ret = platform_msi_domain_alloc_irqs(&mgn_dev->dev,
>> +nvec, mbigen_write_msg);
>> +   if (ret)
>> +   goto out_free_dev;
>> +
>> +   INIT_LIST_HEAD(&mgn_dev->entry);
>> +   raw_spin_lock_init(&mgn_dev->lock);
>> +   INIT_LIST_HEAD(&mgn_dev->mbigen_node_list);
>> +
>> +   /* Parse and get the info of mbigen nodes this
>> +* device connected
>> +*/
>> +   parse_mbigen_node(mgn_dev);
>> +
>> +   mgn_irq_data = kcalloc(nvec, sizeof(*mgn_irq_data), GFP_KERNEL);
>> +   if (!mgn_irq_data)
>> +   return -ENOMEM;
> 
> Hm. Do you need error path here instead of simple return -ENOMEM?
> Maybe 'goto out_free_dev' will work for you.
Right. Memory leak happened.
> 
>> +   mgn_dev->mgn_data = mgn_irq_data;
>> +
>> +   for_each_msi_entry(desc, &mgn_dev->dev) {
>> +   mbigen_set_irq_handler_data(desc, mgn_dev,
>> +   
>> &mgn_irq_data[desc->platform.msi_index]);
>> +   irq_set_chained_handler(desc->irq, 
>> mbigen_handle_cascade_irq);
>> +   }
>> +
>> +   raw_spin_lock(&chip->lock);
>> +   list_add(&mgn_dev->entry, &chip->mbigen_device_list);
>> +   raw_spin_unlock(&chip->lock);
>> +
>> +   return 0;
>> +
>> +out_free_dev:
>> +   kfree(mgn_dev);
>> +   pr_err("failed to get MSIs for device:%s (%d)\n", node->full_name,
>> +   ret);
>> +   return ret;
>> +}
>> +
>> +/*
>> + * Early initialization as an interrupt controller
>> + */
>> +static int __init mbigen_of_init(struct device_node *node)
>> +{
&

Re: [PATCH v5 1/3] initialize each mbigen device node as a interrupt controller.

2015-10-12 Thread majun (F)
Hi Thomas:

在 2015/10/12 0:45, Thomas Gleixner 写道:
> On Sun, 11 Oct 2015, Marc Zyngier wrote:
>> On Sun, 11 Oct 2015 11:54:49 +0200
>> Thomas Gleixner  wrote:
>>
>>> On Sat, 10 Oct 2015, Marc Zyngier wrote:
>>>> On Sat, 10 Oct 2015 17:01:32 +0800
>>>> "majun (F)"  wrote:
>>>>> But there is a problem If i make the structure like you said.
>>>>>
>>>>> For example, my hardware structure likes below:
>>>>>
>>>>> uart --> mbigen --> ITS-pMSI --> ITS --> GIC
>>>>>  virq1
>>>>>
>>>>> virq1 means the virq number allocted by irq_of_parse_and_map() function
>>>>> when system parse the uart dts node in initializing  stage.
>>>>>
>>>>> To create a ITS device, I need to call msi_domain_alloc_irqs() function
>>>>> in my mbigen alloc function.
>>>>>
>>>>> In this function, a new virq number(named as virq2 ) which different from
>>>>> virq1 is allocated.
>>>>> So, this is a big problem.
>>>>
>>>> I think I see what your problem is:
>>>> - The wired interrupt (uart -> mbigen) is allocated through DT (and
>>>>   must be available early, because of of_platform_populate),
>>>> - The MSI (mgigen -> ITS) is dynamic (and allocated much later,
>>>>   because the device model kicks in after irqchip init, and we cannot
>>>>   allocate MSIs without a device).
>>>
>>> Why do we need that wired interrupt at all? 
>>>
>>> We can make mbigen the 'msi-parent' of the device and let the
>>> msi_domain_ops::msi_prepare() callback figure out the actual wiring
>>> through device->fwnode.
>>
>> That's because the device behind the mbigen can't do any MSI at all.
>> Think of a 8250 uart, for example.
>>
>> If we make the mbigen the msi-parent of the uart, then we need to teach
>> the 8250 driver to request MSIs.
> 
> I really do not understand why of_platform_populate cares about
> interrupt allocations. That's outright stupid. We should care about
> that at device probe time, i.e. at the point where the driver is
> registered and probed if there is matching platform data. If we do it
> in of_platform_populate then we allocate interrupts even for devices
> which do not have a driver, i.e. we just waste memory.
> 
> So we better teach a couple of drivers to handle that instead of
> inventing horrible workarounds.
> 
>> It also means that the DT doesn't represent the HW anymore (this
>> wired interrupt actually exists).
> 
> I think the abstraction here is wrong. If it would be correct, then
> PCI-MSI would be wrong. The MSI part of PCI is a MSI producer, mbigen
> is as well. Technically MSI is not integral part of the PCI device, it
> just happens to have it's configuration registers in the PCI
> configuration space of the device:
> 
> [PCI-BUS]--[Interrupt mode selector]
>   ||
>   ||
>   --[Legacy irq gate]<-
>   ||  |
>   ||  |---[Device interrupt]
>   ||  |
>   --[MSI unit]<
> 
> So you have a 'wire' from the device to the MSI unit, but we do not
> care about that 'wire'. All we care about are the MSI configuration
> registers. We find them via the PCI device which gives us the address
> of the PCI configuration space.
> 
> So now in the mbigen case this looks like this:
> 
> [MSI-BUS] - [MBIGEN]<---[Device interrupt]
> 
> Again, you have a 'wire' from the device to the MSI unit (MBIGEN) and
> we do not care about that 'wire' either. What we care about is how we
> find the MSI (mbigen) configuration registers for a particular
> device. So we need a DT/ACPI entry which describes those configuration
> registers and whatever supplementary information is required. That
> will make the mbigen driver extremly simple.
> 

According to your suggestions, I tried to make the hardware structure likes 
below:

device(8250 uart) -> mbigne -> ITS-pMSI --> ITS --> GIC

And  8250 uart dts node is:

 8250_uart {
compatible = "xxx";
msi-parent = < &mbigen>;
config_addr =  ; /* configuration register */
interrupts = ;
interrupt-parent = ?
}

My question is what's the interrupt-parent should be?



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


Re: [PATCH v5 1/3] initialize each mbigen device node as a interrupt controller.

2015-10-14 Thread majun (F)
Hi Thomas:

在 2015/10/13 14:55, Thomas Gleixner 写道:
> Majun,
> 
> On Tue, 13 Oct 2015, majun (F) wrote:
>> 在 2015/10/12 0:45, Thomas Gleixner 写道:
>>> So now in the mbigen case this looks like this:
>>>
>>> [MSI-BUS] - [MBIGEN]<---[Device interrupt]
>>>
>>> Again, you have a 'wire' from the device to the MSI unit (MBIGEN) and
>>> we do not care about that 'wire' either. What we care about is how we
>>> find the MSI (mbigen) configuration registers for a particular
>>> device. So we need a DT/ACPI entry which describes those configuration
>>> registers and whatever supplementary information is required. That
>>> will make the mbigen driver extremly simple.
>>>
>>
>> According to your suggestions, I tried to make the hardware structure likes 
>> below:
>>
>> device(8250 uart) -> mbigne -> ITS-pMSI --> ITS --> GIC
> 
> I'm not sure whether mbigen should be connected to ITS-pMSI (I assume
> you mean ITS-PCI-MSI).

ITS domain has two child domains. One is ITS-pMSI for Non-PCI devices,
the other one is ITS-MSI for PCI devices.

> 
> mbigen is a seperate MSI domain, so it should connect to ITS, but I
> leave that to Marc.

I also think mbigen should connected to ITS.

Now, the hierarchy structure is
MBIGEN -> ITS -> GIC.

This structure is really similar to the structure in my v3 patch except the
dts.

>  
>> And  8250 uart dts node is:
>>
>>  8250_uart {
>>  compatible = "xxx";
>>  msi-parent = < &mbigen>;
>>  config_addr =  ; /* configuration register */
>>  interrupts = ;
>>  interrupt-parent = ?
>> }
>>
>> My question is what's the interrupt-parent should be?
> 
> There is no interrupt parent for 8250_uart. Why would you want that?
> I'm really not a DT expert, but I think you want something like this:
> 
>   8250_uart {
>   compatible = "xxx";
>   msi-parent = < &mbigen_node5>;
>   interrupt-map = <&mbigen5 0>;
>   };
> 

Maybe you mean
interrupt-map = <&mbigen_node5 0>;

I have some questions about this

[1]: I noticed there is no interrupts property,
So, do you mean we don't need this property here ?

[2]: I am confused about interrupt-map.

This property is parsed in function of_irq_parse_raw().
In this fucntion

"
ipar = of_node_get(out_irq->np);
of_get_property(ipar, "interrupt-map", &imaplen);
"
When this function is called by of_irq_parse_one(),
the input para out_irq->np pointed to GIC or mbigen (depends on dts).

So, of_get_property() tried to get the interrupt-map from
GIC or mbgien node.

But there is no interrupt-map property in GIC or mbigen node.



> and then have
> 
>   mbigen_node5 {
>   ...
>   reg = <>;
>   };
> 
> So the other devices which are connected to mbigen_node5 have the same
> msi-parent. But then again, please discuss that with Marc and the DT
> wizards.
> 

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


Re: [PATCH v5 1/3] initialize each mbigen device node as a interrupt controller.

2015-10-14 Thread majun (F)


在 2015/10/14 16:20, Thomas Gleixner 写道:
> On Wed, 14 Oct 2015, majun (F) wrote:
>> But there is no interrupt-map property in GIC or mbigen node.
> 
> Again: I'm not a DT expert. Please discuss that with Marc and the DT
> wizards.
> 
> Thanks,
> 
>   tglx
> 
> .

Ok.
Marc, what's your suggestion ? much appreciated

Thanks!
Ma Jun


> 

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


Re: [PATCH v4 1/2] Add the driver of mbigen interrupt controller

2015-09-06 Thread majun (F)
Hi Alexey:

在 2015/9/4 8:56, Alexey Klimov 写道:
> Hi Ma Jun,
> 
> On Tue, Sep 1, 2015 at 4:45 AM, majun (F)  wrote:
>> Hi Alexey:
>>
[...]
>>>> +   mgn_chip->base = base;
>>>> +   mgn_chip->node = node;
>>>> +
>>>> +   domain = irq_domain_add_tree(node, &mbigen_domain_ops, mgn_chip);
>>>> +   mgn_chip->domain = domain;
>>>> +
>>>> +   raw_spin_lock_init(&mgn_chip->lock);
>>>> +   INIT_LIST_HEAD(&mgn_chip->entry);
>>>> +   INIT_LIST_HEAD(&mgn_chip->mbigen_device_list);
>>>> +
>>>> +   for_each_child_of_node(node, child) {
>>>> +   mbigen_device_init(mgn_chip, child);
>>>
>>> You don't check error from mbigen_device_init()
>> I don't think we need to check errors here.
>> mbigen_device_init() handle all errors.
> 
> For my eyes, mbigen_device_init() is static and used only once here.
> Here you don't check return value from it. If this is correct you can
> convert mbigen_device_init() to return void unless you have future
> plans to modify it.
> 
> Or you have option to check return value here and add error path.

Ok, This will be changed in next version.

> 
> Please add me to cc to next version of patch set which I guess will be v5.
> 

Got it. I will add you to cc list in next version.
Thanks for you review !

Ma Jun


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


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

2015-10-20 Thread majun (F)


在 2015/10/21 2:43, kbuild test robot 写道:
> Hi Ma,
> 
> [auto build test ERROR on tip/irq/core -- if it's inappropriate base, please 
> suggest rules for selecting the more suitable base]
> 
> url:
> https://github.com/0day-ci/linux/commits/MaJun/irqchip-support-mbigen-interrupt-controller/20151020-202450
> config: arm64-allyesconfig (attached as .config)
> reproduce:
> wget 
> https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross
>  -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=arm64 
> 
> All error/warnings (new ones prefixed by >>):
> 
>drivers/irqchip/irq-mbigen.c:84:14: error: 'mbigen_eoi_irq' undeclared 
> here (not in a function)
>  .irq_eoi =  mbigen_eoi_irq,
>  ^
>drivers/irqchip/irq-mbigen.c:85:19: error: 'mbigen_set_type' undeclared 
> here (not in a function)
>  .irq_set_type =  mbigen_set_type,
>   ^

I'll fix this error in v7

>drivers/irqchip/irq-mbigen.c: In function 'mbigen_irq_domain_alloc':
>>> drivers/irqchip/irq-mbigen.c:150:2: error: implicit declaration of function 
>>> 'platform_msi_domain_alloc' [-Werror=implicit-function-declaration]
>  err = platform_msi_domain_alloc(domain, virq, nr_irqs);
>  ^
>>> drivers/irqchip/irq-mbigen.c:159:2: error: implicit declaration of function 
>>> 'platform_msi_get_host_data' [-Werror=implicit-function-declaration]
>  mgn_chip = platform_msi_get_host_data(domain);
>  ^
>>> drivers/irqchip/irq-mbigen.c:159:11: warning: assignment makes pointer from 
>>> integer without a cast
>  mgn_chip = platform_msi_get_host_data(domain);
>   ^
>drivers/irqchip/irq-mbigen.c: In function 'mbigen_device_probe':
>>> drivers/irqchip/irq-mbigen.c:202:2: error: implicit declaration of function 
>>> 'platform_msi_create_device_domain' [-Werror=implicit-function-declaration]
>  domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
>  ^
>drivers/irqchip/irq-mbigen.c:202:9: warning: assignment makes pointer from 
> integer without a cast
>  domain = platform_msi_create_device_domain(&pdev->dev, num_msis,

My patch based on Marc's patch
https://lkml.org/lkml/2015/10/15/545

So, please apply this patch first.

Thanks!
Ma Jun

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


Re: [PATCH v6 2/4] irqchip: add platform device driver for mbigen device

2015-10-20 Thread majun (F)
Sorry, I missed Makefile and Kconfig file in this patch.
I will re-send this patch set.

在 2015/10/20 16:41, MaJun 写道:
> From: Ma Jun 
> 
> Mbigen means Message Based Interrupt Generator(MBIGEN).
> 
> Its a kind of interrupt controller that collects
> the interrupts from external devices and generate msi interrupt.
> Mbigen is applied to reduce the number of wire connected interrupts.
> 
> As the peripherals increasing, the interrupts lines needed is
> increasing much, especially on the Arm64 server SOC.
> 
> Therefore, the interrupt pin in GIC is not enough to cover so
> many peripherals.
> 
> Mbigen is designed to fix this problem.
> 
> Mbigen chip locates in ITS or outside of ITS.
> 
> Mbigen chip hardware structure shows as below:
> 
>   mbigen chip
> |-|---|
> mgn_node0   mgn_node1 mgn_node2
>  | |---|  |---|--|
> dev1  dev1dev2dev1   dev3   dev4
> 
> Each mbigen chip contains several mbigen nodes.
> 
> External devices can connect to mbigen node through wire connecting way.
> 
> Because a mbigen node only can support 128 interrupt maximum, depends
> on the interrupt lines number of devices, a device can connects to one
> more mbigen nodes.
> 
> Also, several different devices can connect to a same mbigen node.
> 
> When devices triggered interrupt,mbigen chip detects and collects
> the interrupts and generates the MBI interrupts by writing the ITS
> Translator register.
> 
> To simplify mbigen driver,I used a new conception--mbigen device.
> Each mbigen device is initialized as a platform device.
> 
> Mbigen device presents the parts(register, pin definition etc.) in
> mbigen chip corresponding to a peripheral device.
> 
> So from software view, the structure likes below
> 
>   mbigen chip
>  |-|-|
> mbigen device1   mbigen device2  mbigen device3
>   |   ||
>  dev1dev2 dev3
> 
> Signed-off-by: Ma Jun 
> ---
>  drivers/irqchip/irq-mbigen.c |   83 
> ++
>  1 files changed, 83 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/irqchip/irq-mbigen.c
> 
> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> new file mode 100644
> index 000..f18132f
> --- /dev/null
> +++ b/drivers/irqchip/irq-mbigen.c
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
> + * Author: Jun Ma 
> + * Author: Yun Wu 
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +/**
> + * 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.
> + */
> +struct mbigen_device {
> + struct platform_device  *pdev;
> + void __iomem*base;
> +};
> +
> +static int mbigen_device_probe(struct platform_device *pdev)
> +{
> + struct mbigen_device *mgn_chip;
> +
> + mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
> + if (!mgn_chip)
> + return -ENOMEM;
> +
> + mgn_chip->pdev = pdev;
> + mgn_chip->base = of_iomap(pdev->dev.of_node, 0);
> +
> + platform_set_drvdata(pdev, mgn_chip);
> +
> + return 0;
> +}
> +
> +static int mbigen_device_remove(struct platform_device *pdev)
> +{
> + struct mbigen_device *mgn_chip = platform_get_drvdata(pdev);
> +
> + iounmap(mgn_chip->base);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mbigen_of_match[] = {
> + { .compatible = "hisilicon,mbigen-v2" },
> + { /* END */ }
> +};
> +MODULE_DEVICE_TABLE(of, mbigen_of_match);
> +
> +static struct platform_driver mbigen_platform_driver = {
> + .driver = {
>

Re: [PATCH v5 1/3] initialize each mbigen device node as a interrupt controller.

2015-10-04 Thread majun (F)
Hi Thomas:

在 2015/10/1 5:37, Thomas Gleixner 写道:
> On Wed, 30 Sep 2015, MaJun wrote:
> 
> First of all.
> 
> [PATCH v5 1/3] initialize each mbigen device node as a interrupt controller
> 
> is not a proper subject line, but that's the least of your problems.
> 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include "irqchip.h"
> 
> Do you really need all these includes?

Ok, I will remove usless includes.
> 
>> +
>> +/* Interrupt numbers per mbigen node supported */
>> +#define IRQS_PER_MBIGEN_NODE(128)
> 
[...]
>> +
>> +info = &mgn_dev->mgn_data[index].info;
>> +info->index = index;
>> +info->global_pin_offset = GET_IRQ_PIN_OFFSET(d->hwirq);
>> +info->nid = info->global_pin_offset / IRQS_PER_MBIGEN_NODE;
>> +
>> +info->local_pin_offset = (info->global_pin_offset % 
>> IRQS_PER_MBIGEN_NODE)
>> +- RESERVED_IRQ_PER_MBIGEN_CHIP;
>> +
>> +info->reg_offset = get_mbigen_vec_reg_addr(info->nid, 
>> info->local_pin_offset);
> 
> So you fill in a structure with 5 fields and the only information
> which is ever used is local_pin_offset.
> 
> What's the point of this exercise? 

Besides local_pin_offset , nid, and reg_offset are also useful information 
which will be used
in next patch.

For each mbigen chip, the register space of mbigen node between each other is 
discontinuous.
So, I need to find the mbigen node number(nid) and pin offset within this 
mbigen node
(local_pin_offset). Based on them, I can get the corresponding register address.

> 
>> +
>> +return &mgn_dev->mgn_data[index];
>> +}
>> +
>> +static int mbigen_set_affinity(struct irq_data *data,
>> +const struct cpumask *mask_val,
>> +bool force)
>> +{
>> +struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(data);
>> +struct irq_chip *chip = irq_get_chip(mgn_irq_data->msi_irq);
> 
> And that msi_irq information comes from where? Nothing in that code
> initializes it.

msi_irq is is initialized in next patch.

>> +struct irq_data *parent_d = irq_get_irq_data(mgn_irq_data->msi_irq);
> 
> Also WHY are you going through a full lookup of the chip and the irq
> data, if that is your parent irq? That's what the domain hierarchy is
> for. If you now tell me, that msi_irq is not the same as data->irq,
> i.e. the virq number, then you have a lot more things to explain.

Yes, they have different virq number. My explanation about this
problem is list at last.


> irq_chip_set_affinity_parent() is the callback you want for your chip,
> not some completely nonsensical hackery.

I think this is used for hierarchy structure. My interrupt controller is not
hierarchy structrue.

> 
>> +
>> +if (chip && chip->irq_set_affinity)
> 
> Why would chip ever be NULL? If your parent interrupt does not have a
> chip assigned then your whole setup is hosed.
> 
>> +static void mbigen_eoi_irq(struct irq_data *data)
>> +{
>> +
>> +struct mbigen_irq_data *mgn_irq_data = irq_data_get_irq_chip_data(data);
>> +struct mbigen_device *mgn_dev = mgn_irq_data->dev;
> 
> So the only reason for accessing yet another data structure is to get
> the base address of that mbi device. You seem to have a strong
> interest in making the cache foot print of your code as big as
> possible. 
> 
>> +struct irq_chip *chip = irq_get_chip(mgn_irq_data->msi_irq);
>> +struct irq_data *parent_d = irq_get_irq_data(mgn_irq_data->msi_irq);
>> +u32 pin_offset, ofst, mask;
>> +
>> +pin_offset = mgn_irq_data->info.local_pin_offset;
>> +
>> +ofst = pin_offset / 32 * 4;
>> +mask = 1 << (pin_offset % 32);
>> +
>> +writel_relaxed(mask, mgn_dev->base + ofst
>> ++ REG_MBIGEN_CLEAR_OFFSET);
>> +
>> +if (chip && chip->irq_eoi)
>> +chip->irq_eoi(parent_d);
> 
> So again. Why would chip be NULL and why would chip NOT have an EOI
> callback?
> 
>> +static int mbigen_domain_xlate(struct irq_domain *d,
>> +   struct device_node *controller,
>> +   const u32 *intspec, unsigned int intsize,
>> +   unsigned long *out_hwirq,
>> +   unsigned int *out_

Re: [PATCH v2 0/3] irqchip/mbigen: bugfixs

2017-05-11 Thread majun (Euler7)
Hi Hanjun,
This patchset is fine to me and make my
D05 machine work again.So,

Tested-by: MaJun 

Thanks
Majun

在 2017/5/12 11:55, Hanjun Guo 写道:
> From: Hanjun Guo 
> 
> Here are 3 bugfixes for mbigen:
> 
> Patch 1 is a critical bugfix which to fix the mbigen probe failure,
> commit 216646e4d82e ("irqchip/mbigen: Fix return value check in
> mbigen_device_probe()") introduced this breakage;
> 
> Patch 2 fixes a potential NULL dereferencing;
> 
> Patch 3 fixes a wrong clear register offset;
> 
> v1 -> v2:
>  - Rebase on top of lastest Linus tree (09d79d1 Merge tag
>'docs-4.12-2' of git://git.lwn.net/linux);
> 
>  - Fix a checkpatch error.
> 
> Thanks
> Hanjun
> 
> Hanjun Guo (2):
>   irqchip/mbigen: Fix memory mapping code
>   irqchip/mbigen: Fix potential NULL dereferencing
> 
> MaJun (1):
>   irqchip/mbigen: Fix the clear register offset
> 
>  drivers/irqchip/irq-mbigen.c | 17 ++---
>  1 file changed, 10 insertions(+), 7 deletions(-)
> 



Re: [PATCH v2 2/3] IRQ/Gic-V3: Change arm-gic-its to support the Mbigen interrupt

2015-06-15 Thread majun (F)


在 2015/6/12 18:48, Thomas Gleixner 写道:
> On Fri, 12 Jun 2015, Ma Jun wrote:
> 
>> This patch is applied to support the mbigen interrupt.
>>
>> As a kind of MSI interrupt controller, the mbigen is used as a child 
>> domain of ITS domain just like PCI devices.
>> So the arm-gic-v3-its and related files are changed.
>>
>> The chip.c is also changed to check irq_ach before it called.
> 
> This patch wants to be split into several:
> 
> 1) Changes to the core code
> 
> 2) New functionality in the core code
> 
> 2) Changes to gic-v3-its
> 
> And all patches require proper changelogs which explain WHY these
> changes are necessary.
> 
> We can see which files are changed from the diffstat and the patch
> ourself. So no point to mention this in the changelog.
> 
> But we cannot figure out from looking at the code WHY you think that
> your approach to solve the problem is the right one.
> 
>>  void irq_chip_ack_parent(struct irq_data *data)
>>  {
>>  data = data->parent_data;
>> -data->chip->irq_ack(data);
>> +if (data->chip->irq_ack)
>> +data->chip->irq_ack(data);
> 
> Why is this required? Just because? Again, you fail to provide a
> rationale for the changes to the irq_chip*parent() functions.
> 
> Why would you call irq_chip_ack_parent() if that parent does not
> provide the required functionality in the first place?
> 

Yes, this is not a necessary callback. I will remove this callback
from mbigen driver.

>>  /*
>> @@ -363,6 +364,9 @@ struct irq_chip {
>>  int (*irq_request_resources)(struct irq_data *data);
>>  void(*irq_release_resources)(struct irq_data *data);
>>  
>> +void(*irq_compose_mbigen_msg)(struct irq_data *data, struct 
>> mbigen_msg *msg);
>> +void(*irq_write_mbigen_msg)(struct irq_data *data, struct 
>> mbigen_msg *msg);
>> +
> 
> What's so special about mbigen to justify extra callbacks which just
> bloat the data structure for everyone. Why are the msi callbacks not
> sufficient?
> 
> MBI is just another variant of MSI, right?
> 
yes,MBI is a kind of MSI which used for non-pci devices.

According to Marc's advice, the irq hierachy structure
in my patch likes below:
non-pci devices-->mbigen-->its-->gic
pci devices -->msi __/

Eventhough the function *irq_compose_mbigen_msg does
the same thing as *irq_chip_compose_msi_msg, I still
added this function. Because I don't want mix the code
used by msi(pci devices) with the code used by mbigen.

> struct mbigen_msg {
>u32 address_lo;
>u32 address_hi;
>u32 data;
> };
> 
> struct mbigen_msg is just a mindless copy of struct msi_msg:
> 
> struct msi_msg {
> u32 address_lo; /* low 32 bits of msi message address */
> u32 address_hi; /* high 32 bits of msi message address */
> u32 data;   /* 16 bits of msi message data */
> };
> 
> So what's the point of this?
>

Based on the same reason, I also added  structure mbigen_msg for
mbigen using.

>>  void(*irq_compose_msi_msg)(struct irq_data *data, struct 
>> msi_msg *msg);
>>  void(*irq_write_msi_msg)(struct irq_data *data, struct 
>> msi_msg *msg);
>>  
> 
>> +
>> +/**
>> + * irq_chip_compose_mbigen_msg - Componse mbigen message for a mbigen irq 
>> chip
>> + * @data:   Pointer to interrupt specific data
>> + * @msg:Pointer to the mbigen message
>> + *
>> + * For hierarchical domains we find the first chip in the hierarchy
>> + * which implements the irq_compose_mbigen_msg callback. For non
>> + * hierarchical we use the top level chip.
>> + */
>> +
>> +int irq_chip_compose_mbigen_msg(struct irq_data *data, struct mbigen_msg 
>> *msg)
>> +{
>> +struct irq_data *pos = NULL;
>> +
>> +#ifdef  CONFIG_IRQ_DOMAIN_HIERARCHY
>> +for (; data; data = data->parent_data)
>> +#endif
>> +if (data->chip && data->chip->irq_compose_mbigen_msg)
>> +pos = data;
>> +if (!pos)
>> +return -ENOSYS;
>> +
>> +pos->chip->irq_compose_mbigen_msg(pos, msg);
>> +
>> +return 0;
>> +}
> 
> Again, this is a completely useless copy of irq_chip_compose_msi_msg().
> Why can't you just use the existing callbacks and use struct msi_msg
> for your special chip?
> 
As mentioned before, to avoid using the code of msi, i added this
function.Because they are different domain.

If you don't mind, I can use the irq_chip_compose_msi_msg function in
mbigen driver instead of irq_chip_compose_mbigen_msg.

> And w/o looking at the mbigen code in detail, I bet it's nothing else
> than MSI for non PCI devices and contains tons of redundant and copied
> code, right?
>
> Can you please provide a proper description of this mbigen chip and
> explain WHY you think that it needs all this special hackery?
> 
> Thanks,
> 
>   tglx
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majord...@vger.kernel.org
> More majordom

Re: [PATCH v2 2/3] IRQ/Gic-V3: Change arm-gic-its to support the Mbigen interrupt

2015-06-23 Thread majun (F)


在 2015/6/19 7:52, Thomas Gleixner 写道:
> On Mon, 15 Jun 2015, majun (F) wrote:
>> 在 2015/6/12 18:48, Thomas Gleixner 写道:
>>> Can you please provide a proper description of this mbigen chip and
>>> explain WHY you think that it needs all this special hackery?
> 
> You carefully avoided to provide a proper description of this mbigen
> chip and how it needs to be integrated into the GIC/ITS whatever
> scenario.
> 
Mbigen means Message Based Interrupt Generator.
Its a kind of interrupt controller collects
the interrupts from external devices and generate msi interrupt.

Mbigen is applied to reduce the number of wire connected interrupts.

As the peripherals increasing, the interrupts lines needed is increasing
much, especially on the Arm64 server soc.

Therefore, the interrupt pin in gic is not enought for so many perpherals.

Mbigen is designed to fix this problem.

Mbigen chip locates in ITS or outside of ITS.

The working flow of Mbigen shows as below:

external devices --> MBIGEN --->ITS

The devices connect to Mbigen chip through wire connecting way.
Mbigen detects and collectes the interrupts from the these devices.

Then, Mbigen generats the MBI interrupts by writting the ITS
Translator register.







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


Re: [PATCH 3/4]: Change arm-gic-its to support the Mbigen interrupt

2015-06-02 Thread majun (F)
Hi Marc:
Thanks for your review.

Accroding to my initial scheme, mbigen and pci devices uses the
same parent domain--MSI domain.

But accroding to your opinion, it seems use the ITS domain as parent domain
of Mbigne is a better way. Am i right ?

Thanks
Ma Jun


在 2015/6/1 17:13, Marc Zyngier 写道:
> Like I said in patch #1, you need to come up with a different approach.
> Use the LPI layer of the ITS as the parent for your MBI, stop messing
> with the PCI stuff, stop poking the ITS internals.
> 
> Thanks,
> 
>   M.

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


Re: [PATCH 4/4]:dt-binding:Documents the mbigen bindings

2015-06-02 Thread majun (F)


在 2015/6/1 18:04, Mark Rutland 写道:
> On Sat, May 30, 2015 at 04:19:18AM +0100, majun (F) wrote:
>> Add the mbigen msi interrupt controller bindings document
>>
>>
>> Signed-off-by: Ma Jun 
>> ---
>>  Documentation/devicetree/bindings/arm/mbigen.txt |   51 
>> ++
>>  1 files changed, 51 insertions(+), 0 deletions(-)
>>  create mode 100755 Documentation/devicetree/bindings/arm/mbigen.txt
>>
>> diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
>> b/Documentation/devicetree/bindings/arm/mbigen.txt
>> new file mode 100755
>> index 000..d442b31
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/arm/mbigen.txt
>> @@ -0,0 +1,51 @@
>> +Hisilicon mbigen device tree bindings.
>> +===
>> +
>> +Mbigen means: message based interrupt generator.
>> +
>> +MBI is kind of msi interrupt only used on Non-PCI devices.
>> +
>> +To reduce the wired interrupt number connected to GIC,
>> +Hisilicon designed mbigen to collect and generate interrupt.
>> +
>> +
>> +Non-pci devices can connect to mbigen and gnerate the inteerrupt
>> +by wirtting ITS register.
> 
> Typos.
> 
>> +
>> +The mbigen and devices connect to mbigen have the following properties:
>> +
>> +
>> +Mbigen required properties:
>> +---
>> +-compatible: Should be "hisilicon,mbi-gen"
>> +-msi-parent: should specified the ITS mbigen connected
>> +-interrupt controller: Identifies the node as an interrupt controller
>> +- #interrupt-cells : Specifies the number of cells needed to encode an
>> +  interrupt source. The value is 2 for now.
> 
> The precise format of these cells needs to be specified, at this point
> in the binding document.
>
ok, i will fix this in next version

> Why do you say "The value is 2 for now"? Do you expect this to grow in
> future? If so, why?
> 
Because the hardware design will be changed in the near future, to compatible
with these chips, this value need to change either.

>> +- reg: Specifies the base physical address and size of the ITS
>> +  registers.
> 
> This doesn't sound right. This isn't the ITS, so it shouldn't refer to
> the ITS registers in this manner.
> 
> Does the mbigen not have its own set of registers?
> 
> Thanks,
> Mark.
> 
yes, you are right, it should be mbigen register.
>> +
>> +Examples:
>> +
>> +mbigen_pa: interrupt-controller@4c03 {
>> +compatible = "hisilicon,mbi-gen";
>> +msi-parent = <&its_pa>;
>> +interrupt-controller;
>> +#interrupt-cells = <2>;
>> +reg = <0x4c03 0x1>;
>> +};
>> +
>> +Device connect to mbigen required properties:
>> +
>> +-interrupt-parent: Specifies the mbigen node which device connected.
>> +-interrupts:specifies the interrupt source.The first cell is hwirq num, the
>> +  second number is trigger type.
>> +
>> +Examples:
>> +usb0: ehci@a100 {
>> +compatible = "generic-ehci";
>> +interrupt-parent = <&mbigen_pa>;
>> +reg = <0xa100 0x1>;
>> +interrupts = <20 4>;
>> +};
>> +
>> -- 
>> 1.7.1
>>
>>
> 
> .
> 

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


[PATCH 1/4]:Add mbigen driver to support mbigen interrupt controller

2015-05-29 Thread majun (F)
This patch contains the mbigen device driver.

To support Mbigen device, irq-mbigen.c and mbi.h are added.

As a MSI interrupt controller, the mbigen is used as a child domain of
MSI domain just like PCI devices.

Change log:
--irq-mbigen.c: the driver of mbigen device.The mbigen irq domain is created 
here
   as child domain of MSI.
--Add CONFIG_MBIGEN_IRQ_DOMAIN enable this driver

Signed-off-by: Yun Wu 
Signed-off-by: Ma Jun 
---
 drivers/irqchip/Kconfig  |4 +
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-mbigen.c |  562 ++
 include/linux/mbi.h  |   77 ++
 4 files changed, 644 insertions(+), 0 deletions(-)
 mode change 100644 => 100755 drivers/irqchip/Kconfig
 mode change 100644 => 100755 drivers/irqchip/Makefile
 create mode 100755 drivers/irqchip/irq-mbigen.c
 create mode 100644 include/linux/mbi.h

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
old mode 100644
new mode 100755
index 6de62a9..595a6eb
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -26,6 +26,10 @@ config ARM_GIC_V3
 config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
+   select MBIGEN_IRQ_DOMAIN
+
+config MBIGEN_IRQ_DOMAIN
+   bool

 config ARM_NVIC
bool
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
old mode 100644
new mode 100755
index dda4927..23571c1
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o 
irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)  += irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)   += irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)   += irq-gic-v3-its.o
+obj-$(CONFIG_MBIGEN_IRQ_DOMAIN)+= irq-mbigen.o
 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)  += irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)+= irq-atmel-aic-common.o 
irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100755
index 000..462f9a0
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2014 Hisilicon Limited, All Rights Reserved.
+ * Author: Yun Wu 
+ * Author: Jun Ma 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "irqchip.h"
+
+/* Register offsets */
+#define MG_IRQ_TYPE0x0
+#define MG_IRQ_CLEAR   0x100
+#define MG_IRQ_STATUS  0x200
+#define MG_MSG_DATA0x300
+
+/* The gap between normal and extended pin region */
+#define MG_EXT_OFST0x10
+
+/* Max number of interrupts supported */
+#define MG_NR_IRQS 640
+
+/* Number of mbigens supported in one chip */
+#define MG_NR  6
+
+struct mbigen_node {
+   struct list_headentry;
+   struct mbigen   *mbigen;
+   struct device_node  *source;
+   unsigned intirq;
+   unsigned intnr_irqs;
+};
+
+struct mbigen {
+   raw_spinlock_t  lock;
+   struct list_headentry;
+   struct mbigen_chip  *chip;
+   unsigned intnid;
+   unsigned intirqs_used;
+   struct list_headnodes;
+};
+
+struct mbigen_chip {
+   raw_spinlock_t  lock;
+   struct list_headentry;
+   struct device   *dev;
+   struct device_node  *node;
+   void __iomem*base;
+   struct irq_domain   *domain;
+   struct list_headnodes;
+};
+
+static LIST_HEAD(mbigen_chips);
+static DEFINE_SPINLOCK(mbigen_lock);
+
+int get_mbi_offset(int virq)
+{
+   struct irq_data *data;
+   struct mbi_desc *mbidesc;
+   int offset = 0;
+
+   data = irq_get_irq_data(virq);
+
+   mbidesc = (struct mbi_desc *)data->msi_desc;
+   offset = mbidesc->offset;
+   return offset;
+}
+
+int mbi_parse_irqs(struct device *dev, struct mbi_ops *ops)
+{
+   pr_warn("%s:this function not use now\n", __func__);
+   return -EINVAL;
+}
+EXPORT_SYMBOL(mbi_parse_irqs);
+
+void mbi_free_irqs(struct device *dev, unsigned int virq, unsigned int nvec)
+{
+   pr_warn("%s:this function not use now\n", __func__);
+}
+EXPORT_SYMBOL(mbi_free_irqs);
+
+static in

[PATCH 0/4] Cover: Support mbigen msi interrupt controller

2015-05-29 Thread majun (F)
This patch set is applied to supprot the mbigen device.

Mbigen means message based interrupt generator.
It locate in ITS or out side of ITS.

In fact, mbigen is a kind of interrupt controller collects
the irq form Non-PCI devices and generate msi interrupt.

Hisilicon designed mbigen to reduce the wired interrupt
number connected to GIC.

In these patches, the interrupts from Non-PCI devices are
named as MBI to distiguish between legacy MSI interrupt from
PCI devices.

As a MSI interrupt controller, the mbigen is used as a child
domain of MSI domain just like PCI devices.

So,in order to support the mbigen interrupt controller, the
msi.c and its-gic-v3-its.c are changed.

Ma Jun (4):
  Add mbigen driver to support mbigen interrupt controller
  Change msi to support the Mbigen interrupt
  Change arm-gic-its to support the Mbigen interrupt
  dt-binding:Documents the mbigen bindings

 Documentation/devicetree/bindings/arm/mbigen.txt |   51 ++
 drivers/irqchip/Kconfig  |4 +
 drivers/irqchip/Makefile |1 +
 drivers/irqchip/irq-gic-v3-its.c |   71 +--
 drivers/irqchip/irq-mbigen.c |  562 ++
 include/linux/irq.h  |1 +
 include/linux/irqchip/arm-gic-its.h  |   68 +++
 include/linux/irqdomain.h|2 +-
 include/linux/mbi.h  |   77 +++
 include/linux/msi.h  |1 +
 kernel/irq/chip.c|   12 +-
 kernel/irq/msi.c |   22 +-
 12 files changed, 818 insertions(+), 54 deletions(-)
 create mode 100755 Documentation/devicetree/bindings/arm/mbigen.txt
 mode change 100644 => 100755 drivers/irqchip/Kconfig
 mode change 100644 => 100755 drivers/irqchip/Makefile
 mode change 100644 => 100755 drivers/irqchip/irq-gic-v3-its.c
 create mode 100755 drivers/irqchip/irq-mbigen.c
 create mode 100755 include/linux/irqchip/arm-gic-its.h
 create mode 100644 include/linux/mbi.h
 mode change 100644 => 100755 include/linux/msi.h
 mode change 100644 => 100755 kernel/irq/msi.c

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


[PATCH 2/4]: Change msi to support the Mbigen interrupt

2015-05-29 Thread majun (F)
This patch is applied to support the interrupts from Mbigen.

As a interrupt controller, Mbigen is used as a child domain of MSI
domain just like pci device.

Change log:
--add IRQ_DOMAIN_FLAG_MBIGEN to presents the interrupt from mbigen
--add function is_mbigen_domain to check the interrupt domain
--modified irq_chip_write_msi_msg to use the different message write function
  for interrupt from mbigen

Signed-off-by: Ma Jun 
---
 include/linux/irqdomain.h |2 +-
 include/linux/msi.h   |1 +
 kernel/irq/msi.c  |   22 +-
 3 files changed, 23 insertions(+), 2 deletions(-)
 mode change 100644 => 100755 include/linux/msi.h
 mode change 100644 => 100755 kernel/irq/msi.c

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 676d730..cb6b33a 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -136,7 +136,7 @@ enum {

/* Core calls alloc/free recursive through the domain hierarchy. */
IRQ_DOMAIN_FLAG_AUTO_RECURSIVE  = (1 << 1),
-
+   IRQ_DOMAIN_FLAG_MBIGEN = (1 << 2),
/*
 * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
 * for implementation specific purposes and ignored by the
diff --git a/include/linux/msi.h b/include/linux/msi.h
old mode 100644
new mode 100755
index 8ac4a68..3e2b6c7
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -239,5 +239,6 @@ irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev 
*dev,
 int pci_msi_domain_check_cap(struct irq_domain *domain,
 struct msi_domain_info *info, struct device *dev);
 #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
+bool is_mbigen_domain(struct irq_data *data);

 #endif /* LINUX_MSI_H */
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
old mode 100644
new mode 100755
index 474de5c..1dba07e
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -31,11 +31,31 @@ void get_cached_msi_msg(unsigned int irq, struct msi_msg 
*msg)
 }
 EXPORT_SYMBOL_GPL(get_cached_msi_msg);

+bool is_mbigen_domain(struct irq_data *data)
+{
+   int virq;
+   struct irq_domain *domain;
+   struct irq_data *source_irq_data;
+
+   virq = data->irq;
+   source_irq_data = irq_get_irq_data(virq);
+   domain = source_irq_data->domain;
+
+   if (domain->flags & IRQ_DOMAIN_FLAG_MBIGEN)
+   return true;
+   else
+   return false;
+
+}
+
 #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
 static inline void irq_chip_write_msi_msg(struct irq_data *data,
  struct msi_msg *msg)
 {
-   data->chip->irq_write_msi_msg(data, msg);
+   if (is_mbigen_domain(data))
+   data->chip->irq_write_mbi_msg(data, msg);
+   else
+   data->chip->irq_write_msi_msg(data, msg);
 }

 /**
-- 
1.7.1



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


[PATCH 3/4]: Change arm-gic-its to support the Mbigen interrupt

2015-05-29 Thread majun (F)
This patch is applied to support the mbigen interrupt.

Change log:
--For irq_mbigen.c using,move some struct and function definition
  to a new head file arm-gic-its.h
--Add a irq_write_mbi_msg member for mbi interrupt using
--For mbi interrupt, the event id depends on the Hardware pin number on mbigen,
  so, the its_get_event_id is changed to calclulate the event id of mbi 
interrupt
--For mbigen, the device id information need to be carried with msg. So,
  its_irq_compose_msi_msg is changed.
--its_mask_msi_irq and its_unmaks_msi_irq are modifid for mbi interrupt using.
--before the irq_ack callback, check the irq_ack first(chip.c)


Signed-off-by: Ma Jun 
---
 drivers/irqchip/irq-gic-v3-its.c|   71 +++---
 include/linux/irq.h |1 +
 include/linux/irqchip/arm-gic-its.h |   68 +
 kernel/irq/chip.c   |   12 --
 4 files changed, 100 insertions(+), 52 deletions(-)
 mode change 100644 => 100755 drivers/irqchip/irq-gic-v3-its.c
 create mode 100755 include/linux/irqchip/arm-gic-its.h

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
old mode 100644
new mode 100755
index 9687f8a..21c36bf
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -30,7 +31,7 @@
 #include 
 #include 

-#include 
+#include 

 #include 
 #include 
@@ -42,36 +43,6 @@

 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING(1 << 0)

-/*
- * Collection structure - just an ID, and a redistributor address to
- * ping. We use one per CPU as a bag of interrupts assigned to this
- * CPU.
- */
-struct its_collection {
-   u64 target_address;
-   u16 col_id;
-};
-
-/*
- * The ITS structure - contains most of the infrastructure, with the
- * msi_controller, the command queue, the collections, and the list of
- * devices writing to it.
- */
-struct its_node {
-   raw_spinlock_t  lock;
-   struct list_headentry;
-   struct msi_controller   msi_chip;
-   struct irq_domain   *domain;
-   void __iomem*base;
-   unsigned long   phys_base;
-   struct its_cmd_block*cmd_base;
-   struct its_cmd_block*cmd_write;
-   void*tables[GITS_BASER_NR_REGS];
-   struct its_collection   *collections;
-   struct list_headits_device_list;
-   u64 flags;
-   u32 ite_size;
-};

 #define ITS_ITT_ALIGN  SZ_256

@@ -79,17 +50,6 @@ struct its_node {
  * The ITS view of a device - belongs to an ITS, a collection, owns an
  * interrupt translation table, and a list of interrupts.
  */
-struct its_device {
-   struct list_headentry;
-   struct its_node *its;
-   struct its_collection   *collection;
-   void*itt;
-   unsigned long   *lpi_map;
-   irq_hw_number_t lpi_base;
-   int nr_lpis;
-   u32 nr_ites;
-   u32 device_id;
-};

 static LIST_HEAD(its_nodes);
 static DEFINE_SPINLOCK(its_lock);
@@ -528,7 +488,11 @@ static void its_send_invall(struct its_node *its, struct 
its_collection *col)
 static inline u32 its_get_event_id(struct irq_data *d)
 {
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
-   return d->hwirq - its_dev->lpi_base;
+
+   if (!is_mbigen_domain(d))
+   return d->hwirq - its_dev->lpi_base;
+   else
+   return get_mbi_offset(d->irq);
 }

 static void lpi_set_config(struct irq_data *d, bool enable)
@@ -599,7 +563,13 @@ static void its_irq_compose_msi_msg(struct irq_data *d, 
struct msi_msg *msg)

msg->address_lo = addr & ((1UL << 32) - 1);
msg->address_hi = addr >> 32;
-   msg->data   = its_get_event_id(d);
+
+   /*for devices connect to mbigen, device id
+*information is needed*/
+   if (!is_mbigen_domain(d))
+   msg->data = its_get_event_id(d);
+   else
+   msg->data = (its_dev->device_id << 16) | its_get_event_id(d);
 }

 static struct irq_chip its_irq_chip = {
@@ -613,13 +583,15 @@ static struct irq_chip its_irq_chip = {

 static void its_mask_msi_irq(struct irq_data *d)
 {
-   pci_msi_mask_irq(d);
+   if (!is_mbigen_domain(d))
+   pci_msi_mask_irq(d);
irq_chip_mask_parent(d);
 }

 static void its_unmask_msi_irq(struct irq_data *d)
 {
-   pci_msi_unmask_irq(d);
+   if (!is_mbigen_domain(d))
+   pci_msi_unmask_irq(d);
irq_chip_unmask_parent(d);
 }

@@ -629,6 +601,8 @@ static struct irq_chip its_msi_irq_chip = {
.irq_mask   = its_mask_msi_irq,
.irq_eoi= irq_chip_eoi_parent,
.irq_write_msi_msg  = pc

[PATCH 4/4]:dt-binding:Documents the mbigen bindings

2015-05-29 Thread majun (F)
Add the mbigen msi interrupt controller bindings document


Signed-off-by: Ma Jun 
---
 Documentation/devicetree/bindings/arm/mbigen.txt |   51 ++
 1 files changed, 51 insertions(+), 0 deletions(-)
 create mode 100755 Documentation/devicetree/bindings/arm/mbigen.txt

diff --git a/Documentation/devicetree/bindings/arm/mbigen.txt 
b/Documentation/devicetree/bindings/arm/mbigen.txt
new file mode 100755
index 000..d442b31
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mbigen.txt
@@ -0,0 +1,51 @@
+Hisilicon mbigen device tree bindings.
+===
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and gnerate the inteerrupt
+by wirtting ITS register.
+
+The mbigen and devices connect to mbigen have the following properties:
+
+
+Mbigen required properties:
+---
+-compatible: Should be "hisilicon,mbi-gen"
+-msi-parent: should specified the ITS mbigen connected
+-interrupt controller: Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value is 2 for now.
+- reg: Specifies the base physical address and size of the ITS
+  registers.
+
+Examples:
+
+   mbigen_pa: interrupt-controller@4c03 {
+   compatible = "hisilicon,mbi-gen";
+   msi-parent = <&its_pa>;
+   interrupt-controller;
+   #interrupt-cells = <2>;
+   reg = <0x4c03 0x1>;
+   };
+
+Device connect to mbigen required properties:
+
+-interrupt-parent: Specifies the mbigen node which device connected.
+-interrupts:specifies the interrupt source.The first cell is hwirq num, the
+  second number is trigger type.
+
+Examples:
+   usb0: ehci@a100 {
+   compatible = "generic-ehci";
+   interrupt-parent = <&mbigen_pa>;
+   reg = <0xa100 0x1>;
+   interrupts = <20 4>;
+   };
+
-- 
1.7.1


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


Re: [PATCH 1/4]:Add mbigen driver to support mbigen interrupt controller

2015-05-29 Thread majun (F)
Hi Joe Perches:
Thanks for you advice.
I will fixed it in next version

在 2015/5/30 13:38, Joe Perches 写道:
> On Sat, 2015-05-30 at 11:19 +0800, majun (F) wrote:
>> This patch contains the mbigen device driver.
> 
> Trivial notes:
> 
> Please use scripts/checkpatch.pl on your patches and see
> if you want to correct any of the messages it produces.
> 
>> diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
> 
> You could add
> #define pr_fmt(fmt) "mbigen: " fmt
> before any of the #includes so that all of the
> pr_(fmt, ...) uses are prefixed with "mbigen: "
> 
>> +int mbi_parse_irqs(struct device *dev, struct mbi_ops *ops)
>> +{
>> +pr_warn("%s:this function not use now\n", __func__);
> 
> Maybe pr_warn_once()
> 
>> +return -EINVAL;
>> +}
>> +EXPORT_SYMBOL(mbi_parse_irqs);
>> +
>> +void mbi_free_irqs(struct device *dev, unsigned int virq, unsigned int nvec)
>> +{
>> +pr_warn("%s:this function not use now\n", __func__);
> 
> pr_warn_once()?
> 
>> +static struct mbigen *mbigen_get_device(struct mbigen_chip *chip,
>> +
>> unsigned int nid)
>> +{
>> +struct mbigen *tmp, *mbigen;
>> +bool found = false;
>> +
>> +if (nid >= MG_NR) {
>> +pr_warn("MBIGEN: Device ID exceeds max number!\n");
> 
> So this wouldn't need a "MBIGEN: " prefix
> 
> etc...
> 
> 
> .
> 

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


Re: [PATCH v3 1/3] IRQ/Gic-V3: Add mbigen driver to support mbigen interrupt controller

2015-07-07 Thread majun (F)
Hi Thomas:

在 2015/7/6 20:33, Thomas Gleixner 写道:
> On Mon, 6 Jul 2015, Ma Jun wrote:
> 

>> +/**
>> + * get_mbigen_node_type: get the mbigen node type
>> + * @nid: the mbigen node value
>> + * return 0: evnent id of interrupt connected to this node can be changed.
>> + * return 1: evnent id of interrupt connected to this node cant be changed.
>> + */
>> +static int get_mbigen_node_type(int nid)
>> +{
>> +if (nid > MG_NR) {
>> +pr_warn("MBIGEN: Device ID exceeds max number!\n");
>> +return 1;
>> +}
>> +if ((nid == 0) || (nid == 5) || (nid > 7))
>> +return 0;
>> +else
>> +return 1;
> 
> Oh no. We do not hardcode such properties into a driver. That wants to
> be in the device tree and set as a property in the node data structure.
> 
Ok,I will move this to device tree

>> +static int mbigen_write_msg(struct irq_data *d, struct msi_msg *msg)
>> +{
>> +struct mbigen_chip *chip = d->domain->host_data;
>> +void __iomem *addr;
>> +u32 nid, val, offset;
>> +int ret = 0;
>> +
>> +nid = GET_NODE_NUM(d->hwirq);
>> +ret = get_mbigen_node_type(nid);
>> +if (ret)
>> +return 0;
> 
> Care to explain what this does? It seems for some nodes you cannot
> write the msi message. So how is that supposed to work? How is that
> interrupt controlled (mask/unmask ...) ?
> 
This function is used to write irq event id into vector register.Depends on
hardware design, write operation is permitted in some mbigen node(nid=0,5,and 
>7),
For other mbigen node, this register is read only.

But only vector register has this problem. Other registers are ok for 
read/write.

>> +
>> +ofst = hwirq / 32 * 4;
>> +mask = 1 << (hwirq % 32);
>> +
>> +addr = chip->base + MBIGEN_TYPE_REG_ADDR(nid, ofst);
>> +raw_spin_lock(&chip->lock);
>> +val = readl_relaxed(addr);
>> +
>> +if (type == IRQ_TYPE_LEVEL_HIGH)
>> +val |= mask;
>> +else if (type == IRQ_TYPE_EDGE_RISING)
>> +val &= ~mask;
>> +
>> +writel_relaxed(val, addr);
>> +raw_spin_unlock(&chip->lock);
> 
> What is the lock protecting here? The read/write access to a per
> interrupt register? Why is the per interrupt descriptor lock not
> sufficient and why does the above write_msg not requited locking?
> 
yes,lock protecting is not necessary here.

>> +return 0;
[...]
>> +static int mbigen_domain_alloc(struct irq_domain *domain, unsigned int virq,
>> +   unsigned int nr_irqs, void *arg)
>> +{
>> +struct mbigen_chip *chip = domain->host_data;
>> +struct of_phandle_args *irq_data = arg;
>> +irq_hw_number_t hwirq;
>> +u32 nid, dev_id, mbi_lines;
>> +struct mbigen_node *mgn_node;
>> +struct mbigen_device *mgn_dev;
>> +msi_alloc_info_t out_arg;
>> +int ret = 0, i;
>> +
>> +/* OF style allocation, one interrupt at a time */
> 
> -ENOPARSE
> 
what's this mean? I didn't find this definition in kernel code

>> +WARN_ON(nr_irqs != 1);
>> +
>> +dev_id = irq_data->args[0];
>> +nid = irq_data->args[3];
>> +hwirq = COMPOSE_HWIRQ(nid, irq_data->args[2]);
>> +
>> +mgn_node = get_mbigen_node(chip, nid);
>> +if (!mgn_node)
>> +return -ENODEV;
>> +
>> +mgn_dev = mbigen_create_device(mgn_node, irq_data->np, virq, nr_irqs);
>> +if (!mgn_dev)
>> +return -ENOMEM;
> 
> Leaks the node allocation.
> 
>> +
>> +mbi_lines = irq_data->args[1];
>> +
>> +ret = its_msi_prepare(domain, dev_id, mbi_lines, &out_arg);
> 
> This looks wrong. Why do you have an explicit call for this in the
> allocation function?
> 
> msi_domain_ops.msi_prepare is called from the core code and you should
> provide a msi_prepare callback which does the necessary initialization
> and invokes the parent domains msi_prepare callback.
> 
According to Marc suggestion, I changed the ITS code so I can use 
its_msi_prepare
function in my code.
So,do you mean i should not call this function directly ?
How about make this code likes below in mbigen driver:

static struct msi_domain_ops mbigen_domain_ops = {

.msi_prepare= mbigen_domain_ops_prepare,
};

static int mbigen_domain_ops_prepare(struct irq_domain *domain, struct device 
*dev,
   int nvec, msi_alloc_info_t *info)
{
return its_msi_prepare(domain, dev_id, count, info);
}


>> +if (ret)
>> +return ret;
> 
> Leaks the node allocation and the device.
> 
>> +
>> +ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &out_arg);
>> +if (ret < 0)
>> +return ret;
>> +
>> +for (i = 0; i < nr_irqs; i++) {
> 
> This loop is required because?
> 
Although we know this value is 1, I think use loop seems better

>> +irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
>> +&mbigen_irq_chip, mgn_dev);
>> +}
>> +
>> +return ret;
> 
>> +/*
>> + * Early initialization as an interrupt 

  1   2   >