diff options
Diffstat (limited to 'drivers/tty/serial/sc16is7xx.c')
-rw-r--r-- | drivers/tty/serial/sc16is7xx.c | 66 |
1 files changed, 43 insertions, 23 deletions
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index ea61a297b463..e6553d04a551 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -303,7 +303,7 @@ struct sc16is7xx_devtype { struct sc16is7xx_one { struct uart_port port; - struct work_struct tx_work; + struct kthread_work tx_work; struct work_struct md_work; }; @@ -311,15 +311,18 @@ struct sc16is7xx_port { struct uart_driver uart; struct sc16is7xx_devtype *devtype; struct regmap *regmap; - struct mutex mutex; struct clk *clk; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; #endif unsigned char buf[SC16IS7XX_FIFO_SIZE]; + struct kthread_worker kworker; + struct task_struct *kworker_task; + struct kthread_work irq_work; struct sc16is7xx_one p[0]; }; +#define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e))) #define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) @@ -616,9 +619,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) !!(msr & SC16IS7XX_MSR_CTS_BIT)); break; case SC16IS7XX_IIR_THRI_SRC: - mutex_lock(&s->mutex); sc16is7xx_handle_tx(port); - mutex_unlock(&s->mutex); break; default: dev_err_ratelimited(port->dev, @@ -629,25 +630,29 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) } while (1); } -static irqreturn_t sc16is7xx_ist(int irq, void *dev_id) +static void sc16is7xx_ist(struct kthread_work *ws) { - struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); int i; for (i = 0; i < s->uart.nr; ++i) sc16is7xx_port_irq(s, i); +} + +static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) +{ + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + + queue_kthread_work(&s->kworker, &s->irq_work); return IRQ_HANDLED; } -static void sc16is7xx_wq_proc(struct work_struct *ws) +static void sc16is7xx_tx_proc(struct kthread_work *ws) { struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work); - struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); - mutex_lock(&s->mutex); sc16is7xx_handle_tx(&one->port); - mutex_unlock(&s->mutex); } static void sc16is7xx_stop_tx(struct uart_port* port) @@ -669,6 +674,7 @@ static void sc16is7xx_stop_rx(struct uart_port* port) static void sc16is7xx_start_tx(struct uart_port *port) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); /* handle rs485 */ @@ -677,8 +683,7 @@ static void sc16is7xx_start_tx(struct uart_port *port) mdelay(port->rs485.delay_rts_before_send); } - if (!work_pending(&one->tx_work)) - schedule_work(&one->tx_work); + queue_kthread_work(&s->kworker, &one->tx_work); } static unsigned int sc16is7xx_tx_empty(struct uart_port *port) @@ -909,6 +914,8 @@ static int sc16is7xx_startup(struct uart_port *port) static void sc16is7xx_shutdown(struct uart_port *port) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + /* Disable all interrupts */ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); /* Disable TX/RX */ @@ -919,6 +926,8 @@ static void sc16is7xx_shutdown(struct uart_port *port) SC16IS7XX_EFCR_TXDISABLE_BIT); sc16is7xx_power(port, 0); + + flush_kthread_worker(&s->kworker); } static const char *sc16is7xx_type(struct uart_port *port) @@ -1036,6 +1045,7 @@ static int sc16is7xx_probe(struct device *dev, struct sc16is7xx_devtype *devtype, struct regmap *regmap, int irq, unsigned long flags) { + struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 }; unsigned long freq, *pfreq = dev_get_platdata(dev); int i, ret; struct sc16is7xx_port *s; @@ -1077,6 +1087,16 @@ static int sc16is7xx_probe(struct device *dev, goto out_clk; } + init_kthread_worker(&s->kworker); + init_kthread_work(&s->irq_work, sc16is7xx_ist); + s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, + "sc16is7xx"); + if (IS_ERR(s->kworker_task)) { + ret = PTR_ERR(s->kworker_task); + goto out_uart; + } + sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param); + #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) { /* Setup GPIO cotroller */ @@ -1092,12 +1112,10 @@ static int sc16is7xx_probe(struct device *dev, s->gpio.can_sleep = 1; ret = gpiochip_add(&s->gpio); if (ret) - goto out_uart; + goto out_thread; } #endif - mutex_init(&s->mutex); - for (i = 0; i < devtype->nr_uart; ++i) { /* Initialize port data */ s->p[i].port.line = i; @@ -1117,7 +1135,7 @@ static int sc16is7xx_probe(struct device *dev, SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT); /* Initialize queue for start TX */ - INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc); + init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc); /* Initialize queue for changing mode */ INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc); /* Register port */ @@ -1127,22 +1145,23 @@ static int sc16is7xx_probe(struct device *dev, } /* Setup interrupt */ - ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist, - IRQF_ONESHOT | flags, dev_name(dev), s); + ret = devm_request_irq(dev, irq, sc16is7xx_irq, + IRQF_ONESHOT | flags, dev_name(dev), s); if (!ret) return 0; for (i = 0; i < s->uart.nr; i++) uart_remove_one_port(&s->uart, &s->p[i].port); - mutex_destroy(&s->mutex); - #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) gpiochip_remove(&s->gpio); -out_uart: +out_thread: #endif + kthread_stop(s->kworker_task); + +out_uart: uart_unregister_driver(&s->uart); out_clk: @@ -1163,13 +1182,14 @@ static int sc16is7xx_remove(struct device *dev) #endif for (i = 0; i < s->uart.nr; i++) { - cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); uart_remove_one_port(&s->uart, &s->p[i].port); sc16is7xx_power(&s->p[i].port, 0); } - mutex_destroy(&s->mutex); + flush_kthread_worker(&s->kworker); + kthread_stop(s->kworker_task); + uart_unregister_driver(&s->uart); if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); |