Skip to content

Commit

Permalink
serial: sc16is7xx: change EFR lock to operate on each channels
Browse files Browse the repository at this point in the history
Now that the driver has been converted to use one regmap per port, change
efr locking to operate on a channel basis instead of on the whole IC.

Fixes: 3837a03 ("serial: sc16is7xx: improve regmap debugfs by using one regmap per port")
Cc:  <stable@vger.kernel.org> # 6.1.x: 3837a03 serial: sc16is7xx: improve regmap debugfs by using one regmap per port
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Link: https://lore.kernel.org/r/20231211171353.2901416-5-hugo@hugovil.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Hugo Villeneuve authored and Greg Kroah-Hartman committed Dec 15, 2023
1 parent 41a308c commit 4409df5
Showing 1 changed file with 26 additions and 23 deletions.
49 changes: 26 additions & 23 deletions drivers/tty/serial/sc16is7xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ struct sc16is7xx_one_config {
struct sc16is7xx_one {
struct uart_port port;
struct regmap *regmap;
struct mutex efr_lock; /* EFR registers access */
struct kthread_work tx_work;
struct kthread_work reg_work;
struct kthread_delayed_work ms_work;
Expand All @@ -342,7 +343,6 @@ struct sc16is7xx_port {
unsigned char buf[SC16IS7XX_FIFO_SIZE];
struct kthread_worker kworker;
struct task_struct *kworker_task;
struct mutex efr_lock;
struct sc16is7xx_one p[];
};

Expand Down Expand Up @@ -494,7 +494,6 @@ static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg)

static int sc16is7xx_set_baud(struct uart_port *port, int baud)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
u8 lcr;
u8 prescaler = 0;
Expand All @@ -518,7 +517,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
* because the bulk of the interrupt processing is run as a workqueue
* job in thread context.
*/
mutex_lock(&s->efr_lock);
mutex_lock(&one->efr_lock);

lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);

Expand All @@ -537,7 +536,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
/* Put LCR back to the normal mode */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);

mutex_unlock(&s->efr_lock);
mutex_unlock(&one->efr_lock);

sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_CLKSEL_BIT,
Expand Down Expand Up @@ -705,11 +704,10 @@ static unsigned int sc16is7xx_get_hwmctrl(struct uart_port *port)
static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
{
struct uart_port *port = &one->port;
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
unsigned long flags;
unsigned int status, changed;

lockdep_assert_held_once(&s->efr_lock);
lockdep_assert_held_once(&one->efr_lock);

status = sc16is7xx_get_hwmctrl(port);
changed = status ^ one->old_mctrl;
Expand All @@ -735,15 +733,20 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)

static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{
bool rc = true;
struct uart_port *port = &s->p[portno].port;
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);

mutex_lock(&one->efr_lock);

do {
unsigned int iir, rxlen;
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);

iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
if (iir & SC16IS7XX_IIR_NO_INT_BIT)
return false;
if (iir & SC16IS7XX_IIR_NO_INT_BIT) {
rc = false;
goto out_port_irq;
}

iir &= SC16IS7XX_IIR_ID_MASK;

Expand Down Expand Up @@ -783,15 +786,17 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
break;
}
} while (0);
return true;

out_port_irq:
mutex_unlock(&one->efr_lock);

return rc;
}

static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
{
struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;

mutex_lock(&s->efr_lock);

while (1) {
bool keep_polling = false;
int i;
Expand All @@ -802,24 +807,22 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
break;
}

mutex_unlock(&s->efr_lock);

return IRQ_HANDLED;
}

static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
unsigned long flags;

if ((port->rs485.flags & SER_RS485_ENABLED) &&
(port->rs485.delay_rts_before_send > 0))
msleep(port->rs485.delay_rts_before_send);

mutex_lock(&s->efr_lock);
mutex_lock(&one->efr_lock);
sc16is7xx_handle_tx(port);
mutex_unlock(&s->efr_lock);
mutex_unlock(&one->efr_lock);

uart_port_lock_irqsave(port, &flags);
sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT);
Expand Down Expand Up @@ -926,9 +929,9 @@ static void sc16is7xx_ms_proc(struct kthread_work *ws)
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);

if (one->port.state) {
mutex_lock(&s->efr_lock);
mutex_lock(&one->efr_lock);
sc16is7xx_update_mlines(one);
mutex_unlock(&s->efr_lock);
mutex_unlock(&one->efr_lock);

kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ);
}
Expand Down Expand Up @@ -1012,7 +1015,6 @@ static void sc16is7xx_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
unsigned int lcr, flow = 0;
int baud;
Expand Down Expand Up @@ -1071,7 +1073,7 @@ static void sc16is7xx_set_termios(struct uart_port *port,
port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;

/* As above, claim the mutex while accessing the EFR. */
mutex_lock(&s->efr_lock);
mutex_lock(&one->efr_lock);

sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_B);
Expand Down Expand Up @@ -1101,7 +1103,7 @@ static void sc16is7xx_set_termios(struct uart_port *port,
/* Update LCR register */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);

mutex_unlock(&s->efr_lock);
mutex_unlock(&one->efr_lock);

/* Get baud rate generator configuration */
baud = uart_get_baud_rate(port, termios, old,
Expand Down Expand Up @@ -1535,7 +1537,6 @@ static int sc16is7xx_probe(struct device *dev,

s->devtype = devtype;
dev_set_drvdata(dev, s);
mutex_init(&s->efr_lock);

kthread_init_worker(&s->kworker);
s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker,
Expand Down Expand Up @@ -1578,6 +1579,8 @@ static int sc16is7xx_probe(struct device *dev,
goto out_ports;
}

mutex_init(&s->p[i].efr_lock);

ret = uart_get_rs485_mode(&s->p[i].port);
if (ret)
goto out_ports;
Expand Down

0 comments on commit 4409df5

Please sign in to comment.