为什么我的中断没有连接? qemu_irq_is_connected( ) returns 错误
Why my interrupt is not connected? qemu_irq_is_connected( ) returns false
我正在尝试让中断在 qemu 中为设备工作。机器名为ab21q,是arm64虚拟机的修改版,设备名为ab21q_axpu.
下面是一些相关的代码。我引用了 pl011.c。 (本次测试临时切换回qemu-5.1.0。)
==== hw/arm/ab21q.c
machab21q_init(MachineState *machine)
{
.... skip ....
create_ab21q_axpu_device(vms, sysmem); // ab21q-axpu test
....
}
static void create_ab21q_axpu_device(const Ab21qMachineState *vms, MemoryRegion *mem)
{
char *nodename;
hwaddr base = vms->memmap[AB21Q_AXPU].base;
hwaddr size = vms->memmap[AB21Q_AXPU].size;
int irq = vms->irqmap[AB21Q_AXPU];
const char compat[] = "ab21q-axpu";
DeviceState *dev = qdev_new(TYPE_AB21Q_AXPU);
SysBusDevice *s = SYS_BUS_DEVICE(dev);
//sysbus_create_simple("ab21q-axpu", base, qdev_get_gpio_in(vms->gic, irq));
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
memory_region_add_subregion(mem, base,
sysbus_mmio_get_region(s, 0));
sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
nodename = g_strdup_printf("/ab21q_axpu@%" PRIx64, base);
qemu_fdt_add_subnode(vms->fdt, nodename);
qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat));
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size);
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
GIC_FDT_IRQ_TYPE_SPI, irq,
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop_cell(vms->fdt, nodename, "interrupt-parent", vms->gic_phandle);
g_free(nodename);
}
==== hw/misc/ab21q_axpu.c
static void ab21q_axpu_init(Object *obj)
{
Ab21qAxpuState *s = AB21Q_AXPU(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
int i;
memory_region_init_io(&s->iomem, OBJECT(s), &ab21q_axpu_ops, s,
TYPE_AB21Q_AXPU, 0x200000*64);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
s->init = 0;
s->int_flag = 0;
s->status = 0;
s->id = CHIP_ID;
}
static void ab21q_axpu_realize(DeviceState *d, Error **errp)
{
Ab21qAxpuState *s = AB21Q_AXPU(d);
SysBusDevice *sbd = SYS_BUS_DEVICE(d);
if (qemu_irq_is_connected(s->irq)) {printf("axpu irq connected!\n");}
else { printf("axpu irq not connected!\n");}
}
static void ab21q_axpu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ab21q_axpu_realize;
}
static void ab21q_axpu_set_irq(Ab21qAxpuState *s, int irq)
{
s->status = irq;
qemu_set_irq(s->irq, 1);
}
static void ab21q_axpu_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
Ab21qAxpuState *s = (Ab21qAxpuState *)opaque;
.... skip ...
switch (offset) {
case TRIGGER_RUN:
....
if (((uint64_t *)(s->ioctl_arg + *host_virt_offset_p))[0] == 0x1604) {
s->int_flag = 1;
ab21q_axpu_set_irq(s, INT_AXPU_RUN_FINISHED);
}
机器和设备工作正常。 (实际上该设备是 qemu 链接到的共享库)除了中断不起作用,即使 qemu set_irq。我用 qemu_irq_is_connected
检查了实现功能。 pl011 案例显示 pl011 irq connected!
,但在我的设备中我看到 axpu irq not connected!
。所以它与设备驱动程序无关,而是 qemu 模型本身。
谁能找到上面代码中缺少的内容?我应该在 acpi table(in ab21q-build-acpi.c) 中添加一些东西吗?
我尝试添加 hw/arm/ab21q-build-acpi.c 这些行。在函数 build_dsdt,
acpi_dsdt_add_axpu(scope, &memmap[AB21Q_AXPU],
(irqmap[AB21Q_AXPU] + ARM_SPI_BASE));
acpi_dsdt_add_axpu函数
static void acpi_dsdt_add_axpu(Aml *scope, const MemMapEntry *uart_memmap,
uint32_t irq)
{
Aml *dev = aml_device("AXPU");
aml_append(dev, aml_name_decl("_HID", aml_string("AXPU0011")));
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
Aml *crs = aml_resource_template();
aml_append(crs, aml_memory32_fixed(uart_memmap->base,
uart_memmap->size, AML_READ_WRITE));
aml_append(crs,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_EXCLUSIVE, &irq, 1));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
}
在虚拟机内(ubuntu 20.04),我做了acpidump并将其转换为.dsl文件。 dsdt.dsl 包含此条目。
设备 (AXPU)
{
Name (_HID, "AXPU0011") // _HID: 硬件ID
名称 (_UID, 零) // _UID: 唯一 ID
Name(_CRS, ResourceTemplate() // _CRS: 当前资源设置
{
Memory32Fixed(读写,
0x09100000, // 地址库
0x00080000, // 地址长度
)
中断 (ResourceConsumer, Level, ActiveHigh, Exclusive, , )
{
0x000000D0,
}
})
}
我不确定我应该在 acpi table 中修复什么。
任何意见或建议将不胜感激。
谢谢!
陈金
所以我添加了一些印刷品。这是结果。
create_uart called!
pl011_init called!
pl011_realize called!
pl011 irq not connected!
now calling sysbus_connect_irq for pl011..
now passed sysbus_connect_irq for pl011..
pl011 irq connected!
create_ab21q_axpu_device called!
ab21q_axpu_init called!
ab21q_axpu_realize called!
axpu irq not connected!
now calling sysbus_connect_irq for ab21q_axpu..
now passed sysbus_connect_irq for ab21q_axpu..
ab21q_axpu irq connected!
所以irq-connection-wise来讲,pl011和ab21q_axpu是一样的!
对于 pl011,在 sysbus_connect_irq 之前也没有连接 irq,
但是在上面的代码中,我错误地使用了 qemu_irq_is_connected(s->irq)) 并且它给了我 true(一个 false true)。我将它固定为 qemu_irq_is_connected(s->irq[0])) 因为它有 6 个 irq 输出并且它在 sysbus_connect_irq 之前返回 false。在 sysbus_connect_irq 之后,ab21q_axpu 和 pl011 的 irq 都显示已连接。
当然,我使用了 qemu_irq_is_connected(AB21Q_AXPU(dev)->irq) 或
qemu_irq_is_connected(PL011(dev)->irq[0]) 检查 xxx_create 函数内的 irq 连接。
ADD:我后来发现 request_irq 函数返回了 -EINVAL。所以中断没有在驱动程序中正确注册。
我正在尝试让中断在 qemu 中为设备工作。机器名为ab21q,是arm64虚拟机的修改版,设备名为ab21q_axpu.
下面是一些相关的代码。我引用了 pl011.c。 (本次测试临时切换回qemu-5.1.0。)
==== hw/arm/ab21q.c
machab21q_init(MachineState *machine)
{
.... skip ....
create_ab21q_axpu_device(vms, sysmem); // ab21q-axpu test
....
}
static void create_ab21q_axpu_device(const Ab21qMachineState *vms, MemoryRegion *mem)
{
char *nodename;
hwaddr base = vms->memmap[AB21Q_AXPU].base;
hwaddr size = vms->memmap[AB21Q_AXPU].size;
int irq = vms->irqmap[AB21Q_AXPU];
const char compat[] = "ab21q-axpu";
DeviceState *dev = qdev_new(TYPE_AB21Q_AXPU);
SysBusDevice *s = SYS_BUS_DEVICE(dev);
//sysbus_create_simple("ab21q-axpu", base, qdev_get_gpio_in(vms->gic, irq));
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
memory_region_add_subregion(mem, base,
sysbus_mmio_get_region(s, 0));
sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
nodename = g_strdup_printf("/ab21q_axpu@%" PRIx64, base);
qemu_fdt_add_subnode(vms->fdt, nodename);
qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat));
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size);
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
GIC_FDT_IRQ_TYPE_SPI, irq,
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop_cell(vms->fdt, nodename, "interrupt-parent", vms->gic_phandle);
g_free(nodename);
}
==== hw/misc/ab21q_axpu.c
static void ab21q_axpu_init(Object *obj)
{
Ab21qAxpuState *s = AB21Q_AXPU(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
int i;
memory_region_init_io(&s->iomem, OBJECT(s), &ab21q_axpu_ops, s,
TYPE_AB21Q_AXPU, 0x200000*64);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
s->init = 0;
s->int_flag = 0;
s->status = 0;
s->id = CHIP_ID;
}
static void ab21q_axpu_realize(DeviceState *d, Error **errp)
{
Ab21qAxpuState *s = AB21Q_AXPU(d);
SysBusDevice *sbd = SYS_BUS_DEVICE(d);
if (qemu_irq_is_connected(s->irq)) {printf("axpu irq connected!\n");}
else { printf("axpu irq not connected!\n");}
}
static void ab21q_axpu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ab21q_axpu_realize;
}
static void ab21q_axpu_set_irq(Ab21qAxpuState *s, int irq)
{
s->status = irq;
qemu_set_irq(s->irq, 1);
}
static void ab21q_axpu_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
Ab21qAxpuState *s = (Ab21qAxpuState *)opaque;
.... skip ...
switch (offset) {
case TRIGGER_RUN:
....
if (((uint64_t *)(s->ioctl_arg + *host_virt_offset_p))[0] == 0x1604) {
s->int_flag = 1;
ab21q_axpu_set_irq(s, INT_AXPU_RUN_FINISHED);
}
机器和设备工作正常。 (实际上该设备是 qemu 链接到的共享库)除了中断不起作用,即使 qemu set_irq。我用 qemu_irq_is_connected
检查了实现功能。 pl011 案例显示 pl011 irq connected!
,但在我的设备中我看到 axpu irq not connected!
。所以它与设备驱动程序无关,而是 qemu 模型本身。
谁能找到上面代码中缺少的内容?我应该在 acpi table(in ab21q-build-acpi.c) 中添加一些东西吗?
我尝试添加 hw/arm/ab21q-build-acpi.c 这些行。在函数 build_dsdt,
acpi_dsdt_add_axpu(scope, &memmap[AB21Q_AXPU],
(irqmap[AB21Q_AXPU] + ARM_SPI_BASE));
acpi_dsdt_add_axpu函数
static void acpi_dsdt_add_axpu(Aml *scope, const MemMapEntry *uart_memmap,
uint32_t irq)
{
Aml *dev = aml_device("AXPU");
aml_append(dev, aml_name_decl("_HID", aml_string("AXPU0011")));
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
Aml *crs = aml_resource_template();
aml_append(crs, aml_memory32_fixed(uart_memmap->base,
uart_memmap->size, AML_READ_WRITE));
aml_append(crs,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_EXCLUSIVE, &irq, 1));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
}
在虚拟机内(ubuntu 20.04),我做了acpidump并将其转换为.dsl文件。 dsdt.dsl 包含此条目。
设备 (AXPU) { Name (_HID, "AXPU0011") // _HID: 硬件ID 名称 (_UID, 零) // _UID: 唯一 ID Name(_CRS, ResourceTemplate() // _CRS: 当前资源设置 { Memory32Fixed(读写, 0x09100000, // 地址库 0x00080000, // 地址长度 ) 中断 (ResourceConsumer, Level, ActiveHigh, Exclusive, , ) { 0x000000D0, } }) }
我不确定我应该在 acpi table 中修复什么。 任何意见或建议将不胜感激。
谢谢!
陈金
所以我添加了一些印刷品。这是结果。
create_uart called!
pl011_init called!
pl011_realize called!
pl011 irq not connected!
now calling sysbus_connect_irq for pl011..
now passed sysbus_connect_irq for pl011..
pl011 irq connected!
create_ab21q_axpu_device called!
ab21q_axpu_init called!
ab21q_axpu_realize called!
axpu irq not connected!
now calling sysbus_connect_irq for ab21q_axpu..
now passed sysbus_connect_irq for ab21q_axpu..
ab21q_axpu irq connected!
所以irq-connection-wise来讲,pl011和ab21q_axpu是一样的! 对于 pl011,在 sysbus_connect_irq 之前也没有连接 irq, 但是在上面的代码中,我错误地使用了 qemu_irq_is_connected(s->irq)) 并且它给了我 true(一个 false true)。我将它固定为 qemu_irq_is_connected(s->irq[0])) 因为它有 6 个 irq 输出并且它在 sysbus_connect_irq 之前返回 false。在 sysbus_connect_irq 之后,ab21q_axpu 和 pl011 的 irq 都显示已连接。 当然,我使用了 qemu_irq_is_connected(AB21Q_AXPU(dev)->irq) 或 qemu_irq_is_connected(PL011(dev)->irq[0]) 检查 xxx_create 函数内的 irq 连接。
ADD:我后来发现 request_irq 函数返回了 -EINVAL。所以中断没有在驱动程序中正确注册。