diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 01:42:52 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 01:42:52 (GMT) |
commit | 17bb51d56cdc8cbf252031db3107de034cfeb44c (patch) | |
tree | f9fb2c16b29a152d3413fa0028e660e3b6146584 | |
parent | 0671b7674f42ab3a200401ea0e48d6f47d34acae (diff) | |
parent | 95aac7b1cd224f568fb83937044cd303ff11b029 (diff) | |
download | linux-17bb51d56cdc8cbf252031db3107de034cfeb44c.tar.xz |
Merge branch 'akpm-incoming-2'
* akpm-incoming-2: (139 commits)
epoll: make epoll_wait() use the hrtimer range feature
select: rename estimate_accuracy() to select_estimate_accuracy()
Remove duplicate includes from many files
ramoops: use the platform data structure instead of module params
kernel/resource.c: handle reinsertion of an already-inserted resource
kfifo: fix kfifo_alloc() to return a signed int value
w1: don't allow arbitrary users to remove w1 devices
alpha: remove dma64_addr_t usage
mips: remove dma64_addr_t usage
sparc: remove dma64_addr_t usage
fuse: use release_pages()
taskstats: use real microsecond granularity for CPU times
taskstats: split fill_pid function
taskstats: separate taskstats commands
delayacct: align to 8 byte boundary on 64-bit systems
delay-accounting: reimplement -c for getdelays.c to report information on a target command
namespaces Kconfig: move namespace menu location after the cgroup
namespaces Kconfig: remove the cgroup device whitelist experimental tag
namespaces Kconfig: remove pointless cgroup dependency
namespaces Kconfig: make namespace a submenu
...
165 files changed, 4758 insertions, 1291 deletions
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c index 6e25c26..a2976a6 100644 --- a/Documentation/accounting/getdelays.c +++ b/Documentation/accounting/getdelays.c @@ -21,6 +21,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/wait.h> #include <signal.h> #include <linux/genetlink.h> @@ -266,11 +267,13 @@ int main(int argc, char *argv[]) int containerset = 0; char containerpath[1024]; int cfd = 0; + int forking = 0; + sigset_t sigset; struct msgtemplate msg; - while (1) { - c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:"); + while (!forking) { + c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:c:"); if (c < 0) break; @@ -319,6 +322,28 @@ int main(int argc, char *argv[]) err(1, "Invalid pid\n"); cmd_type = TASKSTATS_CMD_ATTR_PID; break; + case 'c': + + /* Block SIGCHLD for sigwait() later */ + if (sigemptyset(&sigset) == -1) + err(1, "Failed to empty sigset"); + if (sigaddset(&sigset, SIGCHLD)) + err(1, "Failed to set sigchld in sigset"); + sigprocmask(SIG_BLOCK, &sigset, NULL); + + /* fork/exec a child */ + tid = fork(); + if (tid < 0) + err(1, "Fork failed\n"); + if (tid == 0) + if (execvp(argv[optind - 1], + &argv[optind - 1]) < 0) + exit(-1); + + /* Set the command type and avoid further processing */ + cmd_type = TASKSTATS_CMD_ATTR_PID; + forking = 1; + break; case 'v': printf("debug on\n"); dbg = 1; @@ -370,6 +395,15 @@ int main(int argc, char *argv[]) goto err; } + /* + * If we forked a child, wait for it to exit. Cannot use waitpid() + * as all the delicious data would be reaped as part of the wait + */ + if (tid && forking) { + int sig_received; + sigwait(&sigset, &sig_received); + } + if (tid) { rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET, cmd_type, &tid, sizeof(__u32)); diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index b34823f..190018b 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt @@ -18,7 +18,8 @@ CONTENTS: 1.2 Why are cgroups needed ? 1.3 How are cgroups implemented ? 1.4 What does notify_on_release do ? - 1.5 How do I use cgroups ? + 1.5 What does clone_children do ? + 1.6 How do I use cgroups ? 2. Usage Examples and Syntax 2.1 Basic Usage 2.2 Attaching processes @@ -293,7 +294,16 @@ notify_on_release in the root cgroup at system boot is disabled value of their parents notify_on_release setting. The default value of a cgroup hierarchy's release_agent path is empty. -1.5 How do I use cgroups ? +1.5 What does clone_children do ? +--------------------------------- + +If the clone_children flag is enabled (1) in a cgroup, then all +cgroups created beneath will call the post_clone callbacks for each +subsystem of the newly created cgroup. Usually when this callback is +implemented for a subsystem, it copies the values of the parent +subsystem, this is the case for the cpuset. + +1.6 How do I use cgroups ? -------------------------- To start a new job that is to be contained within a cgroup, using diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index d2af87b..f3da8c0 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -526,6 +526,23 @@ Who: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> ---------------------------- +What: namespace cgroup (ns_cgroup) +When: 2.6.38 +Why: The ns_cgroup leads to some problems: + * cgroup creation is out-of-control + * cgroup name can conflict when pids are looping + * it is not possible to have a single process handling + a lot of namespaces without falling in a exponential creation time + * we may want to create a namespace without creating a cgroup + + The ns_cgroup is replaced by a compatibility flag 'clone_children', + where a newly created cgroup will copy the parent cgroup values. + The userspace has to manually create a cgroup and add a task to + the 'tasks' file. +Who: Daniel Lezcano <daniel.lezcano@free.fr> + +---------------------------- + What: iwlwifi disable_hw_scan module parameters When: 2.6.40 Why: Hareware scan is the prefer method for iwlwifi devices for diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index a563b74..e73df27 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -136,6 +136,7 @@ Table 1-1: Process specific entries in /proc statm Process memory status information status Process status in human readable form wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan + pagemap Page table stack Report full stack trace, enable via CONFIG_STACKTRACE smaps a extension based on maps, showing the memory consumption of each mapping @@ -370,6 +371,7 @@ Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 0 kB Referenced: 892 kB +Anonymous: 0 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB @@ -378,9 +380,15 @@ The first of these lines shows the same information as is displayed for the mapping in /proc/PID/maps. The remaining lines show the size of the mapping (size), the amount of the mapping that is currently resident in RAM (RSS), the process' proportional share of this mapping (PSS), the number of clean and -dirty shared pages in the mapping, and the number of clean and dirty private -pages in the mapping. The "Referenced" indicates the amount of memory -currently marked as referenced or accessed. +dirty private pages in the mapping. Note that even a page which is part of a +MAP_SHARED mapping, but has only a single pte mapped, i.e. is currently used +by only one process, is accounted as private and not as shared. "Referenced" +indicates the amount of memory currently marked as referenced or accessed. +"Anonymous" shows the amount of memory that does not belong to any file. Even +a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE +and a page is modified, the file page is replaced by a private anonymous copy. +"Swap" shows how much would-be-anonymous memory is also used, but out on +swap. This file is only present if the CONFIG_MMU kernel configuration option is enabled. @@ -397,6 +405,9 @@ To clear the bits for the file mapped pages associated with the process > echo 3 > /proc/PID/clear_refs Any other value written to /proc/PID/clear_refs will have no effect. +The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags +using /proc/kpageflags and number of times a page is mapped using +/proc/kpagecount. For detailed explanation, see Documentation/vm/pagemap.txt. 1.2 Kernel data --------------- diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index b606c2c..30289fa 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -80,8 +80,10 @@ dirty_background_bytes Contains the amount of dirty memory at which the pdflush background writeback daemon will start writeback. -If dirty_background_bytes is written, dirty_background_ratio becomes a function -of its value (dirty_background_bytes / the amount of dirtyable system memory). +Note: dirty_background_bytes is the counterpart of dirty_background_ratio. Only +one of them may be specified at a time. When one sysctl is written it is +immediately taken into account to evaluate the dirty memory limits and the +other appears as 0 when read. ============================================================== @@ -97,8 +99,10 @@ dirty_bytes Contains the amount of dirty memory at which a process generating disk writes will itself start writeback. -If dirty_bytes is written, dirty_ratio becomes a function of its value -(dirty_bytes / the amount of dirtyable system memory). +Note: dirty_bytes is the counterpart of dirty_ratio. Only one of them may be +specified at a time. When one sysctl is written it is immediately taken into +account to evaluate the dirty memory limits and the other appears as 0 when +read. Note: the minimum value allowed for dirty_bytes is two pages (in bytes); any value lower than this limit will be ignored and the old configuration will be diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index d1dbd9a..022c2748 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -223,7 +223,7 @@ iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n) */ static int pci_dac_dma_supported(struct pci_dev *dev, u64 mask) { - dma64_addr_t dac_offset = alpha_mv.pci_dac_offset; + dma_addr_t dac_offset = alpha_mv.pci_dac_offset; int ok = 1; /* If this is not set, the machine doesn't support DAC at all. */ @@ -756,7 +756,7 @@ static void alpha_pci_unmap_sg(struct device *dev, struct scatterlist *sg, spin_lock_irqsave(&arena->lock, flags); for (end = sg + nents; sg < end; ++sg) { - dma64_addr_t addr; + dma_addr_t addr; size_t size; long npages, ofs; dma_addr_t tend; diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index baa9036..e2af5eb 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -269,7 +269,8 @@ void ptrace_disable(struct task_struct *child) user_disable_single_step(child); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { unsigned long tmp; size_t copied; @@ -292,7 +293,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_PEEKUSR: force_successful_syscall_return(); ret = get_reg(child, addr); - DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret)); + DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret)); break; /* When I and D space are separate, this will have to be fixed. */ @@ -302,7 +303,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_POKEUSR: /* write the specified register */ - DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data)); + DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data)); ret = put_reg(child, addr, data); break; default: diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index e0cb637..3e97483 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -1075,13 +1075,15 @@ out: } #endif -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { case PTRACE_PEEKUSR: - ret = ptrace_read_user(child, addr, (unsigned long __user *)data); + ret = ptrace_read_user(child, addr, datap); break; case PTRACE_POKEUSR: @@ -1089,34 +1091,34 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_GETREGS: - ret = ptrace_getregs(child, (void __user *)data); + ret = ptrace_getregs(child, datap); break; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (void __user *)data); + ret = ptrace_setregs(child, datap); break; case PTRACE_GETFPREGS: - ret = ptrace_getfpregs(child, (void __user *)data); + ret = ptrace_getfpregs(child, datap); break; case PTRACE_SETFPREGS: - ret = ptrace_setfpregs(child, (void __user *)data); + ret = ptrace_setfpregs(child, datap); break; #ifdef CONFIG_IWMMXT case PTRACE_GETWMMXREGS: - ret = ptrace_getwmmxregs(child, (void __user *)data); + ret = ptrace_getwmmxregs(child, datap); break; case PTRACE_SETWMMXREGS: - ret = ptrace_setwmmxregs(child, (void __user *)data); + ret = ptrace_setwmmxregs(child, datap); break; #endif case PTRACE_GET_THREAD_AREA: ret = put_user(task_thread_info(child)->tp_value, - (unsigned long __user *) data); + datap); break; case PTRACE_SET_SYSCALL: @@ -1126,21 +1128,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef CONFIG_CRUNCH case PTRACE_GETCRUNCHREGS: - ret = ptrace_getcrunchregs(child, (void __user *)data); + ret = ptrace_getcrunchregs(child, datap); break; case PTRACE_SETCRUNCHREGS: - ret = ptrace_setcrunchregs(child, (void __user *)data); + ret = ptrace_setcrunchregs(child, datap); break; #endif #ifdef CONFIG_VFP case PTRACE_GETVFPREGS: - ret = ptrace_getvfpregs(child, (void __user *)data); + ret = ptrace_getvfpregs(child, datap); break; case PTRACE_SETVFPREGS: - ret = ptrace_setvfpregs(child, (void __user *)data); + ret = ptrace_setvfpregs(child, datap); break; #endif diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c index 2f42021..9057d6f 100644 --- a/arch/arm/mach-tegra/timer.c +++ b/arch/arm/mach-tegra/timer.c @@ -28,7 +28,6 @@ #include <linux/cnt32_to_63.h> #include <asm/mach/time.h> -#include <asm/mach/time.h> #include <asm/localtimer.h> #include <mach/iomap.h> diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index c00f119..c435fd9 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -89,7 +89,7 @@ void __kunmap_atomic(void *kvaddr) int idx, type; if (kvaddr >= (void *)FIXADDR_START) { - type = kmap_atomic_idx_pop(); + type = kmap_atomic_idx(); idx = type + KM_TYPE_NR * smp_processor_id(); if (cache_is_vivt()) @@ -101,6 +101,7 @@ void __kunmap_atomic(void *kvaddr) #else (void) idx; /* to kill a warning */ #endif + kmap_atomic_idx_pop(); } else if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) { /* this address was obtained through kmap_high_get() */ kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)])); diff --git a/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/arch/arm/plat-nomadik/include/plat/ste_dma40.h index 5fbde4b..93a8126 100644 --- a/arch/arm/plat-nomadik/include/plat/ste_dma40.h +++ b/arch/arm/plat-nomadik/include/plat/ste_dma40.h @@ -14,7 +14,6 @@ #include <linux/dmaengine.h> #include <linux/workqueue.h> #include <linux/interrupt.h> -#include <linux/dmaengine.h> /* dev types for memcpy */ #define STEDMA40_DEV_DST_MEMORY (-1) diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c index 5e73c25..4aedcab 100644 --- a/arch/avr32/kernel/ptrace.c +++ b/arch/avr32/kernel/ptrace.c @@ -146,9 +146,11 @@ static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs) return ret; } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + void __user *datap = (void __user *) data; switch (request) { /* Read the word at location addr in the child process */ @@ -158,8 +160,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_PEEKUSR: - ret = ptrace_read_user(child, addr, - (unsigned long __user *)data); + ret = ptrace_read_user(child, addr, datap); break; /* Write the word in data at location addr */ @@ -173,11 +174,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_GETREGS: - ret = ptrace_getregs(child, (void __user *)data); + ret = ptrace_getregs(child, datap); break; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (const void __user *)data); + ret = ptrace_setregs(child, datap); break; default: diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index b358393..75089f8 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -38,12 +38,13 @@ * Get contents of register REGNO in task TASK. */ static inline long -get_reg(struct task_struct *task, long regno, unsigned long __user *datap) +get_reg(struct task_struct *task, unsigned long regno, + unsigned long __user *datap) { long tmp; struct pt_regs *regs = task_pt_regs(task); - if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0) + if (regno & 3 || regno > PT_LAST_PSEUDO) return -EIO; switch (regno) { @@ -74,11 +75,11 @@ get_reg(struct task_struct *task, long regno, unsigned long __user *datap) * Write contents of register REGNO in task TASK. */ static inline int -put_reg(struct task_struct *task, long regno, unsigned long data) +put_reg(struct task_struct *task, unsigned long regno, unsigned long data) { struct pt_regs *regs = task_pt_regs(task); - if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0) + if (regno & 3 || regno > PT_LAST_PSEUDO) return -EIO; switch (regno) { @@ -240,7 +241,8 @@ void user_disable_single_step(struct task_struct *child) clear_tsk_thread_flag(child, TIF_SINGLESTEP); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; unsigned long __user *datap = (unsigned long __user *)data; @@ -368,14 +370,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return copy_regset_to_user(child, &user_bfin_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), - (void __user *)data); + datap); case PTRACE_SETREGS: pr_debug("ptrace: PTRACE_SETREGS\n"); return copy_regset_from_user(child, &user_bfin_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), - (const void __user *)data); + datap); case_default: default: diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c index e70c804..320065f 100644 --- a/arch/cris/arch-v10/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -76,9 +76,11 @@ ptrace_disable(struct task_struct *child) * (in user space) where the result of the ptrace call is written (instead of * being returned). */ -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + unsigned int regno = addr >> 2; unsigned long __user *datap = (unsigned long __user *)data; switch (request) { @@ -93,10 +95,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned long tmp; ret = -EIO; - if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) + if ((addr & 3) || regno > PT_MAX) break; - tmp = get_reg(child, addr >> 2); + tmp = get_reg(child, regno); ret = put_user(tmp, datap); break; } @@ -110,19 +112,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* Write the word at location address in the USER area. */ case PTRACE_POKEUSR: ret = -EIO; - if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) + if ((addr & 3) || regno > PT_MAX) break; - addr >>= 2; - - if (addr == PT_DCCR) { + if (regno == PT_DCCR) { /* don't allow the tracing process to change stuff like * interrupt enable, kernel/user bit, dma enables etc. */ data &= DCCR_MASK; data |= get_reg(child, PT_DCCR) & ~DCCR_MASK; } - if (put_reg(child, addr, data)) + if (put_reg(child, regno, data)) break; ret = 0; break; @@ -141,7 +141,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - data += sizeof(long); + datap++; } break; @@ -165,7 +165,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } put_reg(child, i, tmp); - data += sizeof(long); + datap++; } break; diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index f4ebd1e..511ece9 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c @@ -126,9 +126,11 @@ ptrace_disable(struct task_struct *child) } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + unsigned int regno = addr >> 2; unsigned long __user *datap = (unsigned long __user *)data; switch (request) { @@ -163,10 +165,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned long tmp; ret = -EIO; - if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) + if ((addr & 3) || regno > PT_MAX) break; - tmp = get_reg(child, addr >> 2); + tmp = get_reg(child, regno); ret = put_user(tmp, datap); break; } @@ -180,19 +182,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* Write the word at location address in the USER area. */ case PTRACE_POKEUSR: ret = -EIO; - if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) + if ((addr & 3) || regno > PT_MAX) break; - addr >>= 2; - - if (addr == PT_CCS) { + if (regno == PT_CCS) { /* don't allow the tracing process to change stuff like * interrupt enable, kernel/user bit, dma enables etc. */ data &= CCS_MASK; data |= get_reg(child, PT_CCS) & ~CCS_MASK; } - if (put_reg(child, addr, data)) + if (put_reg(child, regno, data)) break; ret = 0; break; diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c index fac0289..9d68f7f 100644 --- a/arch/frv/kernel/ptrace.c +++ b/arch/frv/kernel/ptrace.c @@ -254,23 +254,26 @@ void ptrace_disable(struct task_struct *child) user_disable_single_step(child); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { unsigned long tmp; int ret; + int regno = addr >> 2; + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { tmp = 0; ret = -EIO; - if ((addr & 3) || addr < 0) + if (addr & 3) break; ret = 0; - switch (addr >> 2) { + switch (regno) { case 0 ... PT__END - 1: - tmp = get_reg(child, addr >> 2); + tmp = get_reg(child, regno); break; case PT__END + 0: @@ -299,23 +302,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } if (ret == 0) - ret = put_user(tmp, (unsigned long *) data); + ret = put_user(tmp, datap); break; } case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret = -EIO; - if ((addr & 3) || addr < 0) + if (addr & 3) break; - ret = 0; - switch (addr >> 2) { + switch (regno) { case 0 ... PT__END - 1: - ret = put_reg(child, addr >> 2, data); - break; - - default: - ret = -EIO; + ret = put_reg(child, regno, data); break; } break; @@ -324,25 +322,25 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return copy_regset_to_user(child, &user_frv_native_view, REGSET_GENERAL, 0, sizeof(child->thread.user->i), - (void __user *)data); + datap); case PTRACE_SETREGS: /* Set all integer regs in the child. */ return copy_regset_from_user(child, &user_frv_native_view, REGSET_GENERAL, 0, sizeof(child->thread.user->i), - (const void __user *)data); + datap); case PTRACE_GETFPREGS: /* Get the child FP/Media state. */ return copy_regset_to_user(child, &user_frv_native_view, REGSET_FPMEDIA, 0, sizeof(child->thread.user->f), - (void __user *)data); + datap); case PTRACE_SETFPREGS: /* Set the child FP/Media state. */ return copy_regset_from_user(child, &user_frv_native_view, REGSET_FPMEDIA, 0, sizeof(child->thread.user->f), - (const void __user *)data); + datap); default: ret = ptrace_request(child, request, addr, data); diff --git a/arch/frv/mm/highmem.c b/arch/frv/mm/highmem.c index 61088dc..fd7fcd4 100644 --- a/arch/frv/mm/highmem.c +++ b/arch/frv/mm/highmem.c @@ -68,7 +68,7 @@ EXPORT_SYMBOL(__kmap_atomic); void __kunmap_atomic(void *kvaddr) { - int type = kmap_atomic_idx_pop(); + int type = kmap_atomic_idx(); switch (type) { case 0: __kunmap_atomic_primary(4, 6); break; case 1: __kunmap_atomic_primary(5, 7); break; @@ -83,6 +83,7 @@ void __kunmap_atomic(void *kvaddr) default: BUG(); } + kmap_atomic_idx_pop(); pagefault_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c index df11412..497fa89 100644 --- a/arch/h8300/kernel/ptrace.c +++ b/arch/h8300/kernel/ptrace.c @@ -50,27 +50,29 @@ void ptrace_disable(struct task_struct *child) user_disable_single_step(child); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + int regno = addr >> 2; + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp = 0; - if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) { + if ((addr & 3) || addr >= sizeof(struct user)) { ret = -EIO; break ; } ret = 0; /* Default return condition */ - addr = addr >> 2; /* temporary hack. */ - if (addr < H8300_REGS_NO) - tmp = h8300_get_reg(child, addr); + if (regno < H8300_REGS_NO) + tmp = h8300_get_reg(child, regno); else { - switch(addr) { + switch (regno) { case 49: tmp = child->mm->start_code; break ; @@ -88,24 +90,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } } if (!ret) - ret = put_user(tmp,(unsigned long *) data); + ret = put_user(tmp, datap); break ; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) { + if ((addr & 3) || addr >= sizeof(struct user)) { ret = -EIO; break ; } - addr = addr >> 2; /* temporary hack. */ - if (addr == PT_ORIG_ER0) { + if (regno == PT_ORIG_ER0) { ret = -EIO; break ; } - if (addr < H8300_REGS_NO) { - ret = h8300_put_reg(child, addr, data); + if (regno < H8300_REGS_NO) { + ret = h8300_put_reg(child, regno, data); break ; } ret = -EIO; @@ -116,11 +117,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned long tmp; for (i = 0; i < H8300_REGS_NO; i++) { tmp = h8300_get_reg(child, i); - if (put_user(tmp, (unsigned long *) data)) { + if (put_user(tmp, datap)) { ret = -EFAULT; break; } - data += sizeof(long); + datap++; } ret = 0; break; @@ -130,12 +131,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int i; unsigned long tmp; for (i = 0; i < H8300_REGS_NO; i++) { - if (get_user(tmp, (unsigned long *) data)) { + if (get_user(tmp, datap)) { ret = -EFAULT; break; } h8300_put_reg(child, i, tmp); - data += sizeof(long); + datap++; } ret = 0; break; diff --git a/arch/ia64/include/asm/cputime.h b/arch/ia64/include/asm/cputime.h index 7fa8a85..6073b18 100644 --- a/arch/ia64/include/asm/cputime.h +++ b/arch/ia64/include/asm/cputime.h @@ -56,10 +56,10 @@ typedef u64 cputime64_t; #define jiffies64_to_cputime64(__jif) ((__jif) * (NSEC_PER_SEC / HZ)) /* - * Convert cputime <-> milliseconds + * Convert cputime <-> microseconds */ -#define cputime_to_msecs(__ct) ((__ct) / NSEC_PER_MSEC) -#define msecs_to_cputime(__msecs) ((__msecs) * NSEC_PER_MSEC) +#define cputime_to_usecs(__ct) ((__ct) / NSEC_PER_USEC) +#define usecs_to_cputime(__usecs) ((__usecs) * NSEC_PER_USEC) /* * Convert cputime <-> seconds diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 7c7909f..8848f43 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1177,7 +1177,8 @@ ptrace_disable (struct task_struct *child) } long -arch_ptrace (struct task_struct *child, long request, long addr, long data) +arch_ptrace (struct task_struct *child, long request, + unsigned long addr, unsigned long data) { switch (request) { case PTRACE_PEEKTEXT: diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index 0021ade..2074375 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c @@ -622,9 +622,11 @@ void ptrace_disable(struct task_struct *child) } long -arch_ptrace(struct task_struct *child, long request, long addr, long data) +arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { /* @@ -639,8 +641,7 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) * read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: - ret = ptrace_read_user(child, addr, - (unsigned long __user *)data); + ret = ptrace_read_user(child, addr, datap); break; /* @@ -661,11 +662,11 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_GETREGS: - ret = ptrace_getregs(child, (void __user *)data); + ret = ptrace_getregs(child, datap); break; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (void __user *)data); + ret = ptrace_setregs(child, datap); break; default: diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 616e597..0b25268 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -156,55 +156,57 @@ void user_disable_single_step(struct task_struct *child) singlestep_disable(child); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { unsigned long tmp; int i, ret = 0; + int regno = addr >> 2; /* temporary hack. */ + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: if (addr & 3) goto out_eio; - addr >>= 2; /* temporary hack. */ - if (addr >= 0 && addr < 19) { - tmp = get_reg(child, addr); - } else if (addr >= 21 && addr < 49) { - tmp = child->thread.fp[addr - 21]; + if (regno >= 0 && regno < 19) { + tmp = get_reg(child, regno); + } else if (regno >= 21 && regno < 49) { + tmp = child->thread.fp[regno - 21]; /* Convert internal fpu reg representation * into long double format */ - if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) + if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) tmp = ((tmp & 0xffff0000) << 15) | ((tmp & 0x0000ffff) << 16); } else goto out_eio; - ret = put_user(tmp, (unsigned long *)data); + ret = put_user(tmp, datap); break; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + case PTRACE_POKEUSR: + /* write the word at location addr in the USER area */ if (addr & 3) goto out_eio; - addr >>= 2; /* temporary hack. */ - if (addr == PT_SR) { + if (regno == PT_SR) { data &= SR_MASK; data |= get_reg(child, PT_SR) & ~SR_MASK; } - if (addr >= 0 && addr < 19) { - if (put_reg(child, addr, data)) + if (regno >= 0 && regno < 19) { + if (put_reg(child, regno, data)) goto out_eio; - } else if (addr >= 21 && addr < 48) { + } else if (regno >= 21 && regno < 48) { /* Convert long double format * into internal fpu reg representation */ - if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { - data = (unsigned long)data << 15; + if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { + data <<= 15; data = (data & 0xffff0000) | ((data & 0x0000ffff) >> 1); } - child->thread.fp[addr - 21] = data; + child->thread.fp[regno - 21] = data; } else goto out_eio; break; @@ -212,16 +214,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_GETREGS: /* Get all gp regs from the child. */ for (i = 0; i < 19; i++) { tmp = get_reg(child, i); - ret = put_user(tmp, (unsigned long *)data); + ret = put_user(tmp, datap); if (ret) break; - data += sizeof(long); + datap++; } break; case PTRACE_SETREGS: /* Set all gp regs in the child. */ for (i = 0; i < 19; i++) { - ret = get_user(tmp, (unsigned long *)data); + ret = get_user(tmp, datap); if (ret) break; if (i == PT_SR) { @@ -229,25 +231,24 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) tmp |= get_reg(child, PT_SR) & ~SR_MASK; } put_reg(child, i, tmp); - data += sizeof(long); + datap++; } break; case PTRACE_GETFPREGS: /* Get the child FPU state. */ - if (copy_to_user((void *)data, &child->thread.fp, + if (copy_to_user(datap, &child->thread.fp, sizeof(struct user_m68kfp_struct))) ret = -EFAULT; break; case PTRACE_SETFPREGS: /* Set the child FPU state. */ - if (copy_from_user(&child->thread.fp, (void *)data, + if (copy_from_user(&child->thread.fp, datap, sizeof(struct user_m68kfp_struct))) ret = -EFAULT; break; case PTRACE_GET_THREAD_AREA: - ret = put_user(task_thread_info(child)->tp_value, - (unsigned long __user *)data); + ret = put_user(task_thread_info(child)->tp_value, datap); break; default: diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c index 6fe7c38..6709fb7 100644 --- a/arch/m68knommu/kernel/ptrace.c +++ b/arch/m68knommu/kernel/ptrace.c @@ -112,9 +112,12 @@ void ptrace_disable(struct task_struct *child) user_disable_single_step(child); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + int regno = addr >> 2; + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { /* read the word at location addr in the USER area. */ @@ -122,53 +125,48 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned long tmp; ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) + if ((addr & 3) || addr > sizeof(struct user) - 3) break; tmp = 0; /* Default return condition */ - addr = addr >> 2; /* temporary hack. */ ret = -EIO; - if (addr < 19) { - tmp = get_reg(child, addr); - if (addr == PT_SR) + if (regno < 19) { + tmp = get_reg(child, regno); + if (regno == PT_SR) tmp >>= 16; - } else if (addr >= 21 && addr < 49) { - tmp = child->thread.fp[addr - 21]; - } else if (addr == 49) { + } else if (regno >= 21 && regno < 49) { + tmp = child->thread.fp[regno - 21]; + } else if (regno == 49) { tmp = child->mm->start_code; - } else if (addr == 50) { + } else if (regno == 50) { tmp = child->mm->start_data; - } else if (addr == 51) { + } else if (regno == 51) { tmp = child->mm->end_code; } else break; - ret = put_user(tmp,(unsigned long *) data); + ret = put_user(tmp, datap); break; } case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) + if ((addr & 3) || addr > sizeof(struct user) - 3) break; - addr = addr >> 2; /* temporary hack. */ - - if (addr == PT_SR) { + if (regno == PT_SR) { data &= SR_MASK; data <<= 16; data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); } - if (addr < 19) { - if (put_reg(child, addr, data)) + if (regno < 19) { + if (put_reg(child, regno, data)) break; ret = 0; break; } - if (addr >= 21 && addr < 48) + if (regno >= 21 && regno < 48) { - child->thread.fp[addr - 21] = data; + child->thread.fp[regno - 21] = data; ret = 0; } break; @@ -180,11 +178,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) tmp = get_reg(child, i); if (i == PT_SR) tmp >>= 16; - if (put_user(tmp, (unsigned long *) data)) { + if (put_user(tmp, datap)) { ret = -EFAULT; break; } - data += sizeof(long); + datap++; } ret = 0; break; @@ -194,7 +192,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int i; unsigned long tmp; for (i = 0; i < 19; i++) { - if (get_user(tmp, (unsigned long *) data)) { + if (get_user(tmp, datap)) { ret = -EFAULT; break; } @@ -204,7 +202,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); } put_reg(child, i, tmp); - data += sizeof(long); + datap++; } ret = 0; break; @@ -213,7 +211,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef PTRACE_GETFPREGS case PTRACE_GETFPREGS: { /* Get the child FPU state. */ ret = 0; - if (copy_to_user((void *)data, &child->thread.fp, + if (copy_to_user(datap, &child->thread.fp, sizeof(struct user_m68kfp_struct))) ret = -EFAULT; break; @@ -223,7 +221,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef PTRACE_SETFPREGS case PTRACE_SETFPREGS: { /* Set the child FPU state. */ ret = 0; - if (copy_from_user(&child->thread.fp, (void *)data, + if (copy_from_user(&child->thread.fp, datap, sizeof(struct user_m68kfp_struct))) ret = -EFAULT; break; @@ -231,8 +229,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #endif case PTRACE_GET_THREAD_AREA: - ret = put_user(task_thread_info(child)->tp_value, - (unsigned long __user *)data); + ret = put_user(task_thread_info(child)->tp_value, datap); break; default: diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index dc03ffc..05ac8cc 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c @@ -73,7 +73,8 @@ static microblaze_reg_t *reg_save_addr(unsigned reg_offs, return (microblaze_reg_t *)((char *)regs + reg_offs); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int rval; unsigned long val = 0; @@ -99,7 +100,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } else { rval = -EIO; } - } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { + } else if (addr < PT_SIZE && (addr & 0x3) == 0) { microblaze_reg_t *reg_addr = reg_save_addr(addr, child); if (request == PTRACE_PEEKUSR) val = *reg_addr; diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h index 5f4b9d4..f1f508e 100644 --- a/arch/mips/include/asm/pci/bridge.h +++ b/arch/mips/include/asm/pci/bridge.h @@ -839,7 +839,7 @@ struct bridge_controller { nasid_t nasid; unsigned int widget_id; unsigned int irq_cpu; - dma64_addr_t baddr; + u64 baddr; unsigned int pci_int[8]; }; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index c877733..d21c388 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -255,9 +255,13 @@ int ptrace_set_watch_regs(struct task_struct *child, return 0; } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + void __user *addrp = (void __user *) addr; + void __user *datavp = (void __user *) data; + unsigned long __user *datalp = (void __user *) data; switch (request) { /* when I and D space are separate, these will need to be fixed. */ @@ -386,7 +390,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = -EIO; goto out; } - ret = put_user(tmp, (unsigned long __user *) data); + ret = put_user(tmp, datalp); break; } @@ -478,34 +482,31 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } case PTRACE_GETREGS: - ret = ptrace_getregs(child, (__s64 __user *) data); + ret = ptrace_getregs(child, datavp); break; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (__s64 __user *) data); + ret = ptrace_setregs(child, datavp); break; case PTRACE_GETFPREGS: - ret = ptrace_getfpregs(child, (__u32 __user *) data); + ret = ptrace_getfpregs(child, datavp); break; case PTRACE_SETFPREGS: - ret = ptrace_setfpregs(child, (__u32 __user *) data); + ret = ptrace_setfpregs(child, datavp); break; case PTRACE_GET_THREAD_AREA: - ret = put_user(task_thread_info(child)->tp_value, - (unsigned long __user *) data); + ret = put_user(task_thread_info(child)->tp_value, datalp); break; case PTRACE_GET_WATCH_REGS: - ret = ptrace_get_watch_regs(child, - (struct pt_watch_regs __user *) addr); + ret = ptrace_get_watch_regs(child, addrp); break; case PTRACE_SET_WATCH_REGS: - ret = ptrace_set_watch_regs(child, - (struct pt_watch_regs __user *) addr); + ret = ptrace_set_watch_regs(child, addrp); break; default: diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 1e69b1f..3634c7ea 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -74,7 +74,7 @@ void __kunmap_atomic(void *kvaddr) return; } - type = kmap_atomic_idx_pop(); + type = kmap_atomic_idx(); #ifdef CONFIG_DEBUG_HIGHMEM { int idx = type + KM_TYPE_NR * smp_processor_id(); @@ -89,6 +89,7 @@ void __kunmap_atomic(void *kvaddr) local_flush_tlb_one(vaddr); } #endif + kmap_atomic_idx_pop(); pagefault_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/mn10300/include/asm/highmem.h b/arch/mn10300/include/asm/highmem.h index f577ba2..e2155e6 100644 --- a/arch/mn10300/include/asm/highmem.h +++ b/arch/mn10300/include/asm/highmem.h @@ -101,7 +101,7 @@ static inline void __kunmap_atomic(unsigned long vaddr) return; } - type = kmap_atomic_idx_pop(); + type = kmap_atomic_idx(); #if HIGHMEM_DEBUG { @@ -119,6 +119,8 @@ static inline void __kunmap_atomic(unsigned long vaddr) __flush_tlb_one(vaddr); } #endif + + kmap_atomic_idx_pop(); pagefault_enable(); } #endif /* __KERNEL__ */ diff --git a/arch/mn10300/kernel/ptrace.c b/arch/mn10300/kernel/ptrace.c index cf847da..5c0b07e 100644 --- a/arch/mn10300/kernel/ptrace.c +++ b/arch/mn10300/kernel/ptrace.c @@ -295,31 +295,31 @@ void ptrace_disable(struct task_struct *child) /* * handle the arch-specific side of process tracing */ -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { unsigned long tmp; int ret; + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) + if ((addr & 3) || addr > sizeof(struct user) - 3) break; tmp = 0; /* Default return condition */ if (addr < NR_PTREGS << 2) tmp = get_stack_long(child, ptrace_regid_to_frame[addr]); - ret = put_user(tmp, (unsigned long *) data); + ret = put_user(tmp, datap); break; /* write the word at location addr in the USER area */ case PTRACE_POKEUSR: ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) + if ((addr & 3) || addr > sizeof(struct user) - 3) break; ret = 0; @@ -332,25 +332,25 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return copy_regset_to_user(child, &user_mn10300_native_view, REGSET_GENERAL, 0, NR_PTREGS * sizeof(long), - (void __user *)data); + datap); case PTRACE_SETREGS: /* Set all integer regs in the child. */ return copy_regset_from_user(child, &user_mn10300_native_view, REGSET_GENERAL, 0, NR_PTREGS * sizeof(long), - (const void __user *)data); + datap); case PTRACE_GETFPREGS: /* Get the child FPU state. */ return copy_regset_to_user(child, &user_mn10300_native_view, REGSET_FPU, 0, sizeof(struct fpu_state_struct), - (void __user *)data); + datap); case PTRACE_SETFPREGS: /* Set the child FPU state. */ return copy_regset_from_user(child, &user_mn10300_native_view, REGSET_FPU, 0, sizeof(struct fpu_state_struct), - (const void __user *)data); + datap); default: ret = ptrace_request(child, request, addr, data); diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index c4f49e4..2905b1f 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -110,7 +110,8 @@ void user_enable_block_step(struct task_struct *task) pa_psw(task)->l = 0; } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { unsigned long tmp; long ret = -EIO; @@ -120,11 +121,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* Read the word at location addr in the USER area. For ptraced processes, the kernel saves all regs on a syscall. */ case PTRACE_PEEKUSR: - if ((addr & (sizeof(long)-1)) || - (unsigned long) addr >= sizeof(struct pt_regs)) + if ((addr & (sizeof(unsigned long)-1)) || + addr >= sizeof(struct pt_regs)) break; tmp = *(unsigned long *) ((char *) task_regs(child) + addr); - ret = put_user(tmp, (unsigned long *) data); + ret = put_user(tmp, (unsigned long __user *) data); break; /* Write the word at location addr in the USER area. This will need @@ -151,8 +152,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - if ((addr & (sizeof(long)-1)) || - (unsigned long) addr >= sizeof(struct pt_regs)) + if ((addr & (sizeof(unsigned long)-1)) || + addr >= sizeof(struct pt_regs)) break; if ((addr >= PT_GR1 && addr <= PT_GR31) || addr == PT_IAOQ0 || addr == PT_IAOQ1 || diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h index 8bdc6a9..1cf20bd 100644 --- a/arch/powerpc/include/asm/cputime.h +++ b/arch/powerpc/include/asm/cputime.h @@ -124,23 +124,23 @@ static inline u64 cputime64_to_jiffies64(const cputime_t ct) } /* - * Convert cputime <-> milliseconds + * Convert cputime <-> microseconds */ extern u64 __cputime_msec_factor; -static inline unsigned long cputime_to_msecs(const cputime_t ct) +static inline unsigned long cputime_to_usecs(const cputime_t ct) { - return mulhdu(ct, __cputime_msec_factor); + return mulhdu(ct, __cputime_msec_factor) * USEC_PER_MSEC; } -static inline cputime_t msecs_to_cputime(const unsigned long ms) +static inline cputime_t usecs_to_cputime(const unsigned long us) { cputime_t ct; unsigned long sec; /* have to be a little careful about overflow */ - ct = ms % 1000; - sec = ms / 1000; + ct = us % 1000000; + sec = us / 1000000; if (ct) { ct *= tb_ticks_per_sec; do_div(ct, 1000); diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 286d978..a9b3296 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1406,37 +1406,42 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, * we mark them as obsolete now, they will be removed in a future version */ -static long arch_ptrace_old(struct task_struct *child, long request, long addr, - long data) +static long arch_ptrace_old(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { + void __user *datavp = (void __user *) data; + switch (request) { case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ return copy_regset_to_user(child, &user_ppc_native_view, REGSET_GPR, 0, 32 * sizeof(long), - (void __user *) data); + datavp); case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ return copy_regset_from_user(child, &user_ppc_native_view, REGSET_GPR, 0, 32 * sizeof(long), - (const void __user *) data); + datavp); case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ return copy_regset_to_user(child, &user_ppc_native_view, REGSET_FPR, 0, 32 * sizeof(double), - (void __user *) data); + datavp); case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */ return copy_regset_from_user(child, &user_ppc_native_view, REGSET_FPR, 0, 32 * sizeof(double), - (const void __user *) data); + datavp); } return -EPERM; } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret = -EPERM; + void __user *datavp = (void __user *) data; + unsigned long __user *datalp = datavp; switch (request) { /* read the word at location addr in the USER area. */ @@ -1446,11 +1451,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = -EIO; /* convert to index and check */ #ifdef CONFIG_PPC32 - index = (unsigned long) addr >> 2; + index = addr >> 2; if ((addr & 3) || (index > PT_FPSCR) || (child->thread.regs == NULL)) #else - index = (unsigned long) addr >> 3; + index = addr >> 3; if ((addr & 7) || (index > PT_FPSCR)) #endif break; @@ -1463,7 +1468,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) tmp = ((unsigned long *)child->thread.fpr) [TS_FPRWIDTH * (index - PT_FPR0)]; } - ret = put_user(tmp,(unsigned long __user *) data); + ret = put_user(tmp, datalp); break; } @@ -1474,11 +1479,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = -EIO; /* convert to index and check */ #ifdef CONFIG_PPC32 - index = (unsigned long) addr >> 2; + index = addr >> 2; if ((addr & 3) || (index > PT_FPSCR) || (child->thread.regs == NULL)) #else - index = (unsigned long) addr >> 3; + index = addr >> 3; if ((addr & 7) || (index > PT_FPSCR)) #endif break; @@ -1525,11 +1530,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) dbginfo.features = 0; #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ - if (!access_ok(VERIFY_WRITE, data, + if (!access_ok(VERIFY_WRITE, datavp, sizeof(struct ppc_debug_info))) return -EFAULT; - ret = __copy_to_user((struct ppc_debug_info __user *)data, - &dbginfo, sizeof(struct ppc_debug_info)) ? + ret = __copy_to_user(datavp, &dbginfo, + sizeof(struct ppc_debug_info)) ? -EFAULT : 0; break; } @@ -1537,11 +1542,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PPC_PTRACE_SETHWDEBUG: { struct ppc_hw_breakpoint bp_info; - if (!access_ok(VERIFY_READ, data, + if (!access_ok(VERIFY_READ, datavp, sizeof(struct ppc_hw_breakpoint))) return -EFAULT; - ret = __copy_from_user(&bp_info, - (struct ppc_hw_breakpoint __user *)data, + ret = __copy_from_user(&bp_info, datavp, sizeof(struct ppc_hw_breakpoint)) ? -EFAULT : 0; if (!ret) @@ -1560,11 +1564,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) if (addr > 0) break; #ifdef CONFIG_PPC_ADV_DEBUG_REGS - ret = put_user(child->thread.dac1, - (unsigned long __user *)data); + ret = put_user(child->thread.dac1, datalp); #else - ret = put_user(child->thread.dabr, - (unsigned long __user *)data); + ret = put_user(child->thread.dabr, datalp); #endif break; } @@ -1580,7 +1582,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return copy_regset_to_user(child, &user_ppc_native_view, REGSET_GPR, 0, sizeof(struct pt_regs), - (void __user *) data); + datavp); #ifdef CONFIG_PPC64 case PTRACE_SETREGS64: @@ -1589,19 +1591,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return copy_regset_from_user(child, &user_ppc_native_view, REGSET_GPR, 0, sizeof(struct pt_regs), - (const void __user *) data); + datavp); case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */ return copy_regset_to_user(child, &user_ppc_native_view, REGSET_FPR, 0, sizeof(elf_fpregset_t), - (void __user *) data); + datavp); case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */ return copy_regset_from_user(child, &user_ppc_native_view, REGSET_FPR, 0, sizeof(elf_fpregset_t), - (const void __user *) data); + datavp); #ifdef CONFIG_ALTIVEC case PTRACE_GETVRREGS: @@ -1609,40 +1611,40 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) REGSET_VMX, 0, (33 * sizeof(vector128) + sizeof(u32)), - (void __user *) data); + datavp); case PTRACE_SETVRREGS: return copy_regset_from_user(child, &user_ppc_native_view, REGSET_VMX, 0, (33 * sizeof(vector128) + sizeof(u32)), - (const void __user *) data); + datavp); #endif #ifdef CONFIG_VSX case PTRACE_GETVSRREGS: return copy_regset_to_user(child, &user_ppc_native_view, REGSET_VSX, 0, 32 * sizeof(double), - (void __user *) data); + datavp); case PTRACE_SETVSRREGS: return copy_regset_from_user(child, &user_ppc_native_view, REGSET_VSX, 0, 32 * sizeof(double), - (const void __user *) data); + datavp); #endif #ifdef CONFIG_SPE case PTRACE_GETEVRREGS: /* Get the child spe register state. */ return copy_regset_to_user(child, &user_ppc_native_view, REGSET_SPE, 0, 35 * sizeof(u32), - (void __user *) data); + datavp); case PTRACE_SETEVRREGS: /* Set the child spe register state. */ return copy_regset_from_user(child, &user_ppc_native_view, REGSET_SPE, 0, 35 * sizeof(u32), - (const void __user *) data); + datavp); #endif /* Old reverse args ptrace callss */ diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c index b0848b4..e7450bd 100644 --- a/arch/powerpc/mm/highmem.c +++ b/arch/powerpc/mm/highmem.c @@ -62,7 +62,7 @@ void __kunmap_atomic(void *kvaddr) return; } - type = kmap_atomic_idx_pop(); + type = kmap_atomic_idx(); #ifdef CONFIG_DEBUG_HIGHMEM { @@ -79,6 +79,8 @@ void __kunmap_atomic(void *kvaddr) local_flush_tlb_page(NULL, vaddr); } #endif + + kmap_atomic_idx_pop(); pagefault_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index 4127636..9725369 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -50,6 +50,7 @@ #define RIO_ATMU_REGS_OFFSET 0x10c00 #define RIO_P_MSG_REGS_OFFSET 0x11000 #define RIO_S_MSG_REGS_OFFSET 0x13000 +#define RIO_GCCSR 0x13c #define RIO_ESCSR 0x158 #define RIO_CCSR 0x15c #define RIO_LTLEDCSR 0x0608 @@ -87,6 +88,9 @@ #define RIO_IPWSR_PWD 0x00000008 #define RIO_IPWSR_PWB 0x00000004 +#define RIO_EPWISR_PINT 0x80000000 +#define RIO_EPWISR_PW 0x00000001 + #define RIO_MSG_DESC_SIZE 32 #define RIO_MSG_BUFFER_SIZE 4096 #define RIO_MIN_TX_RING_SIZE 2 @@ -1082,18 +1086,12 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) struct rio_priv *priv = port->priv; u32 epwisr, tmp; - ipwmr = in_be32(&priv->msg_regs->pwmr); - ipwsr = in_be32(&priv->msg_regs->pwsr); - epwisr = in_be32(priv->regs_win + RIO_EPWISR); - if (epwisr & 0x80000000) { - tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); - pr_info("RIO_LTLEDCSR = 0x%x\n", tmp); - out_be32(priv->regs_win + RIO_LTLEDCSR, 0); - } + if (!(epwisr & RIO_EPWISR_PW)) + goto pw_done; - if (!(epwisr & 0x00000001)) - return IRQ_HANDLED; + ipwmr = in_be32(&priv->msg_regs->pwmr); + ipwsr = in_be32(&priv->msg_regs->pwsr); #ifdef DEBUG_PW pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr); @@ -1109,20 +1107,6 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) pr_debug(" PWB"); pr_debug(" )\n"); #endif - out_be32(&priv->msg_regs->pwsr, - ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD)); - - if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) { - priv->port_write_msg.err_count++; - pr_info("RIO: Port-Write Transaction Err (%d)\n", - priv->port_write_msg.err_count); - } - if (ipwsr & RIO_IPWSR_PWD) { - priv->port_write_msg.discard_count++; - pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n", - priv->port_write_msg.discard_count); - } - /* Schedule deferred processing if PW was received */ if (ipwsr & RIO_IPWSR_QFI) { /* Save PW message (if there is room in FIFO), @@ -1134,16 +1118,43 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) RIO_PW_MSG_SIZE); } else { priv->port_write_msg.discard_count++; - pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n", + pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n", priv->port_write_msg.discard_count); } + /* Clear interrupt and issue Clear Queue command. This allows + * another port-write to be received. + */ + out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_QFI); + out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ); + schedule_work(&priv->pw_work); } - /* Issue Clear Queue command. This allows another - * port-write to be received. - */ - out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ); + if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) { + priv->port_write_msg.err_count++; + pr_debug("RIO: Port-Write Transaction Err (%d)\n", + priv->port_write_msg.err_count); + /* Clear Transaction Error: port-write controller should be + * disabled when clearing this error + */ + out_be32(&priv->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE); + out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_TE); + out_be32(&priv->msg_regs->pwmr, ipwmr); + } + + if (ipwsr & RIO_IPWSR_PWD) { + priv->port_write_msg.discard_count++; + pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n", + priv->port_write_msg.discard_count); + out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_PWD); + } + +pw_done: + if (epwisr & RIO_EPWISR_PINT) { + tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); + pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); + out_be32(priv->regs_win + RIO_LTLEDCSR, 0); + } return IRQ_HANDLED; } @@ -1461,6 +1472,7 @@ int fsl_rio_setup(struct platform_device *dev) port->host_deviceid = fsl_rio_get_hdid(port->id); port->priv = priv; + port->phys_efptr = 0x100; rio_register_mport(port); priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1); @@ -1508,6 +1520,12 @@ int fsl_rio_setup(struct platform_device *dev) dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", port->sys_size ? 65536 : 256); + if (port->host_deviceid >= 0) + out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST | + RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED); + else + out_be32(priv->regs_win + RIO_GCCSR, 0x00000000); + priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win + RIO_ATMU_REGS_OFFSET); priv->maint_atmu_regs = priv->atmu_regs + 1; diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index 8b1a52a..40e2ab0 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h @@ -73,18 +73,18 @@ cputime64_to_jiffies64(cputime64_t cputime) } /* - * Convert cputime to milliseconds and back. + * Convert cputime to microseconds and back. */ static inline unsigned int -cputime_to_msecs(const cputime_t cputime) +cputime_to_usecs(const cputime_t cputime) { - return cputime_div(cputime, 4096000); + return cputime_div(cputime, 4096); } static inline cputime_t -msecs_to_cputime(const unsigned int m) +usecs_to_cputime(const unsigned int m) { - return (cputime_t) m * 4096000; + return (cputime_t) m * 4096; } /* diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 83339d3..019bb71 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -343,7 +343,8 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) return __poke_user(child, addr, data); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { ptrace_area parea; int copied, ret; diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c index 174c642..5583618 100644 --- a/arch/score/kernel/ptrace.c +++ b/arch/score/kernel/ptrace.c @@ -325,7 +325,8 @@ void ptrace_disable(struct task_struct *child) } long -arch_ptrace(struct task_struct *child, long request, long addr, long data) +arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; unsigned long __user *datap = (void __user *)data; @@ -335,14 +336,14 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = copy_regset_to_user(child, &user_score_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), - (void __user *)datap); + datap); break; case PTRACE_SETREGS: ret = copy_regset_from_user(child, &user_score_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), - (const void __user *)datap); + datap); break; default: diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 2cd42b5..90a15d2 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -365,9 +365,9 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &user_sh_native_view; } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { - struct user * dummy = NULL; unsigned long __user *datap = (unsigned long __user *)data; int ret; @@ -383,17 +383,20 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) if (addr < sizeof(struct pt_regs)) tmp = get_stack_long(child, addr); - else if (addr >= (long) &dummy->fpu && - addr < (long) &dummy->u_fpvalid) { + else if (addr >= offsetof(struct user, fpu) && + addr < offsetof(struct user, u_fpvalid)) { if (!tsk_used_math(child)) { - if (addr == (long)&dummy->fpu.fpscr) + if (addr == offsetof(struct user, fpu.fpscr)) tmp = FPSCR_INIT; else tmp = 0; - } else - tmp = ((long *)child->thread.xstate) - [(addr - (long)&dummy->fpu) >> 2]; - } else if (addr == (long) &dummy->u_fpvalid) + } else { + unsigned long index; + index = addr - offsetof(struct user, fpu); + tmp = ((unsigned long *)child->thread.xstate) + [index >> 2]; + } + } else if (addr == offsetof(struct user, u_fpvalid)) tmp = !!tsk_used_math(child); else if (addr == PT_TEXT_ADDR) tmp = child->mm->start_code; @@ -417,13 +420,15 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) if (addr < sizeof(struct pt_regs)) ret = put_stack_long(child, addr, data); - else if (addr >= (long) &dummy->fpu && - addr < (long) &dummy->u_fpvalid) { + else if (addr >= offsetof(struct user, fpu) && + addr < offsetof(struct user, u_fpvalid)) { + unsigned long index; + index = addr - offsetof(struct user, fpu); set_stopped_child_used_math(child); - ((long *)child->thread.xstate) - [(addr - (long)&dummy->fpu) >> 2] = data; + ((unsigned long *)child->thread.xstate) + [index >> 2] = data; ret = 0; - } else if (addr == (long) &dummy->u_fpvalid) { + } else if (addr == offsetof(struct user, u_fpvalid)) { conditional_stopped_child_used_math(data, child); ret = 0; } @@ -433,35 +438,35 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return copy_regset_to_user(child, &user_sh_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), - (void __user *)data); + datap); case PTRACE_SETREGS: return copy_regset_from_user(child, &user_sh_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), - (const void __user *)data); + datap); #ifdef CONFIG_SH_FPU case PTRACE_GETFPREGS: return copy_regset_to_user(child, &user_sh_native_view, REGSET_FPU, 0, sizeof(struct user_fpu_struct), - (void __user *)data); + datap); case PTRACE_SETFPREGS: return copy_regset_from_user(child, &user_sh_native_view, REGSET_FPU, 0, sizeof(struct user_fpu_struct), - (const void __user *)data); + datap); #endif #ifdef CONFIG_SH_DSP case PTRACE_GETDSPREGS: return copy_regset_to_user(child, &user_sh_native_view, REGSET_DSP, 0, sizeof(struct pt_dspregs), - (void __user *)data); + datap); case PTRACE_SETDSPREGS: return copy_regset_from_user(child, &user_sh_native_view, REGSET_DSP, 0, sizeof(struct pt_dspregs), - (const void __user *)data); + datap); #endif default: ret = ptrace_request(child, request, addr, data); diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index e0fb065..4436eac 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -383,9 +383,11 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &user_sh64_native_view; } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; + unsigned long __user *datap = (unsigned long __user *) data; switch (request) { /* read the word at location addr in the USER area. */ @@ -400,13 +402,15 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) tmp = get_stack_long(child, addr); else if ((addr >= offsetof(struct user, fpu)) && (addr < offsetof(struct user, u_fpvalid))) { - tmp = get_fpu_long(child, addr - offsetof(struct user, fpu)); + unsigned long index; + index = addr - offsetof(struct user, fpu); + tmp = get_fpu_long(child, index); } else if (addr == offsetof(struct user, u_fpvalid)) { tmp = !!tsk_used_math(child); } else { break; } - ret = put_user(tmp, (unsigned long *)data); + ret = put_user(tmp, datap); break; } @@ -437,7 +441,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } else if ((addr >= offsetof(struct user, fpu)) && (addr < offsetof(struct user, u_fpvalid))) { - ret = put_fpu_long(child, addr - offsetof(struct user, fpu), data); + unsigned long index; + index = addr - offsetof(struct user, fpu); + ret = put_fpu_long(child, index, data); } break; @@ -445,23 +451,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return copy_regset_to_user(child, &user_sh64_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), - (void __user *)data); + datap); case PTRACE_SETREGS: return copy_regset_from_user(child, &user_sh64_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), - (const void __user *)data); + datap); #ifdef CONFIG_SH_FPU case PTRACE_GETFPREGS: return copy_regset_to_user(child, &user_sh64_native_view, REGSET_FPU, 0, sizeof(struct user_fpu_struct), - (void __user *)data); + datap); case PTRACE_SETFPREGS: return copy_regset_from_user(child, &user_sh64_native_view, REGSET_FPU, 0, sizeof(struct user_fpu_struct), - (const void __user *)data); + datap); #endif default: ret = ptrace_request(child, request, addr, data); @@ -471,7 +477,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -asmlinkage int sh64_ptrace(long request, long pid, long addr, long data) +asmlinkage int sh64_ptrace(long request, long pid, + unsigned long addr, unsigned long data) { #define WPC_DBRMODE 0x0d104008 static unsigned long first_call; diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h index 2889574..c2ced21 100644 --- a/arch/sparc/include/asm/io_32.h +++ b/arch/sparc/include/asm/io_32.h @@ -208,6 +208,21 @@ _memset_io(volatile void __iomem *dst, int c, __kernel_size_t n) #define memset_io(d,c,sz) _memset_io(d,c,sz) static inline void +_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src, + __kernel_size_t n) +{ + char *d = dst; + + while (n--) { + char tmp = sbus_readb(src); + *d++ = tmp; + src++; + } +} + +#define sbus_memcpy_fromio(d, s, sz) _sbus_memcpy_fromio(d, s, sz) + +static inline void _memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n) { char *d = dst; @@ -222,6 +237,22 @@ _memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n) #define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz) static inline void +_sbus_memcpy_toio(volatile void __iomem *dst, const void *src, + __kernel_size_t n) +{ + const char *s = src; + volatile void __iomem *d = dst; + + while (n--) { + char tmp = *s++; + sbus_writeb(tmp, d); + d++; + } +} + +#define sbus_memcpy_toio(d, s, sz) _sbus_memcpy_toio(d, s, sz) + +static inline void _memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n) { const char *s = src; diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h index 9517d06..9c89654 100644 --- a/arch/sparc/include/asm/io_64.h +++ b/arch/sparc/include/asm/io_64.h @@ -419,6 +419,21 @@ _memset_io(volatile void __iomem *dst, int c, __kernel_size_t n) #define memset_io(d,c,sz) _memset_io(d,c,sz) static inline void +_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src, + __kernel_size_t n) +{ + char *d = dst; + + while (n--) { + char tmp = sbus_readb(src); + *d++ = tmp; + src++; + } +} + +#define sbus_memcpy_fromio(d, s, sz) _sbus_memcpy_fromio(d, s, sz) + +static inline void _memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n) { char *d = dst; @@ -433,6 +448,22 @@ _memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n) #define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz) static inline void +_sbus_memcpy_toio(volatile void __iomem *dst, const void *src, + __kernel_size_t n) +{ + const char *s = src; + volatile void __iomem *d = dst; + + while (n--) { + char tmp = *s++; + sbus_writeb(tmp, d); + d++; + } +} + +#define sbus_memcpy_toio(d, s, sz) _sbus_memcpy_toio(d, s, sz) + +static inline void _memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n) { const char *s = src; diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h index 5312782..948b686 100644 --- a/arch/sparc/include/asm/pci_64.h +++ b/arch/sparc/include/asm/pci_64.h @@ -38,7 +38,7 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) * types on sparc64. However, it requires that the device * can drive enough of the 64 bits. */ -#define PCI64_REQUIRED_MASK (~(dma64_addr_t)0) +#define PCI64_REQUIRED_MASK (~(u64)0) #define PCI64_ADDR_BASE 0xfffc000000000000UL #ifdef CONFIG_PCI diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c index e608f39..27b9e93 100644 --- a/arch/sparc/kernel/ptrace_32.c +++ b/arch/sparc/kernel/ptrace_32.c @@ -323,18 +323,35 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &user_sparc32_view; } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +struct fps { + unsigned long regs[32]; + unsigned long fsr; + unsigned long flags; + unsigned long extra; + unsigned long fpqd; + struct fq { + unsigned long *insnaddr; + unsigned long insn; + } fpq[16]; +}; + +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4]; + void __user *addr2p; const struct user_regset_view *view; + struct pt_regs __user *pregs; + struct fps __user *fps; int ret; view = task_user_regset_view(current); + addr2p = (void __user *) addr2; + pregs = (struct pt_regs __user *) addr; + fps = (struct fps __user *) addr; switch(request) { case PTRACE_GETREGS: { - struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - ret = copy_regset_to_user(child, view, REGSET_GENERAL, 32 * sizeof(u32), 4 * sizeof(u32), @@ -348,8 +365,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } case PTRACE_SETREGS: { - struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - ret = copy_regset_from_user(child, view, REGSET_GENERAL, 32 * sizeof(u32), 4 * sizeof(u32), @@ -363,19 +378,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } case PTRACE_GETFPREGS: { - struct fps { - unsigned long regs[32]; - unsigned long fsr; - unsigned long flags; - unsigned long extra; - unsigned long fpqd; - struct fq { - unsigned long *insnaddr; - unsigned long insn; - } fpq[16]; - }; - struct fps __user *fps = (struct fps __user *) addr; - ret = copy_regset_to_user(child, view, REGSET_FP, 0 * sizeof(u32), 32 * sizeof(u32), @@ -397,19 +399,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } case PTRACE_SETFPREGS: { - struct fps { - unsigned long regs[32]; - unsigned long fsr; - unsigned long flags; - unsigned long extra; - unsigned long fpqd; - struct fq { - unsigned long *insnaddr; - unsigned long insn; - } fpq[16]; - }; - struct fps __user *fps = (struct fps __user *) addr; - ret = copy_regset_from_user(child, view, REGSET_FP, 0 * sizeof(u32), 32 * sizeof(u32), @@ -424,8 +413,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_READTEXT: case PTRACE_READDATA: - ret = ptrace_readdata(child, addr, - (void __user *) addr2, data); + ret = ptrace_readdata(child, addr, addr2p, data); if (ret == data) ret = 0; @@ -435,8 +423,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_WRITETEXT: case PTRACE_WRITEDATA: - ret = ptrace_writedata(child, (void __user *) addr2, - addr, data); + ret = ptrace_writedata(child, addr2p, addr, data); if (ret == data) ret = 0; diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index aa90da0..9ccc812 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c @@ -969,16 +969,19 @@ struct fps { unsigned long fsr; }; -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { const struct user_regset_view *view = task_user_regset_view(current); unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; struct pt_regs __user *pregs; struct fps __user *fps; + void __user *addr2p; int ret; - pregs = (struct pt_regs __user *) (unsigned long) addr; - fps = (struct fps __user *) (unsigned long) addr; + pregs = (struct pt_regs __user *) addr; + fps = (struct fps __user *) addr; + addr2p = (void __user *) addr2; switch (request) { case PTRACE_PEEKUSR: @@ -1029,8 +1032,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_READTEXT: case PTRACE_READDATA: - ret = ptrace_readdata(child, addr, - (char __user *)addr2, data); + ret = ptrace_readdata(child, addr, addr2p, data); if (ret == data) ret = 0; else if (ret >= 0) @@ -1039,8 +1041,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_WRITETEXT: case PTRACE_WRITEDATA: - ret = ptrace_writedata(child, (char __user *) addr2, - addr, data); + ret = ptrace_writedata(child, addr2p, addr, data); if (ret == data) ret = 0; else if (ret >= 0) diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index 5e50c09..4730eac 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -75,7 +75,7 @@ void __kunmap_atomic(void *kvaddr) return; } - type = kmap_atomic_idx_pop(); + type = kmap_atomic_idx(); #ifdef CONFIG_DEBUG_HIGHMEM { @@ -104,6 +104,8 @@ void __kunmap_atomic(void *kvaddr) #endif } #endif + + kmap_atomic_idx_pop(); pagefault_enable(); } EXPORT_SYMBOL(__kunmap_atomic); diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 89cfee0..7e8c284 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -58,6 +58,9 @@ config ARCH_SUPPORTS_OPTIMIZED_INLINING config ARCH_PHYS_ADDR_T_64BIT def_bool y +config ARCH_DMA_ADDR_T_64BIT + def_bool y + config LOCKDEP_SUPPORT def_bool y diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index 5b20c28..9cd2988 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c @@ -45,7 +45,8 @@ void ptrace_disable(struct task_struct *child) clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { unsigned long __user *datap = (long __user __force *)data; unsigned long tmp; @@ -57,7 +58,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) switch (request) { case PTRACE_PEEKUSR: /* Read register from pt_regs. */ - if (addr < 0 || addr >= PTREGS_SIZE) + if (addr >= PTREGS_SIZE) break; childreg = (char *)task_pt_regs(child) + addr; #ifdef CONFIG_COMPAT @@ -76,7 +77,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_POKEUSR: /* Write register in pt_regs. */ - if (addr < 0 || addr >= PTREGS_SIZE) + if (addr >= PTREGS_SIZE) break; childreg = (char *)task_pt_regs(child) + addr; #ifdef CONFIG_COMPAT @@ -98,7 +99,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE)) break; childregs = (long *)task_pt_regs(child); - for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i) { + for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long); + ++i) { ret = __put_user(childregs[i], &datap[i]); if (ret != 0) break; @@ -109,7 +111,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE)) break; childregs = (long *)task_pt_regs(child); - for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i) { + for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long); + ++i) { ret = __get_user(childregs[i], &datap[i]); if (ret != 0) break; diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index f3a50e7..ae51cad 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c @@ -30,8 +30,6 @@ #include <linux/timex.h> #include <asm/setup.h> #include <asm/sections.h> -#include <asm/sections.h> -#include <asm/cacheflush.h> #include <asm/cacheflush.h> #include <asm/pgalloc.h> #include <asm/mmu_context.h> diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c index 8ef6595..abb5733 100644 --- a/arch/tile/mm/highmem.c +++ b/arch/tile/mm/highmem.c @@ -241,7 +241,7 @@ void __kunmap_atomic(void *kvaddr) pte_t pteval = *pte; int idx, type; - type = kmap_atomic_idx_pop(); + type = kmap_atomic_idx(); idx = type + KM_TYPE_NR*smp_processor_id(); /* @@ -252,6 +252,7 @@ void __kunmap_atomic(void *kvaddr) BUG_ON(!pte_present(pteval) && !pte_migrating(pteval)); kmap_atomic_unregister(pte_page(pteval), vaddr); kpte_clear_flush(pte, vaddr); + kmap_atomic_idx_pop(); } else { /* Must be a lowmem page */ BUG_ON(vaddr < PAGE_OFFSET); diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index e051049..a5e33f2 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -42,10 +42,12 @@ void ptrace_disable(struct task_struct *child) extern int peek_user(struct task_struct * child, long addr, long data); extern int poke_user(struct task_struct * child, long addr, long data); -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int i, ret; - unsigned long __user *p = (void __user *)(unsigned long)data; + unsigned long __user *p = (void __user *)data; + void __user *vp = p; switch (request) { /* read word at location addr. */ @@ -107,24 +109,20 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #endif #ifdef PTRACE_GETFPREGS case PTRACE_GETFPREGS: /* Get the child FPU state. */ - ret = get_fpregs((struct user_i387_struct __user *) data, - child); + ret = get_fpregs(vp, child); break; #endif #ifdef PTRACE_SETFPREGS case PTRACE_SETFPREGS: /* Set the child FPU state. */ - ret = set_fpregs((struct user_i387_struct __user *) data, - child); + ret = set_fpregs(vp, child); break; #endif case PTRACE_GET_THREAD_AREA: - ret = ptrace_get_thread_area(child, addr, - (struct user_desc __user *) data); + ret = ptrace_get_thread_area(child, addr, vp); break; case PTRACE_SET_THREAD_AREA: - ret = ptrace_set_thread_area(child, addr, - (struct user_desc __user *) data); + ret = ptrace_set_thread_area(child, addr, datavp); break; case PTRACE_FAULTINFO: { @@ -134,7 +132,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) * On i386, ptrace_faultinfo is smaller! */ ret = copy_to_user(p, &child->thread.arch.faultinfo, - sizeof(struct ptrace_faultinfo)); + sizeof(struct ptrace_faultinfo)) ? + -EIO : 0; break; } @@ -158,7 +157,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef PTRACE_ARCH_PRCTL case PTRACE_ARCH_PRCTL: /* XXX Calls ptrace on the host - needs some SMP thinking */ - ret = arch_prctl(child, data, (void *) addr); + ret = arch_prctl(child, data, (void __user *) addr); break; #endif default: diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index c9b1765..d23b2d3 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -203,8 +203,8 @@ int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) (unsigned long *) &fpregs); } -long subarch_ptrace(struct task_struct *child, long request, long addr, - long data) +long subarch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { return -EIO; } diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index f3458d7..f436136 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c @@ -175,19 +175,18 @@ int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) return restore_fp_registers(userspace_pid[cpu], fpregs); } -long subarch_ptrace(struct task_struct *child, long request, long addr, - long data) +long subarch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret = -EIO; + void __user *datap = (void __user *) data; switch (request) { case PTRACE_GETFPXREGS: /* Get the child FPU state. */ - ret = get_fpregs((struct user_i387_struct __user *) data, - child); + ret = get_fpregs(datap, child); break; case PTRACE_SETFPXREGS: /* Set the child FPU state. */ - ret = set_fpregs((struct user_i387_struct __user *) data, - child); + ret = set_fpregs(datap, child); break; } diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 70c4872..45892dc 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -801,7 +801,8 @@ void ptrace_disable(struct task_struct *child) static const struct user_regset_view user_x86_32_view; /* Initialized below. */ #endif -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret; unsigned long __user *datap = (unsigned long __user *)data; @@ -812,8 +813,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned long tmp; ret = -EIO; - if ((addr & (sizeof(data) - 1)) || addr < 0 || - addr >= sizeof(struct user)) + if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user)) break; tmp = 0; /* Default return condition */ @@ -830,8 +830,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret = -EIO; - if ((addr & (sizeof(data) - 1)) || addr < 0 || - addr >= sizeof(struct user)) + if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user)) break; if (addr < sizeof(struct user_regs_struct)) @@ -888,17 +887,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION case PTRACE_GET_THREAD_AREA: - if (addr < 0) + if ((int) addr < 0) return -EIO; ret = do_get_thread_area(child, addr, - (struct user_desc __user *) data); + (struct user_desc __user *)data); break; case PTRACE_SET_THREAD_AREA: - if (addr < 0) + if ((int) addr < 0) return -EIO; ret = do_set_thread_area(child, addr, - (struct user_desc __user *) data, 0); + (struct user_desc __user *)data, 0); break; #endif diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index d723e36..b499626 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -74,7 +74,7 @@ void __kunmap_atomic(void *kvaddr) vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) { int idx, type; - type = kmap_atomic_idx_pop(); + type = kmap_atomic_idx(); idx = type + KM_TYPE_NR * smp_processor_id(); #ifdef CONFIG_DEBUG_HIGHMEM @@ -87,6 +87,7 @@ void __kunmap_atomic(void *kvaddr) * attributes or becomes a protected page in a hypervisor. */ kpte_clear_flush(kmap_pte-idx, vaddr); + kmap_atomic_idx_pop(); } #ifdef CONFIG_DEBUG_HIGHMEM else { diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 8434620..71a5929 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -51,7 +51,6 @@ #include <asm/numa.h> #include <asm/cacheflush.h> #include <asm/init.h> -#include <linux/bootmem.h> static int __init parse_direct_gbpages_off(char *arg) { diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c index 75a3d7f..7b179b49 100644 --- a/arch/x86/mm/iomap_32.c +++ b/arch/x86/mm/iomap_32.c @@ -98,7 +98,7 @@ iounmap_atomic(void __iomem *kvaddr) vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) { int idx, type; - type = kmap_atomic_idx_pop(); + type = kmap_atomic_idx(); idx = type + KM_TYPE_NR * smp_processor_id(); #ifdef CONFIG_DEBUG_HIGHMEM @@ -111,6 +111,7 @@ iounmap_atomic(void __iomem *kvaddr) * attributes or becomes a protected page in a hypervisor. */ kpte_clear_flush(kmap_pte-idx, vaddr); + kmap_atomic_idx_pop(); } pagefault_enable(); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 580da1a..70ddeae 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -59,7 +59,6 @@ #include <asm/pgtable.h> #include <asm/tlbflush.h> #include <asm/reboot.h> -#include <asm/setup.h> #include <asm/stackprotector.h> #include <asm/hypervisor.h> diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index 9d4e1ce..c72c947 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -256,9 +256,11 @@ int ptrace_pokeusr(struct task_struct *child, long regno, long val) return 0; } -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int ret = -EPERM; + void __user *datap = (void __user *) data; switch (request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -267,7 +269,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_PEEKUSR: /* read register specified by addr. */ - ret = ptrace_peekusr(child, addr, (void __user *) data); + ret = ptrace_peekusr(child, addr, datap); break; case PTRACE_POKETEXT: /* write the word at location addr. */ @@ -280,19 +282,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_GETREGS: - ret = ptrace_getregs(child, (void __user *) data); + ret = ptrace_getregs(child, datap); break; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (void __user *) data); + ret = ptrace_setregs(child, datap); break; case PTRACE_GETXTREGS: - ret = ptrace_getxregs(child, (void __user *) data); + ret = ptrace_getxregs(child, datap); break; case PTRACE_SETXTREGS: - ret = ptrace_setxregs(child, (void __user *) data); + ret = ptrace_setxregs(child, datap); break; default: diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index e7ba774..25373df 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -566,6 +566,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_ struct mailbox mailbox; /* Got a packet for us */ + memset(&st_loc, 0, sizeof(st_loc)); ret = do_ac_read(i, buf, &st_loc, &mailbox); spin_unlock_irqrestore(&apbs[i].mutex, flags); set_current_state(TASK_RUNNING); diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 3afd62e..e9cba13 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -713,7 +713,6 @@ static int khvcd(void *unused) struct hvc_struct *hp; set_freezable(); - __set_current_state(TASK_RUNNING); do { poll_mask = 0; hvc_kicked = 0; diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile index bc397d9..7b78e0d 100644 --- a/drivers/char/ip2/Makefile +++ b/drivers/char/ip2/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_COMPUTONE) += ip2.o -ip2-objs := ip2main.o +ip2-y := ip2main.o diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index eb8a1a8..16a9364 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -2,7 +2,7 @@ # Makefile for the ipmi drivers. # -ipmi_si-objs := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o +ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 1fc8876..2aa3977 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -916,7 +916,7 @@ static struct ipmi_smi_watcher smi_watcher = .smi_gone = ipmi_smi_gone, }; -static __init int init_ipmi_devintf(void) +static int __init init_ipmi_devintf(void) { int rv; @@ -954,7 +954,7 @@ static __init int init_ipmi_devintf(void) } module_init(init_ipmi_devintf); -static __exit void cleanup_ipmi(void) +static void __exit cleanup_ipmi(void) { struct ipmi_reg_list *entry, *entry2; mutex_lock(®_list_mutex); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 4f3f8c9..2fe72f8 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -4442,13 +4442,13 @@ static int ipmi_init_msghandler(void) return 0; } -static __init int ipmi_init_msghandler_mod(void) +static int __init ipmi_init_msghandler_mod(void) { ipmi_init_msghandler(); return 0; } -static __exit void cleanup_ipmi(void) +static void __exit cleanup_ipmi(void) { int count; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b293d57..035da9e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1846,7 +1846,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) return rv; } -static __devinit void hardcode_find_bmc(void) +static void __devinit hardcode_find_bmc(void) { int i; struct smi_info *info; @@ -2029,7 +2029,7 @@ struct SPMITable { s8 spmi_id[1]; /* A '\0' terminated array starts here. */ }; -static __devinit int try_init_spmi(struct SPMITable *spmi) +static int __devinit try_init_spmi(struct SPMITable *spmi) { struct smi_info *info; @@ -2112,7 +2112,7 @@ static __devinit int try_init_spmi(struct SPMITable *spmi) return 0; } -static __devinit void spmi_find_bmc(void) +static void __devinit spmi_find_bmc(void) { acpi_status status; struct SPMITable *spmi; @@ -2325,7 +2325,7 @@ static int __devinit decode_dmi(const struct dmi_header *dm, return 0; } -static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) +static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data) { struct smi_info *info; @@ -3012,7 +3012,7 @@ static __devinitdata struct ipmi_default_vals { .port = 0 } }; -static __devinit void default_find_bmc(void) +static void __devinit default_find_bmc(void) { struct smi_info *info; int i; @@ -3312,7 +3312,7 @@ static int try_smi_init(struct smi_info *new_smi) return rv; } -static __devinit int init_ipmi_si(void) +static int __devinit init_ipmi_si(void) { int i; char *str; @@ -3525,7 +3525,7 @@ static void cleanup_one_si(struct smi_info *to_clean) kfree(to_clean); } -static __exit void cleanup_ipmi_si(void) +static void __exit cleanup_ipmi_si(void) { struct smi_info *e, *tmp_e; diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index c070b53..e6d7562 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -176,9 +176,9 @@ static void mmtimer_setup_int_2(int cpu, u64 expires) * in order to insure that the setup succeeds in a deterministic time frame. * It will check if the interrupt setup succeeded. */ -static int mmtimer_setup(int cpu, int comparator, unsigned long expires) +static int mmtimer_setup(int cpu, int comparator, unsigned long expires, + u64 *set_completion_time) { - switch (comparator) { case 0: mmtimer_setup_int_0(cpu, expires); @@ -191,7 +191,8 @@ static int mmtimer_setup(int cpu, int comparator, unsigned long expires) break; } /* We might've missed our expiration time */ - if (rtc_time() <= expires) + *set_completion_time = rtc_time(); + if (*set_completion_time <= expires) return 1; /* @@ -227,6 +228,8 @@ static int mmtimer_disable_int(long nasid, int comparator) #define TIMER_OFF 0xbadcabLL /* Timer is not setup */ #define TIMER_SET 0 /* Comparator is set for this timer */ +#define MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT 40 + /* There is one of these for each timer */ struct mmtimer { struct rb_node list; @@ -242,6 +245,11 @@ struct mmtimer_node { }; static struct mmtimer_node *timers; +static unsigned mmtimer_interval_retry_increment = + MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT; +module_param(mmtimer_interval_retry_increment, uint, 0644); +MODULE_PARM_DESC(mmtimer_interval_retry_increment, + "RTC ticks to add to expiration on interval retry (default 40)"); /* * Add a new mmtimer struct to the node's mmtimer list. @@ -289,7 +297,8 @@ static void mmtimer_set_next_timer(int nodeid) struct mmtimer_node *n = &timers[nodeid]; struct mmtimer *x; struct k_itimer *t; - int o; + u64 expires, exp, set_completion_time; + int i; restart: if (n->next == NULL) @@ -300,7 +309,8 @@ restart: if (!t->it.mmtimer.incr) { /* Not an interval timer */ if (!mmtimer_setup(x->cpu, COMPARATOR, - t->it.mmtimer.expires)) { + t->it.mmtimer.expires, + &set_completion_time)) { /* Late setup, fire now */ tasklet_schedule(&n->tasklet); } @@ -308,14 +318,23 @@ restart: } /* Interval timer */ - o = 0; - while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) { - unsigned long e, e1; - struct rb_node *next; - t->it.mmtimer.expires += t->it.mmtimer.incr << o; - t->it_overrun += 1 << o; - o++; - if (o > 20) { + i = 0; + expires = exp = t->it.mmtimer.expires; + while (!mmtimer_setup(x->cpu, COMPARATOR, expires, + &set_completion_time)) { + int to; + + i++; + expires = set_completion_time + + mmtimer_interval_retry_increment + (1 << i); + /* Calculate overruns as we go. */ + to = ((u64)(expires - exp) / t->it.mmtimer.incr); + if (to) { + t->it_overrun += to; + t->it.mmtimer.expires += t->it.mmtimer.incr * to; + exp = t->it.mmtimer.expires; + } + if (i > 20) { printk(KERN_ALERT "mmtimer: cannot reschedule timer\n"); t->it.mmtimer.clock = TIMER_OFF; n->next = rb_next(&x->list); @@ -323,21 +342,6 @@ restart: kfree(x); goto restart; } - - e = t->it.mmtimer.expires; - next = rb_next(&x->list); - - if (next == NULL) - continue; - - e1 = rb_entry(next, struct mmtimer, list)-> - timer->it.mmtimer.expires; - if (e > e1) { - n->next = next; - rb_erase(&x->list, &n->timer_head); - mmtimer_add_list(x); - goto restart; - } } } diff --git a/drivers/char/mwave/Makefile b/drivers/char/mwave/Makefile index 754c9e2..26b4fce 100644 --- a/drivers/char/mwave/Makefile +++ b/drivers/char/mwave/Makefile @@ -6,10 +6,10 @@ obj-$(CONFIG_MWAVE) += mwave.o -mwave-objs := mwavedd.o smapi.o tp3780i.o 3780i.o +mwave-y := mwavedd.o smapi.o tp3780i.o 3780i.o # To have the mwave driver disable other uarts if necessary # EXTRA_CFLAGS += -DMWAVE_FUTZ_WITH_OTHER_DEVICES # To compile in lots (~20 KiB) of run-time enablable printk()s for debugging: -EXTRA_CFLAGS += -DMW_TRACE +ccflags-y := -DMW_TRACE diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 463df27..dd9d753 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -303,6 +303,7 @@ static void mxser_enable_must_enchance_mode(unsigned long baseio) outb(oldlcr, baseio + UART_LCR); } +#ifdef CONFIG_PCI static void mxser_disable_must_enchance_mode(unsigned long baseio) { u8 oldlcr; @@ -317,6 +318,7 @@ static void mxser_disable_must_enchance_mode(unsigned long baseio) outb(efr, baseio + MOXA_MUST_EFR_REGISTER); outb(oldlcr, baseio + UART_LCR); } +#endif static void mxser_set_must_xon1_value(unsigned long baseio, u8 value) { @@ -388,6 +390,7 @@ static void mxser_set_must_enum_value(unsigned long baseio, u8 value) outb(oldlcr, baseio + UART_LCR); } +#ifdef CONFIG_PCI static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId) { u8 oldlcr; @@ -404,6 +407,7 @@ static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId) *pId = inb(baseio + MOXA_MUST_HWID_REGISTER); outb(oldlcr, baseio + UART_LCR); } +#endif static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio) { diff --git a/drivers/char/pcmcia/ipwireless/Makefile b/drivers/char/pcmcia/ipwireless/Makefile index b71eb59..db80873d 100644 --- a/drivers/char/pcmcia/ipwireless/Makefile +++ b/drivers/char/pcmcia/ipwireless/Makefile @@ -6,5 +6,5 @@ obj-$(CONFIG_IPWIRELESS) += ipwireless.o -ipwireless-objs := hardware.o main.o network.o tty.o +ipwireless-y := hardware.o main.o network.o tty.o diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 723152d..f176dba 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -613,6 +613,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case PPGETTIME: to_jiffies = pp->pdev->timeout; + memset(&par_timeout, 0, sizeof(par_timeout)); par_timeout.tv_sec = to_jiffies / HZ; par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ); if (copy_to_user (argp, &par_timeout, sizeof(struct timeval))) diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c index 74f00b5..73dcb0e 100644 --- a/drivers/char/ramoops.c +++ b/drivers/char/ramoops.c @@ -25,6 +25,8 @@ #include <linux/time.h> #include <linux/io.h> #include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/ramoops.h> #define RAMOOPS_KERNMSG_HDR "====" #define RAMOOPS_HEADER_SIZE (5 + sizeof(struct timeval)) @@ -91,11 +93,17 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, cxt->count = (cxt->count + 1) % cxt->max_count; } -static int __init ramoops_init(void) +static int __init ramoops_probe(struct platform_device *pdev) { + struct ramoops_platform_data *pdata = pdev->dev.platform_data; struct ramoops_context *cxt = &oops_cxt; int err = -EINVAL; + if (pdata) { + mem_size = pdata->mem_size; + mem_address = pdata->mem_address; + } + if (!mem_size) { printk(KERN_ERR "ramoops: invalid size specification"); goto fail3; @@ -142,7 +150,7 @@ fail3: return err; } -static void __exit ramoops_exit(void) +static int __exit ramoops_remove(struct platform_device *pdev) { struct ramoops_context *cxt = &oops_cxt; @@ -151,8 +159,26 @@ static void __exit ramoops_exit(void) iounmap(cxt->virt_addr); release_mem_region(cxt->phys_addr, cxt->size); + return 0; } +static struct platform_driver ramoops_driver = { + .remove = __exit_p(ramoops_remove), + .driver = { + .name = "ramoops", + .owner = THIS_MODULE, + }, +}; + +static int __init ramoops_init(void) +{ + return platform_driver_probe(&ramoops_driver, ramoops_probe); +} + +static void __exit ramoops_exit(void) +{ + platform_driver_unregister(&ramoops_driver); +} module_init(ramoops_init); module_exit(ramoops_exit); diff --git a/drivers/char/rio/Makefile b/drivers/char/rio/Makefile index 2d1c5a7..1661875 100644 --- a/drivers/char/rio/Makefile +++ b/drivers/char/rio/Makefile @@ -8,5 +8,5 @@ obj-$(CONFIG_RIO) += rio.o -rio-objs := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \ +rio-y := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \ rioparam.o rioroute.o riotable.o riotty.o diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 7c79d24..86308830 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -2345,7 +2345,7 @@ static int __init rp_init(void) ret = tty_register_driver(rocket_driver); if (ret < 0) { printk(KERN_ERR "Couldn't install tty RocketPort driver\n"); - goto err_tty; + goto err_controller; } #ifdef ROCKET_DEBUG_OPEN @@ -2380,6 +2380,9 @@ static int __init rp_init(void) return 0; err_ttyu: tty_unregister_driver(rocket_driver); +err_controller: + if (controller) + release_region(controller, 4); err_tty: put_tty_driver(rocket_driver); err: diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 1746d91..d01fffe 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -301,6 +301,8 @@ struct slgt_info { unsigned int rx_pio; unsigned int if_mode; unsigned int base_clock; + unsigned int xsync; + unsigned int xctrl; /* device status */ @@ -405,6 +407,8 @@ static MGSL_PARAMS default_params = { #define TDCSR 0x94 /* tx DMA control/status */ #define RDDAR 0x98 /* rx DMA descriptor address */ #define TDDAR 0x9c /* tx DMA descriptor address */ +#define XSR 0x40 /* extended sync pattern */ +#define XCR 0x44 /* extended control */ #define RXIDLE BIT14 #define RXBREAK BIT14 @@ -517,6 +521,10 @@ static int set_interface(struct slgt_info *info, int if_mode); static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); static int get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); +static int get_xsync(struct slgt_info *info, int __user *if_mode); +static int set_xsync(struct slgt_info *info, int if_mode); +static int get_xctrl(struct slgt_info *info, int __user *if_mode); +static int set_xctrl(struct slgt_info *info, int if_mode); /* * driver functions @@ -1056,6 +1064,14 @@ static int ioctl(struct tty_struct *tty, struct file *file, return get_gpio(info, argp); case MGSL_IOCWAITGPIO: return wait_gpio(info, argp); + case MGSL_IOCGXSYNC: + return get_xsync(info, argp); + case MGSL_IOCSXSYNC: + return set_xsync(info, (int)arg); + case MGSL_IOCGXCTRL: + return get_xctrl(info, argp); + case MGSL_IOCSXCTRL: + return set_xctrl(info, (int)arg); } mutex_lock(&info->port.mutex); switch (cmd) { @@ -1132,6 +1148,7 @@ static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *us struct MGSL_PARAMS32 tmp_params; DBGINFO(("%s get_params32\n", info->device_name)); + memset(&tmp_params, 0, sizeof(tmp_params)); tmp_params.mode = (compat_ulong_t)info->params.mode; tmp_params.loopback = info->params.loopback; tmp_params.flags = info->params.flags; @@ -1212,12 +1229,16 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file, case MGSL_IOCSGPIO: case MGSL_IOCGGPIO: case MGSL_IOCWAITGPIO: + case MGSL_IOCGXSYNC: + case MGSL_IOCGXCTRL: case MGSL_IOCSTXIDLE: case MGSL_IOCTXENABLE: case MGSL_IOCRXENABLE: case MGSL_IOCTXABORT: case TIOCMIWAIT: case MGSL_IOCSIF: + case MGSL_IOCSXSYNC: + case MGSL_IOCSXCTRL: rc = ioctl(tty, file, cmd, arg); break; } @@ -1617,6 +1638,8 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (cmd != SIOCWANDEV) return hdlc_ioctl(dev, ifr, cmd); + memset(&new_line, 0, sizeof(new_line)); + switch(ifr->ifr_settings.type) { case IF_GET_IFACE: /* return current sync_serial_settings */ @@ -1958,6 +1981,7 @@ static void bh_handler(struct work_struct *work) case MGSL_MODE_RAW: case MGSL_MODE_MONOSYNC: case MGSL_MODE_BISYNC: + case MGSL_MODE_XSYNC: while(rx_get_buf(info)); break; } @@ -2357,26 +2381,27 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id) DBGISR(("slgt_interrupt irq=%d entry\n", info->irq_level)); - spin_lock(&info->lock); - while((gsr = rd_reg32(info, GSR) & 0xffffff00)) { DBGISR(("%s gsr=%08x\n", info->device_name, gsr)); info->irq_occurred = true; for(i=0; i < info->port_count ; i++) { if (info->port_array[i] == NULL) continue; + spin_lock(&info->port_array[i]->lock); if (gsr & (BIT8 << i)) isr_serial(info->port_array[i]); if (gsr & (BIT16 << (i*2))) isr_rdma(info->port_array[i]); if (gsr & (BIT17 << (i*2))) isr_tdma(info->port_array[i]); + spin_unlock(&info->port_array[i]->lock); } } if (info->gpio_present) { unsigned int state; unsigned int changed; + spin_lock(&info->lock); while ((changed = rd_reg32(info, IOSR)) != 0) { DBGISR(("%s iosr=%08x\n", info->device_name, changed)); /* read latched state of GPIO signals */ @@ -2388,22 +2413,24 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id) isr_gpio(info->port_array[i], changed, state); } } + spin_unlock(&info->lock); } for(i=0; i < info->port_count ; i++) { struct slgt_info *port = info->port_array[i]; - - if (port && (port->port.count || port->netcount) && + if (port == NULL) + continue; + spin_lock(&port->lock); + if ((port->port.count || port->netcount) && port->pending_bh && !port->bh_running && !port->bh_requested) { DBGISR(("%s bh queued\n", port->device_name)); schedule_work(&port->task); port->bh_requested = true; } + spin_unlock(&port->lock); } - spin_unlock(&info->lock); - DBGISR(("slgt_interrupt irq=%d exit\n", info->irq_level)); return IRQ_HANDLED; } @@ -2883,6 +2910,69 @@ static int set_interface(struct slgt_info *info, int if_mode) return 0; } +static int get_xsync(struct slgt_info *info, int __user *xsync) +{ + DBGINFO(("%s get_xsync=%x\n", info->device_name, info->xsync)); + if (put_user(info->xsync, xsync)) + return -EFAULT; + return 0; +} + +/* + * set extended sync pattern (1 to 4 bytes) for extended sync mode + * + * sync pattern is contained in least significant bytes of value + * most significant byte of sync pattern is oldest (1st sent/detected) + */ +static int set_xsync(struct slgt_info *info, int xsync) +{ + unsigned long flags; + + DBGINFO(("%s set_xsync=%x)\n", info->device_name, xsync)); + spin_lock_irqsave(&info->lock, flags); + info->xsync = xsync; + wr_reg32(info, XSR, xsync); + spin_unlock_irqrestore(&info->lock, flags); + return 0; +} + +static int get_xctrl(struct slgt_info *info, int __user *xctrl) +{ + DBGINFO(("%s get_xctrl=%x\n", info->device_name, info->xctrl)); + if (put_user(info->xctrl, xctrl)) + return -EFAULT; + return 0; +} + +/* + * set extended control options + * + * xctrl[31:19] reserved, must be zero + * xctrl[18:17] extended sync pattern length in bytes + * 00 = 1 byte in xsr[7:0] + * 01 = 2 bytes in xsr[15:0] + * 10 = 3 bytes in xsr[23:0] + * 11 = 4 bytes in xsr[31:0] + * xctrl[16] 1 = enable terminal count, 0=disabled + * xctrl[15:0] receive terminal count for fixed length packets + * value is count minus one (0 = 1 byte packet) + * when terminal count is reached, receiver + * automatically returns to hunt mode and receive + * FIFO contents are flushed to DMA buffers with + * end of frame (EOF) status + */ +static int set_xctrl(struct slgt_info *info, int xctrl) +{ + unsigned long flags; + + DBGINFO(("%s set_xctrl=%x)\n", info->device_name, xctrl)); + spin_lock_irqsave(&info->lock, flags); + info->xctrl = xctrl; + wr_reg32(info, XCR, xctrl); + spin_unlock_irqrestore(&info->lock, flags); + return 0; +} + /* * set general purpose IO pin state and direction * @@ -2906,7 +2996,7 @@ static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) info->device_name, gpio.state, gpio.smask, gpio.dir, gpio.dmask)); - spin_lock_irqsave(&info->lock,flags); + spin_lock_irqsave(&info->port_array[0]->lock, flags); if (gpio.dmask) { data = rd_reg32(info, IODR); data |= gpio.dmask & gpio.dir; @@ -2919,7 +3009,7 @@ static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) data &= ~(gpio.smask & ~gpio.state); wr_reg32(info, IOVR, data); } - spin_unlock_irqrestore(&info->lock,flags); + spin_unlock_irqrestore(&info->port_array[0]->lock, flags); return 0; } @@ -3020,7 +3110,7 @@ static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) return -EINVAL; init_cond_wait(&wait, gpio.smask); - spin_lock_irqsave(&info->lock, flags); + spin_lock_irqsave(&info->port_array[0]->lock, flags); /* enable interrupts for watched pins */ wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask); /* get current pin states */ @@ -3032,20 +3122,20 @@ static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) } else { /* wait for target state */ add_cond_wait(&info->gpio_wait_q, &wait); - spin_unlock_irqrestore(&info->lock, flags); + spin_unlock_irqrestore(&info->port_array[0]->lock, flags); schedule(); if (signal_pending(current)) rc = -ERESTARTSYS; else gpio.state = wait.data; - spin_lock_irqsave(&info->lock, flags); + spin_lock_irqsave(&info->port_array[0]->lock, flags); remove_cond_wait(&info->gpio_wait_q, &wait); } /* disable all GPIO interrupts if no waiting processes */ if (info->gpio_wait_q == NULL) wr_reg32(info, IOER, 0); - spin_unlock_irqrestore(&info->lock,flags); + spin_unlock_irqrestore(&info->port_array[0]->lock, flags); if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio))) rc = -EFAULT; @@ -3578,7 +3668,6 @@ static void device_init(int adapter_num, struct pci_dev *pdev) /* copy resource information from first port to others */ for (i = 1; i < port_count; ++i) { - port_array[i]->lock = port_array[0]->lock; port_array[i]->irq_level = port_array[0]->irq_level; port_array[i]->reg_addr = port_array[0]->reg_addr; alloc_dma_bufs(port_array[i]); @@ -3763,7 +3852,9 @@ module_exit(slgt_exit); #define CALC_REGADDR() \ unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \ if (addr >= 0x80) \ - reg_addr += (info->port_num) * 32; + reg_addr += (info->port_num) * 32; \ + else if (addr >= 0x40) \ + reg_addr += (info->port_num) * 16; static __u8 rd_reg8(struct slgt_info *info, unsigned int addr) { @@ -4182,7 +4273,13 @@ static void sync_mode(struct slgt_info *info) /* TCR (tx control) * - * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync + * 15..13 mode + * 000=HDLC/SDLC + * 001=raw bit synchronous + * 010=asynchronous/isochronous + * 011=monosync byte synchronous + * 100=bisync byte synchronous + * 101=xsync byte synchronous * 12..10 encoding * 09 CRC enable * 08 CRC32 @@ -4197,6 +4294,9 @@ static void sync_mode(struct slgt_info *info) val = BIT2; switch(info->params.mode) { + case MGSL_MODE_XSYNC: + val |= BIT15 + BIT13; + break; case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; case MGSL_MODE_BISYNC: val |= BIT15; break; case MGSL_MODE_RAW: val |= BIT13; break; @@ -4251,7 +4351,13 @@ static void sync_mode(struct slgt_info *info) /* RCR (rx control) * - * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync + * 15..13 mode + * 000=HDLC/SDLC + * 001=raw bit synchronous + * 010=asynchronous/isochronous + * 011=monosync byte synchronous + * 100=bisync byte synchronous + * 101=xsync byte synchronous * 12..10 encoding * 09 CRC enable * 08 CRC32 @@ -4263,6 +4369,9 @@ static void sync_mode(struct slgt_info *info) val = 0; switch(info->params.mode) { + case MGSL_MODE_XSYNC: + val |= BIT15 + BIT13; + break; case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; case MGSL_MODE_BISYNC: val |= BIT15; break; case MGSL_MODE_RAW: val |= BIT13; break; @@ -4679,6 +4788,7 @@ static bool rx_get_buf(struct slgt_info *info) switch(info->params.mode) { case MGSL_MODE_MONOSYNC: case MGSL_MODE_BISYNC: + case MGSL_MODE_XSYNC: /* ignore residue in byte synchronous modes */ if (desc_residue(info->rbufs[i])) count--; diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 38df8c1..6b68a0f 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -503,6 +503,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, struct kbd_struct * kbd; unsigned int console; unsigned char ucval; + unsigned int uival; void __user *up = (void __user *)arg; int i, perm; int ret = 0; @@ -657,7 +658,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, break; case KDGETMODE: - ucval = vc->vc_mode; + uival = vc->vc_mode; goto setint; case KDMAPDISP: @@ -695,7 +696,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, break; case KDGKBMODE: - ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : + uival = ((kbd->kbdmode == VC_RAW) ? K_RAW : (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : K_XLATE); @@ -717,9 +718,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, break; case KDGKBMETA: - ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); + uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); setint: - ret = put_user(ucval, (int __user *)arg); + ret = put_user(uival, (int __user *)arg); break; case KDGETKEYCODE: @@ -949,7 +950,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, for (i = 0; i < MAX_NR_CONSOLES; ++i) if (! VT_IS_IN_USE(i)) break; - ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; + uival = i < MAX_NR_CONSOLES ? (i+1) : -1; goto setint; /* diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index b3d22d6..e28e41668 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -2,6 +2,7 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/ctype.h> #include <linux/dmi.h> #include <linux/efi.h> #include <linux/bootmem.h> @@ -361,6 +362,33 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy) } } +static void __init print_filtered(const char *info) +{ + const char *p; + + if (!info) + return; + + for (p = info; *p; p++) + if (isprint(*p)) + printk(KERN_CONT "%c", *p); + else + printk(KERN_CONT "\\x%02x", *p & 0xff); +} + +static void __init dmi_dump_ids(void) +{ + printk(KERN_DEBUG "DMI: "); + print_filtered(dmi_get_system_info(DMI_BOARD_NAME)); + printk(KERN_CONT "/"); + print_filtered(dmi_get_system_info(DMI_PRODUCT_NAME)); + printk(KERN_CONT ", BIOS "); + print_filtered(dmi_get_system_info(DMI_BIOS_VERSION)); + printk(KERN_CONT " "); + print_filtered(dmi_get_system_info(DMI_BIOS_DATE)); + printk(KERN_CONT "\n"); +} + static int __init dmi_present(const char __iomem *p) { u8 buf[15]; @@ -381,8 +409,10 @@ static int __init dmi_present(const char __iomem *p) buf[14] >> 4, buf[14] & 0xF); else printk(KERN_INFO "DMI present.\n"); - if (dmi_walk_early(dmi_decode) == 0) + if (dmi_walk_early(dmi_decode) == 0) { + dmi_dump_ids(); return 0; + } } return 1; } diff --git a/drivers/gpio/74x164.c b/drivers/gpio/74x164.c new file mode 100644 index 0000000..d91ff4c --- /dev/null +++ b/drivers/gpio/74x164.c @@ -0,0 +1,182 @@ +/* + * 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver + * + * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2010 Miguel Gaio <miguel.gaio@efixo.com> + * + * 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. + */ + +#include <linux/init.h> +#include <linux/mutex.h> +#include <linux/spi/spi.h> +#include <linux/spi/74x164.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#define GEN_74X164_GPIO_COUNT 8 + + +struct gen_74x164_chip { + struct spi_device *spi; + struct gpio_chip gpio_chip; + struct mutex lock; + u8 port_config; +}; + +static void gen_74x164_set_value(struct gpio_chip *, unsigned, int); + +static struct gen_74x164_chip *gpio_to_chip(struct gpio_chip *gc) +{ + return container_of(gc, struct gen_74x164_chip, gpio_chip); +} + +static int __gen_74x164_write_config(struct gen_74x164_chip *chip) +{ + return spi_write(chip->spi, + &chip->port_config, sizeof(chip->port_config)); +} + +static int gen_74x164_direction_output(struct gpio_chip *gc, + unsigned offset, int val) +{ + gen_74x164_set_value(gc, offset, val); + return 0; +} + +static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct gen_74x164_chip *chip = gpio_to_chip(gc); + int ret; + + mutex_lock(&chip->lock); + ret = (chip->port_config >> offset) & 0x1; + mutex_unlock(&chip->lock); + + return ret; +} + +static void gen_74x164_set_value(struct gpio_chip *gc, + unsigned offset, int val) +{ + struct gen_74x164_chip *chip = gpio_to_chip(gc); + + mutex_lock(&chip->lock); + if (val) + chip->port_config |= (1 << offset); + else + chip->port_config &= ~(1 << offset); + + __gen_74x164_write_config(chip); + mutex_unlock(&chip->lock); +} + +static int __devinit gen_74x164_probe(struct spi_device *spi) +{ + struct gen_74x164_chip *chip; + struct gen_74x164_chip_platform_data *pdata; + int ret; + + pdata = spi->dev.platform_data; + if (!pdata || !pdata->base) { + dev_dbg(&spi->dev, "incorrect or missing platform data\n"); + return -EINVAL; + } + + /* + * bits_per_word cannot be configured in platform data + */ + spi->bits_per_word = 8; + + ret = spi_setup(spi); + if (ret < 0) + return ret; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + mutex_init(&chip->lock); + + dev_set_drvdata(&spi->dev, chip); + + chip->spi = spi; + + chip->gpio_chip.label = GEN_74X164_DRIVER_NAME, + chip->gpio_chip.direction_output = gen_74x164_direction_output; + chip->gpio_chip.get = gen_74x164_get_value; + chip->gpio_chip.set = gen_74x164_set_value; + chip->gpio_chip.base = pdata->base; + chip->gpio_chip.ngpio = GEN_74X164_GPIO_COUNT; + chip->gpio_chip.can_sleep = 1; + chip->gpio_chip.dev = &spi->dev; + chip->gpio_chip.owner = THIS_MODULE; + + ret = __gen_74x164_write_config(chip); + if (ret) { + dev_err(&spi->dev, "Failed writing: %d\n", ret); + goto exit_destroy; + } + + ret = gpiochip_add(&chip->gpio_chip); + if (ret) + goto exit_destroy; + + return ret; + +exit_destroy: + dev_set_drvdata(&spi->dev, NULL); + mutex_destroy(&chip->lock); + kfree(chip); + return ret; +} + +static int gen_74x164_remove(struct spi_device *spi) +{ + struct gen_74x164_chip *chip; + int ret; + + chip = dev_get_drvdata(&spi->dev); + if (chip == NULL) + return -ENODEV; + + dev_set_drvdata(&spi->dev, NULL); + + ret = gpiochip_remove(&chip->gpio_chip); + if (!ret) { + mutex_destroy(&chip->lock); + kfree(chip); + } else + dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n", + ret); + + return ret; +} + +static struct spi_driver gen_74x164_driver = { + .driver = { + .name = GEN_74X164_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = gen_74x164_probe, + .remove = __devexit_p(gen_74x164_remove), +}; + +static int __init gen_74x164_init(void) +{ + return spi_register_driver(&gen_74x164_driver); +} +subsys_initcall(gen_74x164_init); + +static void __exit gen_74x164_exit(void) +{ + spi_unregister_driver(&gen_74x164_driver); +} +module_exit(gen_74x164_exit); + +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>"); +MODULE_DESCRIPTION("GPIO expander driver for 74X164 8-bits shift register"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 510aa20..dd9b4ba 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -70,6 +70,11 @@ config GPIO_MAX730X comment "Memory mapped GPIO expanders:" +config GPIO_BASIC_MMIO + tristate "Basic memory-mapped GPIO controllers support" + help + Say yes here to support basic memory-mapped GPIO controllers. + config GPIO_IT8761E tristate "IT8761E GPIO support" depends on GPIOLIB @@ -267,6 +272,13 @@ config GPIO_ADP5588 To compile this driver as a module, choose M here: the module will be called adp5588-gpio. +config GPIO_ADP5588_IRQ + bool "Interrupt controller support for ADP5588" + depends on GPIO_ADP5588=y + help + Say yes here to enable the adp5588 to be used as an interrupt + controller. It requires the driver to be built in the kernel. + comment "PCI GPIO expanders:" config GPIO_CS5535 @@ -301,6 +313,14 @@ config GPIO_LANGWELL help Say Y here to support Intel Langwell/Penwell GPIO. +config GPIO_PCH + tristate "PCH GPIO of Intel Topcliff" + depends on PCI + help + This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff + which is an IOH(Input/Output Hub) for x86 embedded processor. + This driver can access PCH GPIO device. + config GPIO_TIMBERDALE bool "Support for timberdale GPIO IP" depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM @@ -339,6 +359,14 @@ config GPIO_MC33880 SPI driver for Freescale MC33880 high-side/low-side switch. This provides GPIO interface supporting inputs and outputs. +config GPIO_74X164 + tristate "74x164 serial-in/parallel-out 8-bits shift register" + depends on SPI_MASTER + help + Platform driver for 74x164 compatible serial-in/parallel-out + 8-outputs shift registers. This driver can be used to provide access + to more gpio outputs. + comment "AC97 GPIO expanders:" config GPIO_UCB1400 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fc6019d..da2ecde 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o +obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o obj-$(CONFIG_GPIO_MAX730X) += max730x.o obj-$(CONFIG_GPIO_MAX7300) += max7300.o @@ -17,8 +18,10 @@ obj-$(CONFIG_GPIO_MAX7301) += max7301.o obj-$(CONFIG_GPIO_MAX732X) += max732x.o obj-$(CONFIG_GPIO_MC33880) += mc33880.o obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o +obj-$(CONFIG_GPIO_74X164) += 74x164.o obj-$(CONFIG_GPIO_PCA953X) += pca953x.o obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o +obj-$(CONFIG_GPIO_PCH) += pch_gpio.o obj-$(CONFIG_GPIO_PL061) += pl061.o obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o diff --git a/drivers/gpio/adp5588-gpio.c b/drivers/gpio/adp5588-gpio.c index 2e8e9e2..0871f78 100644 --- a/drivers/gpio/adp5588-gpio.c +++ b/drivers/gpio/adp5588-gpio.c @@ -1,8 +1,8 @@ /* * GPIO Chip driver for Analog Devices - * ADP5588 I/O Expander and QWERTY Keypad Controller + * ADP5588/ADP5587 I/O Expander and QWERTY Keypad Controller * - * Copyright 2009 Analog Devices Inc. + * Copyright 2009-2010 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ @@ -13,21 +13,34 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/i2c/adp5588.h> -#define DRV_NAME "adp5588-gpio" -#define MAXGPIO 18 -#define ADP_BANK(offs) ((offs) >> 3) -#define ADP_BIT(offs) (1u << ((offs) & 0x7)) +#define DRV_NAME "adp5588-gpio" + +/* + * Early pre 4.0 Silicon required to delay readout by at least 25ms, + * since the Event Counter Register updated 25ms after the interrupt + * asserted. + */ +#define WA_DELAYED_READOUT_REVID(rev) ((rev) < 4) struct adp5588_gpio { struct i2c_client *client; struct gpio_chip gpio_chip; struct mutex lock; /* protect cached dir, dat_out */ + /* protect serialized access to the interrupt controller bus */ + struct mutex irq_lock; unsigned gpio_start; + unsigned irq_base; uint8_t dat_out[3]; uint8_t dir[3]; + uint8_t int_lvl[3]; + uint8_t int_en[3]; + uint8_t irq_mask[3]; + uint8_t irq_stat[3]; }; static int adp5588_gpio_read(struct i2c_client *client, u8 reg) @@ -55,8 +68,8 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) struct adp5588_gpio *dev = container_of(chip, struct adp5588_gpio, gpio_chip); - return !!(adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + ADP_BANK(off)) - & ADP_BIT(off)); + return !!(adp5588_gpio_read(dev->client, + GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off)); } static void adp5588_gpio_set_value(struct gpio_chip *chip, @@ -66,8 +79,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip, struct adp5588_gpio *dev = container_of(chip, struct adp5588_gpio, gpio_chip); - bank = ADP_BANK(off); - bit = ADP_BIT(off); + bank = ADP5588_BANK(off); + bit = ADP5588_BIT(off); mutex_lock(&dev->lock); if (val) @@ -87,10 +100,10 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off) struct adp5588_gpio *dev = container_of(chip, struct adp5588_gpio, gpio_chip); - bank = ADP_BANK(off); + bank = ADP5588_BANK(off); mutex_lock(&dev->lock); - dev->dir[bank] &= ~ADP_BIT(off); + dev->dir[bank] &= ~ADP5588_BIT(off); ret = adp5588_gpio_write(dev->client, GPIO_DIR1 + bank, dev->dir[bank]); mutex_unlock(&dev->lock); @@ -105,8 +118,8 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip, struct adp5588_gpio *dev = container_of(chip, struct adp5588_gpio, gpio_chip); - bank = ADP_BANK(off); - bit = ADP_BIT(off); + bank = ADP5588_BANK(off); + bit = ADP5588_BIT(off); mutex_lock(&dev->lock); dev->dir[bank] |= bit; @@ -125,6 +138,213 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip, return ret; } +#ifdef CONFIG_GPIO_ADP5588_IRQ +static int adp5588_gpio_to_irq(struct gpio_chip *chip, unsigned off) +{ + struct adp5588_gpio *dev = + container_of(chip, struct adp5588_gpio, gpio_chip); + return dev->irq_base + off; +} + +static void adp5588_irq_bus_lock(unsigned int irq) +{ + struct adp5588_gpio *dev = get_irq_chip_data(irq); + mutex_lock(&dev->irq_lock); +} + + /* + * genirq core code can issue chip->mask/unmask from atomic context. + * This doesn't work for slow busses where an access needs to sleep. + * bus_sync_unlock() is therefore called outside the atomic context, + * syncs the current irq mask state with the slow external controller + * and unlocks the bus. + */ + +static void adp5588_irq_bus_sync_unlock(unsigned int irq) +{ + struct adp5588_gpio *dev = get_irq_chip_data(irq); + int i; + + for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) + if (dev->int_en[i] ^ dev->irq_mask[i]) { + dev->int_en[i] = dev->irq_mask[i]; + adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i, + dev->int_en[i]); + } + + mutex_unlock(&dev->irq_lock); +} + +static void adp5588_irq_mask(unsigned int irq) +{ + struct adp5588_gpio *dev = get_irq_chip_data(irq); + unsigned gpio = irq - dev->irq_base; + + dev->irq_mask[ADP5588_BANK(gpio)] &= ~ADP5588_BIT(gpio); +} + +static void adp5588_irq_unmask(unsigned int irq) +{ + struct adp5588_gpio *dev = get_irq_chip_data(irq); + unsigned gpio = irq - dev->irq_base; + + dev->irq_mask[ADP5588_BANK(gpio)] |= ADP5588_BIT(gpio); +} + +static int adp5588_irq_set_type(unsigned int irq, unsigned int type) +{ + struct adp5588_gpio *dev = get_irq_chip_data(irq); + uint16_t gpio = irq - dev->irq_base; + unsigned bank, bit; + + if ((type & IRQ_TYPE_EDGE_BOTH)) { + dev_err(&dev->client->dev, "irq %d: unsupported type %d\n", + irq, type); + return -EINVAL; + } + + bank = ADP5588_BANK(gpio); + bit = ADP5588_BIT(gpio); + + if (type & IRQ_TYPE_LEVEL_HIGH) + dev->int_lvl[bank] |= bit; + else if (type & IRQ_TYPE_LEVEL_LOW) + dev->int_lvl[bank] &= ~bit; + else + return -EINVAL; + + adp5588_gpio_direction_input(&dev->gpio_chip, gpio); + adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank, + dev->int_lvl[bank]); + + return 0; +} + +static struct irq_chip adp5588_irq_chip = { + .name = "adp5588", + .mask = adp5588_irq_mask, + .unmask = adp5588_irq_unmask, + .bus_lock = adp5588_irq_bus_lock, + .bus_sync_unlock = adp5588_irq_bus_sync_unlock, + .set_type = adp5588_irq_set_type, +}; + +static int adp5588_gpio_read_intstat(struct i2c_client *client, u8 *buf) +{ + int ret = i2c_smbus_read_i2c_block_data(client, GPIO_INT_STAT1, 3, buf); + + if (ret < 0) + dev_err(&client->dev, "Read INT_STAT Error\n"); + + return ret; +} + +static irqreturn_t adp5588_irq_handler(int irq, void *devid) +{ + struct adp5588_gpio *dev = devid; + unsigned status, bank, bit, pending; + int ret; + status = adp5588_gpio_read(dev->client, INT_STAT); + + if (status & ADP5588_GPI_INT) { + ret = adp5588_gpio_read_intstat(dev->client, dev->irq_stat); + if (ret < 0) + memset(dev->irq_stat, 0, ARRAY_SIZE(dev->irq_stat)); + + for (bank = 0; bank <= ADP5588_BANK(ADP5588_MAXGPIO); + bank++, bit = 0) { + pending = dev->irq_stat[bank] & dev->irq_mask[bank]; + + while (pending) { + if (pending & (1 << bit)) { + handle_nested_irq(dev->irq_base + + (bank << 3) + bit); + pending &= ~(1 << bit); + + } + bit++; + } + } + } + + adp5588_gpio_write(dev->client, INT_STAT, status); /* Status is W1C */ + + return IRQ_HANDLED; +} + +static int adp5588_irq_setup(struct adp5588_gpio *dev) +{ + struct i2c_client *client = dev->client; + struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; + unsigned gpio; + int ret; + + adp5588_gpio_write(client, CFG, ADP5588_AUTO_INC); + adp5588_gpio_write(client, INT_STAT, -1); /* status is W1C */ + adp5588_gpio_read_intstat(client, dev->irq_stat); /* read to clear */ + + dev->irq_base = pdata->irq_base; + mutex_init(&dev->irq_lock); + + for (gpio = 0; gpio < dev->gpio_chip.ngpio; gpio++) { + int irq = gpio + dev->irq_base; + set_irq_chip_data(irq, dev); + set_irq_chip_and_handler(irq, &adp5588_irq_chip, + handle_level_irq); + set_irq_nested_thread(irq, 1); +#ifdef CONFIG_ARM + /* + * ARM needs us to explicitly flag the IRQ as VALID, + * once we do so, it will also set the noprobe. + */ + set_irq_flags(irq, IRQF_VALID); +#else + set_irq_noprobe(irq); +#endif + } + + ret = request_threaded_irq(client->irq, + NULL, + adp5588_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&client->dev), dev); + if (ret) { + dev_err(&client->dev, "failed to request irq %d\n", + client->irq); + goto out; + } + + dev->gpio_chip.to_irq = adp5588_gpio_to_irq; + adp5588_gpio_write(client, CFG, + ADP5588_AUTO_INC | ADP5588_INT_CFG | ADP5588_GPI_INT); + + return 0; + +out: + dev->irq_base = 0; + return ret; +} + +static void adp5588_irq_teardown(struct adp5588_gpio *dev) +{ + if (dev->irq_base) + free_irq(dev->client->irq, dev); +} + +#else +static int adp5588_irq_setup(struct adp5588_gpio *dev) +{ + struct i2c_client *client = dev->client; + dev_warn(&client->dev, "interrupt support not compiled in\n"); + + return 0; +} + +static void adp5588_irq_teardown(struct adp5588_gpio *dev) +{ +} +#endif /* CONFIG_GPIO_ADP5588_IRQ */ + static int __devinit adp5588_gpio_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -160,37 +380,46 @@ static int __devinit adp5588_gpio_probe(struct i2c_client *client, gc->can_sleep = 1; gc->base = pdata->gpio_start; - gc->ngpio = MAXGPIO; + gc->ngpio = ADP5588_MAXGPIO; gc->label = client->name; gc->owner = THIS_MODULE; mutex_init(&dev->lock); - ret = adp5588_gpio_read(dev->client, DEV_ID); if (ret < 0) goto err; revid = ret & ADP5588_DEVICE_ID_MASK; - for (i = 0, ret = 0; i <= ADP_BANK(MAXGPIO); i++) { + for (i = 0, ret = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) { dev->dat_out[i] = adp5588_gpio_read(client, GPIO_DAT_OUT1 + i); dev->dir[i] = adp5588_gpio_read(client, GPIO_DIR1 + i); ret |= adp5588_gpio_write(client, KP_GPIO1 + i, 0); ret |= adp5588_gpio_write(client, GPIO_PULL1 + i, (pdata->pullup_dis_mask >> (8 * i)) & 0xFF); - + ret |= adp5588_gpio_write(client, GPIO_INT_EN1 + i, 0); if (ret) goto err; } + if (pdata->irq_base) { + if (WA_DELAYED_READOUT_REVID(revid)) { + dev_warn(&client->dev, "GPIO int not supported\n"); + } else { + ret = adp5588_irq_setup(dev); + if (ret) + goto err; + } + } + ret = gpiochip_add(&dev->gpio_chip); if (ret) - goto err; + goto err_irq; - dev_info(&client->dev, "gpios %d..%d on a %s Rev. %d\n", + dev_info(&client->dev, "gpios %d..%d (IRQ Base %d) on a %s Rev. %d\n", gc->base, gc->base + gc->ngpio - 1, - client->name, revid); + pdata->irq_base, client->name, revid); if (pdata->setup) { ret = pdata->setup(client, gc->base, gc->ngpio, pdata->context); @@ -199,8 +428,11 @@ static int __devinit adp5588_gpio_probe(struct i2c_client *client, } i2c_set_clientdata(client, dev); + return 0; +err_irq: + adp5588_irq_teardown(dev); err: kfree(dev); return ret; @@ -222,6 +454,9 @@ static int __devexit adp5588_gpio_remove(struct i2c_client *client) } } + if (dev->irq_base) + free_irq(dev->client->irq, dev); + ret = gpiochip_remove(&dev->gpio_chip); if (ret) { dev_err(&client->dev, "gpiochip_remove failed %d\n", ret); diff --git a/drivers/gpio/basic_mmio_gpio.c b/drivers/gpio/basic_mmio_gpio.c new file mode 100644 index 0000000..3addea6 --- /dev/null +++ b/drivers/gpio/basic_mmio_gpio.c @@ -0,0 +1,297 @@ +/* + * Driver for basic memory-mapped GPIO controllers. + * + * Copyright 2008 MontaVista Software, Inc. + * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`....... + * ...`` ```````.. + * ..The simplest form of a GPIO controller that the driver supports is`` + * `.just a single "data" register, where GPIO state can be read and/or ` + * `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.``````` + * ````````` + ___ +_/~~|___/~| . ```~~~~~~ ___/___\___ ,~.`.`.`.`````.~~...,,,,... +__________|~$@~~~ %~ /o*o*o*o*o*o\ .. Implementing such a GPIO . +o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` + `....trivial..'~`.```.``` + * ``````` + * .```````~~~~`..`.``.``. + * . The driver supports `... ,..```.`~~~```````````````....````.``,, + * . big-endian notation, just`. .. A bit more sophisticated controllers , + * . register the device with -be`. .with a pair of set/clear-bit registers , + * `.. suffix. ```~~`````....`.` . affecting the data register and the .` + * ``.`.``...``` ```.. output pins are also supported.` + * ^^ `````.`````````.,``~``~``~~`````` + * . ^^ + * ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`.. + * .. The expectation is that in at least some cases . ,-~~~-, + * .this will be used with roll-your-own ASIC/FPGA .` \ / + * .logic in Verilog or VHDL. ~~~`````````..`````~~` \ / + * ..````````......``````````` \o_ + * | + * ^^ / \ + * + * ...`````~~`.....``.`..........``````.`.``.```........``. + * ` 8, 16, 32 and 64 bits registers are supported, and``. + * . the number of GPIOs is determined by the width of ~ + * .. the registers. ,............```.`.`..`.`.~~~.`.`.`~ + * `.......````.``` + */ + +#include <linux/init.h> +#include <linux/bug.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/compiler.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/log2.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/mod_devicetable.h> +#include <linux/basic_mmio_gpio.h> + +struct bgpio_chip { + struct gpio_chip gc; + void __iomem *reg_dat; + void __iomem *reg_set; + void __iomem *reg_clr; + + /* Number of bits (GPIOs): <register width> * 8. */ + int bits; + + /* + * Some GPIO controllers work with the big-endian bits notation, + * e.g. in a 8-bits register, GPIO7 is the least significant bit. + */ + int big_endian_bits; + + /* + * Used to lock bgpio_chip->data. Also, this is needed to keep + * shadowed and real data registers writes together. + */ + spinlock_t lock; + + /* Shadowed data register to clear/set bits safely. */ + unsigned long data; +}; + +static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc) +{ + return container_of(gc, struct bgpio_chip, gc); +} + +static unsigned long bgpio_in(struct bgpio_chip *bgc) +{ + switch (bgc->bits) { + case 8: + return __raw_readb(bgc->reg_dat); + case 16: + return __raw_readw(bgc->reg_dat); + case 32: + return __raw_readl(bgc->reg_dat); +#if BITS_PER_LONG >= 64 + case 64: + return __raw_readq(bgc->reg_dat); +#endif + } + return -EINVAL; +} + +static void bgpio_out(struct bgpio_chip *bgc, void __iomem *reg, + unsigned long data) +{ + switch (bgc->bits) { + case 8: + __raw_writeb(data, reg); + return; + case 16: + __raw_writew(data, reg); + return; + case 32: + __raw_writel(data, reg); + return; +#if BITS_PER_LONG >= 64 + case 64: + __raw_writeq(data, reg); + return; +#endif + } +} + +static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin) +{ + if (bgc->big_endian_bits) + return 1 << (bgc->bits - 1 - pin); + else + return 1 << pin; +} + +static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return bgpio_in(bgc) & bgpio_pin2mask(bgc, gpio); +} + +static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + unsigned long mask = bgpio_pin2mask(bgc, gpio); + unsigned long flags; + + if (bgc->reg_set) { + if (val) + bgpio_out(bgc, bgc->reg_set, mask); + else + bgpio_out(bgc, bgc->reg_clr, mask); + return; + } + + spin_lock_irqsave(&bgc->lock, flags); + + if (val) + bgc->data |= mask; + else + bgc->data &= ~mask; + + bgpio_out(bgc, bgc->reg_dat, bgc->data); + + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) +{ + return 0; +} + +static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + bgpio_set(gc, gpio, val); + return 0; +} + +static int __devinit bgpio_probe(struct platform_device *pdev) +{ + const struct platform_device_id *platid = platform_get_device_id(pdev); + struct device *dev = &pdev->dev; + struct bgpio_pdata *pdata = dev_get_platdata(dev); + struct bgpio_chip *bgc; + struct resource *res_dat; + struct resource *res_set; + struct resource *res_clr; + resource_size_t dat_sz; + int bits; + int ret; + + res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); + if (!res_dat) + return -EINVAL; + + dat_sz = resource_size(res_dat); + if (!is_power_of_2(dat_sz)) + return -EINVAL; + + bits = dat_sz * 8; + if (bits > BITS_PER_LONG) + return -EINVAL; + + bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL); + if (!bgc) + return -ENOMEM; + + bgc->reg_dat = devm_ioremap(dev, res_dat->start, dat_sz); + if (!bgc->reg_dat) + return -ENOMEM; + + res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set"); + res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr"); + if (res_set && res_clr) { + if (resource_size(res_set) != resource_size(res_clr) || + resource_size(res_set) != dat_sz) + return -EINVAL; + + bgc->reg_set = devm_ioremap(dev, res_set->start, dat_sz); + bgc->reg_clr = devm_ioremap(dev, res_clr->start, dat_sz); + if (!bgc->reg_set || !bgc->reg_clr) + return -ENOMEM; + } else if (res_set || res_clr) { + return -EINVAL; + } + + spin_lock_init(&bgc->lock); + + bgc->bits = bits; + bgc->big_endian_bits = !strcmp(platid->name, "basic-mmio-gpio-be"); + bgc->data = bgpio_in(bgc); + + bgc->gc.ngpio = bits; + bgc->gc.direction_input = bgpio_dir_in; + bgc->gc.direction_output = bgpio_dir_out; + bgc->gc.get = bgpio_get; + bgc->gc.set = bgpio_set; + bgc->gc.dev = dev; + bgc->gc.label = dev_name(dev); + + if (pdata) + bgc->gc.base = pdata->base; + else + bgc->gc.base = -1; + + dev_set_drvdata(dev, bgc); + + ret = gpiochip_add(&bgc->gc); + if (ret) + dev_err(dev, "gpiochip_add() failed: %d\n", ret); + + return ret; +} + +static int __devexit bgpio_remove(struct platform_device *pdev) +{ + struct bgpio_chip *bgc = dev_get_drvdata(&pdev->dev); + + return gpiochip_remove(&bgc->gc); +} + +static const struct platform_device_id bgpio_id_table[] = { + { "basic-mmio-gpio", }, + { "basic-mmio-gpio-be", }, + {}, +}; +MODULE_DEVICE_TABLE(platform, bgpio_id_table); + +static struct platform_driver bgpio_driver = { + .driver = { + .name = "basic-mmio-gpio", + }, + .id_table = bgpio_id_table, + .probe = bgpio_probe, + .remove = __devexit_p(bgpio_remove), +}; + +static int __init bgpio_init(void) +{ + return platform_driver_register(&bgpio_driver); +} +module_init(bgpio_init); + +static void __exit bgpio_exit(void) +{ + platform_driver_unregister(&bgpio_driver); +} +module_exit(bgpio_exit); + +MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers"); +MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 8383a8d..64db9dc 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -18,10 +18,12 @@ /* Supports: * Moorestown platform Langwell chip. * Medfield platform Penwell chip. + * Whitney point. */ #include <linux/module.h> #include <linux/pci.h> +#include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/stddef.h> @@ -158,15 +160,15 @@ static int lnw_irq_type(unsigned irq, unsigned type) spin_unlock_irqrestore(&lnw->lock, flags); return 0; -}; +} static void lnw_irq_unmask(unsigned irq) { -}; +} static void lnw_irq_mask(unsigned irq) { -}; +} static struct irq_chip lnw_irqchip = { .name = "LNW-GPIO", @@ -300,9 +302,88 @@ static struct pci_driver lnw_gpio_driver = { .probe = lnw_gpio_probe, }; + +static int __devinit wp_gpio_probe(struct platform_device *pdev) +{ + struct lnw_gpio *lnw; + struct gpio_chip *gc; + struct resource *rc; + int retval = 0; + + rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!rc) + return -EINVAL; + + lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL); + if (!lnw) { + dev_err(&pdev->dev, + "can't allocate whitneypoint_gpio chip data\n"); + return -ENOMEM; + } + lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc)); + if (lnw->reg_base == NULL) { + retval = -EINVAL; + goto err_kmalloc; + } + spin_lock_init(&lnw->lock); + gc = &lnw->chip; + gc->label = dev_name(&pdev->dev); + gc->owner = THIS_MODULE; + gc->direction_input = lnw_gpio_direction_input; + gc->direction_output = lnw_gpio_direction_output; + gc->get = lnw_gpio_get; + gc->set = lnw_gpio_set; + gc->to_irq = NULL; + gc->base = 0; + gc->ngpio = 64; + gc->can_sleep = 0; + retval = gpiochip_add(gc); + if (retval) { + dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n", + retval); + goto err_ioremap; + } + platform_set_drvdata(pdev, lnw); + return 0; +err_ioremap: + iounmap(lnw->reg_base); +err_kmalloc: + kfree(lnw); + return retval; +} + +static int __devexit wp_gpio_remove(struct platform_device *pdev) +{ + struct lnw_gpio *lnw = platform_get_drvdata(pdev); + int err; + err = gpiochip_remove(&lnw->chip); + if (err) + dev_err(&pdev->dev, "failed to remove gpio_chip.\n"); + iounmap(lnw->reg_base); + kfree(lnw); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver wp_gpio_driver = { + .probe = wp_gpio_probe, + .remove = __devexit_p(wp_gpio_remove), + .driver = { + .name = "wp_gpio", + .owner = THIS_MODULE, + }, +}; + static int __init lnw_gpio_init(void) { - return pci_register_driver(&lnw_gpio_driver); + int ret; + ret = pci_register_driver(&lnw_gpio_driver); + if (ret < 0) + return ret; + ret = platform_driver_register(&wp_gpio_driver); + if (ret < 0) + pci_unregister_driver(&lnw_gpio_driver); + return ret; } device_initcall(lnw_gpio_init); diff --git a/drivers/gpio/pch_gpio.c b/drivers/gpio/pch_gpio.c new file mode 100644 index 0000000..0eba0a7 --- /dev/null +++ b/drivers/gpio/pch_gpio.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/gpio.h> + +#define PCH_GPIO_ALL_PINS 0xfff /* Mask for GPIO pins 0 to 11 */ +#define GPIO_NUM_PINS 12 /* Specifies number of GPIO PINS GPIO0-GPIO11 */ + +struct pch_regs { + u32 ien; + u32 istatus; + u32 idisp; + u32 iclr; + u32 imask; + u32 imaskclr; + u32 po; + u32 pi; + u32 pm; + u32 im0; + u32 im1; + u32 reserved[4]; + u32 reset; +}; + +/** + * struct pch_gpio_reg_data - The register store data. + * @po_reg: To store contents of PO register. + * @pm_reg: To store contents of PM register. + */ +struct pch_gpio_reg_data { + u32 po_reg; + u32 pm_reg; +}; + +/** + * struct pch_gpio - GPIO private data structure. + * @base: PCI base address of Memory mapped I/O register. + * @reg: Memory mapped PCH GPIO register list. + * @dev: Pointer to device structure. + * @gpio: Data for GPIO infrastructure. + * @pch_gpio_reg: Memory mapped Register data is saved here + * when suspend. + */ +struct pch_gpio { + void __iomem *base; + struct pch_regs __iomem *reg; + struct device *dev; + struct gpio_chip gpio; + struct pch_gpio_reg_data pch_gpio_reg; + struct mutex lock; +}; + +static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) +{ + u32 reg_val; + struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio); + + mutex_lock(&chip->lock); + reg_val = ioread32(&chip->reg->po); + if (val) + reg_val |= (1 << nr); + else + reg_val &= ~(1 << nr); + + iowrite32(reg_val, &chip->reg->po); + mutex_unlock(&chip->lock); +} + +static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr) +{ + struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio); + + return ioread32(&chip->reg->pi) & (1 << nr); +} + +static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, + int val) +{ + struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio); + u32 pm; + u32 reg_val; + + mutex_lock(&chip->lock); + pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS; + pm |= (1 << nr); + iowrite32(pm, &chip->reg->pm); + + reg_val = ioread32(&chip->reg->po); + if (val) + reg_val |= (1 << nr); + else + reg_val &= ~(1 << nr); + + mutex_unlock(&chip->lock); + + return 0; +} + +static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) +{ + struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio); + u32 pm; + + mutex_lock(&chip->lock); + pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS; /*bits 0-11*/ + pm &= ~(1 << nr); + iowrite32(pm, &chip->reg->pm); + mutex_unlock(&chip->lock); + + return 0; +} + +/* + * Save register configuration and disable interrupts. + */ +static void pch_gpio_save_reg_conf(struct pch_gpio *chip) +{ + chip->pch_gpio_reg.po_reg = ioread32(&chip->reg->po); + chip->pch_gpio_reg.pm_reg = ioread32(&chip->reg->pm); +} + +/* + * This function restores the register configuration of the GPIO device. + */ +static void pch_gpio_restore_reg_conf(struct pch_gpio *chip) +{ + /* to store contents of PO register */ + iowrite32(chip->pch_gpio_reg.po_reg, &chip->reg->po); + /* to store contents of PM register */ + iowrite32(chip->pch_gpio_reg.pm_reg, &chip->reg->pm); +} + +static void pch_gpio_setup(struct pch_gpio *chip) +{ + struct gpio_chip *gpio = &chip->gpio; + + gpio->label = dev_name(chip->dev); + gpio->owner = THIS_MODULE; + gpio->direction_input = pch_gpio_direction_input; + gpio->get = pch_gpio_get; + gpio->direction_output = pch_gpio_direction_output; + gpio->set = pch_gpio_set; + gpio->dbg_show = NULL; + gpio->base = -1; + gpio->ngpio = GPIO_NUM_PINS; + gpio->can_sleep = 0; +} + +static int __devinit pch_gpio_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + s32 ret; + struct pch_gpio *chip; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->dev = &pdev->dev; + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "%s : pci_enable_device FAILED", __func__); + goto err_pci_enable; + } + + ret = pci_request_regions(pdev, KBUILD_MODNAME); + if (ret) { + dev_err(&pdev->dev, "pci_request_regions FAILED-%d", ret); + goto err_request_regions; + } + + chip->base = pci_iomap(pdev, 1, 0); + if (chip->base == 0) { + dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); + ret = -ENOMEM; + goto err_iomap; + } + + chip->reg = chip->base; + pci_set_drvdata(pdev, chip); + mutex_init(&chip->lock); + pch_gpio_setup(chip); + ret = gpiochip_add(&chip->gpio); + if (ret) { + dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n"); + goto err_gpiochip_add; + } + + return 0; + +err_gpiochip_add: + pci_iounmap(pdev, chip->base); + +err_iomap: + pci_release_regions(pdev); + +err_request_regions: + pci_disable_device(pdev); + +err_pci_enable: + kfree(chip); + dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret); + return ret; +} + +static void __devexit pch_gpio_remove(struct pci_dev *pdev) +{ + int err; + struct pch_gpio *chip = pci_get_drvdata(pdev); + + err = gpiochip_remove(&chip->gpio); + if (err) + dev_err(&pdev->dev, "Failed gpiochip_remove\n"); + + pci_iounmap(pdev, chip->base); + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(chip); +} + +#ifdef CONFIG_PM +static int pch_gpio_suspend(struct pci_dev *pdev, pm_message_t state) +{ + s32 ret; + struct pch_gpio *chip = pci_get_drvdata(pdev); + + pch_gpio_save_reg_conf(chip); + pch_gpio_restore_reg_conf(chip); + + ret = pci_save_state(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret); + return ret; + } + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_wake(pdev, PCI_D0, 1); + if (ret) + dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret); + + return 0; +} + +static int pch_gpio_resume(struct pci_dev *pdev) +{ + s32 ret; + struct pch_gpio *chip = pci_get_drvdata(pdev); + + ret = pci_enable_wake(pdev, PCI_D0, 0); + + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret); + return ret; + } + pci_restore_state(pdev); + + iowrite32(0x01, &chip->reg->reset); + iowrite32(0x00, &chip->reg->reset); + pch_gpio_restore_reg_conf(chip); + + return 0; +} +#else +#define pch_gpio_suspend NULL +#define pch_gpio_resume NULL +#endif + +static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) }, + { 0, } +}; + +static struct pci_driver pch_gpio_driver = { + .name = "pch_gpio", + .id_table = pch_gpio_pcidev_id, + .probe = pch_gpio_probe, + .remove = __devexit_p(pch_gpio_remove), + .suspend = pch_gpio_suspend, + .resume = pch_gpio_resume +}; + +static int __init pch_gpio_pci_init(void) +{ + return pci_register_driver(&pch_gpio_driver); +} +module_init(pch_gpio_pci_init); + +static void __exit pch_gpio_pci_exit(void) +{ + pci_unregister_driver(&pch_gpio_driver); +} +module_exit(pch_gpio_pci_exit); + +MODULE_DESCRIPTION("PCH GPIO PCI Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index ddd0531..4529366 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c @@ -47,6 +47,7 @@ struct timbgpio { spinlock_t lock; /* mutual exclusion */ struct gpio_chip gpio; int irq_base; + unsigned long last_ier; }; static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, @@ -112,16 +113,24 @@ static void timbgpio_irq_disable(unsigned irq) { struct timbgpio *tgpio = get_irq_chip_data(irq); int offset = irq - tgpio->irq_base; + unsigned long flags; - timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 0); + spin_lock_irqsave(&tgpio->lock, flags); + tgpio->last_ier &= ~(1 << offset); + iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); + spin_unlock_irqrestore(&tgpio->lock, flags); } static void timbgpio_irq_enable(unsigned irq) { struct timbgpio *tgpio = get_irq_chip_data(irq); int offset = irq - tgpio->irq_base; + unsigned long flags; - timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 1); + spin_lock_irqsave(&tgpio->lock, flags); + tgpio->last_ier |= 1 << offset; + iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); + spin_unlock_irqrestore(&tgpio->lock, flags); } static int timbgpio_irq_type(unsigned irq, unsigned trigger) @@ -194,8 +203,16 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) ipr = ioread32(tgpio->membase + TGPIO_IPR); iowrite32(ipr, tgpio->membase + TGPIO_ICR); + /* + * Some versions of the hardware trash the IER register if more than + * one interrupt is received simultaneously. + */ + iowrite32(0, tgpio->membase + TGPIO_IER); + for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio) generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset)); + + iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); } static struct irq_chip timbgpio_irqchip = { diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c index 0acf639..2025818 100644 --- a/drivers/media/IR/lirc_dev.c +++ b/drivers/media/IR/lirc_dev.c @@ -27,7 +27,6 @@ #include <linux/fs.h> #include <linux/poll.h> #include <linux/completion.h> -#include <linux/errno.h> #include <linux/mutex.h> #include <linux/wait.h> #include <linux/unistd.h> diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index f540ff9..e61db9d 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -29,7 +29,6 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/gpio.h> -#include <linux/interrupt.h> #include <asm/intel_scu_ipc.h> #include <linux/device.h> #include <linux/intel_pmic_gpio.h> diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c index 3222fa3..0f4a53b 100644 --- a/drivers/rapidio/rio-driver.c +++ b/drivers/rapidio/rio-driver.c @@ -192,7 +192,7 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv) out:return 0; } -static struct device rio_bus = { +struct device rio_bus = { .init_name = "rapidio", }; diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 8070e07..1eb82c4 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -48,7 +48,7 @@ DEFINE_SPINLOCK(rio_global_list_lock); static int next_destid = 0; static int next_switchid = 0; static int next_net = 0; -static int next_comptag; +static int next_comptag = 1; static struct timer_list rio_enum_timer = TIMER_INITIALIZER(rio_enum_timeout, 0, 0); @@ -121,27 +121,6 @@ static int rio_clear_locks(struct rio_mport *port) u32 result; int ret = 0; - /* Assign component tag to all devices */ - next_comptag = 1; - rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++); - - list_for_each_entry(rdev, &rio_devices, global_list) { - /* Mark device as discovered */ - rio_read_config_32(rdev, - rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, - &result); - rio_write_config_32(rdev, - rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, - result | RIO_PORT_GEN_DISCOVERED); - - rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag); - rdev->comp_tag = next_comptag++; - if (next_comptag >= 0x10000) { - pr_err("RIO: Component Tag Counter Overflow\n"); - break; - } - } - /* Release host device id locks */ rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, port->host_deviceid); @@ -162,6 +141,15 @@ static int rio_clear_locks(struct rio_mport *port) rdev->vid, rdev->did); ret = -EINVAL; } + + /* Mark device as discovered and enable master */ + rio_read_config_32(rdev, + rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, + &result); + result |= RIO_PORT_GEN_DISCOVERED | RIO_PORT_GEN_MASTER; + rio_write_config_32(rdev, + rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, + result); } return ret; @@ -420,11 +408,27 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, hopcount, RIO_EFB_ERR_MGMNT); } + if (rdev->pef & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { + rio_mport_read_config_32(port, destid, hopcount, + RIO_SWP_INFO_CAR, &rdev->swpinfo); + } + rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, &rdev->src_ops); rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, &rdev->dst_ops); + if (do_enum) { + /* Assign component tag to device */ + if (next_comptag >= 0x10000) { + pr_err("RIO: Component Tag Counter Overflow\n"); + goto cleanup; + } + rio_mport_write_config_32(port, destid, hopcount, + RIO_COMPONENT_TAG_CSR, next_comptag); + rdev->comp_tag = next_comptag++; + } + if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { if (do_enum) { rio_set_device_id(port, destid, hopcount, next_destid); @@ -439,9 +443,10 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, /* If a PE has both switch and other functions, show it as a switch */ if (rio_is_switch(rdev)) { - rio_mport_read_config_32(port, destid, hopcount, - RIO_SWP_INFO_CAR, &rdev->swpinfo); - rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL); + rswitch = kzalloc(sizeof(*rswitch) + + RIO_GET_TOTAL_PORTS(rdev->swpinfo) * + sizeof(rswitch->nextdev[0]), + GFP_KERNEL); if (!rswitch) goto cleanup; rswitch->switchid = next_switchid; @@ -458,6 +463,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, rdid++) rswitch->route_table[rdid] = RIO_INVALID_ROUTE; rdev->rswitch = rswitch; + rswitch->rdev = rdev; dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, rdev->rswitch->switchid); rio_switch_init(rdev, do_enum); @@ -478,6 +484,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, } rdev->dev.bus = &rio_bus_type; + rdev->dev.parent = &rio_bus; device_initialize(&rdev->dev); rdev->dev.release = rio_release_dev; @@ -718,86 +725,53 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) } /** - * rio_get_swpinfo_inport- Gets the ingress port number - * @mport: Master port to send transaction - * @destid: Destination ID associated with the switch - * @hopcount: Number of hops to the device - * - * Returns port number being used to access the switch device. - */ -static u8 -rio_get_swpinfo_inport(struct rio_mport *mport, u16 destid, u8 hopcount) -{ - u32 result; - - rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR, - &result); - - return (u8) (result & 0xff); -} - -/** - * rio_get_swpinfo_tports- Gets total number of ports on the switch - * @mport: Master port to send transaction - * @destid: Destination ID associated with the switch - * @hopcount: Number of hops to the device - * - * Returns total numbers of ports implemented by the switch device. - */ -static u8 rio_get_swpinfo_tports(struct rio_mport *mport, u16 destid, - u8 hopcount) -{ - u32 result; - - rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR, - &result); - - return RIO_GET_TOTAL_PORTS(result); -} - -/** - * rio_net_add_mport- Add a master port to a RIO network - * @net: RIO network - * @port: Master port to add - * - * Adds a master port to the network list of associated master - * ports.. - */ -static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port) -{ - spin_lock(&rio_global_list_lock); - list_add_tail(&port->nnode, &net->mports); - spin_unlock(&rio_global_list_lock); -} - -/** * rio_enum_peer- Recursively enumerate a RIO network through a master port * @net: RIO network being enumerated * @port: Master port to send transactions * @hopcount: Number of hops into the network + * @prev: Previous RIO device connected to the enumerated one + * @prev_port: Port on previous RIO device * * Recursively enumerates a RIO network. Transactions are sent via the * master port passed in @port. */ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, - u8 hopcount) + u8 hopcount, struct rio_dev *prev, int prev_port) { int port_num; - int num_ports; int cur_destid; int sw_destid; int sw_inport; struct rio_dev *rdev; u16 destid; + u32 regval; int tmp; + if (rio_mport_chk_dev_access(port, + RIO_ANY_DESTID(port->sys_size), hopcount)) { + pr_debug("RIO: device access check failed\n"); + return -1; + } + if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) { pr_debug("RIO: PE already discovered by this host\n"); /* * Already discovered by this host. Add it as another - * master port for the current network. + * link to the existing device. */ - rio_net_add_mport(net, port); + rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), + hopcount, RIO_COMPONENT_TAG_CSR, ®val); + + if (regval) { + rdev = rio_get_comptag((regval & 0xffff), NULL); + + if (rdev && prev && rio_is_switch(prev)) { + pr_debug("RIO: redundant path to %s\n", + rio_name(rdev)); + prev->rswitch->nextdev[prev_port] = rdev; + } + } + return 0; } @@ -828,13 +802,15 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, if (rdev) { /* Add device to the global and bus/net specific list. */ list_add_tail(&rdev->net_list, &net->devices); + rdev->prev = prev; + if (prev && rio_is_switch(prev)) + prev->rswitch->nextdev[prev_port] = rdev; } else return -1; if (rio_is_switch(rdev)) { next_switchid++; - sw_inport = rio_get_swpinfo_inport(port, - RIO_ANY_DESTID(port->sys_size), hopcount); + sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, port->host_deviceid, sw_inport, 0); rdev->rswitch->route_table[port->host_deviceid] = sw_inport; @@ -847,14 +823,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, rdev->rswitch->route_table[destid] = sw_inport; } - num_ports = - rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size), - hopcount); pr_debug( "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", - rio_name(rdev), rdev->vid, rdev->did, num_ports); + rio_name(rdev), rdev->vid, rdev->did, + RIO_GET_TOTAL_PORTS(rdev->swpinfo)); sw_destid = next_destid; - for (port_num = 0; port_num < num_ports; port_num++) { + for (port_num = 0; + port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo); + port_num++) { /*Enable Input Output Port (transmitter reviever)*/ rio_enable_rx_tx_port(port, 0, RIO_ANY_DESTID(port->sys_size), @@ -879,7 +855,8 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, RIO_ANY_DESTID(port->sys_size), port_num, 0); - if (rio_enum_peer(net, port, hopcount + 1) < 0) + if (rio_enum_peer(net, port, hopcount + 1, + rdev, port_num) < 0) return -1; /* Update routing tables */ @@ -945,10 +922,11 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, */ static int rio_enum_complete(struct rio_mport *port) { - u32 tag_csr; + u32 regval; - rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr); - return (tag_csr & 0xffff) ? 1 : 0; + rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR, + ®val); + return (regval & RIO_PORT_GEN_MASTER) ? 1 : 0; } /** @@ -966,7 +944,6 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, u8 hopcount) { u8 port_num, route_port; - int num_ports; struct rio_dev *rdev; u16 ndestid; @@ -983,13 +960,14 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, /* Associated destid is how we accessed this switch */ rdev->rswitch->destid = destid; - num_ports = rio_get_swpinfo_tports(port, destid, hopcount); pr_debug( "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", - rio_name(rdev), rdev->vid, rdev->did, num_ports); - for (port_num = 0; port_num < num_ports; port_num++) { - if (rio_get_swpinfo_inport(port, destid, hopcount) == - port_num) + rio_name(rdev), rdev->vid, rdev->did, + RIO_GET_TOTAL_PORTS(rdev->swpinfo)); + for (port_num = 0; + port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo); + port_num++) { + if (RIO_GET_PORT_NUM(rdev->swpinfo) == port_num) continue; if (rio_sport_is_active @@ -1011,6 +989,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, break; } + if (ndestid == RIO_ANY_DESTID(port->sys_size)) + continue; rio_unlock_device(port, destid, hopcount); if (rio_disc_peer (net, port, ndestid, hopcount + 1) < 0) @@ -1108,8 +1088,7 @@ static void rio_update_route_tables(struct rio_mport *port) if (rswitch->destid == destid) continue; - sport = rio_get_swpinfo_inport(port, - rswitch->destid, rswitch->hopcount); + sport = RIO_GET_PORT_NUM(rswitch->rdev->swpinfo); if (rswitch->add_entry) { rio_route_add_entry(port, rswitch, @@ -1184,7 +1163,11 @@ int __devinit rio_enum_mport(struct rio_mport *mport) /* Enable Input Output Port (transmitter reviever) */ rio_enable_rx_tx_port(mport, 1, 0, 0, 0); - if (rio_enum_peer(net, mport, 0) < 0) { + /* Set component tag for host */ + rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR, + next_comptag++); + + if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { /* A higher priority host won enumeration, bail. */ printk(KERN_INFO "RIO: master port %d device has lost enumeration to a remote host\n", diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 00b4756..137ed93 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -40,9 +40,6 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch char *str = buf; int i; - if (!rdev->rswitch) - goto out; - for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); i++) { if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE) @@ -52,7 +49,6 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch rdev->rswitch->route_table[i]); } - out: return (str - buf); } @@ -63,10 +59,11 @@ struct device_attribute rio_dev_attrs[] = { __ATTR_RO(asm_did), __ATTR_RO(asm_vid), __ATTR_RO(asm_rev), - __ATTR_RO(routes), __ATTR_NULL, }; +static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL); + static ssize_t rio_read_config(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, @@ -218,7 +215,17 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev) { int err = 0; - err = sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr); + err = device_create_bin_file(&rdev->dev, &rio_config_attr); + + if (!err && rdev->rswitch) { + err = device_create_file(&rdev->dev, &dev_attr_routes); + if (!err && rdev->rswitch->sw_sysfs) + err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE); + } + + if (err) + pr_warning("RIO: Failed to create attribute file(s) for %s\n", + rio_name(rdev)); return err; } @@ -231,5 +238,10 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev) */ void rio_remove_sysfs_dev_files(struct rio_dev *rdev) { - sysfs_remove_bin_file(&rdev->dev.kobj, &rio_config_attr); + device_remove_bin_file(&rdev->dev, &rio_config_attr); + if (rdev->rswitch) { + device_remove_file(&rdev->dev, &dev_attr_routes); + if (rdev->rswitch->sw_sysfs) + rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE); + } } diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 74e9d22..68cf0c9 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -443,7 +443,7 @@ rio_mport_get_physefb(struct rio_mport *port, int local, * @from is not %NULL, searches continue from next device on the global * list. */ -static struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) +struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) { struct list_head *n; struct rio_dev *rdev; @@ -495,6 +495,232 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) } /** + * rio_chk_dev_route - Validate route to the specified device. + * @rdev: RIO device failed to respond + * @nrdev: Last active device on the route to rdev + * @npnum: nrdev's port number on the route to rdev + * + * Follows a route to the specified RIO device to determine the last available + * device (and corresponding RIO port) on the route. + */ +static int +rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) +{ + u32 result; + int p_port, dstid, rc = -EIO; + struct rio_dev *prev = NULL; + + /* Find switch with failed RIO link */ + while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) { + if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) { + prev = rdev->prev; + break; + } + rdev = rdev->prev; + } + + if (prev == NULL) + goto err_out; + + dstid = (rdev->pef & RIO_PEF_SWITCH) ? + rdev->rswitch->destid : rdev->destid; + p_port = prev->rswitch->route_table[dstid]; + + if (p_port != RIO_INVALID_ROUTE) { + pr_debug("RIO: link failed on [%s]-P%d\n", + rio_name(prev), p_port); + *nrdev = prev; + *npnum = p_port; + rc = 0; + } else + pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); +err_out: + return rc; +} + +/** + * rio_mport_chk_dev_access - Validate access to the specified device. + * @mport: Master port to send transactions + * @destid: Device destination ID in network + * @hopcount: Number of hops into the network + */ +int +rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) +{ + int i = 0; + u32 tmp; + + while (rio_mport_read_config_32(mport, destid, hopcount, + RIO_DEV_ID_CAR, &tmp)) { + i++; + if (i == RIO_MAX_CHK_RETRY) + return -EIO; + mdelay(1); + } + + return 0; +} + +/** + * rio_chk_dev_access - Validate access to the specified device. + * @rdev: Pointer to RIO device control structure + */ +static int rio_chk_dev_access(struct rio_dev *rdev) +{ + u8 hopcount = 0xff; + u16 destid = rdev->destid; + + if (rdev->rswitch) { + destid = rdev->rswitch->destid; + hopcount = rdev->rswitch->hopcount; + } + + return rio_mport_chk_dev_access(rdev->net->hport, destid, hopcount); +} + +/** + * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and + * returns link-response (if requested). + * @rdev: RIO devive to issue Input-status command + * @pnum: Device port number to issue the command + * @lnkresp: Response from a link partner + */ +static int +rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) +{ + struct rio_mport *mport = rdev->net->hport; + u16 destid = rdev->rswitch->destid; + u8 hopcount = rdev->rswitch->hopcount; + u32 regval; + int checkcount; + + if (lnkresp) { + /* Read from link maintenance response register + * to clear valid bit */ + rio_mport_read_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), + ®val); + udelay(50); + } + + /* Issue Input-status command */ + rio_mport_write_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), + RIO_MNT_REQ_CMD_IS); + + /* Exit if the response is not expected */ + if (lnkresp == NULL) + return 0; + + checkcount = 3; + while (checkcount--) { + udelay(50); + rio_mport_read_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), + ®val); + if (regval & RIO_PORT_N_MNT_RSP_RVAL) { + *lnkresp = regval; + return 0; + } + } + + return -EIO; +} + +/** + * rio_clr_err_stopped - Clears port Error-stopped states. + * @rdev: Pointer to RIO device control structure + * @pnum: Switch port number to clear errors + * @err_status: port error status (if 0 reads register from device) + */ +static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) +{ + struct rio_mport *mport = rdev->net->hport; + u16 destid = rdev->rswitch->destid; + u8 hopcount = rdev->rswitch->hopcount; + struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; + u32 regval; + u32 far_ackid, far_linkstat, near_ackid; + + if (err_status == 0) + rio_mport_read_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), + &err_status); + + if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) { + pr_debug("RIO_EM: servicing Output Error-Stopped state\n"); + /* + * Send a Link-Request/Input-Status control symbol + */ + if (rio_get_input_status(rdev, pnum, ®val)) { + pr_debug("RIO_EM: Input-status response timeout\n"); + goto rd_err; + } + + pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", + pnum, regval); + far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; + far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; + rio_mport_read_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), + ®val); + pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); + near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24; + pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \ + " near_ackID=0x%02x\n", + pnum, far_ackid, far_linkstat, near_ackid); + + /* + * If required, synchronize ackIDs of near and + * far sides. + */ + if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) || + (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) { + /* Align near outstanding/outbound ackIDs with + * far inbound. + */ + rio_mport_write_config_32(mport, destid, + hopcount, rdev->phys_efptr + + RIO_PORT_N_ACK_STS_CSR(pnum), + (near_ackid << 24) | + (far_ackid << 8) | far_ackid); + /* Align far outstanding/outbound ackIDs with + * near inbound. + */ + far_ackid++; + if (nextdev) + rio_write_config_32(nextdev, + nextdev->phys_efptr + + RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)), + (far_ackid << 24) | + (near_ackid << 8) | near_ackid); + else + pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n"); + } +rd_err: + rio_mport_read_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), + &err_status); + pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); + } + + if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) { + pr_debug("RIO_EM: servicing Input Error-Stopped state\n"); + rio_get_input_status(nextdev, + RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); + udelay(50); + + rio_mport_read_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), + &err_status); + pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); + } + + return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | + RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0; +} + +/** * rio_inb_pwrite_handler - process inbound port-write message * @pw_msg: pointer to inbound port-write message * @@ -507,13 +733,13 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) struct rio_mport *mport; u8 hopcount; u16 destid; - u32 err_status; + u32 err_status, em_perrdet, em_ltlerrdet; int rc, portnum; rdev = rio_get_comptag(pw_msg->em.comptag, NULL); if (rdev == NULL) { - /* Someting bad here (probably enumeration error) */ - pr_err("RIO: %s No matching device for CTag 0x%08x\n", + /* Device removed or enumeration error */ + pr_debug("RIO: %s No matching device for CTag 0x%08x\n", __func__, pw_msg->em.comptag); return -EIO; } @@ -524,12 +750,11 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) { u32 i; for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { - pr_debug("0x%02x: %08x %08x %08x %08x", + pr_debug("0x%02x: %08x %08x %08x %08x\n", i*4, pw_msg->raw[i], pw_msg->raw[i + 1], pw_msg->raw[i + 2], pw_msg->raw[i + 3]); i += 4; } - pr_debug("\n"); } #endif @@ -545,6 +770,26 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) return 0; } + portnum = pw_msg->em.is_port & 0xFF; + + /* Check if device and route to it are functional: + * Sometimes devices may send PW message(s) just before being + * powered down (or link being lost). + */ + if (rio_chk_dev_access(rdev)) { + pr_debug("RIO: device access failed - get link partner\n"); + /* Scan route to the device and identify failed link. + * This will replace device and port reported in PW message. + * PW message should not be used after this point. + */ + if (rio_chk_dev_route(rdev, &rdev, &portnum)) { + pr_err("RIO: Route trace for %s failed\n", + rio_name(rdev)); + return -EIO; + } + pw_msg = NULL; + } + /* For End-point devices processing stops here */ if (!(rdev->pef & RIO_PEF_SWITCH)) return 0; @@ -562,9 +807,6 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) /* * Process the port-write notification from switch */ - - portnum = pw_msg->em.is_port & 0xFF; - if (rdev->rswitch->em_handle) rdev->rswitch->em_handle(rdev, portnum); @@ -573,29 +815,28 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) &err_status); pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); - if (pw_msg->em.errdetect) { - pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", - portnum, pw_msg->em.errdetect); - /* Clear EM Port N Error Detect CSR */ - rio_mport_write_config_32(mport, destid, hopcount, - rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); - } + if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) { - if (pw_msg->em.ltlerrdet) { - pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", - pw_msg->em.ltlerrdet); - /* Clear EM L/T Layer Error Detect CSR */ - rio_mport_write_config_32(mport, destid, hopcount, - rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); - } + if (!(rdev->rswitch->port_ok & (1 << portnum))) { + rdev->rswitch->port_ok |= (1 << portnum); + rio_set_port_lockout(rdev, portnum, 0); + /* Schedule Insertion Service */ + pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", + rio_name(rdev), portnum); + } - /* Clear Port Errors */ - rio_mport_write_config_32(mport, destid, hopcount, - rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), - err_status & RIO_PORT_N_ERR_STS_CLR_MASK); + /* Clear error-stopped states (if reported). + * Depending on the link partner state, two attempts + * may be needed for successful recovery. + */ + if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | + RIO_PORT_N_ERR_STS_PW_INP_ES)) { + if (rio_clr_err_stopped(rdev, portnum, err_status)) + rio_clr_err_stopped(rdev, portnum, 0); + } + } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */ - if (rdev->rswitch->port_ok & (1 << portnum)) { - if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) { + if (rdev->rswitch->port_ok & (1 << portnum)) { rdev->rswitch->port_ok &= ~(1 << portnum); rio_set_port_lockout(rdev, portnum, 1); @@ -608,21 +849,32 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", rio_name(rdev), portnum); } - } else { - if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) { - rdev->rswitch->port_ok |= (1 << portnum); - rio_set_port_lockout(rdev, portnum, 0); + } - /* Schedule Insertion Service */ - pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", - rio_name(rdev), portnum); - } + rio_mport_read_config_32(mport, destid, hopcount, + rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); + if (em_perrdet) { + pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", + portnum, em_perrdet); + /* Clear EM Port N Error Detect CSR */ + rio_mport_write_config_32(mport, destid, hopcount, + rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); + } + + rio_mport_read_config_32(mport, destid, hopcount, + rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); + if (em_ltlerrdet) { + pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", + em_ltlerrdet); + /* Clear EM L/T Layer Error Detect CSR */ + rio_mport_write_config_32(mport, destid, hopcount, + rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); } - /* Clear Port-Write Pending bit */ + /* Clear remaining error bits and Port-Write Pending bit */ rio_mport_write_config_32(mport, destid, hopcount, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), - RIO_PORT_N_ERR_STS_PW_PEND); + err_status); return 0; } diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index f27b7a9..b1af414 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h @@ -14,6 +14,8 @@ #include <linux/list.h> #include <linux/rio.h> +#define RIO_MAX_CHK_RETRY 3 + /* Functions internal to the RIO core code */ extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid, @@ -22,6 +24,8 @@ extern u32 rio_mport_get_physefb(struct rio_mport *port, int local, u16 destid, u8 hopcount); extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, u8 hopcount, u32 from); +extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, + u8 hopcount); extern int rio_create_sysfs_dev_files(struct rio_dev *rdev); extern int rio_enum_mport(struct rio_mport *mport); extern int rio_disc_mport(struct rio_mport *mport); @@ -34,6 +38,7 @@ extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table); extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock); +extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from); /* Structures internal to the RIO core code */ extern struct device_attribute rio_dev_attrs[]; diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig index 2b4e9b2..f47fee5 100644 --- a/drivers/rapidio/switches/Kconfig +++ b/drivers/rapidio/switches/Kconfig @@ -20,6 +20,13 @@ config RAPIDIO_TSI568 ---help--- Includes support for IDT Tsi568 serial RapidIO switch. +config RAPIDIO_CPS_GEN2 + bool "IDT CPS Gen.2 SRIO switch support" + depends on RAPIDIO + default n + ---help--- + Includes support for ITD CPS Gen.2 serial RapidIO switches. + config RAPIDIO_TSI500 bool "Tsi500 Parallel RapidIO switch support" depends on RAPIDIO diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile index fe4adc3..48d67a6 100644 --- a/drivers/rapidio/switches/Makefile +++ b/drivers/rapidio/switches/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_RAPIDIO_TSI57X) += tsi57x.o obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o obj-$(CONFIG_RAPIDIO_TSI568) += tsi568.o obj-$(CONFIG_RAPIDIO_TSI500) += tsi500.o +obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o ifeq ($(CONFIG_RAPIDIO_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c new file mode 100644 index 0000000..0bb871c --- /dev/null +++ b/drivers/rapidio/switches/idt_gen2.c @@ -0,0 +1,447 @@ +/* + * IDT CPS Gen.2 Serial RapidIO switch family support + * + * Copyright 2010 Integrated Device Technology, Inc. + * Alexandre Bounine <alexandre.bounine@idt.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/rio.h> +#include <linux/rio_drv.h> +#include <linux/rio_ids.h> +#include <linux/delay.h> +#include "../rio.h" + +#define LOCAL_RTE_CONF_DESTID_SEL 0x010070 +#define LOCAL_RTE_CONF_DESTID_SEL_PSEL 0x0000001f + +#define IDT_LT_ERR_REPORT_EN 0x03100c + +#define IDT_PORT_ERR_REPORT_EN(n) (0x031044 + (n)*0x40) +#define IDT_PORT_ERR_REPORT_EN_BC 0x03ff04 + +#define IDT_PORT_ISERR_REPORT_EN(n) (0x03104C + (n)*0x40) +#define IDT_PORT_ISERR_REPORT_EN_BC 0x03ff0c +#define IDT_PORT_INIT_TX_ACQUIRED 0x00000020 + +#define IDT_LANE_ERR_REPORT_EN(n) (0x038010 + (n)*0x100) +#define IDT_LANE_ERR_REPORT_EN_BC 0x03ff10 + +#define IDT_DEV_CTRL_1 0xf2000c +#define IDT_DEV_CTRL_1_GENPW 0x02000000 +#define IDT_DEV_CTRL_1_PRSTBEH 0x00000001 + +#define IDT_CFGBLK_ERR_CAPTURE_EN 0x020008 +#define IDT_CFGBLK_ERR_REPORT 0xf20014 +#define IDT_CFGBLK_ERR_REPORT_GENPW 0x00000002 + +#define IDT_AUX_PORT_ERR_CAP_EN 0x020000 +#define IDT_AUX_ERR_REPORT_EN 0xf20018 +#define IDT_AUX_PORT_ERR_LOG_I2C 0x00000002 +#define IDT_AUX_PORT_ERR_LOG_JTAG 0x00000001 + +#define IDT_ISLTL_ADDRESS_CAP 0x021014 + +#define IDT_RIO_DOMAIN 0xf20020 +#define IDT_RIO_DOMAIN_MASK 0x000000ff + +#define IDT_PW_INFO_CSR 0xf20024 + +#define IDT_SOFT_RESET 0xf20040 +#define IDT_SOFT_RESET_REQ 0x00030097 + +#define IDT_I2C_MCTRL 0xf20050 +#define IDT_I2C_MCTRL_GENPW 0x04000000 + +#define IDT_JTAG_CTRL 0xf2005c +#define IDT_JTAG_CTRL_GENPW 0x00000002 + +#define IDT_LANE_CTRL(n) (0xff8000 + (n)*0x100) +#define IDT_LANE_CTRL_BC 0xffff00 +#define IDT_LANE_CTRL_GENPW 0x00200000 +#define IDT_LANE_DFE_1_BC 0xffff18 +#define IDT_LANE_DFE_2_BC 0xffff1c + +#define IDT_PORT_OPS(n) (0xf40004 + (n)*0x100) +#define IDT_PORT_OPS_GENPW 0x08000000 +#define IDT_PORT_OPS_PL_ELOG 0x00000040 +#define IDT_PORT_OPS_LL_ELOG 0x00000020 +#define IDT_PORT_OPS_LT_ELOG 0x00000010 +#define IDT_PORT_OPS_BC 0xf4ff04 + +#define IDT_PORT_ISERR_DET(n) (0xf40008 + (n)*0x100) + +#define IDT_ERR_CAP 0xfd0000 +#define IDT_ERR_CAP_LOG_OVERWR 0x00000004 + +#define IDT_ERR_RD 0xfd0004 + +#define IDT_DEFAULT_ROUTE 0xde +#define IDT_NO_ROUTE 0xdf + +static int +idtg2_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 route_port) +{ + /* + * Select routing table to update + */ + if (table == RIO_GLOBAL_TABLE) + table = 0; + else + table++; + + rio_mport_write_config_32(mport, destid, hopcount, + LOCAL_RTE_CONF_DESTID_SEL, table); + + /* + * Program destination port for the specified destID + */ + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, + (u32)route_destid); + + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, + (u32)route_port); + udelay(10); + + return 0; +} + +static int +idtg2_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 *route_port) +{ + u32 result; + + /* + * Select routing table to read + */ + if (table == RIO_GLOBAL_TABLE) + table = 0; + else + table++; + + rio_mport_write_config_32(mport, destid, hopcount, + LOCAL_RTE_CONF_DESTID_SEL, table); + + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, + route_destid); + + rio_mport_read_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); + + if (IDT_DEFAULT_ROUTE == (u8)result || IDT_NO_ROUTE == (u8)result) + *route_port = RIO_INVALID_ROUTE; + else + *route_port = (u8)result; + + return 0; +} + +static int +idtg2_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table) +{ + u32 i; + + /* + * Select routing table to read + */ + if (table == RIO_GLOBAL_TABLE) + table = 0; + else + table++; + + rio_mport_write_config_32(mport, destid, hopcount, + LOCAL_RTE_CONF_DESTID_SEL, table); + + for (i = RIO_STD_RTE_CONF_EXTCFGEN; + i <= (RIO_STD_RTE_CONF_EXTCFGEN | 0xff);) { + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, i); + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, + (IDT_DEFAULT_ROUTE << 24) | (IDT_DEFAULT_ROUTE << 16) | + (IDT_DEFAULT_ROUTE << 8) | IDT_DEFAULT_ROUTE); + i += 4; + } + + return 0; +} + + +static int +idtg2_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, + u8 sw_domain) +{ + /* + * Switch domain configuration operates only at global level + */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_RIO_DOMAIN, (u32)sw_domain); + return 0; +} + +static int +idtg2_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, + u8 *sw_domain) +{ + u32 regval; + + /* + * Switch domain configuration operates only at global level + */ + rio_mport_read_config_32(mport, destid, hopcount, + IDT_RIO_DOMAIN, ®val); + + *sw_domain = (u8)(regval & 0xff); + + return 0; +} + +static int +idtg2_em_init(struct rio_dev *rdev) +{ + struct rio_mport *mport = rdev->net->hport; + u16 destid = rdev->rswitch->destid; + u8 hopcount = rdev->rswitch->hopcount; + u32 regval; + int i, tmp; + + /* + * This routine performs device-specific initialization only. + * All standard EM configuration should be performed at upper level. + */ + + pr_debug("RIO: %s [%d:%d]\n", __func__, destid, hopcount); + + /* Set Port-Write info CSR: PRIO=3 and CRF=1 */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_PW_INFO_CSR, 0x0000e000); + + /* + * Configure LT LAYER error reporting. + */ + + /* Enable standard (RIO.p8) error reporting */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_LT_ERR_REPORT_EN, + REM_LTL_ERR_ILLTRAN | REM_LTL_ERR_UNSOLR | + REM_LTL_ERR_UNSUPTR); + + /* Use Port-Writes for LT layer error reporting. + * Enable per-port reset + */ + rio_mport_read_config_32(mport, destid, hopcount, + IDT_DEV_CTRL_1, ®val); + rio_mport_write_config_32(mport, destid, hopcount, + IDT_DEV_CTRL_1, + regval | IDT_DEV_CTRL_1_GENPW | IDT_DEV_CTRL_1_PRSTBEH); + + /* + * Configure PORT error reporting. + */ + + /* Report all RIO.p8 errors supported by device */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037); + + /* Configure reporting of implementation specific errors/events */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_PORT_ISERR_REPORT_EN_BC, IDT_PORT_INIT_TX_ACQUIRED); + + /* Use Port-Writes for port error reporting and enable error logging */ + tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo); + for (i = 0; i < tmp; i++) { + rio_mport_read_config_32(mport, destid, hopcount, + IDT_PORT_OPS(i), ®val); + rio_mport_write_config_32(mport, destid, hopcount, + IDT_PORT_OPS(i), regval | IDT_PORT_OPS_GENPW | + IDT_PORT_OPS_PL_ELOG | + IDT_PORT_OPS_LL_ELOG | + IDT_PORT_OPS_LT_ELOG); + } + /* Overwrite error log if full */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR); + + /* + * Configure LANE error reporting. + */ + + /* Disable line error reporting */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_LANE_ERR_REPORT_EN_BC, 0); + + /* Use Port-Writes for lane error reporting (when enabled) + * (do per-lane update because lanes may have different configuration) + */ + tmp = (rdev->did == RIO_DID_IDTCPS1848) ? 48 : 16; + for (i = 0; i < tmp; i++) { + rio_mport_read_config_32(mport, destid, hopcount, + IDT_LANE_CTRL(i), ®val); + rio_mport_write_config_32(mport, destid, hopcount, + IDT_LANE_CTRL(i), regval | IDT_LANE_CTRL_GENPW); + } + + /* + * Configure AUX error reporting. + */ + + /* Disable JTAG and I2C Error capture */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_AUX_PORT_ERR_CAP_EN, 0); + + /* Disable JTAG and I2C Error reporting/logging */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_AUX_ERR_REPORT_EN, 0); + + /* Disable Port-Write notification from JTAG */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_JTAG_CTRL, 0); + + /* Disable Port-Write notification from I2C */ + rio_mport_read_config_32(mport, destid, hopcount, + IDT_I2C_MCTRL, ®val); + rio_mport_write_config_32(mport, destid, hopcount, + IDT_I2C_MCTRL, + regval & ~IDT_I2C_MCTRL_GENPW); + + /* + * Configure CFG_BLK error reporting. + */ + + /* Disable Configuration Block error capture */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_CFGBLK_ERR_CAPTURE_EN, 0); + + /* Disable Port-Writes for Configuration Block error reporting */ + rio_mport_read_config_32(mport, destid, hopcount, + IDT_CFGBLK_ERR_REPORT, ®val); + rio_mport_write_config_32(mport, destid, hopcount, + IDT_CFGBLK_ERR_REPORT, + regval & ~IDT_CFGBLK_ERR_REPORT_GENPW); + + /* set TVAL = ~50us */ + rio_mport_write_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); + + return 0; +} + +static int +idtg2_em_handler(struct rio_dev *rdev, u8 portnum) +{ + struct rio_mport *mport = rdev->net->hport; + u16 destid = rdev->rswitch->destid; + u8 hopcount = rdev->rswitch->hopcount; + u32 regval, em_perrdet, em_ltlerrdet; + + rio_mport_read_config_32(mport, destid, hopcount, + rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); + if (em_ltlerrdet) { + /* Service Logical/Transport Layer Error(s) */ + if (em_ltlerrdet & REM_LTL_ERR_IMPSPEC) { + /* Implementation specific error reported */ + rio_mport_read_config_32(mport, destid, hopcount, + IDT_ISLTL_ADDRESS_CAP, ®val); + + pr_debug("RIO: %s Implementation Specific LTL errors" \ + " 0x%x @(0x%x)\n", + rio_name(rdev), em_ltlerrdet, regval); + + /* Clear implementation specific address capture CSR */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_ISLTL_ADDRESS_CAP, 0); + + } + } + + rio_mport_read_config_32(mport, destid, hopcount, + rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); + if (em_perrdet) { + /* Service Port-Level Error(s) */ + if (em_perrdet & REM_PED_IMPL_SPEC) { + /* Implementation Specific port error reported */ + + /* Get IS errors reported */ + rio_mport_read_config_32(mport, destid, hopcount, + IDT_PORT_ISERR_DET(portnum), ®val); + + pr_debug("RIO: %s Implementation Specific Port" \ + " errors 0x%x\n", rio_name(rdev), regval); + + /* Clear all implementation specific events */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_PORT_ISERR_DET(portnum), 0); + } + } + + return 0; +} + +static ssize_t +idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct rio_dev *rdev = to_rio_dev(dev); + struct rio_mport *mport = rdev->net->hport; + u16 destid = rdev->rswitch->destid; + u8 hopcount = rdev->rswitch->hopcount; + ssize_t len = 0; + u32 regval; + + while (!rio_mport_read_config_32(mport, destid, hopcount, + IDT_ERR_RD, ®val)) { + if (!regval) /* 0 = end of log */ + break; + len += snprintf(buf + len, PAGE_SIZE - len, + "%08x\n", regval); + if (len >= (PAGE_SIZE - 10)) + break; + } + + return len; +} + +static DEVICE_ATTR(errlog, S_IRUGO, idtg2_show_errlog, NULL); + +static int idtg2_sysfs(struct rio_dev *rdev, int create) +{ + struct device *dev = &rdev->dev; + int err = 0; + + if (create == RIO_SW_SYSFS_CREATE) { + /* Initialize sysfs entries */ + err = device_create_file(dev, &dev_attr_errlog); + if (err) + dev_err(dev, "Unable create sysfs errlog file\n"); + } else + device_remove_file(dev, &dev_attr_errlog); + + return err; +} + +static int idtg2_switch_init(struct rio_dev *rdev, int do_enum) +{ + pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); + rdev->rswitch->add_entry = idtg2_route_add_entry; + rdev->rswitch->get_entry = idtg2_route_get_entry; + rdev->rswitch->clr_table = idtg2_route_clr_table; + rdev->rswitch->set_domain = idtg2_set_domain; + rdev->rswitch->get_domain = idtg2_get_domain; + rdev->rswitch->em_init = idtg2_em_init; + rdev->rswitch->em_handle = idtg2_em_handler; + rdev->rswitch->sw_sysfs = idtg2_sysfs; + + return 0; +} + +DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init); +DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init); diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c index 2c790c1..fc9f637 100644 --- a/drivers/rapidio/switches/idtcps.c +++ b/drivers/rapidio/switches/idtcps.c @@ -117,6 +117,10 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) { + struct rio_mport *mport = rdev->net->hport; + u16 destid = rdev->rswitch->destid; + u8 hopcount = rdev->rswitch->hopcount; + pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); rdev->rswitch->add_entry = idtcps_route_add_entry; rdev->rswitch->get_entry = idtcps_route_get_entry; @@ -126,6 +130,12 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) rdev->rswitch->em_init = NULL; rdev->rswitch->em_handle = NULL; + if (do_enum) { + /* set TVAL = ~50us */ + rio_mport_write_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); + } + return 0; } diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c index f7fd789..b9a389b 100644 --- a/drivers/rapidio/switches/tsi568.c +++ b/drivers/rapidio/switches/tsi568.c @@ -29,7 +29,7 @@ #define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n) #define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n) -#define TSI568_SP_MODE_BC 0x10004 +#define TSI568_SP_MODE(n) (0x11004 + 0x100*n) #define TSI568_SP_MODE_PW_DIS 0x08000000 static int @@ -117,14 +117,19 @@ tsi568_em_init(struct rio_dev *rdev) u16 destid = rdev->rswitch->destid; u8 hopcount = rdev->rswitch->hopcount; u32 regval; + int portnum; pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount); /* Make sure that Port-Writes are disabled (for all ports) */ - rio_mport_read_config_32(mport, destid, hopcount, - TSI568_SP_MODE_BC, ®val); - rio_mport_write_config_32(mport, destid, hopcount, - TSI568_SP_MODE_BC, regval | TSI568_SP_MODE_PW_DIS); + for (portnum = 0; + portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) { + rio_mport_read_config_32(mport, destid, hopcount, + TSI568_SP_MODE(portnum), ®val); + rio_mport_write_config_32(mport, destid, hopcount, + TSI568_SP_MODE(portnum), + regval | TSI568_SP_MODE_PW_DIS); + } return 0; } diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c index d34df72..2003fb6 100644 --- a/drivers/rapidio/switches/tsi57x.c +++ b/drivers/rapidio/switches/tsi57x.c @@ -166,7 +166,8 @@ tsi57x_em_init(struct rio_dev *rdev) pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount); - for (portnum = 0; portnum < 16; portnum++) { + for (portnum = 0; + portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) { /* Make sure that Port-Writes are enabled (for all ports) */ rio_mport_read_config_32(mport, destid, hopcount, TSI578_SP_MODE(portnum), ®val); @@ -205,6 +206,10 @@ tsi57x_em_init(struct rio_dev *rdev) portnum++; } + /* set TVAL = ~50us */ + rio_mport_write_config_32(mport, destid, hopcount, + rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8); + return 0; } diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2785a0f..6a77437 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -171,7 +171,8 @@ config RTC_DRV_DS3232 depends on RTC_CLASS && I2C help If you say yes here you get support for Dallas Semiconductor - DS3232 real-time clock chips. + DS3232 real-time clock chips. If an interrupt is associated + with the device, the alarm functionality is supported. This driver can also be built as a module. If so, the module will be called rtc-ds3232. @@ -952,4 +953,13 @@ config RTC_DRV_JZ4740 This driver can also be buillt as a module. If so, the module will be called rtc-jz4740. +config RTC_DRV_LPC32XX + depends on ARCH_LPC32XX + tristate "NXP LPC32XX RTC" + help + This enables support for the NXP RTC in the LPC32XX + + This driver can also be buillt as a module. If so, the module + will be called rtc-lpc32xx. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 0f207b3..7a7cb32 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o +obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 565562b..e6539cb 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -158,8 +158,10 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc_dev_prepare(rtc); err = device_register(&rtc->dev); - if (err) + if (err) { + put_device(&rtc->dev); goto exit_kfree; + } rtc_dev_add_device(rtc); rtc_sysfs_add_device(rtc); diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index d4fb82d..b4b6087 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -2,7 +2,7 @@ * Blackfin On-Chip Real Time Clock Driver * Supports BF51x/BF52x/BF53[123]/BF53[467]/BF54x * - * Copyright 2004-2009 Analog Devices Inc. + * Copyright 2004-2010 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -183,29 +183,33 @@ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id) struct bfin_rtc *rtc = dev_get_drvdata(dev); unsigned long events = 0; bool write_complete = false; - u16 rtc_istat, rtc_ictl; + u16 rtc_istat, rtc_istat_clear, rtc_ictl, bits; dev_dbg_stamp(dev); rtc_istat = bfin_read_RTC_ISTAT(); rtc_ictl = bfin_read_RTC_ICTL(); + rtc_istat_clear = 0; - if (rtc_istat & RTC_ISTAT_WRITE_COMPLETE) { - bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE); + bits = RTC_ISTAT_WRITE_COMPLETE; + if (rtc_istat & bits) { + rtc_istat_clear |= bits; write_complete = true; complete(&bfin_write_complete); } - if (rtc_ictl & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) { - if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) { - bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY); + bits = (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY); + if (rtc_ictl & bits) { + if (rtc_istat & bits) { + rtc_istat_clear |= bits; events |= RTC_AF | RTC_IRQF; } } - if (rtc_ictl & RTC_ISTAT_SEC) { - if (rtc_istat & RTC_ISTAT_SEC) { - bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); + bits = RTC_ISTAT_SEC; + if (rtc_ictl & bits) { + if (rtc_istat & bits) { + rtc_istat_clear |= bits; events |= RTC_UF | RTC_IRQF; } } @@ -213,9 +217,10 @@ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id) if (events) rtc_update_irq(rtc->rtc_dev, 1, events); - if (write_complete || events) + if (write_complete || events) { + bfin_write_RTC_ISTAT(rtc_istat_clear); return IRQ_HANDLED; - else + } else return IRQ_NONE; } @@ -422,9 +427,13 @@ static int __devexit bfin_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - if (device_may_wakeup(&pdev->dev)) { + struct device *dev = &pdev->dev; + + dev_dbg_stamp(dev); + + if (device_may_wakeup(dev)) { enable_irq_wake(IRQ_RTC); - bfin_rtc_sync_pending(&pdev->dev); + bfin_rtc_sync_pending(dev); } else bfin_rtc_int_clear(0); @@ -433,7 +442,11 @@ static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) static int bfin_rtc_resume(struct platform_device *pdev) { - if (device_may_wakeup(&pdev->dev)) + struct device *dev = &pdev->dev; + + dev_dbg_stamp(dev); + + if (device_may_wakeup(dev)) disable_irq_wake(IRQ_RTC); /* diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 9de8516..5706355 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -2,6 +2,7 @@ * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C * * Copyright (C) 2009-2010 Freescale Semiconductor. + * Author: Jack Lan <jack.lan@freescale.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -175,6 +176,182 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) DS3232_REG_SECONDS, 7, buf); } +/* + * DS3232 has two alarm, we only use alarm1 + * According to linux specification, only support one-shot alarm + * no periodic alarm mode + */ +static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control, stat; + int ret; + u8 buf[4]; + + mutex_lock(&ds3232->mutex); + + ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); + if (ret < 0) + goto out; + stat = ret; + ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (ret < 0) + goto out; + control = ret; + ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto out; + + alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F); + alarm->time.tm_min = bcd2bin(buf[1] & 0x7F); + alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F); + alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F); + + alarm->time.tm_mon = -1; + alarm->time.tm_year = -1; + alarm->time.tm_wday = -1; + alarm->time.tm_yday = -1; + alarm->time.tm_isdst = -1; + + alarm->enabled = !!(control & DS3232_REG_CR_A1IE); + alarm->pending = !!(stat & DS3232_REG_SR_A1F); + + ret = 0; +out: + mutex_unlock(&ds3232->mutex); + return ret; +} + +/* + * linux rtc-module does not support wday alarm + * and only 24h time mode supported indeed + */ +static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control, stat; + int ret; + u8 buf[4]; + + if (client->irq <= 0) + return -EINVAL; + + mutex_lock(&ds3232->mutex); + + buf[0] = bin2bcd(alarm->time.tm_sec); + buf[1] = bin2bcd(alarm->time.tm_min); + buf[2] = bin2bcd(alarm->time.tm_hour); + buf[3] = bin2bcd(alarm->time.tm_mday); + + /* clear alarm interrupt enable bit */ + ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (ret < 0) + goto out; + control = ret; + control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); + ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + if (ret < 0) + goto out; + + /* clear any pending alarm flag */ + ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); + if (ret < 0) + goto out; + stat = ret; + stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); + ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); + if (ret < 0) + goto out; + + ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + + if (alarm->enabled) { + control |= DS3232_REG_CR_A1IE; + ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + } +out: + mutex_unlock(&ds3232->mutex); + return ret; +} + +static void ds3232_update_alarm(struct i2c_client *client) +{ + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control; + int ret; + u8 buf[4]; + + mutex_lock(&ds3232->mutex); + + ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto unlock; + + buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[0]; + buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[1]; + buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[2]; + buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[3]; + + ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto unlock; + + control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (control < 0) + goto unlock; + + if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF)) + /* enable alarm1 interrupt */ + control |= DS3232_REG_CR_A1IE; + else + /* disable alarm1 interrupt */ + control &= ~(DS3232_REG_CR_A1IE); + i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + +unlock: + mutex_unlock(&ds3232->mutex); +} + +static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + + if (client->irq <= 0) + return -EINVAL; + + if (enabled) + ds3232->rtc->irq_data |= RTC_AF; + else + ds3232->rtc->irq_data &= ~RTC_AF; + + ds3232_update_alarm(client); + return 0; +} + +static int ds3232_update_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + + if (client->irq <= 0) + return -EINVAL; + + if (enabled) + ds3232->rtc->irq_data |= RTC_UF; + else + ds3232->rtc->irq_data &= ~RTC_UF; + + ds3232_update_alarm(client); + return 0; +} + static irqreturn_t ds3232_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; @@ -222,6 +399,10 @@ unlock: static const struct rtc_class_ops ds3232_rtc_ops = { .read_time = ds3232_read_time, .set_time = ds3232_set_time, + .read_alarm = ds3232_read_alarm, + .set_alarm = ds3232_set_alarm, + .alarm_irq_enable = ds3232_alarm_irq_enable, + .update_irq_enable = ds3232_update_irq_enable, }; static int __devinit ds3232_probe(struct i2c_client *client, diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 2619d57..2e16f72 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> + * Copyright (C) 2010, Paul Cercueil <paul@crapouillou.net> * JZ4740 SoC RTC driver * * This program is free software; you can redistribute it and/or modify it @@ -161,7 +162,8 @@ static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC_ALARM, secs); if (!ret) - ret = jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AE, alrm->enabled); + ret = jz4740_rtc_ctrl_set_bits(rtc, + JZ_RTC_CTRL_AE | JZ_RTC_CTRL_AF_IRQ, alrm->enabled); return ret; } @@ -258,6 +260,8 @@ static int __devinit jz4740_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); + device_init_wakeup(&pdev->dev, 1); + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4740_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc)) { @@ -318,12 +322,43 @@ static int __devexit jz4740_rtc_remove(struct platform_device *pdev) return 0; } + +#ifdef CONFIG_PM +static int jz4740_rtc_suspend(struct device *dev) +{ + struct jz4740_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->irq); + return 0; +} + +static int jz4740_rtc_resume(struct device *dev) +{ + struct jz4740_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->irq); + return 0; +} + +static const struct dev_pm_ops jz4740_pm_ops = { + .suspend = jz4740_rtc_suspend, + .resume = jz4740_rtc_resume, +}; +#define JZ4740_RTC_PM_OPS (&jz4740_pm_ops) + +#else +#define JZ4740_RTC_PM_OPS NULL +#endif /* CONFIG_PM */ + struct platform_driver jz4740_rtc_driver = { - .probe = jz4740_rtc_probe, - .remove = __devexit_p(jz4740_rtc_remove), - .driver = { - .name = "jz4740-rtc", + .probe = jz4740_rtc_probe, + .remove = __devexit_p(jz4740_rtc_remove), + .driver = { + .name = "jz4740-rtc", .owner = THIS_MODULE, + .pm = JZ4740_RTC_PM_OPS, }, }; diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c new file mode 100644 index 0000000..ec8701c --- /dev/null +++ b/drivers/rtc/rtc-lpc32xx.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2010 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/rtc.h> +#include <linux/slab.h> +#include <linux/io.h> + +/* + * Clock and Power control register offsets + */ +#define LPC32XX_RTC_UCOUNT 0x00 +#define LPC32XX_RTC_DCOUNT 0x04 +#define LPC32XX_RTC_MATCH0 0x08 +#define LPC32XX_RTC_MATCH1 0x0C +#define LPC32XX_RTC_CTRL 0x10 +#define LPC32XX_RTC_INTSTAT 0x14 +#define LPC32XX_RTC_KEY 0x18 +#define LPC32XX_RTC_SRAM 0x80 + +#define LPC32XX_RTC_CTRL_MATCH0 (1 << 0) +#define LPC32XX_RTC_CTRL_MATCH1 (1 << 1) +#define LPC32XX_RTC_CTRL_ONSW_MATCH0 (1 << 2) +#define LPC32XX_RTC_CTRL_ONSW_MATCH1 (1 << 3) +#define LPC32XX_RTC_CTRL_SW_RESET (1 << 4) +#define LPC32XX_RTC_CTRL_CNTR_DIS (1 << 6) +#define LPC32XX_RTC_CTRL_ONSW_FORCE_HI (1 << 7) + +#define LPC32XX_RTC_INTSTAT_MATCH0 (1 << 0) +#define LPC32XX_RTC_INTSTAT_MATCH1 (1 << 1) +#define LPC32XX_RTC_INTSTAT_ONSW (1 << 2) + +#define LPC32XX_RTC_KEY_ONSW_LOADVAL 0xB5C13F27 + +#define RTC_NAME "rtc-lpc32xx" + +#define rtc_readl(dev, reg) \ + __raw_readl((dev)->rtc_base + (reg)) +#define rtc_writel(dev, reg, val) \ + __raw_writel((val), (dev)->rtc_base + (reg)) + +struct lpc32xx_rtc { + void __iomem *rtc_base; + int irq; + unsigned char alarm_enabled; + struct rtc_device *rtc; + spinlock_t lock; +}; + +static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time) +{ + unsigned long elapsed_sec; + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + + elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT); + rtc_time_to_tm(elapsed_sec, time); + + return rtc_valid_tm(time); +} + +static int lpc32xx_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + u32 tmp; + + spin_lock_irq(&rtc->lock); + + /* RTC must be disabled during count update */ + tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | LPC32XX_RTC_CTRL_CNTR_DIS); + rtc_writel(rtc, LPC32XX_RTC_UCOUNT, secs); + rtc_writel(rtc, LPC32XX_RTC_DCOUNT, 0xFFFFFFFF - secs); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp &= ~LPC32XX_RTC_CTRL_CNTR_DIS); + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static int lpc32xx_rtc_read_alarm(struct device *dev, + struct rtc_wkalrm *wkalrm) +{ + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + + rtc_time_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time); + wkalrm->enabled = rtc->alarm_enabled; + wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) & + LPC32XX_RTC_INTSTAT_MATCH0); + + return rtc_valid_tm(&wkalrm->time); +} + +static int lpc32xx_rtc_set_alarm(struct device *dev, + struct rtc_wkalrm *wkalrm) +{ + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + unsigned long alarmsecs; + u32 tmp; + int ret; + + ret = rtc_tm_to_time(&wkalrm->time, &alarmsecs); + if (ret < 0) { + dev_warn(dev, "Failed to convert time: %d\n", ret); + return ret; + } + + spin_lock_irq(&rtc->lock); + + /* Disable alarm during update */ + tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp & ~LPC32XX_RTC_CTRL_MATCH0); + + rtc_writel(rtc, LPC32XX_RTC_MATCH0, alarmsecs); + + rtc->alarm_enabled = wkalrm->enabled; + if (wkalrm->enabled) { + rtc_writel(rtc, LPC32XX_RTC_INTSTAT, + LPC32XX_RTC_INTSTAT_MATCH0); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | + LPC32XX_RTC_CTRL_MATCH0); + } + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static int lpc32xx_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + u32 tmp; + + spin_lock_irq(&rtc->lock); + tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL); + + if (enabled) { + rtc->alarm_enabled = 1; + tmp |= LPC32XX_RTC_CTRL_MATCH0; + } else { + rtc->alarm_enabled = 0; + tmp &= ~LPC32XX_RTC_CTRL_MATCH0; + } + + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp); + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev) +{ + struct lpc32xx_rtc *rtc = dev; + + spin_lock(&rtc->lock); + + /* Disable alarm interrupt */ + rtc_writel(rtc, LPC32XX_RTC_CTRL, + rtc_readl(rtc, LPC32XX_RTC_CTRL) & + ~LPC32XX_RTC_CTRL_MATCH0); + rtc->alarm_enabled = 0; + + /* + * Write a large value to the match value so the RTC won't + * keep firing the match status + */ + rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF); + rtc_writel(rtc, LPC32XX_RTC_INTSTAT, LPC32XX_RTC_INTSTAT_MATCH0); + + spin_unlock(&rtc->lock); + + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops lpc32xx_rtc_ops = { + .read_time = lpc32xx_rtc_read_time, + .set_mmss = lpc32xx_rtc_set_mmss, + .read_alarm = lpc32xx_rtc_read_alarm, + .set_alarm = lpc32xx_rtc_set_alarm, + .alarm_irq_enable = lpc32xx_rtc_alarm_irq_enable, +}; + +static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct lpc32xx_rtc *rtc; + resource_size_t size; + int rtcirq; + u32 tmp; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Can't get memory resource\n"); + return -ENOENT; + } + + rtcirq = platform_get_irq(pdev, 0); + if (rtcirq < 0 || rtcirq >= NR_IRQS) { + dev_warn(&pdev->dev, "Can't get interrupt resource\n"); + rtcirq = -1; + } + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (unlikely(!rtc)) { + dev_err(&pdev->dev, "Can't allocate memory\n"); + return -ENOMEM; + } + rtc->irq = rtcirq; + + size = resource_size(res); + + if (!devm_request_mem_region(&pdev->dev, res->start, size, + pdev->name)) { + dev_err(&pdev->dev, "RTC registers are not free\n"); + return -EBUSY; + } + + rtc->rtc_base = devm_ioremap(&pdev->dev, res->start, size); + if (!rtc->rtc_base) { + dev_err(&pdev->dev, "Can't map memory\n"); + return -ENOMEM; + } + + spin_lock_init(&rtc->lock); + + /* + * The RTC is on a seperate power domain and can keep it's state + * across a chip power cycle. If the RTC has never been previously + * setup, then set it up now for the first time. + */ + tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL); + if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) { + tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET | + LPC32XX_RTC_CTRL_CNTR_DIS | + LPC32XX_RTC_CTRL_MATCH0 | + LPC32XX_RTC_CTRL_MATCH1 | + LPC32XX_RTC_CTRL_ONSW_MATCH0 | + LPC32XX_RTC_CTRL_ONSW_MATCH1 | + LPC32XX_RTC_CTRL_ONSW_FORCE_HI); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp); + + /* Clear latched interrupt states */ + rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF); + rtc_writel(rtc, LPC32XX_RTC_INTSTAT, + LPC32XX_RTC_INTSTAT_MATCH0 | + LPC32XX_RTC_INTSTAT_MATCH1 | + LPC32XX_RTC_INTSTAT_ONSW); + + /* Write key value to RTC so it won't reload on reset */ + rtc_writel(rtc, LPC32XX_RTC_KEY, + LPC32XX_RTC_KEY_ONSW_LOADVAL); + } else { + rtc_writel(rtc, LPC32XX_RTC_CTRL, + tmp & ~LPC32XX_RTC_CTRL_MATCH0); + } + + platform_set_drvdata(pdev, rtc); + + rtc->rtc = rtc_device_register(RTC_NAME, &pdev->dev, &lpc32xx_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + dev_err(&pdev->dev, "Can't get RTC\n"); + platform_set_drvdata(pdev, NULL); + return PTR_ERR(rtc->rtc); + } + + /* + * IRQ is enabled after device registration in case alarm IRQ + * is pending upon suspend exit. + */ + if (rtc->irq >= 0) { + if (devm_request_irq(&pdev->dev, rtc->irq, + lpc32xx_rtc_alarm_interrupt, + IRQF_DISABLED, pdev->name, rtc) < 0) { + dev_warn(&pdev->dev, "Can't request interrupt.\n"); + rtc->irq = -1; + } else { + device_init_wakeup(&pdev->dev, 1); + } + } + + return 0; +} + +static int __devexit lpc32xx_rtc_remove(struct platform_device *pdev) +{ + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + if (rtc->irq >= 0) + device_init_wakeup(&pdev->dev, 0); + + platform_set_drvdata(pdev, NULL); + rtc_device_unregister(rtc->rtc); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + if (rtc->irq >= 0) { + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(rtc->irq); + else + disable_irq_wake(rtc->irq); + } + + return 0; +} + +static int lpc32xx_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + if (rtc->irq >= 0 && device_may_wakeup(&pdev->dev)) + disable_irq_wake(rtc->irq); + + return 0; +} + +/* Unconditionally disable the alarm */ +static int lpc32xx_rtc_freeze(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + spin_lock_irq(&rtc->lock); + + rtc_writel(rtc, LPC32XX_RTC_CTRL, + rtc_readl(rtc, LPC32XX_RTC_CTRL) & + ~LPC32XX_RTC_CTRL_MATCH0); + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static int lpc32xx_rtc_thaw(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + if (rtc->alarm_enabled) { + spin_lock_irq(&rtc->lock); + + rtc_writel(rtc, LPC32XX_RTC_CTRL, + rtc_readl(rtc, LPC32XX_RTC_CTRL) | + LPC32XX_RTC_CTRL_MATCH0); + + spin_unlock_irq(&rtc->lock); + } + + return 0; +} + +static const struct dev_pm_ops lpc32xx_rtc_pm_ops = { + .suspend = lpc32xx_rtc_suspend, + .resume = lpc32xx_rtc_resume, + .freeze = lpc32xx_rtc_freeze, + .thaw = lpc32xx_rtc_thaw, + .restore = lpc32xx_rtc_resume +}; + +#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops) +#else +#define LPC32XX_RTC_PM_OPS NULL +#endif + +static struct platform_driver lpc32xx_rtc_driver = { + .probe = lpc32xx_rtc_probe, + .remove = __devexit_p(lpc32xx_rtc_remove), + .driver = { + .name = RTC_NAME, + .owner = THIS_MODULE, + .pm = LPC32XX_RTC_PM_OPS + }, +}; + +static int __init lpc32xx_rtc_init(void) +{ + return platform_driver_register(&lpc32xx_rtc_driver); +} +module_init(lpc32xx_rtc_init); + +static void __exit lpc32xx_rtc_exit(void) +{ + platform_driver_unregister(&lpc32xx_rtc_driver); +} +module_exit(lpc32xx_rtc_exit); + +MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com"); +MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtc-lpc32xx"); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 64d9727..73377b0 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -34,7 +34,8 @@ * Board-specific wiring options include using split power mode with * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset), * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from - * low power modes). See the BOARD-SPECIFIC CUSTOMIZATION comment. + * low power modes) for OMAP1 boards (OMAP-L138 has this built into + * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment. */ #define OMAP_RTC_BASE 0xfffb4800 @@ -401,16 +402,17 @@ static int __init omap_rtc_probe(struct platform_device *pdev) /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE: * - * - Boards wired so that RTC_WAKE_INT does something, and muxed - * right (W13_1610_RTC_WAKE_INT is the default after chip reset), - * should initialize the device wakeup flag appropriately. + * - Device wake-up capability setting should come through chip + * init logic. OMAP1 boards should initialize the "wakeup capable" + * flag in the platform device if the board is wired right for + * being woken up by RTC alarm. For OMAP-L138, this capability + * is built into the SoC by the "Deep Sleep" capability. * * - Boards wired so RTC_ON_nOFF is used as the reset signal, * rather than nPWRON_RESET, should forcibly enable split * power mode. (Some chip errata report that RTC_CTRL_SPLIT * is write-only, and always reads as zero...) */ - device_init_wakeup(&pdev->dev, 0); if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT) pr_info("%s: split power mode\n", pdev->name); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index f57a87f..cf953ec 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -100,7 +100,7 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) spin_lock_irq(&s3c_rtc_pie_lock); if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - tmp = readb(s3c_rtc_base + S3C2410_RTCCON); + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); tmp &= ~S3C64XX_RTCCON_TICEN; if (enabled) @@ -171,8 +171,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) goto retry_get_time; } - pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", - rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, + pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); @@ -185,7 +185,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_year += 100; rtc_tm->tm_mon -= 1; - return 0; + return rtc_valid_tm(rtc_tm); } static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) @@ -193,8 +193,8 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) void __iomem *base = s3c_rtc_base; int year = tm->tm_year - 100; - pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, + pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); /* we get around y2k by simply not supporting it */ @@ -231,9 +231,9 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; - pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", + pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", alm_en, - alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, + 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); @@ -242,34 +242,34 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alm_en & S3C2410_RTCALM_SECEN) alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); else - alm_tm->tm_sec = 0xff; + alm_tm->tm_sec = -1; if (alm_en & S3C2410_RTCALM_MINEN) alm_tm->tm_min = bcd2bin(alm_tm->tm_min); else - alm_tm->tm_min = 0xff; + alm_tm->tm_min = -1; if (alm_en & S3C2410_RTCALM_HOUREN) alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); else - alm_tm->tm_hour = 0xff; + alm_tm->tm_hour = -1; if (alm_en & S3C2410_RTCALM_DAYEN) alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); else - alm_tm->tm_mday = 0xff; + alm_tm->tm_mday = -1; if (alm_en & S3C2410_RTCALM_MONEN) { alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon); alm_tm->tm_mon -= 1; } else { - alm_tm->tm_mon = 0xff; + alm_tm->tm_mon = -1; } if (alm_en & S3C2410_RTCALM_YEAREN) alm_tm->tm_year = bcd2bin(alm_tm->tm_year); else - alm_tm->tm_year = 0xffff; + alm_tm->tm_year = -1; return 0; } @@ -280,10 +280,10 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) void __iomem *base = s3c_rtc_base; unsigned int alrm_en; - pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", + pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, - tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, - tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; @@ -318,7 +318,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) unsigned int ticnt; if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - ticnt = readb(s3c_rtc_base + S3C2410_RTCCON); + ticnt = readw(s3c_rtc_base + S3C2410_RTCCON); ticnt &= S3C64XX_RTCCON_TICEN; } else { ticnt = readb(s3c_rtc_base + S3C2410_TICNT); @@ -379,7 +379,8 @@ static const struct rtc_class_ops s3c_rtcops = { .set_alarm = s3c_rtc_setalarm, .irq_set_freq = s3c_rtc_setfreq, .irq_set_state = s3c_rtc_setpie, - .proc = s3c_rtc_proc, + .proc = s3c_rtc_proc, + .alarm_irq_enable = s3c_rtc_setaie, }; static void s3c_rtc_enable(struct platform_device *pdev, int en) @@ -391,11 +392,11 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) return; if (!en) { - tmp = readb(base + S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); if (s3c_rtc_cpu_type == TYPE_S3C64XX) tmp &= ~S3C64XX_RTCCON_TICEN; tmp &= ~S3C2410_RTCCON_RTCEN; - writeb(tmp, base + S3C2410_RTCCON); + writew(tmp, base + S3C2410_RTCCON); if (s3c_rtc_cpu_type == TYPE_S3C2410) { tmp = readb(base + S3C2410_TICNT); @@ -405,25 +406,28 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) } else { /* re-enable the device, and check it is ok */ - if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ + if ((readw(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0) { dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp | S3C2410_RTCCON_RTCEN, + base + S3C2410_RTCCON); } - if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ + if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)) { dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp & ~S3C2410_RTCCON_CNTSEL, + base + S3C2410_RTCCON); } - if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ + if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)) { dev_info(&pdev->dev, "removing RTCCON_CLKRST\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp & ~S3C2410_RTCCON_CLKRST, + base + S3C2410_RTCCON); } } } @@ -452,8 +456,8 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) static int __devinit s3c_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; + struct rtc_time rtc_tm; struct resource *res; - unsigned int tmp, i; int ret; pr_debug("%s: probe=%p\n", __func__, pdev); @@ -514,8 +518,8 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_enable(pdev, 1); - pr_debug("s3c2410_rtc: RTCCON=%02x\n", - readb(s3c_rtc_base + S3C2410_RTCCON)); + pr_debug("s3c2410_rtc: RTCCON=%02x\n", + readw(s3c_rtc_base + S3C2410_RTCCON)); device_init_wakeup(&pdev->dev, 1); @@ -534,11 +538,19 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) /* Check RTC Time */ - for (i = S3C2410_RTCSEC; i <= S3C2410_RTCYEAR; i += 0x4) { - tmp = readb(s3c_rtc_base + i); + s3c_rtc_gettime(NULL, &rtc_tm); + + if (rtc_valid_tm(&rtc_tm)) { + rtc_tm.tm_year = 100; + rtc_tm.tm_mon = 0; + rtc_tm.tm_mday = 1; + rtc_tm.tm_hour = 0; + rtc_tm.tm_min = 0; + rtc_tm.tm_sec = 0; + + s3c_rtc_settime(NULL, &rtc_tm); - if ((tmp & 0xf) > 0x9 || ((tmp >> 4) & 0xf) > 0x9) - writeb(0, s3c_rtc_base + i); + dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); } if (s3c_rtc_cpu_type == TYPE_S3C64XX) @@ -578,7 +590,7 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) /* save TICNT for anyone using periodic interrupts */ ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON); + ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON); ticnt_en_save &= S3C64XX_RTCCON_TICEN; } s3c_rtc_enable(pdev, 0); @@ -596,8 +608,8 @@ static int s3c_rtc_resume(struct platform_device *pdev) s3c_rtc_enable(pdev, 1); writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { - tmp = readb(s3c_rtc_base + S3C2410_RTCCON); - writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); + writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); } if (device_may_wakeup(&pdev->dev)) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 42e303f..0e6aa3d 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -697,9 +697,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; - u32 *buffer, *dst; - u32 __iomem *src; - int c, i, cnt = 0, err = 0; + u8 *buffer, *dst; + u8 __iomem *src; + int c, cnt = 0, err = 0; unsigned long total_size; if (!info || ! info->screen_base) @@ -730,7 +730,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (!buffer) return -ENOMEM; - src = (u32 __iomem *) (info->screen_base + p); + src = (u8 __iomem *) (info->screen_base + p); if (info->fbops->fb_sync) info->fbops->fb_sync(info); @@ -738,17 +738,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) while (count) { c = (count > PAGE_SIZE) ? PAGE_SIZE : count; dst = buffer; - for (i = c >> 2; i--; ) - *dst++ = fb_readl(src++); - if (c & 3) { - u8 *dst8 = (u8 *) dst; - u8 __iomem *src8 = (u8 __iomem *) src; - - for (i = c & 3; i--;) - *dst8++ = fb_readb(src8++); - - src = (u32 __iomem *) src8; - } + fb_memcpy_fromfb(dst, src, c); + dst += c; + src += c; if (copy_to_user(buf, buffer, c)) { err = -EFAULT; @@ -772,9 +764,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; - u32 *buffer, *src; - u32 __iomem *dst; - int c, i, cnt = 0, err = 0; + u8 *buffer, *src; + u8 __iomem *dst; + int c, cnt = 0, err = 0; unsigned long total_size; if (!info || !info->screen_base) @@ -811,7 +803,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (!buffer) return -ENOMEM; - dst = (u32 __iomem *) (info->screen_base + p); + dst = (u8 __iomem *) (info->screen_base + p); if (info->fbops->fb_sync) info->fbops->fb_sync(info); @@ -825,19 +817,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) break; } - for (i = c >> 2; i--; ) - fb_writel(*src++, dst++); - - if (c & 3) { - u8 *src8 = (u8 *) src; - u8 __iomem *dst8 = (u8 __iomem *) dst; - - for (i = c & 3; i--; ) - fb_writeb(*src8++, dst8++); - - dst = (u32 __iomem *) dst8; - } - + fb_memcpy_tofb(dst, src, c); + dst += c; + src += c; *ppos += c; buf += c; cnt += c; @@ -877,13 +859,13 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) if ((err = info->fbops->fb_pan_display(var, info))) return err; - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - info->var.vmode |= FB_VMODE_YWRAP; - else - info->var.vmode &= ~FB_VMODE_YWRAP; - return 0; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; } static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index ca3355e..933899d 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -1143,8 +1143,10 @@ static int __devinit gbefb_probe(struct platform_device *p_dev) return -ENOMEM; #ifndef MODULE - if (fb_get_options("gbefb", &options)) - return -ENODEV; + if (fb_get_options("gbefb", &options)) { + ret = -ENODEV; + goto out_release_framebuffer; + } gbefb_setup(options); #endif diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index f9fa0fd..1717623 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -869,12 +869,9 @@ static int MGAG100_preinit(struct matrox_fb_info *minfo) minfo->capable.plnwt = minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100 ? minfo->devflags.sgram : 1; -#ifdef CONFIG_FB_MATROX_G if (minfo->devflags.g450dac) { minfo->outputs[0].output = &g450out; - } else -#endif - { + } else { minfo->outputs[0].output = &m1064; } minfo->outputs[0].src = minfo->outputs[0].default_src; diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 1e3e8f1..31b8f67 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -280,7 +280,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, return fxtal * (*feed) / (*in) * ctl->den; } -static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, +static int matroxfb_mavenclock(const struct matrox_pll_ctl *ctl, unsigned int htotal, unsigned int vtotal, unsigned int* in, unsigned int* feed, unsigned int* post, unsigned int* htotal2) { diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c index 2ffb34a..87785c2 100644 --- a/drivers/video/omap/blizzard.c +++ b/drivers/video/omap/blizzard.c @@ -1590,7 +1590,7 @@ static int blizzard_init(struct omapfb_device *fbdev, int ext_mode, blizzard.auto_update_window.width = fbdev->panel->x_res; blizzard.auto_update_window.height = fbdev->panel->y_res; blizzard.auto_update_window.out_x = 0; - blizzard.auto_update_window.out_x = 0; + blizzard.auto_update_window.out_y = 0; blizzard.auto_update_window.out_width = fbdev->panel->x_res; blizzard.auto_update_window.out_height = fbdev->panel->y_res; blizzard.auto_update_window.format = 0; diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index ed371c8..b16e613 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -181,6 +181,15 @@ void savagefb_create_i2c_busses(struct fb_info *info) par->chan.algo.getscl = prosavage_gpio_getscl; break; case FB_ACCEL_SAVAGE4: + par->chan.reg = CR_SERIAL1; + if (par->pcidev->revision > 1 && !(VGArCR(0xa6, par) & 0x40)) + par->chan.reg = CR_SERIAL2; + par->chan.ioaddr = par->mmio.vbase; + par->chan.algo.setsda = prosavage_gpio_setsda; + par->chan.algo.setscl = prosavage_gpio_setscl; + par->chan.algo.getsda = prosavage_gpio_getsda; + par->chan.algo.getscl = prosavage_gpio_getscl; + break; case FB_ACCEL_SAVAGE2000: par->chan.reg = 0xff20; par->chan.ioaddr = par->mmio.vbase; diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 2839e28..b7b5014 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -517,10 +517,10 @@ static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO); static W1_MASTER_ATTR_RO(attempts, S_IRUGO); static W1_MASTER_ATTR_RO(timeout, S_IRUGO); static W1_MASTER_ATTR_RO(pointer, S_IRUGO); -static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO); -static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUGO); -static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUGO); -static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUGO); +static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUSR | S_IWGRP); +static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUSR | S_IWGRP); +static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUSR | S_IWGRP); +static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUSR | S_IWGRP); static struct attribute *w1_master_default_attrs[] = { &w1_master_attribute_name.attr, diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index bb4cc5b..79e2ca7 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -42,7 +42,7 @@ config BINFMT_ELF_FDPIC config CORE_DUMP_DEFAULT_ELF_HEADERS bool "Write ELF core dumps with partial segments" - default n + default y depends on BINFMT_ELF && ELF_CORE help ELF core dump files describe each memory mapping of the crashed @@ -60,7 +60,7 @@ config CORE_DUMP_DEFAULT_ELF_HEADERS inherited. See Documentation/filesystems/proc.txt for details. This config option changes the default setting of coredump_filter - seen at boot time. If unsure, say N. + seen at boot time. If unsure, say Y. config BINFMT_FLAT bool "Kernel support for flat binaries" diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 256bb7b..8cf0724 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -77,9 +77,6 @@ /* Maximum number of nesting allowed inside epoll sets */ #define EP_MAX_NESTS 4 -/* Maximum msec timeout value storeable in a long int */ -#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ) - #define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) #define EP_UNACTIVE_PTR ((void *) -1L) @@ -1117,18 +1114,22 @@ static int ep_send_events(struct eventpoll *ep, static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, int maxevents, long timeout) { - int res, eavail; + int res, eavail, timed_out = 0; unsigned long flags; - long jtimeout; + long slack; wait_queue_t wait; - - /* - * Calculate the timeout by checking for the "infinite" value (-1) - * and the overflow condition. The passed timeout is in milliseconds, - * that why (t * HZ) / 1000. - */ - jtimeout = (timeout < 0 || timeout >= EP_MAX_MSTIMEO) ? - MAX_SCHEDULE_TIMEOUT : (timeout * HZ + 999) / 1000; + struct timespec end_time; + ktime_t expires, *to = NULL; + + if (timeout > 0) { + ktime_get_ts(&end_time); + timespec_add_ns(&end_time, (u64)timeout * NSEC_PER_MSEC); + slack = select_estimate_accuracy(&end_time); + to = &expires; + *to = timespec_to_ktime(end_time); + } else if (timeout == 0) { + timed_out = 1; + } retry: spin_lock_irqsave(&ep->lock, flags); @@ -1150,7 +1151,7 @@ retry: * to TASK_INTERRUPTIBLE before doing the checks. */ set_current_state(TASK_INTERRUPTIBLE); - if (!list_empty(&ep->rdllist) || !jtimeout) + if (!list_empty(&ep->rdllist) || timed_out) break; if (signal_pending(current)) { res = -EINTR; @@ -1158,7 +1159,9 @@ retry: } spin_unlock_irqrestore(&ep->lock, flags); - jtimeout = schedule_timeout(jtimeout); + if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS)) + timed_out = 1; + spin_lock_irqsave(&ep->lock, flags); } __remove_wait_queue(&ep->wq, &wait); @@ -1176,7 +1179,7 @@ retry: * more luck. */ if (!res && eavail && - !(res = ep_send_events(ep, events, maxevents)) && jtimeout) + !(res = ep_send_events(ep, events, maxevents)) && !timed_out) goto retry; return res; @@ -66,6 +66,12 @@ char core_pattern[CORENAME_MAX_SIZE] = "core"; unsigned int core_pipe_limit; int suid_dumpable = 0; +struct core_name { + char *corename; + int used, size; +}; +static atomic_t call_count = ATOMIC_INIT(1); + /* The maximal length of core_pattern is also specified in sysctl.c */ static LIST_HEAD(formats); @@ -1003,7 +1009,7 @@ int flush_old_exec(struct linux_binprm * bprm) bprm->mm = NULL; /* We're using it now */ - current->flags &= ~PF_RANDOMIZE; + current->flags &= ~(PF_RANDOMIZE | PF_KTHREAD); flush_thread(); current->personality &= ~bprm->per_clear; @@ -1083,14 +1089,14 @@ EXPORT_SYMBOL(setup_new_exec); */ int prepare_bprm_creds(struct linux_binprm *bprm) { - if (mutex_lock_interruptible(¤t->cred_guard_mutex)) + if (mutex_lock_interruptible(¤t->signal->cred_guard_mutex)) return -ERESTARTNOINTR; bprm->cred = prepare_exec_creds(); if (likely(bprm->cred)) return 0; - mutex_unlock(¤t->cred_guard_mutex); + mutex_unlock(¤t->signal->cred_guard_mutex); return -ENOMEM; } @@ -1098,7 +1104,7 @@ void free_bprm(struct linux_binprm *bprm) { free_arg_pages(bprm); if (bprm->cred) { - mutex_unlock(¤t->cred_guard_mutex); + mutex_unlock(¤t->signal->cred_guard_mutex); abort_creds(bprm->cred); } kfree(bprm); @@ -1119,13 +1125,13 @@ void install_exec_creds(struct linux_binprm *bprm) * credentials; any time after this it may be unlocked. */ security_bprm_committed_creds(bprm); - mutex_unlock(¤t->cred_guard_mutex); + mutex_unlock(¤t->signal->cred_guard_mutex); } EXPORT_SYMBOL(install_exec_creds); /* * determine how safe it is to execute the proposed program - * - the caller must hold current->cred_guard_mutex to protect against + * - the caller must hold ->cred_guard_mutex to protect against * PTRACE_ATTACH */ int check_unsafe_exec(struct linux_binprm *bprm) @@ -1406,7 +1412,6 @@ int do_execve(const char * filename, if (retval < 0) goto out; - current->flags &= ~PF_KTHREAD; retval = search_binary_handler(bprm,regs); if (retval < 0) goto out; @@ -1459,127 +1464,148 @@ void set_binfmt(struct linux_binfmt *new) EXPORT_SYMBOL(set_binfmt); +static int expand_corename(struct core_name *cn) +{ + char *old_corename = cn->corename; + + cn->size = CORENAME_MAX_SIZE * atomic_inc_return(&call_count); + cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL); + + if (!cn->corename) { + kfree(old_corename); + return -ENOMEM; + } + + return 0; +} + +static int cn_printf(struct core_name *cn, const char *fmt, ...) +{ + char *cur; + int need; + int ret; + va_list arg; + + va_start(arg, fmt); + need = vsnprintf(NULL, 0, fmt, arg); + va_end(arg); + + if (likely(need < cn->size - cn->used - 1)) + goto out_printf; + + ret = expand_corename(cn); + if (ret) + goto expand_fail; + +out_printf: + cur = cn->corename + cn->used; + va_start(arg, fmt); + vsnprintf(cur, need + 1, fmt, arg); + va_end(arg); + cn->used += need; + return 0; + +expand_fail: + return ret; +} + /* format_corename will inspect the pattern parameter, and output a * name into corename, which must have space for at least * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. */ -static int format_corename(char *corename, long signr) +static int format_corename(struct core_name *cn, long signr) { const struct cred *cred = current_cred(); const char *pat_ptr = core_pattern; int ispipe = (*pat_ptr == '|'); - char *out_ptr = corename; - char *const out_end = corename + CORENAME_MAX_SIZE; - int rc; int pid_in_pattern = 0; + int err = 0; + + cn->size = CORENAME_MAX_SIZE * atomic_read(&call_count); + cn->corename = kmalloc(cn->size, GFP_KERNEL); + cn->used = 0; + + if (!cn->corename) + return -ENOMEM; /* Repeat as long as we have more pattern to process and more output space */ while (*pat_ptr) { if (*pat_ptr != '%') { - if (out_ptr == out_end) + if (*pat_ptr == 0) goto out; - *out_ptr++ = *pat_ptr++; + err = cn_printf(cn, "%c", *pat_ptr++); } else { switch (*++pat_ptr) { + /* single % at the end, drop that */ case 0: goto out; /* Double percent, output one percent */ case '%': - if (out_ptr == out_end) - goto out; - *out_ptr++ = '%'; + err = cn_printf(cn, "%c", '%'); break; /* pid */ case 'p': pid_in_pattern = 1; - rc = snprintf(out_ptr, out_end - out_ptr, - "%d", task_tgid_vnr(current)); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; + err = cn_printf(cn, "%d", + task_tgid_vnr(current)); break; /* uid */ case 'u': - rc = snprintf(out_ptr, out_end - out_ptr, - "%d", cred->uid); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; + err = cn_printf(cn, "%d", cred->uid); break; /* gid */ case 'g': - rc = snprintf(out_ptr, out_end - out_ptr, - "%d", cred->gid); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; + err = cn_printf(cn, "%d", cred->gid); break; /* signal that caused the coredump */ case 's': - rc = snprintf(out_ptr, out_end - out_ptr, - "%ld", signr); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; + err = cn_printf(cn, "%ld", signr); break; /* UNIX time of coredump */ case 't': { struct timeval tv; do_gettimeofday(&tv); - rc = snprintf(out_ptr, out_end - out_ptr, - "%lu", tv.tv_sec); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; + err = cn_printf(cn, "%lu", tv.tv_sec); break; } /* hostname */ case 'h': down_read(&uts_sem); - rc = snprintf(out_ptr, out_end - out_ptr, - "%s", utsname()->nodename); + err = cn_printf(cn, "%s", + utsname()->nodename); up_read(&uts_sem); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; break; /* executable */ case 'e': - rc = snprintf(out_ptr, out_end - out_ptr, - "%s", current->comm); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; + err = cn_printf(cn, "%s", current->comm); break; /* core limit size */ case 'c': - rc = snprintf(out_ptr, out_end - out_ptr, - "%lu", rlimit(RLIMIT_CORE)); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; + err = cn_printf(cn, "%lu", + rlimit(RLIMIT_CORE)); break; default: break; } ++pat_ptr; } + + if (err) + return err; } + /* Backward compatibility with core_uses_pid: * * If core_pattern does not include a %p (as is the default) * and core_uses_pid is set, then .%pid will be appended to * the filename. Do not do this for piped commands. */ if (!ispipe && !pid_in_pattern && core_uses_pid) { - rc = snprintf(out_ptr, out_end - out_ptr, - ".%d", task_tgid_vnr(current)); - if (rc > out_end - out_ptr) - goto out; - out_ptr += rc; + err = cn_printf(cn, ".%d", task_tgid_vnr(current)); + if (err) + return err; } out: - *out_ptr = 0; return ispipe; } @@ -1856,7 +1882,7 @@ static int umh_pipe_setup(struct subprocess_info *info) void do_coredump(long signr, int exit_code, struct pt_regs *regs) { struct core_state core_state; - char corename[CORENAME_MAX_SIZE + 1]; + struct core_name cn; struct mm_struct *mm = current->mm; struct linux_binfmt * binfmt; const struct cred *old_cred; @@ -1911,7 +1937,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) */ clear_thread_flag(TIF_SIGPENDING); - ispipe = format_corename(corename, signr); + ispipe = format_corename(&cn, signr); + + if (ispipe == -ENOMEM) { + printk(KERN_WARNING "format_corename failed\n"); + printk(KERN_WARNING "Aborting core\n"); + goto fail_corename; + } if (ispipe) { int dump_count; @@ -1948,7 +1980,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) goto fail_dropcount; } - helper_argv = argv_split(GFP_KERNEL, corename+1, NULL); + helper_argv = argv_split(GFP_KERNEL, cn.corename+1, NULL); if (!helper_argv) { printk(KERN_WARNING "%s failed to allocate memory\n", __func__); @@ -1961,7 +1993,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) argv_free(helper_argv); if (retval) { printk(KERN_INFO "Core dump to %s pipe failed\n", - corename); + cn.corename); goto close_fail; } } else { @@ -1970,7 +2002,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) if (cprm.limit < binfmt->min_coredump) goto fail_unlock; - cprm.file = filp_open(corename, + cprm.file = filp_open(cn.corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600); if (IS_ERR(cprm.file)) @@ -2012,6 +2044,8 @@ fail_dropcount: if (ispipe) atomic_dec(&core_dump_count); fail_unlock: + kfree(cn.corename); +fail_corename: coredump_finish(mm); revert_creds(old_cred); fail_creds: diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index b986642..6e07696 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1334,12 +1334,7 @@ out_finish: static void fuse_retrieve_end(struct fuse_conn *fc, struct fuse_req *req) { - int i; - - for (i = 0; i < req->num_pages; i++) { - struct page *page = req->pages[i]; - page_cache_release(page); - } + release_pages(req->pages, req->num_pages, 0); } static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 60c2b944..79cf7f61 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -544,6 +544,34 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session) } /* + * Check if root directory is empty (has less than 3 files). + * + * Used to detect broken CDs where ISO root directory is empty but Joliet root + * directory is OK. If such CD has Rock Ridge extensions, they will be disabled + * (and Joliet used instead) or else no files would be visible. + */ +static bool rootdir_empty(struct super_block *sb, unsigned long block) +{ + int offset = 0, files = 0, de_len; + struct iso_directory_record *de; + struct buffer_head *bh; + + bh = sb_bread(sb, block); + if (!bh) + return true; + while (files < 3) { + de = (struct iso_directory_record *) (bh->b_data + offset); + de_len = *(unsigned char *) de; + if (de_len == 0) + break; + files++; + offset += de_len; + } + brelse(bh); + return files < 3; +} + +/* * Initialize the superblock and read the root inode. * * Note: a check_disk_change() has been done immediately prior @@ -843,6 +871,18 @@ root_found: goto out_no_root; /* + * Fix for broken CDs with Rock Ridge and empty ISO root directory but + * correct Joliet root directory. + */ + if (sbi->s_rock == 1 && joliet_level && + rootdir_empty(s, sbi->s_firstdatazone)) { + printk(KERN_NOTICE + "ISOFS: primary root directory is empty. " + "Disabling Rock Ridge and switching to Joliet."); + sbi->s_rock = 0; + } + + /* * If this disk has both Rock Ridge and Joliet on it, then we * want to use Rock Ridge by default. This can be overridden * by using the norock mount option. There is still one other diff --git a/fs/proc/base.c b/fs/proc/base.c index 9b094c1..f3d02ca 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -226,7 +226,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task) { struct mm_struct *mm; - if (mutex_lock_killable(&task->cred_guard_mutex)) + if (mutex_lock_killable(&task->signal->cred_guard_mutex)) return NULL; mm = get_task_mm(task); @@ -235,7 +235,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task) mmput(mm); mm = NULL; } - mutex_unlock(&task->cred_guard_mutex); + mutex_unlock(&task->signal->cred_guard_mutex); return mm; } @@ -2354,14 +2354,14 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, goto out_free; /* Guard against adverse ptrace interaction */ - length = mutex_lock_interruptible(&task->cred_guard_mutex); + length = mutex_lock_interruptible(&task->signal->cred_guard_mutex); if (length < 0) goto out_free; length = security_setprocattr(task, (char*)file->f_path.dentry->d_name.name, (void*)page, count); - mutex_unlock(&task->cred_guard_mutex); + mutex_unlock(&task->signal->cred_guard_mutex); out_free: free_page((unsigned long) page); out: diff --git a/fs/proc/softirqs.c b/fs/proc/softirqs.c index 1807c24..3799473 100644 --- a/fs/proc/softirqs.c +++ b/fs/proc/softirqs.c @@ -10,13 +10,13 @@ static int show_softirqs(struct seq_file *p, void *v) { int i, j; - seq_printf(p, " "); + seq_printf(p, " "); for_each_possible_cpu(i) seq_printf(p, "CPU%-8d", i); seq_printf(p, "\n"); for (i = 0; i < NR_SOFTIRQS; i++) { - seq_printf(p, "%8s:", softirq_to_name[i]); + seq_printf(p, "%12s:", softirq_to_name[i]); for_each_possible_cpu(j) seq_printf(p, " %10u", kstat_softirqs_cpu(i, j)); seq_printf(p, "\n"); diff --git a/fs/proc/stat.c b/fs/proc/stat.c index bf31b03..e15a19c 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c @@ -31,7 +31,6 @@ static int show_stat(struct seq_file *p, void *v) u64 sum_softirq = 0; unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; struct timespec boottime; - unsigned int per_irq_sum; user = nice = system = idle = iowait = irq = softirq = steal = cputime64_zero; @@ -52,9 +51,7 @@ static int show_stat(struct seq_file *p, void *v) guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); guest_nice = cputime64_add(guest_nice, kstat_cpu(i).cpustat.guest_nice); - for_each_irq_nr(j) { - sum += kstat_irqs_cpu(j, i); - } + sum += kstat_cpu_irqs_sum(i); sum += arch_irq_stat_cpu(i); for (j = 0; j < NR_SOFTIRQS; j++) { @@ -110,13 +107,8 @@ static int show_stat(struct seq_file *p, void *v) seq_printf(p, "intr %llu", (unsigned long long)sum); /* sum again ? it could be updated? */ - for_each_irq_nr(j) { - per_irq_sum = 0; - for_each_possible_cpu(i) - per_irq_sum += kstat_irqs_cpu(j, i); - - seq_printf(p, " %u", per_irq_sum); - } + for_each_irq_nr(j) + seq_printf(p, " %u", kstat_irqs(j)); seq_printf(p, "\nctxt %llu\n" diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 871e25e..da6b01d 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -327,6 +327,7 @@ struct mem_size_stats { unsigned long private_clean; unsigned long private_dirty; unsigned long referenced; + unsigned long anonymous; unsigned long swap; u64 pss; }; @@ -357,6 +358,9 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, if (!page) continue; + if (PageAnon(page)) + mss->anonymous += PAGE_SIZE; + mss->resident += PAGE_SIZE; /* Accumulate the size in pages that have been accessed. */ if (pte_young(ptent) || PageReferenced(page)) @@ -410,6 +414,7 @@ static int show_smap(struct seq_file *m, void *v) "Private_Clean: %8lu kB\n" "Private_Dirty: %8lu kB\n" "Referenced: %8lu kB\n" + "Anonymous: %8lu kB\n" "Swap: %8lu kB\n" "KernelPageSize: %8lu kB\n" "MMUPageSize: %8lu kB\n", @@ -421,6 +426,7 @@ static int show_smap(struct seq_file *m, void *v) mss.private_clean >> 10, mss.private_dirty >> 10, mss.referenced >> 10, + mss.anonymous >> 10, mss.swap >> 10, vma_kernel_pagesize(vma) >> 10, vma_mmu_pagesize(vma) >> 10); diff --git a/fs/select.c b/fs/select.c index 500a669..b7b10aa 100644 --- a/fs/select.c +++ b/fs/select.c @@ -67,7 +67,7 @@ static long __estimate_accuracy(struct timespec *tv) return slack; } -static long estimate_accuracy(struct timespec *tv) +long select_estimate_accuracy(struct timespec *tv) { unsigned long ret; struct timespec now; @@ -417,7 +417,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) } if (end_time && !timed_out) - slack = estimate_accuracy(end_time); + slack = select_estimate_accuracy(end_time); retval = 0; for (;;) { @@ -769,7 +769,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list, } if (end_time && !timed_out) - slack = estimate_accuracy(end_time); + slack = select_estimate_accuracy(end_time); for (;;) { struct poll_list *walk; diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h index ca0f239..2bcc5c7 100644 --- a/include/asm-generic/cputime.h +++ b/include/asm-generic/cputime.h @@ -33,10 +33,10 @@ typedef u64 cputime64_t; /* - * Convert cputime to milliseconds and back. + * Convert cputime to microseconds and back. */ -#define cputime_to_msecs(__ct) jiffies_to_msecs(__ct) -#define msecs_to_cputime(__msecs) msecs_to_jiffies(__msecs) +#define cputime_to_usecs(__ct) jiffies_to_usecs(__ct); +#define usecs_to_cputime(__msecs) usecs_to_jiffies(__msecs); /* * Convert cputime to seconds and back. diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 8ca18e2..ff5c660 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -210,7 +210,7 @@ extern void gpio_unexport(unsigned gpio); #endif /* CONFIG_GPIO_SYSFS */ -#else /* !CONFIG_HAVE_GPIO_LIB */ +#else /* !CONFIG_GPIOLIB */ static inline int gpio_is_valid(int number) { @@ -239,7 +239,7 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value) gpio_set_value(gpio, value); } -#endif /* !CONFIG_HAVE_GPIO_LIB */ +#endif /* !CONFIG_GPIOLIB */ #ifndef CONFIG_GPIO_SYSFS diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h new file mode 100644 index 0000000..198087a --- /dev/null +++ b/include/linux/basic_mmio_gpio.h @@ -0,0 +1,20 @@ +/* + * Basic memory-mapped GPIO controllers. + * + * Copyright 2008 MontaVista Software, Inc. + * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __BASIC_MMIO_GPIO_H +#define __BASIC_MMIO_GPIO_H + +struct bgpio_pdata { + int base; +}; + +#endif /* __BASIC_MMIO_GPIO_H */ diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 709dfb9..ed4ba11 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -154,6 +154,10 @@ enum { * A thread in rmdir() is wating for this cgroup. */ CGRP_WAIT_ON_RMDIR, + /* + * Clone cgroup values when creating a new child cgroup + */ + CGRP_CLONE_CHILDREN, }; /* which pidlist file are we talking about? */ diff --git a/include/linux/fb.h b/include/linux/fb.h index f0268de..7fca3dc 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -931,6 +931,8 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { #define fb_writel sbus_writel #define fb_writeq sbus_writeq #define fb_memset sbus_memset_io +#define fb_memcpy_fromfb sbus_memcpy_fromio +#define fb_memcpy_tofb sbus_memcpy_toio #elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__) || defined(__bfin__) @@ -943,6 +945,8 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { #define fb_writel __raw_writel #define fb_writeq __raw_writeq #define fb_memset memset_io +#define fb_memcpy_fromfb memcpy_fromio +#define fb_memcpy_tofb memcpy_toio #else @@ -955,6 +959,8 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { #define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b)) #define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b)) #define fb_memset memset +#define fb_memcpy_fromfb memcpy +#define fb_memcpy_tofb memcpy #endif diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 8a85ec1..e913819 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -37,27 +37,6 @@ extern unsigned long totalhigh_pages; void kmap_flush_unused(void); -DECLARE_PER_CPU(int, __kmap_atomic_idx); - -static inline int kmap_atomic_idx_push(void) -{ - int idx = __get_cpu_var(__kmap_atomic_idx)++; -#ifdef CONFIG_DEBUG_HIGHMEM - WARN_ON_ONCE(in_irq() && !irqs_disabled()); - BUG_ON(idx > KM_TYPE_NR); -#endif - return idx; -} - -static inline int kmap_atomic_idx_pop(void) -{ - int idx = --__get_cpu_var(__kmap_atomic_idx); -#ifdef CONFIG_DEBUG_HIGHMEM - BUG_ON(idx < 0); -#endif - return idx; -} - #else /* CONFIG_HIGHMEM */ static inline unsigned int nr_free_highpages(void) { return 0; } @@ -95,6 +74,36 @@ static inline void __kunmap_atomic(void *addr) #endif /* CONFIG_HIGHMEM */ +#if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) + +DECLARE_PER_CPU(int, __kmap_atomic_idx); + +static inline int kmap_atomic_idx_push(void) +{ + int idx = __get_cpu_var(__kmap_atomic_idx)++; +#ifdef CONFIG_DEBUG_HIGHMEM + WARN_ON_ONCE(in_irq() && !irqs_disabled()); + BUG_ON(idx > KM_TYPE_NR); +#endif + return idx; +} + +static inline int kmap_atomic_idx(void) +{ + return __get_cpu_var(__kmap_atomic_idx) - 1; +} + +static inline int kmap_atomic_idx_pop(void) +{ + int idx = --__get_cpu_var(__kmap_atomic_idx); +#ifdef CONFIG_DEBUG_HIGHMEM + BUG_ON(idx < 0); +#endif + return idx; +} + +#endif + /* * Make both: kmap_atomic(page, idx) and kmap_atomic(page) work. */ diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h index 269181b..3c5d6b6 100644 --- a/include/linux/i2c/adp5588.h +++ b/include/linux/i2c/adp5588.h @@ -74,6 +74,20 @@ #define ADP5588_DEVICE_ID_MASK 0xF + /* Configuration Register1 */ +#define ADP5588_AUTO_INC (1 << 7) +#define ADP5588_GPIEM_CFG (1 << 6) +#define ADP5588_INT_CFG (1 << 4) +#define ADP5588_GPI_IEN (1 << 1) + +/* Interrupt Status Register */ +#define ADP5588_GPI_INT (1 << 1) +#define ADP5588_KE_INT (1 << 0) + +#define ADP5588_MAXGPIO 18 +#define ADP5588_BANK(offs) ((offs) >> 3) +#define ADP5588_BIT(offs) (1u << ((offs) & 0x7)) + /* Put one of these structures in i2c_board_info platform_data */ #define ADP5588_KEYMAPSIZE 80 @@ -126,9 +140,12 @@ struct adp5588_kpad_platform_data { const struct adp5588_gpio_platform_data *gpio_data; }; +struct i2c_client; /* forward declaration */ + struct adp5588_gpio_platform_data { - unsigned gpio_start; /* GPIO Chip base # */ - unsigned pullup_dis_mask; /* Pull-Up Disable Mask */ + int gpio_start; /* GPIO Chip base # */ + unsigned irq_base; /* interrupt base # */ + unsigned pullup_dis_mask; /* Pull-Up Disable Mask */ int (*setup)(struct i2c_client *client, int gpio, unsigned ngpio, void *context); diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 2fea6c8..1f8c06c 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -29,6 +29,8 @@ extern struct fs_struct init_fs; .running = 0, \ .lock = __SPIN_LOCK_UNLOCKED(sig.cputimer.lock), \ }, \ + .cred_guard_mutex = \ + __MUTEX_INITIALIZER(sig.cred_guard_mutex), \ } extern struct nsproxy init_nsproxy; @@ -145,8 +147,6 @@ extern struct cred init_cred; .group_leader = &tsk, \ RCU_INIT_POINTER(.real_cred, &init_cred), \ RCU_INIT_POINTER(.cred, &init_cred), \ - .cred_guard_mutex = \ - __MUTEX_INITIALIZER(tsk.cred_guard_mutex), \ .comm = "swapper", \ .thread = INIT_THREAD, \ .fs = &init_fs, \ diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index c059044..ad54c84 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -33,6 +33,7 @@ struct kernel_stat { #ifndef CONFIG_GENERIC_HARDIRQS unsigned int irqs[NR_IRQS]; #endif + unsigned long irqs_sum; unsigned int softirqs[NR_SOFTIRQS]; }; @@ -54,6 +55,7 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *desc) { kstat_this_cpu.irqs[irq]++; + kstat_this_cpu.irqs_sum++; } static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) @@ -65,8 +67,9 @@ static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu); #define kstat_irqs_this_cpu(DESC) \ ((DESC)->kstat_irqs[smp_processor_id()]) -#define kstat_incr_irqs_this_cpu(irqno, DESC) \ - ((DESC)->kstat_irqs[smp_processor_id()]++) +#define kstat_incr_irqs_this_cpu(irqno, DESC) do {\ + ((DESC)->kstat_irqs[smp_processor_id()]++);\ + kstat_this_cpu.irqs_sum++; } while (0) #endif @@ -83,6 +86,7 @@ static inline unsigned int kstat_softirqs_cpu(unsigned int irq, int cpu) /* * Number of interrupts per specific IRQ source, since bootup */ +#ifndef CONFIG_GENERIC_HARDIRQS static inline unsigned int kstat_irqs(unsigned int irq) { unsigned int sum = 0; @@ -93,7 +97,17 @@ static inline unsigned int kstat_irqs(unsigned int irq) return sum; } +#else +extern unsigned int kstat_irqs(unsigned int irq); +#endif +/* + * Number of interrupts per cpu, since bootup + */ +static inline unsigned int kstat_cpu_irqs_sum(unsigned int cpu) +{ + return kstat_cpu(cpu).irqs_sum; +} /* * Lock/unlock the current runqueue - to extract task statistics: diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index c238ad2..10308c6 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -171,8 +171,17 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void); } -/* __kfifo_must_check_helper() is temporarily disabled because it was faulty */ -#define __kfifo_must_check_helper(x) (x) +static inline unsigned int __must_check +__kfifo_uint_must_check_helper(unsigned int val) +{ + return val; +} + +static inline int __must_check +__kfifo_int_must_check_helper(int val) +{ + return val; +} /** * kfifo_initialized - Check if the fifo is initialized @@ -264,7 +273,7 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void); * @fifo: address of the fifo to be used */ #define kfifo_avail(fifo) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmpq = (fifo); \ const size_t __recsize = sizeof(*__tmpq->rectype); \ @@ -297,7 +306,7 @@ __kfifo_must_check_helper( \ * This function returns the size of the next fifo record in number of bytes. */ #define kfifo_peek_len(fifo) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ const size_t __recsize = sizeof(*__tmp->rectype); \ @@ -320,7 +329,7 @@ __kfifo_must_check_helper( \ * Return 0 if no error, otherwise an error code. */ #define kfifo_alloc(fifo, size, gfp_mask) \ -__kfifo_must_check_helper( \ +__kfifo_int_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ @@ -416,7 +425,7 @@ __kfifo_must_check_helper( \ * writer, you don't need extra locking to use these macro. */ #define kfifo_get(fifo, val) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ typeof((val) + 1) __val = (val); \ @@ -457,7 +466,7 @@ __kfifo_must_check_helper( \ * writer, you don't need extra locking to use these macro. */ #define kfifo_peek(fifo, val) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ typeof((val) + 1) __val = (val); \ @@ -549,7 +558,7 @@ __kfifo_must_check_helper( \ * writer, you don't need extra locking to use these macro. */ #define kfifo_out(fifo, buf, n) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ typeof((buf) + 1) __buf = (buf); \ @@ -577,7 +586,7 @@ __kfifo_must_check_helper( \ * copied. */ #define kfifo_out_spinlocked(fifo, buf, n, lock) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ unsigned long __flags; \ unsigned int __ret; \ @@ -606,7 +615,7 @@ __kfifo_must_check_helper( \ * writer, you don't need extra locking to use these macro. */ #define kfifo_from_user(fifo, from, len, copied) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ const void __user *__from = (from); \ @@ -634,7 +643,7 @@ __kfifo_must_check_helper( \ * writer, you don't need extra locking to use these macro. */ #define kfifo_to_user(fifo, to, len, copied) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ void __user *__to = (to); \ @@ -761,7 +770,7 @@ __kfifo_must_check_helper( \ * writer, you don't need extra locking to use these macro. */ #define kfifo_out_peek(fifo, buf, n) \ -__kfifo_must_check_helper( \ +__kfifo_uint_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ typeof((buf) + 1) __buf = (buf); \ diff --git a/include/linux/poll.h b/include/linux/poll.h index 600cc1f..56e76af 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -73,6 +73,8 @@ extern void poll_initwait(struct poll_wqueues *pwq); extern void poll_freewait(struct poll_wqueues *pwq); extern int poll_schedule_timeout(struct poll_wqueues *pwq, int state, ktime_t *expires, unsigned long slack); +extern long select_estimate_accuracy(struct timespec *tv); + static inline int poll_schedule(struct poll_wqueues *pwq, int state) { diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 4272521..092a04f 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -100,7 +100,8 @@ #include <linux/sched.h> /* For struct task_struct. */ -extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); +extern long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data); extern int ptrace_traceme(void); extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); @@ -108,7 +109,8 @@ extern int ptrace_attach(struct task_struct *tsk); extern int ptrace_detach(struct task_struct *, unsigned int); extern void ptrace_disable(struct task_struct *); extern int ptrace_check_attach(struct task_struct *task, int kill); -extern int ptrace_request(struct task_struct *child, long request, long addr, long data); +extern int ptrace_request(struct task_struct *child, long request, + unsigned long addr, unsigned long data); extern void ptrace_notify(int exit_code); extern void __ptrace_link(struct task_struct *child, struct task_struct *new_parent); @@ -132,8 +134,10 @@ static inline void ptrace_unlink(struct task_struct *child) __ptrace_unlink(child); } -int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data); -int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data); +int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, + unsigned long data); +int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, + unsigned long data); /** * task_ptrace - return %PT_* flags that apply to a task diff --git a/include/linux/ramoops.h b/include/linux/ramoops.h new file mode 100644 index 0000000..0ae68a2 --- /dev/null +++ b/include/linux/ramoops.h @@ -0,0 +1,15 @@ +#ifndef __RAMOOPS_H +#define __RAMOOPS_H + +/* + * Ramoops platform data + * @mem_size memory size for ramoops + * @mem_address physical memory address to contain ramoops + */ + +struct ramoops_platform_data { + unsigned long mem_size; + unsigned long mem_address; +}; + +#endif diff --git a/include/linux/rio.h b/include/linux/rio.h index bd6eb0e..0bed941 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -67,6 +67,7 @@ #define RIO_PW_MSG_SIZE 64 extern struct bus_type rio_bus_type; +extern struct device rio_bus; extern struct list_head rio_devices; /* list of all devices */ struct rio_mport; @@ -98,6 +99,7 @@ union rio_pw_msg; * @riores: RIO resources this device owns * @pwcback: port-write callback function for this device * @destid: Network destination ID + * @prev: Previous RIO device connected to the current one */ struct rio_dev { struct list_head global_list; /* node in list of all RIO devices */ @@ -111,7 +113,7 @@ struct rio_dev { u16 asm_rev; u16 efptr; u32 pef; - u32 swpinfo; /* Only used for switches */ + u32 swpinfo; u32 src_ops; u32 dst_ops; u32 comp_tag; @@ -124,6 +126,7 @@ struct rio_dev { struct resource riores[RIO_MAX_DEV_RESOURCES]; int (*pwcback) (struct rio_dev *rdev, union rio_pw_msg *msg, int step); u16 destid; + struct rio_dev *prev; }; #define rio_dev_g(n) list_entry(n, struct rio_dev, global_list) @@ -174,6 +177,7 @@ enum rio_phy_type { * @index: Port index, unique among all port interfaces of the same type * @sys_size: RapidIO common transport system size * @phy_type: RapidIO phy type + * @phys_efptr: RIO port extended features pointer * @name: Port name string * @priv: Master port private data */ @@ -195,6 +199,7 @@ struct rio_mport { * 1 - Large size, 65536 devices. */ enum rio_phy_type phy_type; /* RapidIO phy type */ + u32 phys_efptr; unsigned char name[40]; void *priv; /* Master port private data */ }; @@ -215,9 +220,14 @@ struct rio_net { unsigned char id; /* RIO network ID */ }; +/* Definitions used by switch sysfs initialization callback */ +#define RIO_SW_SYSFS_CREATE 1 /* Create switch attributes */ +#define RIO_SW_SYSFS_REMOVE 0 /* Remove switch attributes */ + /** * struct rio_switch - RIO switch info * @node: Node in global list of switches + * @rdev: Associated RIO device structure * @switchid: Switch ID that is unique across a network * @hopcount: Hopcount to this switch * @destid: Associated destid in the path @@ -230,9 +240,12 @@ struct rio_net { * @get_domain: Callback for switch-specific domain get function * @em_init: Callback for switch-specific error management initialization function * @em_handle: Callback for switch-specific error management handler function + * @sw_sysfs: Callback that initializes switch-specific sysfs attributes + * @nextdev: Array of per-port pointers to the next attached device */ struct rio_switch { struct list_head node; + struct rio_dev *rdev; u16 switchid; u16 hopcount; u16 destid; @@ -250,6 +263,8 @@ struct rio_switch { u8 *sw_domain); int (*em_init) (struct rio_dev *dev); int (*em_handle) (struct rio_dev *dev, u8 swport); + int (*sw_sysfs) (struct rio_dev *dev, int create); + struct rio_dev *nextdev[0]; }; /* Low-level architecture-dependent routines */ diff --git a/include/linux/rio_ids.h b/include/linux/rio_ids.h index db50e1c..ee7b6ad 100644 --- a/include/linux/rio_ids.h +++ b/include/linux/rio_ids.h @@ -34,5 +34,7 @@ #define RIO_DID_IDTCPS16 0x035b #define RIO_DID_IDTCPS6Q 0x035f #define RIO_DID_IDTCPS10Q 0x035e +#define RIO_DID_IDTCPS1848 0x0374 +#define RIO_DID_IDTCPS1616 0x0379 #endif /* LINUX_RIO_IDS_H */ diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h index aedee04..d63dcba 100644 --- a/include/linux/rio_regs.h +++ b/include/linux/rio_regs.h @@ -33,6 +33,7 @@ #define RIO_PEF_MEMORY 0x40000000 /* [I] MMIO */ #define RIO_PEF_PROCESSOR 0x20000000 /* [I] Processor */ #define RIO_PEF_SWITCH 0x10000000 /* [I] Switch */ +#define RIO_PEF_MULTIPORT 0x08000000 /* [VI, 2.1] Multiport */ #define RIO_PEF_INB_MBOX 0x00f00000 /* [II] Mailboxes */ #define RIO_PEF_INB_MBOX0 0x00800000 /* [II] Mailbox 0 */ #define RIO_PEF_INB_MBOX1 0x00400000 /* [II] Mailbox 1 */ @@ -51,6 +52,7 @@ #define RIO_SWP_INFO_PORT_TOTAL_MASK 0x0000ff00 /* [I] Total number of ports */ #define RIO_SWP_INFO_PORT_NUM_MASK 0x000000ff /* [I] Maintenance transaction port number */ #define RIO_GET_TOTAL_PORTS(x) ((x & RIO_SWP_INFO_PORT_TOTAL_MASK) >> 8) +#define RIO_GET_PORT_NUM(x) (x & RIO_SWP_INFO_PORT_NUM_MASK) #define RIO_SRC_OPS_CAR 0x18 /* [I] Source Operations CAR */ #define RIO_SRC_OPS_READ 0x00008000 /* [I] Read op */ @@ -159,6 +161,7 @@ #define RIO_COMPONENT_TAG_CSR 0x6c /* [III] Component Tag CSR */ #define RIO_STD_RTE_CONF_DESTID_SEL_CSR 0x70 +#define RIO_STD_RTE_CONF_EXTCFGEN 0x80000000 #define RIO_STD_RTE_CONF_PORT_SEL_CSR 0x74 #define RIO_STD_RTE_DEFAULT_PORT 0x78 @@ -222,15 +225,17 @@ #define RIO_PORT_GEN_MASTER 0x40000000 #define RIO_PORT_GEN_DISCOVERED 0x20000000 #define RIO_PORT_N_MNT_REQ_CSR(x) (0x0040 + x*0x20) /* 0x0002 */ +#define RIO_MNT_REQ_CMD_RD 0x03 /* Reset-device command */ +#define RIO_MNT_REQ_CMD_IS 0x04 /* Input-status command */ #define RIO_PORT_N_MNT_RSP_CSR(x) (0x0044 + x*0x20) /* 0x0002 */ #define RIO_PORT_N_MNT_RSP_RVAL 0x80000000 /* Response Valid */ -#define RIO_PORT_N_MNT_RSP_ASTAT 0x000003e0 /* ackID Status */ +#define RIO_PORT_N_MNT_RSP_ASTAT 0x000007e0 /* ackID Status */ #define RIO_PORT_N_MNT_RSP_LSTAT 0x0000001f /* Link Status */ #define RIO_PORT_N_ACK_STS_CSR(x) (0x0048 + x*0x20) /* 0x0002 */ #define RIO_PORT_N_ACK_CLEAR 0x80000000 -#define RIO_PORT_N_ACK_INBOUND 0x1f000000 -#define RIO_PORT_N_ACK_OUTSTAND 0x00001f00 -#define RIO_PORT_N_ACK_OUTBOUND 0x0000001f +#define RIO_PORT_N_ACK_INBOUND 0x3f000000 +#define RIO_PORT_N_ACK_OUTSTAND 0x00003f00 +#define RIO_PORT_N_ACK_OUTBOUND 0x0000003f #define RIO_PORT_N_ERR_STS_CSR(x) (0x0058 + x*0x20) #define RIO_PORT_N_ERR_STS_PW_OUT_ES 0x00010000 /* Output Error-stopped */ #define RIO_PORT_N_ERR_STS_PW_INP_ES 0x00000100 /* Input Error-stopped */ @@ -238,7 +243,6 @@ #define RIO_PORT_N_ERR_STS_PORT_ERR 0x00000004 #define RIO_PORT_N_ERR_STS_PORT_OK 0x00000002 #define RIO_PORT_N_ERR_STS_PORT_UNINIT 0x00000001 -#define RIO_PORT_N_ERR_STS_CLR_MASK 0x07120204 #define RIO_PORT_N_CTL_CSR(x) (0x005c + x*0x20) #define RIO_PORT_N_CTL_PWIDTH 0xc0000000 #define RIO_PORT_N_CTL_PWIDTH_1 0x00000000 @@ -261,6 +265,10 @@ #define RIO_EM_EFB_HEADER 0x000 /* Error Management Extensions Block Header */ #define RIO_EM_LTL_ERR_DETECT 0x008 /* Logical/Transport Layer Error Detect CSR */ #define RIO_EM_LTL_ERR_EN 0x00c /* Logical/Transport Layer Error Enable CSR */ +#define REM_LTL_ERR_ILLTRAN 0x08000000 /* Illegal Transaction decode */ +#define REM_LTL_ERR_UNSOLR 0x00800000 /* Unsolicited Response */ +#define REM_LTL_ERR_UNSUPTR 0x00400000 /* Unsupported Transaction */ +#define REM_LTL_ERR_IMPSPEC 0x000000ff /* Implementation Specific */ #define RIO_EM_LTL_HIADDR_CAP 0x010 /* Logical/Transport Layer High Address Capture CSR */ #define RIO_EM_LTL_ADDR_CAP 0x014 /* Logical/Transport Layer Address Capture CSR */ #define RIO_EM_LTL_DEVID_CAP 0x018 /* Logical/Transport Layer Device ID Capture CSR */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 393ce94..be7adb7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -626,6 +626,10 @@ struct signal_struct { int oom_adj; /* OOM kill score adjustment (bit shift) */ int oom_score_adj; /* OOM kill score adjustment */ + + struct mutex cred_guard_mutex; /* guard against foreign influences on + * credential calculations + * (notably. ptrace) */ }; /* Context switch must be unlocked if interrupts are to be enabled */ @@ -1305,9 +1309,6 @@ struct task_struct { * credentials (COW) */ const struct cred __rcu *cred; /* effective (overridable) subjective task * credentials (COW) */ - struct mutex cred_guard_mutex; /* guard against foreign influences on - * credential calculations - * (notably. ptrace) */ struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */ char comm[TASK_COMM_LEN]; /* executable name excluding path @@ -2236,9 +2237,16 @@ static inline void task_unlock(struct task_struct *p) spin_unlock(&p->alloc_lock); } -extern struct sighand_struct *lock_task_sighand(struct task_struct *tsk, +extern struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, unsigned long *flags); +#define lock_task_sighand(tsk, flags) \ +({ struct sighand_struct *__ss; \ + __cond_lock(&(tsk)->sighand->siglock, \ + (__ss = __lock_task_sighand(tsk, flags))); \ + __ss; \ +}) \ + static inline void unlock_task_sighand(struct task_struct *tsk, unsigned long *flags) { diff --git a/include/linux/spi/74x164.h b/include/linux/spi/74x164.h new file mode 100644 index 0000000..d85c52f --- /dev/null +++ b/include/linux/spi/74x164.h @@ -0,0 +1,11 @@ +#ifndef LINUX_SPI_74X164_H +#define LINUX_SPI_74X164_H + +#define GEN_74X164_DRIVER_NAME "74x164" + +struct gen_74x164_chip_platform_data { + /* number assigned to the first GPIO */ + unsigned base; +}; + +#endif diff --git a/include/linux/synclink.h b/include/linux/synclink.h index 0ff2779..2e7d81c 100644 --- a/include/linux/synclink.h +++ b/include/linux/synclink.h @@ -126,6 +126,7 @@ #define MGSL_MODE_BISYNC 4 #define MGSL_MODE_RAW 6 #define MGSL_MODE_BASE_CLOCK 7 +#define MGSL_MODE_XSYNC 8 #define MGSL_BUS_TYPE_ISA 1 #define MGSL_BUS_TYPE_EISA 2 @@ -290,6 +291,10 @@ struct gpio_desc { #define MGSL_IOCSGPIO _IOW(MGSL_MAGIC_IOC,16,struct gpio_desc) #define MGSL_IOCGGPIO _IOR(MGSL_MAGIC_IOC,17,struct gpio_desc) #define MGSL_IOCWAITGPIO _IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc) +#define MGSL_IOCSXSYNC _IO(MGSL_MAGIC_IOC, 19) +#define MGSL_IOCGXSYNC _IO(MGSL_MAGIC_IOC, 20) +#define MGSL_IOCSXCTRL _IO(MGSL_MAGIC_IOC, 21) +#define MGSL_IOCGXCTRL _IO(MGSL_MAGIC_IOC, 22) #ifdef __KERNEL__ /* provide 32 bit ioctl compatibility on 64 bit systems */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index e6319d1..cacc27a 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -701,7 +701,8 @@ asmlinkage long sys_nfsservctl(int cmd, asmlinkage long sys_syslog(int type, char __user *buf, int len); asmlinkage long sys_uselib(const char __user *library); asmlinkage long sys_ni_syscall(void); -asmlinkage long sys_ptrace(long request, long pid, long addr, long data); +asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, + unsigned long data); asmlinkage long sys_add_key(const char __user *_type, const char __user *_description, diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 10db010..3a2e66d 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -150,7 +150,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) * * Return %LSM_UNSAFE_* bits applied to an exec because of tracing. * - * @task->cred_guard_mutex is held by the caller through the do_execve(). + * @task->signal->cred_guard_mutex is held by the caller through the do_execve(). */ static inline int tracehook_unsafe_exec(struct task_struct *task) { diff --git a/include/linux/virtio_9p.h b/include/linux/virtio_9p.h index 1faa80d..e68b439 100644 --- a/include/linux/virtio_9p.h +++ b/include/linux/virtio_9p.h @@ -5,7 +5,6 @@ #include <linux/types.h> #include <linux/virtio_ids.h> #include <linux/virtio_config.h> -#include <linux/types.h> /* The feature bitmap for virtio 9P */ diff --git a/init/Kconfig b/init/Kconfig index 3ae8ffe..88c1046 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -518,7 +518,6 @@ if CGROUPS config CGROUP_DEBUG bool "Example debug cgroup subsystem" - depends on CGROUPS default n help This option enables a simple cgroup subsystem that @@ -529,7 +528,6 @@ config CGROUP_DEBUG config CGROUP_NS bool "Namespace cgroup subsystem" - depends on CGROUPS help Provides a simple namespace cgroup subsystem to provide hierarchical naming of sets of namespaces, @@ -538,21 +536,18 @@ config CGROUP_NS config CGROUP_FREEZER bool "Freezer cgroup subsystem" - depends on CGROUPS help Provides a way to freeze and unfreeze all tasks in a cgroup. config CGROUP_DEVICE bool "Device controller for cgroups" - depends on CGROUPS && EXPERIMENTAL help Provides a cgroup implementing whitelists for devices which a process in the cgroup can mknod or open. config CPUSETS bool "Cpuset support" - depends on CGROUPS help This option will let you create and manage CPUSETs which allow dynamically partitioning a system into sets of CPUs and @@ -568,7 +563,6 @@ config PROC_PID_CPUSET config CGROUP_CPUACCT bool "Simple CPU accounting cgroup subsystem" - depends on CGROUPS help Provides a simple Resource Controller for monitoring the total CPU consumed by the tasks in a cgroup. @@ -578,11 +572,10 @@ config RESOURCE_COUNTERS help This option enables controller independent resource accounting infrastructure that works with cgroups. - depends on CGROUPS config CGROUP_MEM_RES_CTLR bool "Memory Resource Controller for Control Groups" - depends on CGROUPS && RESOURCE_COUNTERS + depends on RESOURCE_COUNTERS select MM_OWNER help Provides a memory resource controller that manages both anonymous @@ -623,7 +616,7 @@ config CGROUP_MEM_RES_CTLR_SWAP menuconfig CGROUP_SCHED bool "Group CPU scheduler" - depends on EXPERIMENTAL && CGROUPS + depends on EXPERIMENTAL default n help This feature lets CPU scheduler recognize task groups and control CPU @@ -652,7 +645,7 @@ endif #CGROUP_SCHED config BLK_CGROUP tristate "Block IO controller" - depends on CGROUPS && BLOCK + depends on BLOCK default n ---help--- Generic block IO controller cgroup interface. This is the common @@ -682,6 +675,59 @@ config DEBUG_BLK_CGROUP endif # CGROUPS +menuconfig NAMESPACES + bool "Namespaces support" if EMBEDDED + default !EMBEDDED + help + Provides the way to make tasks work with different objects using + the same id. For example same IPC id may refer to different objects + or same user id or pid may refer to different tasks when used in + different namespaces. + +if NAMESPACES + +config UTS_NS + bool "UTS namespace" + default y + help + In this namespace tasks see different info provided with the + uname() system call + +config IPC_NS + bool "IPC namespace" + depends on (SYSVIPC || POSIX_MQUEUE) + default y + help + In this namespace tasks work with IPC ids which correspond to + different IPC objects in different namespaces. + +config USER_NS + bool "User namespace (EXPERIMENTAL)" + depends on EXPERIMENTAL + default y + help + This allows containers, i.e. vservers, to use user namespaces + to provide different user info for different servers. + If unsure, say N. + +config PID_NS + bool "PID Namespaces" + default y + help + Support process id namespaces. This allows having multiple + processes with the same pid as long as they are in different + pid namespaces. This is a building block of containers. + +config NET_NS + bool "Network namespace" + depends on NET + default y + help + Allow user space to create what appear to be multiple instances + of the network stack. + +endif # NAMESPACES + config MM_OWNER bool @@ -734,57 +780,6 @@ config RELAY If unsure, say N. -config NAMESPACES - bool "Namespaces support" if EMBEDDED - default !EMBEDDED - help - Provides the way to make tasks work with different objects using - the same id. For example same IPC id may refer to different objects - or same user id or pid may refer to different tasks when used in - different namespaces. - -config UTS_NS - bool "UTS namespace" - depends on NAMESPACES - help - In this namespace tasks see different info provided with the - uname() system call - -config IPC_NS - bool "IPC namespace" - depends on NAMESPACES && (SYSVIPC || POSIX_MQUEUE) - help - In this namespace tasks work with IPC ids which correspond to - different IPC objects in different namespaces. - -config USER_NS - bool "User namespace (EXPERIMENTAL)" - depends on NAMESPACES && EXPERIMENTAL - help - This allows containers, i.e. vservers, to use user namespaces - to provide different user info for different servers. - If unsure, say N. - -config PID_NS - bool "PID Namespaces (EXPERIMENTAL)" - default n - depends on NAMESPACES && EXPERIMENTAL - help - Support process id namespaces. This allows having multiple - processes with the same pid as long as they are in different - pid namespaces. This is a building block of containers. - - Unless you want to work with an experimental feature - say N here. - -config NET_NS - bool "Network namespace" - default n - depends on NAMESPACES && EXPERIMENTAL && NET - help - Allow user space to create what appear to be multiple instances - of the network stack. - config BLK_DEV_INITRD bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support" depends on BROKEN || !FRV diff --git a/ipc/compat.c b/ipc/compat.c index 9dc2c7d..845a287 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -241,6 +241,8 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr) struct semid64_ds __user *up64; int version = compat_ipc_parse_version(&third); + memset(&s64, 0, sizeof(s64)); + if (!uptr) return -EINVAL; if (get_user(pad, (u32 __user *) uptr)) @@ -421,6 +423,8 @@ long compat_sys_msgctl(int first, int second, void __user *uptr) int version = compat_ipc_parse_version(&second); void __user *p; + memset(&m64, 0, sizeof(m64)); + switch (second & (~IPC_64)) { case IPC_INFO: case IPC_RMID: @@ -594,6 +598,8 @@ long compat_sys_shmctl(int first, int second, void __user *uptr) int err, err2; int version = compat_ipc_parse_version(&second); + memset(&s64, 0, sizeof(s64)); + switch (second & (~IPC_64)) { case IPC_RMID: case SHM_LOCK: diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c index d8d1e9f..380ea4f 100644 --- a/ipc/compat_mq.c +++ b/ipc/compat_mq.c @@ -53,6 +53,9 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name, void __user *p = NULL; if (u_attr && oflag & O_CREAT) { struct mq_attr attr; + + memset(&attr, 0, sizeof(attr)); + p = compat_alloc_user_space(sizeof(attr)); if (get_compat_mq_attr(&attr, u_attr) || copy_to_user(p, &attr, sizeof(attr))) @@ -127,6 +130,8 @@ asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes, struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p)); long ret; + memset(&mqstat, 0, sizeof(mqstat)); + if (u_mqstat) { if (get_compat_mq_attr(&mqstat, u_mqstat) || copy_to_user(p, &mqstat, sizeof(mqstat))) @@ -108,7 +108,11 @@ void __init shm_init (void) { shm_init_ns(&init_ipc_ns); ipc_init_proc_interface("sysvipc/shm", - " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", +#if BITS_PER_LONG <= 32 + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", +#else + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", +#endif IPC_SHM_IDS, sysvipc_shm_proc_show); } @@ -544,6 +548,34 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf } /* + * Calculate and add used RSS and swap pages of a shm. + * Called with shm_ids.rw_mutex held as a reader + */ +static void shm_add_rss_swap(struct shmid_kernel *shp, + unsigned long *rss_add, unsigned long *swp_add) +{ + struct inode *inode; + + inode = shp->shm_file->f_path.dentry->d_inode; + + if (is_file_hugepages(shp->shm_file)) { + struct address_space *mapping = inode->i_mapping; + struct hstate *h = hstate_file(shp->shm_file); + *rss_add += pages_per_huge_page(h) * mapping->nrpages; + } else { +#ifdef CONFIG_SHMEM + struct shmem_inode_info *info = SHMEM_I(inode); + spin_lock(&info->lock); + *rss_add += inode->i_mapping->nrpages; + *swp_add += info->swapped; + spin_unlock(&info->lock); +#else + *rss_add += inode->i_mapping->nrpages; +#endif + } +} + +/* * Called with shm_ids.rw_mutex held as a reader */ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, @@ -560,30 +592,13 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, for (total = 0, next_id = 0; total < in_use; next_id++) { struct kern_ipc_perm *ipc; struct shmid_kernel *shp; - struct inode *inode; ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id); if (ipc == NULL) continue; shp = container_of(ipc, struct shmid_kernel, shm_perm); - inode = shp->shm_file->f_path.dentry->d_inode; - - if (is_file_hugepages(shp->shm_file)) { - struct address_space *mapping = inode->i_mapping; - struct hstate *h = hstate_file(shp->shm_file); - *rss += pages_per_huge_page(h) * mapping->nrpages; - } else { -#ifdef CONFIG_SHMEM - struct shmem_inode_info *info = SHMEM_I(inode); - spin_lock(&info->lock); - *rss += inode->i_mapping->nrpages; - *swp += info->swapped; - spin_unlock(&info->lock); -#else - *rss += inode->i_mapping->nrpages; -#endif - } + shm_add_rss_swap(shp, rss, swp); total++; } @@ -1072,6 +1087,9 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr) static int sysvipc_shm_proc_show(struct seq_file *s, void *it) { struct shmid_kernel *shp = it; + unsigned long rss = 0, swp = 0; + + shm_add_rss_swap(shp, &rss, &swp); #if BITS_PER_LONG <= 32 #define SIZE_SPEC "%10lu" @@ -1081,7 +1099,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it) return seq_printf(s, "%10d %10d %4o " SIZE_SPEC " %5u %5u " - "%5lu %5u %5u %5u %5u %10lu %10lu %10lu\n", + "%5lu %5u %5u %5u %5u %10lu %10lu %10lu " + SIZE_SPEC " " SIZE_SPEC "\n", shp->shm_perm.key, shp->shm_perm.id, shp->shm_perm.mode, @@ -1095,6 +1114,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it) shp->shm_perm.cgid, shp->shm_atim, shp->shm_dtim, - shp->shm_ctim); + shp->shm_ctim, + rss * PAGE_SIZE, + swp * PAGE_SIZE); } #endif diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 9270d53..5cf3669 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -243,6 +243,11 @@ static int notify_on_release(const struct cgroup *cgrp) return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); } +static int clone_children(const struct cgroup *cgrp) +{ + return test_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); +} + /* * for_each_subsys() allows you to iterate on each subsystem attached to * an active hierarchy @@ -1040,6 +1045,8 @@ static int cgroup_show_options(struct seq_file *seq, struct vfsmount *vfs) seq_puts(seq, ",noprefix"); if (strlen(root->release_agent_path)) seq_printf(seq, ",release_agent=%s", root->release_agent_path); + if (clone_children(&root->top_cgroup)) + seq_puts(seq, ",clone_children"); if (strlen(root->name)) seq_printf(seq, ",name=%s", root->name); mutex_unlock(&cgroup_mutex); @@ -1050,6 +1057,7 @@ struct cgroup_sb_opts { unsigned long subsys_bits; unsigned long flags; char *release_agent; + bool clone_children; char *name; /* User explicitly requested empty subsystem */ bool none; @@ -1066,7 +1074,8 @@ struct cgroup_sb_opts { */ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) { - char *token, *o = data ?: "all"; + char *token, *o = data; + bool all_ss = false, one_ss = false; unsigned long mask = (unsigned long)-1; int i; bool module_pin_failed = false; @@ -1082,22 +1091,27 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) while ((token = strsep(&o, ",")) != NULL) { if (!*token) return -EINVAL; - if (!strcmp(token, "all")) { - /* Add all non-disabled subsystems */ - opts->subsys_bits = 0; - for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { - struct cgroup_subsys *ss = subsys[i]; - if (ss == NULL) - continue; - if (!ss->disabled) - opts->subsys_bits |= 1ul << i; - } - } else if (!strcmp(token, "none")) { + if (!strcmp(token, "none")) { /* Explicitly have no subsystems */ opts->none = true; - } else if (!strcmp(token, "noprefix")) { + continue; + } + if (!strcmp(token, "all")) { + /* Mutually exclusive option 'all' + subsystem name */ + if (one_ss) + return -EINVAL; + all_ss = true; + continue; + } + if (!strcmp(token, "noprefix")) { set_bit(ROOT_NOPREFIX, &opts->flags); - } else if (!strncmp(token, "release_agent=", 14)) { + continue; + } + if (!strcmp(token, "clone_children")) { + opts->clone_children = true; + continue; + } + if (!strncmp(token, "release_agent=", 14)) { /* Specifying two release agents is forbidden */ if (opts->release_agent) return -EINVAL; @@ -1105,7 +1119,9 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) kstrndup(token + 14, PATH_MAX - 1, GFP_KERNEL); if (!opts->release_agent) return -ENOMEM; - } else if (!strncmp(token, "name=", 5)) { + continue; + } + if (!strncmp(token, "name=", 5)) { const char *name = token + 5; /* Can't specify an empty name */ if (!strlen(name)) @@ -1127,20 +1143,44 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) GFP_KERNEL); if (!opts->name) return -ENOMEM; - } else { - struct cgroup_subsys *ss; - for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { - ss = subsys[i]; - if (ss == NULL) - continue; - if (!strcmp(token, ss->name)) { - if (!ss->disabled) - set_bit(i, &opts->subsys_bits); - break; - } - } - if (i == CGROUP_SUBSYS_COUNT) - return -ENOENT; + + continue; + } + + for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { + struct cgroup_subsys *ss = subsys[i]; + if (ss == NULL) + continue; + if (strcmp(token, ss->name)) + continue; + if (ss->disabled) + continue; + + /* Mutually exclusive option 'all' + subsystem name */ + if (all_ss) + return -EINVAL; + set_bit(i, &opts->subsys_bits); + one_ss = true; + + break; + } + if (i == CGROUP_SUBSYS_COUNT) + return -ENOENT; + } + + /* + * If the 'all' option was specified select all the subsystems, + * otherwise 'all, 'none' and a subsystem name options were not + * specified, let's default to 'all' + */ + if (all_ss || (!all_ss && !one_ss && !opts->none)) { + for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { + struct cgroup_subsys *ss = subsys[i]; + if (ss == NULL) + continue; + if (ss->disabled) + continue; + set_bit(i, &opts->subsys_bits); } } @@ -1355,6 +1395,8 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts) strcpy(root->release_agent_path, opts->release_agent); if (opts->name) strcpy(root->name, opts->name); + if (opts->clone_children) + set_bit(CGRP_CLONE_CHILDREN, &root->top_cgroup.flags); return root; } @@ -1880,6 +1922,8 @@ static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft, const char *buffer) { BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX); + if (strlen(buffer) >= PATH_MAX) + return -EINVAL; if (!cgroup_lock_live_group(cgrp)) return -ENODEV; strcpy(cgrp->root->release_agent_path, buffer); @@ -3173,6 +3217,23 @@ fail: return ret; } +static u64 cgroup_clone_children_read(struct cgroup *cgrp, + struct cftype *cft) +{ + return clone_children(cgrp); +} + +static int cgroup_clone_children_write(struct cgroup *cgrp, + struct cftype *cft, + u64 val) +{ + if (val) + set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); + else + clear_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); + return 0; +} + /* * for the common functions, 'private' gives the type of file */ @@ -3203,6 +3264,11 @@ static struct cftype files[] = { .write_string = cgroup_write_event_control, .mode = S_IWUGO, }, + { + .name = "cgroup.clone_children", + .read_u64 = cgroup_clone_children_read, + .write_u64 = cgroup_clone_children_write, + }, }; static struct cftype cft_release_agent = { @@ -3332,6 +3398,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, if (notify_on_release(parent)) set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); + if (clone_children(parent)) + set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); + for_each_subsys(root, ss) { struct cgroup_subsys_state *css = ss->create(ss, cgrp); @@ -3346,6 +3415,8 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, goto err_destroy; } /* At error, ->destroy() callback has to free assigned ID. */ + if (clone_children(parent) && ss->post_clone) + ss->post_clone(ss, cgrp); } cgroup_lock_hierarchy(root); diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index ce71ed5..e7bebb7 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -48,20 +48,19 @@ static inline struct freezer *task_freezer(struct task_struct *task) struct freezer, css); } -int cgroup_freezing_or_frozen(struct task_struct *task) +static inline int __cgroup_freezing_or_frozen(struct task_struct *task) { - struct freezer *freezer; - enum freezer_state state; + enum freezer_state state = task_freezer(task)->state; + return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN); +} +int cgroup_freezing_or_frozen(struct task_struct *task) +{ + int result; task_lock(task); - freezer = task_freezer(task); - if (!freezer->css.cgroup->parent) - state = CGROUP_THAWED; /* root cgroup can't be frozen */ - else - state = freezer->state; + result = __cgroup_freezing_or_frozen(task); task_unlock(task); - - return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN); + return result; } /* @@ -154,13 +153,6 @@ static void freezer_destroy(struct cgroup_subsys *ss, kfree(cgroup_freezer(cgroup)); } -/* Task is frozen or will freeze immediately when next it gets woken */ -static bool is_task_frozen_enough(struct task_struct *task) -{ - return frozen(task) || - (task_is_stopped_or_traced(task) && freezing(task)); -} - /* * The call to cgroup_lock() in the freezer.state write method prevents * a write to that file racing against an attach, and hence the @@ -174,24 +166,25 @@ static int freezer_can_attach(struct cgroup_subsys *ss, /* * Anything frozen can't move or be moved to/from. - * - * Since orig_freezer->state == FROZEN means that @task has been - * frozen, so it's sufficient to check the latter condition. */ - if (is_task_frozen_enough(task)) + freezer = cgroup_freezer(new_cgroup); + if (freezer->state != CGROUP_THAWED) return -EBUSY; - freezer = cgroup_freezer(new_cgroup); - if (freezer->state == CGROUP_FROZEN) + rcu_read_lock(); + if (__cgroup_freezing_or_frozen(task)) { + rcu_read_unlock(); return -EBUSY; + } + rcu_read_unlock(); if (threadgroup) { struct task_struct *c; rcu_read_lock(); list_for_each_entry_rcu(c, &task->thread_group, thread_group) { - if (is_task_frozen_enough(c)) { + if (__cgroup_freezing_or_frozen(c)) { rcu_read_unlock(); return -EBUSY; } @@ -236,31 +229,30 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) /* * caller must hold freezer->lock */ -static void update_freezer_state(struct cgroup *cgroup, +static void update_if_frozen(struct cgroup *cgroup, struct freezer *freezer) { struct cgroup_iter it; struct task_struct *task; unsigned int nfrozen = 0, ntotal = 0; + enum freezer_state old_state = freezer->state; cgroup_iter_start(cgroup, &it); while ((task = cgroup_iter_next(cgroup, &it))) { ntotal++; - if (is_task_frozen_enough(task)) + if (frozen(task)) nfrozen++; } - /* - * Transition to FROZEN when no new tasks can be added ensures - * that we never exist in the FROZEN state while there are unfrozen - * tasks. - */ - if (nfrozen == ntotal) - freezer->state = CGROUP_FROZEN; - else if (nfrozen > 0) - freezer->state = CGROUP_FREEZING; - else - freezer->state = CGROUP_THAWED; + if (old_state == CGROUP_THAWED) { + BUG_ON(nfrozen > 0); + } else if (old_state == CGROUP_FREEZING) { + if (nfrozen == ntotal) + freezer->state = CGROUP_FROZEN; + } else { /* old_state == CGROUP_FROZEN */ + BUG_ON(nfrozen != ntotal); + } + cgroup_iter_end(cgroup, &it); } @@ -279,7 +271,7 @@ static int freezer_read(struct cgroup *cgroup, struct cftype *cft, if (state == CGROUP_FREEZING) { /* We change from FREEZING to FROZEN lazily if the cgroup was * only partially frozen when we exitted write. */ - update_freezer_state(cgroup, freezer); + update_if_frozen(cgroup, freezer); state = freezer->state; } spin_unlock_irq(&freezer->lock); @@ -301,7 +293,7 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) while ((task = cgroup_iter_next(cgroup, &it))) { if (!freeze_task(task, true)) continue; - if (is_task_frozen_enough(task)) + if (frozen(task)) continue; if (!freezing(task) && !freezer_should_skip(task)) num_cant_freeze_now++; @@ -335,7 +327,7 @@ static int freezer_change_state(struct cgroup *cgroup, spin_lock_irq(&freezer->lock); - update_freezer_state(cgroup, freezer); + update_if_frozen(cgroup, freezer); if (goal_state == freezer->state) goto out; diff --git a/kernel/cred.c b/kernel/cred.c index 9a3e226..6a1aa00 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -325,7 +325,7 @@ EXPORT_SYMBOL(prepare_creds); /* * Prepare credentials for current to perform an execve() - * - The caller must hold current->cred_guard_mutex + * - The caller must hold ->cred_guard_mutex */ struct cred *prepare_exec_creds(void) { @@ -384,8 +384,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) struct cred *new; int ret; - mutex_init(&p->cred_guard_mutex); - if ( #ifdef CONFIG_KEYS !p->cred->thread_keyring && diff --git a/kernel/exit.c b/kernel/exit.c index 894179a..b194feb 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -703,6 +703,8 @@ static void exit_mm(struct task_struct * tsk) * space. */ static struct task_struct *find_new_reaper(struct task_struct *father) + __releases(&tasklist_lock) + __acquires(&tasklist_lock) { struct pid_namespace *pid_ns = task_active_pid_ns(father); struct task_struct *thread; diff --git a/kernel/fork.c b/kernel/fork.c index e87aaaa..3b159c5 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -908,6 +908,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) sig->oom_adj = current->signal->oom_adj; sig->oom_score_adj = current->signal->oom_score_adj; + mutex_init(&sig->cred_guard_mutex); + return 0; } diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 9d917ff..9988d03 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -393,3 +393,18 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) struct irq_desc *desc = irq_to_desc(irq); return desc ? desc->kstat_irqs[cpu] : 0; } + +#ifdef CONFIG_GENERIC_HARDIRQS +unsigned int kstat_irqs(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + int cpu; + int sum = 0; + + if (!desc) + return 0; + for_each_possible_cpu(cpu) + sum += desc->kstat_irqs[cpu]; + return sum; +} +#endif /* CONFIG_GENERIC_HARDIRQS */ diff --git a/kernel/ns_cgroup.c b/kernel/ns_cgroup.c index 2a5dfec..2c98ad9 100644 --- a/kernel/ns_cgroup.c +++ b/kernel/ns_cgroup.c @@ -85,6 +85,14 @@ static struct cgroup_subsys_state *ns_create(struct cgroup_subsys *ss, return ERR_PTR(-EPERM); if (!cgroup_is_descendant(cgroup, current)) return ERR_PTR(-EPERM); + if (test_bit(CGRP_CLONE_CHILDREN, &cgroup->flags)) { + printk("ns_cgroup can't be created with parent " + "'clone_children' set.\n"); + return ERR_PTR(-EINVAL); + } + + printk_once("ns_cgroup deprecated: consider using the " + "'clone_children' flag without the ns_cgroup.\n"); ns_cgroup = kzalloc(sizeof(*ns_cgroup), GFP_KERNEL); if (!ns_cgroup) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index f34d798..99bbaa3 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -181,7 +181,7 @@ int ptrace_attach(struct task_struct *task) * under ptrace. */ retval = -ERESTARTNOINTR; - if (mutex_lock_interruptible(&task->cred_guard_mutex)) + if (mutex_lock_interruptible(&task->signal->cred_guard_mutex)) goto out; task_lock(task); @@ -208,7 +208,7 @@ int ptrace_attach(struct task_struct *task) unlock_tasklist: write_unlock_irq(&tasklist_lock); unlock_creds: - mutex_unlock(&task->cred_guard_mutex); + mutex_unlock(&task->signal->cred_guard_mutex); out: return retval; } @@ -329,6 +329,8 @@ int ptrace_detach(struct task_struct *child, unsigned int data) * and reacquire the lock. */ void exit_ptrace(struct task_struct *tracer) + __releases(&tasklist_lock) + __acquires(&tasklist_lock) { struct task_struct *p, *n; LIST_HEAD(ptrace_dead); @@ -402,7 +404,7 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds return copied; } -static int ptrace_setoptions(struct task_struct *child, long data) +static int ptrace_setoptions(struct task_struct *child, unsigned long data) { child->ptrace &= ~PT_TRACE_MASK; @@ -481,7 +483,8 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) #define is_sysemu_singlestep(request) 0 #endif -static int ptrace_resume(struct task_struct *child, long request, long data) +static int ptrace_resume(struct task_struct *child, long request, + unsigned long data) { if (!valid_signal(data)) return -EIO; @@ -558,10 +561,12 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type, #endif int ptrace_request(struct task_struct *child, long request, - long addr, long data) + unsigned long addr, unsigned long data) { int ret = -EIO; siginfo_t siginfo; + void __user *datavp = (void __user *) data; + unsigned long __user *datalp = datavp; switch (request) { case PTRACE_PEEKTEXT: @@ -578,19 +583,17 @@ int ptrace_request(struct task_struct *child, long request, ret = ptrace_setoptions(child, data); break; case PTRACE_GETEVENTMSG: - ret = put_user(child->ptrace_message, (unsigned long __user *) data); + ret = put_user(child->ptrace_message, datalp); break; case PTRACE_GETSIGINFO: ret = ptrace_getsiginfo(child, &siginfo); if (!ret) - ret = copy_siginfo_to_user((siginfo_t __user *) data, - &siginfo); + ret = copy_siginfo_to_user(datavp, &siginfo); break; case PTRACE_SETSIGINFO: - if (copy_from_user(&siginfo, (siginfo_t __user *) data, - sizeof siginfo)) + if (copy_from_user(&siginfo, datavp, sizeof siginfo)) ret = -EFAULT; else ret = ptrace_setsiginfo(child, &siginfo); @@ -621,7 +624,7 @@ int ptrace_request(struct task_struct *child, long request, } mmput(mm); - ret = put_user(tmp, (unsigned long __user *) data); + ret = put_user(tmp, datalp); break; } #endif @@ -650,7 +653,7 @@ int ptrace_request(struct task_struct *child, long request, case PTRACE_SETREGSET: { struct iovec kiov; - struct iovec __user *uiov = (struct iovec __user *) data; + struct iovec __user *uiov = datavp; if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) return -EFAULT; @@ -691,7 +694,8 @@ static struct task_struct *ptrace_get_task_struct(pid_t pid) #define arch_ptrace_attach(child) do { } while (0) #endif -SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data) +SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, + unsigned long, data) { struct task_struct *child; long ret; @@ -732,7 +736,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data) return ret; } -int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data) +int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, + unsigned long data) { unsigned long tmp; int copied; @@ -743,7 +748,8 @@ int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data) return put_user(tmp, (unsigned long __user *)data); } -int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data) +int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, + unsigned long data) { int copied; diff --git a/kernel/resource.c b/kernel/resource.c index 7b36976..9c9841c 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -453,6 +453,8 @@ static struct resource * __insert_resource(struct resource *parent, struct resou if (first == parent) return first; + if (WARN_ON(first == new)) /* duplicated insertion */ + return first; if ((first->start > new->start) || (first->end < new->end)) break; diff --git a/kernel/signal.c b/kernel/signal.c index 919562c..4e3cff1 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1105,7 +1105,8 @@ int zap_other_threads(struct task_struct *p) return count; } -struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags) +struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, + unsigned long *flags) { struct sighand_struct *sighand; @@ -1617,6 +1618,8 @@ static int sigkill_pending(struct task_struct *tsk) * is gone, we keep current->exit_code unless clear_code. */ static void ptrace_stop(int exit_code, int clear_code, siginfo_t *info) + __releases(¤t->sighand->siglock) + __acquires(¤t->sighand->siglock) { if (arch_ptrace_stop_needed(exit_code, info)) { /* diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 11281d5..c8231fb 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -175,22 +175,8 @@ static void send_cpu_listeners(struct sk_buff *skb, up_write(&listeners->sem); } -static int fill_pid(pid_t pid, struct task_struct *tsk, - struct taskstats *stats) +static void fill_stats(struct task_struct *tsk, struct taskstats *stats) { - int rc = 0; - - if (!tsk) { - rcu_read_lock(); - tsk = find_task_by_vpid(pid); - if (tsk) - get_task_struct(tsk); - rcu_read_unlock(); - if (!tsk) - return -ESRCH; - } else - get_task_struct(tsk); - memset(stats, 0, sizeof(*stats)); /* * Each accounting subsystem adds calls to its functions to @@ -209,17 +195,27 @@ static int fill_pid(pid_t pid, struct task_struct *tsk, /* fill in extended acct fields */ xacct_add_tsk(stats, tsk); +} - /* Define err: label here if needed */ - put_task_struct(tsk); - return rc; +static int fill_stats_for_pid(pid_t pid, struct taskstats *stats) +{ + struct task_struct *tsk; + rcu_read_lock(); + tsk = find_task_by_vpid(pid); + if (tsk) + get_task_struct(tsk); + rcu_read_unlock(); + if (!tsk) + return -ESRCH; + fill_stats(tsk, stats); + put_task_struct(tsk); + return 0; } -static int fill_tgid(pid_t tgid, struct task_struct *first, - struct taskstats *stats) +static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats) { - struct task_struct *tsk; + struct task_struct *tsk, *first; unsigned long flags; int rc = -ESRCH; @@ -228,8 +224,7 @@ static int fill_tgid(pid_t tgid, struct task_struct *first, * leaders who are already counted with the dead tasks */ rcu_read_lock(); - if (!first) - first = find_task_by_vpid(tgid); + first = find_task_by_vpid(tgid); if (!first || !lock_task_sighand(first, &flags)) goto out; @@ -268,7 +263,6 @@ out: return rc; } - static void fill_tgid_exit(struct task_struct *tsk) { unsigned long flags; @@ -360,6 +354,12 @@ static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid) struct nlattr *na, *ret; int aggr; + /* If we don't pad, we end up with alignment on a 4 byte boundary. + * This causes lots of runtime warnings on systems requiring 8 byte + * alignment */ + u32 pids[2] = { pid, 0 }; + int pid_size = ALIGN(sizeof(pid), sizeof(long)); + aggr = (type == TASKSTATS_TYPE_PID) ? TASKSTATS_TYPE_AGGR_PID : TASKSTATS_TYPE_AGGR_TGID; @@ -367,7 +367,7 @@ static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid) na = nla_nest_start(skb, aggr); if (!na) goto err; - if (nla_put(skb, type, sizeof(pid), &pid) < 0) + if (nla_put(skb, type, pid_size, pids) < 0) goto err; ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats)); if (!ret) @@ -424,39 +424,46 @@ err: return rc; } -static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) +static int cmd_attr_register_cpumask(struct genl_info *info) { - int rc; - struct sk_buff *rep_skb; - struct taskstats *stats; - size_t size; cpumask_var_t mask; + int rc; if (!alloc_cpumask_var(&mask, GFP_KERNEL)) return -ENOMEM; - rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], mask); if (rc < 0) - goto free_return_rc; - if (rc == 0) { - rc = add_del_listener(info->snd_pid, mask, REGISTER); - goto free_return_rc; - } + goto out; + rc = add_del_listener(info->snd_pid, mask, REGISTER); +out: + free_cpumask_var(mask); + return rc; +} + +static int cmd_attr_deregister_cpumask(struct genl_info *info) +{ + cpumask_var_t mask; + int rc; + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) + return -ENOMEM; rc = parse(info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK], mask); if (rc < 0) - goto free_return_rc; - if (rc == 0) { - rc = add_del_listener(info->snd_pid, mask, DEREGISTER); -free_return_rc: - free_cpumask_var(mask); - return rc; - } + goto out; + rc = add_del_listener(info->snd_pid, mask, DEREGISTER); +out: free_cpumask_var(mask); + return rc; +} + +static int cmd_attr_pid(struct genl_info *info) +{ + struct taskstats *stats; + struct sk_buff *rep_skb; + size_t size; + u32 pid; + int rc; - /* - * Size includes space for nested attributes - */ size = nla_total_size(sizeof(u32)) + nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); @@ -465,33 +472,64 @@ free_return_rc: return rc; rc = -EINVAL; - if (info->attrs[TASKSTATS_CMD_ATTR_PID]) { - u32 pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]); - stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid); - if (!stats) - goto err; - - rc = fill_pid(pid, NULL, stats); - if (rc < 0) - goto err; - } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) { - u32 tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]); - stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid); - if (!stats) - goto err; - - rc = fill_tgid(tgid, NULL, stats); - if (rc < 0) - goto err; - } else + pid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_PID]); + stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, pid); + if (!stats) + goto err; + + rc = fill_stats_for_pid(pid, stats); + if (rc < 0) + goto err; + return send_reply(rep_skb, info); +err: + nlmsg_free(rep_skb); + return rc; +} + +static int cmd_attr_tgid(struct genl_info *info) +{ + struct taskstats *stats; + struct sk_buff *rep_skb; + size_t size; + u32 tgid; + int rc; + + size = nla_total_size(sizeof(u32)) + + nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); + + rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size); + if (rc < 0) + return rc; + + rc = -EINVAL; + tgid = nla_get_u32(info->attrs[TASKSTATS_CMD_ATTR_TGID]); + stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tgid); + if (!stats) goto err; + rc = fill_stats_for_tgid(tgid, stats); + if (rc < 0) + goto err; return send_reply(rep_skb, info); err: nlmsg_free(rep_skb); return rc; } +static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) +{ + if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK]) + return cmd_attr_register_cpumask(info); + else if (info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK]) + return cmd_attr_deregister_cpumask(info); + else if (info->attrs[TASKSTATS_CMD_ATTR_PID]) + return cmd_attr_pid(info); + else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) + return cmd_attr_tgid(info); + else + return -EINVAL; +} + static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk) { struct signal_struct *sig = tsk->signal; @@ -555,9 +593,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead) if (!stats) goto err; - rc = fill_pid(-1, tsk, stats); - if (rc < 0) - goto err; + fill_stats(tsk, stats); /* * Doesn't matter if tsk is the leader or the last group member leaving diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index b8d2852..2dec9bc 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -31,7 +31,6 @@ #include <linux/perf_event.h> #include <linux/stringify.h> #include <linux/limits.h> -#include <linux/uaccess.h> #include <asm/bitsperlong.h> #include "trace.h" diff --git a/kernel/tsacct.c b/kernel/tsacct.c index 0a67e041..24dc60d 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c @@ -63,12 +63,10 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) stats->ac_ppid = pid_alive(tsk) ? rcu_dereference(tsk->real_parent)->tgid : 0; rcu_read_unlock(); - stats->ac_utime = cputime_to_msecs(tsk->utime) * USEC_PER_MSEC; - stats->ac_stime = cputime_to_msecs(tsk->stime) * USEC_PER_MSEC; - stats->ac_utimescaled = - cputime_to_msecs(tsk->utimescaled) * USEC_PER_MSEC; - stats->ac_stimescaled = - cputime_to_msecs(tsk->stimescaled) * USEC_PER_MSEC; + stats->ac_utime = cputime_to_usecs(tsk->utime); + stats->ac_stime = cputime_to_usecs(tsk->stime); + stats->ac_utimescaled = cputime_to_usecs(tsk->utimescaled); + stats->ac_stimescaled = cputime_to_usecs(tsk->stimescaled); stats->ac_minflt = tsk->min_flt; stats->ac_majflt = tsk->maj_flt; diff --git a/mm/highmem.c b/mm/highmem.c index 781e754..693394d 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -29,6 +29,11 @@ #include <linux/kgdb.h> #include <asm/tlbflush.h> + +#if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) +DEFINE_PER_CPU(int, __kmap_atomic_idx); +#endif + /* * Virtual_count is not a pure "count". * 0 means that it is not mapped, and has not been mapped @@ -43,7 +48,6 @@ unsigned long totalhigh_pages __read_mostly; EXPORT_SYMBOL(totalhigh_pages); -DEFINE_PER_CPU(int, __kmap_atomic_idx); EXPORT_PER_CPU_SYMBOL(__kmap_atomic_idx); unsigned int nr_free_highpages (void) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 9be3cf8..9a99cfa 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -89,7 +89,10 @@ enum mem_cgroup_stat_index { MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */ MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */ MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */ - MEM_CGROUP_EVENTS, /* incremented at every pagein/pageout */ + MEM_CGROUP_STAT_DATA, /* end of data requires synchronization */ + /* incremented at every pagein/pageout */ + MEM_CGROUP_EVENTS = MEM_CGROUP_STAT_DATA, + MEM_CGROUP_ON_MOVE, /* someone is moving account between groups */ MEM_CGROUP_STAT_NSTATS, }; @@ -254,6 +257,12 @@ struct mem_cgroup { * percpu counter. */ struct mem_cgroup_stat_cpu *stat; + /* + * used when a cpu is offlined or other synchronizations + * See mem_cgroup_read_stat(). + */ + struct mem_cgroup_stat_cpu nocpu_base; + spinlock_t pcp_counter_lock; }; /* Stuffs for move charges at task migration. */ @@ -530,14 +539,40 @@ mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz) return mz; } +/* + * Implementation Note: reading percpu statistics for memcg. + * + * Both of vmstat[] and percpu_counter has threshold and do periodic + * synchronization to implement "quick" read. There are trade-off between + * reading cost and precision of value. Then, we may have a chance to implement + * a periodic synchronizion of counter in memcg's counter. + * + * But this _read() function is used for user interface now. The user accounts + * memory usage by memory cgroup and he _always_ requires exact value because + * he accounts memory. Even if we provide quick-and-fuzzy read, we always + * have to visit all online cpus and make sum. So, for now, unnecessary + * synchronization is not implemented. (just implemented for cpu hotplug) + * + * If there are kernel internal actions which can make use of some not-exact + * value, and reading all cpu value can be performance bottleneck in some + * common workload, threashold and synchonization as vmstat[] should be + * implemented. + */ static s64 mem_cgroup_read_stat(struct mem_cgroup *mem, enum mem_cgroup_stat_index idx) { int cpu; s64 val = 0; - for_each_possible_cpu(cpu) + get_online_cpus(); + for_each_online_cpu(cpu) val += per_cpu(mem->stat->count[idx], cpu); +#ifdef CONFIG_HOTPLUG_CPU + spin_lock(&mem->pcp_counter_lock); + val += mem->nocpu_base.count[idx]; + spin_unlock(&mem->pcp_counter_lock); +#endif + put_online_cpus(); return val; } @@ -659,40 +694,83 @@ static struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) return mem; } -/* - * Call callback function against all cgroup under hierarchy tree. - */ -static int mem_cgroup_walk_tree(struct mem_cgroup *root, void *data, - int (*func)(struct mem_cgroup *, void *)) +/* The caller has to guarantee "mem" exists before calling this */ +static struct mem_cgroup *mem_cgroup_start_loop(struct mem_cgroup *mem) { - int found, ret, nextid; struct cgroup_subsys_state *css; - struct mem_cgroup *mem; - - if (!root->use_hierarchy) - return (*func)(root, data); + int found; - nextid = 1; - do { - ret = 0; + if (!mem) /* ROOT cgroup has the smallest ID */ + return root_mem_cgroup; /*css_put/get against root is ignored*/ + if (!mem->use_hierarchy) { + if (css_tryget(&mem->css)) + return mem; + return NULL; + } + rcu_read_lock(); + /* + * searching a memory cgroup which has the smallest ID under given + * ROOT cgroup. (ID >= 1) + */ + css = css_get_next(&mem_cgroup_subsys, 1, &mem->css, &found); + if (css && css_tryget(css)) + mem = container_of(css, struct mem_cgroup, css); + else mem = NULL; + rcu_read_unlock(); + return mem; +} + +static struct mem_cgroup *mem_cgroup_get_next(struct mem_cgroup *iter, + struct mem_cgroup *root, + bool cond) +{ + int nextid = css_id(&iter->css) + 1; + int found; + int hierarchy_used; + struct cgroup_subsys_state *css; + + hierarchy_used = iter->use_hierarchy; + css_put(&iter->css); + /* If no ROOT, walk all, ignore hierarchy */ + if (!cond || (root && !hierarchy_used)) + return NULL; + + if (!root) + root = root_mem_cgroup; + + do { + iter = NULL; rcu_read_lock(); - css = css_get_next(&mem_cgroup_subsys, nextid, &root->css, - &found); + + css = css_get_next(&mem_cgroup_subsys, nextid, + &root->css, &found); if (css && css_tryget(css)) - mem = container_of(css, struct mem_cgroup, css); + iter = container_of(css, struct mem_cgroup, css); rcu_read_unlock(); - - if (mem) { - ret = (*func)(mem, data); - css_put(&mem->css); - } + /* If css is NULL, no more cgroups will be found */ nextid = found + 1; - } while (!ret && css); + } while (css && !iter); - return ret; + return iter; } +/* + * for_eacn_mem_cgroup_tree() for visiting all cgroup under tree. Please + * be careful that "break" loop is not allowed. We have reference count. + * Instead of that modify "cond" to be false and "continue" to exit the loop. + */ +#define for_each_mem_cgroup_tree_cond(iter, root, cond) \ + for (iter = mem_cgroup_start_loop(root);\ + iter != NULL;\ + iter = mem_cgroup_get_next(iter, root, cond)) + +#define for_each_mem_cgroup_tree(iter, root) \ + for_each_mem_cgroup_tree_cond(iter, root, true) + +#define for_each_mem_cgroup_all(iter) \ + for_each_mem_cgroup_tree_cond(iter, NULL, true) + static inline bool mem_cgroup_is_root(struct mem_cgroup *mem) { @@ -1051,7 +1129,52 @@ static unsigned int get_swappiness(struct mem_cgroup *memcg) return swappiness; } -/* A routine for testing mem is not under move_account */ +static void mem_cgroup_start_move(struct mem_cgroup *mem) +{ + int cpu; + + get_online_cpus(); + spin_lock(&mem->pcp_counter_lock); + for_each_online_cpu(cpu) + per_cpu(mem->stat->count[MEM_CGROUP_ON_MOVE], cpu) += 1; + mem->nocpu_base.count[MEM_CGROUP_ON_MOVE] += 1; + spin_unlock(&mem->pcp_counter_lock); + put_online_cpus(); + + synchronize_rcu(); +} + +static void mem_cgroup_end_move(struct mem_cgroup *mem) +{ + int cpu; + + if (!mem) + return; + get_online_cpus(); + spin_lock(&mem->pcp_counter_lock); + for_each_online_cpu(cpu) + per_cpu(mem->stat->count[MEM_CGROUP_ON_MOVE], cpu) -= 1; + mem->nocpu_base.count[MEM_CGROUP_ON_MOVE] -= 1; + spin_unlock(&mem->pcp_counter_lock); + put_online_cpus(); +} +/* + * 2 routines for checking "mem" is under move_account() or not. + * + * mem_cgroup_stealed() - checking a cgroup is mc.from or not. This is used + * for avoiding race in accounting. If true, + * pc->mem_cgroup may be overwritten. + * + * mem_cgroup_under_move() - checking a cgroup is mc.from or mc.to or + * under hierarchy of moving cgroups. This is for + * waiting at hith-memory prressure caused by "move". + */ + +static bool mem_cgroup_stealed(struct mem_cgroup *mem) +{ + VM_BUG_ON(!rcu_read_lock_held()); + return this_cpu_read(mem->stat->count[MEM_CGROUP_ON_MOVE]) > 0; +} static bool mem_cgroup_under_move(struct mem_cgroup *mem) { @@ -1092,13 +1215,6 @@ static bool mem_cgroup_wait_acct_move(struct mem_cgroup *mem) return false; } -static int mem_cgroup_count_children_cb(struct mem_cgroup *mem, void *data) -{ - int *val = data; - (*val)++; - return 0; -} - /** * mem_cgroup_print_oom_info: Called from OOM with tasklist_lock held in read mode. * @memcg: The memory cgroup that went over limit @@ -1173,7 +1289,10 @@ done: static int mem_cgroup_count_children(struct mem_cgroup *mem) { int num = 0; - mem_cgroup_walk_tree(mem, &num, mem_cgroup_count_children_cb); + struct mem_cgroup *iter; + + for_each_mem_cgroup_tree(iter, mem) + num++; return num; } @@ -1322,49 +1441,39 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem, return total; } -static int mem_cgroup_oom_lock_cb(struct mem_cgroup *mem, void *data) -{ - int *val = (int *)data; - int x; - /* - * Logically, we can stop scanning immediately when we find - * a memcg is already locked. But condidering unlock ops and - * creation/removal of memcg, scan-all is simple operation. - */ - x = atomic_inc_return(&mem->oom_lock); - *val = max(x, *val); - return 0; -} /* * Check OOM-Killer is already running under our hierarchy. * If someone is running, return false. */ static bool mem_cgroup_oom_lock(struct mem_cgroup *mem) { - int lock_count = 0; + int x, lock_count = 0; + struct mem_cgroup *iter; - mem_cgroup_walk_tree(mem, &lock_count, mem_cgroup_oom_lock_cb); + for_each_mem_cgroup_tree(iter, mem) { + x = atomic_inc_return(&iter->oom_lock); + lock_count = max(x, lock_count); + } if (lock_count == 1) return true; return false; } -static int mem_cgroup_oom_unlock_cb(struct mem_cgroup *mem, void *data) +static int mem_cgroup_oom_unlock(struct mem_cgroup *mem) { + struct mem_cgroup *iter; + /* * When a new child is created while the hierarchy is under oom, * mem_cgroup_oom_lock() may not be called. We have to use * atomic_add_unless() here. */ - atomic_add_unless(&mem->oom_lock, -1, 0); + for_each_mem_cgroup_tree(iter, mem) + atomic_add_unless(&iter->oom_lock, -1, 0); return 0; } -static void mem_cgroup_oom_unlock(struct mem_cgroup *mem) -{ - mem_cgroup_walk_tree(mem, NULL, mem_cgroup_oom_unlock_cb); -} static DEFINE_MUTEX(memcg_oom_mutex); static DECLARE_WAIT_QUEUE_HEAD(memcg_oom_waitq); @@ -1462,34 +1571,73 @@ bool mem_cgroup_handle_oom(struct mem_cgroup *mem, gfp_t mask) /* * Currently used to update mapped file statistics, but the routine can be * generalized to update other statistics as well. + * + * Notes: Race condition + * + * We usually use page_cgroup_lock() for accessing page_cgroup member but + * it tends to be costly. But considering some conditions, we doesn't need + * to do so _always_. + * + * Considering "charge", lock_page_cgroup() is not required because all + * file-stat operations happen after a page is attached to radix-tree. There + * are no race with "charge". + * + * Considering "uncharge", we know that memcg doesn't clear pc->mem_cgroup + * at "uncharge" intentionally. So, we always see valid pc->mem_cgroup even + * if there are race with "uncharge". Statistics itself is properly handled + * by flags. + * + * Considering "move", this is an only case we see a race. To make the race + * small, we check MEM_CGROUP_ON_MOVE percpu value and detect there are + * possibility of race condition. If there is, we take a lock. */ -void mem_cgroup_update_file_mapped(struct page *page, int val) + +static void mem_cgroup_update_file_stat(struct page *page, int idx, int val) { struct mem_cgroup *mem; - struct page_cgroup *pc; + struct page_cgroup *pc = lookup_page_cgroup(page); + bool need_unlock = false; - pc = lookup_page_cgroup(page); if (unlikely(!pc)) return; - lock_page_cgroup(pc); + rcu_read_lock(); mem = pc->mem_cgroup; - if (!mem || !PageCgroupUsed(pc)) - goto done; + if (unlikely(!mem || !PageCgroupUsed(pc))) + goto out; + /* pc->mem_cgroup is unstable ? */ + if (unlikely(mem_cgroup_stealed(mem))) { + /* take a lock against to access pc->mem_cgroup */ + lock_page_cgroup(pc); + need_unlock = true; + mem = pc->mem_cgroup; + if (!mem || !PageCgroupUsed(pc)) + goto out; + } - /* - * Preemption is already disabled. We can use __this_cpu_xxx - */ - if (val > 0) { - __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]); - SetPageCgroupFileMapped(pc); - } else { - __this_cpu_dec(mem->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]); - ClearPageCgroupFileMapped(pc); + this_cpu_add(mem->stat->count[idx], val); + + switch (idx) { + case MEM_CGROUP_STAT_FILE_MAPPED: + if (val > 0) + SetPageCgroupFileMapped(pc); + else if (!page_mapped(page)) + ClearPageCgroupFileMapped(pc); + break; + default: + BUG(); } -done: - unlock_page_cgroup(pc); +out: + if (unlikely(need_unlock)) + unlock_page_cgroup(pc); + rcu_read_unlock(); + return; +} + +void mem_cgroup_update_file_mapped(struct page *page, int val) +{ + mem_cgroup_update_file_stat(page, MEM_CGROUP_STAT_FILE_MAPPED, val); } /* @@ -1605,15 +1753,55 @@ static void drain_all_stock_sync(void) atomic_dec(&memcg_drain_count); } -static int __cpuinit memcg_stock_cpu_callback(struct notifier_block *nb, +/* + * This function drains percpu counter value from DEAD cpu and + * move it to local cpu. Note that this function can be preempted. + */ +static void mem_cgroup_drain_pcp_counter(struct mem_cgroup *mem, int cpu) +{ + int i; + + spin_lock(&mem->pcp_counter_lock); + for (i = 0; i < MEM_CGROUP_STAT_DATA; i++) { + s64 x = per_cpu(mem->stat->count[i], cpu); + + per_cpu(mem->stat->count[i], cpu) = 0; + mem->nocpu_base.count[i] += x; + } + /* need to clear ON_MOVE value, works as a kind of lock. */ + per_cpu(mem->stat->count[MEM_CGROUP_ON_MOVE], cpu) = 0; + spin_unlock(&mem->pcp_counter_lock); +} + +static void synchronize_mem_cgroup_on_move(struct mem_cgroup *mem, int cpu) +{ + int idx = MEM_CGROUP_ON_MOVE; + + spin_lock(&mem->pcp_counter_lock); + per_cpu(mem->stat->count[idx], cpu) = mem->nocpu_base.count[idx]; + spin_unlock(&mem->pcp_counter_lock); +} + +static int __cpuinit memcg_cpu_hotplug_callback(struct notifier_block *nb, unsigned long action, void *hcpu) { int cpu = (unsigned long)hcpu; struct memcg_stock_pcp *stock; + struct mem_cgroup *iter; + + if ((action == CPU_ONLINE)) { + for_each_mem_cgroup_all(iter) + synchronize_mem_cgroup_on_move(iter, cpu); + return NOTIFY_OK; + } - if (action != CPU_DEAD) + if ((action != CPU_DEAD) || action != CPU_DEAD_FROZEN) return NOTIFY_OK; + + for_each_mem_cgroup_all(iter) + mem_cgroup_drain_pcp_counter(iter, cpu); + stock = &per_cpu(memcg_stock, cpu); drain_stock(stock); return NOTIFY_OK; @@ -3038,6 +3226,7 @@ move_account: lru_add_drain_all(); drain_all_stock_sync(); ret = 0; + mem_cgroup_start_move(mem); for_each_node_state(node, N_HIGH_MEMORY) { for (zid = 0; !ret && zid < MAX_NR_ZONES; zid++) { enum lru_list l; @@ -3051,6 +3240,7 @@ move_account: if (ret) break; } + mem_cgroup_end_move(mem); memcg_oom_recover(mem); /* it seems parent cgroup doesn't have enough mem */ if (ret == -ENOMEM) @@ -3137,33 +3327,25 @@ static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft, return retval; } -struct mem_cgroup_idx_data { - s64 val; - enum mem_cgroup_stat_index idx; -}; -static int -mem_cgroup_get_idx_stat(struct mem_cgroup *mem, void *data) +static u64 mem_cgroup_get_recursive_idx_stat(struct mem_cgroup *mem, + enum mem_cgroup_stat_index idx) { - struct mem_cgroup_idx_data *d = data; - d->val += mem_cgroup_read_stat(mem, d->idx); - return 0; -} + struct mem_cgroup *iter; + s64 val = 0; -static void -mem_cgroup_get_recursive_idx_stat(struct mem_cgroup *mem, - enum mem_cgroup_stat_index idx, s64 *val) -{ - struct mem_cgroup_idx_data d; - d.idx = idx; - d.val = 0; - mem_cgroup_walk_tree(mem, &d, mem_cgroup_get_idx_stat); - *val = d.val; + /* each per cpu's value can be minus.Then, use s64 */ + for_each_mem_cgroup_tree(iter, mem) + val += mem_cgroup_read_stat(iter, idx); + + if (val < 0) /* race ? */ + val = 0; + return val; } static inline u64 mem_cgroup_usage(struct mem_cgroup *mem, bool swap) { - u64 idx_val, val; + u64 val; if (!mem_cgroup_is_root(mem)) { if (!swap) @@ -3172,16 +3354,12 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *mem, bool swap) return res_counter_read_u64(&mem->memsw, RES_USAGE); } - mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_CACHE, &idx_val); - val = idx_val; - mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_RSS, &idx_val); - val += idx_val; + val = mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_CACHE); + val += mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_RSS); - if (swap) { - mem_cgroup_get_recursive_idx_stat(mem, - MEM_CGROUP_STAT_SWAPOUT, &idx_val); - val += idx_val; - } + if (swap) + val += mem_cgroup_get_recursive_idx_stat(mem, + MEM_CGROUP_STAT_SWAPOUT); return val << PAGE_SHIFT; } @@ -3389,9 +3567,9 @@ struct { }; -static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data) +static void +mem_cgroup_get_local_stat(struct mem_cgroup *mem, struct mcs_total_stat *s) { - struct mcs_total_stat *s = data; s64 val; /* per cpu stat */ @@ -3421,13 +3599,15 @@ static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data) s->stat[MCS_ACTIVE_FILE] += val * PAGE_SIZE; val = mem_cgroup_get_local_zonestat(mem, LRU_UNEVICTABLE); s->stat[MCS_UNEVICTABLE] += val * PAGE_SIZE; - return 0; } static void mem_cgroup_get_total_stat(struct mem_cgroup *mem, struct mcs_total_stat *s) { - mem_cgroup_walk_tree(mem, s, mem_cgroup_get_local_stat); + struct mem_cgroup *iter; + + for_each_mem_cgroup_tree(iter, mem) + mem_cgroup_get_local_stat(iter, s); } static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft, @@ -3604,7 +3784,7 @@ static int compare_thresholds(const void *a, const void *b) return _a->threshold - _b->threshold; } -static int mem_cgroup_oom_notify_cb(struct mem_cgroup *mem, void *data) +static int mem_cgroup_oom_notify_cb(struct mem_cgroup *mem) { struct mem_cgroup_eventfd_list *ev; @@ -3615,7 +3795,10 @@ static int mem_cgroup_oom_notify_cb(struct mem_cgroup *mem, void *data) static void mem_cgroup_oom_notify(struct mem_cgroup *mem) { - mem_cgroup_walk_tree(mem, NULL, mem_cgroup_oom_notify_cb); + struct mem_cgroup *iter; + + for_each_mem_cgroup_tree(iter, mem) + mem_cgroup_oom_notify_cb(iter); } static int mem_cgroup_usage_register_event(struct cgroup *cgrp, @@ -4032,6 +4215,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void) vfree(mem); mem = NULL; } + spin_lock_init(&mem->pcp_counter_lock); return mem; } @@ -4158,7 +4342,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) &per_cpu(memcg_stock, cpu); INIT_WORK(&stock->work, drain_local_stock); } - hotcpu_notifier(memcg_stock_cpu_callback, 0); + hotcpu_notifier(memcg_cpu_hotplug_callback, 0); } else { parent = mem_cgroup_from_cont(cont->parent); mem->use_hierarchy = parent->use_hierarchy; @@ -4513,6 +4697,7 @@ static void mem_cgroup_clear_mc(void) mc.to = NULL; mc.moving_task = NULL; spin_unlock(&mc.lock); + mem_cgroup_end_move(from); memcg_oom_recover(from); memcg_oom_recover(to); wake_up_all(&mc.waitq); @@ -4543,6 +4728,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss, VM_BUG_ON(mc.moved_charge); VM_BUG_ON(mc.moved_swap); VM_BUG_ON(mc.moving_task); + mem_cgroup_start_move(from); spin_lock(&mc.lock); mc.from = from; mc.to = mem; @@ -378,6 +378,7 @@ void release_pages(struct page **pages, int nr, int cold) pagevec_free(&pages_to_free); } +EXPORT_SYMBOL(release_pages); /* * The pages which we're about to release may be in the deferred lru-addition |