Move AHCI ports to their own class

This commit is contained in:
Justin C. Miller
2018-05-10 09:50:31 -07:00
parent a1bc76f305
commit 8ae3eea19c
2 changed files with 140 additions and 29 deletions

View File

@@ -47,6 +47,98 @@ enum class ata_cmd : uint8_t
identify = 0xEC identify = 0xEC
}; };
struct ahci_port_data
{
uint64_t command_base;
uint64_t fis_base;
uint32_t interrupt_status;
uint32_t interrupt_enable;
uint32_t command;
uint32_t reserved;
uint32_t task_file;
uint32_t signature;
uint32_t serial_status;
uint32_t serial_control;
uint32_t serial_error;
} __attribute__ ((packed));
ahci_port::ahci_port(ahci_port_data *data, bool impl) :
m_data(data),
m_state(state::unimpl)
{
if (impl) {
m_state = state::inactive;
update();
}
}
void
ahci_port::update()
{
if (m_state == state::unimpl) return;
uint32_t detected = m_data->serial_status & 0x0f;
uint32_t power = (m_data->serial_status >> 8) & 0x0f;
if (detected == 0x3 && power == 0x1)
m_state = state::active;
else
m_state = state::inactive;
}
enum class ahci_hba::cap : uint32_t
{
cccs = 0x00000080, // Command completion coalescing
sam = 0x00040000, // ACHI-only mode
sclo = 0x01000000, // Command list override
ssntf = 0x40000000, // SNotification register
sncq = 0x40000000, // Native command queuing
s64a = 0x80000000 // 64bit addressing
};
IS_BITFIELD(ahci_hba::cap);
enum class ahci_hba::cap2 : uint32_t
{
boh = 0x00000001 // BIOS OS hand-off
};
IS_BITFIELD(ahci_hba::cap2);
ahci_hba::ahci_hba(pci_device *device)
{
page_manager *pm = page_manager::get();
uint32_t bar5 = device->get_bar(5);
m_bara = reinterpret_cast<uint32_t *>(bar5 & ~0xfffull);
pm->map_offset_pointer(reinterpret_cast<void **>(&m_bara), 0x2000);
ahci_port_data *port_data = reinterpret_cast<ahci_port_data *>(
kutil::offset_pointer(m_bara, 0x100));
uint32_t cap_reg = m_bara[0];
m_cap = static_cast<cap>(cap_reg);
m_cap2 = static_cast<cap2>(m_bara[6]);
uint32_t ports = (cap_reg & 0xf) + 1;
uint32_t slots = ((cap_reg >> 8) & 0x1f) + 1;
log::info(logs::driver, " %d ports", ports);
log::info(logs::driver, " %d command slots", slots);
m_ports.ensure_capacity(ports);
uint32_t pi = m_bara[3];
for (int i = 0; i < ports; ++i) {
bool impl = ((pi & (1 << i)) != 0);
m_ports.emplace(&port_data[i], impl);
}
}
ahci_driver::ahci_driver() ahci_driver::ahci_driver()
{ {
} }
@@ -57,32 +149,5 @@ ahci_driver::register_device(pci_device *device)
log::info(logs::driver, "AHCI registering device %d:%d:%d:", log::info(logs::driver, "AHCI registering device %d:%d:%d:",
device->bus(), device->device(), device->function()); device->bus(), device->device(), device->function());
uint32_t bar5 = device->get_bar(5); ahci_hba &hba = m_devices.emplace(device);
uint32_t *bara = reinterpret_cast<uint32_t *>(bar5 & ~0xfffull);
page_manager *pm = page_manager::get();
pm->map_offset_pointer(reinterpret_cast<void **>(&bara), 0x2000);
uint32_t cap = bara[0];
log::info(logs::driver, " %d ports", (cap & 0xf) + 1);
log::info(logs::driver, " %d command slots", ((cap >> 8) & 0x1f) + 1);
log::info(logs::driver, " Supports:");
if (cap & 0x80000000) log::info(logs::driver, " - 64 bit addressing");
if (cap & 0x40000000) log::info(logs::driver, " - native command queuing");
if (cap & 0x20000000) log::info(logs::driver, " - SNotification register");
if (cap & 0x10000000) log::info(logs::driver, " - mechanical presence switches");
if (cap & 0x08000000) log::info(logs::driver, " - staggered spin up");
if (cap & 0x04000000) log::info(logs::driver, " - agressive link power management");
if (cap & 0x02000000) log::info(logs::driver, " - activity LED");
if (cap & 0x01000000) log::info(logs::driver, " - command list override");
if (cap & 0x00040000) log::info(logs::driver, " - AHCI only");
if (cap & 0x00020000) log::info(logs::driver, " - port multiplier");
if (cap & 0x00010000) log::info(logs::driver, " - FIS switching");
if (cap & 0x00008000) log::info(logs::driver, " - PIO multiple DRQ");
if (cap & 0x00004000) log::info(logs::driver, " - slumber state");
if (cap & 0x00002000) log::info(logs::driver, " - partial state");
if (cap & 0x00000080) log::info(logs::driver, " - command completion coalescing");
if (cap & 0x00000040) log::info(logs::driver, " - enclosure management");
if (cap & 0x00000020) log::info(logs::driver, " - external SATA");
} }

View File

@@ -4,6 +4,52 @@
#include "kutil/vector.h" #include "kutil/vector.h"
class pci_device; class pci_device;
struct ahci_port_data;
/// A port on an AHCI HBA
class ahci_port
{
public:
/// Constructor.
/// \arg data Pointer to the device's registers for this port
/// \arg impl Whether this port is marked as implemented in the HBA
ahci_port(ahci_port_data *data, bool impl);
enum class state { unimpl, inactive, active };
/// Get the current state of this device
/// \returns An enum representing the state
state get_state() const { return m_state; }
/// Update the state of this object from the register data
void update();
private:
ahci_port_data *m_data;
state m_state;
};
/// An AHCI host bus adapter
class ahci_hba
{
public:
/// Constructor.
/// \arg device The PCI device for this HBA
ahci_hba(pci_device *device);
private:
enum class cap : uint32_t;
enum class cap2 : uint32_t;
pci_device *m_device;
uint32_t *m_bara;
kutil::vector<ahci_port> m_ports;
cap m_cap;
cap2 m_cap2;
};
/// Basic AHCI driver /// Basic AHCI driver
@@ -22,5 +68,5 @@ public:
void unregister_device(pci_device *device); void unregister_device(pci_device *device);
private: private:
kutil::vector<pci_device *> m_devices; kutil::vector<ahci_hba> m_devices;
}; };