#include <sys/types.h>
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/atomic.h>
#include <sys/clockintr.h>
#include <dev/dt/dtvar.h>
struct dt_probe *dtpp_profile;
struct dt_probe *dtpp_interval;
#define DTEVT_PROV_PROFILE DTEVT_COMMON
int dt_prov_profile_alloc(struct dt_probe *, struct dt_softc *,
struct dt_pcb_list *, struct dtioc_req *);
struct dt_provider dt_prov_profile = {
.dtpv_name = "profile",
.dtpv_alloc = dt_prov_profile_alloc,
.dtpv_enter = NULL,
.dtpv_leave = NULL,
.dtpv_dealloc = NULL,
};
struct dt_provider dt_prov_interval = {
.dtpv_name = "interval",
.dtpv_alloc = dt_prov_profile_alloc,
.dtpv_enter = NULL,
.dtpv_leave = NULL,
.dtpv_dealloc = NULL,
};
int
dt_prov_profile_init(void)
{
dtpp_profile = dt_dev_alloc_probe("hz", "97", &dt_prov_profile);
if (dtpp_profile == NULL)
return 0;
dt_dev_register_probe(dtpp_profile);
dtpp_interval = dt_dev_alloc_probe("hz", "1", &dt_prov_interval);
if (dtpp_interval == NULL)
return 1;
dt_dev_register_probe(dtpp_interval);
return 2;
}
int
dt_prov_profile_alloc(struct dt_probe *dtp, struct dt_softc *sc,
struct dt_pcb_list *plist, struct dtioc_req *dtrq)
{
uint64_t nsecs;
struct dt_pcb *dp;
struct cpu_info *ci;
CPU_INFO_ITERATOR cii;
KASSERT(TAILQ_EMPTY(plist));
KASSERT(dtp == dtpp_profile || dtp == dtpp_interval);
nsecs = dtrq->dtrq_nsecs;
if (nsecs < USEC_TO_NSEC(200) || nsecs > SEC_TO_NSEC(UINT32_MAX))
return EINVAL;
CPU_INFO_FOREACH(cii, ci) {
if (!CPU_IS_PRIMARY(ci) && (dtp == dtpp_interval))
continue;
dp = dt_pcb_alloc(dtp, sc);
if (dp == NULL) {
dt_pcb_purge(plist);
return ENOMEM;
}
dp->dp_nsecs = nsecs;
dp->dp_cpu = ci;
dp->dp_evtflags = dtrq->dtrq_evtflags & DTEVT_PROV_PROFILE;
TAILQ_INSERT_HEAD(plist, dp, dp_snext);
}
return 0;
}
void
dt_clock(struct clockrequest *cr, void *cf, void *arg)
{
uint64_t count;
struct dt_evt *dtev;
struct dt_pcb *dp = arg;
count = clockrequest_advance(cr, dp->dp_nsecs);
if (count == 0)
return;
else if (count > 1)
dt_pcb_ring_skiptick(dp, count - 1);
dtev = dt_pcb_ring_get(dp, 1);
if (dtev == NULL)
return;
dt_pcb_ring_consume(dp, dtev);
}