Add debugging prints to all the methods in case there are problems with
managing levels. This can be enabled with the debug.cpufreq.verbose tunable and sysctl.
This commit is contained in:
parent
b6e8f5f503
commit
46ef074ef7
@ -83,6 +83,11 @@ TAILQ_HEAD(cf_setting_lst, cf_setting_array);
|
|||||||
#define CF_MTX_UNLOCK(x) sx_xunlock((x))
|
#define CF_MTX_UNLOCK(x) sx_xunlock((x))
|
||||||
#define CF_MTX_ASSERT(x) sx_assert((x), SX_XLOCKED)
|
#define CF_MTX_ASSERT(x) sx_assert((x), SX_XLOCKED)
|
||||||
|
|
||||||
|
#define CF_DEBUG(msg...) do { \
|
||||||
|
if (cf_verbose) \
|
||||||
|
printf("cpufreq: " msg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static int cpufreq_attach(device_t dev);
|
static int cpufreq_attach(device_t dev);
|
||||||
static int cpufreq_detach(device_t dev);
|
static int cpufreq_detach(device_t dev);
|
||||||
static void cpufreq_evaluate(void *arg);
|
static void cpufreq_evaluate(void *arg);
|
||||||
@ -120,10 +125,14 @@ DRIVER_MODULE(cpufreq, cpu, cpufreq_driver, cpufreq_dc, 0, 0);
|
|||||||
static eventhandler_tag cf_ev_tag;
|
static eventhandler_tag cf_ev_tag;
|
||||||
|
|
||||||
static int cf_lowest_freq;
|
static int cf_lowest_freq;
|
||||||
|
static int cf_verbose;
|
||||||
TUNABLE_INT("debug.cpufreq.lowest", &cf_lowest_freq);
|
TUNABLE_INT("debug.cpufreq.lowest", &cf_lowest_freq);
|
||||||
|
TUNABLE_INT("debug.cpufreq.verbose", &cf_verbose);
|
||||||
SYSCTL_NODE(_debug, OID_AUTO, cpufreq, CTLFLAG_RD, NULL, "cpufreq debugging");
|
SYSCTL_NODE(_debug, OID_AUTO, cpufreq, CTLFLAG_RD, NULL, "cpufreq debugging");
|
||||||
SYSCTL_INT(_debug_cpufreq, OID_AUTO, lowest, CTLFLAG_RW, &cf_lowest_freq, 1,
|
SYSCTL_INT(_debug_cpufreq, OID_AUTO, lowest, CTLFLAG_RW, &cf_lowest_freq, 1,
|
||||||
"Don't provide levels below this frequency.");
|
"Don't provide levels below this frequency.");
|
||||||
|
SYSCTL_INT(_debug_cpufreq, OID_AUTO, verbose, CTLFLAG_RW, &cf_verbose, 1,
|
||||||
|
"Print verbose debugging messages");
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cpufreq_attach(device_t dev)
|
cpufreq_attach(device_t dev)
|
||||||
@ -132,6 +141,7 @@ cpufreq_attach(device_t dev)
|
|||||||
device_t parent;
|
device_t parent;
|
||||||
int numdevs;
|
int numdevs;
|
||||||
|
|
||||||
|
CF_DEBUG("initializing %s\n", device_get_nameunit(dev));
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
parent = device_get_parent(dev);
|
parent = device_get_parent(dev);
|
||||||
sc->dev = dev;
|
sc->dev = dev;
|
||||||
@ -151,6 +161,8 @@ cpufreq_attach(device_t dev)
|
|||||||
if (numdevs > 1)
|
if (numdevs > 1)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
|
CF_DEBUG("initializing one-time data for %s\n",
|
||||||
|
device_get_nameunit(dev));
|
||||||
SYSCTL_ADD_PROC(&sc->sysctl_ctx,
|
SYSCTL_ADD_PROC(&sc->sysctl_ctx,
|
||||||
SYSCTL_CHILDREN(device_get_sysctl_tree(parent)),
|
SYSCTL_CHILDREN(device_get_sysctl_tree(parent)),
|
||||||
OID_AUTO, "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
|
OID_AUTO, "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
|
||||||
@ -171,13 +183,16 @@ cpufreq_detach(device_t dev)
|
|||||||
struct cpufreq_softc *sc;
|
struct cpufreq_softc *sc;
|
||||||
int numdevs;
|
int numdevs;
|
||||||
|
|
||||||
|
CF_DEBUG("shutdown %s\n", device_get_nameunit(dev));
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
sysctl_ctx_free(&sc->sysctl_ctx);
|
sysctl_ctx_free(&sc->sysctl_ctx);
|
||||||
|
|
||||||
/* Only clean up these resources when the last device is detaching. */
|
/* Only clean up these resources when the last device is detaching. */
|
||||||
numdevs = devclass_get_count(cpufreq_dc);
|
numdevs = devclass_get_count(cpufreq_dc);
|
||||||
if (numdevs == 1)
|
if (numdevs == 1) {
|
||||||
|
CF_DEBUG("final shutdown for %s\n", device_get_nameunit(dev));
|
||||||
EVENTHANDLER_DEREGISTER(cpufreq_changed, cf_ev_tag);
|
EVENTHANDLER_DEREGISTER(cpufreq_changed, cf_ev_tag);
|
||||||
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -219,24 +234,34 @@ cf_set_method(device_t dev, const struct cf_level *level, int priority)
|
|||||||
if (sc->saved_level.total_set.freq != CPUFREQ_VAL_UNKNOWN) {
|
if (sc->saved_level.total_set.freq != CPUFREQ_VAL_UNKNOWN) {
|
||||||
level = &sc->saved_level;
|
level = &sc->saved_level;
|
||||||
priority = sc->saved_priority;
|
priority = sc->saved_priority;
|
||||||
|
CF_DEBUG("restoring saved level, freq %d prio %d\n",
|
||||||
|
level->total_set.freq, priority);
|
||||||
} else {
|
} else {
|
||||||
|
CF_DEBUG("NULL level, no saved level\n");
|
||||||
error = ENXIO;
|
error = ENXIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else if (priority < sc->curr_priority) {
|
} else if (priority < sc->curr_priority) {
|
||||||
|
CF_DEBUG("ignoring, curr prio %d less than %d\n", priority,
|
||||||
|
sc->curr_priority);
|
||||||
error = EPERM;
|
error = EPERM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reject levels that are below our specified threshold. */
|
/* Reject levels that are below our specified threshold. */
|
||||||
if (level->total_set.freq <= cf_lowest_freq) {
|
if (level->total_set.freq <= cf_lowest_freq) {
|
||||||
|
CF_DEBUG("rejecting freq %d, less than %d limit\n",
|
||||||
|
level->total_set.freq, cf_lowest_freq);
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If already at this level, just return. */
|
/* If already at this level, just return. */
|
||||||
if (CPUFREQ_CMP(sc->curr_level.total_set.freq, level->total_set.freq))
|
if (CPUFREQ_CMP(sc->curr_level.total_set.freq, level->total_set.freq)) {
|
||||||
|
CF_DEBUG("skipping freq %d, same as current level %d\n",
|
||||||
|
level->total_set.freq, sc->curr_level.total_set.freq);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* First, set the absolute frequency via its driver. */
|
/* First, set the absolute frequency via its driver. */
|
||||||
set = &level->abs_set;
|
set = &level->abs_set;
|
||||||
@ -254,6 +279,8 @@ cf_set_method(device_t dev, const struct cf_level *level, int priority)
|
|||||||
sched_bind(curthread, pc->pc_cpuid);
|
sched_bind(curthread, pc->pc_cpuid);
|
||||||
mtx_unlock_spin(&sched_lock);
|
mtx_unlock_spin(&sched_lock);
|
||||||
}
|
}
|
||||||
|
CF_DEBUG("setting abs freq %d on %s (cpu %d)\n", set->freq,
|
||||||
|
device_get_nameunit(set->dev), PCPU_GET(cpuid));
|
||||||
error = CPUFREQ_DRV_SET(set->dev, set);
|
error = CPUFREQ_DRV_SET(set->dev, set);
|
||||||
if (cpu_id != pc->pc_cpuid) {
|
if (cpu_id != pc->pc_cpuid) {
|
||||||
mtx_lock_spin(&sched_lock);
|
mtx_lock_spin(&sched_lock);
|
||||||
@ -281,6 +308,8 @@ cf_set_method(device_t dev, const struct cf_level *level, int priority)
|
|||||||
sched_bind(curthread, pc->pc_cpuid);
|
sched_bind(curthread, pc->pc_cpuid);
|
||||||
mtx_unlock_spin(&sched_lock);
|
mtx_unlock_spin(&sched_lock);
|
||||||
}
|
}
|
||||||
|
CF_DEBUG("setting rel freq %d on %s (cpu %d)\n", set->freq,
|
||||||
|
device_get_nameunit(set->dev), PCPU_GET(cpuid));
|
||||||
error = CPUFREQ_DRV_SET(set->dev, set);
|
error = CPUFREQ_DRV_SET(set->dev, set);
|
||||||
if (cpu_id != pc->pc_cpuid) {
|
if (cpu_id != pc->pc_cpuid) {
|
||||||
mtx_lock_spin(&sched_lock);
|
mtx_lock_spin(&sched_lock);
|
||||||
@ -295,6 +324,7 @@ cf_set_method(device_t dev, const struct cf_level *level, int priority)
|
|||||||
|
|
||||||
/* If we were restoring a saved state, reset it to "unused". */
|
/* If we were restoring a saved state, reset it to "unused". */
|
||||||
if (level == &sc->saved_level) {
|
if (level == &sc->saved_level) {
|
||||||
|
CF_DEBUG("resetting saved level\n");
|
||||||
sc->saved_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
|
sc->saved_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
|
||||||
sc->saved_priority = 0;
|
sc->saved_priority = 0;
|
||||||
}
|
}
|
||||||
@ -307,6 +337,8 @@ cf_set_method(device_t dev, const struct cf_level *level, int priority)
|
|||||||
if (sc->curr_level.total_set.freq != CPUFREQ_VAL_UNKNOWN &&
|
if (sc->curr_level.total_set.freq != CPUFREQ_VAL_UNKNOWN &&
|
||||||
sc->saved_level.total_set.freq == CPUFREQ_VAL_UNKNOWN &&
|
sc->saved_level.total_set.freq == CPUFREQ_VAL_UNKNOWN &&
|
||||||
priority > sc->curr_priority) {
|
priority > sc->curr_priority) {
|
||||||
|
CF_DEBUG("saving level, freq %d prio %d\n",
|
||||||
|
sc->curr_level.total_set.freq, sc->curr_priority);
|
||||||
sc->saved_level = sc->curr_level;
|
sc->saved_level = sc->curr_level;
|
||||||
sc->saved_priority = sc->curr_priority;
|
sc->saved_priority = sc->curr_priority;
|
||||||
}
|
}
|
||||||
@ -339,8 +371,10 @@ cf_get_method(device_t dev, struct cf_level *level)
|
|||||||
/* If we already know the current frequency, we're done. */
|
/* If we already know the current frequency, we're done. */
|
||||||
CF_MTX_LOCK(&sc->lock);
|
CF_MTX_LOCK(&sc->lock);
|
||||||
curr_set = &sc->curr_level.total_set;
|
curr_set = &sc->curr_level.total_set;
|
||||||
if (curr_set->freq != CPUFREQ_VAL_UNKNOWN)
|
if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) {
|
||||||
|
CF_DEBUG("get returning known freq %d\n", curr_set->freq);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
CF_MTX_UNLOCK(&sc->lock);
|
CF_MTX_UNLOCK(&sc->lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -388,8 +422,10 @@ cf_get_method(device_t dev, struct cf_level *level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(devs, M_TEMP);
|
free(devs, M_TEMP);
|
||||||
if (curr_set->freq != CPUFREQ_VAL_UNKNOWN)
|
if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) {
|
||||||
|
CF_DEBUG("get matched freq %d from drivers\n", curr_set->freq);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We couldn't find an exact match, so attempt to estimate and then
|
* We couldn't find an exact match, so attempt to estimate and then
|
||||||
@ -405,6 +441,7 @@ cf_get_method(device_t dev, struct cf_level *level)
|
|||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
if (CPUFREQ_CMP(rate, levels[i].total_set.freq)) {
|
if (CPUFREQ_CMP(rate, levels[i].total_set.freq)) {
|
||||||
sc->curr_level = levels[i];
|
sc->curr_level = levels[i];
|
||||||
|
CF_DEBUG("get estimated freq %d\n", curr_set->freq);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,8 +495,13 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count)
|
|||||||
* provide settings for informational purposes only.
|
* provide settings for informational purposes only.
|
||||||
*/
|
*/
|
||||||
error = CPUFREQ_DRV_TYPE(devs[i], &type);
|
error = CPUFREQ_DRV_TYPE(devs[i], &type);
|
||||||
if (error || (type & CPUFREQ_FLAG_INFO_ONLY))
|
if (error || (type & CPUFREQ_FLAG_INFO_ONLY)) {
|
||||||
|
if (error == 0) {
|
||||||
|
CF_DEBUG("skipping info-only driver %s\n",
|
||||||
|
device_get_nameunit(devs[i]));
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
set_count = MAX_SETTINGS;
|
set_count = MAX_SETTINGS;
|
||||||
error = CPUFREQ_DRV_SETTINGS(devs[i], sets, &set_count);
|
error = CPUFREQ_DRV_SETTINGS(devs[i], sets, &set_count);
|
||||||
if (error || set_count == 0)
|
if (error || set_count == 0)
|
||||||
@ -471,6 +513,7 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count)
|
|||||||
error = cpufreq_insert_abs(sc, sets, set_count);
|
error = cpufreq_insert_abs(sc, sets, set_count);
|
||||||
break;
|
break;
|
||||||
case CPUFREQ_TYPE_RELATIVE:
|
case CPUFREQ_TYPE_RELATIVE:
|
||||||
|
CF_DEBUG("adding %d relative settings\n", set_count);
|
||||||
set_arr = malloc(sizeof(*set_arr), M_TEMP, M_NOWAIT);
|
set_arr = malloc(sizeof(*set_arr), M_TEMP, M_NOWAIT);
|
||||||
if (set_arr == NULL) {
|
if (set_arr == NULL) {
|
||||||
error = ENOMEM;
|
error = ENOMEM;
|
||||||
@ -482,7 +525,6 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
@ -578,12 +620,16 @@ cpufreq_insert_abs(struct cpufreq_softc *sc, struct cf_setting *sets,
|
|||||||
sc->all_count++;
|
sc->all_count++;
|
||||||
|
|
||||||
if (TAILQ_EMPTY(list)) {
|
if (TAILQ_EMPTY(list)) {
|
||||||
|
CF_DEBUG("adding abs setting %d at head\n",
|
||||||
|
sets[i].freq);
|
||||||
TAILQ_INSERT_HEAD(list, level, link);
|
TAILQ_INSERT_HEAD(list, level, link);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TAILQ_FOREACH_REVERSE(search, list, cf_level_lst, link) {
|
TAILQ_FOREACH_REVERSE(search, list, cf_level_lst, link) {
|
||||||
if (sets[i].freq <= search->total_set.freq) {
|
if (sets[i].freq <= search->total_set.freq) {
|
||||||
|
CF_DEBUG("adding abs setting %d after %d\n",
|
||||||
|
sets[i].freq, search->total_set.freq);
|
||||||
TAILQ_INSERT_AFTER(list, search, level, link);
|
TAILQ_INSERT_AFTER(list, search, level, link);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -610,8 +656,12 @@ cpufreq_expand_set(struct cpufreq_softc *sc, struct cf_setting_array *set_arr)
|
|||||||
if (search->rel_set[i].dev == set_arr->sets[0].dev)
|
if (search->rel_set[i].dev == set_arr->sets[0].dev)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i != search->rel_count)
|
if (i != search->rel_count) {
|
||||||
|
CF_DEBUG("skipping modified level, freq %d (dev %s)\n",
|
||||||
|
search->total_set.freq,
|
||||||
|
device_get_nameunit(search->rel_set[i].dev));
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add each setting to the level, duplicating if necessary. */
|
/* Add each setting to the level, duplicating if necessary. */
|
||||||
for (i = 0; i < set_arr->count; i++) {
|
for (i = 0; i < set_arr->count; i++) {
|
||||||
@ -638,6 +688,9 @@ cpufreq_expand_set(struct cpufreq_softc *sc, struct cf_setting_array *set_arr)
|
|||||||
MAX_SETTINGS));
|
MAX_SETTINGS));
|
||||||
fill->rel_set[fill->rel_count] = *set;
|
fill->rel_set[fill->rel_count] = *set;
|
||||||
fill->rel_count++;
|
fill->rel_count++;
|
||||||
|
CF_DEBUG(
|
||||||
|
"expand set added rel setting %d%% to %d level\n",
|
||||||
|
set->freq / 100, fill->total_set.freq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,6 +730,7 @@ cpufreq_dup_set(struct cpufreq_softc *sc, struct cf_level *dup,
|
|||||||
else
|
else
|
||||||
fill_set->lat = set->lat;
|
fill_set->lat = set->lat;
|
||||||
}
|
}
|
||||||
|
CF_DEBUG("dup set considering derived setting %d\n", fill_set->freq);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we copied an old level that we already modified (say, at 100%),
|
* If we copied an old level that we already modified (say, at 100%),
|
||||||
@ -687,6 +741,8 @@ cpufreq_dup_set(struct cpufreq_softc *sc, struct cf_level *dup,
|
|||||||
for (i = fill->rel_count; i != 0; i--) {
|
for (i = fill->rel_count; i != 0; i--) {
|
||||||
if (fill->rel_set[i - 1].dev != set->dev)
|
if (fill->rel_set[i - 1].dev != set->dev)
|
||||||
break;
|
break;
|
||||||
|
CF_DEBUG("removed last relative driver: %s\n",
|
||||||
|
device_get_nameunit(set->dev));
|
||||||
fill->rel_count--;
|
fill->rel_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,15 +756,22 @@ cpufreq_dup_set(struct cpufreq_softc *sc, struct cf_level *dup,
|
|||||||
*/
|
*/
|
||||||
list = &sc->all_levels;
|
list = &sc->all_levels;
|
||||||
if (TAILQ_EMPTY(list)) {
|
if (TAILQ_EMPTY(list)) {
|
||||||
|
CF_DEBUG("dup done, inserted %d at head\n", fill_set->freq);
|
||||||
TAILQ_INSERT_HEAD(list, fill, link);
|
TAILQ_INSERT_HEAD(list, fill, link);
|
||||||
} else {
|
} else {
|
||||||
TAILQ_FOREACH_REVERSE(itr, list, cf_level_lst, link) {
|
TAILQ_FOREACH_REVERSE(itr, list, cf_level_lst, link) {
|
||||||
itr_set = &itr->total_set;
|
itr_set = &itr->total_set;
|
||||||
if (CPUFREQ_CMP(fill_set->freq, itr_set->freq)) {
|
if (CPUFREQ_CMP(fill_set->freq, itr_set->freq)) {
|
||||||
|
CF_DEBUG(
|
||||||
|
"dup done, freeing new level %d, matches %d\n",
|
||||||
|
fill_set->freq, itr_set->freq);
|
||||||
free(fill, M_TEMP);
|
free(fill, M_TEMP);
|
||||||
fill = NULL;
|
fill = NULL;
|
||||||
break;
|
break;
|
||||||
} else if (fill_set->freq < itr_set->freq) {
|
} else if (fill_set->freq < itr_set->freq) {
|
||||||
|
CF_DEBUG(
|
||||||
|
"dup done, inserting new level %d after %d\n",
|
||||||
|
fill_set->freq, itr_set->freq);
|
||||||
TAILQ_INSERT_AFTER(list, itr, fill, link);
|
TAILQ_INSERT_AFTER(list, itr, fill, link);
|
||||||
sc->all_count++;
|
sc->all_count++;
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user