Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153545462
D37427.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D37427.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D37427: Support adding child devices to the genreic timer
Attached
Detach File
Event Timeline
Log In to Comment