* This is called as the result of a hardware specific frequency control driver * calling cpufreq_register. It provides a general interface for system wide * frequency controls and operates on a per cpu basis. */
| 149 | * frequency controls and operates on a per cpu basis. |
| 150 | */ |
| 151 | static int |
| 152 | cpufreq_attach(device_t dev) |
| 153 | { |
| 154 | struct cpufreq_softc *sc; |
| 155 | struct pcpu *pc; |
| 156 | device_t parent; |
| 157 | uint64_t rate; |
| 158 | |
| 159 | CF_DEBUG("initializing %s\n", device_get_nameunit(dev)); |
| 160 | sc = device_get_softc(dev); |
| 161 | parent = device_get_parent(dev); |
| 162 | sc->dev = dev; |
| 163 | sysctl_ctx_init(&sc->sysctl_ctx); |
| 164 | TAILQ_INIT(&sc->all_levels); |
| 165 | CF_MTX_INIT(&sc->lock); |
| 166 | sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN; |
| 167 | SLIST_INIT(&sc->saved_freq); |
| 168 | /* Try to get nominal CPU freq to use it as maximum later if needed */ |
| 169 | sc->max_mhz = cpu_get_nominal_mhz(dev); |
| 170 | /* If that fails, try to measure the current rate */ |
| 171 | if (sc->max_mhz <= 0) { |
| 172 | CF_DEBUG("Unable to obtain nominal frequency.\n"); |
| 173 | pc = cpu_get_pcpu(dev); |
| 174 | if (cpu_est_clockrate(pc->pc_cpuid, &rate) == 0) |
| 175 | sc->max_mhz = rate / 1000000; |
| 176 | else |
| 177 | sc->max_mhz = CPUFREQ_VAL_UNKNOWN; |
| 178 | } |
| 179 | |
| 180 | CF_DEBUG("initializing one-time data for %s\n", |
| 181 | device_get_nameunit(dev)); |
| 182 | sc->levels_buf = malloc(CF_MAX_LEVELS * sizeof(*sc->levels_buf), |
| 183 | M_DEVBUF, M_WAITOK); |
| 184 | SYSCTL_ADD_PROC(&sc->sysctl_ctx, |
| 185 | SYSCTL_CHILDREN(device_get_sysctl_tree(parent)), |
| 186 | OID_AUTO, "freq", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, |
| 187 | sc, 0, cpufreq_curr_sysctl, "I", "Current CPU frequency"); |
| 188 | SYSCTL_ADD_PROC(&sc->sysctl_ctx, |
| 189 | SYSCTL_CHILDREN(device_get_sysctl_tree(parent)), |
| 190 | OID_AUTO, "freq_levels", |
| 191 | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0, |
| 192 | cpufreq_levels_sysctl, "A", "CPU frequency levels"); |
| 193 | |
| 194 | /* |
| 195 | * Queue a one-shot broadcast that levels have changed. |
| 196 | * It will run once the system has completed booting. |
| 197 | */ |
| 198 | TASK_INIT(&sc->startup_task, 0, cpufreq_startup_task, dev); |
| 199 | taskqueue_enqueue(taskqueue_thread, &sc->startup_task); |
| 200 | |
| 201 | return (0); |
| 202 | } |
| 203 | |
| 204 | /* Handle any work to be done for all drivers that attached during boot. */ |
| 205 | static void |
nothing calls this directly
no test coverage detected