struct timeintr_ops { void (*ti_init)(void *, void (*)(void *), void *); bool (*ti_map)(void *, const struct timespec *, uint32_t *); void (*ti_arm)(void *, uint32_t); int ti_flags; }; #define TIMEINTR_ONESHOT __BIT(0) #define TIMEINTR_PERIODIC __BIT(1) #define TIMEINTR_PERCPU __BIT(2) struct timeintr *timeintr_attach(uint64_t/*freq*/, uint64_t/*quality*/, const struct timeintr_ops *, void *); #if 0 initialization -> MD code attaches various timeintrs -> MI code decides which timeintr source to use based on available ones (or maybe uses more than one at a time) -> MI code calls ti->ti_init(ti, hiresclock, cookie) so the timer interrupt will call hiresclock(cookie, tsc) when it fires callout_schedule_hires(callouthandle, ts) -> calls ti->ti_map(ti, ts, &tsc) to map to device-dependent time scale => e.g.: for lapic in tsc deadline mode, converts ts to tsc units -> inserts {tsc, callouthandle} into priority queue -> if sooner than soonest event, call ti->ti_arm(ti, tsc) => e.g.: for lapic in tsc deadline mode, arms one-shot timer eventually interrupt happens, calls hiresclock(cookie, tsc) -> (maybe schedules softint) -> goes through every callouthandle in queue up to tsc -> if queue is nonempty, calls ti->ti_arm(ti, tsc) with next tsc in queue #endif