Keep per-timer interrupt data together

Eliminate a redundant resource array allow possible use by bhyve later.

Reviewed by:	kevans
Sponsored by:	Arm Ltd
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D37424
This commit is contained in:
Andrew Turner 2023-03-14 09:27:23 +00:00
parent 559e41a11b
commit b71ef90ec2

View File

@ -97,9 +97,16 @@ __FBSDID("$FreeBSD$");
#define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */
#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */
struct arm_tmr_softc;
struct arm_tmr_irq {
struct resource *res;
void *ihl;
int rid;
};
struct arm_tmr_softc {
struct resource *res[GT_IRQ_COUNT];
void *ihl[GT_IRQ_COUNT];
struct arm_tmr_irq irqs[GT_IRQ_COUNT];
uint64_t (*get_cntxct)(bool);
uint32_t clkfreq;
struct eventtimer et;
@ -108,16 +115,6 @@ struct arm_tmr_softc {
static struct arm_tmr_softc *arm_tmr_sc = NULL;
#ifdef DEV_ACPI
static struct resource_spec timer_acpi_spec[] = {
{ SYS_RES_IRQ, GT_PHYS_SECURE, RF_ACTIVE | RF_OPTIONAL },
{ SYS_RES_IRQ, GT_PHYS_NONSECURE, RF_ACTIVE },
{ SYS_RES_IRQ, GT_VIRT, RF_ACTIVE },
{ SYS_RES_IRQ, GT_HYP_PHYS, RF_ACTIVE | RF_OPTIONAL },
{ -1, 0 }
};
#endif
static const struct arm_tmr_irq_defs {
int idx;
const char *name;
@ -402,6 +399,29 @@ arm_tmr_intr(void *arg)
return (FILTER_HANDLED);
}
static int
arm_tmr_attach_irq(device_t dev, struct arm_tmr_softc *sc,
const struct arm_tmr_irq_defs *irq_def, int rid, int flags)
{
sc->irqs[irq_def->idx].res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
&rid, flags);
if (sc->irqs[irq_def->idx].res == NULL) {
if (bootverbose || (flags & RF_OPTIONAL) == 0) {
device_printf(dev,
"could not allocate irq for %s interrupt '%s'\n",
(flags & RF_OPTIONAL) != 0 ? "optional" :
"required", irq_def->name);
}
if ((flags & RF_OPTIONAL) == 0)
return (ENXIO);
} else if (bootverbose) {
device_printf(dev, "allocated irq for '%s'\n", irq_def->name);
}
return (0);
}
#ifdef FDT
static int
arm_tmr_fdt_probe(device_t dev)
@ -479,42 +499,18 @@ arm_tmr_fdt_attach(device_t dev)
flags &= ~RF_OPTIONAL;
}
sc->res[irq_def->idx] = bus_alloc_resource_any(dev,
SYS_RES_IRQ, &rid, flags);
if (sc->res[irq_def->idx] == NULL) {
device_printf(dev,
"could not allocate irq for %s interrupt '%s'\n",
(flags & RF_OPTIONAL) != 0 ? "optional" :
"required", irq_def->name);
if ((flags & RF_OPTIONAL) == 0) {
error = ENXIO;
goto out;
}
continue;
}
if (bootverbose) {
device_printf(dev,
"allocated irq for '%s'\n", irq_def->name);
}
error = arm_tmr_attach_irq(dev, sc, irq_def, rid, flags);
if (error != 0)
goto out;
}
error = arm_tmr_attach(dev);
out:
if (error != 0) {
for (i = 0; i < GT_IRQ_COUNT; i++) {
if (sc->res[i] != NULL) {
/*
* rid may not match the index into sc->res in
* a number of cases; e.g., optional sec-phys or
* interrupt-names specifying them in a
* different order than expected.
*/
if (sc->irqs[i].res != NULL) {
bus_release_resource(dev, SYS_RES_IRQ,
rman_get_rid(sc->res[i]), sc->res[i]);
sc->irqs[i].rid, sc->irqs[i].res);
}
}
}
@ -578,18 +574,29 @@ arm_tmr_acpi_probe(device_t dev)
static int
arm_tmr_acpi_attach(device_t dev)
{
const struct arm_tmr_irq_defs *irq_def;
struct arm_tmr_softc *sc;
int error;
sc = device_get_softc(dev);
if (bus_alloc_resources(dev, timer_acpi_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
for (int i = 0; i < nitems(arm_tmr_irq_defs); i++) {
irq_def = &arm_tmr_irq_defs[i];
error = arm_tmr_attach_irq(dev, sc, irq_def, irq_def->idx,
irq_def->flags);
if (error != 0)
goto out;
}
error = arm_tmr_attach(dev);
if (error != 0)
bus_release_resources(dev, timer_acpi_spec, sc->res);
out:
if (error != 0) {
for (int i = 0; i < GT_IRQ_COUNT; i++) {
if (sc->irqs[i].res != NULL) {
bus_release_resource(dev, SYS_RES_IRQ,
sc->irqs[i].rid, sc->irqs[i].res);
}
}
}
return (error);
}
#endif
@ -643,13 +650,13 @@ arm_tmr_attach(device_t dev)
for (i = 0; i < nitems(arm_tmr_irq_defs); i++) {
irq_def = &arm_tmr_irq_defs[i];
MPASS(sc->res[irq_def->idx] != NULL ||
MPASS(sc->irqs[irq_def->idx].res != NULL ||
(irq_def->flags & RF_OPTIONAL) != 0);
}
#ifdef __aarch64__
/* Use the virtual timer if we have one. */
if (sc->res[GT_VIRT] != NULL) {
if (sc->irqs[GT_VIRT].res != NULL) {
sc->physical = false;
first_timer = GT_VIRT;
last_timer = GT_VIRT;
@ -667,24 +674,25 @@ arm_tmr_attach(device_t dev)
/* Setup secure, non-secure and virtual IRQs handler */
for (i = first_timer; i <= last_timer; i++) {
/* If we do not have the interrupt, skip it. */
if (sc->res[i] == NULL)
if (sc->irqs[i].res == NULL)
continue;
error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK,
arm_tmr_intr, NULL, sc, &sc->ihl[i]);
error = bus_setup_intr(dev, sc->irqs[i].res, INTR_TYPE_CLK,
arm_tmr_intr, NULL, sc, &sc->irqs[i].ihl);
if (error) {
device_printf(dev, "Unable to alloc int resource.\n");
for (int j = first_timer; j < i; j++)
bus_teardown_intr(dev, sc->res[j], &sc->ihl[j]);
bus_teardown_intr(dev, sc->irqs[j].res,
&sc->irqs[j].ihl);
return (ENXIO);
}
}
/* Disable the virtual timer until we are ready */
if (sc->res[GT_VIRT] != NULL)
if (sc->irqs[GT_VIRT].res != NULL)
arm_tmr_disable(false);
/* And the physical */
if ((sc->res[GT_PHYS_SECURE] != NULL ||
sc->res[GT_PHYS_NONSECURE] != NULL) && HAS_PHYS)
if ((sc->irqs[GT_PHYS_SECURE].res != NULL ||
sc->irqs[GT_PHYS_NONSECURE].res != NULL) && HAS_PHYS)
arm_tmr_disable(true);
arm_tmr_timecount.tc_frequency = sc->clkfreq;