diff --git a/headers/private/kernel/acpi.h b/headers/private/kernel/acpi.h index 5b3795ebe4..894866b498 100644 --- a/headers/private/kernel/acpi.h +++ b/headers/private/kernel/acpi.h @@ -277,4 +277,48 @@ enum { }; +/* The following definitions are adapted from acpica/include/acrestyp.h */ + + +typedef struct acpi_resource_source +{ + uint8 index; + uint16 string_length; + char *string_ptr; +} _PACKED acpi_resource_source; + +typedef struct acpi_resource_fixed_memory32 { + uint8 write_protect; + uint32 address; + uint32 address_length; +} _PACKED acpi_resource_fixed_memory32; + +typedef struct acpi_resource_extended_irq { + uint8 producer_consumer; + uint8 triggering; + uint8 polarity; + uint8 shareable; + uint8 wake_capable; + uint8 interrupt_count; + acpi_resource_source resource_source; + uint32 interrupts[1]; +} _PACKED acpi_resource_extended_irq; + +typedef union acpi_resource_data { + acpi_resource_fixed_memory32 fixed_memory32; + acpi_resource_extended_irq extended_irq; +} acpi_resource_data; + +typedef struct acpi_resource { + uint32 type; + uint32 length; + acpi_resource_data data; +} _PACKED acpi_resource; + +enum { + ACPI_RESOURCE_TYPE_FIXED_MEMORY32 = 10, + ACPI_RESOURCE_TYPE_EXTENDED_IRQ = 15, +}; + + #endif /* _KERNEL_ACPI_H */ diff --git a/src/add-ons/kernel/busses/virtio/virtio_mmio/virtio_mmio.cpp b/src/add-ons/kernel/busses/virtio/virtio_mmio/virtio_mmio.cpp index 82c3504be3..cd098e79dc 100644 --- a/src/add-ons/kernel/busses/virtio/virtio_mmio/virtio_mmio.cpp +++ b/src/add-ons/kernel/busses/virtio/virtio_mmio/virtio_mmio.cpp @@ -12,11 +12,14 @@ #include #include +#include #include #include #include +#include + #include #include #include "VirtioDevice.h" @@ -80,7 +83,6 @@ virtio_device_supports_device(device_node* parent) const char* name; const char* bus; - const char* compatible; status_t status = gDeviceManager->get_attr_string(parent, B_DEVICE_PRETTY_NAME, &name, false); @@ -93,19 +95,68 @@ virtio_device_supports_device(device_node* parent) if (status < B_OK) return -1.0f; - status = gDeviceManager->get_attr_string(parent, "fdt/compatible", - &compatible, false); + // detect virtio device from FDT + if (strcmp(bus, "fdt") == 0) { + const char* compatible; + status = gDeviceManager->get_attr_string(parent, "fdt/compatible", + &compatible, false); - if (status < B_OK) - return -1.0f; + if (status < B_OK) + return -1.0f; - if (strcmp(bus, "fdt") != 0) - return 0.0f; + if (strcmp(compatible, "virtio,mmio") != 0) + return 0.0f; - if (strcmp(compatible, "virtio,mmio") != 0) - return 0.0f; + return 1.0f; + } - return 1.0f; + // detect virtio device from ACPI + if (strcmp(bus, "acpi") == 0) { + const char* hid; + status = gDeviceManager->get_attr_string(parent, "acpi/hid", + &hid, false); + + if (status < B_OK) + return -1.0f; + + if (strcmp(hid, "LNRO0005") != 0) + return 0.0f; + + return 1.0f; + } + + return 0.0f; +} + + +struct virtio_memory_range { + uint64 base; + uint64 length; +}; + +static acpi_status +virtio_crs_find_address(acpi_resource *res, void *context) +{ + virtio_memory_range &range = *((virtio_memory_range *)context); + + if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { + range.base = res->data.fixed_memory32.address; + range.length = res->data.fixed_memory32.address_length; + } + + return B_OK; +} + + +static acpi_status +virtio_crs_find_interrupt(acpi_resource *res, void *context) +{ + uint64 &interrupt = *((uint64 *)context); + + if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) + interrupt = res->data.extended_irq.interrupts[0]; + + return B_OK; } @@ -114,18 +165,47 @@ virtio_device_register_device(device_node* parent) { TRACE("register_device(%p)\n", parent); - fdt_device_module_info *parentModule; - fdt_device* parentDev; - if (gDeviceManager->get_driver(parent, (driver_module_info**)&parentModule, - (void**)&parentDev)) { - ERROR("can't get parent node driver"); - return B_ERROR; + const char* bus; + + status_t status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false); + + if (status < B_OK) + return -1.0f; + + uint64 regs = 0; + uint64 regsLen = 0; + + // initialize virtio device from FDT + if (strcmp(bus, "fdt") == 0) { + fdt_device_module_info *parentModule; + fdt_device* parentDev; + if (gDeviceManager->get_driver(parent, (driver_module_info**)&parentModule, + (void**)&parentDev)) { + ERROR("can't get parent node driver"); + return B_ERROR; + } + + if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) { + ERROR("no regs"); + return B_ERROR; + } } - uint64 regs, regsLen; - if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) { - ERROR("no regs"); - return B_ERROR; + // initialize virtio device from ACPI + if (strcmp(bus, "acpi") == 0) { + acpi_device_module_info *parentModule; + acpi_device parentDev; + if (gDeviceManager->get_driver(parent, (driver_module_info**)&parentModule, + (void**)&parentDev)) { + ERROR("can't get parent node driver"); + return B_ERROR; + } + + virtio_memory_range range = { 0, 0 }; + parentModule->walk_resources(parentDev, (char *)"_CRS", + virtio_crs_find_address, &range); + regs = range.base; + regsLen = range.length; } VirtioRegs *volatile mappedRegs; @@ -172,49 +252,85 @@ virtio_device_init_device(device_node* node, void** cookie) DeviceNodePutter<&gDeviceManager> parent(gDeviceManager->get_parent_node(node)); - fdt_device_module_info *parentModule; - fdt_device* parentDev; - if (gDeviceManager->get_driver(parent.Get(), - (driver_module_info**)&parentModule, (void**)&parentDev)) - panic("can't get parent node driver"); + const char* bus; - dprintf(" bus: %p\n", parentModule->get_bus(parentDev)); - dprintf(" compatible: %s\n", (const char*)parentModule->get_prop(parentDev, - "compatible", NULL)); + status_t status = gDeviceManager->get_attr_string(parent.Get(), B_DEVICE_BUS, &bus, false); - uint64 regs; - uint64 regsLen; - for (uint32 i = 0; parentModule->get_reg(parentDev, i, ®s, ®sLen); - i++) { - dprintf(" reg[%" B_PRIu32 "]: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n", - i, regs, regsLen); - } + if (status < B_OK) + return -1.0f; - device_node* interruptController; - uint64 interrupt; - for (uint32 i = 0; parentModule->get_interrupt(parentDev, - i, &interruptController, &interrupt); i++) { + uint64 regs = 0; + uint64 regsLen = 0; + uint64 interrupt = 0; - const char* name; - if (interruptController == NULL - || gDeviceManager->get_attr_string(interruptController, "fdt/name", - &name, false) < B_OK) { - name = NULL; + // initialize virtio device from FDT + if (strcmp(bus, "fdt") == 0) { + fdt_device_module_info *parentModule; + fdt_device* parentDev; + if (gDeviceManager->get_driver(parent.Get(), + (driver_module_info**)&parentModule, (void**)&parentDev)) + panic("can't get parent node driver"); + + dprintf(" bus: %p\n", parentModule->get_bus(parentDev)); + dprintf(" compatible: %s\n", (const char*)parentModule->get_prop(parentDev, + "compatible", NULL)); + + for (uint32 i = 0; parentModule->get_reg(parentDev, i, ®s, ®sLen); + i++) { + dprintf(" reg[%" B_PRIu32 "]: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n", + i, regs, regsLen); } - dprintf(" interrupt[%" B_PRIu32 "]: ('%s', 0x%" B_PRIx64 ")\n", i, - name, interrupt); + device_node* interruptController; + for (uint32 i = 0; parentModule->get_interrupt(parentDev, + i, &interruptController, &interrupt); i++) { + + const char* name; + if (interruptController == NULL + || gDeviceManager->get_attr_string(interruptController, "fdt/name", + &name, false) < B_OK) { + name = NULL; + } + + dprintf(" interrupt[%" B_PRIu32 "]: ('%s', 0x%" B_PRIx64 ")\n", i, + name, interrupt); + } + + if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) { + dprintf(" no regs\n"); + return B_ERROR; + } + + if (!parentModule->get_interrupt(parentDev, 0, &interruptController, + &interrupt)) { + dprintf(" no interrupts\n"); + return B_ERROR; + } } - if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) { - dprintf(" no regs\n"); - return B_ERROR; - } + // initialize virtio device from ACPI + if (strcmp(bus, "acpi") == 0) { + acpi_device_module_info *parentModule; + acpi_device parentDev; + if (gDeviceManager->get_driver(parent.Get(), (driver_module_info**)&parentModule, + (void**)&parentDev)) { + ERROR("can't get parent node driver"); + return B_ERROR; + } - if (!parentModule->get_interrupt(parentDev, 0, &interruptController, - &interrupt)) { - dprintf(" no interrupts\n"); - return B_ERROR; + virtio_memory_range range = { 0, 0 }; + parentModule->walk_resources(parentDev, (char *)"_CRS", + virtio_crs_find_address, &range); + regs = range.base; + regsLen = range.length; + + parentModule->walk_resources(parentDev, (char *)"_CRS", + virtio_crs_find_interrupt, &interrupt); + + dprintf(" regs: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n", + regs, regsLen); + dprintf(" interrupt: 0x%" B_PRIx64 "\n", + interrupt); } ObjectDeleter dev(new(std::nothrow) VirtioDevice());