mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 15:14:18 +08:00
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 ...
This commit is contained in:
commit
17bb51d56c
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
---------------
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/cnt32_to_63.h>
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/localtimer.h>
|
||||
|
||||
|
@ -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)]));
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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,19 +1086,13 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
|
||||
struct rio_priv *priv = port->priv;
|
||||
u32 epwisr, tmp;
|
||||
|
||||
epwisr = in_be32(priv->regs_win + RIO_EPWISR);
|
||||
if (!(epwisr & RIO_EPWISR_PW))
|
||||
goto pw_done;
|
||||
|
||||
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 & 0x00000001))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
#ifdef DEBUG_PW
|
||||
pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
|
||||
if (ipwsr & RIO_IPWSR_QF)
|
||||
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -207,6 +207,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)
|
||||
{
|
||||
@ -221,6 +236,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)
|
||||
{
|
||||
|
@ -418,6 +418,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)
|
||||
{
|
||||
@ -432,6 +447,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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -4,5 +4,5 @@
|
||||
|
||||
obj-$(CONFIG_COMPUTONE) += ip2.o
|
||||
|
||||
ip2-objs := ip2main.o
|
||||
ip2-y := ip2main.o
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)))
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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--;
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
|
182
drivers/gpio/74x164.c
Normal file
182
drivers/gpio/74x164.c
Normal file
@ -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");
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
297
drivers/gpio/basic_mmio_gpio.c
Normal file
297
drivers/gpio/basic_mmio_gpio.c
Normal file
@ -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");
|
@ -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);
|
||||
|
312
drivers/gpio/pch_gpio.c
Normal file
312
drivers/gpio/pch_gpio.c
Normal file
@ -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");
|
@ -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 = {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
@ -717,87 +724,54 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)
|
||||
return (u16) (result & 0xffff);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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",
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -494,6 +494,232 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear Port-Write Pending bit */
|
||||
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 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;
|
||||
}
|
||||
|
@ -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[];
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
447
drivers/rapidio/switches/idt_gen2.c
Normal file
447
drivers/rapidio/switches/idt_gen2.c
Normal file
@ -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);
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user