Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1235951 > unrolled thread
| Started by | MaJun <majun258@huawei.com> |
|---|---|
| First post | 2015-09-30 11:50 +0200 |
| Last post | 2015-09-30 11:50 +0200 |
| Articles | 2 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v5 0/3] Support Mbigen interrupt controller MaJun <majun258@huawei.com> - 2015-09-30 11:50 +0200
[PATCH v5 2/3] Probe mbigen chip and initial mbigen device as platform device. MaJun <majun258@huawei.com> - 2015-09-30 11:50 +0200
| From | MaJun <majun258@huawei.com> |
|---|---|
| Date | 2015-09-30 11:50 +0200 |
| Subject | [PATCH v5 0/3] Support Mbigen interrupt controller |
| Message-ID | <qembn-1aV-13@gated-at.bofh.it> |
From: Ma Jun <majun258@huawei.com> 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 majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | MaJun <majun258@huawei.com> |
|---|---|
| Date | 2015-09-30 11:50 +0200 |
| Subject | [PATCH v5 2/3] Probe mbigen chip and initial mbigen device as platform device. |
| Message-ID | <qembp-1aV-35@gated-at.bofh.it> |
| In reply to | #1235951 |
From: Ma Jun <majun258@huawei.com>
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 <majun258@huawei.com>
---
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_head local_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_head local_entry;
struct list_head global_entry;
struct device_node *node;
struct mbigen_irq_data *mgn_data;
unsigned int nr_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 msi_desc *desc;
+ void __iomem *base;
+ int ret;
+
+ mgn_chip = kzalloc(sizeof(*mgn_chip), GFP_KERNEL);
+ if (!mgn_chip)
+ return -ENOMEM;
+
+ mgn_chip->pdev = pdev;
+
+ base = of_iomap(root, 0);
+ mgn_chip->base = base;
+
+ of_platform_populate(root, NULL, NULL, &pdev->dev);
+
+ for_each_child_of_node(root, child) {
+ mgn_dev = find_mbigen_device(child);
+ mgn_pdev = of_find_device_by_node(child);
+
+ mgn_dev->base = base;
+ mgn_dev->pdev = mgn_pdev;
+ mgn_dev->chip = mgn_chip;
+
+ /* go to allocate msi-irqs from ITS-pMSI domain */
+ ret = platform_msi_domain_alloc_irqs(&mgn_pdev->dev,
+ mgn_dev->nr_irqs, mbigen_write_msg);
+ if (ret) {
+ pr_warn("mbigen-v2:failed to allocate msi irqs\n");
+ continue;
+ }
+
+ for_each_msi_entry(desc, &mgn_pdev->dev) {
+ mbigen_set_irq_handler_data(desc, mgn_dev);
+ irq_set_chained_handler(desc->irq, mbigen_handle_cascade_irq);
+ }
+
+ /* add this mbigen device into local mbigen device list
+ *which belong to mbigen chip
+ */
+ INIT_LIST_HEAD(&mgn_dev->local_entry);
+ INIT_LIST_HEAD(&mgn_chip->local_mgn_dev_list);
+ raw_spin_lock_init(&mgn_chip->lock);
+
+ raw_spin_lock(&mgn_chip->lock);
+ list_add(&mgn_dev->local_entry, &mgn_chip->local_mgn_dev_list);
+ raw_spin_unlock(&mgn_chip->lock);
+ }
+
+ platform_set_drvdata(pdev, mgn_chip);
+
+ return 0;
+}
+
+static int mbigen_chip_remove(struct platform_device *pdev)
+{
+ struct mbigen_chip *mgn_chip = platform_get_drvdata(pdev);
+ struct mbigen_device *mgn_dev, *tmp;
+
+ raw_spin_lock(&mgn_chip->lock);
+ list_for_each_entry_safe(mgn_dev, tmp, &mgn_chip->local_mgn_dev_list,
+ local_entry) {
+ list_del(&mgn_dev->local_entry);
+ mbigen_device_free(mgn_dev);
+ }
+ raw_spin_lock(&mgn_chip->lock);
+
+ iounmap(mgn_chip->base);
+ kfree(mgn_chip);
+
+ 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_chip_probe,
+ .remove = mbigen_chip_remove,
+};
+
+static int __init mbigen_chip_init(void)
+{
+ return platform_driver_register(&mbigen_platform_driver);
+}
+core_initcall(mbigen_chip_init);
+
MODULE_AUTHOR("Jun Ma <majun258@huawei.com>");
MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>");
MODULE_LICENSE("GPL");
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web