Commit c5f4644e6c8ba21666128603e4e92544d3cd740d
Committed by
Russell King
1 parent
a839688362
Exists in
master
and in
7 other branches
[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
- drivers/serial/8250.c
- drivers/serial/au1x00_uart.c
- drivers/serial/ip22zilog.c
- drivers/serial/mpsc.c
- drivers/serial/pmac_zilog.c
- drivers/serial/pxa.c
- drivers/serial/serial_core.c
- drivers/serial/serial_txx9.c
- drivers/serial/sunsab.c
- drivers/serial/sunsu.c
- drivers/serial/sunzilog.c
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; |