* [PATCH 0/4] serial: move towards tty_port
@ 2010-05-19 12:13 Alan Cox
2010-05-19 12:13 ` [PATCH 1/4] serial: Change the wait for carrier locking Alan Cox
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Alan Cox @ 2010-05-19 12:13 UTC (permalink / raw)
To: greg, linux-serial
We really want to be using tty_port here so that we can dump all the nasty
horrible complicated locking and POSIX tty behaviour into one place for all
users. This gets us to the point of the block_til_ready helper doing much of
the work.
---
Alan Cox (4):
serial: Use block_til_ready helper
serial: trim locking on the helpers
serial: add port helpers
serial: Change the wait for carrier locking
drivers/serial/serial_core.c | 131 +++++++++++++++---------------------------
1 files changed, 46 insertions(+), 85 deletions(-)
--
Zendemonium
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] serial: Change the wait for carrier locking
2010-05-19 12:13 [PATCH 0/4] serial: move towards tty_port Alan Cox
@ 2010-05-19 12:13 ` Alan Cox
2010-05-19 12:14 ` [PATCH 2/4] serial: add port helpers Alan Cox
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Alan Cox @ 2010-05-19 12:13 UTC (permalink / raw)
To: greg, linux-serial
We want to push the lock/unlock into the helper functions so that we
can prepare to move to using the tty_port helper. The expansion initially
comes out a bit ugly but its worth the temporary expansion IMHO just so
we can produce a nice testable series of changes.
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/serial/serial_core.c | 44 +++++++++++++++++++++++++++++++++---------
1 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 570dca2..424b1c7 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1272,6 +1272,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
struct uart_state *state = tty->driver_data;
struct tty_port *port;
struct uart_port *uport;
+ unsigned long flags;
BUG_ON(!kernel_locked());
@@ -1284,9 +1285,12 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
pr_debug("uart_close(%d) called\n", uport->line);
mutex_lock(&port->mutex);
+ spin_lock_irqsave(&port->lock, flags);
- if (tty_hung_up_p(filp))
+ if (tty_hung_up_p(filp)) {
+ spin_unlock_irqrestore(&port->lock, flags);
goto done;
+ }
if ((tty->count == 1) && (port->count != 1)) {
/*
@@ -1305,8 +1309,10 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
tty->name, port->count);
port->count = 0;
}
- if (port->count)
+ if (port->count) {
+ spin_unlock_irqrestore(&port->lock, flags);
goto done;
+ }
/*
* Now we wait for the transmit buffer to clear; and we notify
@@ -1314,6 +1320,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* setting tty->closing.
*/
tty->closing = 1;
+ spin_unlock_irqrestore(&port->lock, flags);
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, msecs_to_jiffies(port->closing_wait));
@@ -1340,20 +1347,26 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
tty_ldisc_flush(tty);
- tty->closing = 0;
tty_port_tty_set(port, NULL);
+ spin_lock_irqsave(&port->lock, flags);
+ tty->closing = 0;
if (port->blocked_open) {
+ spin_unlock_irqrestore(&port->lock, flags);
if (port->close_delay)
msleep_interruptible(port->close_delay);
+ spin_lock_irqsave(&port->lock, flags);
} else if (!uart_console(uport)) {
+ spin_unlock_irqrestore(&port->lock, flags);
uart_change_pm(state, 3);
+ spin_lock_irqsave(&port->lock, flags);
}
/*
* Wake up anyone trying to open this port.
*/
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
+ spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
done:
@@ -1429,6 +1442,7 @@ static void uart_hangup(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
+ unsigned long flags;
BUG_ON(!kernel_locked());
pr_debug("uart_hangup(%d)\n", state->uart_port->line);
@@ -1437,8 +1451,10 @@ static void uart_hangup(struct tty_struct *tty)
if (port->flags & ASYNC_NORMAL_ACTIVE) {
uart_flush_buffer(tty);
uart_shutdown(tty, state);
+ spin_lock_irqsave(&port->lock, flags);
port->count = 0;
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
+ spin_unlock_irqrestore(&port->lock, flags);
tty_port_tty_set(port, NULL);
wake_up_interruptible(&port->open_wait);
wake_up_interruptible(&port->delta_msr_wait);
@@ -1496,9 +1512,13 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
struct uart_port *uport = state->uart_port;
struct tty_port *port = &state->port;
unsigned int mctrl;
+ unsigned long flags;
+ spin_lock_irqsave(&port->lock, flags);
+ if (!tty_hung_up_p(filp))
+ port->count--;
port->blocked_open++;
- port->count--;
+ spin_unlock_irqrestore(&port->lock, flags);
add_wait_queue(&port->open_wait, &wait);
while (1) {
@@ -1535,23 +1555,26 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
* not set RTS here - we want to make sure we catch
* the data from the modem.
*/
- if (port->tty->termios->c_cflag & CBAUD)
+ if (port->tty->termios->c_cflag & CBAUD) {
+ mutex_lock(&port->mutex);
uart_set_mctrl(uport, TIOCM_DTR);
+ mutex_unlock(&port->mutex);
+ }
/*
* and wait for the carrier to indicate that the
* modem is ready for us.
*/
+ mutex_lock(&port->mutex);
spin_lock_irq(&uport->lock);
uport->ops->enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
+ mutex_unlock(&port->mutex);
if (mctrl & TIOCM_CAR)
break;
- mutex_unlock(&port->mutex);
schedule();
- mutex_lock(&port->mutex);
if (signal_pending(current))
break;
@@ -1559,8 +1582,11 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
- port->count++;
+ spin_lock_irqsave(&port->lock, flags);
+ if (!tty_hung_up_p(filp))
+ port->count++;
port->blocked_open--;
+ spin_unlock_irqrestore(&port->lock, flags);
if (signal_pending(current))
return -ERESTARTSYS;
@@ -1677,9 +1703,9 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
/*
* If we succeeded, wait until the port is ready.
*/
+ mutex_unlock(&port->mutex);
if (retval == 0)
retval = uart_block_til_ready(filp, state);
- mutex_unlock(&port->mutex);
/*
* If this is the first open to succeed, adjust things to suit.
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/4] serial: add port helpers
2010-05-19 12:13 [PATCH 0/4] serial: move towards tty_port Alan Cox
2010-05-19 12:13 ` [PATCH 1/4] serial: Change the wait for carrier locking Alan Cox
@ 2010-05-19 12:14 ` Alan Cox
2010-05-19 12:14 ` [PATCH 3/4] serial: trim locking on the helpers Alan Cox
2010-05-19 12:14 ` [PATCH 4/4] serial: Use block_til_ready helper Alan Cox
3 siblings, 0 replies; 5+ messages in thread
From: Alan Cox @ 2010-05-19 12:14 UTC (permalink / raw)
To: greg, linux-serial
We can make this the same as the ones that will be needed by the tty_port
helper logic that we want to move to but still call them from the existing
code base.
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/serial/serial_core.c | 51 ++++++++++++++++++++++++++++++------------
1 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 424b1c7..2379045 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1501,6 +1501,34 @@ static void uart_update_termios(struct tty_struct *tty,
}
}
+static int uart_carrier_raised(struct tty_port *port)
+{
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport = state->uart_port;
+ int mctrl;
+ mutex_lock(&port->mutex);
+ spin_lock_irq(&uport->lock);
+ uport->ops->enable_ms(uport);
+ mctrl = uport->ops->get_mctrl(uport);
+ spin_unlock_irq(&uport->lock);
+ mutex_unlock(&port->mutex);
+ if (mctrl & TIOCM_CAR)
+ return 1;
+ return 0;
+}
+
+static void uart_dtr_rts(struct tty_port *port, int onoff)
+{
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport = state->uart_port;
+ mutex_lock(&port->mutex);
+ if (onoff)
+ uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+ else
+ uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+ mutex_unlock(&port->mutex);
+}
+
/*
* Block the open until the port is ready. We must be called with
* the per-port semaphore held.
@@ -1509,9 +1537,7 @@ static int
uart_block_til_ready(struct file *filp, struct uart_state *state)
{
DECLARE_WAITQUEUE(wait, current);
- struct uart_port *uport = state->uart_port;
struct tty_port *port = &state->port;
- unsigned int mctrl;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
@@ -1555,23 +1581,14 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
* not set RTS here - we want to make sure we catch
* the data from the modem.
*/
- if (port->tty->termios->c_cflag & CBAUD) {
- mutex_lock(&port->mutex);
- uart_set_mctrl(uport, TIOCM_DTR);
- mutex_unlock(&port->mutex);
- }
+ if (port->tty->termios->c_cflag & CBAUD)
+ tty_port_raise_dtr_rts(port);
/*
* and wait for the carrier to indicate that the
* modem is ready for us.
*/
- mutex_lock(&port->mutex);
- spin_lock_irq(&uport->lock);
- uport->ops->enable_ms(uport);
- mctrl = uport->ops->get_mctrl(uport);
- spin_unlock_irq(&uport->lock);
- mutex_unlock(&port->mutex);
- if (mctrl & TIOCM_CAR)
+ if (tty_port_carrier_raised(port))
break;
schedule();
@@ -2349,6 +2366,11 @@ static const struct tty_operations uart_ops = {
#endif
};
+static const struct tty_port_operations uart_port_ops = {
+ .carrier_raised = uart_carrier_raised,
+ .dtr_rts = uart_dtr_rts,
+};
+
/**
* uart_register_driver - register a driver with the uart core layer
* @drv: low level driver structure
@@ -2405,6 +2427,7 @@ int uart_register_driver(struct uart_driver *drv)
struct tty_port *port = &state->port;
tty_port_init(port);
+ port->ops = &uart_port_ops;
port->close_delay = 500; /* .5 seconds */
port->closing_wait = 30000; /* 30 seconds */
tasklet_init(&state->tlet, uart_tasklet_action,
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/4] serial: trim locking on the helpers
2010-05-19 12:13 [PATCH 0/4] serial: move towards tty_port Alan Cox
2010-05-19 12:13 ` [PATCH 1/4] serial: Change the wait for carrier locking Alan Cox
2010-05-19 12:14 ` [PATCH 2/4] serial: add port helpers Alan Cox
@ 2010-05-19 12:14 ` Alan Cox
2010-05-19 12:14 ` [PATCH 4/4] serial: Use block_til_ready helper Alan Cox
3 siblings, 0 replies; 5+ messages in thread
From: Alan Cox @ 2010-05-19 12:14 UTC (permalink / raw)
To: greg, linux-serial
The port mutex protects port->tty, but these paths never need to walk from
port->tty. They do need the low level lock as the API expects that but they
already also take it.
Thus we can drop the extra mutex lock calls here.
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/serial/serial_core.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 2379045..0603e0d 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1506,12 +1506,10 @@ static int uart_carrier_raised(struct tty_port *port)
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
int mctrl;
- mutex_lock(&port->mutex);
spin_lock_irq(&uport->lock);
uport->ops->enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
- mutex_unlock(&port->mutex);
if (mctrl & TIOCM_CAR)
return 1;
return 0;
@@ -1521,12 +1519,11 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- mutex_lock(&port->mutex);
+
if (onoff)
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
else
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
- mutex_unlock(&port->mutex);
}
/*
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 4/4] serial: Use block_til_ready helper
2010-05-19 12:13 [PATCH 0/4] serial: move towards tty_port Alan Cox
` (2 preceding siblings ...)
2010-05-19 12:14 ` [PATCH 3/4] serial: trim locking on the helpers Alan Cox
@ 2010-05-19 12:14 ` Alan Cox
3 siblings, 0 replies; 5+ messages in thread
From: Alan Cox @ 2010-05-19 12:14 UTC (permalink / raw)
To: greg, linux-serial
Our code now rather closely resembles the helper, so switch to it.
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/serial/serial_core.c | 87 ------------------------------------------
1 files changed, 1 insertions(+), 86 deletions(-)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 0603e0d..a55751a 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1526,91 +1526,6 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
}
-/*
- * Block the open until the port is ready. We must be called with
- * the per-port semaphore held.
- */
-static int
-uart_block_til_ready(struct file *filp, struct uart_state *state)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct tty_port *port = &state->port;
- unsigned long flags;
-
- spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp))
- port->count--;
- port->blocked_open++;
- spin_unlock_irqrestore(&port->lock, flags);
-
- add_wait_queue(&port->open_wait, &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- /*
- * If we have been hung up, tell userspace/restart open.
- */
- if (tty_hung_up_p(filp) || port->tty == NULL)
- break;
-
- /*
- * If the port has been closed, tell userspace/restart open.
- */
- if (!(port->flags & ASYNC_INITIALIZED))
- break;
-
- /*
- * If non-blocking mode is set, or CLOCAL mode is set,
- * we don't want to wait for the modem status lines to
- * indicate that the port is ready.
- *
- * Also, if the port is not enabled/configured, we want
- * to allow the open to succeed here. Note that we will
- * have set TTY_IO_ERROR for a non-existant port.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (port->tty->termios->c_cflag & CLOCAL) ||
- (port->tty->flags & (1 << TTY_IO_ERROR)))
- break;
-
- /*
- * Set DTR to allow modem to know we're waiting. Do
- * not set RTS here - we want to make sure we catch
- * the data from the modem.
- */
- if (port->tty->termios->c_cflag & CBAUD)
- tty_port_raise_dtr_rts(port);
-
- /*
- * and wait for the carrier to indicate that the
- * modem is ready for us.
- */
- if (tty_port_carrier_raised(port))
- break;
-
- schedule();
-
- if (signal_pending(current))
- break;
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&port->open_wait, &wait);
-
- spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- spin_unlock_irqrestore(&port->lock, flags);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (!port->tty || tty_hung_up_p(filp))
- return -EAGAIN;
-
- return 0;
-}
-
static struct uart_state *uart_get(struct uart_driver *drv, int line)
{
struct uart_state *state;
@@ -1719,7 +1634,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
*/
mutex_unlock(&port->mutex);
if (retval == 0)
- retval = uart_block_til_ready(filp, state);
+ retval = tty_port_block_til_ready(port, tty, filp);
/*
* If this is the first open to succeed, adjust things to suit.
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-05-19 12:56 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-19 12:13 [PATCH 0/4] serial: move towards tty_port Alan Cox
2010-05-19 12:13 ` [PATCH 1/4] serial: Change the wait for carrier locking Alan Cox
2010-05-19 12:14 ` [PATCH 2/4] serial: add port helpers Alan Cox
2010-05-19 12:14 ` [PATCH 3/4] serial: trim locking on the helpers Alan Cox
2010-05-19 12:14 ` [PATCH 4/4] serial: Use block_til_ready helper Alan Cox
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).