📄 s3c2410-linux-2.6.11.1-apm-08.11.02.patch
字号:
diff -urN s3c2410-linux-2.6.11.1/arch/arm/kernel/apm.c s3c2410-linux-2.6.11.1-apm-08.11.02/arch/arm/kernel/apm.c--- s3c2410-linux-2.6.11.1/arch/arm/kernel/apm.c 2005-03-04 12:26:46.000000000 -0500+++ s3c2410-linux-2.6.11.1-apm-08.11.02/arch/arm/kernel/apm.c 2008-11-02 08:32:12.000000000 -0500@@ -13,11 +13,11 @@ #include <linux/config.h> #include <linux/module.h> #include <linux/poll.h>-#include <linux/timer.h> #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/miscdevice.h> #include <linux/apm_bios.h>+#include <linux/capability.h> #include <linux/sched.h> #include <linux/pm.h> #include <linux/device.h>@@ -25,6 +25,8 @@ #include <linux/list.h> #include <linux/init.h> #include <linux/completion.h>+#include <linux/kthread.h>+#include <linux/delay.h> #include <asm/apm.h> /* apm_power_info */ #include <asm/system.h>@@ -70,7 +72,8 @@ #define SUSPEND_PENDING 1 /* suspend pending read */ #define SUSPEND_READ 2 /* suspend read, pending ack */ #define SUSPEND_ACKED 3 /* suspend acked */-#define SUSPEND_DONE 4 /* suspend completed */+#define SUSPEND_WAIT 4 /* waiting for suspend */+#define SUSPEND_DONE 5 /* suspend completed */ struct apm_queue queue; };@@ -80,6 +83,7 @@ */ static int suspends_pending; static int apm_disabled;+static struct task_struct *kapmd_tsk; static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);@@ -96,10 +100,10 @@ * to be suspending the system. */ static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);-static DECLARE_COMPLETION(kapmd_exit); static DEFINE_SPINLOCK(kapmd_queue_lock); static struct apm_queue kapmd_queue; +static DECLARE_MUTEX(state_lock); static const char driver_version[] = "1.13"; /* no spaces */ @@ -147,38 +151,60 @@ q->events[q->event_head] = event; } -static void queue_event_one_user(struct apm_user *as, apm_event_t event)+static void queue_event(apm_event_t event) {- if (as->suser && as->writer) {- switch (event) {- case APM_SYS_SUSPEND:- case APM_USER_SUSPEND:- /*- * If this user already has a suspend pending,- * don't queue another one.- */- if (as->suspend_state != SUSPEND_NONE)- return;+ struct apm_user *as; - as->suspend_state = SUSPEND_PENDING;- suspends_pending++;- break;- }+ down_read(&user_list_lock);+ list_for_each_entry(as, &apm_user_list, list) {+ if (as->reader)+ queue_add_event(&as->queue, event); }- queue_add_event(&as->queue, event);+ up_read(&user_list_lock);+ wake_up_interruptible(&apm_waitqueue); } -static void queue_event(apm_event_t event, struct apm_user *sender)+/*+ * queue_suspend_event - queue an APM suspend event.+ *+ * Check that we're in a state where we can suspend. If not,+ * return -EBUSY. Otherwise, queue an event to all "writer"+ * users. If there are no "writer" users, return '1' to+ * indicate that we can immediately suspend.+ */+static int queue_suspend_event(apm_event_t event, struct apm_user *sender) { struct apm_user *as;+ int ret = 1; + down(&state_lock); down_read(&user_list_lock);++ /*+ * If a thread is still processing, we can't suspend, so reject+ * the request.+ */+ list_for_each_entry(as, &apm_user_list, list) {+ if (as != sender && as->reader && as->writer && as->suser &&+ as->suspend_state != SUSPEND_NONE) {+ ret = -EBUSY;+ goto out;+ }+ }+ list_for_each_entry(as, &apm_user_list, list) {- if (as != sender && as->reader)- queue_event_one_user(as, event);+ if (as != sender && as->reader && as->writer && as->suser) {+ as->suspend_state = SUSPEND_PENDING;+ suspends_pending++;+ queue_add_event(&as->queue, event);+ ret = 0;+ } }+ out: up_read(&user_list_lock);+ up(&state_lock); wake_up_interruptible(&apm_waitqueue);+ return ret; } static void apm_suspend(void)@@ -190,17 +216,22 @@ * Anyone on the APM queues will think we're still suspended. * Send a message so everyone knows we're now awake again. */- queue_event(APM_NORMAL_RESUME, NULL);+ queue_event(APM_NORMAL_RESUME); /* * Finally, wake up anyone who is sleeping on the suspend. */+ down(&state_lock); down_read(&user_list_lock); list_for_each_entry(as, &apm_user_list, list) {- as->suspend_result = err;- as->suspend_state = SUSPEND_DONE;+ if (as->suspend_state == SUSPEND_WAIT ||+ as->suspend_state == SUSPEND_ACKED) {+ as->suspend_result = err;+ as->suspend_state = SUSPEND_DONE;+ } } up_read(&user_list_lock);+ up(&state_lock); wake_up(&apm_suspend_waitqueue); }@@ -226,8 +257,11 @@ if (copy_to_user(buf, &event, sizeof(event))) break; - if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)+ down(&state_lock);+ if (as->suspend_state == SUSPEND_PENDING &&+ (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)) as->suspend_state = SUSPEND_READ;+ up(&state_lock); buf += sizeof(event); i -= sizeof(event);@@ -269,9 +303,13 @@ switch (cmd) { case APM_IOC_SUSPEND:+ down(&state_lock);+ as->suspend_result = -EINTR; if (as->suspend_state == SUSPEND_READ) {+ int pending;+ /* * If we read a suspend command from /dev/apm_bios, * then the corresponding APM_IOC_SUSPEND ioctl is@@ -279,47 +317,73 @@ */ as->suspend_state = SUSPEND_ACKED; suspends_pending--;+ pending = suspends_pending == 0;+ up(&state_lock);++ /*+ * If there are no further acknowledges required,+ * suspend the system.+ */+ if (pending)+ apm_suspend();++ /*+ * Wait for the suspend/resume to complete. If there+ * are pending acknowledges, we wait here for them.+ *+ * Note: we need to ensure that the PM subsystem does+ * not kick us out of the wait when it suspends the+ * threads.+ */+ flags = current->flags;+ current->flags |= PF_NOFREEZE;++ wait_event(apm_suspend_waitqueue,+ as->suspend_state == SUSPEND_DONE); } else {+ as->suspend_state = SUSPEND_WAIT;+ up(&state_lock);+ /* * Otherwise it is a request to suspend the system. * Queue an event for all readers, and expect an * acknowledge from all writers who haven't already * acknowledged. */- queue_event(APM_USER_SUSPEND, as);- }+ err = queue_suspend_event(APM_USER_SUSPEND, as);+ if (err < 0) {+ /*+ * Avoid taking the lock here - this+ * should be fine.+ */+ as->suspend_state = SUSPEND_NONE;+ break;+ } - /*- * If there are no further acknowledges required, suspend- * the system.- */- if (suspends_pending == 0)- apm_suspend();+ if (err > 0)+ apm_suspend(); - /*- * Wait for the suspend/resume to complete. If there are- * pending acknowledges, we wait here for them.- *- * Note that we need to ensure that the PM subsystem does- * not kick us out of the wait when it suspends the threads.- */- flags = current->flags;- current->flags |= PF_NOFREEZE;+ /*+ * Wait for the suspend/resume to complete. If there+ * are pending acknowledges, we wait here for them.+ *+ * Note: we need to ensure that the PM subsystem does+ * not kick us out of the wait when it suspends the+ * threads.+ */+ flags = current->flags;+ current->flags |= PF_NOFREEZE; - /*- * Note: do not allow a thread which is acking the suspend- * to escape until the resume is complete.- */- if (as->suspend_state == SUSPEND_ACKED)- wait_event(apm_suspend_waitqueue,- as->suspend_state == SUSPEND_DONE);- else wait_event_interruptible(apm_suspend_waitqueue, as->suspend_state == SUSPEND_DONE);+ } current->flags = flags;++ down(&state_lock); err = as->suspend_result; as->suspend_state = SUSPEND_NONE;+ up(&state_lock); break; } @@ -329,6 +393,8 @@ static int apm_release(struct inode * inode, struct file * filp) { struct apm_user *as = filp->private_data;+ int pending = 0;+ filp->private_data = NULL; down_write(&user_list_lock);@@ -341,11 +407,14 @@ * need to balance suspends_pending, which means the * possibility of sleeping. */+ down(&state_lock); if (as->suspend_state != SUSPEND_NONE) { suspends_pending -= 1;- if (suspends_pending == 0)- apm_suspend();+ pending = suspends_pending == 0; }+ up(&state_lock);+ if (pending)+ apm_suspend(); kfree(as); return 0;@@ -358,7 +427,6 @@ as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); if (as) { memset(as, 0, sizeof(*as));- /* * XXX - this is a tiny bit broken, when we consider BSD * process accounting. If the device is opened by root, we@@ -469,16 +537,14 @@ static int kapmd(void *arg) {- daemonize("kapmd");- current->flags |= PF_NOFREEZE;- do { apm_event_t event;+ int ret; wait_event_interruptible(kapmd_wait,- !queue_empty(&kapmd_queue) || !pm_active);+ !queue_empty(&kapmd_queue) || kthread_should_stop()); - if (!pm_active)+ if (kthread_should_stop()) break; spin_lock_irq(&kapmd_queue_lock);@@ -493,13 +559,20 @@ case APM_LOW_BATTERY: case APM_POWER_STATUS_CHANGE:- queue_event(event, NULL);+ queue_event(event); break; case APM_USER_SUSPEND: case APM_SYS_SUSPEND:- queue_event(event, NULL);- if (suspends_pending == 0)+ ret = queue_suspend_event(event, NULL);+ if (ret < 0) {+ /*+ * We were busy. Try again in 50ms.+ */+ queue_add_event(&kapmd_queue, event);+ msleep(50);+ }+ if (ret > 0) apm_suspend(); break; @@ -509,7 +582,7 @@ } } while (1); - complete_and_exit(&kapmd_exit, 0);+ return 0; } static int __init apm_init(void)@@ -521,18 +594,14 @@ return -ENODEV; } - if (PM_IS_ACTIVE()) {- printk(KERN_NOTICE "apm: overridden by ACPI.\n");- return -EINVAL;- }-- pm_active = 1;-- ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);- if (ret < 0) {- pm_active = 0;+ kapmd_tsk = kthread_create(kapmd, NULL, "kapmd");+ if (IS_ERR(kapmd_tsk)) {+ ret = PTR_ERR(kapmd_tsk);+ kapmd_tsk = NULL; return ret; }+ kapmd_tsk->flags |= PF_NOFREEZE;+ wake_up_process(kapmd_tsk); #ifdef CONFIG_PROC_FS create_proc_info_entry("apm", 0, NULL, apm_get_info);@@ -541,10 +610,7 @@ ret = misc_register(&apm_device); if (ret != 0) { remove_proc_entry("apm", NULL);-- pm_active = 0;- wake_up(&kapmd_wait);- wait_for_completion(&kapmd_exit);+ kthread_stop(kapmd_tsk); } return ret;@@ -555,9 +621,7 @@ misc_deregister(&apm_device); remove_proc_entry("apm", NULL); - pm_active = 0;- wake_up(&kapmd_wait);- wait_for_completion(&kapmd_exit);+ kthread_stop(kapmd_tsk); } module_init(apm_init);diff -urN s3c2410-linux-2.6.11.1/arch/arm/kernel/setup.c s3c2410-linux-2.6.11.1-apm-08.11.02/arch/arm/kernel/setup.c--- s3c2410-linux-2.6.11.1/arch/arm/kernel/setup.c 2005-06-01 19:38:57.000000000 -0400+++ s3c2410-linux-2.6.11.1-apm-08.11.02/arch/arm/kernel/setup.c 2008-11-02 08:32:12.000000000 -0500@@ -92,6 +92,14 @@ struct cpu_cache_fns cpu_cache; #endif +struct stack {+ u32 irq[3];+ u32 abt[3];+ u32 und[3];+} ____cacheline_aligned;++static struct stack stacks[NR_CPUS];+ char elf_platform[ELF_PLATFORM_SIZE]; EXPORT_SYMBOL(elf_platform); @@ -316,6 +324,48 @@ cpu_proc_init(); } +/*+ * cpu_init - initialise one CPU.+ *+ * cpu_init dumps the cache information, initialises SMP specific+ * information, and sets up the per-CPU stacks.+ */+void cpu_init(void)+{+ unsigned int cpu = smp_processor_id();+ struct stack *stk = &stacks[cpu];++ if (cpu >= NR_CPUS) {+ printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);+ BUG();+ }++ if (system_state == SYSTEM_BOOTING)+ dump_cpu_info(cpu);++ /*+ * setup stacks for re-entrant exception handlers+ */+ __asm__ (+ "msr cpsr_c, %1\n\t"+ "add sp, %0, %2\n\t"+ "msr cpsr_c, %3\n\t"+ "add sp, %0, %4\n\t"+ "msr cpsr_c, %5\n\t"+ "add sp, %0, %6\n\t"+ "msr cpsr_c, %7"+ :+ : "r" (stk),+ "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),+ "I" (offsetof(struct stack, irq[0])),+ "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),+ "I" (offsetof(struct stack, abt[0])),+ "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),+ "I" (offsetof(struct stack, und[0])),+ "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)+ : "r14");+}+ static struct machine_desc * __init setup_machine(unsigned int nr) { struct machine_desc *list;diff -urN s3c2410-linux-2.6.11.1/arch/arm/mach-s3c2410/irq.c s3c2410-linux-2.6.11.1-apm-08.11.02/arch/arm/mach-s3c2410/irq.c--- s3c2410-linux-2.6.11.1/arch/arm/mach-s3c2410/irq.c 2005-06-01 19:38:57.000000000 -0400+++ s3c2410-linux-2.6.11.1-apm-08.11.02/arch/arm/mach-s3c2410/irq.c 2008-11-02 08:32:12.000000000 -0500@@ -81,7 +81,7 @@ unsigned long s3c_irqwake_eintallow = 0x0000fff0L; unsigned long s3c_irqwake_eintmask = 0xffffffffL; -static int+int s3c_irq_wake(unsigned int irqno, unsigned int state) { unsigned long irqbit = 1 << (irqno - IRQ_EINT0);diff -urN s3c2410-linux-2.6.11.1/arch/arm/mach-s3c2410/irq.h s3c2410-linux-2.6.11.1-apm-08.11.02/arch/arm/mach-s3c2410/irq.h--- s3c2410-linux-2.6.11.1/arch/arm/mach-s3c2410/irq.h 1969-12-31 19:00:00.000000000 -0500+++ s3c2410-linux-2.6.11.1-apm-08.11.02/arch/arm/mach-s3c2410/irq.h 2008-10-16 23:35:57.000000000 -0400@@ -0,0 +1,109 @@+/* arch/arm/mach-s3c2410/irq.h+ *+ * Copyright (c) 2004-2005 Simtec Electronics+ * Ben Dooks <ben@simtec.co.uk>+ *+ * Header file for S3C24XX CPU IRQ support+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License version 2 as+ * published by the Free Software Foundation.+ *+ * Modifications:+*/++#define irqdbf(x...)+#define irqdbf2(x...)++#define EXTINT_OFF (IRQ_EINT4 - 4)++extern struct irqchip s3c_irq_level_chip;++static inline void+s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,+ int subcheck)+{+ unsigned long mask;+ unsigned long submask;++ submask = __raw_readl(S3C2410_INTSUBMSK);+ mask = __raw_readl(S3C2410_INTMSK);++ submask |= (1UL << (irqno - IRQ_S3CUART_RX0));++ /* check to see if we need to mask the parent IRQ */++ if ((submask & subcheck) == subcheck) {+ __raw_writel(mask | parentbit, S3C2410_INTMSK);+ }++ /* write back masks */+ __raw_writel(submask, S3C2410_INTSUBMSK);+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -