Teach the GICv3 driver about a vgic child
This will be used by bhyve to attach a virtual GIC driver. Sponsored by: Innovate UK Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D36590
This commit is contained in:
parent
9526031cd5
commit
e13c6a6fca
@ -33,6 +33,7 @@
|
||||
|
||||
#define GIC_IVAR_HW_REV 500
|
||||
#define GIC_IVAR_BUS 501
|
||||
#define GIC_IVAR_VGIC 502
|
||||
|
||||
/* GIC_IVAR_BUS values */
|
||||
#define GIC_BUS_UNKNOWN 0
|
||||
@ -42,6 +43,7 @@
|
||||
|
||||
__BUS_ACCESSOR(gic, hw_rev, GIC, HW_REV, u_int);
|
||||
__BUS_ACCESSOR(gic, bus, GIC, BUS, u_int);
|
||||
__BUS_ACCESSOR(gic, vgic, GIC, VGIC, u_int);
|
||||
|
||||
/* Software Generated Interrupts */
|
||||
#define GIC_FIRST_SGI 0 /* Irqs 0-15 are SGIs/IPIs. */
|
||||
|
@ -456,6 +456,7 @@ static int
|
||||
gic_v3_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
||||
{
|
||||
struct gic_v3_softc *sc;
|
||||
struct gic_v3_devinfo *di;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
@ -481,6 +482,12 @@ gic_v3_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
||||
("gic_v3_read_ivar: Invalid bus type %u", sc->gic_bus));
|
||||
*result = sc->gic_bus;
|
||||
return (0);
|
||||
case GIC_IVAR_VGIC:
|
||||
di = device_get_ivars(child);
|
||||
if (di == NULL)
|
||||
return (EINVAL);
|
||||
*result = di->is_vgic;
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (ENOENT);
|
||||
|
@ -48,6 +48,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include "gic_v3_reg.h"
|
||||
#include "gic_v3_var.h"
|
||||
|
||||
#define GICV3_PRIV_VGIC 0x80000000
|
||||
#define GICV3_PRIV_FLAGS 0x80000000
|
||||
|
||||
struct gic_v3_acpi_devinfo {
|
||||
struct gic_v3_devinfo di_gic_dinfo;
|
||||
struct resource_list di_rl;
|
||||
@ -86,6 +89,7 @@ struct madt_table_data {
|
||||
ACPI_MADT_GENERIC_DISTRIBUTOR *dist;
|
||||
int count;
|
||||
bool rdist_use_gicc;
|
||||
bool have_vgic;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -152,6 +156,8 @@ rdist_map(ACPI_SUBTABLE_HEADER *entry, void *arg)
|
||||
BUS_SET_RESOURCE(madt_data->parent, madt_data->dev,
|
||||
SYS_RES_MEMORY, madt_data->count, intr->GicrBaseAddress,
|
||||
count);
|
||||
if (intr->VgicInterrupt == 0)
|
||||
madt_data->have_vgic = false;
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -164,6 +170,7 @@ gic_v3_acpi_identify(driver_t *driver, device_t parent)
|
||||
struct madt_table_data madt_data;
|
||||
ACPI_TABLE_MADT *madt;
|
||||
vm_paddr_t physaddr;
|
||||
uintptr_t private;
|
||||
device_t dev;
|
||||
|
||||
physaddr = acpi_find_table(ACPI_SIG_MADT);
|
||||
@ -210,6 +217,7 @@ gic_v3_acpi_identify(driver_t *driver, device_t parent)
|
||||
|
||||
madt_data.dev = dev;
|
||||
madt_data.rdist_use_gicc = false;
|
||||
madt_data.have_vgic = true;
|
||||
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
|
||||
rdist_map, &madt_data);
|
||||
if (madt_data.count == 0) {
|
||||
@ -222,7 +230,12 @@ gic_v3_acpi_identify(driver_t *driver, device_t parent)
|
||||
rdist_map, &madt_data);
|
||||
}
|
||||
|
||||
acpi_set_private(dev, (void *)(uintptr_t)madt_data.dist->Version);
|
||||
private = madt_data.dist->Version;
|
||||
/* Flag that the VGIC is in use */
|
||||
if (madt_data.have_vgic)
|
||||
private |= GICV3_PRIV_VGIC;
|
||||
|
||||
acpi_set_private(dev, (void *)private);
|
||||
|
||||
out:
|
||||
acpi_unmap_table(madt);
|
||||
@ -232,7 +245,7 @@ static int
|
||||
gic_v3_acpi_probe(device_t dev)
|
||||
{
|
||||
|
||||
switch((uintptr_t)acpi_get_private(dev)) {
|
||||
switch((uintptr_t)acpi_get_private(dev) & ~GICV3_PRIV_FLAGS) {
|
||||
case ACPI_MADT_GIC_VERSION_V3:
|
||||
case ACPI_MADT_GIC_VERSION_V4:
|
||||
break;
|
||||
@ -390,9 +403,14 @@ gic_v3_add_children(ACPI_SUBTABLE_HEADER *entry, void *arg)
|
||||
static void
|
||||
gic_v3_acpi_bus_attach(device_t dev)
|
||||
{
|
||||
struct gic_v3_acpi_devinfo *di;
|
||||
struct gic_v3_softc *sc;
|
||||
ACPI_TABLE_MADT *madt;
|
||||
device_t child;
|
||||
vm_paddr_t physaddr;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
physaddr = acpi_find_table(ACPI_SIG_MADT);
|
||||
if (physaddr == 0)
|
||||
return;
|
||||
@ -405,6 +423,20 @@ gic_v3_acpi_bus_attach(device_t dev)
|
||||
|
||||
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
|
||||
gic_v3_add_children, dev);
|
||||
/* Add the vgic child if needed */
|
||||
if (((uintptr_t)acpi_get_private(dev) & GICV3_PRIV_FLAGS) != 0) {
|
||||
child = device_add_child(dev, "vgic", -1);
|
||||
if (child == NULL) {
|
||||
device_printf(dev, "Could not add vgic child\n");
|
||||
} else {
|
||||
di = malloc(sizeof(*di), M_GIC_V3, M_WAITOK | M_ZERO);
|
||||
resource_list_init(&di->di_rl);
|
||||
di->di_gic_dinfo.gic_domain = -1;
|
||||
di->di_gic_dinfo.is_vgic = 1;
|
||||
sc->gic_nchildren++;
|
||||
device_set_ivars(child, di);
|
||||
}
|
||||
}
|
||||
|
||||
acpi_unmap_table(madt);
|
||||
|
||||
|
@ -212,9 +212,10 @@ static int
|
||||
gic_v3_fdt_print_child(device_t bus, device_t child)
|
||||
{
|
||||
struct gic_v3_ofw_devinfo *di = device_get_ivars(child);
|
||||
struct resource_list *rl = &di->di_rl;
|
||||
struct resource_list *rl;
|
||||
int retval = 0;
|
||||
|
||||
rl = &di->di_rl;
|
||||
retval += bus_print_child_header(bus, child);
|
||||
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
|
||||
retval += bus_print_child_footer(bus, child);
|
||||
@ -228,6 +229,8 @@ gic_v3_ofw_get_devinfo(device_t bus __unused, device_t child)
|
||||
struct gic_v3_ofw_devinfo *di;
|
||||
|
||||
di = device_get_ivars(child);
|
||||
if (di->di_gic_dinfo.is_vgic)
|
||||
return (NULL);
|
||||
return (&di->di_dinfo);
|
||||
}
|
||||
|
||||
@ -352,5 +355,23 @@ gic_v3_ofw_bus_attach(device_t dev)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a vgic maintanance interupt add a virtual gic
|
||||
* child so we can use this in the vmm module for bhyve.
|
||||
*/
|
||||
if (OF_hasprop(parent, "interrupts")) {
|
||||
child = device_add_child(dev, "vgic", -1);
|
||||
if (child == NULL) {
|
||||
device_printf(dev, "Could not add vgic child\n");
|
||||
} else {
|
||||
di = malloc(sizeof(*di), M_GIC_V3, M_WAITOK | M_ZERO);
|
||||
resource_list_init(&di->di_rl);
|
||||
di->di_gic_dinfo.gic_domain = -1;
|
||||
di->di_gic_dinfo.is_vgic = 1;
|
||||
device_set_ivars(child, di);
|
||||
sc->gic_nchildren++;
|
||||
}
|
||||
}
|
||||
|
||||
return (bus_generic_attach(dev));
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ struct gic_v3_softc {
|
||||
struct gic_v3_devinfo {
|
||||
int gic_domain;
|
||||
int msi_xref;
|
||||
int is_vgic;
|
||||
};
|
||||
|
||||
#define GIC_INTR_ISRC(sc, irq) (&sc->gic_irqs[irq].gi_isrc)
|
||||
|
Loading…
x
Reference in New Issue
Block a user