All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events
@ 2015-04-10  8:24 Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 2/8] ipmi/powernv: Convert to irq event interface Alistair Popple
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Alistair Popple @ 2015-04-10  8:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple

Whenever an interrupt is received for opal the linux kernel gets a
bitfield indicating certain events that have occurred and need handling
by the various device drivers. Currently this is handled using a
notifier interface where we call every device driver that has
registered to receive opal events.

This approach has several drawbacks. For example each driver has to do
its own checking to see if the event is relevant as well as event
masking. There is also no easy method of recording the number of times
we receive particular events.

This patch solves these issues by exposing opal events via the
standard interrupt APIs by adding a new interrupt chip and
domain. Drivers can then register for the appropriate events using
standard kernel calls such as irq_of_parse_and_map().

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/include/asm/opal.h               |   2 +
 arch/powerpc/platforms/powernv/Makefile       |   2 +-
 arch/powerpc/platforms/powernv/opal-irqchip.c | 244 ++++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal.c         |  70 +-------
 arch/powerpc/platforms/powernv/powernv.h      |   4 +
 5 files changed, 256 insertions(+), 66 deletions(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-irqchip.c

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 9ee0a30..4d969f7 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -979,6 +979,8 @@ extern int opal_resync_timebase(void);
 
 extern void opal_lpc_init(void);
 
+extern int opal_event_request(unsigned int opal_event_nr);
+
 struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
 					     unsigned long vmalloc_size);
 void opal_free_sg_list(struct opal_sg_list *sg);
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 6f3c5d3..911154f 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -1,7 +1,7 @@
 obj-y			+= setup.o opal-wrappers.o opal.o opal-async.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
-obj-y			+= opal-msglog.o opal-hmi.o opal-power.o
+obj-y			+= opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
 
 obj-$(CONFIG_SMP)	+= smp.o subcore.o subcore-asm.o
 obj-$(CONFIG_PCI)	+= pci.o pci-p5ioc2.o pci-ioda.o
diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c
new file mode 100644
index 0000000..5eef3c9
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-irqchip.c
@@ -0,0 +1,244 @@
+/*
+ * This file implements an irqchip for OPAL events. Whenever there is
+ * an interrupt that is handled by OPAL we get passed a list of events
+ * that Linux needs to do something about. These basically look like
+ * interrupts to Linux so we implement an irqchip to handle them.
+ *
+ * Copyright Alistair Popple, IBM Corporation 2014.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/irq_work.h>
+
+#include <asm/machdep.h>
+#include <asm/opal.h>
+
+#include "powernv.h"
+
+struct opal_event_irqchip {
+	struct irq_chip irqchip;
+	struct irq_domain *domain;
+	unsigned long mask;
+};
+static struct opal_event_irqchip opal_event_irqchip;
+
+static unsigned int opal_irq_count;
+static unsigned int *opal_irqs;
+
+static void opal_handle_irq_work(struct irq_work *work);
+static __be64 last_outstanding_events = 0;
+static struct irq_work opal_event_irq_work = {
+	.func = opal_handle_irq_work,
+};
+
+static void opal_event_mask(struct irq_data *d)
+{
+	clear_bit(d->hwirq, &opal_event_irqchip.mask);
+}
+
+static void opal_event_unmask(struct irq_data *d)
+{
+	set_bit(d->hwirq, &opal_event_irqchip.mask);
+
+	opal_poll_events(&last_outstanding_events);
+	if (last_outstanding_events & opal_event_irqchip.mask)
+		/* Need to retrigger the interrupt */
+		irq_work_queue(&opal_event_irq_work);
+}
+
+static int opal_event_set_type(struct irq_data *d, unsigned int flow_type)
+{
+	/*
+	 * For now we only support level triggered events. The irq
+	 * handler will be called continuously until the event has
+	 * been cleared in OPAL.
+	 */
+	if (flow_type != IRQ_TYPE_LEVEL_HIGH)
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct opal_event_irqchip opal_event_irqchip = {
+	.irqchip = {
+		.name = "OPAL EVT",
+		.irq_mask = opal_event_mask,
+		.irq_unmask = opal_event_unmask,
+		.irq_set_type = opal_event_set_type,
+	},
+	.mask = 0,
+};
+
+static int opal_event_map(struct irq_domain *d, unsigned int irq,
+			irq_hw_number_t hwirq)
+{
+	irq_set_chip_data(irq, &opal_event_irqchip);
+	irq_set_chip_and_handler(irq, &opal_event_irqchip.irqchip,
+				handle_level_irq);
+
+	return 0;
+}
+
+void opal_handle_events(uint64_t events)
+{
+	int virq, hwirq = 0;
+	u64 mask = opal_event_irqchip.mask;
+	u64 notifier_mask = 0;
+
+	while (events) {
+		hwirq = fls64(events) - 1;
+		virq = irq_find_mapping(opal_event_irqchip.domain,
+					hwirq);
+		if (virq) {
+			if (BIT_ULL(hwirq) & mask)
+				generic_handle_irq(virq);
+		} else
+			notifier_mask |= BIT_ULL(hwirq);
+		events &= ~BIT_ULL(hwirq);
+	}
+
+	opal_do_notifier(notifier_mask);
+}
+
+static irqreturn_t opal_interrupt(int irq, void *data)
+{
+	__be64 events;
+
+	opal_handle_interrupt(virq_to_hw(irq), &events);
+	opal_handle_events(be64_to_cpu(events));
+
+	return IRQ_HANDLED;
+}
+
+static void opal_handle_irq_work(struct irq_work *work)
+{
+	opal_handle_events(be64_to_cpu(last_outstanding_events));
+}
+
+static int opal_event_match(struct irq_domain *h, struct device_node *node)
+{
+	return h->of_node == node;
+}
+
+static int opal_event_xlate(struct irq_domain *h, struct device_node *np,
+			   const u32 *intspec, unsigned int intsize,
+			   irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+	*out_hwirq = intspec[0];
+	*out_flags = IRQ_TYPE_LEVEL_HIGH;
+
+	return 0;
+}
+
+static const struct irq_domain_ops opal_event_domain_ops = {
+	.match	= opal_event_match,
+	.map	= opal_event_map,
+	.xlate	= opal_event_xlate,
+};
+
+void opal_event_shutdown(void)
+{
+	unsigned int i;
+
+	/* First free interrupts, which will also mask them */
+	for (i = 0; i < opal_irq_count; i++) {
+		if (opal_irqs[i])
+			free_irq(opal_irqs[i], NULL);
+		opal_irqs[i] = 0;
+	}
+}
+
+static int __init opal_event_init(void)
+{
+	struct device_node *dn, *opal_node;
+	const __be32 *irqs;
+	int i, irqlen;
+
+	opal_node = of_find_node_by_path("/ibm,opal");
+	if (!opal_node) {
+		pr_warn("opal: Node not found\n");
+		return -ENODEV;
+	}
+
+	dn = of_find_compatible_node(NULL, NULL, "ibm,opal-event");
+
+	/* If dn is NULL it means the domain won't be linked to a DT
+	 * node so therefore irq_of_parse_and_map(...) wont work. But
+	 * that shouldn't be problem because if we're running a
+	 * version of skiboot that doesn't have the dn then the
+	 * devices won't have the correct properties and will have to
+	 * fall back to the legacy method (opal_event_request(...))
+	 * anyway. */
+	opal_event_irqchip.domain =
+		irq_domain_add_linear(dn, 64, &opal_event_domain_ops,
+				      &opal_event_irqchip);
+	if (IS_ERR(opal_event_irqchip.domain)) {
+		pr_warn("opal: Unable to create irq domain\n");
+		return PTR_ERR(opal_event_irqchip.domain);
+	}
+
+	/* Get interrupt property */
+	irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);
+	opal_irq_count = irqs ? (irqlen / 4) : 0;
+	pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count);
+
+	/* Install interrupt handlers */
+	opal_irqs = kcalloc(opal_irq_count, sizeof(unsigned int), GFP_KERNEL);
+	for (i = 0; irqs && i < opal_irq_count; i++, irqs++) {
+		unsigned int irq, virq;
+		int rc;
+
+		/* Get hardware and virtual IRQ */
+		irq = be32_to_cpup(irqs);
+		virq = irq_create_mapping(NULL, irq);
+		if (virq == NO_IRQ) {
+			pr_warn("Failed to map irq 0x%x\n", irq);
+			continue;
+		}
+
+		/* Install interrupt handler */
+		rc = request_irq(virq, opal_interrupt, 0, "opal", NULL);
+		if (rc) {
+			irq_dispose_mapping(virq);
+			pr_warn("Error %d requesting irq %d (0x%x)\n",
+				 rc, virq, irq);
+			continue;
+		}
+
+		/* Cache IRQ */
+		opal_irqs[i] = virq;
+	}
+
+	return 0;
+}
+machine_core_initcall(powernv, opal_event_init);
+
+/**
+ * opal_event_request(unsigned int opal_event_nr) - Request an event
+ * @opal_event_nr: the opal event number to request
+ *
+ * This routine can be used to find the linux virq number which can
+ * then be passed to request_irq to assign a handler for a particular
+ * opal event. This should only be used by legacy devices which don't
+ * have proper device tree bindings. Most devices should use
+ * irq_of_parse_and_map() instead.
+ */
+int opal_event_request(unsigned int opal_event_nr)
+{
+	return irq_create_mapping(opal_event_irqchip.domain, opal_event_nr);
+}
+EXPORT_SYMBOL(opal_event_request);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 18fd4e7..1d73b85 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -51,8 +51,6 @@ static int mc_recoverable_range_len;
 
 struct device_node *opal_node;
 static DEFINE_SPINLOCK(opal_write_lock);
-static unsigned int *opal_irqs;
-static unsigned int opal_irq_count;
 static ATOMIC_NOTIFIER_HEAD(opal_notifier_head);
 static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX];
 static DEFINE_SPINLOCK(opal_notifier_lock);
@@ -248,7 +246,7 @@ int opal_notifier_unregister(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(opal_notifier_unregister);
 
-static void opal_do_notifier(uint64_t events)
+void opal_do_notifier(uint64_t events)
 {
 	unsigned long flags;
 	uint64_t changed_mask;
@@ -566,8 +564,10 @@ int opal_handle_hmi_exception(struct pt_regs *regs)
 
 	local_paca->hmi_event_available = 0;
 	rc = opal_poll_events(&evt);
-	if (rc == OPAL_SUCCESS && evt)
+	if (rc == OPAL_SUCCESS && evt) {
 		opal_do_notifier(be64_to_cpu(evt));
+		opal_handle_events(be64_to_cpu(evt));
+	}
 
 	return 1;
 }
@@ -604,17 +604,6 @@ out:
 	return !!recover_addr;
 }
 
-static irqreturn_t opal_interrupt(int irq, void *data)
-{
-	__be64 events;
-
-	opal_handle_interrupt(virq_to_hw(irq), &events);
-
-	opal_do_notifier(be64_to_cpu(events));
-
-	return IRQ_HANDLED;
-}
-
 static int opal_sysfs_init(void)
 {
 	opal_kobj = kobject_create_and_add("opal", firmware_kobj);
@@ -701,46 +690,6 @@ static void opal_i2c_create_devs(void)
 		of_platform_device_create(np, NULL, NULL);
 }
 
-static void __init opal_irq_init(struct device_node *dn)
-{
-	const __be32 *irqs;
-	int i, irqlen;
-
-	/* Get interrupt property */
-	irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);
-	opal_irq_count = irqs ? (irqlen / 4) : 0;
-	pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count);
-	if (!opal_irq_count)
-		return;
-
-	/* Install interrupt handlers */
-	opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL);
-	for (i = 0; irqs && i < opal_irq_count; i++, irqs++) {
-		unsigned int irq, virq;
-		int rc;
-
-		/* Get hardware and virtual IRQ */
-		irq = be32_to_cpup(irqs);
-		virq = irq_create_mapping(NULL, irq);
-		if (virq == NO_IRQ) {
-			pr_warn("Failed to map irq 0x%x\n", irq);
-			continue;
-		}
-
-		/* Install interrupt handler */
-		rc = request_irq(virq, opal_interrupt, 0, "opal", NULL);
-		if (rc) {
-			irq_dispose_mapping(virq);
-			pr_warn("Error %d requesting irq %d (0x%x)\n",
-				 rc, virq, irq);
-			continue;
-		}
-
-		/* Cache IRQ */
-		opal_irqs[i] = virq;
-	}
-}
-
 static int __init opal_init(void)
 {
 	struct device_node *np, *consoles;
@@ -769,9 +718,6 @@ static int __init opal_init(void)
 	/* Create i2c platform devices */
 	opal_i2c_create_devs();
 
-	/* Find all OPAL interrupts and request them */
-	opal_irq_init(opal_node);
-
 	/* Create "opal" kobject under /sys/firmware */
 	rc = opal_sysfs_init();
 	if (rc == 0) {
@@ -799,15 +745,9 @@ machine_subsys_initcall(powernv, opal_init);
 
 void opal_shutdown(void)
 {
-	unsigned int i;
 	long rc = OPAL_BUSY;
 
-	/* First free interrupts, which will also mask them */
-	for (i = 0; i < opal_irq_count; i++) {
-		if (opal_irqs[i])
-			free_irq(opal_irqs[i], NULL);
-		opal_irqs[i] = 0;
-	}
+	opal_event_shutdown();
 
 	/*
 	 * Then sync with OPAL which ensure anything that can
diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index 604c48e..41edf6c 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -33,6 +33,10 @@ extern u32 pnv_get_supported_cpuidle_states(void);
 
 extern void pnv_lpc_init(void);
 
+extern void opal_do_notifier(uint64_t events);
+extern void opal_handle_events(uint64_t events);
+extern void opal_event_shutdown(void);
+
 bool cpu_core_split_required(void);
 
 #endif /* _POWERNV_H */
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH V2 2/8] ipmi/powernv: Convert to irq event interface
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
@ 2015-04-10  8:24 ` Alistair Popple
  2015-04-27  3:30   ` Michael Ellerman
  2015-04-10  8:24 ` [PATCH V2 3/8] hvc: Convert to using interrupts instead of opal events Alistair Popple
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 11+ messages in thread
From: Alistair Popple @ 2015-04-10  8:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple

Convert the opal ipmi driver to use the new irq interface for events.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 drivers/char/ipmi/ipmi_powernv.c | 39 ++++++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 17 deletions(-)

diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c
index 79524ed..b3a2224 100644
--- a/drivers/char/ipmi/ipmi_powernv.c
+++ b/drivers/char/ipmi/ipmi_powernv.c
@@ -15,6 +15,8 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
 
 #include <asm/opal.h>
 
@@ -23,8 +25,7 @@ struct ipmi_smi_powernv {
 	u64			interface_id;
 	struct ipmi_device_id	ipmi_id;
 	ipmi_smi_t		intf;
-	u64			event;
-	struct notifier_block	event_nb;
+	unsigned int		irq;
 
 	/**
 	 * We assume that there can only be one outstanding request, so
@@ -196,15 +197,12 @@ static struct ipmi_smi_handlers ipmi_powernv_smi_handlers = {
 	.poll			= ipmi_powernv_poll,
 };
 
-static int ipmi_opal_event(struct notifier_block *nb,
-			  unsigned long events, void *change)
+static irqreturn_t ipmi_opal_event(int irq, void *data)
 {
-	struct ipmi_smi_powernv *smi = container_of(nb,
-					struct ipmi_smi_powernv, event_nb);
+	struct ipmi_smi_powernv *smi = data;
 
-	if (events & smi->event)
-		ipmi_powernv_recv(smi);
-	return 0;
+	ipmi_powernv_recv(smi);
+	return IRQ_HANDLED;
 }
 
 static int ipmi_powernv_probe(struct platform_device *pdev)
@@ -239,13 +237,16 @@ static int ipmi_powernv_probe(struct platform_device *pdev)
 		goto err_free;
 	}
 
-	ipmi->event = 1ull << prop;
-	ipmi->event_nb.notifier_call = ipmi_opal_event;
+	ipmi->irq = irq_of_parse_and_map(dev->of_node, 0);
+	if (!ipmi->irq) {
+		dev_info(dev, "Unable to map irq from device tree\n");
+		ipmi->irq = opal_event_request(prop);
+	}
 
-	rc = opal_notifier_register(&ipmi->event_nb);
-	if (rc) {
-		dev_warn(dev, "OPAL notifier registration failed (%d)\n", rc);
-		goto err_free;
+	if (request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH,
+				"opal-ipmi", ipmi)) {
+		dev_warn(dev, "Unable to request irq\n");
+		goto err_dispose;
 	}
 
 	ipmi->opal_msg = devm_kmalloc(dev,
@@ -270,7 +271,9 @@ static int ipmi_powernv_probe(struct platform_device *pdev)
 err_free_msg:
 	devm_kfree(dev, ipmi->opal_msg);
 err_unregister:
-	opal_notifier_unregister(&ipmi->event_nb);
+	free_irq(ipmi->irq, ipmi);
+err_dispose:
+	irq_dispose_mapping(ipmi->irq);
 err_free:
 	devm_kfree(dev, ipmi);
 	return rc;
@@ -281,7 +284,9 @@ static int ipmi_powernv_remove(struct platform_device *pdev)
 	struct ipmi_smi_powernv *smi = dev_get_drvdata(&pdev->dev);
 
 	ipmi_unregister_smi(smi->intf);
-	opal_notifier_unregister(&smi->event_nb);
+	free_irq(smi->irq, smi);
+	irq_dispose_mapping(smi->irq);
+
 	return 0;
 }
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH V2 3/8] hvc: Convert to using interrupts instead of opal events
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 2/8] ipmi/powernv: Convert to irq event interface Alistair Popple
@ 2015-04-10  8:24 ` Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 4/8] powernv/eeh: Update the EEH code to use the opal irq domain Alistair Popple
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Alistair Popple @ 2015-04-10  8:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple

Convert the opal hvc driver to use the new irqchip to register for
opal events. As older firmware versions may not have device tree
bindings for the interrupt parent we just use a hardcoded hwirq based
on the event number.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 drivers/tty/hvc/hvc_opal.c | 33 +++++++++++----------------------
 1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index 071551b..71aac49 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -29,6 +29,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/export.h>
+#include <linux/interrupt.h>
 
 #include <asm/hvconsole.h>
 #include <asm/prom.h>
@@ -162,27 +163,15 @@ static const struct hv_ops hvc_opal_hvsi_ops = {
 	.tiocmset = hvc_opal_hvsi_tiocmset,
 };
 
-static int hvc_opal_console_event(struct notifier_block *nb,
-				  unsigned long events, void *change)
-{
-	if (events & OPAL_EVENT_CONSOLE_INPUT)
-		hvc_kick();
-	return 0;
-}
-
-static struct notifier_block hvc_opal_console_nb = {
-	.notifier_call	= hvc_opal_console_event,
-};
-
 static int hvc_opal_probe(struct platform_device *dev)
 {
 	const struct hv_ops *ops;
 	struct hvc_struct *hp;
 	struct hvc_opal_priv *pv;
 	hv_protocol_t proto;
-	unsigned int termno, boot = 0;
+	unsigned int termno, irq, boot = 0;
 	const __be32 *reg;
-
+	int rc;
 
 	if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) {
 		proto = HV_PROTOCOL_RAW;
@@ -227,18 +216,18 @@ static int hvc_opal_probe(struct platform_device *dev)
 		dev->dev.of_node->full_name,
 		boot ? " (boot console)" : "");
 
-	/* We don't do IRQ ... */
-	hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS);
+	irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT));
+	if (!irq) {
+		pr_err("hvc_opal: Unable to map interrupt for device %s\n",
+			dev->dev.of_node->full_name);
+		return irq;
+	}
+
+	hp = hvc_alloc(termno, irq, ops, MAX_VIO_PUT_CHARS);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 	dev_set_drvdata(&dev->dev, hp);
 
-	/* ...  but we use OPAL event to kick the console */
-	if (!hvc_opal_event_registered) {
-		opal_notifier_register(&hvc_opal_console_nb);
-		hvc_opal_event_registered = true;
-	}
-
 	return 0;
 }
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH V2 4/8] powernv/eeh: Update the EEH code to use the opal irq domain
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 2/8] ipmi/powernv: Convert to irq event interface Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 3/8] hvc: Convert to using interrupts instead of opal events Alistair Popple
@ 2015-04-10  8:24 ` Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 5/8] powernv/opal: Convert opal message events to " Alistair Popple
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Alistair Popple @ 2015-04-10  8:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple

The eeh code currently uses the old notifier method to get eeh events
from OPAL. It also contains some logic to filter opal events which has
been moved into the virtual irqchip. This patch converts the eeh code
to the new event interface which simplifies event handling.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/platforms/powernv/eeh-ioda.c | 58 +++++++++++++++++--------------
 1 file changed, 31 insertions(+), 27 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 2809c98..6dffc31 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/msi.h>
 #include <linux/notifier.h>
@@ -35,35 +36,24 @@
 #include "pci.h"
 
 static int ioda_eeh_nb_init = 0;
+static int eeh_event_irq = -EINVAL;
 
-static int ioda_eeh_event(struct notifier_block *nb,
-			  unsigned long events, void *change)
+static irqreturn_t ioda_eeh_event(int irq, void *data)
 {
-	uint64_t changed_evts = (uint64_t)change;
-
 	/*
-	 * We simply send special EEH event if EEH has
-	 * been enabled, or clear pending events in
-	 * case that we enable EEH soon
+	 * We simply send special EEH event if EEH has been
+	 * enabled. We don't care about EEH events until we've
+	 * finished processing the outstanding ones. Event processing
+	 * gets unmasked in next_error() if EEH is enabled.
 	 */
-	if (!(changed_evts & OPAL_EVENT_PCI_ERROR) ||
-	    !(events & OPAL_EVENT_PCI_ERROR))
-		return 0;
+	disable_irq_nosync(irq);
 
 	if (eeh_enabled())
 		eeh_send_failure_event(NULL);
-	else
-		opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
 
-	return 0;
+	return IRQ_HANDLED;
 }
 
-static struct notifier_block ioda_eeh_nb = {
-	.notifier_call	= ioda_eeh_event,
-	.next		= NULL,
-	.priority	= 0
-};
-
 #ifdef CONFIG_DEBUG_FS
 static ssize_t ioda_eeh_ei_write(struct file *filp,
 				 const char __user *user_buf,
@@ -185,16 +175,28 @@ static int ioda_eeh_post_init(struct pci_controller *hose)
 
 	/* Register OPAL event notifier */
 	if (!ioda_eeh_nb_init) {
-		ret = opal_notifier_register(&ioda_eeh_nb);
-		if (ret) {
-			pr_err("%s: Can't register OPAL event notifier (%d)\n",
-			       __func__, ret);
+		eeh_event_irq = opal_event_request(ilog2(OPAL_EVENT_PCI_ERROR));
+		if (eeh_event_irq < 0) {
+			pr_err("%s: Can't register OPAL event interrupt (%d)\n",
+			       __func__, eeh_event_irq);
+			return eeh_event_irq;
+		}
+
+		ret = request_irq(eeh_event_irq, ioda_eeh_event, IRQ_TYPE_LEVEL_HIGH,
+				"opal-eeh", NULL);
+		if (ret < 0) {
+			irq_dispose_mapping(eeh_event_irq);
+			pr_err("%s: Can't request OPAL event interrupt (%d)\n",
+			       __func__, eeh_event_irq);
 			return ret;
 		}
 
 		ioda_eeh_nb_init = 1;
 	}
 
+	if (!eeh_enabled())
+		disable_irq(eeh_event_irq);
+
 #ifdef CONFIG_DEBUG_FS
 	if (!phb->has_dbgfs && phb->dbgfs) {
 		phb->has_dbgfs = 1;
@@ -964,12 +966,10 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
 	int state, ret = EEH_NEXT_ERR_NONE;
 
 	/*
-	 * While running here, it's safe to purge the event queue.
-	 * And we should keep the cached OPAL notifier event sychronized
-	 * between the kernel and firmware.
+	 * While running here, it's safe to purge the event queue. The
+	 * event should still be masked.
 	 */
 	eeh_remove_event(NULL, false);
-	opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
 
 	list_for_each_entry(hose, &hose_list, list_node) {
 		/*
@@ -1134,6 +1134,10 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
 			break;
 	}
 
+	/* Unmask the event */
+	if (eeh_enabled())
+		enable_irq(eeh_event_irq);
+
 	return ret;
 }
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH V2 5/8] powernv/opal: Convert opal message events to opal irq domain
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
                   ` (2 preceding siblings ...)
  2015-04-10  8:24 ` [PATCH V2 4/8] powernv/eeh: Update the EEH code to use the opal irq domain Alistair Popple
@ 2015-04-10  8:24 ` Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 6/8] powernv/elog: Convert elog " Alistair Popple
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Alistair Popple @ 2015-04-10  8:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple

This patch converts the opal message event to use the new opal irq
domain.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/platforms/powernv/opal.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 1d73b85..b37f0fc 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -356,33 +356,34 @@ static void opal_handle_message(void)
 	opal_message_do_notify(type, (void *)&msg);
 }
 
-static int opal_message_notify(struct notifier_block *nb,
-			  unsigned long events, void *change)
+static irqreturn_t opal_message_notify(int irq, void *data)
 {
-	if (events & OPAL_EVENT_MSG_PENDING)
-		opal_handle_message();
-	return 0;
+	opal_handle_message();
+	return IRQ_HANDLED;
 }
 
-static struct notifier_block opal_message_nb = {
-	.notifier_call	= opal_message_notify,
-	.next		= NULL,
-	.priority	= 0,
-};
-
 static int __init opal_message_init(void)
 {
-	int ret, i;
+	int ret, i, irq;
 
 	for (i = 0; i < OPAL_MSG_TYPE_MAX; i++)
 		ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]);
 
-	ret = opal_notifier_register(&opal_message_nb);
+	irq = opal_event_request(ilog2(OPAL_EVENT_MSG_PENDING));
+	if (!irq) {
+		pr_err("%s: Can't register OPAL event irq (%d)\n",
+		       __func__, irq);
+		return irq;
+	}
+
+	ret = request_irq(irq, opal_message_notify,
+			IRQ_TYPE_LEVEL_HIGH, "opal-msg", NULL);
 	if (ret) {
-		pr_err("%s: Can't register OPAL event notifier (%d)\n",
+		pr_err("%s: Can't request OPAL event irq (%d)\n",
 		       __func__, ret);
 		return ret;
 	}
+
 	return 0;
 }
 machine_early_initcall(powernv, opal_message_init);
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH V2 6/8] powernv/elog: Convert elog to opal irq domain
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
                   ` (3 preceding siblings ...)
  2015-04-10  8:24 ` [PATCH V2 5/8] powernv/opal: Convert opal message events to " Alistair Popple
@ 2015-04-10  8:24 ` Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 7/8] powernv/opal-dump: Convert to " Alistair Popple
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Alistair Popple @ 2015-04-10  8:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple

This patch converts the elog code to use the opal irq domain instead
of notifier events.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/platforms/powernv/opal-elog.c | 32 +++++++++++++++---------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c
index 518fe95..99b50cd 100644
--- a/arch/powerpc/platforms/powernv/opal-elog.c
+++ b/arch/powerpc/platforms/powernv/opal-elog.c
@@ -10,6 +10,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
@@ -276,24 +277,15 @@ static void elog_work_fn(struct work_struct *work)
 
 static DECLARE_WORK(elog_work, elog_work_fn);
 
-static int elog_event(struct notifier_block *nb,
-				unsigned long events, void *change)
+static irqreturn_t elog_event(int irq, void *data)
 {
-	/* check for error log event */
-	if (events & OPAL_EVENT_ERROR_LOG_AVAIL)
-		schedule_work(&elog_work);
-	return 0;
+	schedule_work(&elog_work);
+	return IRQ_HANDLED;
 }
 
-static struct notifier_block elog_nb = {
-	.notifier_call  = elog_event,
-	.next           = NULL,
-	.priority       = 0
-};
-
 int __init opal_elog_init(void)
 {
-	int rc = 0;
+	int rc = 0, irq;
 
 	/* ELOG not supported by firmware */
 	if (!opal_check_token(OPAL_ELOG_READ))
@@ -305,10 +297,18 @@ int __init opal_elog_init(void)
 		return -1;
 	}
 
-	rc = opal_notifier_register(&elog_nb);
+	irq = opal_event_request(ilog2(OPAL_EVENT_ERROR_LOG_AVAIL));
+	if (!irq) {
+		pr_err("%s: Can't register OPAL event irq (%d)\n",
+		       __func__, irq);
+		return irq;
+	}
+
+	rc = request_irq(irq, elog_event,
+			IRQ_TYPE_LEVEL_HIGH, "opal-elog", NULL);
 	if (rc) {
-		pr_err("%s: Can't register OPAL event notifier (%d)\n",
-		__func__, rc);
+		pr_err("%s: Can't request OPAL event irq (%d)\n",
+		       __func__, rc);
 		return rc;
 	}
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH V2 7/8] powernv/opal-dump: Convert to irq domain
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
                   ` (4 preceding siblings ...)
  2015-04-10  8:24 ` [PATCH V2 6/8] powernv/elog: Convert elog " Alistair Popple
@ 2015-04-10  8:24 ` Alistair Popple
  2015-04-10  8:24 ` [PATCH V2 8/8] opal: Remove events notifier Alistair Popple
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Alistair Popple @ 2015-04-10  8:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple

Convert the opal dump driver to the new opal irq domain.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/platforms/powernv/opal-dump.c | 33 +++++++++++++++---------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
index 23260f7..812f168 100644
--- a/arch/powerpc/platforms/powernv/opal-dump.c
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -15,6 +15,7 @@
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 
 #include <asm/opal.h>
 
@@ -60,7 +61,7 @@ static ssize_t dump_type_show(struct dump_obj *dump_obj,
 			      struct dump_attribute *attr,
 			      char *buf)
 {
-	
+
 	return sprintf(buf, "0x%x %s\n", dump_obj->type,
 		       dump_type_to_string(dump_obj->type));
 }
@@ -408,24 +409,16 @@ static void schedule_process_dump(void)
  * Once we get notification, we add sysfs entries for it.
  * We only fetch the dump on demand, and create sysfs asynchronously.
  */
-static int dump_event(struct notifier_block *nb,
-		      unsigned long events, void *change)
+static irqreturn_t dump_event(int irq, void *data)
 {
-	if (events & OPAL_EVENT_DUMP_AVAIL)
-		schedule_process_dump();
+	schedule_process_dump();
 
-	return 0;
+	return IRQ_HANDLED;
 }
 
-static struct notifier_block dump_nb = {
-	.notifier_call  = dump_event,
-	.next           = NULL,
-	.priority       = 0
-};
-
 void __init opal_platform_dump_init(void)
 {
-	int rc;
+	int rc, irq;
 
 	/* ELOG not supported by firmware */
 	if (!opal_check_token(OPAL_DUMP_READ))
@@ -445,10 +438,18 @@ void __init opal_platform_dump_init(void)
 		return;
 	}
 
-	rc = opal_notifier_register(&dump_nb);
+	irq = opal_event_request(ilog2(OPAL_EVENT_DUMP_AVAIL));
+	if (!irq) {
+		pr_err("%s: Can't register OPAL event irq (%d)\n",
+		       __func__, irq);
+		return;
+	}
+
+	rc = request_irq(irq, dump_event,
+			IRQ_TYPE_LEVEL_HIGH, "opal-dump", NULL);
 	if (rc) {
-		pr_warn("%s: Can't register OPAL event notifier (%d)\n",
-			__func__, rc);
+		pr_err("%s: Can't request OPAL event irq (%d)\n",
+		       __func__, rc);
 		return;
 	}
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH V2 8/8] opal: Remove events notifier
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
                   ` (5 preceding siblings ...)
  2015-04-10  8:24 ` [PATCH V2 7/8] powernv/opal-dump: Convert to " Alistair Popple
@ 2015-04-10  8:24 ` Alistair Popple
  2015-04-30 18:30 ` [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Neelesh Gupta
  2015-04-30 18:44 ` Neelesh Gupta
  8 siblings, 0 replies; 11+ messages in thread
From: Alistair Popple @ 2015-04-10  8:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Alistair Popple

All users of the old opal events notifier have been converted over to
the irq domain so remove the event notifier functions.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 arch/powerpc/platforms/powernv/opal-irqchip.c | 16 ++---
 arch/powerpc/platforms/powernv/opal.c         | 84 +--------------------------
 arch/powerpc/platforms/powernv/powernv.h      |  1 -
 arch/powerpc/platforms/powernv/setup.c        |  2 +-
 4 files changed, 8 insertions(+), 95 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c
index 5eef3c9..8c644d7 100644
--- a/arch/powerpc/platforms/powernv/opal-irqchip.c
+++ b/arch/powerpc/platforms/powernv/opal-irqchip.c
@@ -97,21 +97,17 @@ void opal_handle_events(uint64_t events)
 {
 	int virq, hwirq = 0;
 	u64 mask = opal_event_irqchip.mask;
-	u64 notifier_mask = 0;
 
-	while (events) {
+	while (events & mask) {
 		hwirq = fls64(events) - 1;
-		virq = irq_find_mapping(opal_event_irqchip.domain,
-					hwirq);
-		if (virq) {
-			if (BIT_ULL(hwirq) & mask)
+		if (BIT_ULL(hwirq) & mask) {
+			virq = irq_find_mapping(opal_event_irqchip.domain,
+						hwirq);
+			if (virq)
 				generic_handle_irq(virq);
-		} else
-			notifier_mask |= BIT_ULL(hwirq);
+		}
 		events &= ~BIT_ULL(hwirq);
 	}
-
-	opal_do_notifier(notifier_mask);
 }
 
 static irqreturn_t opal_interrupt(int irq, void *data)
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index b37f0fc..11794d7 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -51,11 +51,7 @@ static int mc_recoverable_range_len;
 
 struct device_node *opal_node;
 static DEFINE_SPINLOCK(opal_write_lock);
-static ATOMIC_NOTIFIER_HEAD(opal_notifier_head);
 static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX];
-static DEFINE_SPINLOCK(opal_notifier_lock);
-static uint64_t last_notified_mask = 0x0ul;
-static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
 
 static void opal_reinit_cores(void)
 {
@@ -220,82 +216,6 @@ static int __init opal_register_exception_handlers(void)
 }
 machine_early_initcall(powernv, opal_register_exception_handlers);
 
-int opal_notifier_register(struct notifier_block *nb)
-{
-	if (!nb) {
-		pr_warning("%s: Invalid argument (%p)\n",
-			   __func__, nb);
-		return -EINVAL;
-	}
-
-	atomic_notifier_chain_register(&opal_notifier_head, nb);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(opal_notifier_register);
-
-int opal_notifier_unregister(struct notifier_block *nb)
-{
-	if (!nb) {
-		pr_warning("%s: Invalid argument (%p)\n",
-			   __func__, nb);
-		return -EINVAL;
-	}
-
-	atomic_notifier_chain_unregister(&opal_notifier_head, nb);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(opal_notifier_unregister);
-
-void opal_do_notifier(uint64_t events)
-{
-	unsigned long flags;
-	uint64_t changed_mask;
-
-	if (atomic_read(&opal_notifier_hold))
-		return;
-
-	spin_lock_irqsave(&opal_notifier_lock, flags);
-	changed_mask = last_notified_mask ^ events;
-	last_notified_mask = events;
-	spin_unlock_irqrestore(&opal_notifier_lock, flags);
-
-	/*
-	 * We feed with the event bits and changed bits for
-	 * enough information to the callback.
-	 */
-	atomic_notifier_call_chain(&opal_notifier_head,
-				   events, (void *)changed_mask);
-}
-
-void opal_notifier_update_evt(uint64_t evt_mask,
-			      uint64_t evt_val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&opal_notifier_lock, flags);
-	last_notified_mask &= ~evt_mask;
-	last_notified_mask |= evt_val;
-	spin_unlock_irqrestore(&opal_notifier_lock, flags);
-}
-
-void opal_notifier_enable(void)
-{
-	int64_t rc;
-	__be64 evt = 0;
-
-	atomic_set(&opal_notifier_hold, 0);
-
-	/* Process pending events */
-	rc = opal_poll_events(&evt);
-	if (rc == OPAL_SUCCESS && evt)
-		opal_do_notifier(be64_to_cpu(evt));
-}
-
-void opal_notifier_disable(void)
-{
-	atomic_set(&opal_notifier_hold, 1);
-}
-
 /*
  * Opal message notifier based on message type. Allow subscribers to get
  * notified for specific messgae type.
@@ -565,10 +485,8 @@ int opal_handle_hmi_exception(struct pt_regs *regs)
 
 	local_paca->hmi_event_available = 0;
 	rc = opal_poll_events(&evt);
-	if (rc == OPAL_SUCCESS && evt) {
-		opal_do_notifier(be64_to_cpu(evt));
+	if (rc == OPAL_SUCCESS && evt)
 		opal_handle_events(be64_to_cpu(evt));
-	}
 
 	return 1;
 }
diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index 41edf6c..addd15c 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -33,7 +33,6 @@ extern u32 pnv_get_supported_cpuidle_states(void);
 
 extern void pnv_lpc_init(void);
 
-extern void opal_do_notifier(uint64_t events);
 extern void opal_handle_events(uint64_t events);
 extern void opal_event_shutdown(void);
 
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index d2de7d5..1fb529d 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -112,7 +112,7 @@ static void pnv_prepare_going_down(void)
 	 * Disable all notifiers from OPAL, we can't
 	 * service interrupts anymore anyway
 	 */
-	opal_notifier_disable();
+	opal_event_shutdown();
 
 	/* Soft disable interrupts */
 	local_irq_disable();
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH V2 2/8] ipmi/powernv: Convert to irq event interface
  2015-04-10  8:24 ` [PATCH V2 2/8] ipmi/powernv: Convert to irq event interface Alistair Popple
@ 2015-04-27  3:30   ` Michael Ellerman
  0 siblings, 0 replies; 11+ messages in thread
From: Michael Ellerman @ 2015-04-27  3:30 UTC (permalink / raw)
  To: Alistair Popple; +Cc: linuxppc-dev

On Fri, 2015-04-10 at 18:24 +1000, Alistair Popple wrote:
> Convert the opal ipmi driver to use the new irq interface for events.

>  drivers/char/ipmi/ipmi_powernv.c | 39 ++++++++++++++++++++++-----------------

This needs to be CC'ed to the IPMI folks, and preferably get their ACK so we
can take the whole series via the powerpc tree.

cheers

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
                   ` (6 preceding siblings ...)
  2015-04-10  8:24 ` [PATCH V2 8/8] opal: Remove events notifier Alistair Popple
@ 2015-04-30 18:30 ` Neelesh Gupta
  2015-04-30 18:44 ` Neelesh Gupta
  8 siblings, 0 replies; 11+ messages in thread
From: Neelesh Gupta @ 2015-04-30 18:30 UTC (permalink / raw)
  To: Alistair Popple, linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 3794 bytes --]

Hi Alistair,

With all the patches applied on top of 'v4.0-rc7', I see this issue during
the boot itself http://pastebin.hursley.ibm.com/918

Few compile warnings and minor comments.
drivers/tty/hvc/hvc_opal.c: In function ‘hvc_opal_probe’:
drivers/tty/hvc/hvc_opal.c:174:6: warning: unused variable ‘rc’ 
[-Wunused-variable]
   int rc;
       ^
drivers/tty/hvc/hvc_opal.c: At top level:
drivers/tty/hvc/hvc_opal.c:65:13: warning: ‘hvc_opal_event_registered’ 
defined but not used [-Wunused-variable]
  static bool hvc_opal_event_registered;



On 04/10/2015 01:54 PM, Alistair Popple wrote:
> Whenever an interrupt is received for opal the linux kernel gets a
> bitfield indicating certain events that have occurred and need handling
> by the various device drivers. Currently this is handled using a
> notifier interface where we call every device driver that has
> registered to receive opal events.
>
> This approach has several drawbacks. For example each driver has to do
> its own checking to see if the event is relevant as well as event
> masking. There is also no easy method of recording the number of times
> we receive particular events.
>
> This patch solves these issues by exposing opal events via the
> standard interrupt APIs by adding a new interrupt chip and
> domain. Drivers can then register for the appropriate events using
> standard kernel calls such as irq_of_parse_and_map().
>
> Signed-off-by: Alistair Popple <alistair@popple.id.au>
> ---
>
> +
> +static int __init opal_event_init(void)
> +{
> +	struct device_node *dn, *opal_node;
> +	const __be32 *irqs;
> +	int i, irqlen;
> +
> +	opal_node = of_find_node_by_path("/ibm,opal");
> +	if (!opal_node) {
> +		pr_warn("opal: Node not found\n");
> +		return -ENODEV;
> +	}
> +
> +	dn = of_find_compatible_node(NULL, NULL, "ibm,opal-event");
> +
> +	/* If dn is NULL it means the domain won't be linked to a DT
> +	 * node so therefore irq_of_parse_and_map(...) wont work. But
> +	 * that shouldn't be problem because if we're running a
> +	 * version of skiboot that doesn't have the dn then the
> +	 * devices won't have the correct properties and will have to
> +	 * fall back to the legacy method (opal_event_request(...))
> +	 * anyway. */
> +	opal_event_irqchip.domain =
> +		irq_domain_add_linear(dn, 64, &opal_event_domain_ops,

A macro would be better, which is maximum event bits we have.

> +				      &opal_event_irqchip);
> +	if (IS_ERR(opal_event_irqchip.domain)) {
> +		pr_warn("opal: Unable to create irq domain\n");
> +		return PTR_ERR(opal_event_irqchip.domain);
> +	}
> +
> +	/* Get interrupt property */
> +	irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);

of_node_put()
Should decrement the refcount of the nodes 'opal_node' and 'dn' (if !NULL)
before returning from the function.

> +	opal_irq_count = irqs ? (irqlen / 4) : 0;
> +	pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count);
> +
> +	/* Install interrupt handlers */
> +	opal_irqs = kcalloc(opal_irq_count, sizeof(unsigned int), GFP_KERNEL);

Safer to use 'sizeof(*opal_irqs)'

Neelesh.

> +	for (i = 0; irqs && i < opal_irq_count; i++, irqs++) {
> +		unsigned int irq, virq;
> +		int rc;
> +
> +		/* Get hardware and virtual IRQ */
> +		irq = be32_to_cpup(irqs);
> +		virq = irq_create_mapping(NULL, irq);
> +		if (virq == NO_IRQ) {
> +			pr_warn("Failed to map irq 0x%x\n", irq);
> +			continue;
> +		}
> +
> +		/* Install interrupt handler */
> +		rc = request_irq(virq, opal_interrupt, 0, "opal", NULL);
> +		if (rc) {
> +			irq_dispose_mapping(virq);
> +			pr_warn("Error %d requesting irq %d (0x%x)\n",
> +				 rc, virq, irq);
> +			continue;
> +		}
> +
> +		/* Cache IRQ */
> +		opal_irqs[i] = virq;
> +	}
> +
> +	return 0;
> +}
> +machine_core_initcall(powernv, opal_event_init);
> +
>


[-- Attachment #2: Type: text/html, Size: 5057 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events
  2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
                   ` (7 preceding siblings ...)
  2015-04-30 18:30 ` [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Neelesh Gupta
@ 2015-04-30 18:44 ` Neelesh Gupta
  8 siblings, 0 replies; 11+ messages in thread
From: Neelesh Gupta @ 2015-04-30 18:44 UTC (permalink / raw)
  To: Alistair Popple, linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 3772 bytes --]

Hi Alistair,

Applied all of the patches on top of 'v4.0-rc7', found this issue during
the boot itself http://pastebin.hursley.ibm.com/918.

There are few compile warnings and minor comments.

drivers/tty/hvc/hvc_opal.c: In function ‘hvc_opal_probe’:
drivers/tty/hvc/hvc_opal.c:174:6: warning: unused variable ‘rc’ 
[-Wunused-variable]
   int rc;
       ^
drivers/tty/hvc/hvc_opal.c: At top level:
drivers/tty/hvc/hvc_opal.c:65:13: warning: ‘hvc_opal_event_registered’ 
defined but not used [-Wunused-variable]
  static bool hvc_opal_event_registered;

Regards,
Neelesh.

On 04/10/2015 01:54 PM, Alistair Popple wrote:
> Whenever an interrupt is received for opal the linux kernel gets a
> bitfield indicating certain events that have occurred and need handling
> by the various device drivers. Currently this is handled using a
> notifier interface where we call every device driver that has
> registered to receive opal events.
>
> This approach has several drawbacks. For example each driver has to do
> its own checking to see if the event is relevant as well as event
> masking. There is also no easy method of recording the number of times
> we receive particular events.
>
> This patch solves these issues by exposing opal events via the
> standard interrupt APIs by adding a new interrupt chip and
> domain. Drivers can then register for the appropriate events using
> standard kernel calls such as irq_of_parse_and_map().
>
> Signed-off-by: Alistair Popple <alistair@popple.id.au>
> ---
>
> +static int __init opal_event_init(void)
> +{
> +	struct device_node *dn, *opal_node;
> +	const __be32 *irqs;
> +	int i, irqlen;
> +
> +	opal_node = of_find_node_by_path("/ibm,opal");
> +	if (!opal_node) {
> +		pr_warn("opal: Node not found\n");
> +		return -ENODEV;
> +	}
> +
> +	dn = of_find_compatible_node(NULL, NULL, "ibm,opal-event");
> +
> +	/* If dn is NULL it means the domain won't be linked to a DT
> +	 * node so therefore irq_of_parse_and_map(...) wont work. But
> +	 * that shouldn't be problem because if we're running a
> +	 * version of skiboot that doesn't have the dn then the
> +	 * devices won't have the correct properties and will have to
> +	 * fall back to the legacy method (opal_event_request(...))
> +	 * anyway. */
> +	opal_event_irqchip.domain =
> +		irq_domain_add_linear(dn, 64, &opal_event_domain_ops,

A macro would be better, which is maximum event bits we have.

> +				      &opal_event_irqchip);
> +	if (IS_ERR(opal_event_irqchip.domain)) {
> +		pr_warn("opal: Unable to create irq domain\n");
> +		return PTR_ERR(opal_event_irqchip.domain);
> +	}
> +
> +	/* Get interrupt property */
> +	irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);
> +	opal_irq_count = irqs ? (irqlen / 4) : 0;

of_node_put()
Need to decrement the refcount of these nodes, 'opal_node' & 'dn' (if !NULL)

> +	pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count);
> +
> +	/* Install interrupt handlers */
> +	opal_irqs = kcalloc(opal_irq_count, sizeof(unsigned int), GFP_KERNEL);

Safe to use 'sizeof(*opal_irqs)'

> +	for (i = 0; irqs && i < opal_irq_count; i++, irqs++) {
> +		unsigned int irq, virq;
> +		int rc;
> +
> +		/* Get hardware and virtual IRQ */
> +		irq = be32_to_cpup(irqs);
> +		virq = irq_create_mapping(NULL, irq);
> +		if (virq == NO_IRQ) {
> +			pr_warn("Failed to map irq 0x%x\n", irq);
> +			continue;
> +		}
> +
> +		/* Install interrupt handler */
> +		rc = request_irq(virq, opal_interrupt, 0, "opal", NULL);
> +		if (rc) {
> +			irq_dispose_mapping(virq);
> +			pr_warn("Error %d requesting irq %d (0x%x)\n",
> +				 rc, virq, irq);
> +			continue;
> +		}
> +
> +		/* Cache IRQ */
> +		opal_irqs[i] = virq;
> +	}
> +
> +	return 0;
> +}
> +machine_core_initcall(powernv, opal_event_init);
> +
>


[-- Attachment #2: Type: text/html, Size: 5002 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-04-30 18:44 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-10  8:24 [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Alistair Popple
2015-04-10  8:24 ` [PATCH V2 2/8] ipmi/powernv: Convert to irq event interface Alistair Popple
2015-04-27  3:30   ` Michael Ellerman
2015-04-10  8:24 ` [PATCH V2 3/8] hvc: Convert to using interrupts instead of opal events Alistair Popple
2015-04-10  8:24 ` [PATCH V2 4/8] powernv/eeh: Update the EEH code to use the opal irq domain Alistair Popple
2015-04-10  8:24 ` [PATCH V2 5/8] powernv/opal: Convert opal message events to " Alistair Popple
2015-04-10  8:24 ` [PATCH V2 6/8] powernv/elog: Convert elog " Alistair Popple
2015-04-10  8:24 ` [PATCH V2 7/8] powernv/opal-dump: Convert to " Alistair Popple
2015-04-10  8:24 ` [PATCH V2 8/8] opal: Remove events notifier Alistair Popple
2015-04-30 18:30 ` [PATCH V2 1/8] powerpc/powernv: Add a virtual irqchip for opal events Neelesh Gupta
2015-04-30 18:44 ` Neelesh Gupta

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.