From bbc3dfe8805de86874b1a1b1429a002e8670043e Mon Sep 17 00:00:00 2001 From: Sam Mendoza-Jonas Date: Mon, 11 Jul 2016 13:38:57 +1000 Subject: 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 Signed-off-by: Michael Ellerman --- drivers/tty/hvc/hvc_console.h | 1 + drivers/tty/hvc/hvc_irq.c | 9 +++++++-- drivers/tty/hvc/hvc_opal.c | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/tty') 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 { struct winsize ws; struct work_struct tty_resize; struct list_head next; + unsigned long flags; }; /* 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) /* if hvc_poll request a repoll, then kick the hvcd thread */ if (hvc_poll(dev_instance)) hvc_kick(); + + /* + * We're safe to always return IRQ_HANDLED as the hvcd thread will + * iterate through each hvc_struct. + */ return IRQ_HANDLED; } @@ -28,8 +33,8 @@ int notifier_add_irq(struct hvc_struct *hp, int irq) hp->irq_requested = 0; return 0; } - rc = request_irq(irq, hvc_handle_interrupt, 0, - "hvc_console", hp); + rc = request_irq(irq, hvc_handle_interrupt, hp->flags, + "hvc_console", hp); if (!rc) hp->irq_requested = 1; 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) hp = hvc_alloc(termno, irq, ops, MAX_VIO_PUT_CHARS); if (IS_ERR(hp)) return PTR_ERR(hp); + + /* hvc consoles on powernv may need to share a single irq */ + hp->flags = IRQF_SHARED; dev_set_drvdata(&dev->dev, hp); return 0; -- cgit v1.2.3 From 00dab8187e182da41122f66c207707b192509df4 Mon Sep 17 00:00:00 2001 From: Sam Mendoza-Jonas Date: Mon, 11 Jul 2016 13:38:58 +1000 Subject: tty/hvc: Use opal irqchip interface if available Update the hvc driver to use the OPAL irqchip if made available by the running firmware. If it is not present, the driver falls back to the existing OPAL event number. Signed-off-by: Samuel Mendoza-Jonas Signed-off-by: Michael Ellerman --- drivers/tty/hvc/hvc_opal.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index b7cd0ae7d927..510799311099 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -214,7 +214,13 @@ static int hvc_opal_probe(struct platform_device *dev) dev->dev.of_node->full_name, boot ? " (boot console)" : ""); - irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT)); + irq = irq_of_parse_and_map(dev->dev.of_node, 0); + if (!irq) { + pr_info("hvc%d: No interrupts property, using OPAL event\n", + termno); + 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); -- cgit v1.2.3