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:
Nate Lawson 2005-04-10 19:11:23 +00:00
parent bce9288570
commit 8d9134815e

View File

@ -83,6 +83,11 @@ TAILQ_HEAD(cf_setting_lst, cf_setting_array);
#define CF_MTX_UNLOCK(x) sx_xunlock((x))
#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_detach(device_t dev);
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 int cf_lowest_freq;
static int cf_verbose;
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_INT(_debug_cpufreq, OID_AUTO, lowest, CTLFLAG_RW, &cf_lowest_freq, 1,
"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
cpufreq_attach(device_t dev)
@ -132,6 +141,7 @@ cpufreq_attach(device_t dev)
device_t parent;
int numdevs;
CF_DEBUG("initializing %s\n", device_get_nameunit(dev));
sc = device_get_softc(dev);
parent = device_get_parent(dev);
sc->dev = dev;
@ -151,6 +161,8 @@ cpufreq_attach(device_t dev)
if (numdevs > 1)
return (0);
CF_DEBUG("initializing one-time data for %s\n",
device_get_nameunit(dev));
SYSCTL_ADD_PROC(&sc->sysctl_ctx,
SYSCTL_CHILDREN(device_get_sysctl_tree(parent)),
OID_AUTO, "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
@ -171,13 +183,16 @@ cpufreq_detach(device_t dev)
struct cpufreq_softc *sc;
int numdevs;
CF_DEBUG("shutdown %s\n", device_get_nameunit(dev));
sc = device_get_softc(dev);
sysctl_ctx_free(&sc->sysctl_ctx);
/* Only clean up these resources when the last device is detaching. */
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);
}
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) {
level = &sc->saved_level;
priority = sc->saved_priority;
CF_DEBUG("restoring saved level, freq %d prio %d\n",
level->total_set.freq, priority);
} else {
CF_DEBUG("NULL level, no saved level\n");
error = ENXIO;
goto out;
}
} else if (priority < sc->curr_priority) {
CF_DEBUG("ignoring, curr prio %d less than %d\n", priority,
sc->curr_priority);
error = EPERM;
goto out;
}
/* Reject levels that are below our specified threshold. */
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;
goto out;
}
/* 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;
}
/* First, set the absolute frequency via its driver. */
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);
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);
if (cpu_id != pc->pc_cpuid) {
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);
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);
if (cpu_id != pc->pc_cpuid) {
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 (level == &sc->saved_level) {
CF_DEBUG("resetting saved level\n");
sc->saved_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
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 &&
sc->saved_level.total_set.freq == CPUFREQ_VAL_UNKNOWN &&
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_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. */
CF_MTX_LOCK(&sc->lock);
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;
}
CF_MTX_UNLOCK(&sc->lock);
/*
@ -388,8 +422,10 @@ cf_get_method(device_t dev, struct cf_level *level)
}
}
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;
}
/*
* 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++) {
if (CPUFREQ_CMP(rate, levels[i].total_set.freq)) {
sc->curr_level = levels[i];
CF_DEBUG("get estimated freq %d\n", curr_set->freq);
break;
}
}
@ -458,8 +495,13 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count)
* provide settings for informational purposes only.
*/
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;
}
set_count = MAX_SETTINGS;
error = CPUFREQ_DRV_SETTINGS(devs[i], sets, &set_count);
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);
break;
case CPUFREQ_TYPE_RELATIVE:
CF_DEBUG("adding %d relative settings\n", set_count);
set_arr = malloc(sizeof(*set_arr), M_TEMP, M_NOWAIT);
if (set_arr == NULL) {
error = ENOMEM;
@ -482,7 +525,6 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count)
break;
default:
error = EINVAL;
break;
}
if (error)
goto out;
@ -578,12 +620,16 @@ cpufreq_insert_abs(struct cpufreq_softc *sc, struct cf_setting *sets,
sc->all_count++;
if (TAILQ_EMPTY(list)) {
CF_DEBUG("adding abs setting %d at head\n",
sets[i].freq);
TAILQ_INSERT_HEAD(list, level, link);
continue;
}
TAILQ_FOREACH_REVERSE(search, list, cf_level_lst, link) {
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);
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)
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;
}
/* Add each setting to the level, duplicating if necessary. */
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));
fill->rel_set[fill->rel_count] = *set;
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
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%),
@ -687,6 +741,8 @@ cpufreq_dup_set(struct cpufreq_softc *sc, struct cf_level *dup,
for (i = fill->rel_count; i != 0; i--) {
if (fill->rel_set[i - 1].dev != set->dev)
break;
CF_DEBUG("removed last relative driver: %s\n",
device_get_nameunit(set->dev));
fill->rel_count--;
}
@ -700,15 +756,22 @@ cpufreq_dup_set(struct cpufreq_softc *sc, struct cf_level *dup,
*/
list = &sc->all_levels;
if (TAILQ_EMPTY(list)) {
CF_DEBUG("dup done, inserted %d at head\n", fill_set->freq);
TAILQ_INSERT_HEAD(list, fill, link);
} else {
TAILQ_FOREACH_REVERSE(itr, list, cf_level_lst, link) {
itr_set = &itr->total_set;
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);
fill = NULL;
break;
} 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);
sc->all_count++;
break;