[Denali] Reset AHCI controller when starting denali.
This commit is contained in:
parent
8adde27d9b
commit
c530921bda
8 changed files with 92 additions and 62 deletions
|
|
@ -1,229 +0,0 @@
|
|||
#include "ahci/ahci_driver.h"
|
||||
|
||||
#include <glacier/status/error.h>
|
||||
#include <glacier/status/error_or.h>
|
||||
#include <mammoth/util/debug.h>
|
||||
#include <stdint.h>
|
||||
#include <zcall.h>
|
||||
|
||||
namespace {
|
||||
|
||||
const uint64_t kGhc_InteruptEnable = 0x2;
|
||||
|
||||
void interrupt_thread(void* void_driver) {
|
||||
AhciDriver* driver = static_cast<AhciDriver*>(void_driver);
|
||||
|
||||
driver->InterruptLoop();
|
||||
|
||||
crash("Driver returned from interrupt loop", glcr::INTERNAL);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
glcr::ErrorOr<glcr::UniquePtr<AhciDriver>> AhciDriver::Init(
|
||||
mmth::OwnedMemoryRegion&& pci_region) {
|
||||
glcr::UniquePtr<AhciDriver> driver(new AhciDriver(glcr::Move(pci_region)));
|
||||
// RET_ERR(driver->LoadCapabilities());
|
||||
RET_ERR(driver->LoadHbaRegisters());
|
||||
RET_ERR(driver->LoadDevices());
|
||||
RET_ERR(driver->RegisterIrq());
|
||||
// driver->DumpCapabilities();
|
||||
// driver->DumpPorts();
|
||||
return driver;
|
||||
}
|
||||
|
||||
glcr::ErrorOr<AhciDevice*> AhciDriver::GetDevice(uint64_t id) {
|
||||
if (id >= 32) {
|
||||
return glcr::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (devices_[id] != nullptr && !devices_[id]->IsInit()) {
|
||||
return glcr::NOT_FOUND;
|
||||
}
|
||||
|
||||
return devices_[id];
|
||||
}
|
||||
|
||||
void AhciDriver::DumpCapabilities() {
|
||||
dbgln("AHCI Capabilities:");
|
||||
uint32_t caps = ahci_hba_->capabilities;
|
||||
|
||||
if (caps & 0x20) {
|
||||
dbgln("External SATA");
|
||||
}
|
||||
if (caps & 0x40) {
|
||||
dbgln("Enclosure Management");
|
||||
}
|
||||
if (caps & 0x80) {
|
||||
dbgln("Command Completion Coalescing");
|
||||
}
|
||||
if (caps & 0x2000) {
|
||||
dbgln("Partial State Capable");
|
||||
}
|
||||
if (caps & 0x4000) {
|
||||
dbgln("Slumber state capable");
|
||||
}
|
||||
if (caps & 0x8000) {
|
||||
dbgln("PIO Multiple DRQ Block");
|
||||
}
|
||||
if (caps & 0x1'0000) {
|
||||
dbgln("FIS-Based Switching");
|
||||
}
|
||||
if (caps & 0x2'0000) {
|
||||
dbgln("Port Multiplier");
|
||||
}
|
||||
if (caps & 0x4'0000) {
|
||||
dbgln("AHCI mode only");
|
||||
}
|
||||
dbgln("Speed support: {}", (caps & 0xF0'0000) >> 20);
|
||||
if (caps & 0x100'0000) {
|
||||
dbgln("Command list override");
|
||||
}
|
||||
if (caps & 0x200'0000) {
|
||||
dbgln("Activity LED");
|
||||
}
|
||||
if (caps & 0x400'0000) {
|
||||
dbgln("Aggresive link power management");
|
||||
}
|
||||
if (caps & 0x800'0000) {
|
||||
dbgln("Staggered spin up");
|
||||
}
|
||||
if (caps & 0x1000'0000) {
|
||||
dbgln("Mechanical Switch Presence");
|
||||
}
|
||||
if (caps & 0x2000'0000) {
|
||||
dbgln("SNotification Register");
|
||||
}
|
||||
if (caps & 0x4000'0000) {
|
||||
dbgln("Native Command Queueing");
|
||||
}
|
||||
if (caps & 0x8000'0000) {
|
||||
dbgln("64bit Addressing");
|
||||
}
|
||||
|
||||
// Secondary.
|
||||
caps = ahci_hba_->capabilities_ext;
|
||||
if (caps & 0x1) {
|
||||
dbgln("BIOS/OS handoff");
|
||||
}
|
||||
if (caps & 0x2) {
|
||||
dbgln("NVMHCI Present");
|
||||
}
|
||||
if (caps & 0x4) {
|
||||
dbgln("Auto partial to slumber tranisitions");
|
||||
}
|
||||
if (caps & 0x8) {
|
||||
dbgln("Device sleep");
|
||||
}
|
||||
if (caps & 0x10) {
|
||||
dbgln("Aggressive device sleep management");
|
||||
}
|
||||
|
||||
dbgln("Control {x}", ahci_hba_->global_host_control);
|
||||
}
|
||||
|
||||
void AhciDriver::DumpPorts() {
|
||||
for (uint64_t i = 0; i < 6; i++) {
|
||||
AhciDevice* dev = devices_[i];
|
||||
if (dev == nullptr || !dev->IsInit()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dbgln("");
|
||||
dbgln("Port {}:", i);
|
||||
dev->DumpInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void AhciDriver::InterruptLoop() {
|
||||
dbgln("Starting interrupt loop");
|
||||
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] != nullptr && devices_[i]->IsInit() &&
|
||||
(ahci_hba_->interrupt_status & (1 << i))) {
|
||||
devices_[i]->HandleIrq();
|
||||
ahci_hba_->interrupt_status &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glcr::ErrorCode AhciDriver::LoadCapabilities() {
|
||||
if (!(pci_device_header_->status_reg & 0x10)) {
|
||||
dbgln("No caps!");
|
||||
return glcr::FAILED_PRECONDITION;
|
||||
}
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(pci_device_header_);
|
||||
uint16_t offset = pci_device_header_->cap_ptr;
|
||||
do {
|
||||
uint16_t* cap = reinterpret_cast<uint16_t*>(base + offset);
|
||||
switch (*cap & 0xFF) {
|
||||
case 0x01:
|
||||
dbgln("Power Management");
|
||||
break;
|
||||
case 0x05:
|
||||
dbgln("MSI");
|
||||
break;
|
||||
case 0x12:
|
||||
dbgln("SATA");
|
||||
break;
|
||||
default:
|
||||
dbgln("Unrecognized cap");
|
||||
break;
|
||||
}
|
||||
|
||||
offset = (*cap & 0xFF00) >> 8;
|
||||
} while (offset);
|
||||
return glcr::OK;
|
||||
}
|
||||
|
||||
glcr::ErrorCode AhciDriver::RegisterIrq() {
|
||||
if (pci_device_header_->interrupt_pin == 0) {
|
||||
crash("Can't register IRQ without a pin num", glcr::INVALID_ARGUMENT);
|
||||
}
|
||||
uint64_t irq_num = 0;
|
||||
switch (pci_device_header_->interrupt_pin) {
|
||||
case 1:
|
||||
irq_num = kZIrqPci1;
|
||||
break;
|
||||
case 2:
|
||||
irq_num = kZIrqPci2;
|
||||
break;
|
||||
case 3:
|
||||
irq_num = kZIrqPci3;
|
||||
break;
|
||||
case 4:
|
||||
irq_num = kZIrqPci4;
|
||||
break;
|
||||
}
|
||||
|
||||
RET_ERR(ZIrqRegister(irq_num, &irq_port_cap_));
|
||||
irq_thread_ = Thread(interrupt_thread, this);
|
||||
ahci_hba_->global_host_control |= kGhc_InteruptEnable;
|
||||
return glcr::OK;
|
||||
}
|
||||
|
||||
glcr::ErrorCode AhciDriver::LoadHbaRegisters() {
|
||||
ahci_region_ = mmth::OwnedMemoryRegion ::DirectPhysical(
|
||||
pci_device_header_->abar, 0x1100);
|
||||
ahci_hba_ = reinterpret_cast<AhciHba*>(ahci_region_.vaddr());
|
||||
num_ports_ = (ahci_hba_->capabilities & 0x1F) + 1;
|
||||
num_commands_ = ((ahci_hba_->capabilities & 0x1F00) >> 8) + 1;
|
||||
|
||||
return glcr::OK;
|
||||
}
|
||||
|
||||
glcr::ErrorCode AhciDriver::LoadDevices() {
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
if (!(ahci_hba_->port_implemented & (1 << i))) {
|
||||
devices_[i] = nullptr;
|
||||
continue;
|
||||
}
|
||||
uint64_t port_addr =
|
||||
reinterpret_cast<uint64_t>(ahci_hba_) + 0x100 + (0x80 * i);
|
||||
devices_[i] = new AhciDevice(reinterpret_cast<AhciPort*>(port_addr));
|
||||
}
|
||||
return glcr::OK;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue