aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Slaby <jirislaby@gmail.com>2007-10-18 06:06:20 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:26 -0400
commitebafeeff0fea029099e9952f233e0794106897a6 (patch)
tree50bc3ca7f9d4c7153c3e98bda28199dcc6eff948
parentc43422053bea7a5ce09f18d0c50a606fe1a549f4 (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.c111
-rw-r--r--include/linux/cyclades.h15
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 */
906static 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 */
932static void
933do_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
1336txdone: 1271txdone:
1337 if (info->xmit_cnt < WAKEUP_CHARS) { 1272 tty_wakeup(info->tty);
1338 cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
1339 }
1340txend: 1273txend:
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
1719ztxdone: 1652ztxdone:
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