aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Mendoza-Jonas <sam@mendozajonas.com>2016-07-10 23:38:57 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2016-07-26 22:38:18 -0400
commitbbc3dfe8805de86874b1a1b1429a002e8670043e (patch)
tree5fc55f25dd0daf89975481a3320fb7c24c9f0ecd
parenta431b946db581d6a121d035a887d370cdc4b8dea (diff)
tty/hvc: Use IRQF_SHARED for OPAL hvc consoles
Commit 2def86a7200c ("hvc: Convert to using interrupts instead of opal events") enabled the use of interrupts in the hvc_driver for OPAL platforms. However on machines with more than one hvc console, any console after the first will fail to register an interrupt handler in notifier_add_irq() since all consoles share the same IRQ number but do not set the IRQF_SHARED flag: genirq: Flags mismatch irq 31. 00000000 (hvc_console) vs. 00000000 (hvc_console) hvc_open: request_irq failed with rc -16. This error propagates up to hvc_open() and the console is closed, but OPAL will still generate interrupts that are not handled, leading to rcu_sched stall warnings. Set IRQF_SHARED when calling request_irq(), allowing additional consoles to start properly. This is only set for consoles handled by hvc_opal_probe(), leaving other types unaffected. Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--drivers/tty/hvc/hvc_console.h1
-rw-r--r--drivers/tty/hvc/hvc_irq.c9
-rw-r--r--drivers/tty/hvc/hvc_opal.c3
3 files changed, 11 insertions, 2 deletions
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index 913101980827..798c48d0d32c 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -60,6 +60,7 @@ struct hvc_struct {
60 struct winsize ws; 60 struct winsize ws;
61 struct work_struct tty_resize; 61 struct work_struct tty_resize;
62 struct list_head next; 62 struct list_head next;
63 unsigned long flags;
63}; 64};
64 65
65/* implemented by a low level driver */ 66/* implemented by a low level driver */
diff --git a/drivers/tty/hvc/hvc_irq.c b/drivers/tty/hvc/hvc_irq.c
index c9adb0559f61..bc7a96874637 100644
--- a/drivers/tty/hvc/hvc_irq.c
+++ b/drivers/tty/hvc/hvc_irq.c
@@ -14,6 +14,11 @@ static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
14 /* if hvc_poll request a repoll, then kick the hvcd thread */ 14 /* if hvc_poll request a repoll, then kick the hvcd thread */
15 if (hvc_poll(dev_instance)) 15 if (hvc_poll(dev_instance))
16 hvc_kick(); 16 hvc_kick();
17
18 /*
19 * We're safe to always return IRQ_HANDLED as the hvcd thread will
20 * iterate through each hvc_struct.
21 */
17 return IRQ_HANDLED; 22 return IRQ_HANDLED;
18} 23}
19 24
@@ -28,8 +33,8 @@ int notifier_add_irq(struct hvc_struct *hp, int irq)
28 hp->irq_requested = 0; 33 hp->irq_requested = 0;
29 return 0; 34 return 0;
30 } 35 }
31 rc = request_irq(irq, hvc_handle_interrupt, 0, 36 rc = request_irq(irq, hvc_handle_interrupt, hp->flags,
32 "hvc_console", hp); 37 "hvc_console", hp);
33 if (!rc) 38 if (!rc)
34 hp->irq_requested = 1; 39 hp->irq_requested = 1;
35 return rc; 40 return rc;
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index 47b54c6aefd2..b7cd0ae7d927 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -224,6 +224,9 @@ static int hvc_opal_probe(struct platform_device *dev)
224 hp = hvc_alloc(termno, irq, ops, MAX_VIO_PUT_CHARS); 224 hp = hvc_alloc(termno, irq, ops, MAX_VIO_PUT_CHARS);
225 if (IS_ERR(hp)) 225 if (IS_ERR(hp))
226 return PTR_ERR(hp); 226 return PTR_ERR(hp);
227
228 /* hvc consoles on powernv may need to share a single irq */
229 hp->flags = IRQF_SHARED;
227 dev_set_drvdata(&dev->dev, hp); 230 dev_set_drvdata(&dev->dev, hp);
228 231
229 return 0; 232 return 0;