Message ID | 20221118145512.509950-1-gsomlo@gmail.com |
---|---|
Headers | show |
Series | serial: liteuart: add IRQ support | expand |
On 21. 11. 22, 19:50, Gabriel L. Somlo wrote: >>> static void liteuart_timer(struct timer_list *t) >>> { >>> struct liteuart_port *uart = from_timer(uart, t, timer); >>> struct uart_port *port = &uart->port; >>> - liteuart_rx_chars(port); >>> - >>> + liteuart_interrupt(0, port); >> >> Are you sure spin_lock() is safe from this path? I assume so, but have you >> thought about it? > > I checked and at that point `in_serving_softirq()` is true. > > *However*, after studying spin_lock() and friends for a while, I'm > not quite clear on whether that unequivocally translates > to "yes, we're safe" :) Depends whether some hard irq context is grabbing the port lock too. If it does, it will spin forever waiting for this soft irq to finish (never happens as it was interrupted). > As such, I'm inclined to switch to `spin_lock_irqsave()` and > `spin_unlock_irqrestore()` even in the interrupt handler, which is > explicitly stated to be "safe from any context": > https://www.kernel.org/doc/html/v4.15/kernel-hacking/locking.html#cheat-sheet-for-locking > The alternative could be to set `TIMER_IRQSAFE` in `timer_setup()`, > but no other tty driver seems to be doing that, so I'd be a bit off > the beaten path there... :) Ah, no. > Please do let me know what you think about this, particularly if you > consider going the spin_lock_irqsave-everywhere-just-to-be-safe route > overkill... :) If you are unsure about the other contexts, irqsave/restore is the way to go. It can be lifted later, if someone investigates harder. thanks,
On Tue, Nov 22, 2022 at 8:44 AM Jiri Slaby <jirislaby@kernel.org> wrote: > On 21. 11. 22, 19:50, Gabriel L. Somlo wrote: > >>> static void liteuart_timer(struct timer_list *t) > >>> { > >>> struct liteuart_port *uart = from_timer(uart, t, timer); > >>> struct uart_port *port = &uart->port; > >>> - liteuart_rx_chars(port); > >>> - > >>> + liteuart_interrupt(0, port); > >> > >> Are you sure spin_lock() is safe from this path? I assume so, but have you > >> thought about it? > > > > I checked and at that point `in_serving_softirq()` is true. > > > > *However*, after studying spin_lock() and friends for a while, I'm > > not quite clear on whether that unequivocally translates > > to "yes, we're safe" :) > > Depends whether some hard irq context is grabbing the port lock too. If > it does, it will spin forever waiting for this soft irq to finish (never > happens as it was interrupted). > > > As such, I'm inclined to switch to `spin_lock_irqsave()` and > > `spin_unlock_irqrestore()` even in the interrupt handler, which is > > explicitly stated to be "safe from any context": > > https://www.kernel.org/doc/html/v4.15/kernel-hacking/locking.html#cheat-sheet-for-locking > > > > > The alternative could be to set `TIMER_IRQSAFE` in `timer_setup()`, > > but no other tty driver seems to be doing that, so I'd be a bit off > > the beaten path there... :) > > Ah, no. > > > Please do let me know what you think about this, particularly if you > > consider going the spin_lock_irqsave-everywhere-just-to-be-safe route > > overkill... :) > > If you are unsure about the other contexts, irqsave/restore is the way > to go. It can be lifted later, if someone investigates harder. Inside the interrupt handler, plain spin_lock() should be OK. Inside the timer handler, I think you need to use spin_lock_irqsave(), as e.g. liteuart_set_termios() (and lots of code in serial_core.c) already uses spin_lock_irqsave(). Besides, on non-SMP, spin_lock() doesn't do anything, so you need to rely on disabling the local interrupt. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
On Tue, Nov 22, 2022 at 10:54:45AM +0100, Geert Uytterhoeven wrote: > On Tue, Nov 22, 2022 at 8:44 AM Jiri Slaby <jirislaby@kernel.org> wrote: > > On 21. 11. 22, 19:50, Gabriel L. Somlo wrote: > > >>> static void liteuart_timer(struct timer_list *t) > > >>> { > > >>> struct liteuart_port *uart = from_timer(uart, t, timer); > > >>> struct uart_port *port = &uart->port; > > >>> - liteuart_rx_chars(port); > > >>> - > > >>> + liteuart_interrupt(0, port); > > >> > > >> Are you sure spin_lock() is safe from this path? I assume so, but have you > > >> thought about it? > > > > > > I checked and at that point `in_serving_softirq()` is true. > > > > > > *However*, after studying spin_lock() and friends for a while, I'm > > > not quite clear on whether that unequivocally translates > > > to "yes, we're safe" :) > > > > Depends whether some hard irq context is grabbing the port lock too. If > > it does, it will spin forever waiting for this soft irq to finish (never > > happens as it was interrupted). > > > > > As such, I'm inclined to switch to `spin_lock_irqsave()` and > > > `spin_unlock_irqrestore()` even in the interrupt handler, which is > > > explicitly stated to be "safe from any context": > > > https://www.kernel.org/doc/html/v4.15/kernel-hacking/locking.html#cheat-sheet-for-locking > > > > > > > > > The alternative could be to set `TIMER_IRQSAFE` in `timer_setup()`, > > > but no other tty driver seems to be doing that, so I'd be a bit off > > > the beaten path there... :) > > > > Ah, no. > > > > > Please do let me know what you think about this, particularly if you > > > consider going the spin_lock_irqsave-everywhere-just-to-be-safe route > > > overkill... :) > > > > If you are unsure about the other contexts, irqsave/restore is the way > > to go. It can be lifted later, if someone investigates harder. > > Inside the interrupt handler, plain spin_lock() should be OK. > Inside the timer handler, I think you need to use spin_lock_irqsave(), > as e.g. liteuart_set_termios() (and lots of code in serial_core.c) > already uses spin_lock_irqsave(). > Besides, on non-SMP, spin_lock() doesn't do anything, so you need > to rely on disabling the local interrupt. Thanks Geert for the clarification! I could write two wrappers around the actual code doing the interrupt handler work, one with spin_lock() for the actual irq handler and another with spin_lock_irqsave() for the timer codepath. But to keep things simple I'm inclined to simply use spin_lock_irqsave() and add a comment saying it's because we need it when polling and it's not actually harmful when using IRQ. Thanks, --Gabriel > Gr{oetje,eeting}s, > > Geert > > -- > Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org > > In personal conversations with technical people, I call myself a hacker. But > when I'm talking to journalists I just say "programmer" or something like that. > -- Linus Torvalds