Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/arm/generic_timer.c
| Show First 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
| #include <machine/cpu.h> | #include <machine/cpu.h> | ||||
| #include <machine/intr.h> | #include <machine/intr.h> | ||||
| #include <machine/md_var.h> | #include <machine/md_var.h> | ||||
| #if defined(__arm__) | #if defined(__arm__) | ||||
| #include <machine/machdep.h> /* For arm_set_delay */ | #include <machine/machdep.h> /* For arm_set_delay */ | ||||
| #endif | #endif | ||||
| #if defined(__aarch64__) | |||||
| #include <machine/vmm.h> /* For virt_enabled() */ | |||||
| #endif | |||||
| #ifdef FDT | #ifdef FDT | ||||
| #include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
| #include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
| #include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
| #endif | #endif | ||||
| #ifdef DEV_ACPI | #ifdef DEV_ACPI | ||||
| #include <contrib/dev/acpica/include/acpi.h> | #include <contrib/dev/acpica/include/acpi.h> | ||||
| #include <dev/acpica/acpivar.h> | #include <dev/acpica/acpivar.h> | ||||
| #endif | #endif | ||||
| #include "generic_timer.h" | |||||
| #define GT_CTRL_ENABLE (1 << 0) | #define GT_CTRL_ENABLE (1 << 0) | ||||
| #define GT_CTRL_INT_MASK (1 << 1) | #define GT_CTRL_INT_MASK (1 << 1) | ||||
| #define GT_CTRL_INT_STAT (1 << 2) | #define GT_CTRL_INT_STAT (1 << 2) | ||||
| #define GT_REG_CTRL 0 | #define GT_REG_CTRL 0 | ||||
| #define GT_REG_TVAL 1 | #define GT_REG_TVAL 1 | ||||
| #define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ | #define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ | ||||
| #define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ | #define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ | ||||
| Show All 33 Lines | static struct timecounter arm_tmr_timecount = { | ||||
| .tc_get_timecount = arm_tmr_get_timecount, | .tc_get_timecount = arm_tmr_get_timecount, | ||||
| .tc_poll_pps = NULL, | .tc_poll_pps = NULL, | ||||
| .tc_counter_mask = ~0u, | .tc_counter_mask = ~0u, | ||||
| .tc_frequency = 0, | .tc_frequency = 0, | ||||
| .tc_quality = 1000, | .tc_quality = 1000, | ||||
| .tc_fill_vdso_timehands = arm_tmr_fill_vdso_timehands, | .tc_fill_vdso_timehands = arm_tmr_fill_vdso_timehands, | ||||
| }; | }; | ||||
| static device_t arm_tmr_dev; | |||||
| #ifdef __arm__ | #ifdef __arm__ | ||||
| #define get_el0(x) cp15_## x ##_get() | #define get_el0(x) cp15_## x ##_get() | ||||
| #define get_el1(x) cp15_## x ##_get() | #define get_el1(x) cp15_## x ##_get() | ||||
| #define set_el0(x, val) cp15_## x ##_set(val) | #define set_el0(x, val) cp15_## x ##_set(val) | ||||
| #define set_el1(x, val) cp15_## x ##_set(val) | #define set_el1(x, val) cp15_## x ##_set(val) | ||||
| #else /* __aarch64__ */ | #else /* __aarch64__ */ | ||||
| #define get_el0(x) READ_SPECIALREG(x ##_el0) | #define get_el0(x) READ_SPECIALREG(x ##_el0) | ||||
| #define get_el1(x) READ_SPECIALREG(x ##_el1) | #define get_el1(x) READ_SPECIALREG(x ##_el1) | ||||
| ▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | arm_tmr_intr(void *arg) | ||||
| } | } | ||||
| if (sc->et.et_active) | if (sc->et.et_active) | ||||
| sc->et.et_event_cb(&sc->et, sc->et.et_arg); | sc->et.et_event_cb(&sc->et, sc->et.et_arg); | ||||
| return (FILTER_HANDLED); | return (FILTER_HANDLED); | ||||
| } | } | ||||
| int | |||||
| arm_tmr_setup_intr(int gt_type, driver_filter_t filter, driver_intr_t handler, | |||||
| void *arg) | |||||
| { | |||||
| if (gt_type != GT_PHYS_SECURE && | |||||
| gt_type != GT_PHYS_NONSECURE && | |||||
| gt_type != GT_VIRT && | |||||
| gt_type != GT_HYP) | |||||
| return (ENXIO); | |||||
| if (arm_tmr_sc->res[gt_type] == NULL) | |||||
| return (ENXIO); | |||||
| return (bus_setup_intr(arm_tmr_dev, arm_tmr_sc->res[gt_type], | |||||
| INTR_TYPE_CLK, filter, handler, arg, &arm_tmr_sc->ihl[gt_type])); | |||||
| } | |||||
| int | |||||
| arm_tmr_teardown_intr(int gt_type) | |||||
| { | |||||
| if (gt_type != GT_PHYS_SECURE && | |||||
| gt_type != GT_PHYS_NONSECURE && | |||||
| gt_type != GT_VIRT && | |||||
| gt_type != GT_HYP) | |||||
| return (ENXIO); | |||||
| if (arm_tmr_sc->res[gt_type] == NULL) | |||||
| return (ENXIO); | |||||
| return (bus_teardown_intr(arm_tmr_dev, arm_tmr_sc->res[gt_type], | |||||
| arm_tmr_sc->ihl[gt_type])); | |||||
| } | |||||
| #ifdef FDT | #ifdef FDT | ||||
| static int | static int | ||||
| arm_tmr_fdt_probe(device_t dev) | arm_tmr_fdt_probe(device_t dev) | ||||
| { | { | ||||
| if (!ofw_bus_status_okay(dev)) | if (!ofw_bus_status_okay(dev)) | ||||
| return (ENXIO); | return (ENXIO); | ||||
| ▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | |||||
| #endif | #endif | ||||
| /* Otherwise set up the secure and non-secure physical timers. */ | /* Otherwise set up the secure and non-secure physical timers. */ | ||||
| { | { | ||||
| sc->physical = true; | sc->physical = true; | ||||
| first_timer = 0; | first_timer = 0; | ||||
| last_timer = 1; | last_timer = 1; | ||||
| } | } | ||||
| #ifdef __aarch64__ | |||||
| sc->physical |= virt_enabled(); | |||||
| #endif | |||||
| arm_tmr_sc = sc; | arm_tmr_sc = sc; | ||||
| /* Setup secure, non-secure and virtual IRQs handler */ | /* Setup secure, non-secure and virtual IRQs handler */ | ||||
| for (i = first_timer; i <= last_timer; i++) { | for (i = GT_PHYS_SECURE; i <= GT_VIRT; i++) { | ||||
| /* If we do not have the interrupt, skip it. */ | /* If we do not have the interrupt, skip it. */ | ||||
| if (sc->res[i] == NULL) | if (sc->res[i] == NULL) | ||||
| continue; | continue; | ||||
| #if defined(__aarch64__) | |||||
| if (i == 2 && virt_enabled()) { | |||||
| /* | |||||
| * Do not install an interrupt handler for the virtual | |||||
| * timer. This will be used by the VM. | |||||
| */ | |||||
| continue; | |||||
| } | |||||
| #endif | |||||
| error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, | error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, | ||||
| arm_tmr_intr, NULL, sc, &sc->ihl[i]); | arm_tmr_intr, NULL, sc, &sc->ihl[i]); | ||||
| if (error) { | if (error) { | ||||
| device_printf(dev, "Unable to alloc int resource.\n"); | device_printf(dev, "Unable to alloc int resource.\n"); | ||||
| return (ENXIO); | return (ENXIO); | ||||
| } | } | ||||
| } | } | ||||
| /* Disable the virtual timer until we are ready */ | /* Disable the virtual timer until we are ready */ | ||||
| if (sc->res[2] != NULL) | if (sc->res[2] != NULL) | ||||
| arm_tmr_disable(false); | arm_tmr_disable(false); | ||||
| /* And the physical */ | /* And the physical */ | ||||
| if (sc->physical) | if (sc->physical) | ||||
| arm_tmr_disable(true); | arm_tmr_disable(true); | ||||
| arm_tmr_timecount.tc_frequency = sc->clkfreq; | arm_tmr_timecount.tc_frequency = sc->clkfreq; | ||||
| Show All 9 Lines | #endif | ||||
| sc->et.et_start = arm_tmr_start; | sc->et.et_start = arm_tmr_start; | ||||
| sc->et.et_stop = arm_tmr_stop; | sc->et.et_stop = arm_tmr_stop; | ||||
| sc->et.et_priv = sc; | sc->et.et_priv = sc; | ||||
| et_register(&sc->et); | et_register(&sc->et); | ||||
| #if defined(__arm__) | #if defined(__arm__) | ||||
| arm_set_delay(arm_tmr_do_delay, sc); | arm_set_delay(arm_tmr_do_delay, sc); | ||||
| #endif | #endif | ||||
| arm_tmr_dev = dev; | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| #ifdef FDT | #ifdef FDT | ||||
| static device_method_t arm_tmr_fdt_methods[] = { | static device_method_t arm_tmr_fdt_methods[] = { | ||||
| DEVMETHOD(device_probe, arm_tmr_fdt_probe), | DEVMETHOD(device_probe, arm_tmr_fdt_probe), | ||||
| DEVMETHOD(device_attach, arm_tmr_attach), | DEVMETHOD(device_attach, arm_tmr_attach), | ||||
| ▲ Show 20 Lines • Show All 102 Lines • Show Last 20 Lines | |||||