From: Jesper S. <js...@re...> - 2000-08-04 09:49:15
|
I tried using the SCI controller for a PPP connection, but it would freeze after a few seconds. The reason is that the PPP driver is called from within the interrupt handler, circumventing the bottom_handler locking which the PPP driver relies on. The fix is to call the PPP driver from a softirq like it's done in serial.c. I've spoken with Rogier Wolff who wrote the SX driver which the SCI driver is based on, and they do not have this problem, for the simple reason that the SX controller will not interrupt until after a 10ms delay - which gives the driver time enough to unwind to a safe state. With the below I can mount NFS over the serial line via PPP. Jesper [note, patch is reversed! Sorry!] diff -urN --exclude-from=/home/jskov/lib/diff-excludes -P ../../devo/linux/linux-sh/drivers/char/sh-sci.c ./drivers/char/sh-sci.c --- ../../devo/linux/linux-sh/drivers/char/sh-sci.c Thu Aug 3 15:20:12 2000 +++ ./drivers/char/sh-sci.c Thu Aug 3 14:36:27 2000 @@ -83,8 +83,6 @@ static struct termios *sci_termios[SCI_NPORTS]; static struct termios *sci_termios_locked[SCI_NPORTS]; -static DECLARE_TASK_QUEUE(tq_serial); - int sci_refcount; int sci_debug = 0; @@ -416,19 +414,6 @@ * the interrupt related routines * * ********************************************************************** */ -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static inline void rs_sched_event(struct sci_port *port, - int event) -{ - port->event |= 1 << event; - queue_task(&port->tqueue, &tq_serial); - mark_bh(SERIAL_BH); -} - - static void sci_transmit_chars(struct sci_port *port) { int count, i; @@ -486,8 +471,12 @@ port->gs.xmit_cnt -= count; } - if (port->gs.xmit_cnt <= port->gs.wakeup_chars) - rs_sched_event(port, RS_EVENT_WRITE_WAKEUP); + if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { + if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + port->gs.tty->ldisc.write_wakeup) + (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + wake_up_interruptible(&port->gs.tty->write_wait); + } save_and_cli(flags); ctrl = sci_in(port, SCSCR); @@ -588,37 +577,6 @@ sci_tx_interrupt(irq, ptr, regs); } -/* - * 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 - * rs_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 rs_sched_event(), and they get done here. - */ -static void do_serial_bh(void) -{ - run_task_queue(&tq_serial); -} - -static void do_softint(void *private_) -{ - struct sci_port *port = (struct sci_port *) private_; - struct tty_struct *tty; - - tty = port->gs.tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } -} - /* ********************************************************************** * * Here are the routines that actually * * interface with the generic_serial driver * @@ -722,10 +680,6 @@ port->gs.tty = tty; port->gs.count++; - port->event = 0; - port->tqueue.routine = do_softint; - port->tqueue.data = port; - /* * Start up serial port */ @@ -1007,7 +961,6 @@ printk("SuperH SCI(F) driver initialized\n"); - init_bh(SERIAL_BH, do_serial_bh); for (j=0; j<SCI_NPORTS; j++) { port = &sci_ports[j]; printk("ttySC%d at 0x%08x is a %s\n", j, port->base, @@ -1043,7 +996,6 @@ for (i=SCI_ERI_IRQ; i<SCI_TEI_IRQ; i++) /* XXX: irq_end?? */ free_irq(i, port); - remove_bh(SERIAL_BH); tty_unregister_driver(&sci_driver); tty_unregister_driver(&sci_callout_driver); } diff -urN --exclude-from=/home/jskov/lib/diff-excludes -P ../../devo/linux/linux-sh/drivers/char/sh-sci.h ./drivers/char/sh-sci.h --- ../../devo/linux/linux-sh/drivers/char/sh-sci.h Thu Aug 3 15:21:49 2000 +++ ./drivers/char/sh-sci.h Thu Aug 3 14:36:27 2000 @@ -159,12 +159,6 @@ #define SCI_MAGIC 0xbabeface -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - struct sci_port { struct gs_port gs; int type; @@ -173,8 +167,6 @@ void (*init_pins)(struct sci_port* port, unsigned int cflag); unsigned int old_cflag; struct async_icount icount; - struct tq_struct tqueue; - unsigned long event; }; #define SCI_IN(size, offset) \ |