SRCS= \
acpi.c \
+ pci.c \
osminixxf.c
ACPICA_SRCS= \
#include <assert.h>
#include <minix/acpi.h>
+#include "pci.h"
+
PUBLIC int acpi_enabled;
PUBLIC struct machine machine;
-#define PCI_MAX_DEVICES 32
-#define PCI_MAX_PINS 4
-
-#define IRQ_TABLE_ENTRIES (PCI_MAX_DEVICES * PCI_MAX_PINS)
-
-PRIVATE int irqtable[IRQ_TABLE_ENTRIES];
-PRIVATE ACPI_HANDLE pci_root_handle;
-
/* don't know where ACPI tables are, we may need to access any memory */
PRIVATE int init_mem_priv(void)
{
machine.apic_enabled ? "APIC" : "PIC");
}
-PRIVATE ACPI_STATUS device_get_int(ACPI_HANDLE handle,
- char * name,
- ACPI_INTEGER * val)
-{
- ACPI_STATUS status;
- char buff[sizeof(ACPI_OBJECT)];
- ACPI_BUFFER abuff;
-
- abuff.Length = sizeof(buff);
- abuff.Pointer = buff;
-
- status = AcpiEvaluateObjectTyped(handle, name, NULL,
- &abuff, ACPI_TYPE_INTEGER);
- if (ACPI_SUCCESS(status)) {
- *val = ((ACPI_OBJECT *)abuff.Pointer)->Integer.Value;
- }
-
- return status;
-}
-
-PRIVATE void do_get_irq(message *m)
-{
- unsigned dev = ((struct acpi_get_irq_req *)m)->dev;
- unsigned pin = ((struct acpi_get_irq_req *)m)->pin;
-
- assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
-
- ((struct acpi_get_irq_resp *)m)->irq =
- irqtable[dev * PCI_MAX_PINS + pin];
-}
-
-PRIVATE void add_irq(unsigned dev, unsigned pin, u8_t irq)
-{
- assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
-
- irqtable[dev * PCI_MAX_PINS + pin] = irq;
-}
-
-PRIVATE ACPI_STATUS get_irq_resource(ACPI_RESOURCE *res, void *context)
-{
- ACPI_PCI_ROUTING_TABLE *tbl = (ACPI_PCI_ROUTING_TABLE *) context;
-
- if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
- ACPI_RESOURCE_IRQ *irq;
-
- irq = &res->Data.Irq;
- add_irq(tbl->Address >> 16, tbl->Pin,
- irq->Interrupts[tbl->SourceIndex]);
- } else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
- ACPI_RESOURCE_EXTENDED_IRQ *irq;
-
- add_irq(tbl->Address >> 16, tbl->Pin,
- irq->Interrupts[tbl->SourceIndex]);
- }
-
- return AE_OK;
-}
-
-PRIVATE ACPI_STATUS get_pci_irq_routing(ACPI_HANDLE handle)
-{
- ACPI_STATUS status;
- ACPI_BUFFER abuff;
- char buff[4096];
- ACPI_PCI_ROUTING_TABLE *tbl;
-
- abuff.Length = sizeof(buff);
- abuff.Pointer = buff;
-
- status = AcpiGetIrqRoutingTable(handle, &abuff);
- if (ACPI_FAILURE(status)) {
- return AE_OK;
- }
-
- for (tbl = (ACPI_PCI_ROUTING_TABLE *)abuff.Pointer; tbl->Length;
- tbl = (ACPI_PCI_ROUTING_TABLE *)
- ((char *)tbl + tbl->Length)) {
- ACPI_HANDLE src_handle;
-
- if (*(char*)tbl->Source == '\0') {
- add_irq(tbl->Address >> 16, tbl->Pin, tbl->SourceIndex);
- continue;
- }
-
- status = AcpiGetHandle(handle, tbl->Source, &src_handle);
- if (ACPI_FAILURE(status)) {
- printf("Failed AcpiGetHandle\n");
- continue;
- }
- status = AcpiWalkResources(src_handle, METHOD_NAME__CRS,
- get_irq_resource, tbl);
- if (ACPI_FAILURE(status)) {
- printf("Failed IRQ resource\n");
- continue;
- }
- }
-
- return AE_OK;
-}
-
-PRIVATE ACPI_STATUS add_pci_root_dev(ACPI_HANDLE handle,
- UINT32 level,
- void *context,
- void **retval)
-{
- int i;
- static unsigned called;
-
- if (++called > 1) {
- printf("ACPI: Warning! Multi rooted PCI is not supported!\n");
- return AE_OK;
- }
-
- for (i = 0; i < IRQ_TABLE_ENTRIES; i++)
- irqtable[i] = -1;
-
- return get_pci_irq_routing(handle);
-}
-
-PRIVATE ACPI_STATUS add_pci_dev(ACPI_HANDLE handle,
- UINT32 level,
- void *context,
- void **retval)
-{
- /* skip pci root when we get to it again */
- if (handle == pci_root_handle)
- return AE_OK;
-
- return get_pci_irq_routing(handle);
-}
-
-PRIVATE void scan_devices(void)
-{
- ACPI_STATUS status;
-
- /* do not scan devices in PIC mode */
- if (!machine.apic_enabled)
- return;
-
- /* get the root first */
- status = AcpiGetDevices("PNP0A03", add_pci_root_dev, NULL, NULL);
- assert(ACPI_SUCCESS(status));
-
- /* get the rest of the devices that implement _PRT */
- status = AcpiGetDevices(NULL, add_pci_dev, NULL, NULL);
- assert(ACPI_SUCCESS(status));
-}
PRIVATE ACPI_STATUS init_acpica(void)
{
ACPI_STATUS status;
set_machine_mode();
- scan_devices();
+ pci_scan_devices();
return AE_OK;
}
case ACPI_REQ_GET_IRQ:
do_get_irq(&m);
break;
+ case ACPI_REQ_MAP_BRIDGE:
+ do_map_bridge(&m);
+ break;
default:
printf("ACPI: ignoring unsupported request %d "
"from %d\n",
--- /dev/null
+#ifndef __ACPI_GLOBALS_H__
+#define __ACPI_GLOBALS_H__
+
+EXTERN int acpi_enabled;
+EXTERN struct machine machine;
+
+#endif /* __ACPI_GLOBALS_H__ */
--- /dev/null
+#include <minix/driver.h>
+#include <acpi.h>
+#include <assert.h>
+#include <minix/acpi.h>
+
+#include "acpi_globals.h"
+
+#define PCI_MAX_DEVICES 32
+#define PCI_MAX_PINS 4
+
+#define IRQ_TABLE_ENTRIES (PCI_MAX_DEVICES * PCI_MAX_PINS)
+
+struct pci_bridge {
+ ACPI_HANDLE handle;
+ int irqtable[IRQ_TABLE_ENTRIES];
+ int primary_bus;
+ int secondary_bus;
+ unsigned device;
+ struct pci_bridge * parent;
+ struct pci_bridge * children[PCI_MAX_DEVICES];
+};
+
+PRIVATE struct pci_bridge pci_root_bridge;
+
+struct irq_resource {
+ struct pci_bridge * bridge;
+ ACPI_PCI_ROUTING_TABLE * tbl;
+};
+
+PRIVATE struct pci_bridge * find_bridge(struct pci_bridge * root,
+ int pbnr,
+ int dev,
+ int sbnr)
+{
+ if (!root)
+ return NULL;
+
+ if (sbnr == -1) {
+ if (root->secondary_bus == pbnr)
+ return root->children[dev];
+ else {
+ /* serach all children */
+ unsigned d;
+ for (d = 0; d < PCI_MAX_DEVICES; d++) {
+ struct pci_bridge * b;
+ b = find_bridge(root->children[d],
+ pbnr, dev, sbnr);
+ if (b)
+ return b;
+ }
+ }
+ } else {
+ if (root->secondary_bus == sbnr)
+ return root;
+ else {
+ /* check all children */
+ unsigned d;
+ for (d = 0; d < PCI_MAX_DEVICES; d++) {
+ struct pci_bridge * b;
+ b = find_bridge(root->children[d],
+ pbnr, dev, sbnr);
+ if (b)
+ return b;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+PUBLIC void do_map_bridge(message *m)
+{
+ int err = OK;
+ unsigned dev = ((struct acpi_map_bridge_req *)m)->device;
+ unsigned pbnr = ((struct acpi_map_bridge_req *)m)->primary_bus;
+ unsigned sbnr = ((struct acpi_map_bridge_req *)m)->secondary_bus;
+
+ struct pci_bridge * bridge;
+
+ bridge = find_bridge(&pci_root_bridge, pbnr, dev, -1);
+
+ if (!bridge) {
+ err = ENODEV;
+ goto map_error;
+ }
+
+ bridge->primary_bus = pbnr;
+ bridge->secondary_bus = sbnr;
+
+map_error:
+ ((struct acpi_map_bridge_resp *)m)->err = err;
+}
+
+PRIVATE ACPI_STATUS device_get_int(ACPI_HANDLE handle,
+ char * name,
+ ACPI_INTEGER * val)
+{
+ ACPI_STATUS status;
+ char buff[sizeof(ACPI_OBJECT)];
+ ACPI_BUFFER abuff;
+
+ abuff.Length = sizeof(buff);
+ abuff.Pointer = buff;
+
+ status = AcpiEvaluateObjectTyped(handle, name, NULL,
+ &abuff, ACPI_TYPE_INTEGER);
+ if (ACPI_SUCCESS(status)) {
+ *val = ((ACPI_OBJECT *)abuff.Pointer)->Integer.Value;
+ }
+
+ return status;
+}
+
+PUBLIC void do_get_irq(message *m)
+{
+ struct pci_bridge * bridge;
+ int irq;
+
+ unsigned bus = ((struct acpi_get_irq_req *)m)->bus;
+ unsigned dev = ((struct acpi_get_irq_req *)m)->dev;
+ unsigned pin = ((struct acpi_get_irq_req *)m)->pin;
+
+ assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
+
+ bridge = find_bridge(&pci_root_bridge, -1, -1, bus);
+
+ if (!bridge)
+ irq = -1;
+ else
+ irq = bridge->irqtable[dev * PCI_MAX_PINS + pin];
+
+ ((struct acpi_get_irq_resp *)m)->irq = irq;
+}
+
+PRIVATE void add_irq(struct pci_bridge * bridge,
+ unsigned dev,
+ unsigned pin,
+ u8_t irq)
+{
+ assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
+
+ bridge->irqtable[dev * PCI_MAX_PINS + pin] = irq;
+}
+
+PRIVATE ACPI_STATUS get_irq_resource(ACPI_RESOURCE *res, void *context)
+{
+ struct irq_resource * ires = (struct irq_resource *) context;
+
+ if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
+ ACPI_RESOURCE_IRQ *irq;
+
+ irq = &res->Data.Irq;
+ add_irq(ires->bridge, ires->tbl->Address >> 16, ires->tbl->Pin,
+ irq->Interrupts[ires->tbl->SourceIndex]);
+ } else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
+ ACPI_RESOURCE_EXTENDED_IRQ *irq;
+
+ add_irq(ires->bridge, ires->tbl->Address >> 16, ires->tbl->Pin,
+ irq->Interrupts[ires->tbl->SourceIndex]);
+ }
+
+ return AE_OK;
+}
+
+PRIVATE ACPI_STATUS get_pci_irq_routing(struct pci_bridge * bridge)
+{
+ ACPI_STATUS status;
+ ACPI_BUFFER abuff;
+ char buff[4096];
+ ACPI_PCI_ROUTING_TABLE *tbl;
+ ACPI_DEVICE_INFO *info;
+ int i;
+
+ abuff.Length = sizeof(buff);
+ abuff.Pointer = buff;
+
+ status = AcpiGetIrqRoutingTable(bridge->handle, &abuff);
+ if (ACPI_FAILURE(status)) {
+ return AE_OK;
+ }
+
+ info = abuff.Pointer;
+ status = AcpiGetObjectInfo(bridge->handle, &info);
+ if (ACPI_FAILURE(status))
+ return status;
+ /*
+ * Decode the device number (upper half of the address) and attach the
+ * new bridge in the children list of its parent
+ */
+ bridge->device = info->Address >> 16;
+ if (bridge != &pci_root_bridge) {
+ bridge->parent->children[bridge->device] = bridge;
+ bridge->primary_bus = bridge->secondary_bus = -1;
+ }
+
+
+ for (i = 0; i < PCI_MAX_DEVICES; i++)
+ bridge->children[i] = NULL;
+ for (i = 0; i < IRQ_TABLE_ENTRIES; i++)
+ bridge->irqtable[i] = -1;
+
+ for (tbl = (ACPI_PCI_ROUTING_TABLE *)abuff.Pointer; tbl->Length;
+ tbl = (ACPI_PCI_ROUTING_TABLE *)
+ ((char *)tbl + tbl->Length)) {
+ ACPI_HANDLE src_handle;
+ struct irq_resource ires;
+
+ if (*(char*)tbl->Source == '\0') {
+ add_irq(bridge, tbl->Address >> 16,
+ tbl->Pin, tbl->SourceIndex);
+ continue;
+ }
+
+ status = AcpiGetHandle(bridge->handle, tbl->Source, &src_handle);
+ if (ACPI_FAILURE(status)) {
+ printf("Failed AcpiGetHandle\n");
+ continue;
+ }
+ ires.bridge = bridge;
+ ires,tbl = tbl;
+ status = AcpiWalkResources(src_handle, METHOD_NAME__CRS,
+ get_irq_resource, &ires);
+ if (ACPI_FAILURE(status)) {
+ printf("Failed IRQ resource\n");
+ continue;
+ }
+ }
+
+ return AE_OK;
+}
+
+PRIVATE ACPI_STATUS add_pci_dev(ACPI_HANDLE handle,
+ UINT32 level,
+ void *context,
+ void **retval)
+{
+ ACPI_STATUS status;
+ ACPI_BUFFER abuff;
+ char buff[4096];
+ ACPI_HANDLE parent_handle;
+ struct pci_bridge * bridge;
+ struct pci_bridge * parent_bridge = (struct pci_bridge *) context;
+
+
+ /* skip pci root when we get to it again */
+ if (handle == pci_root_bridge.handle)
+ return AE_OK;
+
+ status = AcpiGetParent(handle, &parent_handle);
+ if (!ACPI_SUCCESS(status))
+ return status;
+ /* skip devices that have a different parent */
+ if (parent_handle != parent_bridge->handle)
+ return AE_OK;
+
+ abuff.Length = sizeof(buff);
+ abuff.Pointer = buff;
+
+ bridge = malloc(sizeof(struct pci_bridge));
+ if (!bridge)
+ return AE_NO_MEMORY;
+ bridge->handle = handle;
+ bridge->parent = parent_bridge;
+
+ status = get_pci_irq_routing(bridge);
+ if (!(ACPI_SUCCESS(status))) {
+ free(bridge);
+ return status;
+ }
+
+ /* get the pci bridges */
+ status = AcpiGetDevices(NULL, add_pci_dev, bridge, NULL);
+ return status;
+}
+
+PRIVATE ACPI_STATUS add_pci_root_dev(ACPI_HANDLE handle,
+ UINT32 level,
+ void *context,
+ void **retval)
+{
+ static unsigned called;
+ ACPI_STATUS status;
+
+ if (++called > 1) {
+ printf("ACPI: Warning! Multi rooted PCI is not supported!\n");
+ return AE_OK;
+ }
+
+ pci_root_bridge.handle = handle;
+ pci_root_bridge.primary_bus = -1; /* undefined */
+ pci_root_bridge.secondary_bus = 0; /* root bus is 0 in a single root
+ system */
+
+ status = get_pci_irq_routing(&pci_root_bridge);
+ if (!ACPI_SUCCESS(status))
+ return status;
+
+ /* get the pci bridges */
+ status = AcpiGetDevices(NULL, add_pci_dev, &pci_root_bridge, NULL);
+ return status;
+}
+
+PUBLIC void pci_scan_devices(void)
+{
+ ACPI_STATUS status;
+
+ /* do not scan devices in PIC mode */
+ if (!machine.apic_enabled)
+ return;
+
+ /* get the root first */
+ status = AcpiGetDevices("PNP0A03", add_pci_root_dev, NULL, NULL);
+ assert(ACPI_SUCCESS(status));
+}
--- /dev/null
+#ifndef __ACPI_PCI_H__
+#define __ACPI_PCI_H__
+
+#include <minix/ipc.h>
+
+_PROTOTYPE(void do_map_bridge, (message *m));
+_PROTOTYPE(void do_get_irq, (message *m));
+
+_PROTOTYPE(void pci_scan_devices, (void));
+
+
+#endif /* __ACPI_PCI_H__ */
return 0;
}
-PRIVATE int acpi_get_irq(unsigned dev, unsigned pin)
+PRIVATE int acpi_get_irq(unsigned bus, unsigned dev, unsigned pin)
{
int err;
message m;
((struct acpi_get_irq_req *)&m)->hdr.request = ACPI_REQ_GET_IRQ;
+ ((struct acpi_get_irq_req *)&m)->bus = bus;
((struct acpi_get_irq_req *)&m)->dev = dev;
((struct acpi_get_irq_req *)&m)->pin = pin;
*/
slot = ((dev->pd_func) >> 3) & 0x1f;
- return acpi_get_irq(parent_bridge->pd_dev, (pin + slot) % 4);
+ return acpi_get_irq(parent_bridge->pd_busnr,
+ parent_bridge->pd_dev, (pin + slot) % 4);
}
/*===========================================================================*
if (ipr && machine.apic_enabled) {
int irq;
- irq = acpi_get_irq(pcidev[devind].pd_dev, ipr - 1);
+ irq = acpi_get_irq(pcidev[devind].pd_busnr,
+ pcidev[devind].pd_dev, ipr - 1);
if (irq < 0)
irq = derive_irq(&pcidev[devind], ipr - 1);
return 0;
}
+/*
+ * tells acpi which two busses are connected by this bridge. The primary bus
+ * (pbnr) must be already known to acpi and it must map dev as the connection to
+ * the secondary (sbnr) bus
+ */
+PRIVATE void acpi_map_bridge(unsigned pbnr, unsigned dev, unsigned sbnr)
+{
+ int err;
+ message m;
+
+ ((struct acpi_map_bridge_req *)&m)->hdr.request = ACPI_REQ_MAP_BRIDGE;
+ ((struct acpi_map_bridge_req *)&m)->primary_bus = pbnr;
+ ((struct acpi_map_bridge_req *)&m)->secondary_bus = sbnr;
+ ((struct acpi_map_bridge_req *)&m)->device = dev;
+
+ if ((err = sendrec(acpi_ep, &m)) != OK)
+ panic("PCI: error %d while receiveing from ACPI\n", err);
+
+ if (((struct acpi_map_bridge_resp *)&m)->err != OK)
+ panic("PCI: acpi failed to map pci (%d) to pci (%d) bridge\n",
+ pbnr, sbnr);
+}
+
/*===========================================================================*
* do_pcibridge *
*===========================================================================*/
default:
panic("unknown PCI-PCI bridge type: %d", type);
}
+
+ if (machine.apic_enabled)
+ acpi_map_bridge(pcidev[devind].pd_busnr,
+ pcidev[devind].pd_dev, sbusn);
+
if (debug)
{
printf(
#include <minix/ipc.h>
#define ACPI_REQ_GET_IRQ 1
+#define ACPI_REQ_MAP_BRIDGE 2
struct acpi_request_hdr {
endpoint_t m_source; /* message header */
*/
struct acpi_get_irq_req {
struct acpi_request_hdr hdr;
+ u32_t bus;
u32_t dev;
u32_t pin;
- u32_t __padding[5];
+ u32_t __padding[4];
};
/* response from acpi to acpi_get_irq_req */
i32_t irq;
u32_t __padding[7];
};
+
+/* message format for pci bridge mappings to acpi */
+struct acpi_map_bridge_req {
+ struct acpi_request_hdr hdr;
+ u32_t primary_bus;
+ u32_t secondary_bus;
+ u32_t device;
+ u32_t __padding[4];
+};
+
+struct acpi_map_bridge_resp {
+ endpoint_t m_source; /* message header */
+ int err;
+ u32_t __padding[7];
+};