Skip to content

Commit

Permalink
thor: Implement interrupt NAK mechanism
Browse files Browse the repository at this point in the history
Fixes #7.
  • Loading branch information
avdgrinten committed May 24, 2018
1 parent 3d63f56 commit 35484fe
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 124 deletions.
6 changes: 4 additions & 2 deletions drivers/block/ata/src/main.cpp
Expand Up @@ -121,15 +121,17 @@ COFIBER_ROUTINE(cofiber::no_future, Controller::_handleIrqs(), ([=] {

// Check if the device is ready without clearing the IRQ.
auto status = _altSpace.load(alt_regs::inStatus);
if(status & kStatusBsy)
if(status & kStatusBsy) {
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), kHelAckNack, sequence));
continue;
}
assert(!(status & (kStatusErr | kStatusDf)));
assert(status & kStatusRdy);
assert(status & kStatusDrq);

// Clear and acknowledge the IRQ.
auto cleared = _ioSpace.load(regs::inStatus);
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), 0, 0));
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), kHelAckAcknowledge, 0));
assert(!(cleared & (kStatusErr | kStatusDf)));
assert(cleared & kStatusRdy);
assert(cleared & kStatusDrq);
Expand Down
12 changes: 9 additions & 3 deletions drivers/kbd/src/main.cpp
Expand Up @@ -275,7 +275,8 @@ void sendByte(uint8_t data) {
base.store(kbd_register::data, data);
}

void readDeviceData() {
bool readDeviceData() {
bool avail = false;
size_t batch = 1;
uint8_t status;
while((status = base.load(kbd_register::command)) & 0x01) {
Expand All @@ -289,7 +290,11 @@ void readDeviceData() {
}else{
handleKeyboardData(data);
}

avail = true;
}

return avail;
}

COFIBER_ROUTINE(cofiber::no_future, handleKbdIrqs(), ([=] {
Expand All @@ -306,7 +311,8 @@ COFIBER_ROUTINE(cofiber::no_future, handleKbdIrqs(), ([=] {
readDeviceData();

// TODO: Only ack if the IRQ was from the PS/2 controller.
HEL_CHECK(helAcknowledgeIrq(kbdIrq.getHandle(), 0, sequence));
//HEL_CHECK(helAcknowledgeIrq(kbdIrq.getHandle(), kHelAckAcknowledge, 0));
HEL_CHECK(helAcknowledgeIrq(mouseIrq.getHandle(), kHelAckNack, sequence));
}
}))

Expand All @@ -324,7 +330,7 @@ COFIBER_ROUTINE(cofiber::no_future, handleMouseIrqs(), ([=] {
readDeviceData();

// TODO: Only ack if the IRQ was from the PS/2 controller.
HEL_CHECK(helAcknowledgeIrq(mouseIrq.getHandle(), 0, sequence));
HEL_CHECK(helAcknowledgeIrq(mouseIrq.getHandle(), kHelAckAcknowledge, 0));
}
}))

Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/hcds/ehci/src/main.cpp
Expand Up @@ -400,6 +400,7 @@ COFIBER_ROUTINE(cofiber::no_future, Controller::handleIrqs(), ([=] {
&& !(status & usbsts::portChange)) {
if(logIrqs)
std::cout << "ehci: IRQ is not from this controller" << std::endl;
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), kHelAckNack, sequence));
continue;
}

Expand All @@ -409,7 +410,7 @@ COFIBER_ROUTINE(cofiber::no_future, Controller::handleIrqs(), ([=] {
usbsts::transactionIrq(status & usbsts::transactionIrq)
| usbsts::errorIrq(status & usbsts::errorIrq)
| usbsts::portChange(status & usbsts::portChange));
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), 0, 0));
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), kHelAckAcknowledge, 0));

if((status & usbsts::transactionIrq)
|| (status & usbsts::errorIrq)) {
Expand Down
6 changes: 4 additions & 2 deletions drivers/usb/hcds/uhci/src/main.cpp
Expand Up @@ -465,14 +465,16 @@ COFIBER_ROUTINE(cofiber::no_future, Controller::_handleIrqs(), ([=] {
auto stat = _base.load(op_regs::status);
assert(!(stat & status::hostProcessError));
assert(!(stat & status::hostSystemError));
if(!(stat & status::transactionIrq) && !(stat & status::errorIrq))
if(!(stat & status::transactionIrq) && !(stat & status::errorIrq)) {
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), kHelAckNack, sequence));
continue;
}

if(stat & status::errorIrq)
printf("uhci: Error interrupt\n");
_base.store(op_regs::status, status::transactionIrq(stat & status::transactionIrq)
| status::errorIrq(stat & status::errorIrq));
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), 0, sequence));
HEL_CHECK(helAcknowledgeIrq(_irq.getHandle(), kHelAckAcknowledge, 0));

//printf("uhci: Processing transfers.\n");
_progressSchedule();
Expand Down
2 changes: 2 additions & 0 deletions hel/include/hel.h
Expand Up @@ -343,6 +343,8 @@ enum HelIrqFlags {
};

enum HelAckFlags {
kHelAckAcknowledge = 2,
kHelAckNack = 3,
kHelAckKick = 1
};

Expand Down
11 changes: 6 additions & 5 deletions thor/kernel/src/arch/x86/hpet.cpp
Expand Up @@ -67,6 +67,9 @@ struct HpetDevice : IrqSink {
static constexpr bool logIrqs = false;

public:
HpetDevice()
: IrqSink{frigg::String<KernelAlloc>{*kernelAlloc, "hpet-irq"}} { }

void installTimer(PrecisionTimerNode *timer) {
auto irq_lock = frigg::guard(&irqMutex());
auto lock = frigg::guard(&_mutex);
Expand All @@ -83,9 +86,7 @@ struct HpetDevice : IrqSink {
_progress();
}

IrqStatus raise(uint64_t sequence) override {
(void)sequence;

IrqStatus raise() override {
if(logIrqs)
frigg::infoLogger() << "hpet: Irq was raised." << frigg::endLog;
auto irq_lock = frigg::guard(&irqMutex());
Expand All @@ -97,7 +98,7 @@ struct HpetDevice : IrqSink {
// For level-triggered mode we need to inspect the ISR.
if(logIrqs)
frigg::infoLogger() << "hpet: Handler completed." << frigg::endLog;
return irq_status::handled;
return IrqStatus::acked;
}

private:
Expand Down Expand Up @@ -191,7 +192,7 @@ void setupHpet(PhysicalAddr address) {
hpetBase.store(genConfig, enableCounter(true));
}

attachIrq(getGlobalSystemIrq(2), hpetDevice.get());
IrqPin::attachSink(getGlobalSystemIrq(2), hpetDevice.get());

// Program HPET timer 0 in one-shot mode.
if(global_caps & supportsLegacyIrqs) {
Expand Down
27 changes: 20 additions & 7 deletions thor/kernel/src/generic/hel.cpp
Expand Up @@ -1761,8 +1761,9 @@ HelError helAccessIrq(int number, HelHandle *handle) {
auto this_thread = getCurrentThread();
auto this_universe = this_thread->getUniverse();

auto irq = frigg::makeShared<IrqObject>(*kernelAlloc);
attachIrq(getGlobalSystemIrq(number), irq.get());
auto irq = frigg::makeShared<IrqObject>(*kernelAlloc,
frigg::String<KernelAlloc>{*kernelAlloc, "generic-irq-object"});
IrqPin::attachSink(getGlobalSystemIrq(number), irq.get());

{
auto irq_lock = frigg::guard(&irqMutex());
Expand All @@ -1775,11 +1776,21 @@ HelError helAccessIrq(int number, HelHandle *handle) {
return kHelErrNone;
}
HelError helAcknowledgeIrq(HelHandle handle, uint32_t flags, uint64_t sequence) {
assert(!(flags & ~(kHelAckKick)));
assert(!(flags & ~(kHelAckAcknowledge | kHelAckNack | kHelAckKick)));

auto this_thread = getCurrentThread();
auto this_universe = this_thread->getUniverse();

auto mode = flags & (kHelAckAcknowledge | kHelAckNack | kHelAckKick);
if(mode == kHelAckAcknowledge || mode == kHelAckKick) {
if(sequence)
return kHelErrIllegalArgs;
}else if(mode == kHelAckNack) {
// Nothing to check here.
}else{
return kHelErrIllegalArgs;
}

frigg::SharedPtr<IrqObject> irq;
{
auto irq_lock = frigg::guard(&irqMutex());
Expand All @@ -1793,11 +1804,13 @@ HelError helAcknowledgeIrq(HelHandle handle, uint32_t flags, uint64_t sequence)
irq = irq_wrapper->get<IrqDescriptor>().irq;
}

if(flags & kHelAckKick) {
irq->acknowledge();
if(mode == kHelAckAcknowledge) {
IrqPin::ackSink(irq.get());
}else if(mode == kHelAckNack) {
IrqPin::nackSink(irq.get(), sequence);
}else{
assert(!flags);
irq->acknowledge();
assert(mode == kHelAckKick);
IrqPin::kickSink(irq.get());
}

return kHelErrNone;
Expand Down

0 comments on commit 35484fe

Please sign in to comment.