Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

serial: liteuart: add IRQ support for the RX path

Add support for IRQ-driven RX. Support for the TX path will be added
in a separate commit.

Signed-off-by: Gabriel Somlo <gsomlo@gmail.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20221123130500.1030189-13-gsomlo@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Gabriel Somlo and committed by
Greg Kroah-Hartman
5602cf99 7121d86e

+74 -7
+74 -7
drivers/tty/serial/liteuart.c
··· 7 7 8 8 #include <linux/bits.h> 9 9 #include <linux/console.h> 10 + #include <linux/interrupt.h> 10 11 #include <linux/litex.h> 11 12 #include <linux/module.h> 12 13 #include <linux/of.h> ··· 47 46 struct uart_port port; 48 47 struct timer_list timer; 49 48 u32 id; 49 + u8 irq_reg; 50 50 }; 51 51 52 52 #define to_liteuart_port(port) container_of(port, struct liteuart_port, port) ··· 76 74 cpu_relax(); 77 75 78 76 litex_write8(port->membase + OFF_RXTX, ch); 77 + } 78 + 79 + static void liteuart_update_irq_reg(struct uart_port *port, bool set, u8 mask) 80 + { 81 + struct liteuart_port *uart = to_liteuart_port(port); 82 + 83 + if (set) 84 + uart->irq_reg |= mask; 85 + else 86 + uart->irq_reg &= ~mask; 87 + 88 + if (port->irq) 89 + litex_write8(port->membase + OFF_EV_ENABLE, uart->irq_reg); 79 90 } 80 91 81 92 static void liteuart_stop_tx(struct uart_port *port) ··· 144 129 tty_flip_buffer_push(&port->state->port); 145 130 } 146 131 132 + static irqreturn_t liteuart_interrupt(int irq, void *data) 133 + { 134 + struct liteuart_port *uart = data; 135 + struct uart_port *port = &uart->port; 136 + unsigned long flags; 137 + u8 isr; 138 + 139 + /* 140 + * if polling, the context would be "in_serving_softirq", so use 141 + * irq[save|restore] spin_lock variants to cover all possibilities 142 + */ 143 + spin_lock_irqsave(&port->lock, flags); 144 + isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg; 145 + if (isr & EV_RX) 146 + liteuart_rx_chars(port); 147 + spin_unlock_irqrestore(&port->lock, flags); 148 + 149 + return IRQ_RETVAL(isr); 150 + } 151 + 147 152 static void liteuart_timer(struct timer_list *t) 148 153 { 149 154 struct liteuart_port *uart = from_timer(uart, t, timer); 150 155 struct uart_port *port = &uart->port; 151 156 152 - liteuart_rx_chars(port); 153 - 157 + liteuart_interrupt(0, port); 154 158 mod_timer(&uart->timer, jiffies + uart_poll_timeout(port)); 155 159 } 156 160 ··· 195 161 static int liteuart_startup(struct uart_port *port) 196 162 { 197 163 struct liteuart_port *uart = to_liteuart_port(port); 164 + unsigned long flags; 165 + int ret; 198 166 199 - /* disable events */ 200 - litex_write8(port->membase + OFF_EV_ENABLE, 0); 167 + if (port->irq) { 168 + ret = request_irq(port->irq, liteuart_interrupt, 0, 169 + KBUILD_MODNAME, uart); 170 + if (ret) { 171 + dev_warn(port->dev, 172 + "line %d irq %d failed: switch to polling\n", 173 + port->line, port->irq); 174 + port->irq = 0; 175 + } 176 + } 201 177 202 - /* prepare timer for polling */ 203 - timer_setup(&uart->timer, liteuart_timer, 0); 204 - mod_timer(&uart->timer, jiffies + uart_poll_timeout(port)); 178 + spin_lock_irqsave(&port->lock, flags); 179 + /* only enabling rx irqs during startup */ 180 + liteuart_update_irq_reg(port, true, EV_RX); 181 + spin_unlock_irqrestore(&port->lock, flags); 182 + 183 + if (!port->irq) { 184 + timer_setup(&uart->timer, liteuart_timer, 0); 185 + mod_timer(&uart->timer, jiffies + uart_poll_timeout(port)); 186 + } 205 187 206 188 return 0; 207 189 } 208 190 209 191 static void liteuart_shutdown(struct uart_port *port) 210 192 { 193 + struct liteuart_port *uart = to_liteuart_port(port); 194 + unsigned long flags; 195 + 196 + spin_lock_irqsave(&port->lock, flags); 197 + liteuart_update_irq_reg(port, false, EV_RX | EV_TX); 198 + spin_unlock_irqrestore(&port->lock, flags); 199 + 200 + if (port->irq) 201 + free_irq(port->irq, port); 202 + else 203 + del_timer_sync(&uart->timer); 211 204 } 212 205 213 206 static void liteuart_set_termios(struct uart_port *port, struct ktermios *new, ··· 322 261 ret = PTR_ERR(port->membase); 323 262 goto err_erase_id; 324 263 } 264 + 265 + ret = platform_get_irq_optional(pdev, 0); 266 + if (ret < 0 && ret != -ENXIO) 267 + return ret; 268 + if (ret > 0) 269 + port->irq = ret; 325 270 326 271 /* values not from device tree */ 327 272 port->dev = &pdev->dev;