From 9d08aa71a705d6b8c903691d1549085b0f0625d3 Mon Sep 17 00:00:00 2001
From: Federico Vaga <federico.vaga@cern.ch>
Date: Fri, 21 Oct 2016 11:11:29 +0200
Subject: [PATCH] kernel:*: get IRQ numbers from the VIC domain

Actually, this is not what I want. I would like to just use an IRQ
resource with the correct IRQ number. What I want is to hide the IRQ
domain knowledge elsewhere. For instance, in the wrs_device module
that register all our devices. But, since I have to update the kernel
with the least number of changes I will leave this for the future.

Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
---
 kernel/wr_nic/device.c       | 38 +++++++++++++++++++++++++++++++-----
 kernel/wr_nic/nic-hardware.h |  2 +-
 kernel/wr_pstats/wr_pstats.c | 34 +++++++++++++++++++++++++++++---
 3 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/kernel/wr_nic/device.c b/kernel/wr_nic/device.c
index d3f61b56f..20aef6531 100644
--- a/kernel/wr_nic/device.c
+++ b/kernel/wr_nic/device.c
@@ -20,10 +20,19 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/irqdomain.h>
 
 #include "wr-nic.h"
 #include "nic-mem.h"
 
+/**
+ * IRQ domain to be used. This is static here but in general it should be
+ * a module parameter or somehow configurable. For the time being we keep
+ * it hard-coded here.
+ */
+static const char *irqdomain_name = "htvic-wr-swi.0";
+
+
 #if WR_IS_NODE /* Our platform_data is different in node vs switch */
 #include "../spec-nic.h"
 static inline struct wrn_dev *wrn_from_pdev(struct platform_device *pdev)
@@ -42,7 +51,15 @@ static inline struct wrn_dev *wrn_from_pdev(struct platform_device *pdev)
 static int wrn_remove(struct platform_device *pdev)
 {
 	struct wrn_dev *wrn = wrn_from_pdev(pdev);
-	int i;
+	int i, irq;
+	struct irq_domain *irqdomain;
+
+	irqdomain = irq_find_host((struct device_node *)irqdomain_name);
+	if (!irqdomain) {
+		dev_err(&pdev->dev, "The IRQ domain %s does not exist\n",
+			irqdomain_name);
+		return -EINVAL;
+	}
 
 	if (WR_IS_SWITCH) {
 		spin_lock(&wrn->lock);
@@ -71,8 +88,10 @@ static int wrn_remove(struct platform_device *pdev)
 	/* Unregister all interrupts that were registered */
 	for (i = 0; wrn->irq_registered; i++) {
 		static int irqs[] = WRN_IRQ_NUMBERS;
-		if (wrn->irq_registered & (1 << i))
-			free_irq(irqs[i], wrn);
+		if (wrn->irq_registered & (1 << i)) {
+			irq = irq_find_mapping(irqdomain, irqs[i]);
+			free_irq(irq, wrn);
+		}
 		wrn->irq_registered &= ~(1 << i);
 	}
 	return 0;
@@ -113,12 +132,20 @@ static int wrn_probe(struct platform_device *pdev)
 	struct net_device *netdev;
 	struct wrn_ep *ep;
 	struct wrn_dev *wrn = wrn_from_pdev(pdev);
-	int i, err = 0;
+	int i, err = 0, irq;
 
 	/* Lazily: irqs are not in the resource list */
 	static int irqs[] = WRN_IRQ_NUMBERS;
 	static char *irq_names[] = WRN_IRQ_NAMES;
 	static irq_handler_t irq_handlers[] = WRN_IRQ_HANDLERS;
+	struct irq_domain *irqdomain;
+
+	irqdomain = irq_find_host((struct device_node *)irqdomain_name);
+	if (!irqdomain) {
+		dev_err(&pdev->dev, "The IRQ domain %s does not exist\n",
+			irqdomain_name);
+		return -EINVAL;
+	}
 
 	/* No need to lock_irq: we only protect count and continue unlocked */
 	if (WR_IS_SWITCH) {
@@ -148,7 +175,8 @@ static int wrn_probe(struct platform_device *pdev)
 	if (WR_IS_SWITCH) {
 		/* Register the interrupt handlers (not shared) */
 		for (i = 0; i < ARRAY_SIZE(irq_names); i++) {
-			err = request_irq(irqs[i], irq_handlers[i],
+			irq = irq_find_mapping(irqdomain, irqs[i]);
+			err = request_irq(irq, irq_handlers[i],
 					  IRQF_TRIGGER_LOW, irq_names[i], wrn);
 			if (err)
 				goto out;
diff --git a/kernel/wr_nic/nic-hardware.h b/kernel/wr_nic/nic-hardware.h
index ecaa2f107..a51a4bd13 100644
--- a/kernel/wr_nic/nic-hardware.h
+++ b/kernel/wr_nic/nic-hardware.h
@@ -20,7 +20,7 @@
 #define NSEC_PER_TICK (NSEC_PER_SEC / REFCLK_FREQ)
 
 /* The interrupt is one of those managed by our WRVIC device */
-#define WRN_IRQ_BASE		192
+#define WRN_IRQ_BASE		0
 #define WRN_IRQ_NIC		(WRN_IRQ_BASE + 0)
 #define WRN_IRQ_TSTAMP		(WRN_IRQ_BASE + 1)
 //#define WRN_IRQ_PPSG		(WRN_IRQ_BASE + )
diff --git a/kernel/wr_pstats/wr_pstats.c b/kernel/wr_pstats/wr_pstats.c
index 1842c71ac..5d12f2a79 100644
--- a/kernel/wr_pstats/wr_pstats.c
+++ b/kernel/wr_pstats/wr_pstats.c
@@ -28,6 +28,7 @@
 #include <linux/spinlock.h>
 #include <linux/moduleparam.h>
 #include <linux/netdevice.h>
+#include <linux/irqdomain.h>
 
 /*
  * Ugly trick to be able to use headers that have been moved out
@@ -41,6 +42,13 @@
 #define pstats_readl(device, r)		__raw_readl(&device.regs->r)
 #define pstats_writel(val, device, r)	__raw_writel(val, &device.regs->r)
 
+/**
+ * IRQ domain to be used. This is static here but in general it should be
+ * a module parameter or somehow configurable. For the time being we keep
+ * it hard-coded here.
+ */
+static const char *irqdomain_name = "htvic-wr-swi.0";
+
 static int pstats_nports = PSTATS_DEFAULT_NPORTS;
 static uint32_t portmsk;
 static unsigned int firmware_version; /* FPGA firmware version */
@@ -442,8 +450,16 @@ static struct ctl_table_header *pstats_header;
 
 static int __init pstats_init(void)
 {
-	int i, err = 0;
+	int i, err = 0, irq;
 	unsigned int data;
+	struct irq_domain *irqdomain;
+
+	irqdomain = irq_find_host((struct device_node *)irqdomain_name);
+	if (!irqdomain) {
+		pr_err("pstat: The IRQ domain %s does not exist\n",
+			irqdomain_name);
+		return -EINVAL;
+	}
 
 	if (pstats_nports > PSTATS_MAX_NPORTS) {
 		printk(KERN_ERR "%s: Too many ports for pstats %u,"
@@ -531,7 +547,8 @@ static int __init pstats_init(void)
 
 	/*request pstats IRQ*/
 	pstats_irq_disable(PSTATS_ALL_MSK);
-	err = request_irq(WRVIC_BASE_IRQ+WR_PSTATS_IRQ, pstats_irq_handler,
+	irq = irq_find_mapping(irqdomain, WR_PSTATS_IRQ);
+	err = request_irq(irq, pstats_irq_handler,
 			IRQF_SHARED, "wr_pstats", &pstats_dev);
 	if (err) {
 		printk(KERN_ERR "%s: cannot request interrupt\n",
@@ -559,8 +576,19 @@ err_exit:
 
 static void __exit pstats_exit(void)
 {
+	int irq;
+	struct irq_domain *irqdomain;
+
 	pstats_irq_disable(PSTATS_ALL_MSK);
-	free_irq(WRVIC_BASE_IRQ+WR_PSTATS_IRQ, &pstats_dev);
+
+	irqdomain = irq_find_host((struct device_node *)irqdomain_name);
+	if (!irqdomain) {
+		pr_err("pstat: The IRQ domain %s does not exist\n",
+			irqdomain_name);
+	} else {
+		irq = irq_find_mapping(irqdomain, WR_PSTATS_IRQ);
+		free_irq(irq, &pstats_dev);
+	}
 
 	wr_nic_pstats_callback = NULL;
 
-- 
GitLab