diff options
author | Jiri Slaby <jirislaby@gmail.com> | 2007-10-18 06:06:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-18 17:37:26 -0400 |
commit | ebafeeff0fea029099e9952f233e0794106897a6 (patch) | |
tree | 50bc3ca7f9d4c7153c3e98bda28199dcc6eff948 | |
parent | c43422053bea7a5ce09f18d0c50a606fe1a549f4 (diff) |
Char: cyclades, remove bottom half processing
The work done in bottom half doesn't cost much cpu time (e.g. tty_hangup
itself schedules its own bottom half), it's possible to do the work in isr
directly and save hence some .text.
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Paul Fulghum <paulkf@microgate.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/char/cyclades.c | 111 | ||||
-rw-r--r-- | include/linux/cyclades.h | 15 |
2 files changed, 20 insertions, 106 deletions
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 9e0adfe27c12..817fef3071af 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -897,71 +897,6 @@ static inline int serial_paranoia_check(struct cyclades_port *info, | |||
897 | return 0; | 897 | return 0; |
898 | } /* serial_paranoia_check */ | 898 | } /* serial_paranoia_check */ |
899 | 899 | ||
900 | /* | ||
901 | * This routine is used by the interrupt handler to schedule | ||
902 | * processing in the software interrupt portion of the driver | ||
903 | * (also known as the "bottom half"). This can be called any | ||
904 | * number of times for any channel without harm. | ||
905 | */ | ||
906 | static inline void cy_sched_event(struct cyclades_port *info, int event) | ||
907 | { | ||
908 | info->event |= 1 << event; /* remember what kind of event and who */ | ||
909 | schedule_work(&info->tqueue); | ||
910 | } /* cy_sched_event */ | ||
911 | |||
912 | /* | ||
913 | * This routine is used to handle the "bottom half" processing for the | ||
914 | * serial driver, known also the "software interrupt" processing. | ||
915 | * This processing is done at the kernel interrupt level, after the | ||
916 | * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This | ||
917 | * is where time-consuming activities which can not be done in the | ||
918 | * interrupt driver proper are done; the interrupt driver schedules | ||
919 | * them using cy_sched_event(), and they get done here. | ||
920 | * | ||
921 | * This is done through one level of indirection--the task queue. | ||
922 | * When a hardware interrupt service routine wants service by the | ||
923 | * driver's bottom half, it enqueues the appropriate tq_struct (one | ||
924 | * per port) to the keventd work queue and sets a request flag | ||
925 | * that the work queue be processed. | ||
926 | * | ||
927 | * Although this may seem unwieldy, it gives the system a way to | ||
928 | * pass an argument (in this case the pointer to the cyclades_port | ||
929 | * structure) to the bottom half of the driver. Previous kernels | ||
930 | * had to poll every port to see if that port needed servicing. | ||
931 | */ | ||
932 | static void | ||
933 | do_softint(struct work_struct *work) | ||
934 | { | ||
935 | struct cyclades_port *info = | ||
936 | container_of(work, struct cyclades_port, tqueue); | ||
937 | struct tty_struct *tty; | ||
938 | |||
939 | tty = info->tty; | ||
940 | if (!tty) | ||
941 | return; | ||
942 | |||
943 | if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { | ||
944 | tty_hangup(info->tty); | ||
945 | wake_up_interruptible(&info->open_wait); | ||
946 | info->flags &= ~ASYNC_NORMAL_ACTIVE; | ||
947 | } | ||
948 | if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) | ||
949 | wake_up_interruptible(&info->open_wait); | ||
950 | #ifdef CONFIG_CYZ_INTR | ||
951 | if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) && | ||
952 | !timer_pending(&cyz_rx_full_timer[info->line])) | ||
953 | mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1); | ||
954 | #endif | ||
955 | if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) | ||
956 | wake_up_interruptible(&info->delta_msr_wait); | ||
957 | tty_wakeup(tty); | ||
958 | #ifdef Z_WAKE | ||
959 | if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) | ||
960 | complete(&info->shutdown_wait); | ||
961 | #endif | ||
962 | } /* do_softint */ | ||
963 | |||
964 | |||
965 | /***********************************************************/ | 900 | /***********************************************************/ |
966 | /********* Start of block of Cyclom-Y specific code ********/ | 901 | /********* Start of block of Cyclom-Y specific code ********/ |
967 | 902 | ||
@@ -1243,7 +1178,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, | |||
1243 | cy_writeb(base_addr + (CySRER << index), | 1178 | cy_writeb(base_addr + (CySRER << index), |
1244 | readb(base_addr + (CySRER << index)) & | 1179 | readb(base_addr + (CySRER << index)) & |
1245 | ~CyTxRdy); | 1180 | ~CyTxRdy); |
1246 | goto txdone; | 1181 | goto txend; |
1247 | } | 1182 | } |
1248 | 1183 | ||
1249 | /* load the on-chip space for outbound data */ | 1184 | /* load the on-chip space for outbound data */ |
@@ -1334,9 +1269,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, | |||
1334 | } | 1269 | } |
1335 | 1270 | ||
1336 | txdone: | 1271 | txdone: |
1337 | if (info->xmit_cnt < WAKEUP_CHARS) { | 1272 | tty_wakeup(info->tty); |
1338 | cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); | ||
1339 | } | ||
1340 | txend: | 1273 | txend: |
1341 | /* end of service */ | 1274 | /* end of service */ |
1342 | cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f)); | 1275 | cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f)); |
@@ -1369,17 +1302,16 @@ txend: | |||
1369 | if (mdm_change & CyRI) | 1302 | if (mdm_change & CyRI) |
1370 | info->icount.rng++; | 1303 | info->icount.rng++; |
1371 | 1304 | ||
1372 | cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); | 1305 | wake_up_interruptible(&info->delta_msr_wait); |
1373 | } | 1306 | } |
1374 | 1307 | ||
1375 | if ((mdm_change & CyDCD) && | 1308 | if ((mdm_change & CyDCD) && |
1376 | (info->flags & ASYNC_CHECK_CD)) { | 1309 | (info->flags & ASYNC_CHECK_CD)) { |
1377 | if (mdm_status & CyDCD) { | 1310 | if (!(mdm_status & CyDCD)) { |
1378 | cy_sched_event(info, | 1311 | tty_hangup(info->tty); |
1379 | Cy_EVENT_OPEN_WAKEUP); | 1312 | info->flags &= ~ASYNC_NORMAL_ACTIVE; |
1380 | } else { | ||
1381 | cy_sched_event(info, Cy_EVENT_HANGUP); | ||
1382 | } | 1313 | } |
1314 | wake_up_interruptible(&info->open_wait); | ||
1383 | } | 1315 | } |
1384 | if ((mdm_change & CyCTS) && | 1316 | if ((mdm_change & CyCTS) && |
1385 | (info->flags & ASYNC_CTS_FLOW)) { | 1317 | (info->flags & ASYNC_CTS_FLOW)) { |
@@ -1394,8 +1326,7 @@ txend: | |||
1394 | (CySRER << | 1326 | (CySRER << |
1395 | index))| | 1327 | index))| |
1396 | CyTxRdy); | 1328 | CyTxRdy); |
1397 | cy_sched_event(info, | 1329 | tty_wakeup(info->tty); |
1398 | Cy_EVENT_WRITE_WAKEUP); | ||
1399 | } | 1330 | } |
1400 | } else { | 1331 | } else { |
1401 | if (!(mdm_status & CyCTS)) { | 1332 | if (!(mdm_status & CyCTS)) { |
@@ -1633,9 +1564,11 @@ cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl, | |||
1633 | char_count = rx_put - rx_get; | 1564 | char_count = rx_put - rx_get; |
1634 | else | 1565 | else |
1635 | char_count = rx_put - rx_get + rx_bufsize; | 1566 | char_count = rx_put - rx_get + rx_bufsize; |
1636 | if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) { | 1567 | if (char_count >= (int)readl(&buf_ctrl->rx_threshold) && |
1637 | cy_sched_event(info, Cy_EVENT_Z_RX_FULL); | 1568 | !timer_pending(&cyz_rx_full_timer[ |
1638 | } | 1569 | info->line])) |
1570 | mod_timer(&cyz_rx_full_timer[info->line], | ||
1571 | jiffies + 1); | ||
1639 | #endif | 1572 | #endif |
1640 | info->idle_stats.recv_idle = jiffies; | 1573 | info->idle_stats.recv_idle = jiffies; |
1641 | tty_schedule_flip(tty); | 1574 | tty_schedule_flip(tty); |
@@ -1717,9 +1650,7 @@ cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl, | |||
1717 | } | 1650 | } |
1718 | #endif | 1651 | #endif |
1719 | ztxdone: | 1652 | ztxdone: |
1720 | if (info->xmit_cnt < WAKEUP_CHARS) { | 1653 | tty_wakeup(tty); |
1721 | cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); | ||
1722 | } | ||
1723 | /* Update tx_put */ | 1654 | /* Update tx_put */ |
1724 | cy_writel(&buf_ctrl->tx_put, tx_put); | 1655 | cy_writel(&buf_ctrl->tx_put, tx_put); |
1725 | } | 1656 | } |
@@ -1781,10 +1712,11 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1781 | if ((fw_ver > 241 ? ((u_long) param) : | 1712 | if ((fw_ver > 241 ? ((u_long) param) : |
1782 | readl(&ch_ctrl->rs_status)) & | 1713 | readl(&ch_ctrl->rs_status)) & |
1783 | C_RS_DCD) { | 1714 | C_RS_DCD) { |
1784 | cy_sched_event(info, | 1715 | wake_up_interruptible(&info->open_wait); |
1785 | Cy_EVENT_OPEN_WAKEUP); | ||
1786 | } else { | 1716 | } else { |
1787 | cy_sched_event(info, Cy_EVENT_HANGUP); | 1717 | tty_hangup(info->tty); |
1718 | wake_up_interruptible(&info->open_wait); | ||
1719 | info->flags &= ~ASYNC_NORMAL_ACTIVE; | ||
1788 | } | 1720 | } |
1789 | } | 1721 | } |
1790 | break; | 1722 | break; |
@@ -1802,7 +1734,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1802 | break; | 1734 | break; |
1803 | #ifdef Z_WAKE | 1735 | #ifdef Z_WAKE |
1804 | case C_CM_IOCTLW: | 1736 | case C_CM_IOCTLW: |
1805 | cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP); | 1737 | complete(&info->shutdown_wait); |
1806 | break; | 1738 | break; |
1807 | #endif | 1739 | #endif |
1808 | #ifdef CONFIG_CYZ_INTR | 1740 | #ifdef CONFIG_CYZ_INTR |
@@ -1834,7 +1766,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1834 | break; | 1766 | break; |
1835 | } | 1767 | } |
1836 | if (delta_count) | 1768 | if (delta_count) |
1837 | cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); | 1769 | wake_up_interruptible(&info->delta_msr_wait); |
1838 | if (special_count) | 1770 | if (special_count) |
1839 | tty_schedule_flip(tty); | 1771 | tty_schedule_flip(tty); |
1840 | } | 1772 | } |
@@ -2812,7 +2744,6 @@ static void cy_close(struct tty_struct *tty, struct file *filp) | |||
2812 | spin_lock_irqsave(&card->card_lock, flags); | 2744 | spin_lock_irqsave(&card->card_lock, flags); |
2813 | 2745 | ||
2814 | tty->closing = 0; | 2746 | tty->closing = 0; |
2815 | info->event = 0; | ||
2816 | info->tty = NULL; | 2747 | info->tty = NULL; |
2817 | if (info->blocked_open) { | 2748 | if (info->blocked_open) { |
2818 | spin_unlock_irqrestore(&card->card_lock, flags); | 2749 | spin_unlock_irqrestore(&card->card_lock, flags); |
@@ -4444,7 +4375,6 @@ static void cy_hangup(struct tty_struct *tty) | |||
4444 | 4375 | ||
4445 | cy_flush_buffer(tty); | 4376 | cy_flush_buffer(tty); |
4446 | shutdown(info); | 4377 | shutdown(info); |
4447 | info->event = 0; | ||
4448 | info->count = 0; | 4378 | info->count = 0; |
4449 | #ifdef CY_DEBUG_COUNT | 4379 | #ifdef CY_DEBUG_COUNT |
4450 | printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", | 4380 | printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", |
@@ -4502,7 +4432,6 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) | |||
4502 | info->closing_wait = CLOSING_WAIT_DELAY; | 4432 | info->closing_wait = CLOSING_WAIT_DELAY; |
4503 | info->close_delay = 5 * HZ / 10; | 4433 | info->close_delay = 5 * HZ / 10; |
4504 | 4434 | ||
4505 | INIT_WORK(&info->tqueue, do_softint); | ||
4506 | init_waitqueue_head(&info->open_wait); | 4435 | init_waitqueue_head(&info->open_wait); |
4507 | init_waitqueue_head(&info->close_wait); | 4436 | init_waitqueue_head(&info->close_wait); |
4508 | init_completion(&info->shutdown_wait); | 4437 | init_completion(&info->shutdown_wait); |
diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h index 72aa00cc4b2d..06b272590776 100644 --- a/include/linux/cyclades.h +++ b/include/linux/cyclades.h | |||
@@ -569,7 +569,6 @@ struct cyclades_port { | |||
569 | int x_char; /* to be pushed out ASAP */ | 569 | int x_char; /* to be pushed out ASAP */ |
570 | int close_delay; | 570 | int close_delay; |
571 | unsigned short closing_wait; | 571 | unsigned short closing_wait; |
572 | unsigned long event; | ||
573 | int count; /* # of fd on device */ | 572 | int count; /* # of fd on device */ |
574 | int breakon; | 573 | int breakon; |
575 | int breakoff; | 574 | int breakoff; |
@@ -584,7 +583,6 @@ struct cyclades_port { | |||
584 | struct cyclades_monitor mon; | 583 | struct cyclades_monitor mon; |
585 | struct cyclades_idle_stats idle_stats; | 584 | struct cyclades_idle_stats idle_stats; |
586 | struct cyclades_icount icount; | 585 | struct cyclades_icount icount; |
587 | struct work_struct tqueue; | ||
588 | wait_queue_head_t open_wait; | 586 | wait_queue_head_t open_wait; |
589 | wait_queue_head_t close_wait; | 587 | wait_queue_head_t close_wait; |
590 | struct completion shutdown_wait; | 588 | struct completion shutdown_wait; |
@@ -592,19 +590,6 @@ struct cyclades_port { | |||
592 | int throttle; | 590 | int throttle; |
593 | }; | 591 | }; |
594 | 592 | ||
595 | /* | ||
596 | * Events are used to schedule things to happen at timer-interrupt | ||
597 | * time, instead of at cy interrupt time. | ||
598 | */ | ||
599 | #define Cy_EVENT_READ_PROCESS 0 | ||
600 | #define Cy_EVENT_WRITE_WAKEUP 1 | ||
601 | #define Cy_EVENT_HANGUP 2 | ||
602 | #define Cy_EVENT_BREAK 3 | ||
603 | #define Cy_EVENT_OPEN_WAKEUP 4 | ||
604 | #define Cy_EVENT_SHUTDOWN_WAKEUP 5 | ||
605 | #define Cy_EVENT_DELTA_WAKEUP 6 | ||
606 | #define Cy_EVENT_Z_RX_FULL 7 | ||
607 | |||
608 | #define CLOSING_WAIT_DELAY 30*HZ | 593 | #define CLOSING_WAIT_DELAY 30*HZ |
609 | #define CY_CLOSING_WAIT_NONE 65535 | 594 | #define CY_CLOSING_WAIT_NONE 65535 |
610 | #define CY_CLOSING_WAIT_INF 0 | 595 | #define CY_CLOSING_WAIT_INF 0 |