From e9bbba8b847ca4ca5d13493a08dad81c33b9d443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Fri, 29 Aug 2014 13:37:31 +0200 Subject: [PATCH] pc_serial: cache IER and temporarily mask IRQs until dpc done No need to be flooded by IRQs while filling in the FIFO... --- .../drivers/ports/pc_serial/SerialDevice.cpp | 25 ++++++++++++++++--- .../drivers/ports/pc_serial/SerialDevice.h | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp index 37e558af8a..5082d1bd29 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp @@ -29,6 +29,7 @@ SerialDevice::SerialDevice(const struct serial_support_descriptor *device, fIOBase(ioBase), fIRQ(irq), fMaster(master), + fCachedIER(0x0), fCachedIIR(0x1), fPendingDPC(0), fReadBufferAvail(0), @@ -89,6 +90,10 @@ SerialDevice::Init() fReadBufferSem = create_sem(0, "pc_serial:done_read"); fWriteBufferSem = create_sem(0, "pc_serial:done_write"); + // disable IRQ + fCachedIER = 0; + WriteReg8(IER, fCachedIER); + // disable DLAB WriteReg8(LCR, 0); @@ -264,7 +269,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) // remove the handler remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this); // disable IRQ - WriteReg8(IER, 0); + fCachedIER = 0; + WriteReg8(IER, fCachedIER); 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*/); // enable irqs - WriteReg8(IER, IER_RLS | IER_MS | IER_RDA); + fCachedIER = IER_RLS | IER_MS | IER_RDA; + WriteReg8(IER, fCachedIER); //WriteReg8(IER, IER_RDA); } @@ -330,7 +337,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) case TTYOSTART: TRACE("TTYOSTART\n"); // enable irqs - WriteReg8(IER, IER_RLS | IER_MS | IER_RDA | IER_THRE); + fCachedIER |= IER_THRE; + WriteReg8(IER, fCachedIER); return true; case TTYOSYNC: TRACE("TTYOSYNC\n"); @@ -366,8 +374,14 @@ SerialDevice::IsInterruptPending() 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); + } return pending; // 0 means yes } @@ -487,6 +501,9 @@ SerialDevice::InterruptHandler() atomic_add(&fPendingDPC, -1); + // unmask IRQ + WriteReg8(IER, fCachedIER); + TRACE_FUNCRET("< IRQ:%d\n", ret); return ret; } diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h index 38fca92708..3f9daf8685 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h @@ -116,6 +116,7 @@ static void InterruptCallbackFunction(void *cookie, //usb_serial_line_coding fLineCoding; /* deferred interrupt */ + uint8 fCachedIER; // last value written to IER uint8 fCachedIIR; // cached IRQ condition int32 fPendingDPC; // some IRQ still