Move AHCI ports to their own class
This commit is contained in:
@@ -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");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user