diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2005-06-29 04:42:38 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-06-29 04:42:38 -0400 |
commit | c5f4644e6c8ba21666128603e4e92544d3cd740d (patch) | |
tree | 1a8b4c730ca575d4b1118af174b070764803fb2c /drivers | |
parent | a839688362e32f01608838516036697e30618b39 (diff) |
[PATCH] Serial: Adjust serial locking
This patch changes the way serial ports are locked when getting modem
status. This change is necessary because we will need to atomically
read the modem status and take action depending on the CTS status.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/8250.c | 3 | ||||
-rw-r--r-- | drivers/serial/au1x00_uart.c | 3 | ||||
-rw-r--r-- | drivers/serial/ip22zilog.c | 13 | ||||
-rw-r--r-- | drivers/serial/mpsc.c | 3 | ||||
-rw-r--r-- | drivers/serial/pmac_zilog.c | 4 | ||||
-rw-r--r-- | drivers/serial/pxa.c | 3 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 11 | ||||
-rw-r--r-- | drivers/serial/serial_txx9.c | 3 | ||||
-rw-r--r-- | drivers/serial/sunsab.c | 7 | ||||
-rw-r--r-- | drivers/serial/sunsu.c | 3 | ||||
-rw-r--r-- | drivers/serial/sunzilog.c | 13 |
11 files changed, 27 insertions, 39 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 34e75bc8f4..b53b53bb14 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -1376,13 +1376,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) | |||
1376 | static unsigned int serial8250_get_mctrl(struct uart_port *port) | 1376 | static unsigned int serial8250_get_mctrl(struct uart_port *port) |
1377 | { | 1377 | { |
1378 | struct uart_8250_port *up = (struct uart_8250_port *)port; | 1378 | struct uart_8250_port *up = (struct uart_8250_port *)port; |
1379 | unsigned long flags; | ||
1380 | unsigned char status; | 1379 | unsigned char status; |
1381 | unsigned int ret; | 1380 | unsigned int ret; |
1382 | 1381 | ||
1383 | spin_lock_irqsave(&up->port.lock, flags); | ||
1384 | status = serial_in(up, UART_MSR); | 1382 | status = serial_in(up, UART_MSR); |
1385 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
1386 | 1383 | ||
1387 | ret = 0; | 1384 | ret = 0; |
1388 | if (status & UART_MSR_DCD) | 1385 | if (status & UART_MSR_DCD) |
diff --git a/drivers/serial/au1x00_uart.c b/drivers/serial/au1x00_uart.c index 5400dc2c08..6104aeef12 100644 --- a/drivers/serial/au1x00_uart.c +++ b/drivers/serial/au1x00_uart.c | |||
@@ -556,13 +556,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) | |||
556 | static unsigned int serial8250_get_mctrl(struct uart_port *port) | 556 | static unsigned int serial8250_get_mctrl(struct uart_port *port) |
557 | { | 557 | { |
558 | struct uart_8250_port *up = (struct uart_8250_port *)port; | 558 | struct uart_8250_port *up = (struct uart_8250_port *)port; |
559 | unsigned long flags; | ||
560 | unsigned char status; | 559 | unsigned char status; |
561 | unsigned int ret; | 560 | unsigned int ret; |
562 | 561 | ||
563 | spin_lock_irqsave(&up->port.lock, flags); | ||
564 | status = serial_in(up, UART_MSR); | 562 | status = serial_in(up, UART_MSR); |
565 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
566 | 563 | ||
567 | ret = 0; | 564 | ret = 0; |
568 | if (status & UART_MSR_DCD) | 565 | if (status & UART_MSR_DCD) |
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index 3ea46c069f..ea5bf4d4da 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c | |||
@@ -518,27 +518,28 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re | |||
518 | static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port) | 518 | static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port) |
519 | { | 519 | { |
520 | struct zilog_channel *channel; | 520 | struct zilog_channel *channel; |
521 | unsigned long flags; | ||
522 | unsigned char status; | 521 | unsigned char status; |
523 | 522 | ||
524 | spin_lock_irqsave(&port->lock, flags); | ||
525 | |||
526 | channel = ZILOG_CHANNEL_FROM_PORT(port); | 523 | channel = ZILOG_CHANNEL_FROM_PORT(port); |
527 | status = readb(&channel->control); | 524 | status = readb(&channel->control); |
528 | ZSDELAY(); | 525 | ZSDELAY(); |
529 | 526 | ||
530 | spin_unlock_irqrestore(&port->lock, flags); | ||
531 | |||
532 | return status; | 527 | return status; |
533 | } | 528 | } |
534 | 529 | ||
535 | /* The port lock is not held. */ | 530 | /* The port lock is not held. */ |
536 | static unsigned int ip22zilog_tx_empty(struct uart_port *port) | 531 | static unsigned int ip22zilog_tx_empty(struct uart_port *port) |
537 | { | 532 | { |
533 | unsigned long flags; | ||
538 | unsigned char status; | 534 | unsigned char status; |
539 | unsigned int ret; | 535 | unsigned int ret; |
540 | 536 | ||
537 | spin_lock_irqsave(&port->lock, flags); | ||
538 | |||
541 | status = ip22zilog_read_channel_status(port); | 539 | status = ip22zilog_read_channel_status(port); |
540 | |||
541 | spin_unlock_irqrestore(&port->lock, flags); | ||
542 | |||
542 | if (status & Tx_BUF_EMP) | 543 | if (status & Tx_BUF_EMP) |
543 | ret = TIOCSER_TEMT; | 544 | ret = TIOCSER_TEMT; |
544 | else | 545 | else |
@@ -547,7 +548,7 @@ static unsigned int ip22zilog_tx_empty(struct uart_port *port) | |||
547 | return ret; | 548 | return ret; |
548 | } | 549 | } |
549 | 550 | ||
550 | /* The port lock is not held. */ | 551 | /* The port lock is held and interrupts are disabled. */ |
551 | static unsigned int ip22zilog_get_mctrl(struct uart_port *port) | 552 | static unsigned int ip22zilog_get_mctrl(struct uart_port *port) |
552 | { | 553 | { |
553 | unsigned char status; | 554 | unsigned char status; |
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index a2a6433180..e43276c6a9 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c | |||
@@ -1058,12 +1058,9 @@ mpsc_get_mctrl(struct uart_port *port) | |||
1058 | { | 1058 | { |
1059 | struct mpsc_port_info *pi = (struct mpsc_port_info *)port; | 1059 | struct mpsc_port_info *pi = (struct mpsc_port_info *)port; |
1060 | u32 mflags, status; | 1060 | u32 mflags, status; |
1061 | ulong iflags; | ||
1062 | 1061 | ||
1063 | spin_lock_irqsave(&pi->port.lock, iflags); | ||
1064 | status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m : | 1062 | status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m : |
1065 | readl(pi->mpsc_base + MPSC_CHR_10); | 1063 | readl(pi->mpsc_base + MPSC_CHR_10); |
1066 | spin_unlock_irqrestore(&pi->port.lock, iflags); | ||
1067 | 1064 | ||
1068 | mflags = 0; | 1065 | mflags = 0; |
1069 | if (status & 0x1) | 1066 | if (status & 0x1) |
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 85abd8a045..1c9f716171 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c | |||
@@ -604,7 +604,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
604 | /* | 604 | /* |
605 | * Get Modem Control bits (only the input ones, the core will | 605 | * Get Modem Control bits (only the input ones, the core will |
606 | * or that with a cached value of the control ones) | 606 | * or that with a cached value of the control ones) |
607 | * The port lock is not held. | 607 | * The port lock is held and interrupts are disabled. |
608 | */ | 608 | */ |
609 | static unsigned int pmz_get_mctrl(struct uart_port *port) | 609 | static unsigned int pmz_get_mctrl(struct uart_port *port) |
610 | { | 610 | { |
@@ -615,7 +615,7 @@ static unsigned int pmz_get_mctrl(struct uart_port *port) | |||
615 | if (ZS_IS_ASLEEP(uap) || uap->node == NULL) | 615 | if (ZS_IS_ASLEEP(uap) || uap->node == NULL) |
616 | return 0; | 616 | return 0; |
617 | 617 | ||
618 | status = pmz_peek_status(to_pmz(port)); | 618 | status = read_zsreg(uap, R0); |
619 | 619 | ||
620 | ret = 0; | 620 | ret = 0; |
621 | if (status & DCD) | 621 | if (status & DCD) |
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 08b08d6ae9..461c81c932 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c | |||
@@ -274,14 +274,11 @@ static unsigned int serial_pxa_tx_empty(struct uart_port *port) | |||
274 | static unsigned int serial_pxa_get_mctrl(struct uart_port *port) | 274 | static unsigned int serial_pxa_get_mctrl(struct uart_port *port) |
275 | { | 275 | { |
276 | struct uart_pxa_port *up = (struct uart_pxa_port *)port; | 276 | struct uart_pxa_port *up = (struct uart_pxa_port *)port; |
277 | unsigned long flags; | ||
278 | unsigned char status; | 277 | unsigned char status; |
279 | unsigned int ret; | 278 | unsigned int ret; |
280 | 279 | ||
281 | return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; | 280 | return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; |
282 | spin_lock_irqsave(&up->port.lock, flags); | ||
283 | status = serial_in(up, UART_MSR); | 281 | status = serial_in(up, UART_MSR); |
284 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
285 | 282 | ||
286 | ret = 0; | 283 | ret = 0; |
287 | if (status & UART_MSR_DCD) | 284 | if (status & UART_MSR_DCD) |
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 36b1ae083f..f5ce58d051 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
@@ -828,7 +828,10 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file) | |||
828 | if ((!file || !tty_hung_up_p(file)) && | 828 | if ((!file || !tty_hung_up_p(file)) && |
829 | !(tty->flags & (1 << TTY_IO_ERROR))) { | 829 | !(tty->flags & (1 << TTY_IO_ERROR))) { |
830 | result = port->mctrl; | 830 | result = port->mctrl; |
831 | |||
832 | spin_lock_irq(&port->lock); | ||
831 | result |= port->ops->get_mctrl(port); | 833 | result |= port->ops->get_mctrl(port); |
834 | spin_unlock_irq(&port->lock); | ||
832 | } | 835 | } |
833 | up(&state->sem); | 836 | up(&state->sem); |
834 | 837 | ||
@@ -1369,6 +1372,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) | |||
1369 | DECLARE_WAITQUEUE(wait, current); | 1372 | DECLARE_WAITQUEUE(wait, current); |
1370 | struct uart_info *info = state->info; | 1373 | struct uart_info *info = state->info; |
1371 | struct uart_port *port = state->port; | 1374 | struct uart_port *port = state->port; |
1375 | unsigned int mctrl; | ||
1372 | 1376 | ||
1373 | info->blocked_open++; | 1377 | info->blocked_open++; |
1374 | state->count--; | 1378 | state->count--; |
@@ -1416,7 +1420,10 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) | |||
1416 | * and wait for the carrier to indicate that the | 1420 | * and wait for the carrier to indicate that the |
1417 | * modem is ready for us. | 1421 | * modem is ready for us. |
1418 | */ | 1422 | */ |
1419 | if (port->ops->get_mctrl(port) & TIOCM_CAR) | 1423 | spin_lock_irq(&port->lock); |
1424 | mctrl = port->ops->get_mctrl(port); | ||
1425 | spin_unlock_irq(&port->lock); | ||
1426 | if (mctrl & TIOCM_CAR) | ||
1420 | break; | 1427 | break; |
1421 | 1428 | ||
1422 | up(&state->sem); | 1429 | up(&state->sem); |
@@ -1618,7 +1625,9 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) | |||
1618 | 1625 | ||
1619 | if(capable(CAP_SYS_ADMIN)) | 1626 | if(capable(CAP_SYS_ADMIN)) |
1620 | { | 1627 | { |
1628 | spin_lock_irq(&port->lock); | ||
1621 | status = port->ops->get_mctrl(port); | 1629 | status = port->ops->get_mctrl(port); |
1630 | spin_unlock_irq(&port->lock); | ||
1622 | 1631 | ||
1623 | ret += sprintf(buf + ret, " tx:%d rx:%d", | 1632 | ret += sprintf(buf + ret, " tx:%d rx:%d", |
1624 | port->icount.tx, port->icount.rx); | 1633 | port->icount.tx, port->icount.rx); |
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 3f1051a4a1..d085030df7 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c | |||
@@ -442,13 +442,10 @@ static unsigned int serial_txx9_tx_empty(struct uart_port *port) | |||
442 | static unsigned int serial_txx9_get_mctrl(struct uart_port *port) | 442 | static unsigned int serial_txx9_get_mctrl(struct uart_port *port) |
443 | { | 443 | { |
444 | struct uart_txx9_port *up = (struct uart_txx9_port *)port; | 444 | struct uart_txx9_port *up = (struct uart_txx9_port *)port; |
445 | unsigned long flags; | ||
446 | unsigned int ret; | 445 | unsigned int ret; |
447 | 446 | ||
448 | spin_lock_irqsave(&up->port.lock, flags); | ||
449 | ret = ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS) | 447 | ret = ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS) |
450 | | ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS); | 448 | | ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS); |
451 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
452 | 449 | ||
453 | return ret; | 450 | return ret; |
454 | } | 451 | } |
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 10e2990a40..8d19888075 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c | |||
@@ -426,18 +426,15 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
426 | sunsab_tx_idle(up); | 426 | sunsab_tx_idle(up); |
427 | } | 427 | } |
428 | 428 | ||
429 | /* port->lock is not held. */ | 429 | /* port->lock is held by caller and interrupts are disabled. */ |
430 | static unsigned int sunsab_get_mctrl(struct uart_port *port) | 430 | static unsigned int sunsab_get_mctrl(struct uart_port *port) |
431 | { | 431 | { |
432 | struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; | 432 | struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; |
433 | unsigned long flags; | ||
434 | unsigned char val; | 433 | unsigned char val; |
435 | unsigned int result; | 434 | unsigned int result; |
436 | 435 | ||
437 | result = 0; | 436 | result = 0; |
438 | 437 | ||
439 | spin_lock_irqsave(&up->port.lock, flags); | ||
440 | |||
441 | val = readb(&up->regs->r.pvr); | 438 | val = readb(&up->regs->r.pvr); |
442 | result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR; | 439 | result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR; |
443 | 440 | ||
@@ -447,8 +444,6 @@ static unsigned int sunsab_get_mctrl(struct uart_port *port) | |||
447 | val = readb(&up->regs->r.star); | 444 | val = readb(&up->regs->r.star); |
448 | result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0; | 445 | result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0; |
449 | 446 | ||
450 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
451 | |||
452 | return result; | 447 | return result; |
453 | } | 448 | } |
454 | 449 | ||
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index ddc97c905e..d57a3553ae 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c | |||
@@ -572,13 +572,10 @@ static unsigned int sunsu_tx_empty(struct uart_port *port) | |||
572 | static unsigned int sunsu_get_mctrl(struct uart_port *port) | 572 | static unsigned int sunsu_get_mctrl(struct uart_port *port) |
573 | { | 573 | { |
574 | struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; | 574 | struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; |
575 | unsigned long flags; | ||
576 | unsigned char status; | 575 | unsigned char status; |
577 | unsigned int ret; | 576 | unsigned int ret; |
578 | 577 | ||
579 | spin_lock_irqsave(&up->port.lock, flags); | ||
580 | status = serial_in(up, UART_MSR); | 578 | status = serial_in(up, UART_MSR); |
581 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
582 | 579 | ||
583 | ret = 0; | 580 | ret = 0; |
584 | if (status & UART_MSR_DCD) | 581 | if (status & UART_MSR_DCD) |
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 8e65206d3d..bff42a7b89 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c | |||
@@ -610,27 +610,28 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg | |||
610 | static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port) | 610 | static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port) |
611 | { | 611 | { |
612 | struct zilog_channel __iomem *channel; | 612 | struct zilog_channel __iomem *channel; |
613 | unsigned long flags; | ||
614 | unsigned char status; | 613 | unsigned char status; |
615 | 614 | ||
616 | spin_lock_irqsave(&port->lock, flags); | ||
617 | |||
618 | channel = ZILOG_CHANNEL_FROM_PORT(port); | 615 | channel = ZILOG_CHANNEL_FROM_PORT(port); |
619 | status = sbus_readb(&channel->control); | 616 | status = sbus_readb(&channel->control); |
620 | ZSDELAY(); | 617 | ZSDELAY(); |
621 | 618 | ||
622 | spin_unlock_irqrestore(&port->lock, flags); | ||
623 | |||
624 | return status; | 619 | return status; |
625 | } | 620 | } |
626 | 621 | ||
627 | /* The port lock is not held. */ | 622 | /* The port lock is not held. */ |
628 | static unsigned int sunzilog_tx_empty(struct uart_port *port) | 623 | static unsigned int sunzilog_tx_empty(struct uart_port *port) |
629 | { | 624 | { |
625 | unsigned long flags; | ||
630 | unsigned char status; | 626 | unsigned char status; |
631 | unsigned int ret; | 627 | unsigned int ret; |
632 | 628 | ||
629 | spin_lock_irqsave(&port->lock, flags); | ||
630 | |||
633 | status = sunzilog_read_channel_status(port); | 631 | status = sunzilog_read_channel_status(port); |
632 | |||
633 | spin_unlock_irqrestore(&port->lock, flags); | ||
634 | |||
634 | if (status & Tx_BUF_EMP) | 635 | if (status & Tx_BUF_EMP) |
635 | ret = TIOCSER_TEMT; | 636 | ret = TIOCSER_TEMT; |
636 | else | 637 | else |
@@ -639,7 +640,7 @@ static unsigned int sunzilog_tx_empty(struct uart_port *port) | |||
639 | return ret; | 640 | return ret; |
640 | } | 641 | } |
641 | 642 | ||
642 | /* The port lock is not held. */ | 643 | /* The port lock is held and interrupts are disabled. */ |
643 | static unsigned int sunzilog_get_mctrl(struct uart_port *port) | 644 | static unsigned int sunzilog_get_mctrl(struct uart_port *port) |
644 | { | 645 | { |
645 | unsigned char status; | 646 | unsigned char status; |