Page MenuHomeFreeBSD

D37427.diff
No OneTemporary

D37427.diff

diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c
--- a/sys/arm/arm/generic_timer.c
+++ b/sys/arm/arm/generic_timer.c
@@ -48,6 +48,7 @@
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
+#include <sys/proc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
@@ -58,10 +59,7 @@
#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/md_var.h>
-
-#if defined(__arm__)
#include <machine/machdep.h> /* For arm_set_delay */
-#endif
#if defined(__aarch64__)
#include <machine/undefined.h>
@@ -78,6 +76,8 @@
#include <dev/acpica/acpivar.h>
#endif
+#include "pic_if.h"
+
#define GT_PHYS_SECURE 0
#define GT_PHYS_NONSECURE 1
#define GT_VIRT 2
@@ -104,10 +104,14 @@
struct resource *res;
void *ihl;
struct arm_tmr_softc *sc;
+#if defined(__aarch64__)
+ struct intr_irqsrc isrc;
+#endif
u_int flags;
#define TMR_IRQ_PHYS (1 << 0)
#define TMR_IRQ_ET (1 << 1)
#define TMR_IRQ_CHILD (1 << 2)
+ u_int irq;
};
struct arm_tmr_softc {
@@ -116,6 +120,9 @@
uint32_t clkfreq;
struct eventtimer et;
bool physical;
+#if defined(__aarch64__)
+ struct rman intr_rman;
+#endif
};
static struct arm_tmr_softc *arm_tmr_sc = NULL;
@@ -128,6 +135,10 @@
{ -1, 0 }
};
+struct arm_tmr_ivar {
+ struct resource_list rl;
+};
+
static uint32_t arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th,
struct timecounter *tc);
static void arm_tmr_do_delay(int usec, void *);
@@ -363,17 +374,32 @@
{
struct arm_tmr_softc *sc;
struct arm_tmr_irq *irq;
+ struct trapframe *tf;
int ctrl;
- bool physical;
+ bool physical, mask;
irq = (struct arm_tmr_irq *)arg;
- physical = (irq->flags & TMR_IRQ_PHYS) != 0;
+ if ((irq->flags & TMR_IRQ_CHILD) != 0) {
+ /* The child should manage masking the interrupt */
+ mask = false;
+ tf = curthread->td_intr_frame;
+ if (intr_isrc_dispatch(&irq->isrc, tf) != 0) {
+ printf("Stray timer irq %u\n", irq->irq);
+ mask = true;
+ }
+ } else {
+ mask = true;
+ }
+
+ if (mask) {
+ physical = (irq->flags & TMR_IRQ_PHYS) != 0;
- ctrl = get_ctrl(physical);
- if (ctrl & GT_CTRL_INT_STAT) {
- ctrl |= GT_CTRL_INT_MASK;
- set_ctrl(ctrl, physical);
+ ctrl = get_ctrl(physical);
+ if (ctrl & GT_CTRL_INT_STAT) {
+ ctrl |= GT_CTRL_INT_MASK;
+ set_ctrl(ctrl, physical);
+ }
}
if ((irq->flags & TMR_IRQ_ET) != 0) {
@@ -457,11 +483,33 @@
}
#endif
+#if defined(__aarch64__)
+static void
+arm_tmr_add_vtimer(device_t dev)
+{
+ struct arm_tmr_ivar *devi;
+ device_t child;
+
+ child = device_add_child(dev, "vtimer", -1);
+ if (child == NULL) {
+ device_printf(dev, "Could not add vtimer child\n");
+ return;
+ }
+
+ devi = malloc(sizeof(*devi), M_DEVBUF, M_WAITOK | M_ZERO);
+ resource_list_init(&devi->rl);
+ device_set_ivars(child, devi);
+
+ BUS_SET_RESOURCE(dev, child, SYS_RES_IRQ, 0, GT_VIRT, 1);
+}
+#endif
+
static int
arm_tmr_attach(device_t dev)
{
struct arm_tmr_softc *sc;
struct resource *res[GT_IRQ_COUNT];
+ const char *name;
#ifdef FDT
phandle_t node;
pcell_t clock;
@@ -509,11 +557,12 @@
for (i = 0; i < GT_IRQ_COUNT; i++) {
sc->irqs[i].res = res[i];
sc->irqs[i].sc = sc;
+ sc->irqs[i].irq = i;
}
#ifdef __aarch64__
/* Use the virtual timer if we have one. */
- if (sc->irqs[GT_VIRT].res != NULL) {
+ if (sc->irqs[GT_VIRT].res != NULL && !has_hyp()) {
sc->physical = false;
} else
#endif
@@ -545,6 +594,24 @@
}
}
+#if defined(__aarch64__)
+ name = device_get_nameunit(dev);
+ for (i = 0; i < GT_IRQ_COUNT; i++) {
+ intr_isrc_register(&sc->irqs[i].isrc, dev, 0, "%st%u", name, i);
+ }
+ intr_pic_register(dev, 0);
+ sc->intr_rman.rm_type = RMAN_ARRAY;
+ sc->intr_rman.rm_descr = "Timer Interrupts";
+ if (rman_init(&sc->intr_rman) != 0 ||
+ rman_manage_region(&sc->intr_rman, 0, ~0) != 0)
+ panic("%s: failed to set up rman.", __func__);
+
+ /* Add a vtimer child */
+ if (sc->physical)
+ arm_tmr_add_vtimer(dev);
+ bus_generic_attach(dev);
+#endif
+
/* Disable the virtual timer until we are ready */
if (sc->irqs[GT_VIRT].res != NULL)
arm_tmr_disable(false);
@@ -574,9 +641,183 @@
return (0);
}
+#if defined(__aarch64__)
+struct intr_map_data_timer {
+ struct intr_map_data hdr;
+ u_int irq;
+};
+
+static int
+arm_tmr_set_resource(device_t dev, device_t child, int type, int rid,
+ rman_res_t start, rman_res_t count)
+{
+ struct intr_map_data_timer *irq_data;
+ struct arm_tmr_ivar *devi;
+ struct resource_list_entry *rle;
+ u_int irq;
+
+ if (type != SYS_RES_IRQ)
+ return (EINVAL);
+ if (count != 1)
+ return (EINVAL);
+
+ irq_data = (struct intr_map_data_timer *)intr_alloc_map_data(
+ INTR_MAP_DATA_PLAT_1, sizeof(*irq_data), M_WAITOK | M_ZERO);
+ irq_data->irq = start;
+ irq = intr_map_irq(dev, 0, (struct intr_map_data *)irq_data);
+
+ devi = device_get_ivars(child);
+ rle = resource_list_add(&devi->rl, type, rid, irq,
+ irq + count - 1, count);
+ if (rle == NULL)
+ return (ENXIO);
+
+ return (0);
+}
+
+static struct resource *
+arm_tmr_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct arm_tmr_softc *sc;
+ struct resource_list_entry *rle;
+ struct resource_list *rl;
+ struct resource *rv;
+ int isdefault;
+
+ if (type != SYS_RES_IRQ)
+ return (NULL);
+ if (device_get_parent(child) != bus)
+ return (NULL);
+
+ rle = NULL;
+ isdefault = (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1);
+ if (isdefault) {
+ rl = BUS_GET_RESOURCE_LIST(bus, child);
+ if (rl == NULL)
+ return (NULL);
+ rle = resource_list_find(rl, type, *rid);
+ if (rle == NULL)
+ return (NULL);
+ if (rle->res != NULL)
+ panic("%s: resource entry is busy", __func__);
+ start = rle->start;
+ count = rle->count;
+ end = rle->end;
+ }
+ sc = device_get_softc(bus);
+ rv = rman_reserve_resource(&sc->intr_rman, start, end, count, flags,
+ child);
+ if (rv == NULL)
+ return (NULL);
+ rman_set_rid(rv, *rid);
+ if ((flags & RF_ACTIVE) != 0 &&
+ bus_activate_resource(child, type, *rid, rv) != 0) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+
+ return (rv);
+}
+
+static struct resource_list *
+arm_tmr_get_resource_list(device_t bus __unused, device_t child)
+{
+ struct arm_tmr_ivar *devi;
+
+ devi = device_get_ivars(child);
+ return (&devi->rl);
+}
+
+static int
+arm_tmr_print_child(device_t dev, device_t child)
+{
+ struct arm_tmr_ivar *devi;
+ int retval;
+
+ devi = device_get_ivars(child);
+
+ retval = bus_print_child_header(dev, child);
+ resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd");
+ retval += bus_print_child_footer(dev, child);
+
+ return (retval);
+}
+
+static void
+arm_tmr_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct arm_tmr_softc *sc;
+ int i;
+
+ printf("%s\n", __func__);
+ sc = device_get_softc(dev);
+ for (i = 0; i < nitems(sc->irqs); i++) {
+ if (isrc == &sc->irqs[i].isrc) {
+ sc->irqs[i].flags &= ~TMR_IRQ_CHILD;
+ return;
+ }
+ }
+
+ panic("%s: Invalid interrupt", __func__);
+}
+
+static void
+arm_tmr_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct arm_tmr_softc *sc;
+ int i;
+
+ printf("%s\n", __func__);
+ sc = device_get_softc(dev);
+ for (i = 0; i < nitems(sc->irqs); i++) {
+ if (isrc == &sc->irqs[i].isrc) {
+ sc->irqs[i].flags |= TMR_IRQ_CHILD;
+ return;
+ }
+ }
+
+ panic("%s: Invalid interrupt", __func__);
+}
+
+static int
+arm_tmr_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ struct intr_map_data_timer *irq_data;
+ struct arm_tmr_softc *sc;
+
+ if (data->type != INTR_MAP_DATA_PLAT_1)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ irq_data = (struct intr_map_data_timer *)data;
+ MPASS(irq_data->irq < nitems(sc->irqs));
+
+ *isrcp = &sc->irqs[irq_data->irq].isrc;
+ return (0);
+}
+#endif
+
static device_method_t arm_tmr_methods[] = {
DEVMETHOD(device_attach, arm_tmr_attach),
+#if defined(__aarch64__)
+ /* Bus interface */
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_config_intr, bus_generic_config_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_set_resource, arm_tmr_set_resource),
+ DEVMETHOD(bus_alloc_resource, arm_tmr_alloc_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_get_resource_list, arm_tmr_get_resource_list),
+ DEVMETHOD(bus_print_child, arm_tmr_print_child),
+
+ /* Interrupt controller interface */
+ DEVMETHOD(pic_disable_intr, arm_tmr_disable_intr),
+ DEVMETHOD(pic_enable_intr, arm_tmr_enable_intr),
+ DEVMETHOD(pic_map_intr, arm_tmr_map_intr),
+#endif
DEVMETHOD_END,
};

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 22, 7:29 PM (1 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31996004
Default Alt Text
D37427.diff (8 KB)

Event Timeline