OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [kernel/] [power/] [main.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * kernel/power/main.c - PM subsystem core functionality.
3
 *
4
 * Copyright (c) 2003 Patrick Mochel
5
 * Copyright (c) 2003 Open Source Development Lab
6
 *
7
 * This file is released under the GPLv2
8
 *
9
 */
10
 
11
#include <linux/module.h>
12
#include <linux/suspend.h>
13
#include <linux/kobject.h>
14
#include <linux/string.h>
15
#include <linux/delay.h>
16
#include <linux/errno.h>
17
#include <linux/init.h>
18
#include <linux/console.h>
19
#include <linux/cpu.h>
20
#include <linux/resume-trace.h>
21
#include <linux/freezer.h>
22
#include <linux/vmstat.h>
23
#include <linux/syscalls.h>
24
 
25
#include "power.h"
26
 
27
BLOCKING_NOTIFIER_HEAD(pm_chain_head);
28
 
29
DEFINE_MUTEX(pm_mutex);
30
 
31
unsigned int pm_flags;
32
EXPORT_SYMBOL(pm_flags);
33
 
34
#ifdef CONFIG_SUSPEND
35
 
36
/* This is just an arbitrary number */
37
#define FREE_PAGE_NUMBER (100)
38
 
39
static struct platform_suspend_ops *suspend_ops;
40
 
41
/**
42
 *      suspend_set_ops - Set the global suspend method table.
43
 *      @ops:   Pointer to ops structure.
44
 */
45
 
46
void suspend_set_ops(struct platform_suspend_ops *ops)
47
{
48
        mutex_lock(&pm_mutex);
49
        suspend_ops = ops;
50
        mutex_unlock(&pm_mutex);
51
}
52
 
53
/**
54
 * suspend_valid_only_mem - generic memory-only valid callback
55
 *
56
 * Platform drivers that implement mem suspend only and only need
57
 * to check for that in their .valid callback can use this instead
58
 * of rolling their own .valid callback.
59
 */
60
int suspend_valid_only_mem(suspend_state_t state)
61
{
62
        return state == PM_SUSPEND_MEM;
63
}
64
 
65
/**
66
 *      suspend_prepare - Do prep work before entering low-power state.
67
 *
68
 *      This is common code that is called for each state that we're entering.
69
 *      Run suspend notifiers, allocate a console and stop all processes.
70
 */
71
static int suspend_prepare(void)
72
{
73
        int error;
74
        unsigned int free_pages;
75
 
76
        if (!suspend_ops || !suspend_ops->enter)
77
                return -EPERM;
78
 
79
        error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
80
        if (error)
81
                goto Finish;
82
 
83
        pm_prepare_console();
84
 
85
        if (freeze_processes()) {
86
                error = -EAGAIN;
87
                goto Thaw;
88
        }
89
 
90
        free_pages = global_page_state(NR_FREE_PAGES);
91
        if (free_pages < FREE_PAGE_NUMBER) {
92
                pr_debug("PM: free some memory\n");
93
                shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
94
                if (nr_free_pages() < FREE_PAGE_NUMBER) {
95
                        error = -ENOMEM;
96
                        printk(KERN_ERR "PM: No enough memory\n");
97
                }
98
        }
99
        if (!error)
100
                return 0;
101
 
102
 Thaw:
103
        thaw_processes();
104
        pm_restore_console();
105
 Finish:
106
        pm_notifier_call_chain(PM_POST_SUSPEND);
107
        return error;
108
}
109
 
110
/* default implementation */
111
void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
112
{
113
        local_irq_disable();
114
}
115
 
116
/* default implementation */
117
void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
118
{
119
        local_irq_enable();
120
}
121
 
122
/**
123
 *      suspend_enter - enter the desired system sleep state.
124
 *      @state:         state to enter
125
 *
126
 *      This function should be called after devices have been suspended.
127
 */
128
static int suspend_enter(suspend_state_t state)
129
{
130
        int error = 0;
131
 
132
        arch_suspend_disable_irqs();
133
        BUG_ON(!irqs_disabled());
134
 
135
        if ((error = device_power_down(PMSG_SUSPEND))) {
136
                printk(KERN_ERR "Some devices failed to power down\n");
137
                goto Done;
138
        }
139
        error = suspend_ops->enter(state);
140
        device_power_up();
141
 Done:
142
        arch_suspend_enable_irqs();
143
        BUG_ON(irqs_disabled());
144
        return error;
145
}
146
 
147
/**
148
 *      suspend_devices_and_enter - suspend devices and enter the desired system sleep
149
 *                        state.
150
 *      @state:           state to enter
151
 */
152
int suspend_devices_and_enter(suspend_state_t state)
153
{
154
        int error;
155
 
156
        if (!suspend_ops)
157
                return -ENOSYS;
158
 
159
        if (suspend_ops->set_target) {
160
                error = suspend_ops->set_target(state);
161
                if (error)
162
                        return error;
163
        }
164
        suspend_console();
165
        error = device_suspend(PMSG_SUSPEND);
166
        if (error) {
167
                printk(KERN_ERR "Some devices failed to suspend\n");
168
                goto Resume_console;
169
        }
170
        if (suspend_ops->prepare) {
171
                error = suspend_ops->prepare();
172
                if (error)
173
                        goto Resume_devices;
174
        }
175
        error = disable_nonboot_cpus();
176
        if (!error)
177
                suspend_enter(state);
178
 
179
        enable_nonboot_cpus();
180
        if (suspend_ops->finish)
181
                suspend_ops->finish();
182
 Resume_devices:
183
        device_resume();
184
 Resume_console:
185
        resume_console();
186
        return error;
187
}
188
 
189
/**
190
 *      suspend_finish - Do final work before exiting suspend sequence.
191
 *
192
 *      Call platform code to clean up, restart processes, and free the
193
 *      console that we've allocated. This is not called for suspend-to-disk.
194
 */
195
static void suspend_finish(void)
196
{
197
        thaw_processes();
198
        pm_restore_console();
199
        pm_notifier_call_chain(PM_POST_SUSPEND);
200
}
201
 
202
 
203
 
204
 
205
static const char * const pm_states[PM_SUSPEND_MAX] = {
206
        [PM_SUSPEND_STANDBY]    = "standby",
207
        [PM_SUSPEND_MEM]        = "mem",
208
};
209
 
210
static inline int valid_state(suspend_state_t state)
211
{
212
        /* All states need lowlevel support and need to be valid
213
         * to the lowlevel implementation, no valid callback
214
         * implies that none are valid. */
215
        if (!suspend_ops || !suspend_ops->valid || !suspend_ops->valid(state))
216
                return 0;
217
        return 1;
218
}
219
 
220
 
221
/**
222
 *      enter_state - Do common work of entering low-power state.
223
 *      @state:         pm_state structure for state we're entering.
224
 *
225
 *      Make sure we're the only ones trying to enter a sleep state. Fail
226
 *      if someone has beat us to it, since we don't want anything weird to
227
 *      happen when we wake up.
228
 *      Then, do the setup for suspend, enter the state, and cleaup (after
229
 *      we've woken up).
230
 */
231
static int enter_state(suspend_state_t state)
232
{
233
        int error;
234
 
235
        if (!valid_state(state))
236
                return -ENODEV;
237
 
238
        if (!mutex_trylock(&pm_mutex))
239
                return -EBUSY;
240
 
241
        printk("Syncing filesystems ... ");
242
        sys_sync();
243
        printk("done.\n");
244
 
245
        pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
246
        if ((error = suspend_prepare()))
247
                goto Unlock;
248
 
249
        pr_debug("PM: Entering %s sleep\n", pm_states[state]);
250
        error = suspend_devices_and_enter(state);
251
 
252
        pr_debug("PM: Finishing wakeup.\n");
253
        suspend_finish();
254
 Unlock:
255
        mutex_unlock(&pm_mutex);
256
        return error;
257
}
258
 
259
 
260
/**
261
 *      pm_suspend - Externally visible function for suspending system.
262
 *      @state:         Enumerated value of state to enter.
263
 *
264
 *      Determine whether or not value is within range, get state
265
 *      structure, and enter (above).
266
 */
267
 
268
int pm_suspend(suspend_state_t state)
269
{
270
        if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
271
                return enter_state(state);
272
        return -EINVAL;
273
}
274
 
275
EXPORT_SYMBOL(pm_suspend);
276
 
277
#endif /* CONFIG_SUSPEND */
278
 
279
decl_subsys(power,NULL,NULL);
280
 
281
 
282
/**
283
 *      state - control system power state.
284
 *
285
 *      show() returns what states are supported, which is hard-coded to
286
 *      'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
287
 *      'disk' (Suspend-to-Disk).
288
 *
289
 *      store() accepts one of those strings, translates it into the
290
 *      proper enumerated value, and initiates a suspend transition.
291
 */
292
 
293
static ssize_t state_show(struct kset *kset, char *buf)
294
{
295
        char *s = buf;
296
#ifdef CONFIG_SUSPEND
297
        int i;
298
 
299
        for (i = 0; i < PM_SUSPEND_MAX; i++) {
300
                if (pm_states[i] && valid_state(i))
301
                        s += sprintf(s,"%s ", pm_states[i]);
302
        }
303
#endif
304
#ifdef CONFIG_HIBERNATION
305
        s += sprintf(s, "%s\n", "disk");
306
#else
307
        if (s != buf)
308
                /* convert the last space to a newline */
309
                *(s-1) = '\n';
310
#endif
311
        return (s - buf);
312
}
313
 
314
static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
315
{
316
#ifdef CONFIG_SUSPEND
317
        suspend_state_t state = PM_SUSPEND_STANDBY;
318
        const char * const *s;
319
#endif
320
        char *p;
321
        int len;
322
        int error = -EINVAL;
323
 
324
        p = memchr(buf, '\n', n);
325
        len = p ? p - buf : n;
326
 
327
        /* First, check if we are requested to hibernate */
328
        if (len == 4 && !strncmp(buf, "disk", len)) {
329
                error = hibernate();
330
  goto Exit;
331
        }
332
 
333
#ifdef CONFIG_SUSPEND
334
        for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
335
                if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
336
                        break;
337
        }
338
        if (state < PM_SUSPEND_MAX && *s)
339
                error = enter_state(state);
340
#endif
341
 
342
 Exit:
343
        return error ? error : n;
344
}
345
 
346
power_attr(state);
347
 
348
#ifdef CONFIG_PM_TRACE
349
int pm_trace_enabled;
350
 
351
static ssize_t pm_trace_show(struct kset *kset, char *buf)
352
{
353
        return sprintf(buf, "%d\n", pm_trace_enabled);
354
}
355
 
356
static ssize_t
357
pm_trace_store(struct kset *kset, const char *buf, size_t n)
358
{
359
        int val;
360
 
361
        if (sscanf(buf, "%d", &val) == 1) {
362
                pm_trace_enabled = !!val;
363
                return n;
364
        }
365
        return -EINVAL;
366
}
367
 
368
power_attr(pm_trace);
369
 
370
static struct attribute * g[] = {
371
        &state_attr.attr,
372
        &pm_trace_attr.attr,
373
        NULL,
374
};
375
#else
376
static struct attribute * g[] = {
377
        &state_attr.attr,
378
        NULL,
379
};
380
#endif /* CONFIG_PM_TRACE */
381
 
382
static struct attribute_group attr_group = {
383
        .attrs = g,
384
};
385
 
386
 
387
static int __init pm_init(void)
388
{
389
        int error = subsystem_register(&power_subsys);
390
        if (!error)
391
                error = sysfs_create_group(&power_subsys.kobj,&attr_group);
392
        return error;
393
}
394
 
395
core_initcall(pm_init);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.