virtio-mmio: discover devices from ACPI
https://www.kernel.org/doc/Documentation/arm64/arm-acpi.txt https://wiki.linaro.org/LEG/ServerArchitecture/ACPI/LinaroRegistry Change-Id: I330a497173c0a82b789a43720e3d86e1513a661b Reviewed-on: https://review.haiku-os.org/c/haiku/+/5506 Reviewed-by: Fredrik Holmqvist <[email protected]>
This commit is contained in:
committed by
Fredrik Holmqvist
parent
0f1217b8fb
commit
079db739a6
@@ -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 */
|
#endif /* _KERNEL_ACPI_H */
|
||||||
|
|||||||
@@ -12,11 +12,14 @@
|
|||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
|
|
||||||
|
#include <drivers/ACPI.h>
|
||||||
#include <drivers/bus/FDT.h>
|
#include <drivers/bus/FDT.h>
|
||||||
|
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <AutoDeleterDrivers.h>
|
#include <AutoDeleterDrivers.h>
|
||||||
|
|
||||||
|
#include <acpi.h>
|
||||||
|
|
||||||
#include <virtio.h>
|
#include <virtio.h>
|
||||||
#include <virtio_defs.h>
|
#include <virtio_defs.h>
|
||||||
#include "VirtioDevice.h"
|
#include "VirtioDevice.h"
|
||||||
@@ -80,7 +83,6 @@ virtio_device_supports_device(device_node* parent)
|
|||||||
|
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* bus;
|
const char* bus;
|
||||||
const char* compatible;
|
|
||||||
|
|
||||||
status_t status = gDeviceManager->get_attr_string(parent,
|
status_t status = gDeviceManager->get_attr_string(parent,
|
||||||
B_DEVICE_PRETTY_NAME, &name, false);
|
B_DEVICE_PRETTY_NAME, &name, false);
|
||||||
@@ -93,19 +95,68 @@ virtio_device_supports_device(device_node* parent)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return -1.0f;
|
return -1.0f;
|
||||||
|
|
||||||
status = gDeviceManager->get_attr_string(parent, "fdt/compatible",
|
// detect virtio device from FDT
|
||||||
&compatible, false);
|
if (strcmp(bus, "fdt") == 0) {
|
||||||
|
const char* compatible;
|
||||||
|
status = gDeviceManager->get_attr_string(parent, "fdt/compatible",
|
||||||
|
&compatible, false);
|
||||||
|
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return -1.0f;
|
return -1.0f;
|
||||||
|
|
||||||
if (strcmp(bus, "fdt") != 0)
|
if (strcmp(compatible, "virtio,mmio") != 0)
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
if (strcmp(compatible, "virtio,mmio") != 0)
|
return 1.0f;
|
||||||
return 0.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);
|
TRACE("register_device(%p)\n", parent);
|
||||||
|
|
||||||
fdt_device_module_info *parentModule;
|
const char* bus;
|
||||||
fdt_device* parentDev;
|
|
||||||
if (gDeviceManager->get_driver(parent, (driver_module_info**)&parentModule,
|
status_t status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false);
|
||||||
(void**)&parentDev)) {
|
|
||||||
ERROR("can't get parent node driver");
|
if (status < B_OK)
|
||||||
return B_ERROR;
|
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;
|
// initialize virtio device from ACPI
|
||||||
if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) {
|
if (strcmp(bus, "acpi") == 0) {
|
||||||
ERROR("no regs");
|
acpi_device_module_info *parentModule;
|
||||||
return B_ERROR;
|
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;
|
VirtioRegs *volatile mappedRegs;
|
||||||
@@ -172,49 +252,85 @@ virtio_device_init_device(device_node* node, void** cookie)
|
|||||||
DeviceNodePutter<&gDeviceManager>
|
DeviceNodePutter<&gDeviceManager>
|
||||||
parent(gDeviceManager->get_parent_node(node));
|
parent(gDeviceManager->get_parent_node(node));
|
||||||
|
|
||||||
fdt_device_module_info *parentModule;
|
const char* bus;
|
||||||
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));
|
status_t status = gDeviceManager->get_attr_string(parent.Get(), B_DEVICE_BUS, &bus, false);
|
||||||
dprintf(" compatible: %s\n", (const char*)parentModule->get_prop(parentDev,
|
|
||||||
"compatible", NULL));
|
|
||||||
|
|
||||||
uint64 regs;
|
if (status < B_OK)
|
||||||
uint64 regsLen;
|
return -1.0f;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
device_node* interruptController;
|
uint64 regs = 0;
|
||||||
uint64 interrupt;
|
uint64 regsLen = 0;
|
||||||
for (uint32 i = 0; parentModule->get_interrupt(parentDev,
|
uint64 interrupt = 0;
|
||||||
i, &interruptController, &interrupt); i++) {
|
|
||||||
|
|
||||||
const char* name;
|
// initialize virtio device from FDT
|
||||||
if (interruptController == NULL
|
if (strcmp(bus, "fdt") == 0) {
|
||||||
|| gDeviceManager->get_attr_string(interruptController, "fdt/name",
|
fdt_device_module_info *parentModule;
|
||||||
&name, false) < B_OK) {
|
fdt_device* parentDev;
|
||||||
name = NULL;
|
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,
|
device_node* interruptController;
|
||||||
name, interrupt);
|
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)) {
|
// initialize virtio device from ACPI
|
||||||
dprintf(" no regs\n");
|
if (strcmp(bus, "acpi") == 0) {
|
||||||
return B_ERROR;
|
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,
|
virtio_memory_range range = { 0, 0 };
|
||||||
&interrupt)) {
|
parentModule->walk_resources(parentDev, (char *)"_CRS",
|
||||||
dprintf(" no interrupts\n");
|
virtio_crs_find_address, &range);
|
||||||
return B_ERROR;
|
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<VirtioDevice> dev(new(std::nothrow) VirtioDevice());
|
ObjectDeleter<VirtioDevice> dev(new(std::nothrow) VirtioDevice());
|
||||||
|
|||||||
Reference in New Issue
Block a user