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>
This commit is contained in:
committed by
Linus Torvalds
parent
c43422053b
commit
ebafeeff0f
@@ -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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 @@ txend:
|
|||||||
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 @@ txend:
|
|||||||
(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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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
|
||||||
|
Reference in New Issue
Block a user