pc_serial: cache IER and temporarily mask IRQs until dpc done

No need to be flooded by IRQs while filling in the FIFO...
This commit is contained in:
François Revol
2014-08-29 15:21:10 +02:00
parent 9ab497059d
commit e9bbba8b84
2 changed files with 22 additions and 4 deletions
@@ -29,6 +29,7 @@ SerialDevice::SerialDevice(const struct serial_support_descriptor *device,
fIOBase(ioBase), fIOBase(ioBase),
fIRQ(irq), fIRQ(irq),
fMaster(master), fMaster(master),
fCachedIER(0x0),
fCachedIIR(0x1), fCachedIIR(0x1),
fPendingDPC(0), fPendingDPC(0),
fReadBufferAvail(0), fReadBufferAvail(0),
@@ -89,6 +90,10 @@ SerialDevice::Init()
fReadBufferSem = create_sem(0, "pc_serial:done_read"); fReadBufferSem = create_sem(0, "pc_serial:done_read");
fWriteBufferSem = create_sem(0, "pc_serial:done_write"); fWriteBufferSem = create_sem(0, "pc_serial:done_write");
// disable IRQ
fCachedIER = 0;
WriteReg8(IER, fCachedIER);
// disable DLAB // disable DLAB
WriteReg8(LCR, 0); WriteReg8(LCR, 0);
@@ -264,7 +269,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length)
// remove the handler // remove the handler
remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this); remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this);
// disable IRQ // disable IRQ
WriteReg8(IER, 0); fCachedIER = 0;
WriteReg8(IER, fCachedIER);
WriteReg8(MCR, 0); WriteReg8(MCR, 0);
} }
@@ -277,7 +283,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length)
// //
WriteReg8(MCR, MCR_DTR | MCR_RTS | MCR_IRQ_EN /*| MCR_LOOP*//*XXXXXXX*/); WriteReg8(MCR, MCR_DTR | MCR_RTS | MCR_IRQ_EN /*| MCR_LOOP*//*XXXXXXX*/);
// enable irqs // enable irqs
WriteReg8(IER, IER_RLS | IER_MS | IER_RDA); fCachedIER = IER_RLS | IER_MS | IER_RDA;
WriteReg8(IER, fCachedIER);
//WriteReg8(IER, IER_RDA); //WriteReg8(IER, IER_RDA);
} }
@@ -330,7 +337,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length)
case TTYOSTART: case TTYOSTART:
TRACE("TTYOSTART\n"); TRACE("TTYOSTART\n");
// enable irqs // enable irqs
WriteReg8(IER, IER_RLS | IER_MS | IER_RDA | IER_THRE); fCachedIER |= IER_THRE;
WriteReg8(IER, fCachedIER);
return true; return true;
case TTYOSYNC: case TTYOSYNC:
TRACE("TTYOSYNC\n"); TRACE("TTYOSYNC\n");
@@ -366,8 +374,14 @@ SerialDevice::IsInterruptPending()
bool pending = (fCachedIIR & IIR_PENDING) == 0; bool pending = (fCachedIIR & IIR_PENDING) == 0;
if (pending) if (pending) {
// temporarily mask the IRQ
// else VirtualBox triggers one per every written byte it seems
// not sure it's required on real hardware
WriteReg8(IER, fCachedIER & ~(IER_RLS | IER_MS | IER_RDA | IER_THRE));
atomic_add(&fPendingDPC, 1); atomic_add(&fPendingDPC, 1);
}
return pending; // 0 means yes return pending; // 0 means yes
} }
@@ -487,6 +501,9 @@ SerialDevice::InterruptHandler()
atomic_add(&fPendingDPC, -1); atomic_add(&fPendingDPC, -1);
// unmask IRQ
WriteReg8(IER, fCachedIER);
TRACE_FUNCRET("< IRQ:%d\n", ret); TRACE_FUNCRET("< IRQ:%d\n", ret);
return ret; return ret;
} }
@@ -116,6 +116,7 @@ static void InterruptCallbackFunction(void *cookie,
//usb_serial_line_coding fLineCoding; //usb_serial_line_coding fLineCoding;
/* deferred interrupt */ /* deferred interrupt */
uint8 fCachedIER; // last value written to IER
uint8 fCachedIIR; // cached IRQ condition uint8 fCachedIIR; // cached IRQ condition
int32 fPendingDPC; // some IRQ still int32 fPendingDPC; // some IRQ still