提交 ebafeeff 编写于 作者: J Jiri Slaby 提交者: Linus Torvalds

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: NJiri Slaby <jirislaby@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Paul Fulghum <paulkf@microgate.com>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 c4342205
...@@ -897,71 +897,6 @@ static inline int serial_paranoia_check(struct cyclades_port *info, ...@@ -897,71 +897,6 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
return 0; return 0;
} /* serial_paranoia_check */ } /* serial_paranoia_check */
/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver
* (also known as the "bottom half"). This can be called any
* number of times for any channel without harm.
*/
static inline void cy_sched_event(struct cyclades_port *info, int event)
{
info->event |= 1 << event; /* remember what kind of event and who */
schedule_work(&info->tqueue);
} /* cy_sched_event */
/*
* This routine is used to handle the "bottom half" processing for the
* serial driver, known also the "software interrupt" processing.
* This processing is done at the kernel interrupt level, after the
* cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
* is where time-consuming activities which can not be done in the
* interrupt driver proper are done; the interrupt driver schedules
* them using cy_sched_event(), and they get done here.
*
* This is done through one level of indirection--the task queue.
* When a hardware interrupt service routine wants service by the
* driver's bottom half, it enqueues the appropriate tq_struct (one
* per port) to the keventd work queue and sets a request flag
* that the work queue be processed.
*
* Although this may seem unwieldy, it gives the system a way to
* pass an argument (in this case the pointer to the cyclades_port
* structure) to the bottom half of the driver. Previous kernels
* had to poll every port to see if that port needed servicing.
*/
static void
do_softint(struct work_struct *work)
{
struct cyclades_port *info =
container_of(work, struct cyclades_port, tqueue);
struct tty_struct *tty;
tty = info->tty;
if (!tty)
return;
if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
tty_hangup(info->tty);
wake_up_interruptible(&info->open_wait);
info->flags &= ~ASYNC_NORMAL_ACTIVE;
}
if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
wake_up_interruptible(&info->open_wait);
#ifdef CONFIG_CYZ_INTR
if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) &&
!timer_pending(&cyz_rx_full_timer[info->line]))
mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1);
#endif
if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
wake_up_interruptible(&info->delta_msr_wait);
tty_wakeup(tty);
#ifdef Z_WAKE
if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
complete(&info->shutdown_wait);
#endif
} /* do_softint */
/***********************************************************/ /***********************************************************/
/********* Start of block of Cyclom-Y specific code ********/ /********* Start of block of Cyclom-Y specific code ********/
...@@ -1243,7 +1178,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, ...@@ -1243,7 +1178,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
cy_writeb(base_addr + (CySRER << index), cy_writeb(base_addr + (CySRER << index),
readb(base_addr + (CySRER << index)) & readb(base_addr + (CySRER << index)) &
~CyTxRdy); ~CyTxRdy);
goto txdone; goto txend;
} }
/* load the on-chip space for outbound data */ /* load the on-chip space for outbound data */
...@@ -1334,9 +1269,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, ...@@ -1334,9 +1269,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
} }
txdone: txdone:
if (info->xmit_cnt < WAKEUP_CHARS) { tty_wakeup(info->tty);
cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
}
txend: txend:
/* end of service */ /* end of service */
cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f)); cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f));
...@@ -1369,17 +1302,16 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, ...@@ -1369,17 +1302,16 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
if (mdm_change & CyRI) if (mdm_change & CyRI)
info->icount.rng++; info->icount.rng++;
cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); wake_up_interruptible(&info->delta_msr_wait);
} }
if ((mdm_change & CyDCD) && if ((mdm_change & CyDCD) &&
(info->flags & ASYNC_CHECK_CD)) { (info->flags & ASYNC_CHECK_CD)) {
if (mdm_status & CyDCD) { if (!(mdm_status & CyDCD)) {
cy_sched_event(info, tty_hangup(info->tty);
Cy_EVENT_OPEN_WAKEUP); info->flags &= ~ASYNC_NORMAL_ACTIVE;
} else {
cy_sched_event(info, Cy_EVENT_HANGUP);
} }
wake_up_interruptible(&info->open_wait);
} }
if ((mdm_change & CyCTS) && if ((mdm_change & CyCTS) &&
(info->flags & ASYNC_CTS_FLOW)) { (info->flags & ASYNC_CTS_FLOW)) {
...@@ -1394,8 +1326,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, ...@@ -1394,8 +1326,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
(CySRER << (CySRER <<
index))| index))|
CyTxRdy); CyTxRdy);
cy_sched_event(info, tty_wakeup(info->tty);
Cy_EVENT_WRITE_WAKEUP);
} }
} else { } else {
if (!(mdm_status & CyCTS)) { if (!(mdm_status & CyCTS)) {
...@@ -1633,9 +1564,11 @@ cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl, ...@@ -1633,9 +1564,11 @@ cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
char_count = rx_put - rx_get; char_count = rx_put - rx_get;
else else
char_count = rx_put - rx_get + rx_bufsize; char_count = rx_put - rx_get + rx_bufsize;
if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) { if (char_count >= (int)readl(&buf_ctrl->rx_threshold) &&
cy_sched_event(info, Cy_EVENT_Z_RX_FULL); !timer_pending(&cyz_rx_full_timer[
} info->line]))
mod_timer(&cyz_rx_full_timer[info->line],
jiffies + 1);
#endif #endif
info->idle_stats.recv_idle = jiffies; info->idle_stats.recv_idle = jiffies;
tty_schedule_flip(tty); tty_schedule_flip(tty);
...@@ -1717,9 +1650,7 @@ cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl, ...@@ -1717,9 +1650,7 @@ cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
} }
#endif #endif
ztxdone: ztxdone:
if (info->xmit_cnt < WAKEUP_CHARS) { tty_wakeup(tty);
cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
}
/* Update tx_put */ /* Update tx_put */
cy_writel(&buf_ctrl->tx_put, tx_put); cy_writel(&buf_ctrl->tx_put, tx_put);
} }
...@@ -1781,10 +1712,11 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) ...@@ -1781,10 +1712,11 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
if ((fw_ver > 241 ? ((u_long) param) : if ((fw_ver > 241 ? ((u_long) param) :
readl(&ch_ctrl->rs_status)) & readl(&ch_ctrl->rs_status)) &
C_RS_DCD) { C_RS_DCD) {
cy_sched_event(info, wake_up_interruptible(&info->open_wait);
Cy_EVENT_OPEN_WAKEUP);
} else { } else {
cy_sched_event(info, Cy_EVENT_HANGUP); tty_hangup(info->tty);
wake_up_interruptible(&info->open_wait);
info->flags &= ~ASYNC_NORMAL_ACTIVE;
} }
} }
break; break;
...@@ -1802,7 +1734,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) ...@@ -1802,7 +1734,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
break; break;
#ifdef Z_WAKE #ifdef Z_WAKE
case C_CM_IOCTLW: case C_CM_IOCTLW:
cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP); complete(&info->shutdown_wait);
break; break;
#endif #endif
#ifdef CONFIG_CYZ_INTR #ifdef CONFIG_CYZ_INTR
...@@ -1834,7 +1766,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) ...@@ -1834,7 +1766,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
break; break;
} }
if (delta_count) if (delta_count)
cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); wake_up_interruptible(&info->delta_msr_wait);
if (special_count) if (special_count)
tty_schedule_flip(tty); tty_schedule_flip(tty);
} }
...@@ -2812,7 +2744,6 @@ static void cy_close(struct tty_struct *tty, struct file *filp) ...@@ -2812,7 +2744,6 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&card->card_lock, flags); spin_lock_irqsave(&card->card_lock, flags);
tty->closing = 0; tty->closing = 0;
info->event = 0;
info->tty = NULL; info->tty = NULL;
if (info->blocked_open) { if (info->blocked_open) {
spin_unlock_irqrestore(&card->card_lock, flags); spin_unlock_irqrestore(&card->card_lock, flags);
...@@ -4444,7 +4375,6 @@ static void cy_hangup(struct tty_struct *tty) ...@@ -4444,7 +4375,6 @@ static void cy_hangup(struct tty_struct *tty)
cy_flush_buffer(tty); cy_flush_buffer(tty);
shutdown(info); shutdown(info);
info->event = 0;
info->count = 0; info->count = 0;
#ifdef CY_DEBUG_COUNT #ifdef CY_DEBUG_COUNT
printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", 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,7 +4432,6 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
info->closing_wait = CLOSING_WAIT_DELAY; info->closing_wait = CLOSING_WAIT_DELAY;
info->close_delay = 5 * HZ / 10; info->close_delay = 5 * HZ / 10;
INIT_WORK(&info->tqueue, do_softint);
init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->close_wait);
init_completion(&info->shutdown_wait); init_completion(&info->shutdown_wait);
......
...@@ -569,7 +569,6 @@ struct cyclades_port { ...@@ -569,7 +569,6 @@ struct cyclades_port {
int x_char; /* to be pushed out ASAP */ int x_char; /* to be pushed out ASAP */
int close_delay; int close_delay;
unsigned short closing_wait; unsigned short closing_wait;
unsigned long event;
int count; /* # of fd on device */ int count; /* # of fd on device */
int breakon; int breakon;
int breakoff; int breakoff;
...@@ -584,7 +583,6 @@ struct cyclades_port { ...@@ -584,7 +583,6 @@ struct cyclades_port {
struct cyclades_monitor mon; struct cyclades_monitor mon;
struct cyclades_idle_stats idle_stats; struct cyclades_idle_stats idle_stats;
struct cyclades_icount icount; struct cyclades_icount icount;
struct work_struct tqueue;
wait_queue_head_t open_wait; wait_queue_head_t open_wait;
wait_queue_head_t close_wait; wait_queue_head_t close_wait;
struct completion shutdown_wait; struct completion shutdown_wait;
...@@ -592,19 +590,6 @@ struct cyclades_port { ...@@ -592,19 +590,6 @@ struct cyclades_port {
int throttle; int throttle;
}; };
/*
* Events are used to schedule things to happen at timer-interrupt
* time, instead of at cy interrupt time.
*/
#define Cy_EVENT_READ_PROCESS 0
#define Cy_EVENT_WRITE_WAKEUP 1
#define Cy_EVENT_HANGUP 2
#define Cy_EVENT_BREAK 3
#define Cy_EVENT_OPEN_WAKEUP 4
#define Cy_EVENT_SHUTDOWN_WAKEUP 5
#define Cy_EVENT_DELTA_WAKEUP 6
#define Cy_EVENT_Z_RX_FULL 7
#define CLOSING_WAIT_DELAY 30*HZ #define CLOSING_WAIT_DELAY 30*HZ
#define CY_CLOSING_WAIT_NONE 65535 #define CY_CLOSING_WAIT_NONE 65535
#define CY_CLOSING_WAIT_INF 0 #define CY_CLOSING_WAIT_INF 0
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册