Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/drivers/cpufreq/cpufreq.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
3
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
4
 *  Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
5
 *  Copyright (C) 2006        Denis Sadykov <denis.m.sadykov@intel.com>
6
 *
7
 *  Feb 2008 - Liu Jinsong <jinsong.liu@intel.com>
8
 *      Add cpufreq limit change handle and per-cpu cpufreq add/del
9
 *      to cope with cpu hotplug
10
 *
11
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12
 *
13
 *  This program is free software; you can redistribute it and/or modify
14
 *  it under the terms of the GNU General Public License as published by
15
 *  the Free Software Foundation; either version 2 of the License, or (at
16
 *  your option) any later version.
17
 *
18
 *  This program is distributed in the hope that it will be useful, but
19
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21
 *  General Public License for more details.
22
 *
23
 *  You should have received a copy of the GNU General Public License along
24
 *  with this program; If not, see <http://www.gnu.org/licenses/>.
25
 *
26
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27
 */
28
29
#include <xen/types.h>
30
#include <xen/errno.h>
31
#include <xen/delay.h>
32
#include <xen/cpumask.h>
33
#include <xen/list.h>
34
#include <xen/sched.h>
35
#include <xen/string.h>
36
#include <xen/timer.h>
37
#include <xen/xmalloc.h>
38
#include <xen/guest_access.h>
39
#include <xen/domain.h>
40
#include <xen/cpu.h>
41
#include <asm/bug.h>
42
#include <asm/io.h>
43
#include <asm/processor.h>
44
#include <asm/percpu.h>
45
#include <acpi/acpi.h>
46
#include <acpi/cpufreq/cpufreq.h>
47
48
static unsigned int __read_mostly usr_min_freq;
49
static unsigned int __read_mostly usr_max_freq;
50
static void cpufreq_cmdline_common_para(struct cpufreq_policy *new_policy);
51
52
struct cpufreq_dom {
53
    unsigned int  dom;
54
    cpumask_var_t map;
55
    struct list_head  node;
56
};
57
static LIST_HEAD_READ_MOSTLY(cpufreq_dom_list_head);
58
59
struct cpufreq_governor *__read_mostly cpufreq_opt_governor;
60
LIST_HEAD_READ_MOSTLY(cpufreq_governor_list);
61
62
/* set xen as default cpufreq */
63
enum cpufreq_controller cpufreq_controller = FREQCTL_xen;
64
65
static int __init cpufreq_cmdline_parse(const char *s);
66
67
static int __init setup_cpufreq_option(const char *str)
68
0
{
69
0
    const char *arg = strpbrk(str, ",:");
70
0
    int choice;
71
0
72
0
    if ( !arg )
73
0
        arg = strchr(str, '\0');
74
0
    choice = parse_bool(str, arg);
75
0
76
0
    if ( choice < 0 && !strncmp(str, "dom0-kernel", arg - str) )
77
0
    {
78
0
        xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
79
0
        cpufreq_controller = FREQCTL_dom0_kernel;
80
0
        opt_dom0_vcpus_pin = 1;
81
0
        return 0;
82
0
    }
83
0
84
0
    if ( choice == 0 || !strncmp(str, "none", arg - str) )
85
0
    {
86
0
        xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
87
0
        cpufreq_controller = FREQCTL_none;
88
0
        return 0;
89
0
    }
90
0
91
0
    if ( choice > 0 || !strncmp(str, "xen", arg - str) )
92
0
    {
93
0
        xen_processor_pmbits |= XEN_PROCESSOR_PM_PX;
94
0
        cpufreq_controller = FREQCTL_xen;
95
0
        if ( *arg && *(arg + 1) )
96
0
            return cpufreq_cmdline_parse(arg + 1);
97
0
    }
98
0
99
0
    return (choice < 0) ? -EINVAL : 0;
100
0
}
101
custom_param("cpufreq", setup_cpufreq_option);
102
103
bool_t __read_mostly cpufreq_verbose;
104
105
struct cpufreq_governor *__find_governor(const char *governor)
106
4
{
107
4
    struct cpufreq_governor *t;
108
4
109
4
    if (!governor)
110
0
        return NULL;
111
4
112
4
    list_for_each_entry(t, &cpufreq_governor_list, governor_list)
113
6
        if (!strnicmp(governor, t->name, CPUFREQ_NAME_LEN))
114
0
            return t;
115
4
116
4
    return NULL;
117
4
}
118
119
int __init cpufreq_register_governor(struct cpufreq_governor *governor)
120
4
{
121
4
    if (!governor)
122
0
        return -EINVAL;
123
4
124
4
    if (__find_governor(governor->name) != NULL)
125
0
        return -EEXIST;
126
4
127
4
    list_add(&governor->governor_list, &cpufreq_governor_list);
128
4
    return 0;
129
4
}
130
131
int cpufreq_limit_change(unsigned int cpu)
132
0
{
133
0
    struct processor_performance *perf;
134
0
    struct cpufreq_policy *data;
135
0
    struct cpufreq_policy policy;
136
0
137
0
    if (!cpu_online(cpu) || !(data = per_cpu(cpufreq_cpu_policy, cpu)) ||
138
0
        !processor_pminfo[cpu])
139
0
        return -ENODEV;
140
0
141
0
    perf = &processor_pminfo[cpu]->perf;
142
0
143
0
    if (perf->platform_limit >= perf->state_count)
144
0
        return -EINVAL;
145
0
146
0
    memcpy(&policy, data, sizeof(struct cpufreq_policy)); 
147
0
148
0
    policy.max =
149
0
        perf->states[perf->platform_limit].core_frequency * 1000;
150
0
151
0
    return __cpufreq_set_policy(data, &policy);
152
0
}
153
154
int cpufreq_add_cpu(unsigned int cpu)
155
11
{
156
11
    int ret = 0;
157
11
    unsigned int firstcpu;
158
11
    unsigned int dom, domexist = 0;
159
11
    unsigned int hw_all = 0;
160
11
    struct list_head *pos;
161
11
    struct cpufreq_dom *cpufreq_dom = NULL;
162
11
    struct cpufreq_policy new_policy;
163
11
    struct cpufreq_policy *policy;
164
11
    struct processor_performance *perf;
165
11
166
11
    /* to protect the case when Px was not controlled by xen */
167
11
    if ( !processor_pminfo[cpu] || !cpu_online(cpu) )
168
11
        return -EINVAL;
169
11
170
0
    perf = &processor_pminfo[cpu]->perf;
171
0
172
0
    if ( !(perf->init & XEN_PX_INIT) )
173
0
        return -EINVAL;
174
0
175
0
    if (!cpufreq_driver)
176
0
        return 0;
177
0
178
0
    if (per_cpu(cpufreq_cpu_policy, cpu))
179
0
        return 0;
180
0
181
0
    if (perf->shared_type == CPUFREQ_SHARED_TYPE_HW)
182
0
        hw_all = 1;
183
0
184
0
    dom = perf->domain_info.domain;
185
0
186
0
    list_for_each(pos, &cpufreq_dom_list_head) {
187
0
        cpufreq_dom = list_entry(pos, struct cpufreq_dom, node);
188
0
        if (dom == cpufreq_dom->dom) {
189
0
            domexist = 1;
190
0
            break;
191
0
        }
192
0
    }
193
0
194
0
    if (!domexist) {
195
0
        cpufreq_dom = xzalloc(struct cpufreq_dom);
196
0
        if (!cpufreq_dom)
197
0
            return -ENOMEM;
198
0
199
0
        if (!zalloc_cpumask_var(&cpufreq_dom->map)) {
200
0
            xfree(cpufreq_dom);
201
0
            return -ENOMEM;
202
0
        }
203
0
204
0
        cpufreq_dom->dom = dom;
205
0
        list_add(&cpufreq_dom->node, &cpufreq_dom_list_head);
206
0
    } else {
207
0
        /* domain sanity check under whatever coordination type */
208
0
        firstcpu = cpumask_first(cpufreq_dom->map);
209
0
        if ((perf->domain_info.coord_type !=
210
0
            processor_pminfo[firstcpu]->perf.domain_info.coord_type) ||
211
0
            (perf->domain_info.num_processors !=
212
0
            processor_pminfo[firstcpu]->perf.domain_info.num_processors)) {
213
0
214
0
            printk(KERN_WARNING "cpufreq fail to add CPU%d:"
215
0
                   "incorrect _PSD(%"PRIu64":%"PRIu64"), "
216
0
                   "expect(%"PRIu64"/%"PRIu64")\n",
217
0
                   cpu, perf->domain_info.coord_type,
218
0
                   perf->domain_info.num_processors,
219
0
                   processor_pminfo[firstcpu]->perf.domain_info.coord_type,
220
0
                   processor_pminfo[firstcpu]->perf.domain_info.num_processors
221
0
                );
222
0
            return -EINVAL;
223
0
        }
224
0
    }
225
0
226
0
    if (!domexist || hw_all) {
227
0
        policy = xzalloc(struct cpufreq_policy);
228
0
        if (!policy) {
229
0
            ret = -ENOMEM;
230
0
            goto err0;
231
0
        }
232
0
233
0
        if (!zalloc_cpumask_var(&policy->cpus)) {
234
0
            xfree(policy);
235
0
            ret = -ENOMEM;
236
0
            goto err0;
237
0
        }
238
0
239
0
        policy->cpu = cpu;
240
0
        per_cpu(cpufreq_cpu_policy, cpu) = policy;
241
0
242
0
        ret = cpufreq_driver->init(policy);
243
0
        if (ret) {
244
0
            free_cpumask_var(policy->cpus);
245
0
            xfree(policy);
246
0
            per_cpu(cpufreq_cpu_policy, cpu) = NULL;
247
0
            goto err0;
248
0
        }
249
0
        if (cpufreq_verbose)
250
0
            printk("CPU %u initialization completed\n", cpu);
251
0
    } else {
252
0
        firstcpu = cpumask_first(cpufreq_dom->map);
253
0
        policy = per_cpu(cpufreq_cpu_policy, firstcpu);
254
0
255
0
        per_cpu(cpufreq_cpu_policy, cpu) = policy;
256
0
        if (cpufreq_verbose)
257
0
            printk("adding CPU %u\n", cpu);
258
0
    }
259
0
260
0
    cpumask_set_cpu(cpu, policy->cpus);
261
0
    cpumask_set_cpu(cpu, cpufreq_dom->map);
262
0
263
0
    ret = cpufreq_statistic_init(cpu);
264
0
    if (ret)
265
0
        goto err1;
266
0
267
0
    if (hw_all || (cpumask_weight(cpufreq_dom->map) ==
268
0
                   perf->domain_info.num_processors)) {
269
0
        memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
270
0
        policy->governor = NULL;
271
0
272
0
        cpufreq_cmdline_common_para(&new_policy);
273
0
274
0
        ret = __cpufreq_set_policy(policy, &new_policy);
275
0
        if (ret) {
276
0
            if (new_policy.governor == CPUFREQ_DEFAULT_GOVERNOR)
277
0
                /* if default governor fail, cpufreq really meet troubles */
278
0
                goto err2;
279
0
            else {
280
0
                /* grub option governor fail */
281
0
                /* give one more chance to default gov */
282
0
                memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
283
0
                new_policy.governor = CPUFREQ_DEFAULT_GOVERNOR;
284
0
                ret = __cpufreq_set_policy(policy, &new_policy);
285
0
                if (ret)
286
0
                    goto err2;
287
0
            }
288
0
        }
289
0
    }
290
0
291
0
    return 0;
292
0
293
0
err2:
294
0
    cpufreq_statistic_exit(cpu);
295
0
err1:
296
0
    per_cpu(cpufreq_cpu_policy, cpu) = NULL;
297
0
    cpumask_clear_cpu(cpu, policy->cpus);
298
0
    cpumask_clear_cpu(cpu, cpufreq_dom->map);
299
0
300
0
    if (cpumask_empty(policy->cpus)) {
301
0
        cpufreq_driver->exit(policy);
302
0
        free_cpumask_var(policy->cpus);
303
0
        xfree(policy);
304
0
    }
305
0
err0:
306
0
    if (cpumask_empty(cpufreq_dom->map)) {
307
0
        list_del(&cpufreq_dom->node);
308
0
        free_cpumask_var(cpufreq_dom->map);
309
0
        xfree(cpufreq_dom);
310
0
    }
311
0
312
0
    return ret;
313
0
}
314
315
int cpufreq_del_cpu(unsigned int cpu)
316
0
{
317
0
    unsigned int dom, domexist = 0;
318
0
    unsigned int hw_all = 0;
319
0
    struct list_head *pos;
320
0
    struct cpufreq_dom *cpufreq_dom = NULL;
321
0
    struct cpufreq_policy *policy;
322
0
    struct processor_performance *perf;
323
0
324
0
    /* to protect the case when Px was not controlled by xen */
325
0
    if ( !processor_pminfo[cpu] || !cpu_online(cpu) )
326
0
        return -EINVAL;
327
0
328
0
    perf = &processor_pminfo[cpu]->perf;
329
0
330
0
    if ( !(perf->init & XEN_PX_INIT) )
331
0
        return -EINVAL;
332
0
333
0
    if (!per_cpu(cpufreq_cpu_policy, cpu))
334
0
        return 0;
335
0
336
0
    if (perf->shared_type == CPUFREQ_SHARED_TYPE_HW)
337
0
        hw_all = 1;
338
0
339
0
    dom = perf->domain_info.domain;
340
0
    policy = per_cpu(cpufreq_cpu_policy, cpu);
341
0
342
0
    list_for_each(pos, &cpufreq_dom_list_head) {
343
0
        cpufreq_dom = list_entry(pos, struct cpufreq_dom, node);
344
0
        if (dom == cpufreq_dom->dom) {
345
0
            domexist = 1;
346
0
            break;
347
0
        }
348
0
    }
349
0
350
0
    if (!domexist)
351
0
        return -EINVAL;
352
0
353
0
    /* for HW_ALL, stop gov for each core of the _PSD domain */
354
0
    /* for SW_ALL & SW_ANY, stop gov for the 1st core of the _PSD domain */
355
0
    if (hw_all || (cpumask_weight(cpufreq_dom->map) ==
356
0
                   perf->domain_info.num_processors))
357
0
        __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
358
0
359
0
    cpufreq_statistic_exit(cpu);
360
0
    per_cpu(cpufreq_cpu_policy, cpu) = NULL;
361
0
    cpumask_clear_cpu(cpu, policy->cpus);
362
0
    cpumask_clear_cpu(cpu, cpufreq_dom->map);
363
0
364
0
    if (cpumask_empty(policy->cpus)) {
365
0
        cpufreq_driver->exit(policy);
366
0
        free_cpumask_var(policy->cpus);
367
0
        xfree(policy);
368
0
    }
369
0
370
0
    /* for the last cpu of the domain, clean room */
371
0
    /* It's safe here to free freq_table, drv_data and policy */
372
0
    if (cpumask_empty(cpufreq_dom->map)) {
373
0
        list_del(&cpufreq_dom->node);
374
0
        free_cpumask_var(cpufreq_dom->map);
375
0
        xfree(cpufreq_dom);
376
0
    }
377
0
378
0
    if (cpufreq_verbose)
379
0
        printk("deleting CPU %u\n", cpu);
380
0
    return 0;
381
0
}
382
383
static void print_PCT(struct xen_pct_register *ptr)
384
0
{
385
0
    printk("\t_PCT: descriptor=%d, length=%d, space_id=%d, "
386
0
           "bit_width=%d, bit_offset=%d, reserved=%d, address=%"PRId64"\n",
387
0
           ptr->descriptor, ptr->length, ptr->space_id, ptr->bit_width,
388
0
           ptr->bit_offset, ptr->reserved, ptr->address);
389
0
}
390
391
static void print_PSS(struct xen_processor_px *ptr, int count)
392
0
{
393
0
    int i;
394
0
    printk("\t_PSS: state_count=%d\n", count);
395
0
    for (i=0; i<count; i++){
396
0
        printk("\tState%d: %"PRId64"MHz %"PRId64"mW %"PRId64"us "
397
0
               "%"PRId64"us %#"PRIx64" %#"PRIx64"\n",
398
0
               i,
399
0
               ptr[i].core_frequency,
400
0
               ptr[i].power,
401
0
               ptr[i].transition_latency,
402
0
               ptr[i].bus_master_latency,
403
0
               ptr[i].control,
404
0
               ptr[i].status);
405
0
    }
406
0
}
407
408
static void print_PSD( struct xen_psd_package *ptr)
409
0
{
410
0
    printk("\t_PSD: num_entries=%"PRId64" rev=%"PRId64
411
0
           " domain=%"PRId64" coord_type=%"PRId64" num_processors=%"PRId64"\n",
412
0
           ptr->num_entries, ptr->revision, ptr->domain, ptr->coord_type,
413
0
           ptr->num_processors);
414
0
}
415
416
static void print_PPC(unsigned int platform_limit)
417
0
{
418
0
    printk("\t_PPC: %d\n", platform_limit);
419
0
}
420
421
int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *dom0_px_info)
422
0
{
423
0
    int ret=0, cpuid;
424
0
    struct processor_pminfo *pmpt;
425
0
    struct processor_performance *pxpt;
426
0
427
0
    cpuid = get_cpu_id(acpi_id);
428
0
    if ( cpuid < 0 || !dom0_px_info)
429
0
    {
430
0
        ret = -EINVAL;
431
0
        goto out;
432
0
    }
433
0
    if ( cpufreq_verbose )
434
0
        printk("Set CPU acpi_id(%d) cpuid(%d) Px State info:\n",
435
0
               acpi_id, cpuid);
436
0
437
0
    pmpt = processor_pminfo[cpuid];
438
0
    if ( !pmpt )
439
0
    {
440
0
        pmpt = xzalloc(struct processor_pminfo);
441
0
        if ( !pmpt )
442
0
        {
443
0
            ret = -ENOMEM;
444
0
            goto out;
445
0
        }
446
0
        processor_pminfo[cpuid] = pmpt;
447
0
    }
448
0
    pxpt = &pmpt->perf;
449
0
    pmpt->acpi_id = acpi_id;
450
0
    pmpt->id = cpuid;
451
0
452
0
    if ( dom0_px_info->flags & XEN_PX_PCT )
453
0
    {
454
0
        /* space_id check */
455
0
        if (dom0_px_info->control_register.space_id != 
456
0
            dom0_px_info->status_register.space_id)
457
0
        {
458
0
            ret = -EINVAL;
459
0
            goto out;
460
0
        }
461
0
462
0
        memcpy ((void *)&pxpt->control_register,
463
0
                (void *)&dom0_px_info->control_register,
464
0
                sizeof(struct xen_pct_register));
465
0
        memcpy ((void *)&pxpt->status_register,
466
0
                (void *)&dom0_px_info->status_register,
467
0
                sizeof(struct xen_pct_register));
468
0
469
0
        if ( cpufreq_verbose )
470
0
        {
471
0
            print_PCT(&pxpt->control_register);
472
0
            print_PCT(&pxpt->status_register);
473
0
        }
474
0
    }
475
0
476
0
    if ( dom0_px_info->flags & XEN_PX_PSS ) 
477
0
    {
478
0
        /* capability check */
479
0
        if (dom0_px_info->state_count <= 1)
480
0
        {
481
0
            ret = -EINVAL;
482
0
            goto out;
483
0
        }
484
0
485
0
        if ( !(pxpt->states = xmalloc_array(struct xen_processor_px,
486
0
                        dom0_px_info->state_count)) )
487
0
        {
488
0
            ret = -ENOMEM;
489
0
            goto out;
490
0
        }
491
0
        if ( copy_from_guest(pxpt->states, dom0_px_info->states,
492
0
                             dom0_px_info->state_count) )
493
0
        {
494
0
            ret = -EFAULT;
495
0
            goto out;
496
0
        }
497
0
        pxpt->state_count = dom0_px_info->state_count;
498
0
499
0
        if ( cpufreq_verbose )
500
0
            print_PSS(pxpt->states,pxpt->state_count);
501
0
    }
502
0
503
0
    if ( dom0_px_info->flags & XEN_PX_PSD )
504
0
    {
505
0
        /* check domain coordination */
506
0
        if (dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_ALL &&
507
0
            dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_ANY &&
508
0
            dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_HW)
509
0
        {
510
0
            ret = -EINVAL;
511
0
            goto out;
512
0
        }
513
0
514
0
        pxpt->shared_type = dom0_px_info->shared_type;
515
0
        memcpy ((void *)&pxpt->domain_info,
516
0
                (void *)&dom0_px_info->domain_info,
517
0
                sizeof(struct xen_psd_package));
518
0
519
0
        if ( cpufreq_verbose )
520
0
            print_PSD(&pxpt->domain_info);
521
0
    }
522
0
523
0
    if ( dom0_px_info->flags & XEN_PX_PPC )
524
0
    {
525
0
        pxpt->platform_limit = dom0_px_info->platform_limit;
526
0
527
0
        if ( cpufreq_verbose )
528
0
            print_PPC(pxpt->platform_limit);
529
0
530
0
        if ( pxpt->init == XEN_PX_INIT )
531
0
        {
532
0
            ret = cpufreq_limit_change(cpuid); 
533
0
            goto out;
534
0
        }
535
0
    }
536
0
537
0
    if ( dom0_px_info->flags == ( XEN_PX_PCT | XEN_PX_PSS |
538
0
                XEN_PX_PSD | XEN_PX_PPC ) )
539
0
    {
540
0
        pxpt->init = XEN_PX_INIT;
541
0
542
0
        ret = cpufreq_cpu_init(cpuid);
543
0
        goto out;
544
0
    }
545
0
546
0
out:
547
0
    return ret;
548
0
}
549
550
static void cpufreq_cmdline_common_para(struct cpufreq_policy *new_policy)
551
0
{
552
0
    if (usr_max_freq)
553
0
        new_policy->max = usr_max_freq;
554
0
    if (usr_min_freq)
555
0
        new_policy->min = usr_min_freq;
556
0
}
557
558
static int __init cpufreq_handle_common_option(const char *name, const char *val)
559
0
{
560
0
    if (!strcmp(name, "maxfreq") && val) {
561
0
        usr_max_freq = simple_strtoul(val, NULL, 0);
562
0
        return 1;
563
0
    }
564
0
565
0
    if (!strcmp(name, "minfreq") && val) {
566
0
        usr_min_freq = simple_strtoul(val, NULL, 0);
567
0
        return 1;
568
0
    }
569
0
570
0
    if (!strcmp(name, "verbose")) {
571
0
        cpufreq_verbose = !val || !!simple_strtoul(val, NULL, 0);
572
0
        return 1;
573
0
    }
574
0
575
0
    return 0;
576
0
}
577
578
static int __init cpufreq_cmdline_parse(const char *s)
579
0
{
580
0
    static struct cpufreq_governor *__initdata cpufreq_governors[] =
581
0
    {
582
0
        CPUFREQ_DEFAULT_GOVERNOR,
583
0
        &cpufreq_gov_userspace,
584
0
        &cpufreq_gov_dbs,
585
0
        &cpufreq_gov_performance,
586
0
        &cpufreq_gov_powersave
587
0
    };
588
0
    static char __initdata buf[128];
589
0
    char *str = buf;
590
0
    unsigned int gov_index = 0;
591
0
    int rc = 0;
592
0
593
0
    strlcpy(buf, s, sizeof(buf));
594
0
    do {
595
0
        char *val, *end = strchr(str, ',');
596
0
        unsigned int i;
597
0
598
0
        if (end)
599
0
            *end++ = '\0';
600
0
        val = strchr(str, '=');
601
0
        if (val)
602
0
            *val++ = '\0';
603
0
604
0
        if (!cpufreq_opt_governor) {
605
0
            if (!val) {
606
0
                for (i = 0; i < ARRAY_SIZE(cpufreq_governors); ++i) {
607
0
                    if (!strcmp(str, cpufreq_governors[i]->name)) {
608
0
                        cpufreq_opt_governor = cpufreq_governors[i];
609
0
                        gov_index = i;
610
0
                        str = NULL;
611
0
                        break;
612
0
                    }
613
0
                }
614
0
            } else {
615
0
                cpufreq_opt_governor = CPUFREQ_DEFAULT_GOVERNOR;
616
0
            }
617
0
        }
618
0
619
0
        if (str && !cpufreq_handle_common_option(str, val) &&
620
0
            (!cpufreq_governors[gov_index]->handle_option ||
621
0
             !cpufreq_governors[gov_index]->handle_option(str, val)))
622
0
        {
623
0
            printk(XENLOG_WARNING "cpufreq/%s: option '%s' not recognized\n",
624
0
                   cpufreq_governors[gov_index]->name, str);
625
0
            rc = -EINVAL;
626
0
        }
627
0
628
0
        str = end;
629
0
    } while (str);
630
0
631
0
    return rc;
632
0
}
633
634
static int cpu_callback(
635
    struct notifier_block *nfb, unsigned long action, void *hcpu)
636
33
{
637
33
    unsigned int cpu = (unsigned long)hcpu;
638
33
639
33
    switch ( action )
640
33
    {
641
11
    case CPU_DOWN_FAILED:
642
11
    case CPU_ONLINE:
643
11
        (void)cpufreq_add_cpu(cpu);
644
11
        break;
645
0
    case CPU_DOWN_PREPARE:
646
0
        (void)cpufreq_del_cpu(cpu);
647
0
        break;
648
22
    default:
649
22
        break;
650
33
    }
651
33
652
33
    return NOTIFY_DONE;
653
33
}
654
655
static struct notifier_block cpu_nfb = {
656
    .notifier_call = cpu_callback
657
};
658
659
static int __init cpufreq_presmp_init(void)
660
1
{
661
1
    register_cpu_notifier(&cpu_nfb);
662
1
    return 0;
663
1
}
664
presmp_initcall(cpufreq_presmp_init);
665
666
int __init cpufreq_register_driver(struct cpufreq_driver *driver_data)
667
1
{
668
1
   if ( !driver_data || !driver_data->init ||
669
1
        !driver_data->verify || !driver_data->exit ||
670
1
        (!driver_data->target == !driver_data->setpolicy) )
671
0
        return -EINVAL;
672
1
673
1
    if ( cpufreq_driver )
674
0
        return -EBUSY;
675
1
676
1
    cpufreq_driver = driver_data;
677
1
678
1
    return 0;
679
1
}