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 <fredrik.holmqvist@gmail.com>
This commit is contained in:
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 */
|
||||
|
@ -12,11 +12,14 @@
|
||||
#include <KernelExport.h>
|
||||
#include <device_manager.h>
|
||||
|
||||
#include <drivers/ACPI.h>
|
||||
#include <drivers/bus/FDT.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <AutoDeleterDrivers.h>
|
||||
|
||||
#include <acpi.h>
|
||||
|
||||
#include <virtio.h>
|
||||
#include <virtio_defs.h>
|
||||
#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<VirtioDevice> dev(new(std::nothrow) VirtioDevice());
|
||||
|
Loading…
x
Reference in New Issue
Block a user