Message ID | 20170818122201.14552-2-colin.king@canonical.com |
---|---|
State | New |
Headers | show |
On 18.08.2017 14:22, Colin King wrote: > From: Sam Mendoza-Jonas <sam@mendozajonas.com> > > BugLink: http://bugs.launchpad.net/bugs/1711401 > > 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> > (upstream cherry-pick of commit bbc3dfe8805de86874b1a1b1429a002e8670043e) > Signed-off-by: Colin Ian King <colin.king@canonical.com> Acked-by: Stefan Bader <stefan.bader@canonical.com> > --- > 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(-) > > 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; >
Applied to xenial/master-next branch. Thanks.
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;