Enable AHCI interrupts.

* Implement MSI style interrupts
* Move interrupt handling to device_manager for IRQs
* Give device_manager the ability to allocate IRQs
* Move achi::port to an interrupt-based scheme
This commit is contained in:
Justin C. Miller
2018-05-12 18:27:13 -07:00
parent c9277e4b12
commit 289104cde0
12 changed files with 267 additions and 47 deletions

View File

@@ -3,6 +3,28 @@
#include "interrupts.h"
#include "pci.h"
struct pci_cap_msi :
public pci_cap
{
uint16_t control;
uint64_t address;
uint16_t data;
uint16_t reserved;
uint32_t mask;
uint32_t pending;
} __attribute__ ((packed));
struct pci_cap_msix :
public pci_cap
{
uint16_t control;
uint64_t address;
uint16_t data;
uint16_t reserved;
uint32_t mask;
uint32_t pending;
} __attribute__ ((packed));
pci_device::pci_device() :
m_base(nullptr),
@@ -20,6 +42,7 @@ pci_device::pci_device() :
pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func) :
m_base(group.base_for(bus, device, func)),
m_msi(nullptr),
m_bus_addr(bus_addr(bus, device, func)),
m_irq(isr::isrIgnoreF)
{
@@ -34,8 +57,24 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
m_header_type = (m_base[3] >> 16) & 0x7f;
m_multi = ((m_base[3] >> 16) & 0x80) == 0x80;
uint16_t *command = reinterpret_cast<uint16_t *>(&m_base[1]);
*command |= 0x400; // Mask old INTx style interrupts
log::info(logs::device, "Found PCIe device at %02d:%02d:%d of type %d.%d id %04x:%04x",
bus, device, func, m_class, m_subclass, m_vendor, m_device);
// Walk the extended capabilities list
uint8_t next = m_base[13] & 0xff;
while (next) {
pci_cap *cap = reinterpret_cast<pci_cap *>(kutil::offset_pointer(m_base, next));
next = cap->next;
if (cap->id == pci_cap::type::msi) {
m_msi = cap;
pci_cap_msi *mcap = reinterpret_cast<pci_cap_msi *>(cap);
mcap->control |= ~0x1; // Mask interrupts
}
}
}
uint32_t
@@ -66,6 +105,19 @@ pci_device::set_bar(unsigned i, uint32_t val)
m_base[4+i] = val;
}
void
pci_device::write_msi_regs(addr_t address, uint16_t data)
{
kassert(m_msi, "Tried to write MSI for a device without that cap");
if (m_msi->id == pci_cap::type::msi) {
pci_cap_msi *mcap = reinterpret_cast<pci_cap_msi *>(m_msi);
mcap->address = address;
mcap->data = data;
mcap->control |= 1;
} else {
kassert(0, "MIS-X is NYI");
}
}
bool
pci_group::has_device(uint8_t bus, uint8_t device, uint8_t func)