Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/arm/generic_timer.c
Show First 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ | #define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ | ||||
struct arm_tmr_softc { | struct arm_tmr_softc { | ||||
struct resource *res[4]; | struct resource *res[4]; | ||||
void *ihl[4]; | void *ihl[4]; | ||||
uint32_t clkfreq; | uint32_t clkfreq; | ||||
struct eventtimer et; | struct eventtimer et; | ||||
bool physical; | bool physical; | ||||
uint32_t irq_is_initialized[MAXCPU]; | |||||
}; | }; | ||||
static struct arm_tmr_softc *arm_tmr_sc = NULL; | static struct arm_tmr_softc *arm_tmr_sc = NULL; | ||||
static struct resource_spec timer_spec[] = { | static struct resource_spec timer_spec[] = { | ||||
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ | { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ | ||||
{ SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ | { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ | ||||
{ SYS_RES_IRQ, 2, RF_ACTIVE }, /* Virt */ | { SYS_RES_IRQ, 2, RF_ACTIVE }, /* Virt */ | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
static unsigned | static unsigned | ||||
arm_tmr_get_timecount(struct timecounter *tc) | arm_tmr_get_timecount(struct timecounter *tc) | ||||
{ | { | ||||
return (get_cntxct(arm_tmr_sc->physical)); | return (get_cntxct(arm_tmr_sc->physical)); | ||||
} | } | ||||
static void | |||||
arm_tmr_init_secondary(struct arm_tmr_softc * sc) | |||||
{ | |||||
int i; | |||||
/* Ensure irq_is_initialized[0] is observable */ | |||||
rmb(); | |||||
/* Check if interrupt was initialized */ | |||||
if (__predict_false(sc->irq_is_initialized[0] == 0)) | |||||
panic("TMR intr was not initialized on CPU0"); | |||||
/* Unmask interrupts on secondary core */ | |||||
for (i = 0; i < 3; i++) | |||||
arm_unmask_irq(rman_get_start(sc->res[i])); | |||||
} | |||||
static int | static int | ||||
arm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) | arm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) | ||||
{ | { | ||||
struct arm_tmr_softc *sc; | struct arm_tmr_softc *sc; | ||||
int counts, ctrl; | int counts, ctrl; | ||||
sc = (struct arm_tmr_softc *)et->et_priv; | sc = (struct arm_tmr_softc *)et->et_priv; | ||||
/* | |||||
* Check if timer is initialized on current CPU. | |||||
* If not, run init_secondary. | |||||
*/ | |||||
if (atomic_cmpset_32(&sc->irq_is_initialized[curcpu], 0, 1)) | |||||
arm_tmr_init_secondary(sc); | |||||
if (first != 0) { | if (first != 0) { | ||||
counts = ((uint32_t)et->et_frequency * first) >> 32; | counts = ((uint32_t)et->et_frequency * first) >> 32; | ||||
ctrl = get_ctrl(sc->physical); | ctrl = get_ctrl(sc->physical); | ||||
ctrl &= ~GT_CTRL_INT_MASK; | ctrl &= ~GT_CTRL_INT_MASK; | ||||
ctrl |= GT_CTRL_ENABLE; | ctrl |= GT_CTRL_ENABLE; | ||||
set_tval(counts, sc->physical); | set_tval(counts, sc->physical); | ||||
set_ctrl(ctrl, sc->physical); | set_ctrl(ctrl, sc->physical); | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | #endif | ||||
for (i = 0; i < 3; i++) { | for (i = 0; i < 3; i++) { | ||||
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); | ||||
} | } | ||||
} | } | ||||
/* Mark the interrupt as irq_is_initialized and ensure visibility */ | |||||
sc->irq_is_initialized[curcpu] = 1; | |||||
wmb(); | |||||
disable_user_access(); | disable_user_access(); | ||||
arm_tmr_timecount.tc_frequency = sc->clkfreq; | arm_tmr_timecount.tc_frequency = sc->clkfreq; | ||||
tc_init(&arm_tmr_timecount); | tc_init(&arm_tmr_timecount); | ||||
sc->et.et_name = "ARM MPCore Eventtimer"; | sc->et.et_name = "ARM MPCore Eventtimer"; | ||||
sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; | sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; | ||||
▲ Show 20 Lines • Show All 97 Lines • Show Last 20 Lines |