From b3bc1c44d7da60e56366e35e40d31a3742be0f06 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 11:11:20 -0800 Subject: [PATCH] [Denali] Refactore interrupt handling. --- sys/denali/ahci/ahci.h | 12 +++++ sys/denali/ahci/ahci_controller.cpp | 7 ++- sys/denali/ahci/ahci_device.cpp | 78 ++++++++++++++++++++--------- 3 files changed, 70 insertions(+), 27 deletions(-) diff --git a/sys/denali/ahci/ahci.h b/sys/denali/ahci/ahci.h index 9b71c45..320b5fd 100644 --- a/sys/denali/ahci/ahci.h +++ b/sys/denali/ahci/ahci.h @@ -58,6 +58,12 @@ struct AhciHba { const uint32_t kCommand_FIS_Receive_Enable = (1 << 4); const uint32_t kCommand_Start = 1; +const uint32_t kInterrupt_D2H_FIS = 1; +const uint32_t kInterrupt_PIO_FIS = (1 << 1); +const uint32_t kInterrupt_DMA_FIS = (1 << 2); +const uint32_t kInterrupt_DeviceBits_FIS = (1 << 3); +const uint32_t kInterrupt_Unknown_FIS = (1 << 4); + struct AhciPort { uint64_t command_list_base; uint64_t fis_base; @@ -237,7 +243,13 @@ struct DeviceToHostRegisterFis { uint32_t reserved3; } __attribute__((packed)); + struct SetDeviceBitsFis { + uint8_t fis_type; + uint8_t pmport_and_i; + uint8_t status; + uint8_t error; + uint32_t reserved; } __attribute__((packed)); struct ReceivedFis { diff --git a/sys/denali/ahci/ahci_controller.cpp b/sys/denali/ahci/ahci_controller.cpp index d4f2968..1ee5712 100644 --- a/sys/denali/ahci/ahci_controller.cpp +++ b/sys/denali/ahci/ahci_controller.cpp @@ -34,7 +34,7 @@ glcr::ErrorOr> AhciController::Init( } glcr::ErrorOr AhciController::GetDevice(uint64_t id) { - if (id >= 32) { + if (id >= num_ports_) { return glcr::INVALID_ARGUMENT; } @@ -140,9 +140,8 @@ void AhciController::InterruptLoop() { while (true) { uint64_t bytes, caps; check(ZPortRecv(irq_port_cap_, &bytes, nullptr, &caps, nullptr)); - for (uint64_t i = 0; i < 32; i++) { - if (!devices_[i].empty() && devices_[i]->IsInit() && - (ahci_hba_->interrupt_status & (1 << i))) { + for (uint64_t i = 0; i < num_ports_; i++) { + if (!devices_[i].empty() && (ahci_hba_->interrupt_status & (1 << i))) { devices_[i]->HandleIrq(); ahci_hba_->interrupt_status &= ~(1 << i); } diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_device.cpp index c12aa2b..40513ff 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_device.cpp @@ -34,7 +34,9 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { (paddr + 0x500) + (0x100 * i); commands_[i] = nullptr; } - port_struct_->interrupt_enable = 0xFFFFFFFF; + port_struct_->interrupt_enable = + kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS | + kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS; port_struct_->sata_error = -1; port_struct_->command |= kCommand_Start; } @@ -77,48 +79,78 @@ void AhciDevice::DumpInfo() { dbgln("Int enable: {x}", port_struct_->interrupt_enable); } +bool CheckFisType(FIS_TYPE expected, uint8_t actual) { + if (expected == actual) { + return true; + } + dbgln("BAD FIS TYPE (exp,act): {x}, {x}", static_cast(expected), + static_cast(actual)); + return false; +} + void AhciDevice::HandleIrq() { uint32_t int_status = port_struct_->interrupt_status; - // FIXME: Probably only clear the interrupts we know how to handle. port_struct_->interrupt_status = int_status; - uint32_t commands_finished = commands_issued_ & ~port_struct_->command_issue; - - // FIXME: Pass error codes to the callback. - for (uint64_t i = 0; i < 32; i++) { - if (commands_finished & (1 << i)) { - commands_issued_ &= ~(1 << i); - commands_[i]->SignalComplete(); - } - } - - // TODO: Do something with this information. - if (int_status & 0x1) { + bool has_error = false; + if (int_status & kInterrupt_D2H_FIS) { + dbgln("D2H Received"); // Device to host. volatile DeviceToHostRegisterFis& fis = received_fis_->device_to_host_register_fis; - if (fis.fis_type != FIS_TYPE_REG_D2H) { - dbgln("BAD FIS TYPE (exp,act): {x}, {x}", - static_cast(FIS_TYPE_REG_D2H), - static_cast(fis.fis_type)); + if (!CheckFisType(FIS_TYPE_REG_D2H, fis.fis_type)) { return; } if (fis.error) { dbgln("D2H err: {x}", fis.error); dbgln("status: {x}", fis.status); + has_error = true; } } - if (int_status & 0x2) { + if (int_status & kInterrupt_PIO_FIS) { + dbgln("PIO Received"); // PIO. volatile PioSetupFis& fis = received_fis_->pio_set_fis; - if (fis.fis_type != FIS_TYPE_PIO_SETUP) { - dbgln("BAD FIS TYPE (exp,act): {x}, {x}", - static_cast(FIS_TYPE_PIO_SETUP), - static_cast(fis.fis_type)); + if (!CheckFisType(FIS_TYPE_PIO_SETUP, fis.fis_type)) { return; } if (fis.error) { dbgln("PIO err: {x}", fis.error); + dbgln("status: {x}", fis.status); + has_error = true; + } + } + if (int_status & kInterrupt_DMA_FIS) { + dbgln("DMA Received"); + volatile DmaFis& fis = received_fis_->dma_fis; + if (!CheckFisType(FIS_TYPE_DMA_SETUP, fis.fis_type)) { + return; + } + // TODO: Actually do something with this FIS. + } + if (int_status & kInterrupt_DeviceBits_FIS) { + dbgln("Device Bits Received"); + volatile SetDeviceBitsFis& fis = received_fis_->set_device_bits_fis; + if (!CheckFisType(FIS_TYPE_DEV_BITS, fis.fis_type)) { + return; + } + if (fis.error) { + dbgln("SetDeviceBits err: {x}", fis.error); + dbgln("status: {x}", fis.status); + has_error = true; + } + } + if (int_status & kInterrupt_Unknown_FIS) { + dbgln("Unknown FIS recieved, type: {x}", received_fis_->unknown_fis[0]); + } + uint32_t commands_finished = commands_issued_ & ~port_struct_->command_issue; + + for (uint64_t i = 0; i < 32; i++) { + if (commands_finished & (1 << i)) { + commands_issued_ &= ~(1 << i); + // FIXME: Pass error codes to the callback. + commands_[i]->SignalComplete(); + commands_[i] = nullptr; } } }