Add non-MSI IRQ functionality to PCI
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "arch/amd64/hw/ioapic.h"
|
||||
#include "arch/amd64/hw/irq.h"
|
||||
#include "drivers/pci/pci.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/mm.h"
|
||||
#include "sys/debug.h"
|
||||
@@ -107,3 +108,327 @@ uint8_t amd64_ioapic_leg_gsi(uint8_t leg_irq) {
|
||||
return leg_irq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define PCI_LINK_MAX_POSSIBLE_IRQS 16
|
||||
#define PCI_MAX_IRQ_ROUTES 128
|
||||
#define PCI_MAX_LINKS 32
|
||||
|
||||
static struct acpi_pci_link {
|
||||
// Fully-qualified path name
|
||||
char acpi_name[32];
|
||||
uint32_t possible_count;
|
||||
uint32_t possible_interrupts[PCI_LINK_MAX_POSSIBLE_IRQS];
|
||||
uint32_t current_interrupt;
|
||||
} pci_links[PCI_MAX_LINKS];
|
||||
|
||||
static struct acpi_irq_route {
|
||||
uint8_t bus;
|
||||
uint8_t dev;
|
||||
uint8_t pin;
|
||||
|
||||
int is_named;
|
||||
union {
|
||||
char dst_name[32];
|
||||
uint32_t dst_interrupt;
|
||||
};
|
||||
} pci_irq_routing[PCI_MAX_IRQ_ROUTES];
|
||||
static size_t acpi_pci_irq_routes = 0;
|
||||
|
||||
static struct acpi_pci_link *acpi_pci_link_allocate(void) {
|
||||
for (size_t i = 0; i < PCI_MAX_LINKS; ++i) {
|
||||
if (!pci_links[i].acpi_name[0]) {
|
||||
return &pci_links[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int acpi_pci_link_add_possible_interrupt(struct acpi_pci_link *link, uint32_t irq) {
|
||||
if (link->possible_count == PCI_LINK_MAX_POSSIBLE_IRQS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
link->possible_interrupts[link->possible_count++] = irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_pci_add_named_route(uint8_t bus, uint8_t dev, uint8_t pin, const char *link_name) {
|
||||
if (acpi_pci_irq_routes == PCI_MAX_IRQ_ROUTES) {
|
||||
return -1;
|
||||
}
|
||||
_assert(strlen(link_name) < 32);
|
||||
struct acpi_irq_route *route = &pci_irq_routing[acpi_pci_irq_routes++];
|
||||
|
||||
strcpy(route->dst_name, link_name);
|
||||
route->is_named = 1;
|
||||
route->bus = bus;
|
||||
route->dev = dev;
|
||||
route->pin = pin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_pci_add_hard_route(uint8_t bus, uint8_t dev, uint8_t pin, uint32_t irq) {
|
||||
if (acpi_pci_irq_routes == PCI_MAX_IRQ_ROUTES) {
|
||||
return -1;
|
||||
}
|
||||
struct acpi_irq_route *route = &pci_irq_routing[acpi_pci_irq_routes++];
|
||||
|
||||
route->dst_interrupt = irq;
|
||||
route->is_named = 0;
|
||||
route->bus = bus;
|
||||
route->dev = dev;
|
||||
route->pin = pin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ACPI_STATUS acpi_dev_walk_pci_link_possible_resources(ACPI_RESOURCE *Resource, void *Ctx) {
|
||||
struct acpi_pci_link *link = Ctx;
|
||||
|
||||
switch (Resource->Type) {
|
||||
case ACPI_RESOURCE_TYPE_IRQ: {
|
||||
ACPI_RESOURCE_IRQ *Irq = &Resource->Data.Irq;
|
||||
|
||||
for (UINT32 i = 0; i < Irq->InterruptCount; ++i) {
|
||||
_assert(acpi_pci_link_add_possible_interrupt(link, Irq->Interrupts[i]) == 0);
|
||||
}
|
||||
}
|
||||
return AE_OK;
|
||||
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: {
|
||||
ACPI_RESOURCE_EXTENDED_IRQ *ExtendedIrq = &Resource->Data.ExtendedIrq;
|
||||
|
||||
for (UINT32 i = 0; i < ExtendedIrq->InterruptCount; ++i) {
|
||||
_assert(acpi_pci_link_add_possible_interrupt(link, ExtendedIrq->Interrupts[i]) == 0);
|
||||
}
|
||||
}
|
||||
return AE_OK;
|
||||
case ACPI_RESOURCE_TYPE_END_TAG:
|
||||
return AE_OK;
|
||||
default:
|
||||
panic("Unknown resource type for link: %02x\n", Resource->Type);
|
||||
}
|
||||
}
|
||||
|
||||
static ACPI_STATUS acpi_dev_walk_pci_link_current_resources(ACPI_RESOURCE *Resource, void *Ctx) {
|
||||
struct acpi_pci_link *link = Ctx;
|
||||
|
||||
switch (Resource->Type) {
|
||||
case ACPI_RESOURCE_TYPE_IRQ: {
|
||||
ACPI_RESOURCE_IRQ *Irq = &Resource->Data.Irq;
|
||||
if (Irq->InterruptCount == 0) {
|
||||
// Leave in "Unconfigured" state
|
||||
return AE_OK;
|
||||
}
|
||||
assert(Irq->InterruptCount == 1, "Only one current IRQ config supported now\n");
|
||||
|
||||
link->current_interrupt = Irq->Interrupts[0];
|
||||
}
|
||||
return AE_OK;
|
||||
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: {
|
||||
ACPI_RESOURCE_EXTENDED_IRQ *ExtendedIrq = &Resource->Data.ExtendedIrq;
|
||||
if (ExtendedIrq->InterruptCount == 0) {
|
||||
// Leave in "Unconfigured" state
|
||||
return AE_OK;
|
||||
}
|
||||
assert(ExtendedIrq->InterruptCount == 1, "Only one current IRQ config supported now\n");
|
||||
|
||||
link->current_interrupt = ExtendedIrq->Interrupts[0];
|
||||
}
|
||||
return AE_OK;
|
||||
case ACPI_RESOURCE_TYPE_END_TAG:
|
||||
return AE_OK;
|
||||
default:
|
||||
panic("Unknown resource type for link: %02x\n", Resource->Type);
|
||||
}
|
||||
}
|
||||
|
||||
static ACPI_STATUS acpi_dev_walk_pci_link(ACPI_HANDLE LinkDevice, UINT32 NestingLevel, void *Ctx, void **Res) {
|
||||
ACPI_STATUS ret;
|
||||
char ResourceBufferData[256];
|
||||
char LinkName[256];
|
||||
ACPI_BUFFER ResourceBuffer = { sizeof(ResourceBufferData), ResourceBufferData };
|
||||
ACPI_BUFFER LinkNameBuffer = { sizeof(LinkName), LinkName };
|
||||
|
||||
if (ACPI_FAILURE(ret = AcpiGetName(LinkDevice, ACPI_FULL_PATHNAME, &LinkNameBuffer))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct acpi_pci_link *link = acpi_pci_link_allocate();
|
||||
_assert(link);
|
||||
_assert(strlen(LinkName) < 32);
|
||||
strcpy(link->acpi_name, LinkName);
|
||||
link->possible_count = 0;
|
||||
link->current_interrupt = PCI_IRQ_NO_ROUTE;
|
||||
|
||||
if (ACPI_FAILURE(ret = AcpiGetPossibleResources(LinkDevice, &ResourceBuffer))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(ret = AcpiWalkResourceBuffer(&ResourceBuffer, acpi_dev_walk_pci_link_possible_resources, link))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(ret = AcpiGetCurrentResources(LinkDevice, &ResourceBuffer))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(ret = AcpiWalkResourceBuffer(&ResourceBuffer, acpi_dev_walk_pci_link_current_resources, link))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static ACPI_STATUS acpi_dev_walk_pci_buses(ACPI_HANDLE BusDevice, UINT32 NestingLevel, void *Ctx, void **Res) {
|
||||
ACPI_STATUS ret;
|
||||
|
||||
char BusName[256];
|
||||
ACPI_OBJECT BusNumberObject;
|
||||
ACPI_PCI_ROUTING_TABLE IrqRoutingTable[256];
|
||||
ACPI_DEVICE_INFO *DeviceInfo = NULL;
|
||||
|
||||
ACPI_BUFFER BusNameBuffer = { sizeof(BusName), BusName };
|
||||
ACPI_BUFFER BusNumberObjectBuffer = { sizeof(BusNumberObject), &BusNumberObject };
|
||||
ACPI_BUFFER IrqRoutingTableBuffer = { sizeof(IrqRoutingTable), IrqRoutingTable };
|
||||
|
||||
if (ACPI_FAILURE(ret = AcpiGetName(BusDevice, ACPI_FULL_PATHNAME, &BusNameBuffer))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(ret = AcpiGetObjectInfo(BusDevice, &DeviceInfo))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
UINT8 Bus = 0;
|
||||
int assigned_bus_number = 0;
|
||||
|
||||
// Try to get bus number from _BBN (Base Bus Number)
|
||||
if (ACPI_FAILURE(ret = AcpiEvaluateObjectTyped(BusDevice, "_BBN", NULL, &BusNumberObjectBuffer, ACPI_TYPE_INTEGER))) {
|
||||
if (ret != AE_NOT_FOUND) {
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
assigned_bus_number = 1;
|
||||
kdebug("%s._BBN = %p\n", BusName, BusNumberObject.Integer.Value);
|
||||
if (BusNumberObject.Integer.Value > 0xFF) {
|
||||
panic("Bus number is too high: %p\n", BusNumberObject.Integer.Value);
|
||||
}
|
||||
Bus = BusNumberObject.Integer.Value;
|
||||
}
|
||||
|
||||
kdebug("PCI Root Bus: 0x%02x (%s)\n", Bus, BusName);
|
||||
kdebug(" _HID = %s, _CLS = %s\n",
|
||||
((DeviceInfo->Valid & ACPI_VALID_HID) ? DeviceInfo->HardwareId.String : "NONE"),
|
||||
((DeviceInfo->Valid & ACPI_VALID_CLS) ? DeviceInfo->ClassCode.String : "NONE"));
|
||||
if (DeviceInfo->Valid & ACPI_VALID_CID) {
|
||||
for (size_t i = 0; i < DeviceInfo->CompatibleIdList.Count; ++i) {
|
||||
kdebug(" _CID = %s\n", DeviceInfo->CompatibleIdList.Ids[i].String);
|
||||
}
|
||||
}
|
||||
|
||||
//pci_add_root_bus(Bus);
|
||||
|
||||
// Get _PRT
|
||||
if (ACPI_FAILURE(ret = AcpiGetIrqRoutingTable(BusDevice, &IrqRoutingTableBuffer))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
UINT32 Offset = 0;
|
||||
|
||||
while (Offset < IrqRoutingTableBuffer.Length) {
|
||||
ACPI_PCI_ROUTING_TABLE *Route = (ACPI_PCI_ROUTING_TABLE *) ((uintptr_t) IrqRoutingTable + Offset);
|
||||
|
||||
if (!Route->Length) {
|
||||
break;
|
||||
}
|
||||
|
||||
UINT8 Device = (Route->Address >> 16) & 0xFF;
|
||||
_assert((Route->Address & 0xFFFF) == 0xFFFF);
|
||||
|
||||
// Check if it's a "hard" route, meaning it's not a reference to a PCI Link device but
|
||||
// GSI number is specified directly instead
|
||||
if (Route->SourceIndex == 0) {
|
||||
// It's a LNKx reference
|
||||
_assert(acpi_pci_add_named_route(Bus, Device, Route->Pin, Route->Source) == 0);
|
||||
} else {
|
||||
// IRQ number specified directly
|
||||
_assert(acpi_pci_add_hard_route(Bus, Device, Route->Pin, Route->SourceIndex) == 0);
|
||||
}
|
||||
|
||||
Offset += Route->Length;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
int amd64_pci_init_irqs(void) {
|
||||
ACPI_STATUS ret;
|
||||
|
||||
// 1. Walk links
|
||||
if (ACPI_FAILURE(ret = AcpiGetDevices("PNP0C0F", acpi_dev_walk_pci_link, NULL, NULL))) {
|
||||
kerror("ACPI INIT failure %s\n", AcpiFormatException(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 2. Walk buses
|
||||
// Will also match PCI Express buses
|
||||
if (ACPI_FAILURE(ret = AcpiGetDevices("PNP0A03" /* PCI Bus */, acpi_dev_walk_pci_buses, NULL, NULL))) {
|
||||
kerror("ACPI INIT failure %s\n", AcpiFormatException(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Dump PCI Link table
|
||||
kdebug("PCI Interrupt Link Devices:\n");
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
if (pci_links[i].acpi_name[0]) {
|
||||
if (pci_links[i].current_interrupt == PCI_IRQ_NO_ROUTE) {
|
||||
kdebug("%s: Unmapped\n", pci_links[i].acpi_name);
|
||||
} else {
|
||||
kdebug("%s: Current IRQ %u\n", pci_links[i].acpi_name, pci_links[i].current_interrupt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t amd64_pci_link_route(const char *link_name) {
|
||||
for (size_t i = 0; i < PCI_MAX_LINKS; ++i) {
|
||||
if (!strcmp(link_name, pci_links[i].acpi_name)) {
|
||||
return pci_links[i].current_interrupt;
|
||||
}
|
||||
}
|
||||
|
||||
// No such link exists
|
||||
kdebug("No link named %s\n", link_name);
|
||||
return PCI_IRQ_INVALID;
|
||||
}
|
||||
|
||||
uint32_t amd64_pci_pin_irq_route(struct pci_device *dev, uint8_t pin) {
|
||||
uint8_t b, d, f;
|
||||
pci_get_device_address(dev, &b, &d, &f);
|
||||
|
||||
for (size_t i = 0; i < acpi_pci_irq_routes; ++i) {
|
||||
struct acpi_irq_route *route = &pci_irq_routing[i];
|
||||
|
||||
if (route->bus == b && route->dev == d && route->pin == pin) {
|
||||
// Found matching route
|
||||
if (route->is_named) {
|
||||
// Resolve LNKx
|
||||
return amd64_pci_link_route(route->dst_name);
|
||||
} else {
|
||||
return route->dst_interrupt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No such route exists
|
||||
kerror("No PCI IRQ route %02x:%02x:%02x:INT%c#\n", b, d, f, pin + 'A');
|
||||
return PCI_IRQ_INVALID;
|
||||
}
|
||||
|
||||
+13
-13
@@ -97,19 +97,19 @@ int irq_add_leg_handler(uint8_t leg_irq, irq_handler_func_t handler, void *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
//int irq_add_pci_handler(pci_addr_t addr, uint8_t pin, irq_handler_func_t handler, void *ctx) {
|
||||
// _assert(pin < 4);
|
||||
// uint32_t irq_route = amd64_pci_pin_irq_route(PCI_BUS(addr), PCI_DEV(addr), PCI_FUNC(addr), pin);
|
||||
// _assert(irq_route != PCI_IRQ_INVALID);
|
||||
//
|
||||
// if (irq_route == PCI_IRQ_NO_ROUTE) {
|
||||
// panic("TODO: allocate PCI IRQ routes\n");
|
||||
// }
|
||||
//
|
||||
// kdebug("Assigning handler to " PCI_FMTADDR " INT%c# -> GSI%d", PCI_VAADDR(addr), pin + 'A', irq_route);
|
||||
//
|
||||
// return irq_add_handler(irq_route, handler, ctx);
|
||||
//}
|
||||
int irq_add_pci_handler(struct pci_device *dev, uint8_t pin, irq_handler_func_t handler, void *ctx) {
|
||||
_assert(pin < 4);
|
||||
uint32_t irq_route = amd64_pci_pin_irq_route(dev, pin);
|
||||
_assert(irq_route != PCI_IRQ_INVALID);
|
||||
|
||||
if (irq_route == PCI_IRQ_NO_ROUTE) {
|
||||
panic("TODO: allocate PCI IRQ routes\n");
|
||||
}
|
||||
|
||||
//kdebug("Assigning handler to " PCI_FMTADDR " INT%c# -> GSI%d", PCI_VAADDR(addr), pin + 'A', irq_route);
|
||||
|
||||
return irq_add_handler(irq_route, handler, ctx);
|
||||
}
|
||||
|
||||
void irq_enable_ioapic_mode(void) {
|
||||
ioapic_available = 1;
|
||||
|
||||
+53
-1
@@ -1,7 +1,8 @@
|
||||
#include "arch/amd64/hw/ioapic.h"
|
||||
#include "drivers/pci/pci.h"
|
||||
#include "arch/amd64/hw/ioapic.h"
|
||||
#include "arch/amd64/hw/acpi.h"
|
||||
#include "arch/amd64/hw/io.h"
|
||||
#include "drivers/pci/pci.h"
|
||||
#include "sys/snprintf.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/string.h"
|
||||
@@ -20,6 +21,9 @@ struct pci_driver;
|
||||
#define pcie_config_read_dword(dev, off) \
|
||||
(*(uint32_t *) ((dev)->pcie_config + (off)))
|
||||
|
||||
#define pcie_config_write_dword(dev, off, val) \
|
||||
(*(uint32_t *) ((dev)->pcie_config + (off))) = (val);
|
||||
|
||||
#define PCI_CAP_MSI_64 (1 << 7)
|
||||
#define PCI_CAP_MSI_EN (1 << 0)
|
||||
struct pci_cap_msi {
|
||||
@@ -72,6 +76,26 @@ static size_t g_pci_driver_count;
|
||||
#define PCI_DRIVER_CLASS 1
|
||||
#define PCI_DRIVER_DEV 2
|
||||
|
||||
void pci_config_write_dword(struct pci_device *dev, uint16_t off, uint32_t val) {
|
||||
if (PCI_IS_EXPRESS(dev)) {
|
||||
pcie_config_write_dword(dev, off, val);
|
||||
} else {
|
||||
pci_config_write_dword_legacy(dev->bus, dev->dev, dev->func, off, val);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_config_write_dword_legacy(uint8_t bus, uint8_t dev, uint8_t func, uint32_t off, uint32_t val) {
|
||||
uint32_t w0;
|
||||
w0 = (((uint32_t) bus) << 16) |
|
||||
(((uint32_t) dev) << 11) |
|
||||
(((uint32_t) func) << 8) |
|
||||
(off & ~0x3) |
|
||||
(1 << 31);
|
||||
|
||||
outl(PCI_PORT_CONFIG_ADDR, w0);
|
||||
outl(PCI_PORT_CONFIG_DATA, val);
|
||||
}
|
||||
|
||||
uint32_t pci_config_read_dword(struct pci_device *dev, uint16_t off) {
|
||||
if (PCI_IS_EXPRESS(dev)) {
|
||||
return pcie_config_read_dword(dev, off);
|
||||
@@ -110,6 +134,13 @@ void pci_add_irq(struct pci_device *dev, irq_handler_func_t handler, void *ctx)
|
||||
dev->msi->msi32.message_data = vector;
|
||||
}
|
||||
dev->msi->message_control |= PCI_CAP_MSI_EN;
|
||||
} else {
|
||||
uint32_t irq_config = pci_config_read_dword(dev, PCI_CONFIG_IRQ);
|
||||
uint8_t irq_pin = (irq_config >> 8) & 0xFF;
|
||||
if (irq_pin) {
|
||||
kdebug("Uses INT%c# IRQ pin\n\n", 'A' + irq_pin - 1);
|
||||
irq_add_pci_handler(dev, irq_pin - 1, handler, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,10 +157,29 @@ void pci_add_class_driver(uint32_t full_class, pci_driver_func_t func, const cha
|
||||
driver->match = full_class & ~0xFF000000;
|
||||
}
|
||||
|
||||
void pci_add_device_driver(uint32_t id, pci_driver_func_t func, const char *name) {
|
||||
if (g_pci_driver_count == PCI_MAX_DRIVERS) {
|
||||
panic("Too many PCI drivers loaded\n");
|
||||
}
|
||||
|
||||
struct pci_driver *driver = &g_pci_drivers[g_pci_driver_count++];
|
||||
|
||||
strcpy(driver->name, name);
|
||||
driver->init_func = func;
|
||||
driver->type = PCI_DRIVER_DEV;
|
||||
driver->match = id;
|
||||
}
|
||||
|
||||
void pci_add_root_bus(uint8_t n) {
|
||||
kwarn("%s: %02x\n", __func__, n);
|
||||
}
|
||||
|
||||
void pci_get_device_address(const struct pci_device *dev, uint8_t *b, uint8_t *d, uint8_t *f) {
|
||||
*b = dev->bus;
|
||||
*d = dev->dev;
|
||||
*f = dev->func;
|
||||
}
|
||||
|
||||
static void pci_pick_driver(uint32_t device_id, uint32_t class_id, struct pci_driver **class_driver, struct pci_driver **dev_driver) {
|
||||
struct pci_driver *rclass = NULL, *rdev = NULL;
|
||||
for (size_t i = 0; i < g_pci_driver_count; ++i) {
|
||||
@@ -368,6 +418,8 @@ static void pcie_enumerate_segment(uintptr_t base_address, uint16_t seg, uint8_t
|
||||
}
|
||||
|
||||
void pci_init(void) {
|
||||
amd64_pci_init_irqs();
|
||||
|
||||
if (acpi_mcfg) {
|
||||
uint32_t mcfg_entry_count = (acpi_mcfg->hdr.length - sizeof(struct acpi_header) - 8) / sizeof(struct acpi_mcfg_entry);
|
||||
kdebug("MCFG has %u entries:\n", mcfg_entry_count);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// irq.h header to provide controller-agnostic interface
|
||||
#include "sys/types.h"
|
||||
|
||||
struct pci_device;
|
||||
|
||||
#define IOAPIC_REG_ID 0x00
|
||||
#define IOAPIC_REG_VER 0x01
|
||||
#define IOAPIC_REG_REDIR 0x10
|
||||
@@ -50,4 +52,4 @@ uint8_t amd64_ioapic_leg_gsi(uint8_t leg_irq);
|
||||
#define PCI_IRQ_INVALID 0xFFFFFFFE
|
||||
|
||||
int amd64_pci_init_irqs(void);
|
||||
uint32_t amd64_pci_pin_irq_route(uint8_t bus, uint8_t dev, uint8_t func, uint8_t pin);
|
||||
uint32_t amd64_pci_pin_irq_route(struct pci_device *dev, uint8_t pin);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define IRQ_UNHANDLED ((uint32_t) -1)
|
||||
|
||||
typedef uint32_t (*irq_handler_func_t) (void *);
|
||||
struct pci_device;
|
||||
|
||||
struct irq_handler {
|
||||
irq_handler_func_t func;
|
||||
@@ -18,7 +19,7 @@ struct irq_handler {
|
||||
int irq_add_handler(uint8_t gsi, irq_handler_func_t handler, void *ctx);
|
||||
int irq_add_leg_handler(uint8_t leg_irq, irq_handler_func_t handler, void *ctx);
|
||||
int irq_add_msi_handler(irq_handler_func_t handler, void *ctx, uint8_t *vector);
|
||||
//int irq_add_pci_handler(pci_addr_t addr, uint8_t pin, irq_handler_func_t handler, void *ctx);
|
||||
int irq_add_pci_handler(struct pci_device *dev, uint8_t pin, irq_handler_func_t handler, void *ctx);
|
||||
|
||||
int irq_has_handler(uint8_t gsi);
|
||||
|
||||
|
||||
@@ -21,14 +21,19 @@
|
||||
struct pci_device;
|
||||
typedef void (*pci_driver_func_t)(struct pci_device *dev);
|
||||
|
||||
void pci_get_device_address(const struct pci_device *dev, uint8_t *b, uint8_t *d, uint8_t *f);
|
||||
|
||||
void pci_init(void);
|
||||
void pci_add_root_bus(uint8_t n);
|
||||
|
||||
uint32_t pci_config_read_dword_legacy(uint8_t bus, uint8_t dev, uint8_t func, uint32_t off);
|
||||
uint32_t pci_config_read_dword(struct pci_device *dev, uint16_t off);
|
||||
void pci_config_write_dword_legacy(uint8_t bus, uint8_t dev, uint8_t func, uint32_t off, uint32_t val);
|
||||
void pci_config_write_dword(struct pci_device *dev, uint16_t off, uint32_t val);
|
||||
void pci_add_irq(struct pci_device *dev, irq_handler_func_t handler, void *ctx);
|
||||
|
||||
void pci_add_class_driver(uint32_t full_class, pci_driver_func_t func, const char *name);
|
||||
void pci_add_device_driver(uint32_t id, pci_driver_func_t func, const char *name);
|
||||
|
||||
// pcidb.c
|
||||
const char *pci_class_string(uint16_t full_class);
|
||||
|
||||
Reference in New Issue
Block a user