|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/dev/cpufreq/cpufreq.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
1 /* 2 * Copyright (c) 2007-2009, Kohsuke Ohtani 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * cpufreq.c - CPU frequency control driver 32 */ 33 34 /* 35 * Dynamic voltage scaling (DVS) 36 * 37 * DVS is widely used with mobile systems to save the processor 38 * power consumption, with minimum impact on performance. 39 * The basic idea is come from the fact the power consumption is 40 * proportional to V^2 x f, where V is voltage and f is frequency. 41 * Since processor does not always require the full performance, 42 * we can reduce power consumption by lowering voltage and frequeceny. 43 */ 44 45 #include <sys/ioctl.h> 46 #include <sys/power.h> 47 #include <driver.h> 48 #include <sys/sysinfo.h> 49 #include <devctl.h> 50 #include <cpufreq.h> 51 52 /* #define DEBUG_CPUFREQ 1 */ 53 54 #ifdef DEBUG_CPUFREQ 55 #define DPRINTF(a) printf a 56 #else 57 #define DPRINTF(a) 58 #endif 59 60 /* 61 * DVS parameters 62 */ 63 #define SAMPLING_RATE 50 /* msec */ 64 #define SAMPLING_TICK mstohz(SAMPLING_RATE) 65 #define WEIGHT 3 66 67 struct cpufreq_softc { 68 int enable; /* true if enabled */ 69 device_t dev; /* device object */ 70 struct timer timer; /* performance sampling timer */ 71 struct cpufreq_ops *ops; /* low level h/w operations */ 72 }; 73 74 static int cpufreq_ioctl(device_t, u_long, void *); 75 static int cpufreq_devctl(device_t, u_long, void *); 76 static int cpufreq_init(struct driver *); 77 78 79 static struct devops cpufreq_devops= { 80 /* open */ no_open, 81 /* close */ no_close, 82 /* read */ no_read, 83 /* write */ no_write, 84 /* ioctl */ cpufreq_ioctl, 85 /* devctl */ cpufreq_devctl, 86 }; 87 88 struct driver cpufreq_driver = { 89 /* name */ "cpufreq", 90 /* devops */ &cpufreq_devops, 91 /* devsz */ sizeof(struct cpufreq_softc), 92 /* flags */ 0, 93 /* probe */ NULL, 94 /* init */ cpufreq_init, 95 /* shutdown */ NULL, 96 }; 97 98 /* 99 * DVS related data 100 */ 101 static u_long last_cputicks; 102 static u_long last_idleticks; 103 static int cur_speed; /* current CPU speed (%) */ 104 static int max_speed; /* maximum CPU speed (%) */ 105 static int min_speed; /* minimum CPU speed (%) */ 106 static u_long avg_workload; /* average workload */ 107 static u_long avg_deadline; /* average deadline */ 108 static u_long excess_cycles; /* cycles left over from the last interval */ 109 110 /* 111 * Predict max CPU speed. 112 * 113 * DVS Algorithm: AVG<3> 114 * 115 * Computes an exponentially moving average of the previous intervals. 116 * <wight> is the relative weighting of past intervals relative to 117 * the current interval. 118 * 119 * predict = (weight x current + past) / (weight + 1) 120 * 121 * Refernce: 122 * K.Govil, E.Chan, H.Wasserman, 123 * "Comparing Algorithm for Dynamic Speed-Setting of a Low-Power CPU". 124 * Proc. 1st Int'l Conference on Mobile Computing and Networking, 125 * Nov 1995. 126 */ 127 static void 128 cpufreq_predict_max_speed(u_long run_cycles, u_long idle_cycles) 129 { 130 u_long new_workload, new_deadline; 131 132 new_workload = run_cycles * cur_speed; 133 new_deadline = (run_cycles + idle_cycles) * cur_speed; 134 135 avg_workload = (avg_workload * WEIGHT + new_workload) / (WEIGHT + 1); 136 avg_deadline = (avg_deadline * WEIGHT + new_deadline) / (WEIGHT + 1); 137 138 max_speed = (int)(avg_workload * 100 / avg_deadline); 139 if (max_speed < 50) 140 max_speed = 50; 141 142 DPRINTF(("cpufreq: new_workload=%u new_deadline=%u\n", 143 new_workload, new_deadline)); 144 DPRINTF(("cpufreq: avg_workload=%u avg_deadline=%u\n", 145 avg_workload, avg_deadline)); 146 DPRINTF(("cpufreq: max_speed=%d\n", max_speed)); 147 } 148 149 /* 150 * Predict CPU speed. 151 * 152 * DVS Algorithm: Weiser Style 153 * 154 * If the utilization prediction x is high (over 70%), increase the 155 * speed by 20% of the maximum speed. If the utilization prediction 156 * is low (under 50%), decrease the speed by (60 - x)% of the 157 * maximum speed. 158 * 159 * excess_cycles is defined as the number of uncompleted run cycles 160 * from the last interval. For example, if we find 70% activity 161 * when runnig at full speed, and their processor speed was set to 162 * 50% during that interval, excess_cycles is set to 20%. This 163 * value (20%) is used to calculate the processor speed in the next 164 * interval. 165 * 166 * Refernce: 167 * M.Weiser, B.Welch, A.Demers, and S.Shenker, 168 * "Scheduling for Reduced CPU Energy", In Proceedings of the 169 * 1st Symposium on Operating Systems Design and Implementation, 170 * pages 13-23, November 1994. 171 */ 172 static int 173 cpufreq_predict_cpu_speed(u_long run_cycles, u_long idle_cycles) 174 { 175 u_long next_excess; 176 u_int run_percent; 177 u_int new_speed = cur_speed; 178 179 run_cycles += excess_cycles; 180 run_percent = (int)((run_cycles * 100) / (idle_cycles + run_cycles)); 181 182 next_excess = run_cycles - 183 cur_speed * (run_cycles + idle_cycles) / 100; 184 if (next_excess < 0) 185 next_excess = 0; 186 187 if (excess_cycles > idle_cycles) 188 new_speed = 100; 189 else if (run_percent > 70) 190 new_speed = cur_speed + 20; 191 else if (run_percent < 50) 192 new_speed = cur_speed - (60 - run_percent); 193 194 if (new_speed > max_speed) 195 new_speed = max_speed; 196 if (new_speed < min_speed) 197 new_speed = min_speed; 198 199 DPRINTF(("cpufreq: run_percent=%d next_excess=%d new_speed=%d\n\n", 200 run_percent, next_excess, new_speed)); 201 202 excess_cycles = next_excess; 203 204 return new_speed; 205 } 206 207 /* 208 * Timer callback routine. 209 */ 210 static void 211 cpufreq_timeout(void *arg) 212 { 213 struct cpufreq_softc *sc = arg; 214 struct timerinfo info; 215 int new_speed; 216 u_long idle_cycles, run_cycles; 217 218 /* 219 * Get run/idle cycles. 220 */ 221 sysinfo(INFO_TIMER, &info); 222 idle_cycles = info.idleticks - last_idleticks; 223 run_cycles = info.cputicks - last_cputicks - idle_cycles; 224 225 DPRINTF(("cpufreq: run_cycles=%d idle_cycles=%d cur_speed=%d\n", 226 run_cycles, idle_cycles, cur_speed)); 227 228 /* 229 * Predict max CPU speed. 230 */ 231 cpufreq_predict_max_speed(run_cycles, idle_cycles); 232 233 /* 234 * Predict next CPU speed. 235 */ 236 new_speed = cpufreq_predict_cpu_speed(run_cycles, idle_cycles); 237 if (new_speed != cur_speed) { 238 sc->ops->setperf(new_speed); 239 cur_speed = sc->ops->getperf(); 240 } 241 242 last_cputicks = info.cputicks; 243 last_idleticks = info.idleticks; 244 245 timer_callout(&sc->timer, SAMPLING_RATE, &cpufreq_timeout, sc); 246 } 247 248 /* 249 * Enable DVS operation 250 */ 251 static void 252 cpufreq_enable(struct cpufreq_softc *sc) 253 { 254 struct timerinfo info; 255 256 ASSERT(sc->ops != NULL); 257 258 DPRINTF(("cpufreq: enable\n")); 259 260 if (sc->enable) 261 return; 262 sc->enable = 1; 263 264 /* 265 * Initialize DVS parameters. 266 */ 267 sysinfo(INFO_TIMER, &info); 268 last_cputicks = info.cputicks; 269 last_idleticks = info.idleticks; 270 271 max_speed = 100; /* max 100% */ 272 min_speed = 5; /* min 5% */ 273 cur_speed = sc->ops->getperf(); 274 275 excess_cycles = 0; 276 avg_workload = SAMPLING_TICK * 100; 277 avg_deadline = SAMPLING_TICK * 100; 278 279 timer_callout(&sc->timer, SAMPLING_RATE, &cpufreq_timeout, sc); 280 } 281 282 /* 283 * Disable DVS operation 284 */ 285 static void 286 cpufreq_disable(struct cpufreq_softc *sc) 287 { 288 289 DPRINTF(("cpufreq: disable\n")); 290 291 if (!sc->enable) 292 return; 293 sc->enable = 0; 294 295 timer_stop(&sc->timer); 296 297 /* Set CPU speed to 100% */ 298 sc->ops->setperf(100); 299 cur_speed = 100; 300 } 301 302 static int 303 cpufreq_ioctl(device_t dev, u_long cmd, void *arg) 304 { 305 struct cpufreq_softc *sc = device_private(dev); 306 struct cpufreqinfo info; 307 308 if (sc->ops == NULL) 309 return EINVAL; 310 311 switch (cmd) { 312 case CFIOC_GET_INFO: 313 sc->ops->getinfo(&info); 314 if (copyout(&info, arg, sizeof(info))) 315 return EFAULT; 316 break; 317 default: 318 return EINVAL; 319 } 320 return 0; 321 } 322 323 static int 324 cpufreq_devctl(device_t dev, u_long cmd, void *arg) 325 { 326 struct cpufreq_softc *sc = device_private(dev); 327 int error = 0; 328 int policy; 329 330 DPRINTF(("cpufreq: devctl cmd=%d\n", cmd)); 331 332 if (sc->ops == NULL) 333 return 0; 334 335 switch (cmd) { 336 case DEVCTL_PM_CHGPOLICY: 337 DPRINTF(("cpufreq: change policy\n")); 338 policy = *(int *)arg; 339 DPRINTF(("cpufreq: policy=%d\n", policy)); 340 if (policy == PM_POWERSAVE) 341 cpufreq_enable(sc); 342 else 343 cpufreq_disable(sc); 344 break; 345 } 346 return error; 347 } 348 349 void 350 cpufreq_attach(struct cpufreq_ops *ops) 351 { 352 struct cpufreq_softc *sc; 353 device_t dev; 354 int policy; 355 356 DPRINTF(("cpufreq: attach ops=%x\n", ops)); 357 358 dev = device_create(&cpufreq_driver, "cpufreq", D_CHR|D_PROT); 359 360 sc = device_private(dev); 361 sc->dev = dev; 362 sc->enable = 0; 363 sc->ops = ops; 364 cur_speed = 100; 365 366 policy = DEFAULT_POWER_POLICY; 367 if (policy == PM_POWERSAVE) 368 cpufreq_enable(sc); 369 } 370 371 static int 372 cpufreq_init(struct driver *self) 373 { 374 375 return 0; 376 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |