aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2005-06-29 04:42:38 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-06-29 04:42:38 -0400
commitc5f4644e6c8ba21666128603e4e92544d3cd740d (patch)
tree1a8b4c730ca575d4b1118af174b070764803fb2c
parenta839688362e32f01608838516036697e30618b39 (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>
-rw-r--r--Documentation/serial/driver4
-rw-r--r--drivers/serial/8250.c3
-rw-r--r--drivers/serial/au1x00_uart.c3
-rw-r--r--drivers/serial/ip22zilog.c13
-rw-r--r--drivers/serial/mpsc.c3
-rw-r--r--drivers/serial/pmac_zilog.c4
-rw-r--r--drivers/serial/pxa.c3
-rw-r--r--drivers/serial/serial_core.c11
-rw-r--r--drivers/serial/serial_txx9.c3
-rw-r--r--drivers/serial/sunsab.c7
-rw-r--r--drivers/serial/sunsu.c3
-rw-r--r--drivers/serial/sunzilog.c13
12 files changed, 29 insertions, 41 deletions
diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index e9c0178cd202..ac7eabbf662a 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -107,8 +107,8 @@ hardware.
107 indicate that the signal is permanently active. If RI is 107 indicate that the signal is permanently active. If RI is
108 not available, the signal should not be indicated as active. 108 not available, the signal should not be indicated as active.
109 109
110 Locking: none. 110 Locking: port->lock taken.
111 Interrupts: caller dependent. 111 Interrupts: locally disabled.
112 This call must not sleep 112 This call must not sleep
113 113
114 stop_tx(port,tty_stop) 114 stop_tx(port,tty_stop)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 34e75bc8f4cc..b53b53bb1475 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)
1376static unsigned int serial8250_get_mctrl(struct uart_port *port) 1376static 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 5400dc2c087e..6104aeef1243 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)
556static unsigned int serial8250_get_mctrl(struct uart_port *port) 556static 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 3ea46c069f6f..ea5bf4d4daa3 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
518static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port) 518static __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. */
536static unsigned int ip22zilog_tx_empty(struct uart_port *port) 531static 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. */
551static unsigned int ip22zilog_get_mctrl(struct uart_port *port) 552static 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 a2a643318002..e43276c6a954 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 85abd8a045e0..1c9f71617123 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 */
609static unsigned int pmz_get_mctrl(struct uart_port *port) 609static 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 08b08d6ae904..461c81c93207 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)
274static unsigned int serial_pxa_get_mctrl(struct uart_port *port) 274static 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
281return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; 280return 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 36b1ae083fb7..f5ce58d0514d 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 3f1051a4a13f..d085030df70b 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)
442static unsigned int serial_txx9_get_mctrl(struct uart_port *port) 442static 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 10e2990a40d4..8d198880756a 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. */
430static unsigned int sunsab_get_mctrl(struct uart_port *port) 430static 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 ddc97c905e14..d57a3553aea3 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)
572static unsigned int sunsu_get_mctrl(struct uart_port *port) 572static 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 8e65206d3d76..bff42a7b89d0 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
610static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port) 610static __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. */
628static unsigned int sunzilog_tx_empty(struct uart_port *port) 623static 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. */
643static unsigned int sunzilog_get_mctrl(struct uart_port *port) 644static unsigned int sunzilog_get_mctrl(struct uart_port *port)
644{ 645{
645 unsigned char status; 646 unsigned char status;