Commit c5f4644e6c8ba21666128603e4e92544d3cd740d

Authored by Russell King
Committed by Russell King
1 parent a839688362

[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>

Showing 12 changed files with 29 additions and 41 deletions Side-by-side Diff

Documentation/serial/driver
... ... @@ -107,8 +107,8 @@
107 107 indicate that the signal is permanently active. If RI is
108 108 not available, the signal should not be indicated as active.
109 109  
110   - Locking: none.
111   - Interrupts: caller dependent.
  110 + Locking: port->lock taken.
  111 + Interrupts: locally disabled.
112 112 This call must not sleep
113 113  
114 114 stop_tx(port,tty_stop)
drivers/serial/8250.c
... ... @@ -1376,13 +1376,10 @@
1376 1376 static unsigned int serial8250_get_mctrl(struct uart_port *port)
1377 1377 {
1378 1378 struct uart_8250_port *up = (struct uart_8250_port *)port;
1379   - unsigned long flags;
1380 1379 unsigned char status;
1381 1380 unsigned int ret;
1382 1381  
1383   - spin_lock_irqsave(&up->port.lock, flags);
1384 1382 status = serial_in(up, UART_MSR);
1385   - spin_unlock_irqrestore(&up->port.lock, flags);
1386 1383  
1387 1384 ret = 0;
1388 1385 if (status & UART_MSR_DCD)
drivers/serial/au1x00_uart.c
... ... @@ -556,13 +556,10 @@
556 556 static unsigned int serial8250_get_mctrl(struct uart_port *port)
557 557 {
558 558 struct uart_8250_port *up = (struct uart_8250_port *)port;
559   - unsigned long flags;
560 559 unsigned char status;
561 560 unsigned int ret;
562 561  
563   - spin_lock_irqsave(&up->port.lock, flags);
564 562 status = serial_in(up, UART_MSR);
565   - spin_unlock_irqrestore(&up->port.lock, flags);
566 563  
567 564 ret = 0;
568 565 if (status & UART_MSR_DCD)
drivers/serial/ip22zilog.c
... ... @@ -518,27 +518,28 @@
518 518 static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
519 519 {
520 520 struct zilog_channel *channel;
521   - unsigned long flags;
522 521 unsigned char status;
523 522  
524   - spin_lock_irqsave(&port->lock, flags);
525   -
526 523 channel = ZILOG_CHANNEL_FROM_PORT(port);
527 524 status = readb(&channel->control);
528 525 ZSDELAY();
529 526  
530   - spin_unlock_irqrestore(&port->lock, flags);
531   -
532 527 return status;
533 528 }
534 529  
535 530 /* The port lock is not held. */
536 531 static unsigned int ip22zilog_tx_empty(struct uart_port *port)
537 532 {
  533 + unsigned long flags;
538 534 unsigned char status;
539 535 unsigned int ret;
540 536  
  537 + spin_lock_irqsave(&port->lock, flags);
  538 +
541 539 status = ip22zilog_read_channel_status(port);
  540 +
  541 + spin_unlock_irqrestore(&port->lock, flags);
  542 +
542 543 if (status & Tx_BUF_EMP)
543 544 ret = TIOCSER_TEMT;
544 545 else
... ... @@ -547,7 +548,7 @@
547 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 552 static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
552 553 {
553 554 unsigned char status;
drivers/serial/mpsc.c
... ... @@ -1058,12 +1058,9 @@
1058 1058 {
1059 1059 struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
1060 1060 u32 mflags, status;
1061   - ulong iflags;
1062 1061  
1063   - spin_lock_irqsave(&pi->port.lock, iflags);
1064 1062 status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m :
1065 1063 readl(pi->mpsc_base + MPSC_CHR_10);
1066   - spin_unlock_irqrestore(&pi->port.lock, iflags);
1067 1064  
1068 1065 mflags = 0;
1069 1066 if (status & 0x1)
drivers/serial/pmac_zilog.c
... ... @@ -604,7 +604,7 @@
604 604 /*
605 605 * Get Modem Control bits (only the input ones, the core will
606 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 609 static unsigned int pmz_get_mctrl(struct uart_port *port)
610 610 {
... ... @@ -615,7 +615,7 @@
615 615 if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
616 616 return 0;
617 617  
618   - status = pmz_peek_status(to_pmz(port));
  618 + status = read_zsreg(uap, R0);
619 619  
620 620 ret = 0;
621 621 if (status & DCD)
drivers/serial/pxa.c
... ... @@ -274,14 +274,11 @@
274 274 static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
275 275 {
276 276 struct uart_pxa_port *up = (struct uart_pxa_port *)port;
277   - unsigned long flags;
278 277 unsigned char status;
279 278 unsigned int ret;
280 279  
281 280 return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
282   - spin_lock_irqsave(&up->port.lock, flags);
283 281 status = serial_in(up, UART_MSR);
284   - spin_unlock_irqrestore(&up->port.lock, flags);
285 282  
286 283 ret = 0;
287 284 if (status & UART_MSR_DCD)
drivers/serial/serial_core.c
... ... @@ -828,7 +828,10 @@
828 828 if ((!file || !tty_hung_up_p(file)) &&
829 829 !(tty->flags & (1 << TTY_IO_ERROR))) {
830 830 result = port->mctrl;
  831 +
  832 + spin_lock_irq(&port->lock);
831 833 result |= port->ops->get_mctrl(port);
  834 + spin_unlock_irq(&port->lock);
832 835 }
833 836 up(&state->sem);
834 837  
... ... @@ -1369,6 +1372,7 @@
1369 1372 DECLARE_WAITQUEUE(wait, current);
1370 1373 struct uart_info *info = state->info;
1371 1374 struct uart_port *port = state->port;
  1375 + unsigned int mctrl;
1372 1376  
1373 1377 info->blocked_open++;
1374 1378 state->count--;
... ... @@ -1416,7 +1420,10 @@
1416 1420 * and wait for the carrier to indicate that the
1417 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 1427 break;
1421 1428  
1422 1429 up(&state->sem);
1423 1430  
... ... @@ -1618,7 +1625,9 @@
1618 1625  
1619 1626 if(capable(CAP_SYS_ADMIN))
1620 1627 {
  1628 + spin_lock_irq(&port->lock);
1621 1629 status = port->ops->get_mctrl(port);
  1630 + spin_unlock_irq(&port->lock);
1622 1631  
1623 1632 ret += sprintf(buf + ret, " tx:%d rx:%d",
1624 1633 port->icount.tx, port->icount.rx);
drivers/serial/serial_txx9.c
... ... @@ -442,13 +442,10 @@
442 442 static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
443 443 {
444 444 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
445   - unsigned long flags;
446 445 unsigned int ret;
447 446  
448   - spin_lock_irqsave(&up->port.lock, flags);
449 447 ret = ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS)
450 448 | ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS);
451   - spin_unlock_irqrestore(&up->port.lock, flags);
452 449  
453 450 return ret;
454 451 }
drivers/serial/sunsab.c
... ... @@ -426,18 +426,15 @@
426 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 430 static unsigned int sunsab_get_mctrl(struct uart_port *port)
431 431 {
432 432 struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
433   - unsigned long flags;
434 433 unsigned char val;
435 434 unsigned int result;
436 435  
437 436 result = 0;
438 437  
439   - spin_lock_irqsave(&up->port.lock, flags);
440   -
441 438 val = readb(&up->regs->r.pvr);
442 439 result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR;
443 440  
... ... @@ -446,8 +443,6 @@
446 443  
447 444 val = readb(&up->regs->r.star);
448 445 result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0;
449   -
450   - spin_unlock_irqrestore(&up->port.lock, flags);
451 446  
452 447 return result;
453 448 }
drivers/serial/sunsu.c
... ... @@ -572,13 +572,10 @@
572 572 static unsigned int sunsu_get_mctrl(struct uart_port *port)
573 573 {
574 574 struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
575   - unsigned long flags;
576 575 unsigned char status;
577 576 unsigned int ret;
578 577  
579   - spin_lock_irqsave(&up->port.lock, flags);
580 578 status = serial_in(up, UART_MSR);
581   - spin_unlock_irqrestore(&up->port.lock, flags);
582 579  
583 580 ret = 0;
584 581 if (status & UART_MSR_DCD)
drivers/serial/sunzilog.c
... ... @@ -610,27 +610,28 @@
610 610 static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port)
611 611 {
612 612 struct zilog_channel __iomem *channel;
613   - unsigned long flags;
614 613 unsigned char status;
615 614  
616   - spin_lock_irqsave(&port->lock, flags);
617   -
618 615 channel = ZILOG_CHANNEL_FROM_PORT(port);
619 616 status = sbus_readb(&channel->control);
620 617 ZSDELAY();
621 618  
622   - spin_unlock_irqrestore(&port->lock, flags);
623   -
624 619 return status;
625 620 }
626 621  
627 622 /* The port lock is not held. */
628 623 static unsigned int sunzilog_tx_empty(struct uart_port *port)
629 624 {
  625 + unsigned long flags;
630 626 unsigned char status;
631 627 unsigned int ret;
632 628  
  629 + spin_lock_irqsave(&port->lock, flags);
  630 +
633 631 status = sunzilog_read_channel_status(port);
  632 +
  633 + spin_unlock_irqrestore(&port->lock, flags);
  634 +
634 635 if (status & Tx_BUF_EMP)
635 636 ret = TIOCSER_TEMT;
636 637 else
... ... @@ -639,7 +640,7 @@
639 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 644 static unsigned int sunzilog_get_mctrl(struct uart_port *port)
644 645 {
645 646 unsigned char status;